From 958bbf6c9a3c55aa2a1543679f95b4b985a31ed3 Mon Sep 17 00:00:00 2001 From: tterrag Date: Fri, 11 Jan 2019 17:16:14 -0500 Subject: [PATCH] Fix MC-136995 - Chunk loading and unloading issue with entities placed in exact positions. (#5160) This includes three commits from 1.12.x: https://github.com/MinecraftForge/MinecraftForge/commit/c20a5e8805f64097430cf0722011f20862a8df9c https://github.com/MinecraftForge/MinecraftForge/commit/93b704b459c6f537d3b1651008c49ce1db2e0ca1 https://github.com/MinecraftForge/MinecraftForge/commit/ee0d43bbde37e258c36de1003436dbe3fcf88077 Scatter gun patches to improve entity tracking and position tracking. Provided by Aikar through the Paper project, this commit of patches combines the following patches: https://github.com/PaperMC/Paper/blob/fd1bd5223a461b6d98280bb8f2d67280a30dd24a/Spigot-Server-Patches/0306-Mark-chunk-dirty-anytime-entities-change-to-guarante.patch https://github.com/PaperMC/Paper/blob/fd1bd5223a461b6d98280bb8f2d67280a30dd24a/Spigot-Server-Patches/0315-Always-process-chunk-registration-after-moving.patch https://github.com/PaperMC/Paper/blob/fd1bd5223a461b6d98280bb8f2d67280a30dd24a/Spigot-Server-Patches/0335-Ensure-chunks-are-always-loaded-on-hard-position-set.patch https://github.com/PaperMC/Paper/blob/fd1bd5223a461b6d98280bb8f2d67280a30dd24a/Spigot-Server-Patches/0378-Sync-Player-Position-to-Vehicles.patch Co-authored-by: Gabriel Harris-Rouquette --- .../net/minecraft/entity/Entity.java.patch | 75 ++++++++++++++----- .../entity/EntityLeashKnot.java.patch | 10 +++ .../entity/monster/EntityShulker.java.patch | 10 ++- .../network/NetHandlerPlayServer.java.patch | 14 +++- .../net/minecraft/world/World.java.patch | 17 +++++ .../minecraft/world/chunk/Chunk.java.patch | 18 ++++- .../common/extensions/IForgeEntity.java | 24 ++++++ 7 files changed, 148 insertions(+), 20 deletions(-) create mode 100644 patches/minecraft/net/minecraft/entity/EntityLeashKnot.java.patch diff --git a/patches/minecraft/net/minecraft/entity/Entity.java.patch b/patches/minecraft/net/minecraft/entity/Entity.java.patch index 3319308f0..c322b0218 100644 --- a/patches/minecraft/net/minecraft/entity/Entity.java.patch +++ b/patches/minecraft/net/minecraft/entity/Entity.java.patch @@ -27,7 +27,23 @@ } public EntityType func_200600_R() { -@@ -845,7 +847,7 @@ +@@ -324,6 +326,7 @@ + this.field_70165_t = p_70107_1_; + this.field_70163_u = p_70107_3_; + this.field_70161_v = p_70107_5_; ++ if (this.isAddedToWorld() && !this.field_70170_p.field_72995_K) this.field_70170_p.func_72866_a(this, false); // Forge - Process chunk registration after moving. + float f = this.field_70130_N / 2.0F; + float f1 = this.field_70131_O; + this.func_174826_a(new AxisAlignedBB(p_70107_1_ - (double)f, p_70107_3_, p_70107_5_ - (double)f, p_70107_1_ + (double)f, p_70107_3_ + (double)f1, p_70107_5_ + (double)f)); +@@ -794,6 +797,7 @@ + this.field_70165_t = (axisalignedbb.field_72340_a + axisalignedbb.field_72336_d) / 2.0D; + this.field_70163_u = axisalignedbb.field_72338_b; + this.field_70161_v = (axisalignedbb.field_72339_c + axisalignedbb.field_72334_f) / 2.0D; ++ if (this.isAddedToWorld() && !this.field_70170_p.field_72995_K) this.field_70170_p.func_72866_a(this, false); // Forge - Process chunk registration after moving. + } + + protected SoundEvent func_184184_Z() { +@@ -845,7 +849,7 @@ protected void func_180429_a(BlockPos p_180429_1_, IBlockState p_180429_2_) { if (!p_180429_2_.func_185904_a().func_76224_d()) { @@ -36,7 +52,7 @@ this.func_184185_a(soundtype.func_185844_d(), soundtype.func_185843_a() * 0.15F, soundtype.func_185847_b()); } } -@@ -1040,6 +1042,7 @@ +@@ -1040,6 +1044,7 @@ int k = MathHelper.func_76128_c(this.field_70161_v); BlockPos blockpos = new BlockPos(i, j, k); IBlockState iblockstate = this.field_70170_p.func_180495_p(blockpos); @@ -44,7 +60,7 @@ if (iblockstate.func_185901_i() != EnumBlockRenderType.INVISIBLE) { this.field_70170_p.func_195594_a(new BlockParticleData(Particles.field_197611_d, iblockstate), this.field_70165_t + ((double)this.field_70146_Z.nextFloat() - 0.5D) * (double)this.field_70130_N, this.func_174813_aQ().field_72338_b + 0.1D, this.field_70161_v + ((double)this.field_70146_Z.nextFloat() - 0.5D) * (double)this.field_70130_N, -this.field_70159_w * 4.0D, 1.5D, -this.field_70179_y * 4.0D); } -@@ -1053,7 +1056,7 @@ +@@ -1053,7 +1058,7 @@ double d0 = this.field_70163_u + (double)this.func_70047_e(); BlockPos blockpos = new BlockPos(this.field_70165_t, d0, this.field_70161_v); IFluidState ifluidstate = this.field_70170_p.func_204610_c(blockpos); @@ -53,7 +69,15 @@ } } -@@ -1370,6 +1373,7 @@ +@@ -1122,6 +1127,7 @@ + this.field_70126_B -= 360.0F; + } + ++ if (!this.field_70170_p.field_72995_K) this.field_70170_p.func_72964_e((int) Math.floor(this.field_70165_t) >> 4, (int) Math.floor(this.field_70161_v) >> 4); // Forge - ensure target chunk is loaded. + this.func_70107_b(this.field_70165_t, this.field_70163_u, this.field_70161_v); + this.func_70101_b(p_70080_7_, p_70080_8_); + } +@@ -1370,6 +1376,7 @@ if (this.field_184238_ar) { p_189511_1_.func_74757_a("Glowing", this.field_184238_ar); } @@ -61,7 +85,7 @@ if (!this.field_184236_aF.isEmpty()) { NBTTagList nbttaglist = new NBTTagList(); -@@ -1381,6 +1385,9 @@ +@@ -1381,6 +1388,9 @@ p_189511_1_.func_74782_a("Tags", nbttaglist); } @@ -71,7 +95,7 @@ this.func_70014_b(p_189511_1_); if (this.func_184207_aI()) { NBTTagList nbttaglist1 = new NBTTagList(); -@@ -1466,6 +1473,8 @@ +@@ -1466,6 +1476,8 @@ this.func_174810_b(p_70020_1_.func_74767_n("Silent")); this.func_189654_d(p_70020_1_.func_74767_n("NoGravity")); this.func_184195_f(p_70020_1_.func_74767_n("Glowing")); @@ -80,7 +104,7 @@ if (p_70020_1_.func_150297_b("Tags", 9)) { this.field_184236_aF.clear(); NBTTagList nbttaglist1 = p_70020_1_.func_150295_c("Tags", 8); -@@ -1546,6 +1555,8 @@ +@@ -1546,6 +1558,8 @@ } else { EntityItem entityitem = new EntityItem(this.field_70170_p, this.field_70165_t, this.field_70163_u + (double)p_70099_2_, this.field_70161_v, p_70099_1_); entityitem.func_174869_p(); @@ -89,7 +113,7 @@ this.field_70170_p.func_72838_d(entityitem); return entityitem; } -@@ -1595,6 +1606,7 @@ +@@ -1595,6 +1609,7 @@ this.field_70159_w = 0.0D; this.field_70181_x = 0.0D; this.field_70179_y = 0.0D; @@ -97,7 +121,7 @@ this.func_70071_h_(); if (this.func_184218_aH()) { entity.func_184232_k(this); -@@ -1636,6 +1648,7 @@ +@@ -1636,6 +1651,7 @@ } } @@ -105,7 +129,7 @@ if (p_184205_2_ || this.func_184228_n(p_184205_1_) && p_184205_1_.func_184219_q(this)) { if (this.func_184218_aH()) { this.func_184210_p(); -@@ -1663,6 +1676,7 @@ +@@ -1663,6 +1679,7 @@ public void func_184210_p() { if (this.field_184239_as != null) { Entity entity = this.field_184239_as; @@ -113,7 +137,7 @@ this.field_184239_as = null; entity.func_184225_p(this); } -@@ -1789,10 +1803,15 @@ +@@ -1789,10 +1806,15 @@ return !this.func_184188_bt().isEmpty(); } @@ -129,7 +153,7 @@ public boolean func_70093_af() { return this.func_70083_f(1); } -@@ -2053,6 +2072,14 @@ +@@ -2053,6 +2075,14 @@ @Nullable public Entity func_184204_a(int p_184204_1_) { @@ -144,7 +168,7 @@ if (!this.field_70170_p.field_72995_K && !this.field_70128_L) { this.field_70170_p.field_72984_F.func_76320_a("changeDimension"); MinecraftServer minecraftserver = this.func_184102_h(); -@@ -2060,7 +2087,7 @@ +@@ -2060,7 +2090,7 @@ WorldServer worldserver = minecraftserver.func_71218_a(i); WorldServer worldserver1 = minecraftserver.func_71218_a(p_184204_1_); this.field_71093_bK = p_184204_1_; @@ -153,7 +177,7 @@ worldserver1 = minecraftserver.func_200667_a(DimensionType.OVERWORLD); this.field_71093_bK = 0; } -@@ -2069,16 +2096,17 @@ +@@ -2069,16 +2099,17 @@ this.field_70128_L = false; this.field_70170_p.field_72984_F.func_76320_a("reposition"); BlockPos blockpos; @@ -176,7 +200,7 @@ d0 = MathHelper.func_151237_a(d0 * 8.0D, worldserver1.func_175723_af().func_177726_b() + 16.0D, worldserver1.func_175723_af().func_177728_d() - 16.0D); d1 = MathHelper.func_151237_a(d1 * 8.0D, worldserver1.func_175723_af().func_177736_c() + 16.0D, worldserver1.func_175723_af().func_177733_e() - 16.0D); } -@@ -2087,8 +2115,7 @@ +@@ -2087,8 +2118,7 @@ d1 = (double)MathHelper.func_76125_a((int)d1, -29999872, 29999872); float f = this.field_70177_z; this.func_70012_b(d0, this.field_70163_u, d1, 90.0F, 0.0F); @@ -186,7 +210,7 @@ blockpos = new BlockPos(this); } -@@ -2097,7 +2124,7 @@ +@@ -2097,7 +2127,7 @@ Entity entity = this.func_200600_R().func_200721_a(worldserver1); if (entity != null) { entity.func_180432_n(this); @@ -195,7 +219,7 @@ BlockPos blockpos1 = worldserver1.func_205770_a(Heightmap.Type.MOTION_BLOCKING_NO_LEAVES, worldserver1.func_175694_M()); entity.func_174828_a(blockpos1, entity.field_70177_z, entity.field_70125_A); } else { -@@ -2591,4 +2618,32 @@ +@@ -2591,4 +2621,49 @@ public double func_212107_bY() { return this.field_211517_W; } @@ -227,4 +251,21 @@ + && (this instanceof EntityPlayer || net.minecraftforge.event.ForgeEventFactory.getMobGriefingEvent(field_70170_p, this)) + && this.field_70130_N * this.field_70130_N * this.field_70131_O > 0.512F; + } ++ ++ /* ================================== Forge Start =====================================*/ ++ /** ++ * Internal use for keeping track of entities that are tracked by a world, to ++ * allow guarantees that entity position changes will force a chunk load, avoiding ++ * potential issues with entity desyncing and bad chunk data. ++ */ ++ private boolean isAddedToWorld; ++ ++ @Override ++ public final boolean isAddedToWorld() { return this.isAddedToWorld; } ++ ++ @Override ++ public void onAddedToWorld() { this.isAddedToWorld = true; } ++ ++ @Override ++ public void onRemovedFromWorld() { this.isAddedToWorld = false; } } diff --git a/patches/minecraft/net/minecraft/entity/EntityLeashKnot.java.patch b/patches/minecraft/net/minecraft/entity/EntityLeashKnot.java.patch new file mode 100644 index 000000000..bbfe697a2 --- /dev/null +++ b/patches/minecraft/net/minecraft/entity/EntityLeashKnot.java.patch @@ -0,0 +1,10 @@ +--- a/net/minecraft/entity/EntityLeashKnot.java ++++ b/net/minecraft/entity/EntityLeashKnot.java +@@ -38,6 +38,7 @@ + this.field_70165_t = (double)this.field_174861_a.func_177958_n() + 0.5D; + this.field_70163_u = (double)this.field_174861_a.func_177956_o() + 0.5D; + this.field_70161_v = (double)this.field_174861_a.func_177952_p() + 0.5D; ++ if (this.isAddedToWorld() && !this.field_70170_p.field_72995_K) this.field_70170_p.func_72866_a(this, false); // Forge - Process chunk registration after moving. + } + + public void func_174859_a(EnumFacing p_174859_1_) { diff --git a/patches/minecraft/net/minecraft/entity/monster/EntityShulker.java.patch b/patches/minecraft/net/minecraft/entity/monster/EntityShulker.java.patch index e9e834f21..5fe493ec5 100644 --- a/patches/minecraft/net/minecraft/entity/monster/EntityShulker.java.patch +++ b/patches/minecraft/net/minecraft/entity/monster/EntityShulker.java.patch @@ -1,6 +1,14 @@ --- a/net/minecraft/entity/monster/EntityShulker.java +++ b/net/minecraft/entity/monster/EntityShulker.java -@@ -338,6 +338,13 @@ +@@ -245,6 +245,7 @@ + this.field_70165_t = (double)blockpos.func_177958_n() + 0.5D; + this.field_70163_u = (double)blockpos.func_177956_o(); + this.field_70161_v = (double)blockpos.func_177952_p() + 0.5D; ++ if (this.isAddedToWorld() && !this.field_70170_p.field_72995_K) this.field_70170_p.func_72866_a(this, false); // Forge - Process chunk registration after moving. + this.field_70169_q = this.field_70165_t; + this.field_70167_r = this.field_70163_u; + this.field_70166_s = this.field_70161_v; +@@ -338,6 +339,13 @@ } } diff --git a/patches/minecraft/net/minecraft/network/NetHandlerPlayServer.java.patch b/patches/minecraft/net/minecraft/network/NetHandlerPlayServer.java.patch index 475fa9f4d..8aaf5e29f 100644 --- a/patches/minecraft/net/minecraft/network/NetHandlerPlayServer.java.patch +++ b/patches/minecraft/net/minecraft/network/NetHandlerPlayServer.java.patch @@ -1,6 +1,18 @@ --- a/net/minecraft/network/NetHandlerPlayServer.java +++ b/net/minecraft/network/NetHandlerPlayServer.java -@@ -1265,5 +1265,7 @@ +@@ -327,9 +327,11 @@ + } + + entity.func_70080_a(d3, d4, d5, f, f1); ++ this.field_147369_b.func_70080_a(d3, d4, d5, this.field_147369_b.field_70177_z, this.field_147369_b.field_70125_A); // Forge - Resync player position on vehicle moving + boolean flag2 = worldserver.func_195586_b(entity, entity.func_174813_aQ().func_186664_h(0.0625D)); + if (flag && (flag1 || !flag2)) { + entity.func_70080_a(d0, d1, d2, f, f1); ++ this.field_147369_b.func_70080_a(d0, d1, d2, this.field_147369_b.field_70177_z, this.field_147369_b.field_70125_A); // Forge - Resync player position on vehicle moving + this.field_147371_a.func_179290_a(new SPacketMoveVehicle(entity)); + return; + } +@@ -1265,5 +1267,7 @@ } public void func_147349_a(CPacketCustomPayload p_147349_1_) { diff --git a/patches/minecraft/net/minecraft/world/World.java.patch b/patches/minecraft/net/minecraft/world/World.java.patch index e7ef4b39f..47e9f61b6 100644 --- a/patches/minecraft/net/minecraft/world/World.java.patch +++ b/patches/minecraft/net/minecraft/world/World.java.patch @@ -235,6 +235,23 @@ this.func_72964_e(i, j).func_76612_a(p_72838_1_); this.field_72996_f.add(p_72838_1_); this.func_72923_a(p_72838_1_); +@@ -766,14 +818,14 @@ + for(int i = 0; i < this.field_73021_x.size(); ++i) { + ((IWorldEventListener)this.field_73021_x.get(i)).func_72703_a(p_72923_1_); + } +- ++ p_72923_1_.onAddedToWorld(); + } + + public void func_72847_b(Entity p_72847_1_) { + for(int i = 0; i < this.field_73021_x.size(); ++i) { + ((IWorldEventListener)this.field_73021_x.get(i)).func_72709_b(p_72847_1_); + } +- ++ p_72847_1_.onRemovedFromWorld(); + } + + public void func_72900_e(Entity p_72900_1_) { @@ -816,52 +868,62 @@ this.field_73021_x.add(p_72954_1_); } diff --git a/patches/minecraft/net/minecraft/world/chunk/Chunk.java.patch b/patches/minecraft/net/minecraft/world/chunk/Chunk.java.patch index c7fd73214..cc1213db6 100644 --- a/patches/minecraft/net/minecraft/world/chunk/Chunk.java.patch +++ b/patches/minecraft/net/minecraft/world/chunk/Chunk.java.patch @@ -17,7 +17,23 @@ } public Chunk(World p_i48703_1_, ChunkPrimer p_i48703_2_, int p_i48703_3_, int p_i48703_4_) { -@@ -1164,4 +1165,30 @@ +@@ -593,6 +594,7 @@ + p_76612_1_.field_70162_ai = k; + p_76612_1_.field_70164_aj = this.field_76647_h; + this.field_76645_j[k].add(p_76612_1_); ++ this.func_76630_e(); // Forge - ensure chunks are marked to save after an entity add + } + + public void func_201607_a(Heightmap.Type p_201607_1_, long[] p_201607_2_) { +@@ -613,6 +615,7 @@ + } + + this.field_76645_j[p_76608_2_].remove(p_76608_1_); ++ this.func_76630_e(); // Forge - ensure chunks are marked to save after entity removals + } + + public boolean func_177444_d(BlockPos p_177444_1_) { +@@ -1164,4 +1167,30 @@ QUEUED, CHECK; } diff --git a/src/main/java/net/minecraftforge/common/extensions/IForgeEntity.java b/src/main/java/net/minecraftforge/common/extensions/IForgeEntity.java index f0d07fd40..64cbc6ece 100644 --- a/src/main/java/net/minecraftforge/common/extensions/IForgeEntity.java +++ b/src/main/java/net/minecraftforge/common/extensions/IForgeEntity.java @@ -181,4 +181,28 @@ public interface IForgeEntity extends ICapabilitySerializable if (forSpawnCount && (this instanceof EntityLiving) && ((EntityLiving)this).isNoDespawnRequired()) return false; return type.getBaseClass().isAssignableFrom(this.getClass()); } + + /** + * Gets whether this entity has been added to a world (for tracking). Specifically + * between the times when an entity is added to a world and the entity being removed + * from the world's tracked lists. See {@link World#onEntityAdded(Entity)} and + * {@link World#onEntityRemoved(Entity)}. + * + * @return True if this entity is being tracked by a world + */ + boolean isAddedToWorld(); + + /** + * Called after the entity has been added to the world's + * ticking list. Can be overriden, but needs to call super + * to prevent MC-136995. + */ + void onAddedToWorld(); + + /** + * Called after the entity has been removed to the world's + * ticking list. Can be overriden, but needs to call super + * to prevent MC-136995. + */ + void onRemovedFromWorld(); }