mirror of
https://github.com/PaperMC/Paper.git
synced 2024-12-31 00:20:44 +01:00
Finish chunk tick iteration optimisation port from Moonrise
This commit is contained in:
parent
077f411288
commit
e43b9191b2
3 changed files with 78 additions and 383 deletions
|
@ -25176,6 +25176,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||||
+ return load ? this.syncLoad(chunkX, chunkZ, toStatus) : null;
|
+ return load ? this.syncLoad(chunkX, chunkZ, toStatus) : null;
|
||||||
+ }
|
+ }
|
||||||
+ // Paper end - rewrite chunk system
|
+ // Paper end - rewrite chunk system
|
||||||
|
+ private ServerChunkCache.ChunkAndHolder[] iterationCopy; // Paper - chunk tick iteration optimisations
|
||||||
|
|
||||||
public ServerChunkCache(ServerLevel world, LevelStorageSource.LevelStorageAccess session, DataFixer dataFixer, StructureTemplateManager structureTemplateManager, Executor workerExecutor, ChunkGenerator chunkGenerator, int viewDistance, int simulationDistance, boolean dsync, ChunkProgressListener worldGenerationProgressListener, ChunkStatusUpdateListener chunkStatusChangeListener, Supplier<DimensionDataStorage> persistentStateManagerFactory) {
|
public ServerChunkCache(ServerLevel world, LevelStorageSource.LevelStorageAccess session, DataFixer dataFixer, StructureTemplateManager structureTemplateManager, Executor workerExecutor, ChunkGenerator chunkGenerator, int viewDistance, int simulationDistance, boolean dsync, ChunkProgressListener worldGenerationProgressListener, ChunkStatusUpdateListener chunkStatusChangeListener, Supplier<DimensionDataStorage> persistentStateManagerFactory) {
|
||||||
this.level = world;
|
this.level = world;
|
||||||
|
@ -25210,13 +25211,13 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||||
- }
|
- }
|
||||||
- // Paper end - Perf: Optimise getChunkAt calls for loaded chunks
|
- // Paper end - Perf: Optimise getChunkAt calls for loaded chunks
|
||||||
- ProfilerFiller gameprofilerfiller = this.level.getProfiler();
|
- ProfilerFiller gameprofilerfiller = this.level.getProfiler();
|
||||||
|
-
|
||||||
|
- gameprofilerfiller.incrementCounter("getChunk");
|
||||||
|
- long k = ChunkPos.asLong(x, z);
|
||||||
+ // Paper start - rewrite chunk system
|
+ // Paper start - rewrite chunk system
|
||||||
+ if (leastStatus == ChunkStatus.FULL) {
|
+ if (leastStatus == ChunkStatus.FULL) {
|
||||||
+ final LevelChunk ret = this.fullChunks.get(ca.spottedleaf.moonrise.common.util.CoordinateUtils.getChunkKey(x, z));
|
+ final LevelChunk ret = this.fullChunks.get(ca.spottedleaf.moonrise.common.util.CoordinateUtils.getChunkKey(x, z));
|
||||||
|
|
||||||
- gameprofilerfiller.incrementCounter("getChunk");
|
|
||||||
- long k = ChunkPos.asLong(x, z);
|
|
||||||
-
|
|
||||||
- for (int l = 0; l < 4; ++l) {
|
- for (int l = 0; l < 4; ++l) {
|
||||||
- if (k == this.lastChunkPos[l] && leastStatus == this.lastChunkStatus[l]) {
|
- if (k == this.lastChunkPos[l] && leastStatus == this.lastChunkStatus[l]) {
|
||||||
- ChunkAccess ichunkaccess = this.lastChunk[l];
|
- ChunkAccess ichunkaccess = this.lastChunk[l];
|
||||||
|
@ -25431,6 +25432,44 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||||
long i = this.level.getGameTime();
|
long i = this.level.getGameTime();
|
||||||
long j = i - this.lastInhabitedUpdate;
|
long j = i - this.lastInhabitedUpdate;
|
||||||
|
|
||||||
|
@@ -0,0 +0,0 @@ public class ServerChunkCache extends ChunkSource {
|
||||||
|
|
||||||
|
gameprofilerfiller.push("pollingChunks");
|
||||||
|
gameprofilerfiller.push("filteringLoadedChunks");
|
||||||
|
- List<ServerChunkCache.ChunkAndHolder> list = Lists.newArrayListWithCapacity(this.chunkMap.size());
|
||||||
|
- Iterator iterator = this.chunkMap.getChunks().iterator();
|
||||||
|
- if (this.level.getServer().tickRateManager().runsNormally()) this.level.timings.chunkTicks.startTiming(); // Paper
|
||||||
|
+ // Paper start - chunk tick iteration optimisations
|
||||||
|
+ List<ServerChunkCache.ChunkAndHolder> list;
|
||||||
|
+ {
|
||||||
|
+ final ca.spottedleaf.moonrise.common.list.ReferenceList<net.minecraft.server.level.ServerChunkCache.ChunkAndHolder> tickingChunks =
|
||||||
|
+ ((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel) this.level).moonrise$getTickingChunks();
|
||||||
|
|
||||||
|
- while (iterator.hasNext()) {
|
||||||
|
- ChunkHolder playerchunk = (ChunkHolder) iterator.next();
|
||||||
|
- LevelChunk chunk = playerchunk.getTickingChunk();
|
||||||
|
+ final ServerChunkCache.ChunkAndHolder[] raw = tickingChunks.getRawDataUnchecked();
|
||||||
|
+ final int size = tickingChunks.size();
|
||||||
|
|
||||||
|
- if (chunk != null) {
|
||||||
|
- list.add(new ServerChunkCache.ChunkAndHolder(chunk, playerchunk));
|
||||||
|
+ if (this.iterationCopy == null || this.iterationCopy.length < size) {
|
||||||
|
+ this.iterationCopy = new ServerChunkCache.ChunkAndHolder[raw.length];
|
||||||
|
}
|
||||||
|
+ System.arraycopy(raw, 0, this.iterationCopy, 0, size);
|
||||||
|
+
|
||||||
|
+ list = it.unimi.dsi.fastutil.objects.ObjectArrayList.wrap(
|
||||||
|
+ this.iterationCopy, size
|
||||||
|
+ );
|
||||||
|
}
|
||||||
|
+ // Paper end - chunk tick iteration optimisations
|
||||||
|
+ Iterator iterator = null; // Paper - chunk tick iteration optimisations
|
||||||
|
+ if (this.level.getServer().tickRateManager().runsNormally()) this.level.timings.chunkTicks.startTiming(); // Paper
|
||||||
|
+
|
||||||
|
+ // Paper - chunk tick iteration optimisations
|
||||||
|
|
||||||
|
if (this.level.tickRateManager().runsNormally()) {
|
||||||
|
gameprofilerfiller.popPush("naturalSpawnCount");
|
||||||
@@ -0,0 +0,0 @@ public class ServerChunkCache extends ChunkSource {
|
@@ -0,0 +0,0 @@ public class ServerChunkCache extends ChunkSource {
|
||||||
LevelChunk chunk1 = chunkproviderserver_a.chunk;
|
LevelChunk chunk1 = chunkproviderserver_a.chunk;
|
||||||
ChunkPos chunkcoordintpair = chunk1.getPos();
|
ChunkPos chunkcoordintpair = chunk1.getPos();
|
||||||
|
@ -25456,6 +25495,34 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||||
@@ -0,0 +0,0 @@ public class ServerChunkCache extends ChunkSource {
|
@@ -0,0 +0,0 @@ public class ServerChunkCache extends ChunkSource {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gameprofilerfiller.popPush("broadcast");
|
||||||
|
- list.forEach((chunkproviderserver_a1) -> {
|
||||||
|
- this.level.timings.broadcastChunkUpdates.startTiming(); // Paper - timing
|
||||||
|
- chunkproviderserver_a1.holder.broadcastChanges(chunkproviderserver_a1.chunk);
|
||||||
|
- this.level.timings.broadcastChunkUpdates.stopTiming(); // Paper - timing
|
||||||
|
- });
|
||||||
|
+ // Paper start - chunk tick iteration optimisations
|
||||||
|
+ this.level.timings.broadcastChunkUpdates.startTiming(); // Paper - timing
|
||||||
|
+ {
|
||||||
|
+ final it.unimi.dsi.fastutil.objects.ObjectArrayList<net.minecraft.server.level.ServerChunkCache.ChunkAndHolder> chunks = (it.unimi.dsi.fastutil.objects.ObjectArrayList<net.minecraft.server.level.ServerChunkCache.ChunkAndHolder>)list;
|
||||||
|
+ final ServerChunkCache.ChunkAndHolder[] raw = chunks.elements();
|
||||||
|
+ final int size = chunks.size();
|
||||||
|
+
|
||||||
|
+ Objects.checkFromToIndex(0, size, raw.length);
|
||||||
|
+ for (int idx = 0; idx < size; ++idx) {
|
||||||
|
+ final ServerChunkCache.ChunkAndHolder holder = raw[idx];
|
||||||
|
+ raw[idx] = null;
|
||||||
|
+
|
||||||
|
+ holder.holder().broadcastChanges(holder.chunk());
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ this.level.timings.broadcastChunkUpdates.stopTiming(); // Paper - timing
|
||||||
|
+ // Paper end - chunk tick iteration optimisations
|
||||||
|
gameprofilerfiller.pop();
|
||||||
|
gameprofilerfiller.pop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void getFullChunk(long pos, Consumer<LevelChunk> chunkConsumer) {
|
private void getFullChunk(long pos, Consumer<LevelChunk> chunkConsumer) {
|
||||||
- ChunkHolder playerchunk = this.getVisibleChunkIfPresent(pos);
|
- ChunkHolder playerchunk = this.getVisibleChunkIfPresent(pos);
|
||||||
-
|
-
|
||||||
|
|
|
@ -61,6 +61,14 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||||
this.level.timings.countNaturalMobs.stopTiming(); // Paper - timings
|
this.level.timings.countNaturalMobs.stopTiming(); // Paper - timings
|
||||||
|
|
||||||
this.lastSpawnState = spawnercreature_d;
|
this.lastSpawnState = spawnercreature_d;
|
||||||
|
gameprofilerfiller.popPush("spawnAndTick");
|
||||||
|
boolean flag = this.level.getGameRules().getBoolean(GameRules.RULE_DOMOBSPAWNING) && !this.level.players().isEmpty(); // CraftBukkit
|
||||||
|
|
||||||
|
- Util.shuffle(list, this.level.random);
|
||||||
|
+ if (!this.level.paperConfig().entities.spawning.perPlayerMobSpawns) Util.shuffle(list, this.level.random); // Paper - per player mob spawns - do not need this when per-player is enabled
|
||||||
|
// Paper start - PlayerNaturallySpawnCreaturesEvent
|
||||||
|
int chunkRange = level.spigotConfig.mobSpawnRange;
|
||||||
|
chunkRange = (chunkRange > level.spigotConfig.viewDistance) ? (byte) level.spigotConfig.viewDistance : chunkRange;
|
||||||
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||||
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||||
|
|
|
@ -1,380 +0,0 @@
|
||||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
||||||
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
|
||||||
Date: Sat, 23 Sep 2023 21:36:36 -0700
|
|
||||||
Subject: [PATCH] Optimise chunk tick iteration
|
|
||||||
|
|
||||||
When per-player mob spawning is enabled we do not need to randomly
|
|
||||||
shuffle the chunk list. Additionally, we can use the NearbyPlayers
|
|
||||||
class to quickly retrieve nearby players instead of possible
|
|
||||||
searching all players on the server.
|
|
||||||
|
|
||||||
diff --git a/src/main/java/io/papermc/paper/util/player/NearbyPlayers.java b/src/main/java/io/papermc/paper/util/player/NearbyPlayers.java
|
|
||||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
|
||||||
--- a/src/main/java/io/papermc/paper/util/player/NearbyPlayers.java
|
|
||||||
+++ b/src/main/java/io/papermc/paper/util/player/NearbyPlayers.java
|
|
||||||
@@ -0,0 +0,0 @@ public final class NearbyPlayers {
|
|
||||||
GENERAL_SMALL,
|
|
||||||
GENERAL_REALLY_SMALL,
|
|
||||||
TICK_VIEW_DISTANCE,
|
|
||||||
- VIEW_DISTANCE;
|
|
||||||
+ VIEW_DISTANCE, // Paper - optimise chunk iteration
|
|
||||||
+ SPAWN_RANGE, // Paper - optimise chunk iteration
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final NearbyMapType[] MOB_TYPES = NearbyMapType.values();
|
|
||||||
@@ -0,0 +0,0 @@ public final class NearbyPlayers {
|
|
||||||
private static final int GENERAL_AREA_VIEW_DISTANCE = 33;
|
|
||||||
private static final int GENERAL_SMALL_VIEW_DISTANCE = 10;
|
|
||||||
private static final int GENERAL_REALLY_SMALL_VIEW_DISTANCE = 3;
|
|
||||||
+ private static final int SPAWN_RANGE_VIEW_DISTANCE = net.minecraft.server.level.DistanceManager.MOB_SPAWN_RANGE; // Paper - optimise chunk iteration
|
|
||||||
|
|
||||||
public static final int GENERAL_AREA_VIEW_DISTANCE_BLOCKS = (GENERAL_AREA_VIEW_DISTANCE << 4);
|
|
||||||
public static final int GENERAL_SMALL_AREA_VIEW_DISTANCE_BLOCKS = (GENERAL_SMALL_VIEW_DISTANCE << 4);
|
|
||||||
public static final int GENERAL_REALLY_SMALL_AREA_VIEW_DISTANCE_BLOCKS = (GENERAL_REALLY_SMALL_VIEW_DISTANCE << 4);
|
|
||||||
+ public static final int SPAWN_RANGE_VIEW_DISTANCE_BLOCKS = (SPAWN_RANGE_VIEW_DISTANCE << 4); // Paper - optimise chunk iteration
|
|
||||||
|
|
||||||
private final ServerLevel world;
|
|
||||||
private final Reference2ReferenceOpenHashMap<ServerPlayer, TrackedPlayer[]> players = new Reference2ReferenceOpenHashMap<>();
|
|
||||||
@@ -0,0 +0,0 @@ public final class NearbyPlayers {
|
|
||||||
players[NearbyMapType.GENERAL_REALLY_SMALL.ordinal()].update(chunk.x, chunk.z, GENERAL_REALLY_SMALL_VIEW_DISTANCE);
|
|
||||||
players[NearbyMapType.TICK_VIEW_DISTANCE.ordinal()].update(chunk.x, chunk.z, ChunkSystem.getTickViewDistance(player));
|
|
||||||
players[NearbyMapType.VIEW_DISTANCE.ordinal()].update(chunk.x, chunk.z, ChunkSystem.getLoadViewDistance(player));
|
|
||||||
+ players[NearbyMapType.SPAWN_RANGE.ordinal()].update(chunk.x, chunk.z, SPAWN_RANGE_VIEW_DISTANCE); // Paper - optimise chunk iteration
|
|
||||||
}
|
|
||||||
|
|
||||||
public TrackedChunk getChunk(final ChunkPos pos) {
|
|
||||||
diff --git a/src/main/java/net/minecraft/server/level/ChunkHolder.java b/src/main/java/net/minecraft/server/level/ChunkHolder.java
|
|
||||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
|
||||||
--- a/src/main/java/net/minecraft/server/level/ChunkHolder.java
|
|
||||||
+++ b/src/main/java/net/minecraft/server/level/ChunkHolder.java
|
|
||||||
@@ -0,0 +0,0 @@ public class ChunkHolder {
|
|
||||||
|
|
||||||
// Paper start
|
|
||||||
public void onChunkAdd() {
|
|
||||||
-
|
|
||||||
+ // Paper start - optimise chunk tick iteration
|
|
||||||
+ if (this.needsBroadcastChanges()) {
|
|
||||||
+ this.chunkMap.needsChangeBroadcasting.add(this);
|
|
||||||
+ }
|
|
||||||
+ // Paper end - optimise chunk tick iteration
|
|
||||||
}
|
|
||||||
|
|
||||||
public void onChunkRemove() {
|
|
||||||
-
|
|
||||||
+ // Paper start - optimise chunk tick iteration
|
|
||||||
+ if (this.needsBroadcastChanges()) {
|
|
||||||
+ this.chunkMap.needsChangeBroadcasting.remove(this);
|
|
||||||
+ }
|
|
||||||
+ // Paper end - optimise chunk tick iteration
|
|
||||||
}
|
|
||||||
// Paper end
|
|
||||||
|
|
||||||
@@ -0,0 +0,0 @@ public class ChunkHolder {
|
|
||||||
|
|
||||||
if (i < 0 || i >= this.changedBlocksPerSection.length) return; // CraftBukkit - SPIGOT-6086, SPIGOT-6296
|
|
||||||
if (this.changedBlocksPerSection[i] == null) {
|
|
||||||
- this.hasChangedSections = true;
|
|
||||||
+ this.hasChangedSections = true; this.addToBroadcastMap(); // Paper - optimise chunk tick iteration
|
|
||||||
this.changedBlocksPerSection[i] = new ShortOpenHashSet();
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -0,0 +0,0 @@ public class ChunkHolder {
|
|
||||||
int k = this.lightEngine.getMaxLightSection();
|
|
||||||
|
|
||||||
if (y >= j && y <= k) {
|
|
||||||
+ this.addToBroadcastMap(); // Paper - optimise chunk tick iteration
|
|
||||||
int l = y - j;
|
|
||||||
|
|
||||||
if (lightType == LightLayer.SKY) {
|
|
||||||
@@ -0,0 +0,0 @@ public class ChunkHolder {
|
|
||||||
this.broadcast(this.getPlayers(onChunkViewEdge), packet); // Paper - rewrite chunk system
|
|
||||||
}
|
|
||||||
// Paper end - starlight
|
|
||||||
+ // Paper start - optimise chunk tick iteration
|
|
||||||
+ public final boolean needsBroadcastChanges() {
|
|
||||||
+ return this.hasChangedSections || !this.skyChangedLightSectionFilter.isEmpty() || !this.blockChangedLightSectionFilter.isEmpty();
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ private void addToBroadcastMap() {
|
|
||||||
+ io.papermc.paper.util.TickThread.ensureTickThread(this.chunkMap.level, this.pos, "Asynchronous ChunkHolder update is not allowed");
|
|
||||||
+ this.chunkMap.needsChangeBroadcasting.add(this);
|
|
||||||
+ }
|
|
||||||
+ // Paper end - optimise chunk tick iteration
|
|
||||||
|
|
||||||
public void broadcastChanges(LevelChunk chunk) {
|
|
||||||
- if (this.hasChangedSections || !this.skyChangedLightSectionFilter.isEmpty() || !this.blockChangedLightSectionFilter.isEmpty()) {
|
|
||||||
+ if (this.needsBroadcastChanges()) { // Paper - optimise chunk tick iteration; moved into above, other logic needs to call
|
|
||||||
Level world = chunk.getLevel();
|
|
||||||
List list;
|
|
||||||
|
|
||||||
diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java
|
|
||||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
|
||||||
--- a/src/main/java/net/minecraft/server/level/ChunkMap.java
|
|
||||||
+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java
|
|
||||||
@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
|
||||||
this.playerEntityTrackerTrackMaps[i].remove(player);
|
|
||||||
}
|
|
||||||
// Paper end - use distance map to optimise tracker
|
|
||||||
+ this.playerMobSpawnMap.remove(player); // Paper - optimise chunk tick iteration
|
|
||||||
}
|
|
||||||
|
|
||||||
void updateMaps(ServerPlayer player) {
|
|
||||||
@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
|
||||||
}
|
|
||||||
public final io.papermc.paper.util.player.NearbyPlayers nearbyPlayers;
|
|
||||||
// Paper end
|
|
||||||
+ // Paper start - optimise chunk tick iteration
|
|
||||||
+ public final it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet<ChunkHolder> needsChangeBroadcasting = new it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet<>();
|
|
||||||
+ public final com.destroystokyo.paper.util.misc.PlayerAreaMap playerMobSpawnMap = new com.destroystokyo.paper.util.misc.PlayerAreaMap(this.pooledLinkedPlayerHashSets);
|
|
||||||
+ // Paper end - optimise chunk tick iteration
|
|
||||||
|
|
||||||
public ChunkMap(ServerLevel world, LevelStorageSource.LevelStorageAccess session, DataFixer dataFixer, StructureTemplateManager structureTemplateManager, Executor executor, BlockableEventLoop<Runnable> mainThreadExecutor, LightChunkGetter chunkProvider, ChunkGenerator chunkGenerator, ChunkProgressListener worldGenerationProgressListener, ChunkStatusUpdateListener chunkStatusChangeListener, Supplier<DimensionDataStorage> persistentStateManagerFactory, int viewDistance, boolean dsync) {
|
|
||||||
super(new RegionStorageInfo(session.getLevelId(), world.dimension(), "chunk"), session.getDimensionPath(world.dimension()).resolve("region"), dataFixer, dsync);
|
|
||||||
@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
|
||||||
}
|
|
||||||
// Paper end - Optional per player mob spawns
|
|
||||||
|
|
||||||
- private static double euclideanDistanceSquared(ChunkPos pos, Entity entity) {
|
|
||||||
+ public static double euclideanDistanceSquared(ChunkPos pos, Entity entity) { // Paper - optimise chunk iteration; public
|
|
||||||
double d0 = (double) SectionPos.sectionToBlockCoord(pos.x, 8);
|
|
||||||
double d1 = (double) SectionPos.sectionToBlockCoord(pos.z, 8);
|
|
||||||
double d2 = d0 - entity.getX();
|
|
||||||
diff --git a/src/main/java/net/minecraft/server/level/DistanceManager.java b/src/main/java/net/minecraft/server/level/DistanceManager.java
|
|
||||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
|
||||||
--- a/src/main/java/net/minecraft/server/level/DistanceManager.java
|
|
||||||
+++ b/src/main/java/net/minecraft/server/level/DistanceManager.java
|
|
||||||
@@ -0,0 +0,0 @@ public abstract class DistanceManager {
|
|
||||||
private static final int INITIAL_TICKET_LIST_CAPACITY = 4;
|
|
||||||
final Long2ObjectMap<ObjectSet<ServerPlayer>> playersPerChunk = new Long2ObjectOpenHashMap();
|
|
||||||
// Paper - rewrite chunk system
|
|
||||||
- private final DistanceManager.FixedPlayerDistanceChunkTracker naturalSpawnChunkCounter = new DistanceManager.FixedPlayerDistanceChunkTracker(8);
|
|
||||||
+ public static final int MOB_SPAWN_RANGE = 8; //private final DistanceManager.FixedPlayerDistanceChunkTracker naturalSpawnChunkCounter = new DistanceManager.FixedPlayerDistanceChunkTracker(8); // Paper - optimise chunk tick iteration
|
|
||||||
// Paper - rewrite chunk system
|
|
||||||
private final ChunkMap chunkMap; // Paper
|
|
||||||
|
|
||||||
@@ -0,0 +0,0 @@ public abstract class DistanceManager {
|
|
||||||
long i = chunkcoordintpair.toLong();
|
|
||||||
|
|
||||||
// Paper - no longer used
|
|
||||||
- this.naturalSpawnChunkCounter.update(i, 0, true);
|
|
||||||
+ //this.naturalSpawnChunkCounter.update(i, 0, true); // Paper - optimise chunk tick iteration
|
|
||||||
//this.playerTicketManager.update(i, 0, true); // Paper - no longer used
|
|
||||||
//this.tickingTicketsTracker.addTicket(TicketType.PLAYER, chunkcoordintpair, this.getPlayerTicketLevel(), chunkcoordintpair); // Paper - no longer used
|
|
||||||
}
|
|
||||||
@@ -0,0 +0,0 @@ public abstract class DistanceManager {
|
|
||||||
if (objectset != null) objectset.remove(player); // Paper - some state corruption happens here, don't crash, clean up gracefully
|
|
||||||
if (objectset == null || objectset.isEmpty()) { // Paper
|
|
||||||
this.playersPerChunk.remove(i);
|
|
||||||
- this.naturalSpawnChunkCounter.update(i, Integer.MAX_VALUE, false);
|
|
||||||
+ //this.naturalSpawnChunkCounter.update(i, Integer.MAX_VALUE, false); // Paper - optimise chunk tick iteration
|
|
||||||
//this.playerTicketManager.update(i, Integer.MAX_VALUE, false); // Paper - no longer used
|
|
||||||
//this.tickingTicketsTracker.removeTicket(TicketType.PLAYER, chunkcoordintpair, this.getPlayerTicketLevel(), chunkcoordintpair); // Paper - no longer used
|
|
||||||
}
|
|
||||||
@@ -0,0 +0,0 @@ public abstract class DistanceManager {
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getNaturalSpawnChunkCount() {
|
|
||||||
- this.naturalSpawnChunkCounter.runAllUpdates();
|
|
||||||
- return this.naturalSpawnChunkCounter.chunks.size();
|
|
||||||
+ return this.chunkMap.playerMobSpawnMap.size(); // Paper - optimise chunk tick iteration
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean hasPlayersNearby(long chunkPos) {
|
|
||||||
- this.naturalSpawnChunkCounter.runAllUpdates();
|
|
||||||
- return this.naturalSpawnChunkCounter.chunks.containsKey(chunkPos);
|
|
||||||
+ return this.chunkMap.playerMobSpawnMap.getObjectsInRange(chunkPos) != null; // Paper - optimise chunk tick iteration
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getDebugStatus() {
|
|
||||||
diff --git a/src/main/java/net/minecraft/server/level/ServerChunkCache.java b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
|
|
||||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
|
||||||
--- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java
|
|
||||||
+++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
|
|
||||||
@@ -0,0 +0,0 @@ public class ServerChunkCache extends ChunkSource {
|
|
||||||
|
|
||||||
gameprofilerfiller.push("pollingChunks");
|
|
||||||
gameprofilerfiller.push("filteringLoadedChunks");
|
|
||||||
- List<ServerChunkCache.ChunkAndHolder> list = Lists.newArrayListWithCapacity(this.chunkMap.size());
|
|
||||||
- Iterator iterator = this.chunkMap.getChunks().iterator();
|
|
||||||
+ // Paper - optimise chunk tick iteration
|
|
||||||
if (this.level.getServer().tickRateManager().runsNormally()) this.level.timings.chunkTicks.startTiming(); // Paper
|
|
||||||
|
|
||||||
- while (iterator.hasNext()) {
|
|
||||||
- ChunkHolder playerchunk = (ChunkHolder) iterator.next();
|
|
||||||
- LevelChunk chunk = playerchunk.getTickingChunk();
|
|
||||||
-
|
|
||||||
- if (chunk != null) {
|
|
||||||
- list.add(new ServerChunkCache.ChunkAndHolder(chunk, playerchunk));
|
|
||||||
- }
|
|
||||||
- }
|
|
||||||
+ // Paper - optimise chunk tick iteration
|
|
||||||
|
|
||||||
if (this.level.tickRateManager().runsNormally()) {
|
|
||||||
gameprofilerfiller.popPush("naturalSpawnCount");
|
|
||||||
@@ -0,0 +0,0 @@ public class ServerChunkCache extends ChunkSource {
|
|
||||||
gameprofilerfiller.popPush("spawnAndTick");
|
|
||||||
boolean flag = this.level.getGameRules().getBoolean(GameRules.RULE_DOMOBSPAWNING) && !this.level.players().isEmpty(); // CraftBukkit
|
|
||||||
|
|
||||||
- Util.shuffle(list, this.level.random);
|
|
||||||
- // Paper start - PlayerNaturallySpawnCreaturesEvent
|
|
||||||
- int chunkRange = level.spigotConfig.mobSpawnRange;
|
|
||||||
- chunkRange = (chunkRange > level.spigotConfig.viewDistance) ? (byte) level.spigotConfig.viewDistance : chunkRange;
|
|
||||||
- chunkRange = Math.min(chunkRange, 8);
|
|
||||||
- for (ServerPlayer entityPlayer : this.level.players()) {
|
|
||||||
- entityPlayer.playerNaturallySpawnedEvent = new com.destroystokyo.paper.event.entity.PlayerNaturallySpawnCreaturesEvent(entityPlayer.getBukkitEntity(), (byte) chunkRange);
|
|
||||||
- entityPlayer.playerNaturallySpawnedEvent.callEvent();
|
|
||||||
+ // Paper start - optimise chunk tick iteration
|
|
||||||
+ ChunkMap playerChunkMap = this.chunkMap;
|
|
||||||
+ for (ServerPlayer player : this.level.players) {
|
|
||||||
+ if (!player.affectsSpawning || player.isSpectator()) {
|
|
||||||
+ playerChunkMap.playerMobSpawnMap.remove(player);
|
|
||||||
+ player.playerNaturallySpawnedEvent = null;
|
|
||||||
+ player.lastEntitySpawnRadiusSquared = -1.0;
|
|
||||||
+ continue;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ int viewDistance = io.papermc.paper.chunk.system.ChunkSystem.getTickViewDistance(player);
|
|
||||||
+
|
|
||||||
+ // copied and modified from isOutisdeRange
|
|
||||||
+ int chunkRange = (int)level.spigotConfig.mobSpawnRange;
|
|
||||||
+ chunkRange = (chunkRange > viewDistance) ? viewDistance : chunkRange;
|
|
||||||
+ chunkRange = (chunkRange > DistanceManager.MOB_SPAWN_RANGE) ? DistanceManager.MOB_SPAWN_RANGE : chunkRange;
|
|
||||||
+
|
|
||||||
+ com.destroystokyo.paper.event.entity.PlayerNaturallySpawnCreaturesEvent event = new com.destroystokyo.paper.event.entity.PlayerNaturallySpawnCreaturesEvent(player.getBukkitEntity(), (byte)chunkRange);
|
|
||||||
+ event.callEvent();
|
|
||||||
+ if (event.isCancelled() || event.getSpawnRadius() < 0) {
|
|
||||||
+ playerChunkMap.playerMobSpawnMap.remove(player);
|
|
||||||
+ player.playerNaturallySpawnedEvent = null;
|
|
||||||
+ player.lastEntitySpawnRadiusSquared = -1.0;
|
|
||||||
+ continue;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ int range = Math.min(event.getSpawnRadius(), DistanceManager.MOB_SPAWN_RANGE); // limit to max spawn range
|
|
||||||
+ int chunkX = io.papermc.paper.util.CoordinateUtils.getChunkCoordinate(player.getX());
|
|
||||||
+ int chunkZ = io.papermc.paper.util.CoordinateUtils.getChunkCoordinate(player.getZ());
|
|
||||||
+
|
|
||||||
+ playerChunkMap.playerMobSpawnMap.addOrUpdate(player, chunkX, chunkZ, range);
|
|
||||||
+ player.lastEntitySpawnRadiusSquared = (double)((range << 4) * (range << 4)); // used in anyPlayerCloseEnoughForSpawning
|
|
||||||
+ player.playerNaturallySpawnedEvent = event;
|
|
||||||
}
|
|
||||||
- // Paper end - PlayerNaturallySpawnCreaturesEvent
|
|
||||||
+ // Paper end - optimise chunk tick iteration
|
|
||||||
int l = this.level.getGameRules().getInt(GameRules.RULE_RANDOMTICKING);
|
|
||||||
boolean flag1 = this.level.ticksPerSpawnCategory.getLong(org.bukkit.entity.SpawnCategory.ANIMAL) != 0L && this.level.getLevelData().getGameTime() % this.level.ticksPerSpawnCategory.getLong(org.bukkit.entity.SpawnCategory.ANIMAL) == 0L; // CraftBukkit
|
|
||||||
- Iterator iterator1 = list.iterator();
|
|
||||||
+ // Paper - optimise chunk tick iteration
|
|
||||||
|
|
||||||
int chunksTicked = 0; // Paper
|
|
||||||
- while (iterator1.hasNext()) {
|
|
||||||
- ServerChunkCache.ChunkAndHolder chunkproviderserver_a = (ServerChunkCache.ChunkAndHolder) iterator1.next();
|
|
||||||
- LevelChunk chunk1 = chunkproviderserver_a.chunk;
|
|
||||||
+ // Paper start - optimise chunk tick iteration
|
|
||||||
+ io.papermc.paper.util.player.NearbyPlayers nearbyPlayers = this.chunkMap.getNearbyPlayers(); // Paper - optimise chunk tick iteration
|
|
||||||
+ Iterator<LevelChunk> chunkIterator;
|
|
||||||
+ if (this.level.paperConfig().entities.spawning.perPlayerMobSpawns) {
|
|
||||||
+ chunkIterator = this.tickingChunks.iterator();
|
|
||||||
+ } else {
|
|
||||||
+ chunkIterator = this.tickingChunks.unsafeIterator();
|
|
||||||
+ List<LevelChunk> shuffled = Lists.newArrayListWithCapacity(this.tickingChunks.size());
|
|
||||||
+ while (chunkIterator.hasNext()) {
|
|
||||||
+ shuffled.add(chunkIterator.next());
|
|
||||||
+ }
|
|
||||||
+ Util.shuffle(shuffled, this.level.random);
|
|
||||||
+ chunkIterator = shuffled.iterator();
|
|
||||||
+ }
|
|
||||||
+ try {
|
|
||||||
+ // Paper end - optimise chunk tick iteration
|
|
||||||
+ while (chunkIterator.hasNext()) {
|
|
||||||
+ LevelChunk chunk1 = chunkIterator.next();
|
|
||||||
+ // Paper end - optimise chunk tick iteration
|
|
||||||
ChunkPos chunkcoordintpair = chunk1.getPos();
|
|
||||||
|
|
||||||
- if (this.level.isNaturalSpawningAllowed(chunkcoordintpair) && this.chunkMap.anyPlayerCloseEnoughForSpawning(chunkcoordintpair)) {
|
|
||||||
+ // Paper start - optimise chunk tick iteration
|
|
||||||
+ com.destroystokyo.paper.util.maplist.ReferenceList<ServerPlayer> playersNearby
|
|
||||||
+ = nearbyPlayers.getPlayers(chunkcoordintpair, io.papermc.paper.util.player.NearbyPlayers.NearbyMapType.SPAWN_RANGE);
|
|
||||||
+ if (playersNearby == null) {
|
|
||||||
+ continue;
|
|
||||||
+ }
|
|
||||||
+ Object[] rawData = playersNearby.getRawData();
|
|
||||||
+ boolean spawn = false;
|
|
||||||
+ boolean tick = false;
|
|
||||||
+ for (int itr = 0, len = playersNearby.size(); itr < len; ++itr) {
|
|
||||||
+ ServerPlayer player = (ServerPlayer)rawData[itr];
|
|
||||||
+ if (player.isSpectator()) {
|
|
||||||
+ continue;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ double distance = ChunkMap.euclideanDistanceSquared(chunkcoordintpair, player);
|
|
||||||
+ spawn |= player.lastEntitySpawnRadiusSquared >= distance;
|
|
||||||
+ tick |= ((double)io.papermc.paper.util.player.NearbyPlayers.SPAWN_RANGE_VIEW_DISTANCE_BLOCKS) * ((double)io.papermc.paper.util.player.NearbyPlayers.SPAWN_RANGE_VIEW_DISTANCE_BLOCKS) >= distance;
|
|
||||||
+ if (spawn & tick) {
|
|
||||||
+ break;
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+ if (tick && chunk1.chunkStatus.isOrAfter(net.minecraft.server.level.FullChunkStatus.ENTITY_TICKING)) {
|
|
||||||
+ // Paper end - optimise chunk tick iteration
|
|
||||||
chunk1.incrementInhabitedTime(j);
|
|
||||||
- if (flag && (this.spawnEnemies || this.spawnFriendlies) && this.level.getWorldBorder().isWithinBounds(chunkcoordintpair) && this.chunkMap.anyPlayerCloseEnoughForSpawning(chunkcoordintpair, true)) { // Spigot
|
|
||||||
+ if (spawn && flag && (this.spawnEnemies || this.spawnFriendlies) && this.level.getWorldBorder().isWithinBounds(chunkcoordintpair)) { // Spigot // Paper - optimise chunk tick iteration
|
|
||||||
NaturalSpawner.spawnForChunk(this.level, chunk1, spawnercreature_d, this.spawnFriendlies, this.spawnEnemies, flag1);
|
|
||||||
}
|
|
||||||
|
|
||||||
- if (this.level.shouldTickBlocksAt(chunkcoordintpair.toLong())) {
|
|
||||||
+ if (true || this.level.shouldTickBlocksAt(chunkcoordintpair.toLong())) { // Paper - optimise chunk tick iteration
|
|
||||||
this.level.tickChunk(chunk1, l);
|
|
||||||
if ((chunksTicked++ & 1) == 0) net.minecraft.server.MinecraftServer.getServer().executeMidTickTasks(); // Paper
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+ // Paper start - optimise chunk tick iteration
|
|
||||||
+ } finally {
|
|
||||||
+ if (chunkIterator instanceof io.papermc.paper.util.maplist.IteratorSafeOrderedReferenceSet.Iterator safeIterator) {
|
|
||||||
+ safeIterator.finishedIterating();
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+ // Paper end - optimise chunk tick iteration
|
|
||||||
this.level.timings.chunkTicks.stopTiming(); // Paper
|
|
||||||
|
|
||||||
gameprofilerfiller.popPush("customSpawners");
|
|
||||||
@@ -0,0 +0,0 @@ public class ServerChunkCache extends ChunkSource {
|
|
||||||
}
|
|
||||||
|
|
||||||
gameprofilerfiller.popPush("broadcast");
|
|
||||||
- list.forEach((chunkproviderserver_a1) -> {
|
|
||||||
+ // Paper - optimise chunk tick iteration
|
|
||||||
this.level.timings.broadcastChunkUpdates.startTiming(); // Paper - timing
|
|
||||||
- chunkproviderserver_a1.holder.broadcastChanges(chunkproviderserver_a1.chunk);
|
|
||||||
+ // Paper start - optimise chunk tick iteration
|
|
||||||
+ if (!this.chunkMap.needsChangeBroadcasting.isEmpty()) {
|
|
||||||
+ it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet<ChunkHolder> copy = this.chunkMap.needsChangeBroadcasting.clone();
|
|
||||||
+ this.chunkMap.needsChangeBroadcasting.clear();
|
|
||||||
+ for (ChunkHolder holder : copy) {
|
|
||||||
+ holder.broadcastChanges(holder.getFullChunkNowUnchecked()); // LevelChunks are NEVER unloaded
|
|
||||||
+ if (holder.needsBroadcastChanges()) {
|
|
||||||
+ // I DON'T want to KNOW what DUMB plugins might be doing.
|
|
||||||
+ this.chunkMap.needsChangeBroadcasting.add(holder);
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+ // Paper end - optimise chunk tick iteration
|
|
||||||
this.level.timings.broadcastChunkUpdates.stopTiming(); // Paper - timing
|
|
||||||
- });
|
|
||||||
+ // Paper - optimise chunk tick iteration
|
|
||||||
gameprofilerfiller.pop();
|
|
||||||
gameprofilerfiller.pop();
|
|
||||||
}
|
|
||||||
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
|
||||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
|
||||||
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
|
||||||
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
|
||||||
@@ -0,0 +0,0 @@ public class ServerPlayer extends Player {
|
|
||||||
});
|
|
||||||
}
|
|
||||||
// Paper end - replace player chunk loader
|
|
||||||
+ // Paper start - optimise chunk tick iteration
|
|
||||||
+ public double lastEntitySpawnRadiusSquared = -1.0;
|
|
||||||
+ // Paper end - optimise chunk tick iteration
|
|
||||||
|
|
||||||
public ServerPlayer(MinecraftServer server, ServerLevel world, GameProfile profile, ClientInformation clientOptions) {
|
|
||||||
super(world, world.getSharedSpawnPos(), world.getSharedSpawnAngle(), profile);
|
|
Loading…
Reference in a new issue