diff --git a/api/src/main/java/kr/toxicity/model/api/nms/HitBox.java b/api/src/main/java/kr/toxicity/model/api/nms/HitBox.java index cc51b9fc..2eee37f5 100644 --- a/api/src/main/java/kr/toxicity/model/api/nms/HitBox.java +++ b/api/src/main/java/kr/toxicity/model/api/nms/HitBox.java @@ -195,6 +195,19 @@ default void listener(@NotNull Function + * This method ensures that the hitbox position follows its model even when + * it is outside the server's simulation distance. It should be called + * periodically from the entity tracker's tick system. + *

+ * + * @since 3.3.2 + */ + @ApiStatus.Internal + void syncPosition(); + /** * Returns the entity tracker registry for this hitbox's source entity. * diff --git a/api/src/main/java/kr/toxicity/model/api/tracker/EntityTracker.java b/api/src/main/java/kr/toxicity/model/api/tracker/EntityTracker.java index a2334725..40c49bac 100644 --- a/api/src/main/java/kr/toxicity/model/api/tracker/EntityTracker.java +++ b/api/src/main/java/kr/toxicity/model/api/tracker/EntityTracker.java @@ -30,10 +30,7 @@ import org.jetbrains.annotations.Nullable; import org.joml.Quaternionf; -import java.util.Objects; -import java.util.Optional; -import java.util.Set; -import java.util.UUID; +import java.util.*; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; @@ -146,6 +143,16 @@ public EntityTracker(@NotNull EntityTrackerRegistry registry, @NotNull RenderPip if (isClosed()) return; createHitBox(null, CREATE_HITBOX_PREDICATE); }); + tick((_, _) -> { + var hbs = new ArrayList<>(registry.hitBoxCache.values()); + if (!hbs.isEmpty()) { + registry.entity().platform().task(() -> { + for (var hb : hbs) { + hb.syncPosition(); + } + }); + } + }); tick((_, _) -> updateLocation()); tick((_, _) -> { if (damageTint.getAndDecrement() == 0) update(TrackerUpdateAction.previousTint()); diff --git a/api/src/main/java/kr/toxicity/model/api/tracker/EntityTrackerRegistry.java b/api/src/main/java/kr/toxicity/model/api/tracker/EntityTrackerRegistry.java index f2b0ee53..3b2fa3f3 100644 --- a/api/src/main/java/kr/toxicity/model/api/tracker/EntityTrackerRegistry.java +++ b/api/src/main/java/kr/toxicity/model/api/tracker/EntityTrackerRegistry.java @@ -309,6 +309,7 @@ private void initialLoad() { } private void refreshPlayer() { + if (entity.dead()) return; entity.trackedBy() .map(p -> BetterModel.player(p.uuid()).orElse(null)) .filter(Objects::nonNull) diff --git a/nms/v1_21_R3/src/main/kotlin/kr/toxicity/model/bukkit/nms/v1_21_R3/HitBoxImpl.kt b/nms/v1_21_R3/src/main/kotlin/kr/toxicity/model/bukkit/nms/v1_21_R3/HitBoxImpl.kt index a92e7e8e..235238d8 100644 --- a/nms/v1_21_R3/src/main/kotlin/kr/toxicity/model/bukkit/nms/v1_21_R3/HitBoxImpl.kt +++ b/nms/v1_21_R3/src/main/kotlin/kr/toxicity/model/bukkit/nms/v1_21_R3/HitBoxImpl.kt @@ -119,6 +119,25 @@ internal class HitBoxImpl( override fun relativePosition(): Vector3f = delegate.position().run { bone.hitBoxPosition(posCache).add(x.toFloat(), y.toFloat(), z.toFloat()) } + + override fun syncPosition() { + yRot = bone.rotation().y + yHeadRot = yRot + yBodyRot = yRot + val pos = relativePosition() + val minusHeight = source.minY * bone.hitBoxScale() + setPos( + pos.x.toDouble(), + pos.y.toDouble() + minusHeight, + pos.z.toDouble() + ) + interaction.setPos( + pos.x.toDouble(), + pos.y.toDouble() + minusHeight, + pos.z.toDouble() + ) + } + override fun listener(): HitBoxListener = listener override fun listener(listener: HitBoxListener) { this.listener = listener diff --git a/nms/v1_21_R4/src/main/kotlin/kr/toxicity/model/bukkit/nms/v1_21_R4/HitBoxImpl.kt b/nms/v1_21_R4/src/main/kotlin/kr/toxicity/model/bukkit/nms/v1_21_R4/HitBoxImpl.kt index ec779f14..6c7251de 100644 --- a/nms/v1_21_R4/src/main/kotlin/kr/toxicity/model/bukkit/nms/v1_21_R4/HitBoxImpl.kt +++ b/nms/v1_21_R4/src/main/kotlin/kr/toxicity/model/bukkit/nms/v1_21_R4/HitBoxImpl.kt @@ -121,6 +121,25 @@ internal class HitBoxImpl( override fun relativePosition(): Vector3f = delegate.position().run { bone.hitBoxPosition(posCache).add(x.toFloat(), y.toFloat(), z.toFloat()) } + + override fun syncPosition() { + yRot = bone.rotation().y + yHeadRot = yRot + yBodyRot = yRot + val pos = relativePosition() + val minusHeight = source.minY * bone.hitBoxScale() + setPos( + pos.x.toDouble(), + pos.y.toDouble() + minusHeight, + pos.z.toDouble() + ) + interaction.setPos( + pos.x.toDouble(), + pos.y.toDouble() + minusHeight, + pos.z.toDouble() + ) + } + override fun listener(): HitBoxListener = listener override fun listener(listener: HitBoxListener) { this.listener = listener diff --git a/nms/v1_21_R5/src/main/kotlin/kr/toxicity/model/bukkit/nms/v1_21_R5/HitBoxImpl.kt b/nms/v1_21_R5/src/main/kotlin/kr/toxicity/model/bukkit/nms/v1_21_R5/HitBoxImpl.kt index 18b23b4b..84dd2205 100644 --- a/nms/v1_21_R5/src/main/kotlin/kr/toxicity/model/bukkit/nms/v1_21_R5/HitBoxImpl.kt +++ b/nms/v1_21_R5/src/main/kotlin/kr/toxicity/model/bukkit/nms/v1_21_R5/HitBoxImpl.kt @@ -121,6 +121,25 @@ internal class HitBoxImpl( override fun relativePosition(): Vector3f = delegate.position().run { bone.hitBoxPosition(posCache).add(x.toFloat(), y.toFloat(), z.toFloat()) } + + override fun syncPosition() { + yRot = bone.rotation().y + yHeadRot = yRot + yBodyRot = yRot + val pos = relativePosition() + val minusHeight = source.minY * bone.hitBoxScale() + setPos( + pos.x.toDouble(), + pos.y.toDouble() + minusHeight, + pos.z.toDouble() + ) + interaction.setPos( + pos.x.toDouble(), + pos.y.toDouble() + minusHeight, + pos.z.toDouble() + ) + } + override fun listener(): HitBoxListener = listener override fun listener(listener: HitBoxListener) { this.listener = listener diff --git a/nms/v1_21_R6/src/main/kotlin/kr/toxicity/model/bukkit/nms/v1_21_R6/HitBoxImpl.kt b/nms/v1_21_R6/src/main/kotlin/kr/toxicity/model/bukkit/nms/v1_21_R6/HitBoxImpl.kt index 9895179d..12af603b 100644 --- a/nms/v1_21_R6/src/main/kotlin/kr/toxicity/model/bukkit/nms/v1_21_R6/HitBoxImpl.kt +++ b/nms/v1_21_R6/src/main/kotlin/kr/toxicity/model/bukkit/nms/v1_21_R6/HitBoxImpl.kt @@ -121,6 +121,25 @@ internal class HitBoxImpl( override fun relativePosition(): Vector3f = delegate.position().run { bone.hitBoxPosition(posCache).add(x.toFloat(), y.toFloat(), z.toFloat()) } + + override fun syncPosition() { + yRot = bone.rotation().y + yHeadRot = yRot + yBodyRot = yRot + val pos = relativePosition() + val minusHeight = source.minY * bone.hitBoxScale() + setPos( + pos.x.toDouble(), + pos.y.toDouble() + minusHeight, + pos.z.toDouble() + ) + interaction.setPos( + pos.x.toDouble(), + pos.y.toDouble() + minusHeight, + pos.z.toDouble() + ) + } + override fun listener(): HitBoxListener = listener override fun listener(listener: HitBoxListener) { this.listener = listener diff --git a/nms/v1_21_R7/src/main/kotlin/kr/toxicity/model/bukkit/nms/v1_21_R7/HitBoxImpl.kt b/nms/v1_21_R7/src/main/kotlin/kr/toxicity/model/bukkit/nms/v1_21_R7/HitBoxImpl.kt index a66217bc..fe66572d 100644 --- a/nms/v1_21_R7/src/main/kotlin/kr/toxicity/model/bukkit/nms/v1_21_R7/HitBoxImpl.kt +++ b/nms/v1_21_R7/src/main/kotlin/kr/toxicity/model/bukkit/nms/v1_21_R7/HitBoxImpl.kt @@ -121,6 +121,25 @@ internal class HitBoxImpl( override fun relativePosition(): Vector3f = delegate.position().run { bone.hitBoxPosition(posCache).add(x.toFloat(), y.toFloat(), z.toFloat()) } + + override fun syncPosition() { + yRot = bone.rotation().y + yHeadRot = yRot + yBodyRot = yRot + val pos = relativePosition() + val minusHeight = source.minY * bone.hitBoxScale() + setPos( + pos.x.toDouble(), + pos.y.toDouble() + minusHeight, + pos.z.toDouble() + ) + interaction.setPos( + pos.x.toDouble(), + pos.y.toDouble() + minusHeight, + pos.z.toDouble() + ) + } + override fun listener(): HitBoxListener = listener override fun listener(listener: HitBoxListener) { this.listener = listener diff --git a/nms/v26_R1/src/main/kotlin/kr/toxicity/model/bukkit/nms/v26_R1/HitBoxImpl.kt b/nms/v26_R1/src/main/kotlin/kr/toxicity/model/bukkit/nms/v26_R1/HitBoxImpl.kt index d3c933e8..726c3bfb 100644 --- a/nms/v26_R1/src/main/kotlin/kr/toxicity/model/bukkit/nms/v26_R1/HitBoxImpl.kt +++ b/nms/v26_R1/src/main/kotlin/kr/toxicity/model/bukkit/nms/v26_R1/HitBoxImpl.kt @@ -121,6 +121,25 @@ internal class HitBoxImpl( override fun relativePosition(): Vector3f = delegate.position().run { bone.hitBoxPosition(posCache).add(x.toFloat(), y.toFloat(), z.toFloat()) } + + override fun syncPosition() { + yRot = bone.rotation().y + yHeadRot = yRot + yBodyRot = yRot + val pos = relativePosition() + val minusHeight = source.minY * bone.hitBoxScale() + setPos( + pos.x.toDouble(), + pos.y.toDouble() + minusHeight, + pos.z.toDouble() + ) + interaction.setPos( + pos.x.toDouble(), + pos.y.toDouble() + minusHeight, + pos.z.toDouble() + ) + } + override fun listener(): HitBoxListener = listener override fun listener(listener: HitBoxListener) { this.listener = listener diff --git a/platform/fabric/src/main/kotlin/kr/toxicity/model/impl/fabric/entity/HitBoxEntityImpl.kt b/platform/fabric/src/main/kotlin/kr/toxicity/model/impl/fabric/entity/HitBoxEntityImpl.kt index 6a27cbc7..53e80e0e 100644 --- a/platform/fabric/src/main/kotlin/kr/toxicity/model/impl/fabric/entity/HitBoxEntityImpl.kt +++ b/platform/fabric/src/main/kotlin/kr/toxicity/model/impl/fabric/entity/HitBoxEntityImpl.kt @@ -128,6 +128,19 @@ class HitBoxEntityImpl( ) } + override fun syncPosition() { + yRot = bone.rotation().y + yHeadRot = yRot + yBodyRot = yRot + val pos = relativePosition() + val minusHeight = source.minY * bone.hitBoxScale() + val targetX = pos.x.toDouble() + val targetY = pos.y.toDouble() + minusHeight + val targetZ = pos.z.toDouble() + setPos(targetX, targetY, targetZ) + interaction.setPos(targetX, targetY, targetZ) + } + override fun listener(): HitBoxListener = listener override fun listener(listener: HitBoxListener) {