From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Aikar Date: Wed, 4 Jul 2018 02:10:36 -0400 Subject: [PATCH] Store reference to current Chunk for Entity and Block Entities This enables us a fast reference to the entities current chunk instead of having to look it up by hashmap lookups. diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java index ec553e7d7595ef3652bfa3325a07483bb3c32245..2bea2f4748cadf479dd4f89792ef5ffdd88e9cab 100644 --- a/src/main/java/net/minecraft/world/entity/Entity.java +++ b/src/main/java/net/minecraft/world/entity/Entity.java @@ -261,7 +261,7 @@ public abstract class Entity implements INamableTileEntity, ICommandListener, ne } public boolean isChunkLoaded() { - return world.isChunkLoaded((int) Math.floor(this.locX()) >> 4, (int) Math.floor(this.locZ()) >> 4); + return getCurrentChunk() != null; } // CraftBukkit end @@ -1763,6 +1763,23 @@ public abstract class Entity implements INamableTileEntity, ICommandListener, ne } // Paper start + public java.lang.ref.WeakReference currentChunk = null; + + public void setCurrentChunk(net.minecraft.world.level.chunk.Chunk chunk) { + this.currentChunk = chunk != null ? new java.lang.ref.WeakReference<>(chunk) : null; + } + /** + * Returns the entities current registered chunk. If the entity is not added to a chunk yet, it will return null + */ + public net.minecraft.world.level.chunk.Chunk getCurrentChunk() { + final net.minecraft.world.level.chunk.Chunk chunk = currentChunk != null ? currentChunk.get() : null; + if (chunk != null && chunk.loaded) { + return chunk; + } + + return !inChunk ? null : ((WorldServer)world).getChunkProvider().getChunkAtIfLoadedMainThreadNoCache(chunkX, chunkZ); + } + private MinecraftKey entityKey; private String entityKeyString; diff --git a/src/main/java/net/minecraft/world/level/block/entity/TileEntity.java b/src/main/java/net/minecraft/world/level/block/entity/TileEntity.java index 2b58ae6d91fe0d0f36eedbb78a3c8a8a66d92405..75110c41af3e0097aef65091a2497dd87d08b4b2 100644 --- a/src/main/java/net/minecraft/world/level/block/entity/TileEntity.java +++ b/src/main/java/net/minecraft/world/level/block/entity/TileEntity.java @@ -11,6 +11,7 @@ import net.minecraft.world.level.World; import net.minecraft.world.level.block.EnumBlockMirror; import net.minecraft.world.level.block.EnumBlockRotation; import net.minecraft.world.level.block.state.IBlockData; +import net.minecraft.world.level.chunk.Chunk; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.util.Supplier; @@ -63,6 +64,15 @@ public abstract class TileEntity implements net.minecraft.server.KeyedObject { / getMinecraftKey(); // Try to load if it doesn't exists. return tileEntityKeyString; } + + private java.lang.ref.WeakReference currentChunk = null; + public Chunk getCurrentChunk() { + final Chunk chunk = currentChunk != null ? currentChunk.get() : null; + return chunk != null && chunk.loaded ? chunk : null; + } + public void setCurrentChunk(Chunk chunk) { + this.currentChunk = chunk != null ? new java.lang.ref.WeakReference<>(chunk) : null; + } // Paper end @Nullable diff --git a/src/main/java/net/minecraft/world/level/chunk/Chunk.java b/src/main/java/net/minecraft/world/level/chunk/Chunk.java index b15200c2a3923bd8be2ee5e73fdadfeea3e3a8dc..929f6fcd4b9f1b9a1488e170d6a77a5d64beecf3 100644 --- a/src/main/java/net/minecraft/world/level/chunk/Chunk.java +++ b/src/main/java/net/minecraft/world/level/chunk/Chunk.java @@ -90,11 +90,36 @@ public class Chunk implements IChunkAccess { this(world, chunkcoordintpair, biomestorage, ChunkConverter.a, TickListEmpty.b(), TickListEmpty.b(), 0L, (ChunkSection[]) null, (Consumer) null); } + // Paper start + private class TileEntityHashMap extends java.util.HashMap { + @Override + public TileEntity put(BlockPosition key, TileEntity value) { + TileEntity replaced = super.put(key, value); + if (replaced != null) { + replaced.setCurrentChunk(null); + } + if (value != null) { + value.setCurrentChunk(Chunk.this); + } + return replaced; + } + + @Override + public TileEntity remove(Object key) { + TileEntity removed = super.remove(key); + if (removed != null) { + removed.setCurrentChunk(null); + } + return removed; + } + } + // Paper end + public Chunk(World world, ChunkCoordIntPair chunkcoordintpair, BiomeStorage biomestorage, ChunkConverter chunkconverter, TickList ticklist, TickList ticklist1, long i, @Nullable ChunkSection[] achunksection, @Nullable Consumer consumer) { this.sections = new ChunkSection[16]; this.e = Maps.newHashMap(); this.heightMap = Maps.newEnumMap(HeightMap.Type.class); - this.tileEntities = Maps.newHashMap(); + this.tileEntities = new TileEntityHashMap(); // Paper this.l = Maps.newHashMap(); this.m = Maps.newHashMap(); this.n = new ShortList[16]; @@ -505,6 +530,7 @@ public class Chunk implements IChunkAccess { } entity.inChunk = true; + entity.setCurrentChunk(this); // Paper entity.chunkX = this.loc.x; entity.chunkY = k; entity.chunkZ = this.loc.z; @@ -517,6 +543,7 @@ public class Chunk implements IChunkAccess { ((HeightMap) this.heightMap.get(heightmap_type)).a(along); } + public final void removeEntity(Entity entity) { this.b(entity); } // Paper - OBFHELPER public void b(Entity entity) { this.a(entity, entity.chunkY); } @@ -531,7 +558,12 @@ public class Chunk implements IChunkAccess { i = this.entitySlices.length - 1; } - this.entitySlices[i].remove(entity); + // Paper start + if (entity.currentChunk != null && entity.currentChunk.get() == this) entity.setCurrentChunk(null); + if (!this.entitySlices[i].remove(entity)) { + return; + } + // Paper end this.entities.remove(entity); // Paper } diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java index df7e5f1d17ddfeffc15df02906c3bf9f9461d82b..eea242af23825ad29ada6e997205e87edffb6bb9 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java @@ -145,6 +145,7 @@ import net.minecraft.world.entity.vehicle.EntityMinecartMobSpawner; import net.minecraft.world.entity.vehicle.EntityMinecartRideable; import net.minecraft.world.entity.vehicle.EntityMinecartTNT; import net.minecraft.world.phys.AxisAlignedBB; +import org.bukkit.Chunk; // Paper import org.bukkit.EntityEffect; import org.bukkit.Location; import org.bukkit.Server; @@ -186,6 +187,12 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity { this.entity = entity; } + @Override + public Chunk getChunk() { + net.minecraft.world.level.chunk.Chunk currentChunk = entity.getCurrentChunk(); + return currentChunk != null ? currentChunk.bukkitChunk : getLocation().getChunk(); + } + public static CraftEntity getEntity(CraftServer server, Entity entity) { /* * Order is *EXTREMELY* important -- keep it right! =D