2019-01-01 03:15:55 +00:00
|
|
|
From 12e96fa13e82f5b001e6e3ee87ad4a4c347f022e Mon Sep 17 00:00:00 2001
|
2018-09-04 23:18:06 +00:00
|
|
|
From: Zach Brown <zach.brown@destroystokyo.com>
|
|
|
|
Date: Tue, 4 Sep 2018 19:07:57 -0400
|
|
|
|
Subject: [PATCH] MC-2025: Save and load entity AABB to prevent wobble
|
|
|
|
|
|
|
|
What follows is a summarized analysis provided on the Mojira and associated subreddit by various MC community members
|
|
|
|
who have investigated this issue and found a solution. This work is largely a result of their efforts.
|
|
|
|
|
|
|
|
The underlying cause of MC-2025 is that sometimes an AABB ends up slightly smaller than the desired width. If this
|
|
|
|
happens before the entity is pushed up against a boundary (i.e. blocks or walls), then upon chunk save and reload, the
|
|
|
|
AABB size will be recomputed such that it is intersecting the wall, allowing the entity to be pushed into the wall,
|
|
|
|
suffocate, and die. Although the rounding artifacts get larger at larger world coordinates, the drift we see is
|
|
|
|
miniscule. Closer to the world origin, we have seen error on the order of 2-46. Compare this to the fact that
|
|
|
|
(due to MC-4), entity coordinates send to clients are quantized to multiples of 1/4096 (2-12).
|
|
|
|
|
|
|
|
But, OMG, do the rounding errors mean that AABB's accumulate shrinkage over time? Actually, no. The statistics on IEEE
|
|
|
|
rounding do not have that kind of bias. What has not been stated is that the AABB is just as likely to end up larger
|
|
|
|
than the expected width; on save and reload, the entity ends up slightly away from the wall, and we don't notice any
|
|
|
|
problem. In reality, the AABB size ends up undergoing random wobble around the expected value all the time, and that
|
|
|
|
wobble isn't functionally any different from the kind we'd get even if we tried to force the AABB size to be stable!
|
|
|
|
|
|
|
|
This reasoning leads us to one clear conclusion: The simplest, least invasive, and most correct solution is to just
|
|
|
|
store the AABB in NBT data on chunk save and restore the AABB exactly as it was saved upon reload.
|
|
|
|
|
|
|
|
diff --git a/src/main/java/net/minecraft/server/AxisAlignedBB.java b/src/main/java/net/minecraft/server/AxisAlignedBB.java
|
2019-01-01 03:15:55 +00:00
|
|
|
index 1c0b783e8..c5e541985 100644
|
2018-09-04 23:18:06 +00:00
|
|
|
--- a/src/main/java/net/minecraft/server/AxisAlignedBB.java
|
|
|
|
+++ b/src/main/java/net/minecraft/server/AxisAlignedBB.java
|
2019-01-01 03:15:55 +00:00
|
|
|
@@ -5,12 +5,12 @@ import javax.annotation.Nullable;
|
2018-09-04 23:18:06 +00:00
|
|
|
|
|
|
|
public class AxisAlignedBB {
|
2019-01-01 03:15:55 +00:00
|
|
|
|
2018-10-22 23:16:21 +00:00
|
|
|
- public final double minX;
|
|
|
|
- public final double minY;
|
|
|
|
- public final double minZ;
|
|
|
|
- public final double maxX;
|
|
|
|
- public final double maxY;
|
|
|
|
- public final double maxZ;
|
|
|
|
+ public final double minX; public double getMinX() { return this.minX; } // Paper - OBFHELPER
|
2018-10-25 16:07:54 +00:00
|
|
|
+ public final double minY; public double getMinY() { return this.minY; } // Paper - OBFHELPER
|
2018-10-22 23:16:21 +00:00
|
|
|
+ public final double minZ; public double getMinZ() { return this.minZ; } // Paper - OBFHELPER
|
|
|
|
+ public final double maxX; public double getMaxX() { return this.maxX; } // Paper - OBFHELPER
|
|
|
|
+ public final double maxY; public double getMaxY() { return this.maxY; } // Paper - OBFHELPER
|
|
|
|
+ public final double maxZ; public double getMaxZ() { return this.maxZ; } // Paper - OBFHELPER
|
2018-09-04 23:18:06 +00:00
|
|
|
|
|
|
|
public AxisAlignedBB(double d0, double d1, double d2, double d3, double d4, double d5) {
|
2018-10-22 23:16:21 +00:00
|
|
|
this.minX = Math.min(d0, d3);
|
2018-09-04 23:18:06 +00:00
|
|
|
diff --git a/src/main/java/net/minecraft/server/Entity.java b/src/main/java/net/minecraft/server/Entity.java
|
2019-01-01 03:15:55 +00:00
|
|
|
index 3311e2b24..2e2d14d93 100644
|
2018-09-04 23:18:06 +00:00
|
|
|
--- a/src/main/java/net/minecraft/server/Entity.java
|
|
|
|
+++ b/src/main/java/net/minecraft/server/Entity.java
|
2019-01-01 03:15:55 +00:00
|
|
|
@@ -1657,6 +1657,12 @@ public abstract class Entity implements INamableTileEntity, ICommandListener, Ke
|
2018-09-04 23:18:06 +00:00
|
|
|
if (spawnedViaMobSpawner) {
|
|
|
|
nbttagcompound.setBoolean("Paper.FromMobSpawner", true);
|
|
|
|
}
|
|
|
|
+ // Paper start - MC-2025 fix - Save entity AABB and load it, floating point issues recalculating AABB can result in wobble
|
|
|
|
+ AxisAlignedBB boundingBox = this.getBoundingBox();
|
|
|
|
+ nbttagcompound.set("Paper.AAAB", this.createList(
|
|
|
|
+ boundingBox.getMinX(), boundingBox.getMinY(), boundingBox.getMinZ(),
|
|
|
|
+ boundingBox.getMaxX(), boundingBox.getMaxY(), boundingBox.getMaxZ()
|
|
|
|
+ ));
|
|
|
|
// Paper end
|
|
|
|
return nbttagcompound;
|
|
|
|
} catch (Throwable throwable) {
|
2019-01-01 03:15:55 +00:00
|
|
|
@@ -1746,6 +1752,16 @@ public abstract class Entity implements INamableTileEntity, ICommandListener, Ke
|
2018-09-04 23:18:06 +00:00
|
|
|
if (this.aD()) {
|
|
|
|
this.setPosition(this.locX, this.locY, this.locZ);
|
|
|
|
}
|
|
|
|
+ // Paper start - MC-2025 fix - Save entity AABB and load it, floating point issues recalculating AABB can result in wobble
|
|
|
|
+ // Placement is important, always after the setPosition call above
|
|
|
|
+ if (nbttagcompound.hasKey("Paper.AABB")) {
|
|
|
|
+ NBTTagList savedBB = nbttagcompound.getList("Paper.AABB", 6);
|
|
|
|
+ this.setBoundingBox(new AxisAlignedBB(
|
|
|
|
+ savedBB.getDoubleAt(0), savedBB.getDoubleAt(1), savedBB.getDoubleAt(2),
|
|
|
|
+ savedBB.getDoubleAt(3), savedBB.getDoubleAt(4), savedBB.getDoubleAt(5)
|
|
|
|
+ ));
|
|
|
|
+ }
|
|
|
|
+ // Paper end
|
|
|
|
|
|
|
|
// CraftBukkit start
|
|
|
|
if (this instanceof EntityLiving) {
|
2019-01-01 03:15:55 +00:00
|
|
|
@@ -2814,6 +2830,7 @@ public abstract class Entity implements INamableTileEntity, ICommandListener, Ke
|
2018-09-04 23:18:06 +00:00
|
|
|
return this.boundingBox;
|
|
|
|
}
|
|
|
|
|
|
|
|
+ public void setBoundingBox(AxisAlignedBB axisAlignedBB) { this.a(axisAlignedBB); } // Paper - OBFHELPER
|
|
|
|
public void a(AxisAlignedBB axisalignedbb) {
|
|
|
|
// CraftBukkit start - block invalid bounding boxes
|
2018-10-22 23:16:21 +00:00
|
|
|
double minX = axisalignedbb.minX,
|
2018-09-04 23:18:06 +00:00
|
|
|
--
|
2019-01-01 03:15:55 +00:00
|
|
|
2.20.1
|
2018-09-04 23:18:06 +00:00
|
|
|
|