移植TACZ的延迟补偿

This commit is contained in:
Atsuihsio 2024-06-03 04:01:59 +08:00
parent 7707a24a3d
commit 7094e0d832
5 changed files with 107 additions and 27 deletions

View file

@ -5,6 +5,8 @@ import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.phys.EntityHitResult; import net.minecraft.world.phys.EntityHitResult;
//from TACZ
/** /**
* 用于进行一些并非 {@link LivingEntity} 但是可被子弹击中的特殊实体的处理 * 用于进行一些并非 {@link LivingEntity} 但是可被子弹击中的特殊实体的处理
*/ */

View file

@ -2,6 +2,7 @@ package net.mcreator.target.entity;
import net.mcreator.target.TargetMod; import net.mcreator.target.TargetMod;
import net.mcreator.target.api.entity.ITargetEntity; import net.mcreator.target.api.entity.ITargetEntity;
import net.mcreator.target.tools.HitboxHelper;
import net.mcreator.target.headshot.BoundingBoxManager; import net.mcreator.target.headshot.BoundingBoxManager;
import net.mcreator.target.headshot.IHeadshotBox; import net.mcreator.target.headshot.IHeadshotBox;
import net.mcreator.target.init.TargetModDamageTypes; import net.mcreator.target.init.TargetModDamageTypes;
@ -154,8 +155,8 @@ public class ProjectileEntity extends Entity implements IEntityAdditionalSpawnDa
// hitbox 延迟补偿只有射击者是玩家且被击中者也是玩家才进行此类延迟补偿计算 // hitbox 延迟补偿只有射击者是玩家且被击中者也是玩家才进行此类延迟补偿计算
if (entity instanceof ServerPlayer player && this.shooter instanceof ServerPlayer serverPlayerOwner) { if (entity instanceof ServerPlayer player && this.shooter instanceof ServerPlayer serverPlayerOwner) {
int ping = Mth.floor((serverPlayerOwner.latency / 1000.0) * 20.0 + 0.5); int ping = Mth.floor((serverPlayerOwner.latency / 1000.0) * 20.0 + 0.5);
boundingBox = BoundingBoxManager.getBoundingBox(player, ping); boundingBox = HitboxHelper.getBoundingBox(player, ping);
velocity = BoundingBoxManager.getVelocity(player, ping); velocity = HitboxHelper.getVelocity(player, ping);
} }
// 应用蹲伏导致的 hitbox 变形 // 应用蹲伏导致的 hitbox 变形
boundingBox = boundingBox.expandTowards(0, expandHeight, 0); boundingBox = boundingBox.expandTowards(0, expandHeight, 0);

View file

@ -0,0 +1,23 @@
package net.mcreator.target.event;
import net.mcreator.target.tools.HitboxHelper;
import net.minecraftforge.event.TickEvent;
import net.minecraftforge.event.entity.player.PlayerEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.LogicalSide;
import net.minecraftforge.fml.common.Mod;
@Mod.EventBusSubscriber
public class HitboxHelperEvent {
@SubscribeEvent(receiveCanceled = true)
public static void onPlayerTick(TickEvent.PlayerTickEvent event) {
if (event.side == LogicalSide.SERVER && event.phase == TickEvent.Phase.END) {
HitboxHelper.onPlayerTick(event.player);
}
}
@SubscribeEvent(receiveCanceled = true)
public static void onPlayerLoggedOut(PlayerEvent.PlayerLoggedOutEvent event) {
HitboxHelper.onPlayerLoggedOut(event.getEntity());
}
}

View file

