From ab050c94d0a74f405ae49fce43faf3ee265d9a39 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 4bbebb25a..ea167a17b 100644 --- a/src/main/java/net/minecraft/server/Chunk.java +++ b/src/main/java/net/minecraft/server/Chunk.java @@ -25,7 +25,7 @@ public class Chunk { private final byte[] g; private final int[] h; private final boolean[] i; - private boolean j; + private boolean j; public boolean isLoaded() { return j; } // Paper - OBFHELPER public final World world; public final int[] heightMap; public final int locX; @@ -33,6 +33,30 @@ public class Chunk { private boolean m; public final Map tileEntities; public final List[] entitySlices; // Spigot + // 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 private boolean done; private boolean lit; private boolean r; @@ -80,7 +104,7 @@ public class Chunk { this.g = new byte[256]; this.h = new int[256]; this.i = new boolean[256]; - this.tileEntities = Maps.newHashMap(); + this.tileEntities = new TileEntityHashMap(); // Paper this.x = 4096; this.y = Queues.newConcurrentLinkedQueue(); this.entitySlices = (List[]) (new List[16]); // Spigot @@ -609,6 +633,9 @@ public class Chunk { entity.ac = k; entity.ad = this.locZ; this.entitySlices[k].add(entity); + // Paper start + entity.setCurrentChunk(this); + // Paper end // Spigot start - increment creature type count // Keep this synced up with World.a(Class) if (entity instanceof EntityInsentient) { @@ -641,6 +668,9 @@ public class Chunk { } this.entitySlices[i].remove(entity); + // Paper start + entity.setCurrentChunk(null); + // Paper end // Spigot start - decrement creature type count // Keep this synced up with World.a(Class) if (entity instanceof EntityInsentient) { diff --git a/src/main/java/net/minecraft/server/Entity.java b/src/main/java/net/minecraft/server/Entity.java index 06c72b95f..0e3a94ab8 100644 --- a/src/main/java/net/minecraft/server/Entity.java +++ b/src/main/java/net/minecraft/server/Entity.java @@ -121,7 +121,7 @@ public abstract class Entity implements ICommandListener, KeyedObject { // Paper private static final DataWatcherObject aC = DataWatcher.a(Entity.class, DataWatcherRegistry.h); private static final DataWatcherObject aD = DataWatcher.a(Entity.class, DataWatcherRegistry.h); private static final DataWatcherObject aE = DataWatcher.a(Entity.class, DataWatcherRegistry.h); - public boolean aa; + public boolean aa; public boolean isAddedToChunk() { return aa; } // Paper - OBFHELPER public int ab; public int getChunkX() { return ab; } // Paper - OBFHELPER public int ac; public int getChunkY() { return ac; } // Paper - OBFHELPER public int ad; public int getChunkZ() { return ad; } // Paper - OBFHELPER @@ -1703,6 +1703,38 @@ public abstract class Entity implements ICommandListener, KeyedObject { // Paper } // 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 String entityKeyString = null; private MinecraftKey entityKey = getMinecraftKey(); diff --git a/src/main/java/net/minecraft/server/TileEntity.java b/src/main/java/net/minecraft/server/TileEntity.java index 0176ca530..29069b753 100644 --- a/src/main/java/net/minecraft/server/TileEntity.java +++ b/src/main/java/net/minecraft/server/TileEntity.java @@ -28,6 +28,14 @@ public abstract class TileEntity implements KeyedObject { } // Paper start + private java.lang.ref.WeakReference currentChunk = null; + public Chunk getCurrentChunk() { + final Chunk chunk = currentChunk != null ? currentChunk.get() : world.getChunkIfLoaded(position.getX() >> 4, position.getZ() >> 4); + return chunk != null && chunk.isLoaded() ? chunk : null; + } + public void setCurrentChunk(Chunk chunk) { + this.currentChunk = chunk != null ? new java.lang.ref.WeakReference<>(chunk) : null; + } private String tileEntityKeyString = null; private MinecraftKey tileEntityKey = getMinecraftKey(); diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java index c5a194ffe..833e3111d 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; @@ -39,6 +40,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