From bda9bfa66f13a5452e94d471c406ea177822827e 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/server/Chunk.java b/src/main/java/net/minecraft/server/Chunk.java index 2d06202da7..8d9aa271a1 100644 --- a/src/main/java/net/minecraft/server/Chunk.java +++ b/src/main/java/net/minecraft/server/Chunk.java @@ -33,7 +33,7 @@ public class Chunk implements IChunkAccess { private final BiomeBase[] g; private final boolean[] h; private final Map i; - private boolean j; + private boolean j; public boolean isLoaded() { return j; } // Paper - OBFHELPER public final World world; public final Map heightMap; public final int locX; @@ -63,7 +63,30 @@ public class Chunk implements IChunkAccess { // CraftBukkit start - Neighbor loaded cache for chunk lighting and entity ticking private int neighbors = 0x1 << 12; public long chunkKey; + // 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 boolean areNeighborsLoaded(final int radius) { switch (radius) { case 2: @@ -94,7 +117,7 @@ public class Chunk implements IChunkAccess { this.h = new boolean[256]; this.i = Maps.newHashMap(); this.heightMap = Maps.newHashMap(); - this.tileEntities = Maps.newHashMap(); + this.tileEntities = new TileEntityHashMap(); // Paper this.q = Maps.newHashMap(); this.r = Maps.newHashMap(); this.s = new ShortList[16]; @@ -646,6 +669,9 @@ public class Chunk implements IChunkAccess { entity.af = k; entity.ag = this.locZ; this.entitySlices[k].add(entity); + // Paper start + entity.setCurrentChunk(this); + // Paper end } public void a(HeightMap.Type heightmap_type, long[] along) { @@ -664,8 +690,12 @@ public class Chunk implements IChunkAccess { if (i >= this.entitySlices.length) { i = this.entitySlices.length - 1; } - - this.entitySlices[i].remove(entity); + // Paper start + if (!this.entitySlices[i].remove(entity)) { + return; + } + entity.setCurrentChunk(null); + // Paper end } public boolean c(BlockPosition blockposition) { @@ -829,6 +859,7 @@ public class Chunk implements IChunkAccess { } } // Spigot End + entity.setCurrentChunk(null); // Paper // Do not pass along players, as doing so can get them stuck outside of time. // (which for example disables inventory icon updates and prevents block breaking) diff --git a/src/main/java/net/minecraft/server/Entity.java b/src/main/java/net/minecraft/server/Entity.java index 5faaf3b199..8934ff699b 100644 --- a/src/main/java/net/minecraft/server/Entity.java +++ b/src/main/java/net/minecraft/server/Entity.java @@ -133,7 +133,7 @@ public abstract class Entity implements INamableTileEntity, ICommandListener, Ke private static final DataWatcherObject aF = DataWatcher.a(Entity.class, DataWatcherRegistry.i); private static final DataWatcherObject aG = DataWatcher.a(Entity.class, DataWatcherRegistry.i); private static final DataWatcherObject aH = DataWatcher.a(Entity.class, DataWatcherRegistry.i); - public boolean inChunk; + public boolean inChunk; public boolean isAddedToChunk() { return inChunk; } // Paper - OBFHELPER public int ae; public int getChunkX() { return ae; } // Paper - OBFHELPER public int af; public int getChunkY() { return af; } // Paper - OBFHELPER public int ag; public int getChunkZ() { return ag; } // Paper - OBFHELPER @@ -1763,6 +1763,39 @@ public abstract class Entity implements INamableTileEntity, ICommandListener, Ke } // Paper start + private java.lang.ref.WeakReference currentChunk = null; + + public void setCurrentChunk(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 Chunk getCurrentChunk() { + final Chunk chunk = currentChunk != null ? currentChunk.get() : null; + return chunk != null && chunk.isLoaded() ? chunk : (isAddedToChunk() ? world.getChunkIfLoaded(getChunkX(), getChunkZ()) : null); + } + /** + * Returns the chunk at the location, using the entities local cache if avail + * Will only return null if the location specified is not loaded + */ + public Chunk getCurrentChunkAt(int x, int z) { + if (getChunkX() == x && getChunkZ() == z) { + Chunk chunk = getCurrentChunk(); + if (chunk != null) { + return chunk; + } + } + return world.getChunkIfLoaded(x, z); + } + /** + * Returns the chunk at the entities current location, using the entities local cache if avail + * Will only return null if the location specified is not loaded + */ + public Chunk getChunkAtLocation() { + return getCurrentChunkAt((int)Math.floor(locX) >> 4, (int)Math.floor(locZ) >> 4); + } + private MinecraftKey entityKey; private String entityKeyString; diff --git a/src/main/java/net/minecraft/server/TileEntity.java b/src/main/java/net/minecraft/server/TileEntity.java index 5ca7fef518..9361667c3b 100644 --- a/src/main/java/net/minecraft/server/TileEntity.java +++ b/src/main/java/net/minecraft/server/TileEntity.java @@ -41,6 +41,15 @@ public abstract class TileEntity implements KeyedObject { // Paper 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.isLoaded() ? 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/org/bukkit/craftbukkit/entity/CraftEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java index b542b17fd0..9fc7ac8c02 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java @@ -9,6 +9,7 @@ import java.util.UUID; import net.minecraft.server.*; +import org.bukkit.Chunk; import org.bukkit.EntityEffect; import org.bukkit.Location; import org.bukkit.Server; @@ -40,6 +41,12 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity { this.entity = entity; } + @Override + public Chunk getChunk() { + net.minecraft.server.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 -- 2.18.0