@ -26,12 +26,6 @@ public class BoundingBoxManager {
private static final Map<EntityType<?>, IHeadshotBox<?>> headshotBoxes = new HashMap<>(); private static final Map<EntityType<?>, IHeadshotBox<?>> headshotBoxes = new HashMap<>();
private static final WeakHashMap<Player, LinkedList<AABB>> playerBoxes = new WeakHashMap<>(); private static final WeakHashMap<Player, LinkedList<AABB>> playerBoxes = new WeakHashMap<>();
private static final WeakHashMap<Player, LinkedList<Vec3>> PLAYER_POSITION = new WeakHashMap<>();
// 玩家命中箱缓存表
private static final WeakHashMap<Player, LinkedList<AABB>> PLAYER_HITBOXES = new WeakHashMap<>();
// 玩家速度缓存表
private static final WeakHashMap<Player, LinkedList<Vec3>> PLAYER_VELOCITY = new WeakHashMap<>();
static { static {
/* Player */ /* Player */
registerHeadshotBox(EntityType.PLAYER, (entity) -> { registerHeadshotBox(EntityType.PLAYER, (entity) -> {
@ -124,16 +118,6 @@ public class BoundingBoxManager {
playerBoxes.remove(event.getEntity()); playerBoxes.remove(event.getEntity());
} }
public static Vec3 getPlayerVelocity(Player entity) {
LinkedList<Vec3> positions = PLAYER_POSITION.computeIfAbsent(entity, player -> new LinkedList<>());
if (positions.size() > 1) {
Vec3 currPos = positions.getFirst();
Vec3 prevPos = positions.getLast();
return new Vec3(currPos.x - prevPos.x, currPos.y - prevPos.y, currPos.z - prevPos.z);
}
return new Vec3(0, 0, 0);
}
public static AABB getBoundingBox(Player entity, int ping) { public static AABB getBoundingBox(Player entity, int ping) {
if (playerBoxes.containsKey(entity)) { if (playerBoxes.containsKey(entity)) {
LinkedList<AABB> boxes = playerBoxes.get(entity); LinkedList<AABB> boxes = playerBoxes.get(entity);
@ -142,13 +126,4 @@ public class BoundingBoxManager {
} }
return entity.getBoundingBox(); return entity.getBoundingBox();
} }
public static Vec3 getVelocity(Player entity, int ping) {
if (PLAYER_VELOCITY.containsKey(entity)) {
LinkedList<Vec3> velocities = PLAYER_VELOCITY.get(entity);
int index = Mth.clamp(ping, 0, velocities.size() - 1);
return velocities.get(index);
}
return getPlayerVelocity(entity);
}
} }

View file

@ -0,0 +1,79 @@
package net.mcreator.target.tools;
import net.minecraft.util.Mth;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.phys.AABB;
import net.minecraft.world.phys.Vec3;
import java.util.LinkedList;
import java.util.WeakHashMap;
//from TACZ
public final class HitboxHelper {
// 玩家位置缓存表
private static final WeakHashMap<Player, LinkedList<Vec3>> PLAYER_POSITION = new WeakHashMap<>();
// 玩家命中箱缓存表
private static final WeakHashMap<Player, LinkedList<AABB>> PLAYER_HITBOXES = new WeakHashMap<>();
// 玩家速度缓存表
private static final WeakHashMap<Player, LinkedList<Vec3>> PLAYER_VELOCITY = new WeakHashMap<>();
// 命中箱缓存 Tick 上限
private static final int SAVE_TICK = Mth.floor(1000 / 1000 * 20 + 0.5);
public static void onPlayerTick(Player player) {
if (player.isSpectator()) {
PLAYER_POSITION.remove(player);
PLAYER_HITBOXES.remove(player);
PLAYER_VELOCITY.remove(player);
return;
}
LinkedList<Vec3> positions = PLAYER_POSITION.computeIfAbsent(player, p -> new LinkedList<>());
LinkedList<AABB> boxes = PLAYER_HITBOXES.computeIfAbsent(player, p -> new LinkedList<>());
LinkedList<Vec3> velocities = PLAYER_VELOCITY.computeIfAbsent(player, p -> new LinkedList<>());
positions.addFirst(player.position());
boxes.addFirst(player.getBoundingBox());
velocities.addFirst(getPlayerVelocity(player));
// Position 用于速度计算所以只需要缓存 2 个位置
if (positions.size() > 2) {
positions.removeLast();
}
// 命中箱和速度缓存数量限制
if (boxes.size() > SAVE_TICK) {
boxes.removeLast();
velocities.removeLast();
}
}
public static void onPlayerLoggedOut(Player player) {
PLAYER_POSITION.remove(player);
PLAYER_HITBOXES.remove(player);
PLAYER_VELOCITY.remove(player);
}
public static Vec3 getPlayerVelocity(Player entity) {
LinkedList<Vec3> positions = PLAYER_POSITION.computeIfAbsent(entity, player -> new LinkedList<>());
if (positions.size() > 1) {
Vec3 currPos = positions.getFirst();
Vec3 prevPos = positions.getLast();
return new Vec3(currPos.x - prevPos.x, currPos.y - prevPos.y, currPos.z - prevPos.z);
}
return new Vec3(0, 0, 0);
}
public static AABB getBoundingBox(Player entity, int ping) {
if (PLAYER_HITBOXES.containsKey(entity)) {
LinkedList<AABB> boxes = PLAYER_HITBOXES.get(entity);
int index = Mth.clamp(ping, 0, boxes.size() - 1);
return boxes.get(index);
}
return entity.getBoundingBox();
}
public static Vec3 getVelocity(Player entity, int ping) {
if (PLAYER_VELOCITY.containsKey(entity)) {
LinkedList<Vec3> velocities = PLAYER_VELOCITY.get(entity);
int index = Mth.clamp(ping, 0, velocities.size() - 1);
return velocities.get(index);
}
return getPlayerVelocity(entity);
}
}