Another attempt at unload queue, including EAR improvements.

should be fully working now as I pretty much fell back to existing
methods so anything touching the unloadQueue set should behave correctly.

And maintained NMS Reflection safe change too
This commit is contained in:
Aikar 2016-03-21 22:51:14 -04:00
parent 4646f9b68f
commit ae95189944

View File

@ -20,6 +20,8 @@ We mark the chunk as active in many places that notify it is still being used, s
when the chunk unload queue reaches that chunk, and sees the chunk became active again, when the chunk unload queue reaches that chunk, and sees the chunk became active again,
it will skip it and move to next. it will skip it and move to next.
Also optimize EAR to use these methods.
diff --git a/src/main/java/net/minecraft/server/Chunk.java b/src/main/java/net/minecraft/server/Chunk.java diff --git a/src/main/java/net/minecraft/server/Chunk.java b/src/main/java/net/minecraft/server/Chunk.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/server/Chunk.java --- a/src/main/java/net/minecraft/server/Chunk.java
@ -33,22 +35,6 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
// Paper end // Paper end
// CraftBukkit start - Neighbor loaded cache for chunk lighting and entity ticking // CraftBukkit start - Neighbor loaded cache for chunk lighting and entity ticking
@@ -0,0 +0,0 @@ public class Chunk {
}
public void addEntities() {
+ isChunkActive = true; // Paper
this.i = true;
this.world.b(this.tileEntities.values());
@@ -0,0 +0,0 @@ public class Chunk {
}
public void removeEntities() {
+ isChunkActive = false; // Paper
this.i = false;
Iterator iterator = this.tileEntities.values().iterator();
diff --git a/src/main/java/net/minecraft/server/ChunkProviderServer.java b/src/main/java/net/minecraft/server/ChunkProviderServer.java diff --git a/src/main/java/net/minecraft/server/ChunkProviderServer.java b/src/main/java/net/minecraft/server/ChunkProviderServer.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/server/ChunkProviderServer.java --- a/src/main/java/net/minecraft/server/ChunkProviderServer.java
@ -63,45 +49,65 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
private final IChunkLoader chunkLoader; private final IChunkLoader chunkLoader;
public LongObjectHashMap<Chunk> chunks = new LongObjectHashMap<Chunk>(); // CraftBukkit public LongObjectHashMap<Chunk> chunks = new LongObjectHashMap<Chunk>(); // CraftBukkit
@@ -0,0 +0,0 @@ public class ChunkProviderServer implements IChunkProvider { @@ -0,0 +0,0 @@ public class ChunkProviderServer implements IChunkProvider {
return (chunk == null) ? getChunkAt(x, z) : chunk;
}
// CraftBukkit start - Add async variant, provide compatibility - public Chunk getChunkIfLoaded(int x, int z) {
public Chunk getOrCreateChunkFast(int x, int z) { - return chunks.get(LongHash.toLong(x, z));
- Chunk chunk = chunks.get(LongHash.toLong(x, z));
- return (chunk == null) ? getChunkAt(x, z) : chunk;
+ return getChunkAt(x, z); // Paper
+ }
+
+ // Paper start + // Paper start
+ public Chunk getLoadedChunkAtWithoutMarkingActive(int i, int j) { + public Chunk getLoadedChunkAtWithoutMarkingActive(int i, int j) {
+ return chunks.get(LongHash.toLong(i, j)); + return chunks.get(LongHash.toLong(i, j));
} }
- public Chunk getChunkIfLoaded(int x, int z) {
- return chunks.get(LongHash.toLong(x, z));
+ // getChunkIfLoaded -> getChunkIfActive + // getChunkIfLoaded -> getChunkIfActive
+ // this is only used by CraftBukkit now, and plugins shouldnt mark things active + // this is only used by CraftBukkit now, and plugins shouldnt mark things active
+ public Chunk getChunkIfActive(int x, int z) { + public Chunk getChunkIfActive(int x, int z) {
+ Chunk chunk = chunks.get(LongHash.toLong(x, z)); + Chunk chunk = chunks.get(LongHash.toLong(x, z));
+ return (chunk != null && chunk.isChunkActive) ? chunk : null; + return (chunk != null && chunk.isChunkActive) ? chunk : null;
} + }
+ // Paper end + // Paper end
+
public Chunk getLoadedChunkAt(int i, int j) { public Chunk getLoadedChunkAt(int i, int j) {
Chunk chunk = chunks.get(LongHash.toLong(i, j)); // CraftBukkit Chunk chunk = chunks.get(LongHash.toLong(i, j)); // CraftBukkit
this.unloadQueue.remove(i, j); // CraftBukkit - this.unloadQueue.remove(i, j); // CraftBukkit
+ if (chunk != null) { chunk.isChunkActive = true; }// Paper + //this.unloadQueue.remove(i, j); // CraftBukkit // Paper
+ markChunkActive(chunk); // Paper
return chunk; return chunk;
} }
@@ -0,0 +0,0 @@ public class ChunkProviderServer implements IChunkProvider { @@ -0,0 +0,0 @@ public class ChunkProviderServer implements IChunkProvider {
runnable.run(); // CraftBukkit end
} }
+ chunk.isChunkActive = true; // Paper + markChunkActive(chunk); // Paper
return chunk; return chunk;
} }
@@ -0,0 +0,0 @@ public class ChunkProviderServer implements IChunkProvider {
}
public Chunk getChunkAt(int i, int j, Runnable runnable) {
- unloadQueue.remove(i, j);
+ //unloadQueue.remove(i, j); // Paper
Chunk chunk = chunks.get(LongHash.toLong(i, j));
ChunkRegionLoader loader = null;
@@ -0,0 +0,0 @@ public class ChunkProviderServer implements IChunkProvider {
if (runnable != null) {
runnable.run();
}
+ markChunkActive(chunk); // Paper
return chunk;
}
public Chunk originalGetChunkAt(int i, int j) {
- this.unloadQueue.remove(i, j);
+ //this.unloadQueue.remove(i, j); // Paper
Chunk chunk = this.chunks.get(LongHash.toLong(i, j));
boolean newChunk = false;
// CraftBukkit end
@@ -0,0 +0,0 @@ public class ChunkProviderServer implements IChunkProvider { @@ -0,0 +0,0 @@ public class ChunkProviderServer implements IChunkProvider {
continue; continue;
} }
@ -111,6 +117,14 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
if (neighbor != null) { if (neighbor != null) {
neighbor.setNeighborLoaded(-x, -z); neighbor.setNeighborLoaded(-x, -z);
chunk.setNeighborLoaded(x, z); chunk.setNeighborLoaded(x, z);
@@ -0,0 +0,0 @@ public class ChunkProviderServer implements IChunkProvider {
chunk.loadNearby(this, this.chunkGenerator);
world.timings.syncChunkLoadTimer.stopTiming(); // Spigot
}
+ markChunkActive(chunk); // Paper
return chunk;
}
@@ -0,0 +0,0 @@ public class ChunkProviderServer implements IChunkProvider { @@ -0,0 +0,0 @@ public class ChunkProviderServer implements IChunkProvider {
if (!this.world.savingDisabled) { if (!this.world.savingDisabled) {
// CraftBukkit start // CraftBukkit start
@ -148,19 +162,66 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
} }
+ +
+ // Paper start + // Paper start
+ public class ChunkUnloadQueue extends java.util.LinkedList<Chunk> { + public static void markChunkActive(Chunk chunk) {
+ public void remove(int x, int z) { + if (chunk != null) {
+ // nothing! Just to reduce diff + chunk.isChunkActive = true;
+ } + }
+ public void add(int x, int z) { + }
+ public class ChunkUnloadQueue extends LongHashSet { // Provide compat with NMS plugins
+ private java.util.LinkedList<Chunk> unloadQueue = new java.util.LinkedList<Chunk>();
+
+ @Override
+ public boolean isEmpty() {
+ return unloadQueue.isEmpty();
+ }
+
+ @Override
+ public boolean contains(long value) {
+ throw new UnsupportedOperationException("contains on unload queue");
+ }
+
+ @Override
+ public boolean add(long value) {
+ throw new UnsupportedOperationException("add on unload queue");
+ }
+
+ @Override
+ public boolean remove(long value) {
+ throw new UnsupportedOperationException("remove on unload queue");
+ }
+
+ @Override
+ public int size() {
+ return unloadQueue.size();
+ }
+
+ @Override
+ public Iterator iterator() {
+ return unloadQueue.iterator();
+ }
+
+ @Override
+ public boolean contains(int x, int z) {
+ final Chunk chunk = chunks.get(LongHash.toLong(x, z));
+ return (chunk != null && chunk.isInUnloadQueue);
+ }
+
+ public void remove(int x, int z) {
+ final Chunk chunk = chunks.get(LongHash.toLong(x, z));
+ if (chunk != null) {
+ chunk.isChunkActive = true;
+ }
+ }
+ public boolean add(int x, int z) {
+ final Chunk chunk = chunks.get(LongHash.toLong(x, z)); + final Chunk chunk = chunks.get(LongHash.toLong(x, z));
+ if (chunk != null) { + if (chunk != null) {
+ chunk.isChunkActive = false; + chunk.isChunkActive = false;
+ if (!chunk.isInUnloadQueue) { + if (!chunk.isInUnloadQueue) {
+ chunk.isInUnloadQueue = true; + chunk.isInUnloadQueue = true;
+ add(chunk); + return unloadQueue.add(chunk);
+ } + }
+ } + }
+ return false;
+ } + }
+ } + }
+ // Paper end + // Paper end
@ -183,7 +244,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
--- a/src/main/java/net/minecraft/server/World.java --- a/src/main/java/net/minecraft/server/World.java
+++ b/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 { @@ -0,0 +0,0 @@ public abstract class World implements IBlockAccess {
} // Paper end
public Chunk getChunkIfLoaded(int x, int z) { public Chunk getChunkIfLoaded(int x, int z) {
- return ((ChunkProviderServer) this.chunkProvider).getChunkIfLoaded(x, z); - return ((ChunkProviderServer) this.chunkProvider).getChunkIfLoaded(x, z);
@ -222,14 +283,13 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
neighbor.setNeighborUnloaded(-xx, -zz); neighbor.setNeighborUnloaded(-xx, -zz);
chunk.setNeighborUnloaded(xx, zz); chunk.setNeighborUnloaded(xx, zz);
@@ -0,0 +0,0 @@ public class CraftWorld implements World { @@ -0,0 +0,0 @@ public class CraftWorld implements World {
world.timings.syncChunkLoadTimer.startTiming(); // Spigot // Use the default variant of loadChunk when generate == true.
chunk = world.getChunkProviderServer().getOrLoadChunkAt(x, z); return world.getChunkProviderServer().getChunkAt(x, z) != null;
world.timings.syncChunkLoadTimer.stopTiming(); // Spigot }
- } + if (true) { return world.getChunkProviderServer().getOrLoadChunkAt(x, z) != null; } // Paper
+ } else { chunk.isChunkActive = true; } // Paper
return chunk != null;
}
world.getChunkProviderServer().unloadQueue.remove(x, z);
net.minecraft.server.Chunk chunk = world.getChunkProviderServer().chunks.get(LongHash.toLong(x, z));
@@ -0,0 +0,0 @@ public class CraftWorld implements World { @@ -0,0 +0,0 @@ public class CraftWorld implements World {
continue; continue;
} }
@ -244,7 +304,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
// Already unloading? // Already unloading?
- if (cps.unloadQueue.contains(chunk.locX, chunk.locZ)) { - if (cps.unloadQueue.contains(chunk.locX, chunk.locZ)) {
+ if (!chunk.isChunkActive) { // Paper + if (chunk.isInUnloadQueue) { // Paper
continue; continue;
} }
@ -265,12 +325,25 @@ diff --git a/src/main/java/org/spigotmc/ActivationRange.java b/src/main/java/org
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/org/spigotmc/ActivationRange.java --- a/src/main/java/org/spigotmc/ActivationRange.java
+++ b/src/main/java/org/spigotmc/ActivationRange.java +++ b/src/main/java/org/spigotmc/ActivationRange.java
@@ -0,0 +0,0 @@ public class ActivationRange
{
for ( int j1 = k; j1 <= l; ++j1 )
{
- if ( world.getWorld().isChunkLoaded( i1, j1 ) )
- {
- activateChunkEntities( world.getChunkAt( i1, j1 ) );
+ Chunk chunk = world.getChunkIfActive(i1, j1); // Paper
+ if (chunk != null) { // Paper
+ activateChunkEntities( chunk ); // Paper
}
}
}
@@ -0,0 +0,0 @@ public class ActivationRange @@ -0,0 +0,0 @@ public class ActivationRange
int x = MathHelper.floor( entity.locX ); int x = MathHelper.floor( entity.locX );
int z = MathHelper.floor( entity.locZ ); int z = MathHelper.floor( entity.locZ );
// Make sure not on edge of unloaded chunk // Make sure not on edge of unloaded chunk
- Chunk chunk = entity.world.getChunkIfLoaded( x >> 4, z >> 4 ); - Chunk chunk = entity.world.getChunkIfLoaded( x >> 4, z >> 4 );
+ Chunk chunk = entity.world.getChunkIfActive( x >> 4, z >> 4 ); // Paper + Chunk chunk = isActive ? entity.world.getChunkIfActive( x >> 4, z >> 4 ) : null; // Paper
if ( isActive && !( chunk != null && chunk.areNeighborsLoaded( 1 ) ) ) if ( isActive && !( chunk != null && chunk.areNeighborsLoaded( 1 ) ) )
{ {
isActive = false; isActive = false;