From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Aikar Date: Thu, 27 Aug 2015 01:15:02 -0400 Subject: [PATCH] Optimize Chunk Access getting a loaded chunk is one of the most hottest pieces of code in the game. getChunkAt is called for the same chunk multiple times in a row, often from getType(); Optimize this look up by using a Last Access cache. diff --git a/src/main/java/net/minecraft/server/Chunk.java b/src/main/java/net/minecraft/server/Chunk.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/server/Chunk.java +++ b/src/main/java/net/minecraft/server/Chunk.java @@ -0,0 +0,0 @@ public class Chunk { private boolean i; public final World world; public final int[] heightMap; + public final long chunkKey; // Paper public final int locX; public final int locZ; private boolean l; @@ -0,0 +0,0 @@ public class Chunk { this.world = world; this.locX = i; this.locZ = j; + this.chunkKey = org.bukkit.craftbukkit.util.LongHash.toLong(this.locX, this.locZ); // Paper this.heightMap = new int[256]; for (int k = 0; k < this.entitySlices.length; ++k) { diff --git a/src/main/java/net/minecraft/server/ChunkProviderServer.java b/src/main/java/net/minecraft/server/ChunkProviderServer.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/server/ChunkProviderServer.java +++ b/src/main/java/net/minecraft/server/ChunkProviderServer.java @@ -0,0 +0,0 @@ public class ChunkProviderServer implements IChunkProvider { public final ChunkUnloadQueue unloadQueue = new ChunkUnloadQueue(); // CraftBukkit - LongHashSet // Paper -> ChunkUnloadQueue public final ChunkGenerator chunkGenerator; // CraftBukkit - public private final IChunkLoader chunkLoader; - public LongObjectHashMap chunks = new LongObjectHashMap(); // CraftBukkit + // Paper start + protected Chunk lastChunkByPos = null; + public LongObjectHashMap chunks = new LongObjectHashMap() { + @Override + public Chunk get(long key) { + if (lastChunkByPos != null && key == lastChunkByPos.chunkKey) { + return lastChunkByPos; + } + return lastChunkByPos = super.get(key); + } + }; // CraftBukkit + // Paper end // private final LongHashMap chunks = new LongHashMap(); // private final List chunkList = Lists.newArrayList(); public final WorldServer world; @@ -0,0 +0,0 @@ public class ChunkProviderServer implements IChunkProvider { Chunk c = chunks.get(LongHash.toLong(i, j)); if (c != null) { + world.testResetChunkCache(c); // Paper c.mustSave = true; } // CraftBukkit end @@ -0,0 +0,0 @@ public class ChunkProviderServer implements IChunkProvider { chunk.removeEntities(); this.saveChunk(chunk); this.saveChunkNOP(chunk); + world.testResetChunkCache(chunk); // Paper this.chunks.remove(chunkcoordinates); // CraftBukkit } diff --git a/src/main/java/net/minecraft/server/World.java b/src/main/java/net/minecraft/server/World.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/server/World.java +++ b/src/main/java/net/minecraft/server/World.java @@ -0,0 +0,0 @@ public abstract class World implements IBlockAccess { public Chunk getChunkIfLoaded(BlockPosition blockposition) { return this.chunkProvider.getLoadedChunkAt(blockposition.getX() >> 4, blockposition.getZ() >> 4); } + + public void testResetChunkCache(Chunk chunk) { + if (chunk == ((ChunkProviderServer) chunkProvider).lastChunkByPos) { + ((ChunkProviderServer) chunkProvider).lastChunkByPos = null; + } + } // Paper end public Chunk getChunkIfLoaded(int x, int z) { diff --git a/src/main/java/net/minecraft/server/WorldServer.java b/src/main/java/net/minecraft/server/WorldServer.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/server/WorldServer.java +++ b/src/main/java/net/minecraft/server/WorldServer.java @@ -0,0 +0,0 @@ public class WorldServer extends World implements IAsyncTaskHandler { // CraftBukkit end public void doTick() { + ((ChunkProviderServer) chunkProvider).lastChunkByPos = null; // Paper super.doTick(); if (this.getWorldData().isHardcore() && this.getDifficulty() != EnumDifficulty.HARD) { this.getWorldData().setDifficulty(EnumDifficulty.HARD); diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java @@ -0,0 +0,0 @@ public class CraftWorld implements World { world.getChunkProviderServer().unloadQueue.remove(x, z); world.getChunkProviderServer().chunks.remove(LongHash.toLong(x, z)); + world.testResetChunkCache(chunk); // Paper // Update neighbor counts for (int xx = -2; xx < 3; xx++) { --