From 5acfdd6af4b4da901a32dc845b881985028fdce2 Mon Sep 17 00:00:00 2001 From: Pedro <3602279+Doc94@users.noreply.github.com> Date: Wed, 30 Apr 2025 13:53:32 -0400 Subject: [PATCH] Fix save/load NaN Entity Motion (#12269) --- .../0015-Moonrise-optimisation-patches.patch | 16 ++++++++-------- .../net/minecraft/world/entity/Entity.java.patch | 12 +++++++++++- .../main/java/io/papermc/paper/util/MCUtil.java | 14 ++++++++++++-- 3 files changed, 31 insertions(+), 11 deletions(-) diff --git a/paper-server/patches/features/0015-Moonrise-optimisation-patches.patch b/paper-server/patches/features/0015-Moonrise-optimisation-patches.patch index 0a84806449..84b38c3e8b 100644 --- a/paper-server/patches/features/0015-Moonrise-optimisation-patches.patch +++ b/paper-server/patches/features/0015-Moonrise-optimisation-patches.patch @@ -28597,7 +28597,7 @@ index 8cc5c0716392ba06501542ff5cbe71ee43979e5d..09fd99c9cbd23b5f3c899bfb00c9b896 + // Paper end - block counting } diff --git a/net/minecraft/world/entity/Entity.java b/net/minecraft/world/entity/Entity.java -index 24f3fa347c889b4e2b7b2ce69cda0f68e9bbc346..48477efbd01bb1f8987d9a3ae195710e36b7294f 100644 +index 609b52150aab93b0bed3b41632c19a00e372fc64..f6cb7754e865b9df3f2e204a7ea9b522fb01851b 100644 --- a/net/minecraft/world/entity/Entity.java +++ b/net/minecraft/world/entity/Entity.java @@ -140,7 +140,7 @@ import net.minecraft.world.scores.ScoreHolder; @@ -28950,7 +28950,7 @@ index 24f3fa347c889b4e2b7b2ce69cda0f68e9bbc346..48477efbd01bb1f8987d9a3ae195710e } private static float[] collectCandidateStepUpHeights(AABB box, List colliders, float deltaY, float maxUpStep) { -@@ -2599,21 +2747,110 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess +@@ -2600,21 +2748,110 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess } public boolean isInWall() { @@ -29072,7 +29072,7 @@ index 24f3fa347c889b4e2b7b2ce69cda0f68e9bbc346..48477efbd01bb1f8987d9a3ae195710e } public InteractionResult interact(Player player, InteractionHand hand) { -@@ -4061,15 +4298,17 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess +@@ -4062,15 +4299,17 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess } public Iterable getIndirectPassengers() { @@ -29098,7 +29098,7 @@ index 24f3fa347c889b4e2b7b2ce69cda0f68e9bbc346..48477efbd01bb1f8987d9a3ae195710e } public int countPlayerPassengers() { -@@ -4212,77 +4451,136 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess +@@ -4213,77 +4452,136 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess return Mth.lerp(partialTick, this.yRotO, this.yRot); } @@ -29289,7 +29289,7 @@ index 24f3fa347c889b4e2b7b2ce69cda0f68e9bbc346..48477efbd01bb1f8987d9a3ae195710e public boolean touchingUnloadedChunk() { AABB aabb = this.getBoundingBox().inflate(1.0); -@@ -4437,6 +4735,15 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess +@@ -4438,6 +4736,15 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess } public final void setPosRaw(double x, double y, double z, boolean forceBoundingBoxUpdate) { @@ -29305,7 +29305,7 @@ index 24f3fa347c889b4e2b7b2ce69cda0f68e9bbc346..48477efbd01bb1f8987d9a3ae195710e if (!checkPosition(this, x, y, z)) { return; } -@@ -4570,6 +4877,12 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess +@@ -4571,6 +4878,12 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess @Override public final void setRemoved(Entity.RemovalReason removalReason, @Nullable org.bukkit.event.entity.EntityRemoveEvent.Cause cause) { // CraftBukkit - add Bukkit remove cause @@ -29318,7 +29318,7 @@ index 24f3fa347c889b4e2b7b2ce69cda0f68e9bbc346..48477efbd01bb1f8987d9a3ae195710e org.bukkit.craftbukkit.event.CraftEventFactory.callEntityRemoveEvent(this, cause); // CraftBukkit final boolean alreadyRemoved = this.removalReason != null; // Paper - Folia schedulers if (this.removalReason == null) { -@@ -4580,7 +4893,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess +@@ -4581,7 +4894,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess this.stopRiding(); } @@ -29327,7 +29327,7 @@ index 24f3fa347c889b4e2b7b2ce69cda0f68e9bbc346..48477efbd01bb1f8987d9a3ae195710e this.levelCallback.onRemove(removalReason); this.onRemoval(removalReason); // Paper start - Folia schedulers -@@ -4614,7 +4927,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess +@@ -4615,7 +4928,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess public boolean shouldBeSaved() { return (this.removalReason == null || this.removalReason.shouldSave()) && !this.isPassenger() diff --git a/paper-server/patches/sources/net/minecraft/world/entity/Entity.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/Entity.java.patch index 37f0ba3064..428679de20 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/Entity.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/Entity.java.patch @@ -694,7 +694,7 @@ return true; } } -@@ -1805,14 +_,34 @@ +@@ -1805,14 +_,35 @@ } public CompoundTag saveWithoutId(CompoundTag compound) { @@ -715,6 +715,7 @@ } + } // CraftBukkit ++ this.setDeltaMovement(io.papermc.paper.util.MCUtil.sanitizeNanInf(this.deltaMovement, 0D)); // Paper - remove NaN values before usage in saving compound.store("Motion", Vec3.CODEC, this.getDeltaMovement()); + // CraftBukkit start - Checking for NaN pitch/yaw and resetting to zero + // TODO: make sure this is the best way to address this. @@ -810,6 +811,15 @@ return compound; } catch (Throwable var8) { CrashReport crashReport = CrashReport.forThrowable(var8, "Saving entity NBT"); +@@ -1888,7 +_,7 @@ + public void load(CompoundTag compound) { + try { + Vec3 vec3 = compound.read("Pos", Vec3.CODEC).orElse(Vec3.ZERO); +- Vec3 vec31 = compound.read("Motion", Vec3.CODEC).orElse(Vec3.ZERO); ++ Vec3 vec31 = compound.read("Motion", Vec3.CODEC).orElse(Vec3.ZERO); vec31 = io.papermc.paper.util.MCUtil.sanitizeNanInf(vec31, 0D); // Paper - avoid setting NaN values + Vec2 vec2 = compound.read("Rotation", Vec2.CODEC).orElse(Vec2.ZERO); + this.setDeltaMovement(Math.abs(vec31.x) > 10.0 ? 0.0 : vec31.x, Math.abs(vec31.y) > 10.0 ? 0.0 : vec31.y, Math.abs(vec31.z) > 10.0 ? 0.0 : vec31.z); + this.hasImpulse = true; @@ -1932,6 +_,67 @@ } else { throw new IllegalStateException("Entity has invalid rotation"); diff --git a/paper-server/src/main/java/io/papermc/paper/util/MCUtil.java b/paper-server/src/main/java/io/papermc/paper/util/MCUtil.java index 8756aedc69..27927bb796 100644 --- a/paper-server/src/main/java/io/papermc/paper/util/MCUtil.java +++ b/paper-server/src/main/java/io/papermc/paper/util/MCUtil.java @@ -22,9 +22,7 @@ import net.minecraft.core.Vec3i; import net.minecraft.resources.ResourceKey; import net.minecraft.server.MinecraftServer; import net.minecraft.world.level.ChunkPos; -import net.minecraft.world.level.Level; import net.minecraft.world.phys.Vec3; -import org.bukkit.Location; import org.bukkit.NamespacedKey; import org.bukkit.craftbukkit.util.CraftNamespacedKey; import org.bukkit.craftbukkit.util.Waitable; @@ -103,6 +101,18 @@ public final class MCUtil { run.run(); } + public static double sanitizeNanInf(final double value, final double defaultValue) { + return Double.isNaN(value) || Double.isInfinite(value) ? defaultValue : value; + } + + public static Vec3 sanitizeNanInf(final Vec3 vec3, final double defaultValue) { + return new Vec3( + sanitizeNanInf(vec3.x, defaultValue), + sanitizeNanInf(vec3.y, defaultValue), + sanitizeNanInf(vec3.z, defaultValue) + ); + } + public static T ensureMain(Supplier run) { return ensureMain(null, run); }