364 lines
14 KiB
Diff
364 lines
14 KiB
Diff
|
From 8dd291089bfd73acfc3a170e496bf34e855b1de1 Mon Sep 17 00:00:00 2001
|
||
|
From: Alfie Cleveland <alfeh@me.com>
|
||
|
Date: Sun, 9 Jul 2017 00:41:19 +0100
|
||
|
Subject: [PATCH] Reimplement FlatMap
|
||
|
|
||
|
|
||
|
diff --git a/src/main/java/net/frozenorb/util/ChunkFlatMap.java b/src/main/java/net/frozenorb/util/ChunkFlatMap.java
|
||
|
new file mode 100644
|
||
|
index 000000000..6d937ec68
|
||
|
--- /dev/null
|
||
|
+++ b/src/main/java/net/frozenorb/util/ChunkFlatMap.java
|
||
|
@@ -0,0 +1,28 @@
|
||
|
+package net.frozenorb.util;
|
||
|
+
|
||
|
+import net.minecraft.server.Chunk;
|
||
|
+
|
||
|
+public class ChunkFlatMap extends FlatMap<Chunk> {
|
||
|
+
|
||
|
+ private Chunk lastChunk;
|
||
|
+
|
||
|
+ @Override
|
||
|
+ public Chunk get(int x, int z) {
|
||
|
+ Chunk last = lastChunk; // have to do this to be somewhat thread-safe-ish
|
||
|
+
|
||
|
+ if (last != null && last.locX == x && last.locZ == z) {
|
||
|
+ return last;
|
||
|
+ }
|
||
|
+
|
||
|
+ return lastChunk = super.get(x, z);
|
||
|
+ }
|
||
|
+
|
||
|
+ @Override
|
||
|
+ public void remove(int x, int z) {
|
||
|
+ if (lastChunk != null && lastChunk.locX == x && lastChunk.locZ == z) {
|
||
|
+ lastChunk = null; // we don't really care for thread safety here, we'd just lose a few cache hits
|
||
|
+ }
|
||
|
+
|
||
|
+ super.remove(x, z);
|
||
|
+ }
|
||
|
+}
|
||
|
diff --git a/src/main/java/net/frozenorb/util/CoordinateChunkHybridMap.java b/src/main/java/net/frozenorb/util/CoordinateChunkHybridMap.java
|
||
|
new file mode 100644
|
||
|
index 000000000..bd912d30b
|
||
|
--- /dev/null
|
||
|
+++ b/src/main/java/net/frozenorb/util/CoordinateChunkHybridMap.java
|
||
|
@@ -0,0 +1,10 @@
|
||
|
+package net.frozenorb.util;
|
||
|
+
|
||
|
+import net.minecraft.server.Chunk;
|
||
|
+
|
||
|
+public class CoordinateChunkHybridMap extends CoordinateObjectHybridMap<Chunk> {
|
||
|
+
|
||
|
+ public CoordinateChunkHybridMap() {
|
||
|
+ flatMap = new ChunkFlatMap();
|
||
|
+ }
|
||
|
+}
|
||
|
diff --git a/src/main/java/net/frozenorb/util/CoordinateObjectHybridMap.java b/src/main/java/net/frozenorb/util/CoordinateObjectHybridMap.java
|
||
|
new file mode 100644
|
||
|
index 000000000..ac015051c
|
||
|
--- /dev/null
|
||
|
+++ b/src/main/java/net/frozenorb/util/CoordinateObjectHybridMap.java
|
||
|
@@ -0,0 +1,56 @@
|
||
|
+package net.frozenorb.util;
|
||
|
+
|
||
|
+import java.util.Collection;
|
||
|
+import java.util.Collections;
|
||
|
+
|
||
|
+import org.bukkit.craftbukkit.util.LongHash;
|
||
|
+
|
||
|
+import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
|
||
|
+
|
||
|
+public class CoordinateObjectHybridMap<T> {
|
||
|
+
|
||
|
+ private Long2ObjectOpenHashMap<T> backingMap = new Long2ObjectOpenHashMap<T>();
|
||
|
+ private Collection<T> values = Collections.unmodifiableCollection(backingMap.values()); // values() is uncached and is simply a view, so we can cache it and make it externally unmodifiable
|
||
|
+
|
||
|
+ protected FlatMap<T> flatMap;
|
||
|
+
|
||
|
+ public CoordinateObjectHybridMap() {
|
||
|
+ this.flatMap = new FlatMap<T>();
|
||
|
+ }
|
||
|
+
|
||
|
+ public boolean contains(int x, int z) {
|
||
|
+ return get(x, z) != null;
|
||
|
+ }
|
||
|
+
|
||
|
+ public T get(int x, int z) {
|
||
|
+ if (x * x < FlatMap.HALF_DIAMETER_SQUARED && z * z < FlatMap.HALF_DIAMETER_SQUARED) {
|
||
|
+ return flatMap.get(x, z);
|
||
|
+ }
|
||
|
+
|
||
|
+ return backingMap.get(LongHash.toLong(x, z));
|
||
|
+ }
|
||
|
+
|
||
|
+ public void remove(int x, int z) {
|
||
|
+ if (x * x < FlatMap.HALF_DIAMETER_SQUARED && z * z < FlatMap.HALF_DIAMETER_SQUARED) {
|
||
|
+ flatMap.put(x, z, null);
|
||
|
+ }
|
||
|
+
|
||
|
+ backingMap.remove(LongHash.toLong(x, z));
|
||
|
+ }
|
||
|
+
|
||
|
+ public void put(int x, int z, T value) {
|
||
|
+ if (x * x < FlatMap.HALF_DIAMETER_SQUARED && z * z < FlatMap.HALF_DIAMETER_SQUARED) {
|
||
|
+ flatMap.put(x, z, value);
|
||
|
+ }
|
||
|
+
|
||
|
+ backingMap.put(LongHash.toLong(x, z), value);
|
||
|
+ }
|
||
|
+
|
||
|
+ public int size() {
|
||
|
+ return backingMap.size();
|
||
|
+ }
|
||
|
+
|
||
|
+ public Collection<T> values() {
|
||
|
+ return values;
|
||
|
+ }
|
||
|
+}
|
||
|
diff --git a/src/main/java/net/frozenorb/util/FlatMap.java b/src/main/java/net/frozenorb/util/FlatMap.java
|
||
|
new file mode 100644
|
||
|
index 000000000..6a5c36fa2
|
||
|
--- /dev/null
|
||
|
+++ b/src/main/java/net/frozenorb/util/FlatMap.java
|
||
|
@@ -0,0 +1,30 @@
|
||
|
+package net.frozenorb.util;
|
||
|
+
|
||
|
+public class FlatMap<V> {
|
||
|
+
|
||
|
+ private static final int DIAMETER = 4096;
|
||
|
+ private static final int HALF_DIAMETER = DIAMETER / 2;
|
||
|
+ private final Object[] flatLookup;
|
||
|
+
|
||
|
+ public static final int HALF_DIAMETER_SQUARED = HALF_DIAMETER * HALF_DIAMETER;
|
||
|
+
|
||
|
+ public FlatMap() {
|
||
|
+ this.flatLookup = new Object[DIAMETER * DIAMETER];
|
||
|
+ }
|
||
|
+
|
||
|
+ public void put(final int msw, final int lsw, final V value) {
|
||
|
+ this.flatLookup[(msw + HALF_DIAMETER) * DIAMETER + (lsw + HALF_DIAMETER)] = value;
|
||
|
+ }
|
||
|
+
|
||
|
+ public void remove(final int msw, final int lsw) {
|
||
|
+ this.put(msw, lsw, null);
|
||
|
+ }
|
||
|
+
|
||
|
+ public boolean contains(final int msw, final int lsw) {
|
||
|
+ return this.get(msw, lsw) != null;
|
||
|
+ }
|
||
|
+
|
||
|
+ public V get(final int msw, final int lsw) {
|
||
|
+ return (V) this.flatLookup[(msw + HALF_DIAMETER) * DIAMETER + (lsw + HALF_DIAMETER)];
|
||
|
+ }
|
||
|
+}
|
||
|
diff --git a/src/main/java/net/minecraft/server/ChunkProviderServer.java b/src/main/java/net/minecraft/server/ChunkProviderServer.java
|
||
|
index b4ddc3bbf..5a061b274 100644
|
||
|
--- a/src/main/java/net/minecraft/server/ChunkProviderServer.java
|
||
|
+++ b/src/main/java/net/minecraft/server/ChunkProviderServer.java
|
||
|
@@ -1,28 +1,22 @@
|
||
|
package net.minecraft.server;
|
||
|
|
||
|
-import java.io.IOException;
|
||
|
-import java.util.ArrayList;
|
||
|
-import java.util.Collections;
|
||
|
import java.util.Iterator;
|
||
|
import java.util.List;
|
||
|
-import java.util.Set;
|
||
|
-import java.util.concurrent.ConcurrentHashMap;
|
||
|
-
|
||
|
-import net.minecraft.util.com.google.common.collect.Lists;
|
||
|
-import org.apache.logging.log4j.LogManager;
|
||
|
-import org.apache.logging.log4j.Logger;
|
||
|
-
|
||
|
// CraftBukkit start
|
||
|
import java.util.Random;
|
||
|
|
||
|
+import org.apache.logging.log4j.LogManager;
|
||
|
+import org.apache.logging.log4j.Logger;
|
||
|
import org.bukkit.Server;
|
||
|
import org.bukkit.craftbukkit.chunkio.ChunkIOExecutor;
|
||
|
import org.bukkit.craftbukkit.util.LongHash;
|
||
|
import org.bukkit.craftbukkit.util.LongHashSet;
|
||
|
-import org.bukkit.craftbukkit.util.LongObjectHashMap;
|
||
|
import org.bukkit.event.world.ChunkUnloadEvent;
|
||
|
// CraftBukkit end
|
||
|
|
||
|
+import net.frozenorb.util.CoordinateChunkHybridMap;
|
||
|
+import net.frozenorb.util.CoordinateObjectHybridMap;
|
||
|
+
|
||
|
public class ChunkProviderServer implements IChunkProvider {
|
||
|
|
||
|
private static final Logger b = LogManager.getLogger();
|
||
|
@@ -32,7 +26,8 @@ public class ChunkProviderServer implements IChunkProvider {
|
||
|
public IChunkProvider chunkProvider;
|
||
|
private IChunkLoader f;
|
||
|
public boolean forceChunkLoad = false; // true -> false
|
||
|
- public LongObjectHashMap<Chunk> chunks = new LongObjectHashMap<Chunk>();
|
||
|
+ //public LongObjectHashMap<Chunk> chunks = new LongObjectHashMap<Chunk>();
|
||
|
+ public CoordinateObjectHybridMap<Chunk> chunks = new CoordinateChunkHybridMap(); // MineHQ
|
||
|
public WorldServer world;
|
||
|
// CraftBukkit end
|
||
|
|
||
|
@@ -44,7 +39,7 @@ public class ChunkProviderServer implements IChunkProvider {
|
||
|
}
|
||
|
|
||
|
public boolean isChunkLoaded(int i, int j) {
|
||
|
- return this.chunks.containsKey(LongHash.toLong(i, j)); // CraftBukkit
|
||
|
+ return this.chunks.contains(i, j); // CraftBukkit // MineHQ
|
||
|
}
|
||
|
|
||
|
// CraftBukkit start - Change return type to Collection and return the values of our chunk map
|
||
|
@@ -56,7 +51,7 @@ public class ChunkProviderServer implements IChunkProvider {
|
||
|
|
||
|
public void queueUnload(int i, int j) {
|
||
|
// PaperSpigot start - Asynchronous lighting updates
|
||
|
- Chunk chunk = this.chunks.get(LongHash.toLong(i, j));
|
||
|
+ Chunk chunk = this.chunks.get(i, j); // MineHQ
|
||
|
if (chunk != null && chunk.world.paperSpigotConfig.useAsyncLighting && (chunk.pendingLightUpdates.get() > 0 || chunk.world.getTime() - chunk.lightUpdateTime < 20)) {
|
||
|
return;
|
||
|
}
|
||
|
@@ -82,20 +77,22 @@ public class ChunkProviderServer implements IChunkProvider {
|
||
|
if (k < -short1 || k > short1 || l < -short1 || l > short1 || !(this.world.keepSpawnInMemory)) { // Added 'this.world.keepSpawnInMemory'
|
||
|
this.unloadQueue.add(i, j);
|
||
|
|
||
|
- Chunk c = this.chunks.get(LongHash.toLong(i, j));
|
||
|
- if (c != null) {
|
||
|
- c.mustSave = true;
|
||
|
+ // MineHQ start - don't lookup twice
|
||
|
+ if (chunk != null) {
|
||
|
+ chunk.mustSave = true;
|
||
|
}
|
||
|
+ // MineHQ end
|
||
|
}
|
||
|
// CraftBukkit end
|
||
|
} else {
|
||
|
// CraftBukkit start
|
||
|
this.unloadQueue.add(i, j);
|
||
|
|
||
|
- Chunk c = this.chunks.get(LongHash.toLong(i, j));
|
||
|
- if (c != null) {
|
||
|
- c.mustSave = true;
|
||
|
+ // MineHQ start - don't lookup twice
|
||
|
+ if (chunk != null) {
|
||
|
+ chunk.mustSave = true;
|
||
|
}
|
||
|
+ // MineHQ end
|
||
|
// CraftBukkit end
|
||
|
}
|
||
|
}
|
||
|
@@ -112,7 +109,7 @@ public class ChunkProviderServer implements IChunkProvider {
|
||
|
|
||
|
// CraftBukkit start - Add async variant, provide compatibility
|
||
|
public Chunk getChunkIfLoaded(int x, int z) {
|
||
|
- return this.chunks.get(LongHash.toLong(x, z));
|
||
|
+ return this.chunks.get(x, z); // MineHQ
|
||
|
}
|
||
|
|
||
|
public Chunk getChunkAt(int i, int j) {
|
||
|
@@ -121,7 +118,7 @@ public class ChunkProviderServer implements IChunkProvider {
|
||
|
|
||
|
public Chunk getChunkAt(int i, int j, Runnable runnable) {
|
||
|
this.unloadQueue.remove(i, j);
|
||
|
- Chunk chunk = this.chunks.get(LongHash.toLong(i, j));
|
||
|
+ Chunk chunk = this.chunks.get(i, j); // MineHQ
|
||
|
ChunkRegionLoader loader = null;
|
||
|
|
||
|
if (this.f instanceof ChunkRegionLoader) {
|
||
|
@@ -150,7 +147,7 @@ public class ChunkProviderServer implements IChunkProvider {
|
||
|
|
||
|
public Chunk originalGetChunkAt(int i, int j) {
|
||
|
this.unloadQueue.remove(i, j);
|
||
|
- Chunk chunk = (Chunk) this.chunks.get(LongHash.toLong(i, j));
|
||
|
+ Chunk chunk = (Chunk) this.chunks.get(i, j); // MineHQ
|
||
|
boolean newChunk = false;
|
||
|
|
||
|
if (chunk == null) {
|
||
|
@@ -175,7 +172,7 @@ public class ChunkProviderServer implements IChunkProvider {
|
||
|
newChunk = true; // CraftBukkit
|
||
|
}
|
||
|
|
||
|
- this.chunks.put(LongHash.toLong(i, j), chunk); // CraftBukkit
|
||
|
+ this.chunks.put(i, j, chunk); // CraftBukkit // MineHQ
|
||
|
chunk.addEntities();
|
||
|
|
||
|
// CraftBukkit start
|
||
|
@@ -213,7 +210,7 @@ public class ChunkProviderServer implements IChunkProvider {
|
||
|
|
||
|
public Chunk getOrCreateChunk(int i, int j) {
|
||
|
// CraftBukkit start
|
||
|
- Chunk chunk = (Chunk) this.chunks.get(LongHash.toLong(i, j));
|
||
|
+ Chunk chunk = (Chunk) this.chunks.get(i, j); // MineHQ
|
||
|
|
||
|
chunk = chunk == null ? (!this.world.isLoading && !this.forceChunkLoad ? this.emptyChunk : this.getChunkAt(i, j)) : chunk;
|
||
|
if (chunk == this.emptyChunk) return chunk;
|
||
|
@@ -360,7 +357,11 @@ public class ChunkProviderServer implements IChunkProvider {
|
||
|
Server server = this.world.getServer();
|
||
|
for (int i = 0; i < 100 && !this.unloadQueue.isEmpty(); i++) {
|
||
|
long chunkcoordinates = this.unloadQueue.popFirst();
|
||
|
- Chunk chunk = this.chunks.get(chunkcoordinates);
|
||
|
+ // MineHQ start
|
||
|
+ int locX = LongHash.msw(chunkcoordinates);
|
||
|
+ int locZ = LongHash.lsw(chunkcoordinates);
|
||
|
+ Chunk chunk = this.chunks.get(locX, locZ);
|
||
|
+ // MineHQ end
|
||
|
if (chunk == null) continue;
|
||
|
|
||
|
ChunkUnloadEvent event = new ChunkUnloadEvent(chunk.bukkitChunk);
|
||
|
@@ -370,7 +371,7 @@ public class ChunkProviderServer implements IChunkProvider {
|
||
|
chunk.removeEntities();
|
||
|
this.saveChunk(chunk);
|
||
|
this.saveChunkNOP(chunk);
|
||
|
- this.chunks.remove(chunkcoordinates); // CraftBukkit
|
||
|
+ this.chunks.remove(locX, locZ); // CraftBukkit // MineHQ
|
||
|
}
|
||
|
|
||
|
// this.unloadQueue.remove(olong);
|
||
|
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
|
||
|
index 8f4a96fe6..7e5ae9e4e 100644
|
||
|
--- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
|
||
|
+++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
|
||
|
@@ -232,7 +232,7 @@ public class CraftWorld implements World {
|
||
|
}
|
||
|
|
||
|
world.chunkProviderServer.unloadQueue.remove(x, z);
|
||
|
- world.chunkProviderServer.chunks.remove(LongHash.toLong(x, z));
|
||
|
+ world.chunkProviderServer.chunks.remove(x, z); // MineHQ
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
@@ -290,7 +290,7 @@ public class CraftWorld implements World {
|
||
|
}
|
||
|
|
||
|
world.chunkProviderServer.unloadQueue.remove(x, z);
|
||
|
- net.minecraft.server.Chunk chunk = world.chunkProviderServer.chunks.get(LongHash.toLong(x, z));
|
||
|
+ net.minecraft.server.Chunk chunk = world.chunkProviderServer.chunks.get(x, z); // MineHQ
|
||
|
|
||
|
if (chunk == null) {
|
||
|
world.timings.syncChunkLoadTimer.startTiming(); // Spigot
|
||
|
@@ -304,7 +304,7 @@ public class CraftWorld implements World {
|
||
|
|
||
|
private void chunkLoadPostProcess(net.minecraft.server.Chunk chunk, int x, int z) {
|
||
|
if (chunk != null) {
|
||
|
- world.chunkProviderServer.chunks.put(LongHash.toLong(x, z), chunk);
|
||
|
+ world.chunkProviderServer.chunks.put(x, z, chunk); // MineHQ
|
||
|
|
||
|
chunk.addEntities();
|
||
|
|
||
|
diff --git a/src/main/java/org/bukkit/craftbukkit/chunkio/ChunkIOProvider.java b/src/main/java/org/bukkit/craftbukkit/chunkio/ChunkIOProvider.java
|
||
|
index c249e776d..8c6f2a221 100644
|
||
|
--- a/src/main/java/org/bukkit/craftbukkit/chunkio/ChunkIOProvider.java
|
||
|
+++ b/src/main/java/org/bukkit/craftbukkit/chunkio/ChunkIOProvider.java
|
||
|
@@ -36,7 +36,7 @@ class ChunkIOProvider implements AsynchronousExecutor.CallBackProvider<QueuedChu
|
||
|
|
||
|
queuedChunk.loader.loadEntities(chunk, queuedChunk.compound.getCompound("Level"), queuedChunk.world);
|
||
|
chunk.lastSaved = queuedChunk.provider.world.getTime();
|
||
|
- queuedChunk.provider.chunks.put(LongHash.toLong(queuedChunk.x, queuedChunk.z), chunk);
|
||
|
+ queuedChunk.provider.chunks.put(queuedChunk.x, queuedChunk.z, chunk); // MineHQ
|
||
|
chunk.addEntities();
|
||
|
|
||
|
if (queuedChunk.provider.chunkProvider != null) {
|
||
|
--
|
||
|
2.13.3
|
||
|
|