2023-09-24 06:43:10 +02:00
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
2024-01-13 18:34:33 +01:00
index c3ce8a42dddd76b7189ad5685b23f9d9f8ccadb3..f164256d59b761264876ca0c85f812d101bfd5de 100644
2023-09-24 06:43:10 +02:00
--- a/src/main/java/io/papermc/paper/util/player/NearbyPlayers.java
+++ b/src/main/java/io/papermc/paper/util/player/NearbyPlayers.java
@@ -17,7 +17,8 @@ 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();
@@ -26,10 +27,12 @@ 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<>();
@@ -80,6 +83,7 @@ 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));
2024-01-13 18:34:33 +01:00
+ players[NearbyMapType.SPAWN_RANGE.ordinal()].update(chunk.x, chunk.z, SPAWN_RANGE_VIEW_DISTANCE); // Paper - optimise chunk iteration
2023-09-24 06:43:10 +02:00
}
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
2024-01-13 18:34:33 +01:00
index 2b998bdbe49bf8211b755e0eb7c1bf13ac280eab..627a88ec8c3b215b19b55a6d461c8754b4fcd1e8 100644
2023-09-24 06:43:10 +02:00
--- a/src/main/java/net/minecraft/server/level/ChunkHolder.java
+++ b/src/main/java/net/minecraft/server/level/ChunkHolder.java
@@ -79,11 +79,19 @@ 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
@@ -230,7 +238,7 @@ 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();
}
@@ -254,6 +262,7 @@ 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) {
@@ -268,8 +277,19 @@ public class ChunkHolder {
}
}
+ // 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()) {
2024-01-13 18:34:33 +01:00
+ if (this.needsBroadcastChanges()) { // Paper - optimise chunk tick iteration; moved into above, other logic needs to call
2023-09-24 06:43:10 +02:00
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
2024-01-21 19:37:09 +01:00
index c7d78fb217869204157606db8d6d73af0126a68f..6c28b37056c70fa0076b290b24168bfb79ddd77d 100644
2023-09-24 06:43:10 +02:00
--- a/src/main/java/net/minecraft/server/level/ChunkMap.java
+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java
2023-12-25 23:51:56 +01:00
@@ -191,6 +191,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
2023-11-03 15:05:57 +01:00
this.playerEntityTrackerTrackMaps[i].remove(player);
}
// Paper end - use distance map to optimise tracker
2023-09-24 06:43:10 +02:00
+ this.playerMobSpawnMap.remove(player); // Paper - optimise chunk tick iteration
}
void updateMaps(ServerPlayer player) {
2023-12-25 23:51:56 +01:00
@@ -240,6 +241,10 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
2023-09-24 06:43:10 +02:00
}
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(session.getDimensionPath(world.dimension()).resolve("region"), dataFixer, dsync);
2023-12-25 23:51:56 +01:00
@@ -409,7 +414,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
2023-09-24 06:43:10 +02:00
}
2024-01-21 12:53:04 +01:00
// Paper end - Optional per player mob spawns
2023-09-24 06:43:10 +02:00
- private static double euclideanDistanceSquared(ChunkPos pos, Entity entity) {
2024-01-13 18:34:33 +01:00
+ public static double euclideanDistanceSquared(ChunkPos pos, Entity entity) { // Paper - optimise chunk iteration; public
2023-09-24 06:43:10 +02:00
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
2024-01-21 12:11:43 +01:00
index c80a625f7289e3bb33c6851d2072957e153ca1fb..7c425ac50c83757b66a2178bc19d4c920b82f12f 100644
2023-09-24 06:43:10 +02:00
--- a/src/main/java/net/minecraft/server/level/DistanceManager.java
+++ b/src/main/java/net/minecraft/server/level/DistanceManager.java
@@ -50,7 +50,7 @@ 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
2023-12-25 23:51:56 +01:00
@@ -135,7 +135,7 @@ public abstract class DistanceManager {
2023-09-24 06:43:10 +02:00
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
}
2023-12-25 23:51:56 +01:00
@@ -149,7 +149,7 @@ public abstract class DistanceManager {
2024-01-21 12:11:43 +01:00
if (objectset != null) objectset.remove(player); // Paper - some state corruption happens here, don't crash, clean up gracefully
2023-09-24 06:43:10 +02:00
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
}
2023-12-25 23:51:56 +01:00
@@ -191,13 +191,11 @@ public abstract class DistanceManager {
2023-09-24 06:43:10 +02:00
}
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
2024-01-21 12:53:04 +01:00
index dfecd5531862109cd89cfd8a041a8beef70c1a6a..65a20974428ae1c0be2022d997234a16dc281292 100644
2023-09-24 06:43:10 +02:00
--- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java
+++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
2023-12-21 18:15:00 +01:00
@@ -516,18 +516,10 @@ public class ServerChunkCache extends ChunkSource {
2023-09-24 06:43:10 +02:00
2023-12-06 19:18:53 +01:00
gameprofilerfiller.push("pollingChunks");
gameprofilerfiller.push("filteringLoadedChunks");
- List<ServerChunkCache.ChunkAndHolder> list = Lists.newArrayListWithCapacity(this.chunkMap.size());
2023-09-24 06:43:10 +02:00
- Iterator iterator = this.chunkMap.getChunks().iterator();
2023-12-21 18:15:00 +01:00
+ // Paper - optimise chunk tick iteration
2023-12-06 22:40:08 +01:00
if (this.level.getServer().tickRateManager().runsNormally()) this.level.timings.chunkTicks.startTiming(); // Paper
2023-09-24 06:43:10 +02:00
- while (iterator.hasNext()) {
- ChunkHolder playerchunk = (ChunkHolder) iterator.next();
- LevelChunk chunk = playerchunk.getTickingChunk();
2023-12-21 18:15:00 +01:00
-
2023-12-06 19:18:53 +01:00
- if (chunk != null) {
- list.add(new ServerChunkCache.ChunkAndHolder(chunk, playerchunk));
2023-12-21 18:15:00 +01:00
- }
- }
+ // Paper - optimise chunk tick iteration
2023-09-24 06:43:10 +02:00
2023-12-06 19:18:53 +01:00
if (this.level.getServer().tickRateManager().runsNormally()) {
gameprofilerfiller.popPush("naturalSpawnCount");
2023-12-21 18:15:00 +01:00
@@ -562,38 +554,109 @@ public class ServerChunkCache extends ChunkSource {
2023-12-06 19:18:53 +01:00
gameprofilerfiller.popPush("spawnAndTick");
boolean flag = this.level.getGameRules().getBoolean(GameRules.RULE_DOMOBSPAWNING) && !this.level.players().isEmpty(); // CraftBukkit
2023-09-24 06:43:10 +02:00
2023-12-06 19:18:53 +01:00
- Util.shuffle(list, this.level.random);
- // Paper start - call player naturally spawn event
- 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();
2023-09-24 06:43:10 +02:00
+ // Paper start - optimise chunk tick iteration
2023-12-21 18:15:00 +01:00
+ ChunkMap playerChunkMap = this.chunkMap;
2023-12-06 19:18:53 +01:00
+ for (ServerPlayer player : this.level.players) {
+ if (!player.affectsSpawning || player.isSpectator()) {
+ playerChunkMap.playerMobSpawnMap.remove(player);
+ player.playerNaturallySpawnedEvent = null;
+ player.lastEntitySpawnRadiusSquared = -1.0;
2023-09-24 06:43:10 +02:00
+ continue;
+ }
+
2023-12-06 19:18:53 +01:00
+ 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;
2023-09-24 06:43:10 +02:00
+ }
2023-12-06 19:18:53 +01:00
+
+ 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
+ // 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();
2023-12-21 18:15:00 +01:00
+ // Paper - optimise chunk tick iteration
2023-12-06 19:18:53 +01:00
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();
2023-09-24 06:43:10 +02:00
+ }
2023-12-06 19:18:53 +01:00
+ try {
2023-09-24 06:43:10 +02:00
+ // Paper end - optimise chunk tick iteration
2023-12-06 19:18:53 +01:00
+ while (chunkIterator.hasNext()) {
2023-12-21 18:15:00 +01:00
+ LevelChunk chunk1 = chunkIterator.next();
+ // Paper end - optimise chunk tick iteration
2023-12-06 19:18:53 +01:00
ChunkPos chunkcoordintpair = chunk1.getPos();
2023-09-24 06:43:10 +02:00
2023-12-06 19:18:53 +01:00
- 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
}
2023-09-24 06:43:10 +02:00
}
}
2023-12-06 19:18:53 +01:00
+ // Paper start - optimise chunk tick iteration
+ } finally {
+ if (chunkIterator instanceof io.papermc.paper.util.maplist.IteratorSafeOrderedReferenceSet.Iterator safeIterator) {
+ safeIterator.finishedIterating();
+ }
2023-09-24 06:43:10 +02:00
+ }
2023-12-06 19:18:53 +01:00
+ // Paper end - optimise chunk tick iteration
2023-12-06 21:14:54 +01:00
this.level.timings.chunkTicks.stopTiming(); // Paper
2023-12-06 19:18:53 +01:00
gameprofilerfiller.popPush("customSpawners");
2023-12-21 18:15:00 +01:00
@@ -605,11 +668,23 @@ public class ServerChunkCache extends ChunkSource {
2023-09-24 06:43:10 +02:00
}
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();
2023-12-06 19:18:53 +01:00
}
2023-09-24 06:43:10 +02:00
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
2024-01-21 19:37:09 +01:00
index 8afbf0d40af4040b18f68a549710112a0aa5fd00..575681586667933e7f26bb16f7d2aa7c73188cde 100644
2023-09-24 06:43:10 +02:00
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
2023-12-06 19:18:53 +01:00
@@ -325,6 +325,9 @@ public class ServerPlayer extends Player {
2023-09-24 06:43:10 +02:00
});
}
// 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);