mirror of
https://github.com/PaperMC/Paper.git
synced 2024-08-31 17:20:11 +02:00
228 lines
14 KiB
Diff
228 lines
14 KiB
Diff
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
|
Date: Sun, 21 Mar 2021 11:22:10 -0700
|
|
Subject: [PATCH] Do not copy visible chunks
|
|
|
|
For servers with a lot of chunk holders, copying for each
|
|
tickDistanceManager call can take up quite a bit in
|
|
the function. I saw approximately 1/3rd of the function
|
|
on the copy.
|
|
|
|
diff --git a/src/main/java/com/destroystokyo/paper/PaperCommand.java b/src/main/java/com/destroystokyo/paper/PaperCommand.java
|
|
index 4d7575087947f3b199dd895cd9aa02a7d61768b1..315bd2408e4a45993c9b2572e0ab5260a70522ec 100644
|
|
--- a/src/main/java/com/destroystokyo/paper/PaperCommand.java
|
|
+++ b/src/main/java/com/destroystokyo/paper/PaperCommand.java
|
|
@@ -476,7 +476,7 @@ public class PaperCommand extends Command {
|
|
int ticking = 0;
|
|
int entityTicking = 0;
|
|
|
|
- for (ChunkHolder chunk : world.getChunkSource().chunkMap.updatingChunkMap.values()) {
|
|
+ for (ChunkHolder chunk : world.getChunkSource().chunkMap.updatingChunks.getUpdatingMap().values()) { // Paper - change updating chunks map
|
|
if (chunk.getFullChunkUnchecked() == null) {
|
|
continue;
|
|
}
|
|
diff --git a/src/main/java/net/minecraft/server/MCUtil.java b/src/main/java/net/minecraft/server/MCUtil.java
|
|
index 35949e9c15eb998aa89842d34d0999cd973590e0..15f0c85ba9f4f9666e94e67dde43eb2e945ecfbf 100644
|
|
--- a/src/main/java/net/minecraft/server/MCUtil.java
|
|
+++ b/src/main/java/net/minecraft/server/MCUtil.java
|
|
@@ -619,7 +619,7 @@ public final class MCUtil {
|
|
|
|
ServerLevel world = ((org.bukkit.craftbukkit.CraftWorld)bukkitWorld).getHandle();
|
|
ChunkMap chunkMap = world.getChunkSource().chunkMap;
|
|
- Long2ObjectLinkedOpenHashMap<ChunkHolder> visibleChunks = chunkMap.visibleChunkMap;
|
|
+ Long2ObjectLinkedOpenHashMap<ChunkHolder> visibleChunks = chunkMap.updatingChunks.getVisibleMap(); // Paper
|
|
DistanceManager chunkMapDistance = chunkMap.distanceManager;
|
|
List<ChunkHolder> allChunks = new ArrayList<>(visibleChunks.values());
|
|
List<ServerPlayer> players = world.players;
|
|
diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java
|
|
index 09bb6e14864af68e9833e171a33aa981f51c8569..53399b80e60872224ba6b77f41626b2beef236d2 100644
|
|
--- a/src/main/java/net/minecraft/server/level/ChunkMap.java
|
|
+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java
|
|
@@ -120,9 +120,11 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
|
private static final int MIN_VIEW_DISTANCE = 3;
|
|
public static final int MAX_VIEW_DISTANCE = 33;
|
|
public static final int MAX_CHUNK_DISTANCE = 33 + ChunkStatus.maxDistance();
|
|
+ // Paper start - Don't copy
|
|
+ public final com.destroystokyo.paper.util.map.QueuedChangesMapLong2Object<ChunkHolder> updatingChunks = new com.destroystokyo.paper.util.map.QueuedChangesMapLong2Object<>();
|
|
+ // Paper end - Don't copy
|
|
public static final int FORCED_TICKET_LEVEL = 31;
|
|
- public final Long2ObjectLinkedOpenHashMap<ChunkHolder> updatingChunkMap = new Long2ObjectLinkedOpenHashMap();
|
|
- public volatile Long2ObjectLinkedOpenHashMap<ChunkHolder> visibleChunkMap;
|
|
+ // Paper - Don't copy
|
|
private final Long2ObjectLinkedOpenHashMap<ChunkHolder> pendingUnloads;
|
|
public final LongSet entitiesInLevel;
|
|
public final ServerLevel level;
|
|
@@ -299,7 +301,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
|
boolean unloadingPlayerChunk = false; // Paper - do not allow ticket level changes while unloading chunks
|
|
public ChunkMap(ServerLevel world, LevelStorageSource.LevelStorageAccess session, DataFixer dataFixer, StructureManager structureManager, Executor executor, BlockableEventLoop<Runnable> mainThreadExecutor, LightChunkGetter chunkProvider, ChunkGenerator chunkGenerator, ChunkProgressListener worldGenerationProgressListener, ChunkStatusUpdateListener chunkStatusChangeListener, Supplier<DimensionDataStorage> persistentStateManagerFactory, int viewDistance, boolean dsync) {
|
|
super(session.getDimensionPath(world.dimension()).resolve("region"), dataFixer, dsync);
|
|
- this.visibleChunkMap = this.updatingChunkMap.clone();
|
|
+ // Paper - don't copy
|
|
this.pendingUnloads = new Long2ObjectLinkedOpenHashMap();
|
|
this.entitiesInLevel = new LongOpenHashSet();
|
|
this.toDrop = new LongOpenHashSet();
|
|
@@ -516,12 +518,17 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
|
|
|
@Nullable
|
|
public ChunkHolder getUpdatingChunkIfPresent(long pos) {
|
|
- return (ChunkHolder) this.updatingChunkMap.get(pos);
|
|
+ return this.updatingChunks.getUpdating(pos); // Paper - Don't copy
|
|
}
|
|
|
|
@Nullable
|
|
public ChunkHolder getVisibleChunkIfPresent(long pos) {
|
|
- return (ChunkHolder) this.visibleChunkMap.get(pos);
|
|
+ // Paper start - Don't copy
|
|
+ if (Thread.currentThread() == this.level.thread) {
|
|
+ return this.updatingChunks.getVisible(pos);
|
|
+ }
|
|
+ return this.updatingChunks.getVisibleAsync(pos);
|
|
+ // Paper end - Don't copy
|
|
}
|
|
|
|
protected IntSupplier getChunkQueueLevel(long pos) {
|
|
@@ -683,7 +690,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
|
// Paper end
|
|
}
|
|
|
|
- this.updatingChunkMap.put(pos, holder);
|
|
+ this.updatingChunks.queueUpdate(pos, holder); // Paper - Don't copy
|
|
this.modified = true;
|
|
}
|
|
|
|
@@ -763,7 +770,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
|
|
|
protected void saveAllChunks(boolean flush) {
|
|
if (flush) {
|
|
- List<ChunkHolder> list = (List) this.visibleChunkMap.values().stream().filter(ChunkHolder::wasAccessibleSinceLastSave).peek(ChunkHolder::refreshAccessibility).collect(Collectors.toList());
|
|
+ List<ChunkHolder> list = (List) this.updatingChunks.getVisibleValuesCopy().stream().filter(ChunkHolder::wasAccessibleSinceLastSave).peek(ChunkHolder::refreshAccessibility).collect(Collectors.toList()); // Paper
|
|
MutableBoolean mutableboolean = new MutableBoolean();
|
|
|
|
do {
|
|
@@ -794,7 +801,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
|
//this.flushWorker(); // Paper - nuke IOWorker
|
|
this.level.asyncChunkTaskManager.flush(); // Paper - flush to preserve behavior compat with pre-async behaviour
|
|
} else {
|
|
- this.visibleChunkMap.values().forEach(this::saveChunkIfNeeded);
|
|
+ this.updatingChunks.getVisibleValuesCopy().forEach(this::saveChunkIfNeeded); // Paper
|
|
}
|
|
|
|
}
|
|
@@ -828,7 +835,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
|
while (longiterator.hasNext()) { // Spigot
|
|
long j = longiterator.nextLong();
|
|
longiterator.remove(); // Spigot
|
|
- ChunkHolder playerchunk = (ChunkHolder) this.updatingChunkMap.remove(j);
|
|
+ ChunkHolder playerchunk = this.updatingChunks.queueRemove(j); // Paper - Don't copy
|
|
|
|
if (playerchunk != null) {
|
|
this.pendingUnloads.put(j, playerchunk);
|
|
@@ -854,7 +861,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
|
}
|
|
|
|
int l = 0;
|
|
- ObjectIterator objectiterator = this.visibleChunkMap.values().iterator();
|
|
+ Iterator objectiterator = this.updatingChunks.getVisibleValuesCopy().iterator(); // Paper
|
|
|
|
while (false && l < 20 && shouldKeepTicking.getAsBoolean() && objectiterator.hasNext()) { // Paper - incremental chunk and player saving
|
|
if (this.saveChunkIfNeeded((ChunkHolder) objectiterator.next())) {
|
|
@@ -933,7 +940,12 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
|
if (!this.modified) {
|
|
return false;
|
|
} else {
|
|
- this.visibleChunkMap = this.updatingChunkMap.clone();
|
|
+ // Paper start - Don't copy
|
|
+ synchronized (this.updatingChunks) {
|
|
+ this.updatingChunks.performUpdates();
|
|
+ }
|
|
+ // Paper end - Don't copy
|
|
+
|
|
this.modified = false;
|
|
return true;
|
|
}
|
|
@@ -1411,7 +1423,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
|
|
|
this.viewDistance = j;
|
|
this.distanceManager.updatePlayerTickets(this.viewDistance + 1);
|
|
- ObjectIterator objectiterator = this.updatingChunkMap.values().iterator();
|
|
+ Iterator objectiterator = this.updatingChunks.getVisibleValuesCopy().iterator(); // Paper
|
|
|
|
while (objectiterator.hasNext()) {
|
|
ChunkHolder playerchunk = (ChunkHolder) objectiterator.next();
|
|
@@ -1454,7 +1466,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
|
}
|
|
|
|
public int size() {
|
|
- return this.visibleChunkMap.size();
|
|
+ return this.updatingChunks.getVisibleMap().size(); // Paper - Don't copy
|
|
}
|
|
|
|
public DistanceManager getDistanceManager() {
|
|
@@ -1462,13 +1474,13 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
|
}
|
|
|
|
protected Iterable<ChunkHolder> getChunks() {
|
|
- return Iterables.unmodifiableIterable(this.visibleChunkMap.values());
|
|
+ return Iterables.unmodifiableIterable(this.updatingChunks.getVisibleValuesCopy()); // Paper
|
|
}
|
|
|
|
void dumpChunks(Writer writer) throws IOException {
|
|
CsvOutput csvwriter = CsvOutput.builder().addColumn("x").addColumn("z").addColumn("level").addColumn("in_memory").addColumn("status").addColumn("full_status").addColumn("accessible_ready").addColumn("ticking_ready").addColumn("entity_ticking_ready").addColumn("ticket").addColumn("spawning").addColumn("block_entity_count").addColumn("ticking_ticket").addColumn("ticking_level").addColumn("block_ticks").addColumn("fluid_ticks").build(writer);
|
|
TickingTracker tickingtracker = this.distanceManager.tickingTracker();
|
|
- ObjectBidirectionalIterator objectbidirectionaliterator = this.visibleChunkMap.long2ObjectEntrySet().iterator();
|
|
+ ObjectBidirectionalIterator objectbidirectionaliterator = this.updatingChunks.getVisibleMap().clone().long2ObjectEntrySet().fastIterator(); // Paper
|
|
|
|
while (objectbidirectionaliterator.hasNext()) {
|
|
Entry<ChunkHolder> entry = (Entry) objectbidirectionaliterator.next();
|
|
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
|
|
index f7d94cb32a178247bbc5f59e5bc31e79f9fcdc4d..ac41bc23d2f7e16bbacdc9b33fcf6c0d706fa023 100644
|
|
--- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
|
|
+++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
|
|
@@ -151,7 +151,7 @@ public class CraftWorld extends CraftRegionAccessor implements World {
|
|
@Override
|
|
public int getTileEntityCount() {
|
|
// We don't use the full world tile entity list, so we must iterate chunks
|
|
- Long2ObjectLinkedOpenHashMap<ChunkHolder> chunks = world.getChunkSource().chunkMap.visibleChunkMap;
|
|
+ Long2ObjectLinkedOpenHashMap<ChunkHolder> chunks = world.getChunkSource().chunkMap.updatingChunks.getVisibleMap(); // Paper - change updating chunks map
|
|
int size = 0;
|
|
for (ChunkHolder playerchunk : chunks.values()) {
|
|
net.minecraft.world.level.chunk.LevelChunk chunk = playerchunk.getTickingChunk();
|
|
@@ -172,7 +172,7 @@ public class CraftWorld extends CraftRegionAccessor implements World {
|
|
public int getChunkCount() {
|
|
int ret = 0;
|
|
|
|
- for (ChunkHolder chunkHolder : world.getChunkSource().chunkMap.visibleChunkMap.values()) {
|
|
+ for (ChunkHolder chunkHolder : world.getChunkSource().chunkMap.updatingChunks.getVisibleMap().values()) { // Paper - change updating chunks map
|
|
if (chunkHolder.getTickingChunk() != null) {
|
|
++ret;
|
|
}
|
|
@@ -346,7 +346,18 @@ public class CraftWorld extends CraftRegionAccessor implements World {
|
|
|
|
@Override
|
|
public Chunk[] getLoadedChunks() {
|
|
- Long2ObjectLinkedOpenHashMap<ChunkHolder> chunks = this.world.getChunkSource().chunkMap.visibleChunkMap;
|
|
+ // Paper start
|
|
+ if (Thread.currentThread() != world.getLevel().thread) {
|
|
+ // Paper start - change updating chunks map
|
|
+ Long2ObjectLinkedOpenHashMap<ChunkHolder> chunks;
|
|
+ synchronized (world.getChunkSource().chunkMap.updatingChunks) {
|
|
+ chunks = world.getChunkSource().chunkMap.updatingChunks.getVisibleMap().clone();
|
|
+ }
|
|
+ return chunks.values().stream().map(ChunkHolder::getFullChunk).filter(Objects::nonNull).map(net.minecraft.world.level.chunk.LevelChunk::getBukkitChunk).toArray(Chunk[]::new);
|
|
+ // Paper end - change updating chunks map
|
|
+ }
|
|
+ // Paper end
|
|
+ Long2ObjectLinkedOpenHashMap<ChunkHolder> chunks = world.getChunkSource().chunkMap.updatingChunks.getVisibleMap(); // Paper - change updating chunks map
|
|
return chunks.values().stream().map(ChunkHolder::getFullChunk).filter(Objects::nonNull).map(net.minecraft.world.level.chunk.LevelChunk::getBukkitChunk).toArray(Chunk[]::new);
|
|
}
|
|
|
|
@@ -422,7 +433,7 @@ public class CraftWorld extends CraftRegionAccessor implements World {
|
|
|
|
@Override
|
|
public boolean refreshChunk(int x, int z) {
|
|
- ChunkHolder playerChunk = this.world.getChunkSource().chunkMap.visibleChunkMap.get(ChunkPos.asLong(x, z));
|
|
+ ChunkHolder playerChunk = this.world.getChunkSource().chunkMap.updatingChunks.getVisibleMap().get(ChunkPos.asLong(x, z));
|
|
if (playerChunk == null) return false;
|
|
|
|
playerChunk.getTickingChunkFuture().thenAccept(either -> {
|