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.
This commit is contained in:
Spottedleaf 2023-09-23 21:43:10 -07:00
parent 8d922746d9
commit 38dc3b25d8
54 changed files with 1115 additions and 1340 deletions

View File

@ -1,346 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
Date: Tue, 5 May 2020 20:40:53 -0700
Subject: [PATCH] Optimize anyPlayerCloseEnoughForSpawning to use distance maps
Use a distance map to find the players in range quickly
diff --git a/src/main/java/net/minecraft/server/level/ChunkHolder.java b/src/main/java/net/minecraft/server/level/ChunkHolder.java
index c5389e7f3665c06e487dfde3200b7e229694fbd2..4164204ba80f68a768de0ed1721c6447b972a631 100644
--- a/src/main/java/net/minecraft/server/level/ChunkHolder.java
+++ b/src/main/java/net/minecraft/server/level/ChunkHolder.java
@@ -79,16 +79,29 @@ public class ChunkHolder {
// Paper start
public void onChunkAdd() {
-
+ // Paper start - optimise anyPlayerCloseEnoughForSpawning
+ long key = io.papermc.paper.util.MCUtil.getCoordinateKey(this.pos);
+ this.playersInMobSpawnRange = this.chunkMap.playerMobSpawnMap.getObjectsInRange(key);
+ this.playersInChunkTickRange = this.chunkMap.playerChunkTickRangeMap.getObjectsInRange(key);
+ // Paper end - optimise anyPlayerCloseEnoughForSpawning
}
public void onChunkRemove() {
-
+ // Paper start - optimise anyPlayerCloseEnoughForSpawning
+ this.playersInMobSpawnRange = null;
+ this.playersInChunkTickRange = null;
+ // Paper end - optimise anyPlayerCloseEnoughForSpawning
}
// Paper end
public final io.papermc.paper.chunk.system.scheduling.NewChunkHolder newChunkHolder; // Paper - rewrite chunk system
+ // Paper start - optimise anyPlayerCloseEnoughForSpawning
+ // cached here to avoid a map lookup
+ com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<ServerPlayer> playersInMobSpawnRange;
+ com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<ServerPlayer> playersInChunkTickRange;
+ // Paper end - optimise anyPlayerCloseEnoughForSpawning
+
// Paper start - replace player chunk loader
private final com.destroystokyo.paper.util.maplist.ReferenceList<ServerPlayer> playersSentChunkTo = new com.destroystokyo.paper.util.maplist.ReferenceList<>();
diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java
index 52d9d0f2366f292c56eee9fe241cb43bc2900b23..80b2ff12e48e1aabebd9ebcf5958c1f5d073d55b 100644
--- a/src/main/java/net/minecraft/server/level/ChunkMap.java
+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java
@@ -174,12 +174,24 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
return net.minecraft.server.MinecraftServer.getServer().getScaledTrackingDistance(vanilla);
}
// Paper end - use distance map to optimise tracker
+ // Paper start - optimise ChunkMap#anyPlayerCloseEnoughForSpawning
+ // A note about the naming used here:
+ // Previously, mojang used a "spawn range" of 8 for controlling both ticking and
+ // mob spawn range. However, spigot makes the spawn range configurable by
+ // checking if the chunk is in the tick range (8) and the spawn range
+ // obviously this means a spawn range > 8 cannot be implemented
+
+ // these maps are named after spigot's uses
+ public final com.destroystokyo.paper.util.misc.PlayerAreaMap playerMobSpawnMap; // this map is absent from updateMaps since it's controlled at the start of the chunkproviderserver tick
+ public final com.destroystokyo.paper.util.misc.PlayerAreaMap playerChunkTickRangeMap;
+ // Paper end - optimise ChunkMap#anyPlayerCloseEnoughForSpawning
void addPlayerToDistanceMaps(ServerPlayer player) {
this.level.playerChunkLoader.addPlayer(player); // Paper - replace chunk loader
int chunkX = MCUtil.getChunkCoordinate(player.getX());
int chunkZ = MCUtil.getChunkCoordinate(player.getZ());
// Note: players need to be explicitly added to distance maps before they can be updated
+ this.playerChunkTickRangeMap.add(player, chunkX, chunkZ, DistanceManager.MOB_SPAWN_RANGE); // Paper - optimise ChunkMap#anyPlayerCloseEnoughForSpawning
// Paper start - per player mob spawning
if (this.playerMobDistanceMap != null) {
this.playerMobDistanceMap.add(player, chunkX, chunkZ, io.papermc.paper.chunk.system.ChunkSystem.getTickViewDistance(player));
@@ -198,6 +210,10 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
void removePlayerFromDistanceMaps(ServerPlayer player) {
this.level.playerChunkLoader.removePlayer(player); // Paper - replace chunk loader
+ // Paper start - optimise ChunkMap#anyPlayerCloseEnoughForSpawning
+ this.playerMobSpawnMap.remove(player);
+ this.playerChunkTickRangeMap.remove(player);
+ // Paper end - optimise ChunkMap#anyPlayerCloseEnoughForSpawning
// Paper start - per player mob spawning
if (this.playerMobDistanceMap != null) {
this.playerMobDistanceMap.remove(player);
@@ -215,6 +231,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
int chunkZ = MCUtil.getChunkCoordinate(player.getZ());
// Note: players need to be explicitly added to distance maps before they can be updated
this.level.playerChunkLoader.updatePlayer(player); // Paper - replace chunk loader
+ this.playerChunkTickRangeMap.update(player, chunkX, chunkZ, DistanceManager.MOB_SPAWN_RANGE); // Paper - optimise ChunkMap#anyPlayerCloseEnoughForSpawning
// Paper start - per player mob spawning
if (this.playerMobDistanceMap != null) {
this.playerMobDistanceMap.update(player, chunkX, chunkZ, io.papermc.paper.chunk.system.ChunkSystem.getTickViewDistance(player));
@@ -356,6 +373,38 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
this.playerEntityTrackerTrackMaps[ordinal] = new com.destroystokyo.paper.util.misc.PlayerAreaMap(this.pooledLinkedPlayerHashSets);
}
// Paper end - use distance map to optimise entity tracker
+ // Paper start - optimise ChunkMap#anyPlayerCloseEnoughForSpawning
+ this.playerChunkTickRangeMap = new com.destroystokyo.paper.util.misc.PlayerAreaMap(this.pooledLinkedPlayerHashSets,
+ (ServerPlayer player, int rangeX, int rangeZ, int currPosX, int currPosZ, int prevPosX, int prevPosZ,
+ com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<ServerPlayer> newState) -> {
+ ChunkHolder playerChunk = ChunkMap.this.getUpdatingChunkIfPresent(MCUtil.getCoordinateKey(rangeX, rangeZ));
+ if (playerChunk != null) {
+ playerChunk.playersInChunkTickRange = newState;
+ }
+ },
+ (ServerPlayer player, int rangeX, int rangeZ, int currPosX, int currPosZ, int prevPosX, int prevPosZ,
+ com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<ServerPlayer> newState) -> {
+ ChunkHolder playerChunk = ChunkMap.this.getUpdatingChunkIfPresent(MCUtil.getCoordinateKey(rangeX, rangeZ));
+ if (playerChunk != null) {
+ playerChunk.playersInChunkTickRange = newState;
+ }
+ });
+ this.playerMobSpawnMap = new com.destroystokyo.paper.util.misc.PlayerAreaMap(this.pooledLinkedPlayerHashSets,
+ (ServerPlayer player, int rangeX, int rangeZ, int currPosX, int currPosZ, int prevPosX, int prevPosZ,
+ com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<ServerPlayer> newState) -> {
+ ChunkHolder playerChunk = ChunkMap.this.getUpdatingChunkIfPresent(MCUtil.getCoordinateKey(rangeX, rangeZ));
+ if (playerChunk != null) {
+ playerChunk.playersInMobSpawnRange = newState;
+ }
+ },
+ (ServerPlayer player, int rangeX, int rangeZ, int currPosX, int currPosZ, int prevPosX, int prevPosZ,
+ com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<ServerPlayer> newState) -> {
+ ChunkHolder playerChunk = ChunkMap.this.getUpdatingChunkIfPresent(MCUtil.getCoordinateKey(rangeX, rangeZ));
+ if (playerChunk != null) {
+ playerChunk.playersInMobSpawnRange = newState;
+ }
+ });
+ // Paper end - optimise ChunkMap#anyPlayerCloseEnoughForSpawning
}
protected ChunkGenerator generator() {
@@ -930,43 +979,48 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
return this.anyPlayerCloseEnoughForSpawning(pos, false);
}
- boolean anyPlayerCloseEnoughForSpawning(ChunkPos chunkcoordintpair, boolean reducedRange) {
- int chunkRange = level.spigotConfig.mobSpawnRange;
- chunkRange = (chunkRange > level.spigotConfig.viewDistance) ? (byte) level.spigotConfig.viewDistance : chunkRange;
- chunkRange = (chunkRange > 8) ? 8 : chunkRange;
-
- final int finalChunkRange = chunkRange; // Paper for lambda below
- //double blockRange = (reducedRange) ? Math.pow(chunkRange << 4, 2) : 16384.0D; // Paper - use from event
- double blockRange = 16384.0D; // Paper
- // Spigot end
- long i = chunkcoordintpair.toLong();
+ // Paper start - optimise anyPlayerCloseEnoughForSpawning
+ final boolean anyPlayerCloseEnoughForSpawning(ChunkPos chunkcoordintpair, boolean reducedRange) {
+ return this.anyPlayerCloseEnoughForSpawning(this.getUpdatingChunkIfPresent(chunkcoordintpair.toLong()), chunkcoordintpair, reducedRange);
+ }
- if (!this.distanceManager.hasPlayersNearby(i)) {
+ final boolean anyPlayerCloseEnoughForSpawning(ChunkHolder playerchunk, ChunkPos chunkcoordintpair, boolean reducedRange) {
+ // this function is so hot that removing the map lookup call can have an order of magnitude impact on its performance
+ // tested and confirmed via System.nanoTime()
+ com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<ServerPlayer> playersInRange = reducedRange ? playerchunk.playersInMobSpawnRange : playerchunk.playersInChunkTickRange;
+ if (playersInRange == null) {
return false;
- } else {
- Iterator iterator = this.playerMap.getPlayers(i).iterator();
-
- ServerPlayer entityplayer;
+ }
+ Object[] backingSet = playersInRange.getBackingSet();
- do {
- if (!iterator.hasNext()) {
- return false;
+ if (reducedRange) {
+ for (int i = 0, len = backingSet.length; i < len; ++i) {
+ Object raw = backingSet[i];
+ if (!(raw instanceof ServerPlayer player)) {
+ continue;
}
-
- entityplayer = (ServerPlayer) iterator.next();
- // Paper start - add PlayerNaturallySpawnCreaturesEvent
- com.destroystokyo.paper.event.entity.PlayerNaturallySpawnCreaturesEvent event;
- blockRange = 16384.0D;
- if (reducedRange) {
- event = entityplayer.playerNaturallySpawnedEvent;
- if (event == null || event.isCancelled()) return false;
- blockRange = (double) ((event.getSpawnRadius() << 4) * (event.getSpawnRadius() << 4));
+ // don't check spectator and whatnot, already handled by mob spawn map update
+ if (euclideanDistanceSquared(chunkcoordintpair, player) < player.lastEntitySpawnRadiusSquared) {
+ return true; // in range
}
- // Paper end
- } while (!this.playerIsCloseEnoughForSpawning(entityplayer, chunkcoordintpair, blockRange)); // Spigot
-
- return true;
+ }
+ } else {
+ final double range = (DistanceManager.MOB_SPAWN_RANGE * 16) * (DistanceManager.MOB_SPAWN_RANGE * 16);
+ // before spigot, mob spawn range was actually mob spawn range + tick range, but it was split
+ for (int i = 0, len = backingSet.length; i < len; ++i) {
+ Object raw = backingSet[i];
+ if (!(raw instanceof ServerPlayer player)) {
+ continue;
+ }
+ // don't check spectator and whatnot, already handled by mob spawn map update
+ if (euclideanDistanceSquared(chunkcoordintpair, player) < range) {
+ return true; // in range
+ }
+ }
}
+ // no players in range
+ return false;
+ // Paper end - optimise anyPlayerCloseEnoughForSpawning
}
public List<ServerPlayer> getPlayersCloseForSpawning(ChunkPos pos) {
diff --git a/src/main/java/net/minecraft/server/level/DistanceManager.java b/src/main/java/net/minecraft/server/level/DistanceManager.java
index 0a926afa06a5e37cf2650afa1b5099a2a9ffa659..ae4a4710ba07614be42cdcbf52cee04cfa08466b 100644
--- 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 - no longer used
// Paper - rewrite chunk system
private final ChunkMap chunkMap; // Paper
@@ -136,7 +136,7 @@ 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 - no longer used
//this.playerTicketManager.update(i, 0, true); // Paper - no longer used
//this.tickingTicketsTracker.addTicket(TicketType.PLAYER, chunkcoordintpair, this.getPlayerTicketLevel(), chunkcoordintpair); // Paper - no longer used
}
@@ -150,7 +150,7 @@ 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 - no longer used
//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
}
@@ -192,13 +192,17 @@ public abstract class DistanceManager {
}
public int getNaturalSpawnChunkCount() {
- this.naturalSpawnChunkCounter.runAllUpdates();
- return this.naturalSpawnChunkCounter.chunks.size();
+ // Paper start - use distance map to implement
+ // note: this is the spawn chunk count
+ return this.chunkMap.playerChunkTickRangeMap.size();
+ // Paper end - use distance map to implement
}
public boolean hasPlayersNearby(long chunkPos) {
- this.naturalSpawnChunkCounter.runAllUpdates();
- return this.naturalSpawnChunkCounter.chunks.containsKey(chunkPos);
+ // Paper start - use distance map to implement
+ // note: this is the is spawn chunk method
+ return this.chunkMap.playerChunkTickRangeMap.getObjectsInRange(chunkPos) != null;
+ // Paper end - use distance map to implement
}
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 3f5d572994bc8b3f1e106105dc0bb202ad005b8c..5c5fe2087a7617324ab8e18389e3ffa9ac413026 100644
--- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java
+++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
@@ -517,6 +517,37 @@ public class ServerChunkCache extends ChunkSource {
if (flag) {
this.chunkMap.tick();
} else {
+ // Paper start - optimize isOutisdeRange
+ ChunkMap playerChunkMap = this.chunkMap;
+ for (ServerPlayer player : this.level.players) {
+ if (!player.affectsSpawning || player.isSpectator()) {
+ playerChunkMap.playerMobSpawnMap.remove(player);
+ continue;
+ }
+
+ int viewDistance = this.chunkMap.getEffectiveViewDistance();
+
+ // copied and modified from isOutisdeRange
+ int chunkRange = level.spigotConfig.mobSpawnRange;
+ chunkRange = (chunkRange > viewDistance) ? (byte)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.playerChunkTickRangeMap.getLastViewDistance(player) == -1) {
+ playerChunkMap.playerMobSpawnMap.remove(player);
+ continue;
+ }
+
+ int range = Math.min(event.getSpawnRadius(), 32); // limit to max view distance
+ int chunkX = io.papermc.paper.util.MCUtil.getChunkCoordinate(player.getX());
+ int chunkZ = io.papermc.paper.util.MCUtil.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 - optimize isOutisdeRange
LevelData worlddata = this.level.getLevelData();
ProfilerFiller gameprofilerfiller = this.level.getProfiler();
@@ -560,15 +591,7 @@ public class ServerChunkCache extends ChunkSource {
boolean flag2 = this.level.getGameRules().getBoolean(GameRules.RULE_DOMOBSPAWNING) && !this.level.players().isEmpty(); // CraftBukkit
Collections.shuffle(list);
- // 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();
- };
- // Paper end
+ // Paper - moved natural spawn event up
Iterator iterator1 = list.iterator();
while (iterator1.hasNext()) {
@@ -576,9 +599,9 @@ public class ServerChunkCache extends ChunkSource {
LevelChunk chunk1 = chunkproviderserver_a.chunk;
ChunkPos chunkcoordintpair = chunk1.getPos();
- if (this.level.isNaturalSpawningAllowed(chunkcoordintpair) && this.chunkMap.anyPlayerCloseEnoughForSpawning(chunkcoordintpair)) {
+ if (this.level.isNaturalSpawningAllowed(chunkcoordintpair) && this.chunkMap.anyPlayerCloseEnoughForSpawning(chunkproviderserver_a.holder, chunkcoordintpair, false)) { // Paper - optimise anyPlayerCloseEnoughForSpawning
chunk1.incrementInhabitedTime(j);
- if (flag2 && (this.spawnEnemies || this.spawnFriendlies) && this.level.getWorldBorder().isWithinBounds(chunkcoordintpair) && this.chunkMap.anyPlayerCloseEnoughForSpawning(chunkcoordintpair, true)) { // Spigot
+ if (flag2 && (this.spawnEnemies || this.spawnFriendlies) && this.level.getWorldBorder().isWithinBounds(chunkcoordintpair) && this.chunkMap.anyPlayerCloseEnoughForSpawning(chunkproviderserver_a.holder, chunkcoordintpair, true)) { // Spigot // Paper - optimise anyPlayerCloseEnoughForSpawning
NaturalSpawner.spawnForChunk(this.level, chunk1, spawnercreature_d, this.spawnFriendlies, this.spawnEnemies, flag1);
}
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
index ce2972c62f91724f6a9e56c8103fba219f7a60bb..6c00162847b59ffa3d1403b956545c57ba539139 100644
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
@@ -273,6 +273,7 @@ public class ServerPlayer extends Player {
public Integer clientViewDistance;
// CraftBukkit end
public boolean isRealPlayer; // Paper
+ public double lastEntitySpawnRadiusSquared; // Paper - optimise isOutsideRange, this field is in blocks
public final com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<ServerPlayer> cachedSingleHashSet; // Paper
public PlayerNaturallySpawnCreaturesEvent playerNaturallySpawnedEvent; // Paper
public org.bukkit.event.player.PlayerQuitEvent.QuitReason quitReason = null; // Paper - there are a lot of changes to do if we change all methods leading to the event

View File

@ -1,215 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
Date: Thu, 7 May 2020 05:48:54 -0700
Subject: [PATCH] Optimise chunk tick iteration
Use a dedicated list of entity ticking chunks to reduce the cost
diff --git a/src/main/java/net/minecraft/server/level/ChunkHolder.java b/src/main/java/net/minecraft/server/level/ChunkHolder.java
index 4164204ba80f68a768de0ed1721c6447b972a631..4ae1ba645d9fdc1eb6d5a3e4f8ceed9b4841e003 100644
--- a/src/main/java/net/minecraft/server/level/ChunkHolder.java
+++ b/src/main/java/net/minecraft/server/level/ChunkHolder.java
@@ -84,6 +84,11 @@ public class ChunkHolder {
this.playersInMobSpawnRange = this.chunkMap.playerMobSpawnMap.getObjectsInRange(key);
this.playersInChunkTickRange = this.chunkMap.playerChunkTickRangeMap.getObjectsInRange(key);
// Paper end - optimise anyPlayerCloseEnoughForSpawning
+ // Paper start - optimise chunk tick iteration
+ if (this.needsBroadcastChanges()) {
+ this.chunkMap.needsChangeBroadcasting.add(this);
+ }
+ // Paper end - optimise chunk tick iteration
}
public void onChunkRemove() {
@@ -91,6 +96,11 @@ public class ChunkHolder {
this.playersInMobSpawnRange = null;
this.playersInChunkTickRange = null;
// Paper end - optimise anyPlayerCloseEnoughForSpawning
+ // Paper start - optimise chunk tick iteration
+ if (this.needsBroadcastChanges()) {
+ this.chunkMap.needsChangeBroadcasting.remove(this);
+ }
+ // Paper end - optimise chunk tick iteration
}
// Paper end
@@ -230,7 +240,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 +264,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 +279,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() {
+ org.spigotmc.AsyncCatcher.catchOp("ChunkHolder update");
+ 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 - 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 80b2ff12e48e1aabebd9ebcf5958c1f5d073d55b..bcf0dfe50add8e260a280e45673727f964bac6fd 100644
--- a/src/main/java/net/minecraft/server/level/ChunkMap.java
+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java
@@ -115,6 +115,8 @@ import org.bukkit.craftbukkit.generator.CustomChunkGenerator;
import org.bukkit.entity.Player;
// CraftBukkit end
+import it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet; // Paper
+
public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider {
private static final byte CHUNK_TYPE_REPLACEABLE = -1;
@@ -152,6 +154,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
private final Queue<Runnable> unloadQueue;
int viewDistance;
public final com.destroystokyo.paper.util.misc.PlayerAreaMap playerMobDistanceMap; // Paper
+ public final ReferenceOpenHashSet<ChunkHolder> needsChangeBroadcasting = new ReferenceOpenHashSet<>();
// Paper - rewrite chunk system
diff --git a/src/main/java/net/minecraft/server/level/ServerChunkCache.java b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
index 5c5fe2087a7617324ab8e18389e3ffa9ac413026..828de28f2777e2477a9c6545c8af96c4ca4e352b 100644
--- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java
+++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
@@ -48,6 +48,7 @@ import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemp
import net.minecraft.world.level.storage.DimensionDataStorage;
import net.minecraft.world.level.storage.LevelData;
import net.minecraft.world.level.storage.LevelStorageSource;
+import it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet; // Paper
public class ServerChunkCache extends ChunkSource {
@@ -574,42 +575,59 @@ public class ServerChunkCache extends ChunkSource {
this.lastSpawnState = spawnercreature_d;
gameprofilerfiller.popPush("filteringLoadedChunks");
- List<ServerChunkCache.ChunkAndHolder> list = Lists.newArrayListWithCapacity(l);
- Iterator iterator = this.chunkMap.getChunks().iterator();
+ // Paper - moved down
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 - moved down
gameprofilerfiller.popPush("spawnAndTick");
boolean flag2 = this.level.getGameRules().getBoolean(GameRules.RULE_DOMOBSPAWNING) && !this.level.players().isEmpty(); // CraftBukkit
- Collections.shuffle(list);
+ // Paper - only shuffle if per-player mob spawning is disabled
// Paper - moved natural spawn event up
- Iterator iterator1 = list.iterator();
+ // Paper start - optimise chunk tick iteratio
+ Iterator<LevelChunk> iterator1;
+ if (this.level.paperConfig().entities.spawning.perPlayerMobSpawns) {
+ iterator1 = this.entityTickingChunks.iterator();
+ } else {
+ iterator1 = this.entityTickingChunks.unsafeIterator();
+ List<LevelChunk> shuffled = Lists.newArrayListWithCapacity(this.entityTickingChunks.size());
+ while (iterator1.hasNext()) {
+ shuffled.add(iterator1.next());
+ }
+ Collections.shuffle(shuffled);
+ iterator1 = shuffled.iterator();
+ }
+ try {
while (iterator1.hasNext()) {
- ServerChunkCache.ChunkAndHolder chunkproviderserver_a = (ServerChunkCache.ChunkAndHolder) iterator1.next();
- LevelChunk chunk1 = chunkproviderserver_a.chunk;
+ LevelChunk chunk1 = iterator1.next();
+ ChunkHolder holder = chunk1.playerChunk;
+ if (holder != null) {
+ // Paper - move down
+ // Paper end - optimise chunk tick iteration
ChunkPos chunkcoordintpair = chunk1.getPos();
- if (this.level.isNaturalSpawningAllowed(chunkcoordintpair) && this.chunkMap.anyPlayerCloseEnoughForSpawning(chunkproviderserver_a.holder, chunkcoordintpair, false)) { // Paper - optimise anyPlayerCloseEnoughForSpawning
+ if ((true || this.level.isNaturalSpawningAllowed(chunkcoordintpair)) && this.chunkMap.anyPlayerCloseEnoughForSpawning(holder, chunkcoordintpair, false)) { // Paper - optimise anyPlayerCloseEnoughForSpawning // Paper - the chunk is known ticking
chunk1.incrementInhabitedTime(j);
- if (flag2 && (this.spawnEnemies || this.spawnFriendlies) && this.level.getWorldBorder().isWithinBounds(chunkcoordintpair) && this.chunkMap.anyPlayerCloseEnoughForSpawning(chunkproviderserver_a.holder, chunkcoordintpair, true)) { // Spigot // Paper - optimise anyPlayerCloseEnoughForSpawning
+ if (flag2 && (this.spawnEnemies || this.spawnFriendlies) && this.level.getWorldBorder().isWithinBounds(chunkcoordintpair) && this.chunkMap.anyPlayerCloseEnoughForSpawning(holder, chunkcoordintpair, true)) { // Spigot // Paper - optimise anyPlayerCloseEnoughForSpawning & 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 - the chunk is known ticking
this.level.tickChunk(chunk1, k);
}
}
+ // Paper start - optimise chunk tick iteration
+ }
+ }
+
+ } finally {
+ if (iterator1 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");
if (flag2) {
@@ -617,15 +635,24 @@ public class ServerChunkCache extends ChunkSource {
this.level.tickCustomSpawners(this.spawnEnemies, this.spawnFriendlies);
} // Paper - timings
}
-
- 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
- });
gameprofilerfiller.pop();
+ // Paper start - use set of chunks requiring updates, rather than iterating every single one loaded
+ gameprofilerfiller.popPush("broadcast");
+ this.level.timings.broadcastChunkUpdates.startTiming(); // Paper - timing
+ if (!this.chunkMap.needsChangeBroadcasting.isEmpty()) {
+ 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);
+ }
+ }
+ }
+ this.level.timings.broadcastChunkUpdates.stopTiming(); // Paper - timing
gameprofilerfiller.pop();
+ // Paper end - use set of chunks requiring updates, rather than iterating every single one loaded
this.chunkMap.tick();
}
}

View File

@ -5467,6 +5467,453 @@ index 0000000000000000000000000000000000000000..808d1449ac44ae86a650932365081fba
+ }
+ }
+}
diff --git a/src/main/java/io/papermc/paper/util/player/NearbyPlayers.java b/src/main/java/io/papermc/paper/util/player/NearbyPlayers.java
new file mode 100644
index 0000000000000000000000000000000000000000..60c7680d678f9dc6a6a3109b1f6af8150ccd9100
--- /dev/null
+++ b/src/main/java/io/papermc/paper/util/player/NearbyPlayers.java
@@ -0,0 +1,203 @@
+package io.papermc.paper.util.player;
+
+import com.destroystokyo.paper.util.maplist.ReferenceList;
+import io.papermc.paper.chunk.system.ChunkSystem;
+import io.papermc.paper.util.CoordinateUtils;
+import it.unimi.dsi.fastutil.longs.Long2ReferenceOpenHashMap;
+import it.unimi.dsi.fastutil.objects.Reference2ReferenceOpenHashMap;
+import net.minecraft.core.BlockPos;
+import net.minecraft.server.level.ServerLevel;
+import net.minecraft.server.level.ServerPlayer;
+import net.minecraft.world.level.ChunkPos;
+
+public final class NearbyPlayers {
+
+ public static enum NearbyMapType {
+ GENERAL,
+ GENERAL_SMALL,
+ GENERAL_REALLY_SMALL,
+ TICK_VIEW_DISTANCE,
+ VIEW_DISTANCE;
+ }
+
+ private static final NearbyMapType[] MOB_TYPES = NearbyMapType.values();
+ public static final int TOTAL_MAP_TYPES = MOB_TYPES.length;
+
+ 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;
+
+ 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);
+
+ private final ServerLevel world;
+ private final Reference2ReferenceOpenHashMap<ServerPlayer, TrackedPlayer[]> players = new Reference2ReferenceOpenHashMap<>();
+ private final Long2ReferenceOpenHashMap<TrackedChunk> byChunk = new Long2ReferenceOpenHashMap<>();
+
+ public NearbyPlayers(final ServerLevel world) {
+ this.world = world;
+ }
+
+ public void addPlayer(final ServerPlayer player) {
+ final TrackedPlayer[] newTrackers = new TrackedPlayer[TOTAL_MAP_TYPES];
+ if (this.players.put(player, newTrackers) != null) {
+ throw new IllegalStateException("Already have player " + player);
+ }
+
+ final ChunkPos chunk = player.chunkPosition();
+
+ for (int i = 0; i < TOTAL_MAP_TYPES; ++i) {
+ // use 0 for default, will be updated by tickPlayer
+ (newTrackers[i] = new TrackedPlayer(player, MOB_TYPES[i])).add(chunk.x, chunk.z, 0);
+ }
+
+ // update view distances
+ this.tickPlayer(player);
+ }
+
+ public void removePlayer(final ServerPlayer player) {
+ final TrackedPlayer[] players = this.players.remove(player);
+ if (players == null) {
+ throw new IllegalStateException("Don't have player " + player);
+ }
+
+ for (final TrackedPlayer tracker : players) {
+ tracker.remove();
+ }
+ }
+
+ public void tickPlayer(final ServerPlayer player) {
+ final TrackedPlayer[] players = this.players.get(player);
+ if (players == null) {
+ throw new IllegalStateException("Don't have player " + player);
+ }
+
+ final ChunkPos chunk = player.chunkPosition();
+
+ players[NearbyMapType.GENERAL.ordinal()].update(chunk.x, chunk.z, GENERAL_AREA_VIEW_DISTANCE);
+ players[NearbyMapType.GENERAL_SMALL.ordinal()].update(chunk.x, chunk.z, GENERAL_SMALL_VIEW_DISTANCE);
+ 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));
+ }
+
+ public TrackedChunk getChunk(final ChunkPos pos) {
+ return this.byChunk.get(CoordinateUtils.getChunkKey(pos));
+ }
+
+ public TrackedChunk getChunk(final BlockPos pos) {
+ return this.byChunk.get(CoordinateUtils.getChunkKey(pos));
+ }
+
+ public ReferenceList<ServerPlayer> getPlayers(final BlockPos pos, final NearbyMapType type) {
+ final TrackedChunk chunk = this.byChunk.get(CoordinateUtils.getChunkKey(pos));
+
+ return chunk == null ? null : chunk.players[type.ordinal()];
+ }
+
+ public ReferenceList<ServerPlayer> getPlayers(final ChunkPos pos, final NearbyMapType type) {
+ final TrackedChunk chunk = this.byChunk.get(CoordinateUtils.getChunkKey(pos));
+
+ return chunk == null ? null : chunk.players[type.ordinal()];
+ }
+
+ public ReferenceList<ServerPlayer> getPlayersByChunk(final int chunkX, final int chunkZ, final NearbyMapType type) {
+ final TrackedChunk chunk = this.byChunk.get(CoordinateUtils.getChunkKey(chunkX, chunkZ));
+
+ return chunk == null ? null : chunk.players[type.ordinal()];
+ }
+
+ public ReferenceList<ServerPlayer> getPlayersByBlock(final int blockX, final int blockZ, final NearbyMapType type) {
+ final TrackedChunk chunk = this.byChunk.get(CoordinateUtils.getChunkKey(blockX >> 4, blockZ >> 4));
+
+ return chunk == null ? null : chunk.players[type.ordinal()];
+ }
+
+ public static final class TrackedChunk {
+
+ public final ReferenceList<ServerPlayer>[] players = new ReferenceList[TOTAL_MAP_TYPES];
+ private int nonEmptyLists;
+ private int updateCount;
+
+ public boolean isEmpty() {
+ return this.nonEmptyLists == 0;
+ }
+
+ public int getUpdateCount() {
+ return this.updateCount;
+ }
+
+ public ReferenceList<ServerPlayer> getPlayers(final NearbyMapType type) {
+ return this.players[type.ordinal()];
+ }
+
+ public void addPlayer(final ServerPlayer player, final NearbyMapType type) {
+ ++this.updateCount;
+ final int idx = type.ordinal();
+ final ReferenceList<ServerPlayer> list = this.players[idx];
+ if (list == null) {
+ ++this.nonEmptyLists;
+ (this.players[idx] = new ReferenceList<>()).add(player);
+ return;
+ }
+
+ if (!list.add(player)) {
+ throw new IllegalStateException("Already contains player " + player);
+ }
+ }
+
+ public void removePlayer(final ServerPlayer player, final NearbyMapType type) {
+ ++this.updateCount;
+ final int idx = type.ordinal();
+ final ReferenceList<ServerPlayer> list = this.players[idx];
+ if (list == null) {
+ throw new IllegalStateException("Does not contain player " + player);
+ }
+
+ if (!list.remove(player)) {
+ throw new IllegalStateException("Does not contain player " + player);
+ }
+
+ if (list.size() == 0) {
+ this.players[idx] = null;
+ --this.nonEmptyLists;
+ }
+ }
+ }
+
+ private final class TrackedPlayer extends SingleUserAreaMap<ServerPlayer> {
+
+ final NearbyMapType type;
+
+ public TrackedPlayer(final ServerPlayer player, final NearbyMapType type) {
+ super(player);
+ this.type = type;
+ }
+
+ @Override
+ protected void addCallback(final ServerPlayer parameter, final int chunkX, final int chunkZ) {
+ final long chunkKey = CoordinateUtils.getChunkKey(chunkX, chunkZ);
+
+ NearbyPlayers.this.byChunk.computeIfAbsent(chunkKey, (final long keyInMap) -> {
+ return new TrackedChunk();
+ }).addPlayer(parameter, this.type);
+ }
+
+ @Override
+ protected void removeCallback(final ServerPlayer parameter, final int chunkX, final int chunkZ) {
+ final long chunkKey = CoordinateUtils.getChunkKey(chunkX, chunkZ);
+
+ final TrackedChunk chunk = NearbyPlayers.this.byChunk.get(chunkKey);
+ if (chunk == null) {
+ throw new IllegalStateException("Chunk should exist at " + new ChunkPos(chunkKey));
+ }
+
+ chunk.removePlayer(parameter, this.type);
+
+ if (chunk.isEmpty()) {
+ NearbyPlayers.this.byChunk.remove(chunkKey);
+ }
+ }
+ }
+}
diff --git a/src/main/java/io/papermc/paper/util/player/SingleUserAreaMap.java b/src/main/java/io/papermc/paper/util/player/SingleUserAreaMap.java
new file mode 100644
index 0000000000000000000000000000000000000000..d603887f4d0464f4463172fd79bcd5298d54983e
--- /dev/null
+++ b/src/main/java/io/papermc/paper/util/player/SingleUserAreaMap.java
@@ -0,0 +1,232 @@
+package io.papermc.paper.util.player;
+
+import io.papermc.paper.util.IntegerUtil;
+
+public abstract class SingleUserAreaMap<T> {
+
+ private static final int NOT_SET = Integer.MIN_VALUE;
+
+ private final T parameter;
+ private int lastChunkX = NOT_SET;
+ private int lastChunkZ = NOT_SET;
+ private int distance = NOT_SET;
+
+ public SingleUserAreaMap(final T parameter) {
+ this.parameter = parameter;
+ }
+
+ /* math sign function except 0 returns 1 */
+ protected static int sign(int val) {
+ return 1 | (val >> (Integer.SIZE - 1));
+ }
+
+ protected abstract void addCallback(final T parameter, final int chunkX, final int chunkZ);
+
+ protected abstract void removeCallback(final T parameter, final int chunkX, final int chunkZ);
+
+ private void addToNew(final T parameter, final int chunkX, final int chunkZ, final int distance) {
+ final int maxX = chunkX + distance;
+ final int maxZ = chunkZ + distance;
+
+ for (int cx = chunkX - distance; cx <= maxX; ++cx) {
+ for (int cz = chunkZ - distance; cz <= maxZ; ++cz) {
+ this.addCallback(parameter, cx, cz);
+ }
+ }
+ }
+
+ private void removeFromOld(final T parameter, final int chunkX, final int chunkZ, final int distance) {
+ final int maxX = chunkX + distance;
+ final int maxZ = chunkZ + distance;
+
+ for (int cx = chunkX - distance; cx <= maxX; ++cx) {
+ for (int cz = chunkZ - distance; cz <= maxZ; ++cz) {
+ this.removeCallback(parameter, cx, cz);
+ }
+ }
+ }
+
+ public final boolean add(final int chunkX, final int chunkZ, final int distance) {
+ if (distance < 0) {
+ throw new IllegalArgumentException(Integer.toString(distance));
+ }
+ if (this.lastChunkX != NOT_SET) {
+ return false;
+ }
+ this.lastChunkX = chunkX;
+ this.lastChunkZ = chunkZ;
+ this.distance = distance;
+
+ this.addToNew(this.parameter, chunkX, chunkZ, distance);
+
+ return true;
+ }
+
+ public final boolean update(final int toX, final int toZ, final int newViewDistance) {
+ if (newViewDistance < 0) {
+ throw new IllegalArgumentException(Integer.toString(newViewDistance));
+ }
+ final int fromX = this.lastChunkX;
+ final int fromZ = this.lastChunkZ;
+ final int oldViewDistance = this.distance;
+ if (fromX == NOT_SET) {
+ return false;
+ }
+
+ this.lastChunkX = toX;
+ this.lastChunkZ = toZ;
+ this.distance = newViewDistance;
+
+ final T parameter = this.parameter;
+
+
+ final int dx = toX - fromX;
+ final int dz = toZ - fromZ;
+
+ final int totalX = IntegerUtil.branchlessAbs(fromX - toX);
+ final int totalZ = IntegerUtil.branchlessAbs(fromZ - toZ);
+
+ if (Math.max(totalX, totalZ) > (2 * Math.max(newViewDistance, oldViewDistance))) {
+ // teleported?
+ this.removeFromOld(parameter, fromX, fromZ, oldViewDistance);
+ this.addToNew(parameter, toX, toZ, newViewDistance);
+ return true;
+ }
+
+ if (oldViewDistance != newViewDistance) {
+ // remove loop
+
+ final int oldMinX = fromX - oldViewDistance;
+ final int oldMinZ = fromZ - oldViewDistance;
+ final int oldMaxX = fromX + oldViewDistance;
+ final int oldMaxZ = fromZ + oldViewDistance;
+ for (int currX = oldMinX; currX <= oldMaxX; ++currX) {
+ for (int currZ = oldMinZ; currZ <= oldMaxZ; ++currZ) {
+
+ // only remove if we're outside the new view distance...
+ if (Math.max(IntegerUtil.branchlessAbs(currX - toX), IntegerUtil.branchlessAbs(currZ - toZ)) > newViewDistance) {
+ this.removeCallback(parameter, currX, currZ);
+ }
+ }
+ }
+
+ // add loop
+
+ final int newMinX = toX - newViewDistance;
+ final int newMinZ = toZ - newViewDistance;
+ final int newMaxX = toX + newViewDistance;
+ final int newMaxZ = toZ + newViewDistance;
+ for (int currX = newMinX; currX <= newMaxX; ++currX) {
+ for (int currZ = newMinZ; currZ <= newMaxZ; ++currZ) {
+
+ // only add if we're outside the old view distance...
+ if (Math.max(IntegerUtil.branchlessAbs(currX - fromX), IntegerUtil.branchlessAbs(currZ - fromZ)) > oldViewDistance) {
+ this.addCallback(parameter, currX, currZ);
+ }
+ }
+ }
+
+ return true;
+ }
+
+ // x axis is width
+ // z axis is height
+ // right refers to the x axis of where we moved
+ // top refers to the z axis of where we moved
+
+ // same view distance
+
+ // used for relative positioning
+ final int up = sign(dz); // 1 if dz >= 0, -1 otherwise
+ final int right = sign(dx); // 1 if dx >= 0, -1 otherwise
+
+ // The area excluded by overlapping the two view distance squares creates four rectangles:
+ // Two on the left, and two on the right. The ones on the left we consider the "removed" section
+ // and on the right the "added" section.
+ // https://i.imgur.com/MrnOBgI.png is a reference image. Note that the outside border is not actually
+ // exclusive to the regions they surround.
+
+ // 4 points of the rectangle
+ int maxX; // exclusive
+ int minX; // inclusive
+ int maxZ; // exclusive
+ int minZ; // inclusive
+
+ if (dx != 0) {
+ // handle right addition
+
+ maxX = toX + (oldViewDistance * right) + right; // exclusive
+ minX = fromX + (oldViewDistance * right) + right; // inclusive
+ maxZ = fromZ + (oldViewDistance * up) + up; // exclusive
+ minZ = toZ - (oldViewDistance * up); // inclusive
+
+ for (int currX = minX; currX != maxX; currX += right) {
+ for (int currZ = minZ; currZ != maxZ; currZ += up) {
+ this.addCallback(parameter, currX, currZ);
+ }
+ }
+ }
+
+ if (dz != 0) {
+ // handle up addition
+
+ maxX = toX + (oldViewDistance * right) + right; // exclusive
+ minX = toX - (oldViewDistance * right); // inclusive
+ maxZ = toZ + (oldViewDistance * up) + up; // exclusive
+ minZ = fromZ + (oldViewDistance * up) + up; // inclusive
+
+ for (int currX = minX; currX != maxX; currX += right) {
+ for (int currZ = minZ; currZ != maxZ; currZ += up) {
+ this.addCallback(parameter, currX, currZ);
+ }
+ }
+ }
+
+ if (dx != 0) {
+ // handle left removal
+
+ maxX = toX - (oldViewDistance * right); // exclusive
+ minX = fromX - (oldViewDistance * right); // inclusive
+ maxZ = fromZ + (oldViewDistance * up) + up; // exclusive
+ minZ = toZ - (oldViewDistance * up); // inclusive
+
+ for (int currX = minX; currX != maxX; currX += right) {
+ for (int currZ = minZ; currZ != maxZ; currZ += up) {
+ this.removeCallback(parameter, currX, currZ);
+ }
+ }
+ }
+
+ if (dz != 0) {
+ // handle down removal
+
+ maxX = fromX + (oldViewDistance * right) + right; // exclusive
+ minX = fromX - (oldViewDistance * right); // inclusive
+ maxZ = toZ - (oldViewDistance * up); // exclusive
+ minZ = fromZ - (oldViewDistance * up); // inclusive
+
+ for (int currX = minX; currX != maxX; currX += right) {
+ for (int currZ = minZ; currZ != maxZ; currZ += up) {
+ this.removeCallback(parameter, currX, currZ);
+ }
+ }
+ }
+
+ return true;
+ }
+
+ public final boolean remove() {
+ final int chunkX = this.lastChunkX;
+ final int chunkZ = this.lastChunkZ;
+ final int distance = this.distance;
+ if (chunkX == NOT_SET) {
+ return false;
+ }
+
+ this.lastChunkX = this.lastChunkZ = this.distance = NOT_SET;
+
+ this.removeFromOld(this.parameter, chunkX, chunkZ, distance);
+
+ return true;
+ }
+}
diff --git a/src/main/java/net/minecraft/Util.java b/src/main/java/net/minecraft/Util.java
index 092bfedfb32c38550d1cab1b696feac6df09131f..9870eccc1dc5c2201f12f8e2affe647f6b0375f8 100644
--- a/src/main/java/net/minecraft/Util.java
@ -5580,30 +6027,29 @@ index 929d31aa624f035eb314dece08969b102f5781fc..e94f0361cbca873f05b5b768c68c0933
+ // Paper end - MC Utils - default query payloads
}
diff --git a/src/main/java/net/minecraft/network/protocol/login/ServerboundCustomQueryAnswerPacket.java b/src/main/java/net/minecraft/network/protocol/login/ServerboundCustomQueryAnswerPacket.java
index 44cac39893eb968aa8ea21ee571c0dcb866ce06c..953e7573f6b2ca73a8c27c4d63edec89b173f333 100644
index 44cac39893eb968aa8ea21ee571c0dcb866ce06c..5151d68ba6ec72a7124f298253c5f0af080b2ea6 100644
--- a/src/main/java/net/minecraft/network/protocol/login/ServerboundCustomQueryAnswerPacket.java
+++ b/src/main/java/net/minecraft/network/protocol/login/ServerboundCustomQueryAnswerPacket.java
@@ -15,7 +15,18 @@ public record ServerboundCustomQueryAnswerPacket(int transactionId, @Nullable Cu
@@ -15,7 +15,17 @@ public record ServerboundCustomQueryAnswerPacket(int transactionId, @Nullable Cu
}
private static CustomQueryAnswerPayload readPayload(int queryId, FriendlyByteBuf buf) {
- return readUnknownPayload(buf);
+ // Paper start - MC Utils - default query payloads
+ return new net.minecraft.network.protocol.login.ServerboundCustomQueryAnswerPacket.QueryAnswerPayload(
+ buf.readNullable((buf2) -> {
+ int i = buf2.readableBytes();
+ if (i >= 0 && i <= MAX_PAYLOAD_SIZE) {
+ return new FriendlyByteBuf(buf2.readBytes(i));
+ } else {
+ throw new IllegalArgumentException("Payload may not be larger than " + MAX_PAYLOAD_SIZE + " bytes");
+ }
+ })
+ );
+ FriendlyByteBuf buffer = buf.readNullable((buf2) -> {
+ int i = buf2.readableBytes();
+ if (i >= 0 && i <= MAX_PAYLOAD_SIZE) {
+ return new FriendlyByteBuf(buf2.readBytes(i));
+ } else {
+ throw new IllegalArgumentException("Payload may not be larger than " + MAX_PAYLOAD_SIZE + " bytes");
+ }
+ });
+ return buffer == null ? null : new net.minecraft.network.protocol.login.ServerboundCustomQueryAnswerPacket.QueryAnswerPayload(buffer);
+ // Paper end - MC Utils - default query payloads
}
private static CustomQueryAnswerPayload readUnknownPayload(FriendlyByteBuf buf) {
@@ -40,4 +51,21 @@ public record ServerboundCustomQueryAnswerPacket(int transactionId, @Nullable Cu
@@ -40,4 +50,21 @@ public record ServerboundCustomQueryAnswerPacket(int transactionId, @Nullable Cu
public void handle(ServerLoginPacketListener listener) {
listener.handleCustomQueryPacket(this);
}
@ -5920,10 +6366,10 @@ index 1641bdf8725df778ba91bf5cd22c1ebbb3745058..facfdbb87e89f4db33ce13233c2ba436
+ // Paper end
}
diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java
index e9cf8686b59c232816b2fde92fc6616f77979a64..90dce7ed0d3d3dee3bae6657ac3cbeb54dd199ce 100644
index e9cf8686b59c232816b2fde92fc6616f77979a64..10132390dd356461f696971b34df3eeed05c572e 100644
--- a/src/main/java/net/minecraft/server/level/ChunkMap.java
+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java
@@ -167,6 +167,56 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
@@ -167,6 +167,62 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
};
// CraftBukkit end
@ -5934,16 +6380,21 @@ index e9cf8686b59c232816b2fde92fc6616f77979a64..90dce7ed0d3d3dee3bae6657ac3cbeb5
+ int chunkX = io.papermc.paper.util.MCUtil.getChunkCoordinate(player.getX());
+ int chunkZ = io.papermc.paper.util.MCUtil.getChunkCoordinate(player.getZ());
+ // Note: players need to be explicitly added to distance maps before they can be updated
+ this.nearbyPlayers.addPlayer(player);
+ }
+
+ void removePlayerFromDistanceMaps(ServerPlayer player) {
+
+ int chunkX = io.papermc.paper.util.MCUtil.getChunkCoordinate(player.getX());
+ int chunkZ = io.papermc.paper.util.MCUtil.getChunkCoordinate(player.getZ());
+ // Note: players need to be explicitly added to distance maps before they can be updated
+ this.nearbyPlayers.removePlayer(player);
+ }
+
+ void updateMaps(ServerPlayer player) {
+ int chunkX = io.papermc.paper.util.MCUtil.getChunkCoordinate(player.getX());
+ int chunkZ = io.papermc.paper.util.MCUtil.getChunkCoordinate(player.getZ());
+ // Note: players need to be explicitly added to distance maps before they can be updated
+ this.nearbyPlayers.tickPlayer(player);
+ }
+ // Paper end
+ // Paper start
@ -5975,23 +6426,33 @@ index e9cf8686b59c232816b2fde92fc6616f77979a64..90dce7ed0d3d3dee3bae6657ac3cbeb5
+ public final ChunkHolder getUnloadingChunkHolder(int chunkX, int chunkZ) {
+ return this.pendingUnloads.get(io.papermc.paper.util.CoordinateUtils.getChunkKey(chunkX, chunkZ));
+ }
+ public final io.papermc.paper.util.player.NearbyPlayers nearbyPlayers;
+ // Paper end
+
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);
this.visibleChunkMap = this.updatingChunkMap.clone();
@@ -220,6 +270,10 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
@@ -220,7 +276,19 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
this.overworldDataStorage = persistentStateManagerFactory;
this.poiManager = new PoiManager(path.resolve("poi"), dataFixer, dsync, iregistrycustom, world);
this.setServerViewDistance(viewDistance);
+ // Paper start
+ this.dataRegionManager = new io.papermc.paper.chunk.SingleThreadChunkRegionManager(this.level, 2, (1.0 / 3.0), 1, 6, "Data", DataRegionData::new, DataRegionSectionData::new);
+ this.regionManagers.add(this.dataRegionManager);
+ this.nearbyPlayers = new io.papermc.paper.util.player.NearbyPlayers(this.level);
+ // Paper end
+ }
+
+ // Paper start
+ // always use accessor, so folia can override
+ public final io.papermc.paper.util.player.NearbyPlayers getNearbyPlayers() {
+ return this.nearbyPlayers;
}
+ // Paper end
protected ChunkGenerator generator() {
@@ -321,6 +375,15 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
return this.generator;
@@ -321,6 +389,15 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
}
}
@ -6007,7 +6468,7 @@ index e9cf8686b59c232816b2fde92fc6616f77979a64..90dce7ed0d3d3dee3bae6657ac3cbeb5
private CompletableFuture<Either<List<ChunkAccess>, ChunkHolder.ChunkLoadingFailure>> getChunkRangeFuture(ChunkHolder centerChunk, int margin, IntFunction<ChunkStatus> distanceToStatus) {
if (margin == 0) {
ChunkStatus chunkstatus = (ChunkStatus) distanceToStatus.apply(0);
@@ -417,9 +480,9 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
@@ -417,9 +494,9 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
};
stringbuilder.append("Updating:").append(System.lineSeparator());
@ -6019,7 +6480,7 @@ index e9cf8686b59c232816b2fde92fc6616f77979a64..90dce7ed0d3d3dee3bae6657ac3cbeb5
CrashReport crashreport = CrashReport.forThrowable(exception, "Chunk loading");
CrashReportCategory crashreportsystemdetails = crashreport.addCategory("Chunk loading");
@@ -461,8 +524,14 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
@@ -461,8 +538,14 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
holder.setTicketLevel(level);
} else {
holder = new ChunkHolder(new ChunkPos(pos), level, this.level, this.lightEngine, this.queueSorter, this);
@ -6034,7 +6495,7 @@ index e9cf8686b59c232816b2fde92fc6616f77979a64..90dce7ed0d3d3dee3bae6657ac3cbeb5
this.updatingChunkMap.put(pos, holder);
this.modified = true;
}
@@ -484,7 +553,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
@@ -484,7 +567,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
protected void saveAllChunks(boolean flush) {
if (flush) {
@ -6043,7 +6504,7 @@ index e9cf8686b59c232816b2fde92fc6616f77979a64..90dce7ed0d3d3dee3bae6657ac3cbeb5
MutableBoolean mutableboolean = new MutableBoolean();
do {
@@ -513,7 +582,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
@@ -513,7 +596,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
});
this.flushWorker();
} else {
@ -6052,7 +6513,7 @@ index e9cf8686b59c232816b2fde92fc6616f77979a64..90dce7ed0d3d3dee3bae6657ac3cbeb5
}
}
@@ -532,7 +601,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
@@ -532,7 +615,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
}
public boolean hasWork() {
@ -6061,7 +6522,7 @@ index e9cf8686b59c232816b2fde92fc6616f77979a64..90dce7ed0d3d3dee3bae6657ac3cbeb5
}
private void processUnloads(BooleanSupplier shouldKeepTicking) {
@@ -543,6 +612,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
@@ -543,6 +626,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
ChunkHolder playerchunk = (ChunkHolder) this.updatingChunkMap.remove(j);
if (playerchunk != null) {
@ -6069,7 +6530,7 @@ index e9cf8686b59c232816b2fde92fc6616f77979a64..90dce7ed0d3d3dee3bae6657ac3cbeb5
this.pendingUnloads.put(j, playerchunk);
this.modified = true;
++i;
@@ -560,7 +630,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
@@ -560,7 +644,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
}
int l = 0;
@ -6078,7 +6539,7 @@ index e9cf8686b59c232816b2fde92fc6616f77979a64..90dce7ed0d3d3dee3bae6657ac3cbeb5
while (l < 20 && shouldKeepTicking.getAsBoolean() && objectiterator.hasNext()) {
if (this.saveChunkIfNeeded((ChunkHolder) objectiterator.next())) {
@@ -578,7 +648,11 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
@@ -578,7 +662,11 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
if (completablefuture1 != completablefuture) {
this.scheduleUnload(pos, holder);
} else {
@ -6091,7 +6552,7 @@ index e9cf8686b59c232816b2fde92fc6616f77979a64..90dce7ed0d3d3dee3bae6657ac3cbeb5
if (ichunkaccess instanceof LevelChunk) {
((LevelChunk) ichunkaccess).setLoaded(false);
}
@@ -594,7 +668,9 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
@@ -594,7 +682,9 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
this.lightEngine.tryScheduleUpdate();
this.progressListener.onStatusChange(ichunkaccess.getPos(), (ChunkStatus) null);
this.chunkSaveCooldowns.remove(ichunkaccess.getPos().toLong());
@ -6102,7 +6563,7 @@ index e9cf8686b59c232816b2fde92fc6616f77979a64..90dce7ed0d3d3dee3bae6657ac3cbeb5
}
};
@@ -1037,7 +1113,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
@@ -1037,7 +1127,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
}
public int size() {
@ -6111,7 +6572,7 @@ index e9cf8686b59c232816b2fde92fc6616f77979a64..90dce7ed0d3d3dee3bae6657ac3cbeb5
}
public DistanceManager getDistanceManager() {
@@ -1045,19 +1121,19 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
@@ -1045,19 +1135,19 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
}
protected Iterable<ChunkHolder> getChunks() {
@ -6136,7 +6597,7 @@ index e9cf8686b59c232816b2fde92fc6616f77979a64..90dce7ed0d3d3dee3bae6657ac3cbeb5
Optional<ChunkAccess> optional = Optional.ofNullable(playerchunk.getLastAvailable());
Optional<LevelChunk> optional1 = optional.flatMap((ichunkaccess) -> {
return ichunkaccess instanceof LevelChunk ? Optional.of((LevelChunk) ichunkaccess) : Optional.empty();
@@ -1182,6 +1258,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
@@ -1182,6 +1272,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
player.setChunkTrackingView(ChunkTrackingView.EMPTY);
this.updateChunkTracking(player);
@ -6144,7 +6605,7 @@ index e9cf8686b59c232816b2fde92fc6616f77979a64..90dce7ed0d3d3dee3bae6657ac3cbeb5
} else {
SectionPos sectionposition = player.getLastSectionPos();
@@ -1190,6 +1267,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
@@ -1190,6 +1281,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
this.distanceManager.removePlayer(sectionposition, player);
}
@ -6152,7 +6613,7 @@ index e9cf8686b59c232816b2fde92fc6616f77979a64..90dce7ed0d3d3dee3bae6657ac3cbeb5
this.applyChunkTrackingView(player, ChunkTrackingView.EMPTY);
}
@@ -1241,6 +1319,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
@@ -1241,6 +1333,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
this.updateChunkTracking(player);
}
@ -6160,7 +6621,7 @@ index e9cf8686b59c232816b2fde92fc6616f77979a64..90dce7ed0d3d3dee3bae6657ac3cbeb5
}
private void updateChunkTracking(ServerPlayer player) {
@@ -1493,7 +1572,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
@@ -1493,7 +1586,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
private class ChunkDistanceManager extends DistanceManager {
protected ChunkDistanceManager(Executor workerExecutor, Executor mainThreadExecutor) {

View File

@ -1010,7 +1010,7 @@ index ff3f00cf1d5180f83b16acac5676aa22cd967c8a..5aa21689e308842fe5b64689265ba45a
// CraftBukkit end
}
diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java
index 90dce7ed0d3d3dee3bae6657ac3cbeb54dd199ce..449bd9f505fdfb9eab46ff9309d7665bced1e5f8 100644
index 10132390dd356461f696971b34df3eeed05c572e..4dc04c16453174dde2c6bfad711ec9dec01c8f30 100644
--- a/src/main/java/net/minecraft/server/level/ChunkMap.java
+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java
@@ -1,8 +1,10 @@
@ -1024,7 +1024,7 @@ index 90dce7ed0d3d3dee3bae6657ac3cbeb54dd199ce..449bd9f505fdfb9eab46ff9309d7665b
import com.google.common.collect.Lists;
import com.google.common.collect.Queues;
import com.google.common.collect.Sets;
@@ -882,6 +884,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
@@ -896,6 +898,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
ChunkStatus chunkstatus = ChunkLevel.generationStatus(chunkHolder.getTicketLevel());
return !chunkstatus.isOrAfter(ChunkStatus.FULL) ? ChunkHolder.UNLOADED_CHUNK : either.mapLeft((ichunkaccess) -> {
@ -1032,7 +1032,7 @@ index 90dce7ed0d3d3dee3bae6657ac3cbeb54dd199ce..449bd9f505fdfb9eab46ff9309d7665b
ChunkPos chunkcoordintpair = chunkHolder.getPos();
ProtoChunk protochunk = (ProtoChunk) ichunkaccess;
LevelChunk chunk;
@@ -906,6 +909,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
@@ -920,6 +923,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
}
return chunk;
@ -1040,7 +1040,7 @@ index 90dce7ed0d3d3dee3bae6657ac3cbeb54dd199ce..449bd9f505fdfb9eab46ff9309d7665b
});
}, (runnable) -> {
ProcessorHandle mailbox = this.mainThreadMailbox;
@@ -1457,6 +1461,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
@@ -1471,6 +1475,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
List<ServerPlayer> list = Lists.newArrayList();
List<ServerPlayer> list1 = this.level.players();
ObjectIterator objectiterator = this.entityMap.values().iterator();
@ -1048,7 +1048,7 @@ index 90dce7ed0d3d3dee3bae6657ac3cbeb54dd199ce..449bd9f505fdfb9eab46ff9309d7665b
ChunkMap.TrackedEntity playerchunkmap_entitytracker;
@@ -1481,14 +1486,17 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
@@ -1495,14 +1500,17 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
playerchunkmap_entitytracker.serverEntity.sendChanges();
}
}

View File

@ -4493,7 +4493,7 @@ index facfdbb87e89f4db33ce13233c2ba4366d35c15b..807a6bb1026dac2c4cd0a50afe06fd62
private final DebugBuffer<ChunkHolder.ChunkSaveDebug> chunkToSaveHistory;
public int oldTicketLevel;
diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java
index 449bd9f505fdfb9eab46ff9309d7665bced1e5f8..8c84461a5711cb408b0ead397417c31cb2f4d336 100644
index 4dc04c16453174dde2c6bfad711ec9dec01c8f30..b47e30e9ebe0d6a930e01aaf67c138fc345fb11e 100644
--- a/src/main/java/net/minecraft/server/level/ChunkMap.java
+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java
@@ -124,7 +124,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider

View File

@ -2095,7 +2095,7 @@ index 0000000000000000000000000000000000000000..99f49b5625cf51d6c97640553cf5c420
+ }
+}
diff --git a/src/main/java/io/papermc/paper/chunk/system/ChunkSystem.java b/src/main/java/io/papermc/paper/chunk/system/ChunkSystem.java
index 87ae7d64e67ebae5ab53cc239cdf6580dca31652..56c35149fd142af6ffe31434fec0064cf6ea3be5 100644
index 87ae7d64e67ebae5ab53cc239cdf6580dca31652..cbeaadaecf816070b3a37938c8e683180939afc4 100644
--- a/src/main/java/io/papermc/paper/chunk/system/ChunkSystem.java
+++ b/src/main/java/io/papermc/paper/chunk/system/ChunkSystem.java
@@ -32,191 +32,41 @@ public final class ChunkSystem {
@ -2299,7 +2299,40 @@ index 87ae7d64e67ebae5ab53cc239cdf6580dca31652..56c35149fd142af6ffe31434fec0064c
}
public static boolean hasAnyChunkHolders(final ServerLevel level) {
@@ -270,23 +120,15 @@ public final class ChunkSystem {
@@ -243,26 +93,31 @@ public final class ChunkSystem {
public static void onChunkBorder(final LevelChunk chunk, final ChunkHolder holder) {
chunk.playerChunk = holder;
+ chunk.chunkStatus = net.minecraft.server.level.FullChunkStatus.FULL;
}
public static void onChunkNotBorder(final LevelChunk chunk, final ChunkHolder holder) {
-
+ chunk.chunkStatus = net.minecraft.server.level.FullChunkStatus.INACCESSIBLE;
}
public static void onChunkTicking(final LevelChunk chunk, final ChunkHolder holder) {
chunk.level.getChunkSource().tickingChunks.add(chunk);
+ chunk.chunkStatus = net.minecraft.server.level.FullChunkStatus.BLOCK_TICKING;
}
public static void onChunkNotTicking(final LevelChunk chunk, final ChunkHolder holder) {
chunk.level.getChunkSource().tickingChunks.remove(chunk);
+ chunk.chunkStatus = net.minecraft.server.level.FullChunkStatus.FULL;
}
public static void onChunkEntityTicking(final LevelChunk chunk, final ChunkHolder holder) {
chunk.level.getChunkSource().entityTickingChunks.add(chunk);
+ chunk.chunkStatus = net.minecraft.server.level.FullChunkStatus.ENTITY_TICKING;
}
public static void onChunkNotEntityTicking(final LevelChunk chunk, final ChunkHolder holder) {
chunk.level.getChunkSource().entityTickingChunks.remove(chunk);
+ chunk.chunkStatus = net.minecraft.server.level.FullChunkStatus.BLOCK_TICKING;
}
public static ChunkHolder getUnloadingChunkHolder(final ServerLevel level, final int chunkX, final int chunkZ) {
@@ -270,23 +125,15 @@ public final class ChunkSystem {
}
public static int getSendViewDistance(final ServerPlayer player) {
@ -2328,21 +2361,20 @@ index 87ae7d64e67ebae5ab53cc239cdf6580dca31652..56c35149fd142af6ffe31434fec0064c
private ChunkSystem() {
diff --git a/src/main/java/io/papermc/paper/chunk/system/RegionizedPlayerChunkLoader.java b/src/main/java/io/papermc/paper/chunk/system/RegionizedPlayerChunkLoader.java
new file mode 100644
index 0000000000000000000000000000000000000000..842848872b86e5335863d309af956fee74110d52
index 0000000000000000000000000000000000000000..1b090f1e79b996e52097afc49c1cec85936653e6
--- /dev/null
+++ b/src/main/java/io/papermc/paper/chunk/system/RegionizedPlayerChunkLoader.java
@@ -0,0 +1,1440 @@
@@ -0,0 +1,1208 @@
+package io.papermc.paper.chunk.system;
+
+import ca.spottedleaf.concurrentutil.collection.SRSWLinkedQueue;
+import ca.spottedleaf.concurrentutil.executor.standard.PrioritisedExecutor;
+import ca.spottedleaf.concurrentutil.util.ConcurrentUtil;
+import io.papermc.paper.chunk.system.io.RegionFileIOThread;
+import io.papermc.paper.chunk.system.scheduling.ChunkHolderManager;
+import io.papermc.paper.configuration.GlobalConfiguration;
+import io.papermc.paper.util.CoordinateUtils;
+import io.papermc.paper.util.IntegerUtil;
+import io.papermc.paper.util.TickThread;
+import io.papermc.paper.util.player.SingleUserAreaMap;
+import it.unimi.dsi.fastutil.longs.Long2ByteOpenHashMap;
+import it.unimi.dsi.fastutil.longs.LongArrayFIFOQueue;
+import it.unimi.dsi.fastutil.longs.LongArrayList;
@ -2353,7 +2385,6 @@ index 0000000000000000000000000000000000000000..842848872b86e5335863d309af956fee
+import net.minecraft.network.protocol.game.ClientboundSetChunkCacheCenterPacket;
+import net.minecraft.network.protocol.game.ClientboundSetChunkCacheRadiusPacket;
+import net.minecraft.network.protocol.game.ClientboundSetSimulationDistancePacket;
+import net.minecraft.server.level.ChunkMap;
+import net.minecraft.server.level.ChunkTrackingView;
+import net.minecraft.server.level.ServerLevel;
+import net.minecraft.server.level.ServerPlayer;
@ -2365,7 +2396,6 @@ index 0000000000000000000000000000000000000000..842848872b86e5335863d309af956fee
+import net.minecraft.world.level.chunk.ChunkStatus;
+import net.minecraft.world.level.chunk.LevelChunk;
+import net.minecraft.world.level.levelgen.BelowZeroRetrogen;
+import org.apache.commons.lang3.mutable.MutableObject;
+import org.bukkit.craftbukkit.entity.CraftPlayer;
+import org.bukkit.entity.Player;
+import java.lang.invoke.VarHandle;
@ -2845,7 +2875,7 @@ index 0000000000000000000000000000000000000000..842848872b86e5335863d309af956fee
+ parameter.sendUnloadChunk(chunkX, chunkZ);
+ }
+ };
+ private final SingleUserAreaMap<PlayerChunkLoaderData> loadTicketCleanup = new SingleUserAreaMap<>(this) {
+ private final SingleUserAreaMap<io.papermc.paper.chunk.system.RegionizedPlayerChunkLoader.PlayerChunkLoaderData> loadTicketCleanup = new SingleUserAreaMap<>(this) {
+ @Override
+ protected void addCallback(final PlayerChunkLoaderData parameter, final int chunkX, final int chunkZ) {
+ // do nothing, we only care about remove
@ -3488,235 +3518,6 @@ index 0000000000000000000000000000000000000000..842848872b86e5335863d309af956fee
+ }
+ }
+
+ public static abstract class SingleUserAreaMap<T> {
+
+ private static final int NOT_SET = Integer.MIN_VALUE;
+
+ private final T parameter;
+ private int lastChunkX = NOT_SET;
+ private int lastChunkZ = NOT_SET;
+ private int distance = NOT_SET;
+
+ public SingleUserAreaMap(final T parameter) {
+ this.parameter = parameter;
+ }
+
+ /* math sign function except 0 returns 1 */
+ protected static int sign(int val) {
+ return 1 | (val >> (Integer.SIZE - 1));
+ }
+
+ protected abstract void addCallback(final T parameter, final int chunkX, final int chunkZ);
+
+ protected abstract void removeCallback(final T parameter, final int chunkX, final int chunkZ);
+
+ private void addToNew(final T parameter, final int chunkX, final int chunkZ, final int distance) {
+ final int maxX = chunkX + distance;
+ final int maxZ = chunkZ + distance;
+
+ for (int cx = chunkX - distance; cx <= maxX; ++cx) {
+ for (int cz = chunkZ - distance; cz <= maxZ; ++cz) {
+ this.addCallback(parameter, cx, cz);
+ }
+ }
+ }
+
+ private void removeFromOld(final T parameter, final int chunkX, final int chunkZ, final int distance) {
+ final int maxX = chunkX + distance;
+ final int maxZ = chunkZ + distance;
+
+ for (int cx = chunkX - distance; cx <= maxX; ++cx) {
+ for (int cz = chunkZ - distance; cz <= maxZ; ++cz) {
+ this.removeCallback(parameter, cx, cz);
+ }
+ }
+ }
+
+ public final boolean add(final int chunkX, final int chunkZ, final int distance) {
+ if (distance < 0) {
+ throw new IllegalArgumentException(Integer.toString(distance));
+ }
+ if (this.lastChunkX != NOT_SET) {
+ return false;
+ }
+ this.lastChunkX = chunkX;
+ this.lastChunkZ = chunkZ;
+ this.distance = distance;
+
+ this.addToNew(this.parameter, chunkX, chunkZ, distance);
+
+ return true;
+ }
+
+ public final boolean update(final int toX, final int toZ, final int newViewDistance) {
+ if (newViewDistance < 0) {
+ throw new IllegalArgumentException(Integer.toString(newViewDistance));
+ }
+ final int fromX = this.lastChunkX;
+ final int fromZ = this.lastChunkZ;
+ final int oldViewDistance = this.distance;
+ if (fromX == NOT_SET) {
+ return false;
+ }
+
+ this.lastChunkX = toX;
+ this.lastChunkZ = toZ;
+ this.distance = newViewDistance;
+
+ final T parameter = this.parameter;
+
+
+ final int dx = toX - fromX;
+ final int dz = toZ - fromZ;
+
+ final int totalX = IntegerUtil.branchlessAbs(fromX - toX);
+ final int totalZ = IntegerUtil.branchlessAbs(fromZ - toZ);
+
+ if (Math.max(totalX, totalZ) > (2 * Math.max(newViewDistance, oldViewDistance))) {
+ // teleported?
+ this.removeFromOld(parameter, fromX, fromZ, oldViewDistance);
+ this.addToNew(parameter, toX, toZ, newViewDistance);
+ return true;
+ }
+
+ if (oldViewDistance != newViewDistance) {
+ // remove loop
+
+ final int oldMinX = fromX - oldViewDistance;
+ final int oldMinZ = fromZ - oldViewDistance;
+ final int oldMaxX = fromX + oldViewDistance;
+ final int oldMaxZ = fromZ + oldViewDistance;
+ for (int currX = oldMinX; currX <= oldMaxX; ++currX) {
+ for (int currZ = oldMinZ; currZ <= oldMaxZ; ++currZ) {
+
+ // only remove if we're outside the new view distance...
+ if (Math.max(IntegerUtil.branchlessAbs(currX - toX), IntegerUtil.branchlessAbs(currZ - toZ)) > newViewDistance) {
+ this.removeCallback(parameter, currX, currZ);
+ }
+ }
+ }
+
+ // add loop
+
+ final int newMinX = toX - newViewDistance;
+ final int newMinZ = toZ - newViewDistance;
+ final int newMaxX = toX + newViewDistance;
+ final int newMaxZ = toZ + newViewDistance;
+ for (int currX = newMinX; currX <= newMaxX; ++currX) {
+ for (int currZ = newMinZ; currZ <= newMaxZ; ++currZ) {
+
+ // only add if we're outside the old view distance...
+ if (Math.max(IntegerUtil.branchlessAbs(currX - fromX), IntegerUtil.branchlessAbs(currZ - fromZ)) > oldViewDistance) {
+ this.addCallback(parameter, currX, currZ);
+ }
+ }
+ }
+
+ return true;
+ }
+
+ // x axis is width
+ // z axis is height
+ // right refers to the x axis of where we moved
+ // top refers to the z axis of where we moved
+
+ // same view distance
+
+ // used for relative positioning
+ final int up = sign(dz); // 1 if dz >= 0, -1 otherwise
+ final int right = sign(dx); // 1 if dx >= 0, -1 otherwise
+
+ // The area excluded by overlapping the two view distance squares creates four rectangles:
+ // Two on the left, and two on the right. The ones on the left we consider the "removed" section
+ // and on the right the "added" section.
+ // https://i.imgur.com/MrnOBgI.png is a reference image. Note that the outside border is not actually
+ // exclusive to the regions they surround.
+
+ // 4 points of the rectangle
+ int maxX; // exclusive
+ int minX; // inclusive
+ int maxZ; // exclusive
+ int minZ; // inclusive
+
+ if (dx != 0) {
+ // handle right addition
+
+ maxX = toX + (oldViewDistance * right) + right; // exclusive
+ minX = fromX + (oldViewDistance * right) + right; // inclusive
+ maxZ = fromZ + (oldViewDistance * up) + up; // exclusive
+ minZ = toZ - (oldViewDistance * up); // inclusive
+
+ for (int currX = minX; currX != maxX; currX += right) {
+ for (int currZ = minZ; currZ != maxZ; currZ += up) {
+ this.addCallback(parameter, currX, currZ);
+ }
+ }
+ }
+
+ if (dz != 0) {
+ // handle up addition
+
+ maxX = toX + (oldViewDistance * right) + right; // exclusive
+ minX = toX - (oldViewDistance * right); // inclusive
+ maxZ = toZ + (oldViewDistance * up) + up; // exclusive
+ minZ = fromZ + (oldViewDistance * up) + up; // inclusive
+
+ for (int currX = minX; currX != maxX; currX += right) {
+ for (int currZ = minZ; currZ != maxZ; currZ += up) {
+ this.addCallback(parameter, currX, currZ);
+ }
+ }
+ }
+
+ if (dx != 0) {
+ // handle left removal
+
+ maxX = toX - (oldViewDistance * right); // exclusive
+ minX = fromX - (oldViewDistance * right); // inclusive
+ maxZ = fromZ + (oldViewDistance * up) + up; // exclusive
+ minZ = toZ - (oldViewDistance * up); // inclusive
+
+ for (int currX = minX; currX != maxX; currX += right) {
+ for (int currZ = minZ; currZ != maxZ; currZ += up) {
+ this.removeCallback(parameter, currX, currZ);
+ }
+ }
+ }
+
+ if (dz != 0) {
+ // handle down removal
+
+ maxX = fromX + (oldViewDistance * right) + right; // exclusive
+ minX = fromX - (oldViewDistance * right); // inclusive
+ maxZ = toZ - (oldViewDistance * up); // exclusive
+ minZ = fromZ - (oldViewDistance * up); // inclusive
+
+ for (int currX = minX; currX != maxX; currX += right) {
+ for (int currZ = minZ; currZ != maxZ; currZ += up) {
+ this.removeCallback(parameter, currX, currZ);
+ }
+ }
+ }
+
+ return true;
+ }
+
+ public final boolean remove() {
+ final int chunkX = this.lastChunkX;
+ final int chunkZ = this.lastChunkZ;
+ final int distance = this.distance;
+ if (chunkX == NOT_SET) {
+ return false;
+ }
+
+ this.lastChunkX = this.lastChunkZ = this.distance = NOT_SET;
+
+ this.removeFromOld(this.parameter, chunkX, chunkZ, distance);
+
+ return true;
+ }
+ }
+
+ static final class CountedSRSWLinkedQueue<E> {
+
+ private final SRSWLinkedQueue<E> queue = new SRSWLinkedQueue<>();
@ -17710,7 +17511,7 @@ index 807a6bb1026dac2c4cd0a50afe06fd62ce23558b..2b998bdbe49bf8211b755e0eb7c1bf13
// Paper end
}
diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java
index 8c84461a5711cb408b0ead397417c31cb2f4d336..ea0b82165e452b7b82d1d9a58eef6059cba30552 100644
index b47e30e9ebe0d6a930e01aaf67c138fc345fb11e..e2510ee3f0cb93eae2452bec642855cd6c0c2974 100644
--- a/src/main/java/net/minecraft/server/level/ChunkMap.java
+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java
@@ -118,10 +118,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
@ -17745,7 +17546,7 @@ index 8c84461a5711cb408b0ead397417c31cb2f4d336..ea0b82165e452b7b82d1d9a58eef6059
private final String storageName;
private final PlayerMap playerMap;
public final Int2ObjectMap<ChunkMap.TrackedEntity> entityMap;
@@ -148,37 +143,20 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
@@ -148,26 +143,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
private final Queue<Runnable> unloadQueue;
private int serverViewDistance;
@ -17773,34 +17574,38 @@ index 8c84461a5711cb408b0ead397417c31cb2f4d336..ea0b82165e452b7b82d1d9a58eef6059
// Paper start - distance maps
private final com.destroystokyo.paper.util.misc.PooledLinkedHashSets<ServerPlayer> pooledLinkedPlayerHashSets = new com.destroystokyo.paper.util.misc.PooledLinkedHashSets<>();
void addPlayerToDistanceMaps(ServerPlayer player) {
+ this.level.playerChunkLoader.addPlayer(player); // Paper - replace chunk loader
int chunkX = io.papermc.paper.util.MCUtil.getChunkCoordinate(player.getX());
@@ -177,6 +153,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
int chunkZ = io.papermc.paper.util.MCUtil.getChunkCoordinate(player.getZ());
// Note: players need to be explicitly added to distance maps before they can be updated
this.nearbyPlayers.addPlayer(player);
+ this.level.playerChunkLoader.addPlayer(player); // Paper - replace chunk loader
}
void removePlayerFromDistanceMaps(ServerPlayer player) {
+ this.level.playerChunkLoader.removePlayer(player); // Paper - replace chunk loader
}
@@ -186,6 +164,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
int chunkX = io.papermc.paper.util.MCUtil.getChunkCoordinate(player.getX());
@@ -184,6 +161,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
int chunkZ = io.papermc.paper.util.MCUtil.getChunkCoordinate(player.getZ());
// Note: players need to be explicitly added to distance maps before they can be updated
this.nearbyPlayers.removePlayer(player);
+ this.level.playerChunkLoader.removePlayer(player); // Paper - replace chunk loader
}
void updateMaps(ServerPlayer player) {
@@ -191,6 +169,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
int chunkZ = io.papermc.paper.util.MCUtil.getChunkCoordinate(player.getZ());
// Note: players need to be explicitly added to distance maps before they can be updated
this.nearbyPlayers.tickPlayer(player);
+ this.level.playerChunkLoader.updatePlayer(player); // Paper - replace chunk loader
}
// Paper end
// Paper start
@@ -215,16 +194,13 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
@@ -220,17 +199,14 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
}
public final ChunkHolder getUnloadingChunkHolder(int chunkX, int chunkZ) {
- return this.pendingUnloads.get(io.papermc.paper.util.CoordinateUtils.getChunkKey(chunkX, chunkZ));
+ return null; // Paper - rewrite chunk system
}
public final io.papermc.paper.util.player.NearbyPlayers nearbyPlayers;
// Paper end
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) {
@ -17813,7 +17618,7 @@ index 8c84461a5711cb408b0ead397417c31cb2f4d336..ea0b82165e452b7b82d1d9a58eef6059
this.tickingGenerated = new AtomicInteger();
this.playerMap = new PlayerMap();
this.entityMap = new Int2ObjectOpenHashMap();
@@ -255,19 +231,17 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
@@ -261,19 +237,17 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
this.chunkGeneratorState = chunkGenerator.createState(iregistrycustom.lookupOrThrow(Registries.STRUCTURE_SET), this.randomState, j, world.spigotConfig); // Spigot
this.mainThreadExecutor = mainThreadExecutor;
@ -17838,7 +17643,7 @@ index 8c84461a5711cb408b0ead397417c31cb2f4d336..ea0b82165e452b7b82d1d9a58eef6059
this.distanceManager = new ChunkMap.ChunkDistanceManager(executor, mainThreadExecutor);
this.overworldDataStorage = persistentStateManagerFactory;
this.poiManager = new PoiManager(path.resolve("poi"), dataFixer, dsync, iregistrycustom, world);
@@ -311,23 +285,15 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
@@ -325,23 +299,15 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
}
boolean isChunkTracked(ServerPlayer player, int chunkX, int chunkZ) {
@ -17868,7 +17673,7 @@ index 8c84461a5711cb408b0ead397417c31cb2f4d336..ea0b82165e452b7b82d1d9a58eef6059
}
protected ThreadedLevelLightEngine getLightEngine() {
@@ -336,20 +302,22 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
@@ -350,20 +316,22 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
@Nullable
protected ChunkHolder getUpdatingChunkIfPresent(long pos) {
@ -17898,7 +17703,7 @@ index 8c84461a5711cb408b0ead397417c31cb2f4d336..ea0b82165e452b7b82d1d9a58eef6059
}
public String getChunkDebugData(ChunkPos chunkPos) {
@@ -379,92 +347,12 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
@@ -393,92 +361,12 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
// Paper start
public final int getEffectiveViewDistance() {
@ -17993,7 +17798,7 @@ index 8c84461a5711cb408b0ead397417c31cb2f4d336..ea0b82165e452b7b82d1d9a58eef6059
}
public ReportedException debugFuturesAndCreateReportedException(IllegalStateException exception, String details) {
@@ -494,263 +382,72 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
@@ -508,263 +396,72 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
}
public CompletableFuture<Either<LevelChunk, ChunkHolder.ChunkLoadingFailure>> prepareEntityTickingChunk(ChunkHolder chunk) {
@ -18277,7 +18082,7 @@ index 8c84461a5711cb408b0ead397417c31cb2f4d336..ea0b82165e452b7b82d1d9a58eef6059
return nbt.contains("Status", 8);
}
@@ -786,54 +483,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
@@ -800,54 +497,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
}
private CompletableFuture<Either<ChunkAccess, ChunkHolder.ChunkLoadingFailure>> scheduleChunkGeneration(ChunkHolder holder, ChunkStatus requiredStatus) {
@ -18333,7 +18138,7 @@ index 8c84461a5711cb408b0ead397417c31cb2f4d336..ea0b82165e452b7b82d1d9a58eef6059
}
protected void releaseLightTicket(ChunkPos pos) {
@@ -844,7 +494,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
@@ -858,7 +508,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
}));
}
@ -18342,7 +18147,7 @@ index 8c84461a5711cb408b0ead397417c31cb2f4d336..ea0b82165e452b7b82d1d9a58eef6059
ChunkStatus chunkstatus1;
if (distance == 0) {
@@ -856,7 +506,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
@@ -870,7 +520,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
return chunkstatus1;
}
@ -18351,7 +18156,7 @@ index 8c84461a5711cb408b0ead397417c31cb2f4d336..ea0b82165e452b7b82d1d9a58eef6059
if (!nbt.isEmpty()) {
// CraftBukkit start - these are spawned serialized (DefinedStructure) and we don't call an add event below at the moment due to ordering complexities
world.addWorldGenChunkEntities(EntityType.loadEntitiesRecursive(nbt, world).filter((entity) -> {
@@ -871,111 +521,27 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
@@ -885,111 +535,27 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
needsRemoval = true;
}
return !needsRemoval;
@ -18468,7 +18273,7 @@ index 8c84461a5711cb408b0ead397417c31cb2f4d336..ea0b82165e452b7b82d1d9a58eef6059
}
public int getTickingGenerated() {
@@ -983,130 +549,52 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
@@ -997,130 +563,52 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
}
private boolean saveChunkIfNeeded(ChunkHolder chunkHolder) {
@ -18616,7 +18421,7 @@ index 8c84461a5711cb408b0ead397417c31cb2f4d336..ea0b82165e452b7b82d1d9a58eef6059
}
@Nullable
@@ -1129,30 +617,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
@@ -1143,30 +631,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
}
void dumpChunks(Writer writer) throws IOException {
@ -18648,7 +18453,7 @@ index 8c84461a5711cb408b0ead397417c31cb2f4d336..ea0b82165e452b7b82d1d9a58eef6059
}
private static String printFuture(CompletableFuture<Either<LevelChunk, ChunkHolder.ChunkLoadingFailure>> future) {
@@ -1171,6 +636,35 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
@@ -1185,6 +650,35 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
}
}
@ -18684,7 +18489,7 @@ index 8c84461a5711cb408b0ead397417c31cb2f4d336..ea0b82165e452b7b82d1d9a58eef6059
private CompletableFuture<Optional<CompoundTag>> readChunk(ChunkPos chunkPos) {
return this.read(chunkPos).thenApplyAsync((optional) -> {
return optional.map((nbttagcompound) -> this.upgradeChunkTag(nbttagcompound, chunkPos)); // CraftBukkit
@@ -1260,8 +754,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
@@ -1274,8 +768,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
this.distanceManager.addPlayer(SectionPos.of((EntityAccess) player), player);
}
@ -18694,7 +18499,7 @@ index 8c84461a5711cb408b0ead397417c31cb2f4d336..ea0b82165e452b7b82d1d9a58eef6059
this.addPlayerToDistanceMaps(player); // Paper - distance maps
} else {
SectionPos sectionposition = player.getLastSectionPos();
@@ -1272,7 +765,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
@@ -1286,7 +779,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
}
this.removePlayerFromDistanceMaps(player); // Paper - distance maps
@ -18703,7 +18508,7 @@ index 8c84461a5711cb408b0ead397417c31cb2f4d336..ea0b82165e452b7b82d1d9a58eef6059
}
}
@@ -1320,73 +813,30 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
@@ -1334,73 +827,30 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
this.playerMap.unIgnorePlayer(player);
}
@ -18787,7 +18592,7 @@ index 8c84461a5711cb408b0ead397417c31cb2f4d336..ea0b82165e452b7b82d1d9a58eef6059
}
public void addEntity(Entity entity) {
@@ -1450,13 +900,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
@@ -1464,13 +914,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
}
protected void tick() {
@ -18802,7 +18607,7 @@ index 8c84461a5711cb408b0ead397417c31cb2f4d336..ea0b82165e452b7b82d1d9a58eef6059
List<ServerPlayer> list = Lists.newArrayList();
List<ServerPlayer> list1 = this.level.players();
@@ -1565,16 +1009,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
@@ -1579,16 +1023,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
}
public void waitForLightBeforeSending(ChunkPos centerPos, int radius) {
@ -18820,7 +18625,7 @@ index 8c84461a5711cb408b0ead397417c31cb2f4d336..ea0b82165e452b7b82d1d9a58eef6059
}
private class ChunkDistanceManager extends DistanceManager {
@@ -1585,7 +1020,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
@@ -1599,7 +1034,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
@Override
protected boolean isChunkToRemove(long pos) {
@ -21501,10 +21306,18 @@ index 846ae3fd184a1d63b743aa25e045604576697c96..a907b79fd8291a0e92db138f37239d17
public int getIndex() {
diff --git a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
index bcdaa86cfd31c2ce4aadad900c348aee0a9e3fc8..a8b2ce0debe54afeb937a4f1215d6b8955037d3d 100644
index bcdaa86cfd31c2ce4aadad900c348aee0a9e3fc8..85b38592c87bbc071d3fc5de5db131c6626fe004 100644
--- a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
+++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
@@ -661,9 +661,26 @@ public class LevelChunk extends ChunkAccess {
@@ -83,6 +83,7 @@ public class LevelChunk extends ChunkAccess {
private final Int2ObjectMap<GameEventListenerRegistry> gameEventListenerRegistrySections;
private final LevelChunkTicks<Block> blockTicks;
private final LevelChunkTicks<Fluid> fluidTicks;
+ public volatile FullChunkStatus chunkStatus = FullChunkStatus.INACCESSIBLE; // Paper - rewrite chunk system
public LevelChunk(Level world, ChunkPos pos) {
this(world, pos, UpgradeData.EMPTY, new LevelChunkTicks<>(), new LevelChunkTicks<>(), 0L, (LevelChunkSection[]) null, (LevelChunk.PostLoadProcessor) null, (BlendingData) null);
@@ -661,9 +662,26 @@ public class LevelChunk extends ChunkAccess {
}
@ -21534,7 +21347,7 @@ index bcdaa86cfd31c2ce4aadad900c348aee0a9e3fc8..a8b2ce0debe54afeb937a4f1215d6b89
int chunkX = this.chunkPos.x;
int chunkZ = this.chunkPos.z;
net.minecraft.server.level.ServerChunkCache chunkProvider = this.level.getChunkSource();
@@ -678,10 +695,55 @@ public class LevelChunk extends ChunkAccess {
@@ -678,10 +696,55 @@ public class LevelChunk extends ChunkAccess {
}
}
this.setNeighbourLoaded(0, 0, this);
@ -21592,7 +21405,7 @@ index bcdaa86cfd31c2ce4aadad900c348aee0a9e3fc8..a8b2ce0debe54afeb937a4f1215d6b89
if (server != null) {
/*
* If it's a new world, the first few chunks are generated inside
@@ -690,6 +752,7 @@ public class LevelChunk extends ChunkAccess {
@@ -690,6 +753,7 @@ public class LevelChunk extends ChunkAccess {
*/
org.bukkit.Chunk bukkitChunk = new org.bukkit.craftbukkit.CraftChunk(this);
server.getPluginManager().callEvent(new org.bukkit.event.world.ChunkLoadEvent(bukkitChunk, this.needsDecoration));
@ -21600,7 +21413,7 @@ index bcdaa86cfd31c2ce4aadad900c348aee0a9e3fc8..a8b2ce0debe54afeb937a4f1215d6b89
if (this.needsDecoration) {
try (co.aikar.timings.Timing ignored = this.level.timings.chunkLoadPopulate.startTiming()) { // Paper
@@ -718,9 +781,11 @@ public class LevelChunk extends ChunkAccess {
@@ -718,9 +782,11 @@ public class LevelChunk extends ChunkAccess {
}
public void unloadCallback() {
@ -21613,7 +21426,7 @@ index bcdaa86cfd31c2ce4aadad900c348aee0a9e3fc8..a8b2ce0debe54afeb937a4f1215d6b89
server.getPluginManager().callEvent(unloadEvent);
// note: saving can be prevented, but not forced if no saving is actually required
this.mustNotSave = !unloadEvent.isSaveChunk();
@@ -742,9 +807,26 @@ public class LevelChunk extends ChunkAccess {
@@ -742,9 +808,26 @@ public class LevelChunk extends ChunkAccess {
// Paper end
}
@ -21641,7 +21454,7 @@ index bcdaa86cfd31c2ce4aadad900c348aee0a9e3fc8..a8b2ce0debe54afeb937a4f1215d6b89
}
// CraftBukkit end
@@ -813,7 +895,9 @@ public class LevelChunk extends ChunkAccess {
@@ -813,7 +896,9 @@ public class LevelChunk extends ChunkAccess {
return this.blockEntities;
}
@ -21651,7 +21464,7 @@ index bcdaa86cfd31c2ce4aadad900c348aee0a9e3fc8..a8b2ce0debe54afeb937a4f1215d6b89
ChunkPos chunkcoordintpair = this.getPos();
for (int i = 0; i < this.postProcessing.length; ++i) {
@@ -834,6 +918,7 @@ public class LevelChunk extends ChunkAccess {
@@ -834,6 +919,7 @@ public class LevelChunk extends ChunkAccess {
BlockState iblockdata1 = Block.updateFromNeighbourShapes(iblockdata, this.level, blockposition);
this.level.setBlock(blockposition, iblockdata1, 20);
@ -21659,7 +21472,7 @@ index bcdaa86cfd31c2ce4aadad900c348aee0a9e3fc8..a8b2ce0debe54afeb937a4f1215d6b89
}
}
@@ -851,6 +936,10 @@ public class LevelChunk extends ChunkAccess {
@@ -851,6 +937,10 @@ public class LevelChunk extends ChunkAccess {
this.pendingBlockEntities.clear();
this.upgradeData.upgrade(this);
@ -21670,7 +21483,7 @@ index bcdaa86cfd31c2ce4aadad900c348aee0a9e3fc8..a8b2ce0debe54afeb937a4f1215d6b89
}
@Nullable
@@ -900,7 +989,7 @@ public class LevelChunk extends ChunkAccess {
@@ -900,7 +990,7 @@ public class LevelChunk extends ChunkAccess {
}
public FullChunkStatus getFullStatus() {

View File

@ -44,10 +44,10 @@ index b300d12e9e00519028b53aca9c3fb01f589eaa91..63acd109a79ed752a05df3d4f1b99309
}
}
diff --git a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
index a8b2ce0debe54afeb937a4f1215d6b8955037d3d..515aedcf9969b818dfdc02a16a7f7178b5bb5593 100644
index 85b38592c87bbc071d3fc5de5db131c6626fe004..fde60133d2c5557cd8d4a4d2e3a16aa96974fcbb 100644
--- a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
+++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
@@ -1146,11 +1146,11 @@ public class LevelChunk extends ChunkAccess {
@@ -1147,11 +1147,11 @@ public class LevelChunk extends ChunkAccess {
gameprofilerfiller.pop();
} catch (Throwable throwable) {

View File

@ -131,7 +131,7 @@ index 5d65baba605dd83e5f74d526aeda36d8ede8c014..92e76dd39dc3575e9466031dd799080a
}
diff --git a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
index 515aedcf9969b818dfdc02a16a7f7178b5bb5593..56900156d79781f15357a3d25906d32b615366ce 100644
index fde60133d2c5557cd8d4a4d2e3a16aa96974fcbb..d13652d5001c117582b8c470d40207a6c10cb096 100644
--- a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
+++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
@@ -1,6 +1,7 @@
@ -142,7 +142,7 @@ index 515aedcf9969b818dfdc02a16a7f7178b5bb5593..56900156d79781f15357a3d25906d32b
import com.google.common.collect.Maps;
import com.google.common.collect.UnmodifiableIterator;
import com.mojang.logging.LogUtils;
@@ -568,10 +569,16 @@ public class LevelChunk extends ChunkAccess {
@@ -569,10 +570,16 @@ public class LevelChunk extends ChunkAccess {
// CraftBukkit start
} else {
@ -163,7 +163,7 @@ index 515aedcf9969b818dfdc02a16a7f7178b5bb5593..56900156d79781f15357a3d25906d32b
// CraftBukkit end
}
}
@@ -1149,6 +1156,7 @@ public class LevelChunk extends ChunkAccess {
@@ -1150,6 +1157,7 @@ public class LevelChunk extends ChunkAccess {
// Paper start - Prevent tile entity and entity crashes
final String msg = String.format("BlockEntity threw exception at %s:%s,%s,%s", LevelChunk.this.getLevel().getWorld().getName(), this.getPos().getX(), this.getPos().getY(), this.getPos().getZ());
net.minecraft.server.MinecraftServer.LOGGER.error(msg, throwable);

View File

@ -88,10 +88,10 @@ index 60e760b42dd6471a229dfd45490dcf8c51979d35..4a3ac7dedf5cb1e76f16ec4f18e82afc
@Override
public FluidState getFluidState(BlockPos pos) {
diff --git a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
index 56900156d79781f15357a3d25906d32b615366ce..0eedaf7df86b7bdd22623231f9a49da8e798f204 100644
index d13652d5001c117582b8c470d40207a6c10cb096..f6286284b95df0ab6109ff14fda33a48b163f8c2 100644
--- a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
+++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
@@ -295,12 +295,29 @@ public class LevelChunk extends ChunkAccess {
@@ -296,12 +296,29 @@ public class LevelChunk extends ChunkAccess {
}
}

View File

@ -11,10 +11,10 @@ For people who want all chunks to be treated equally, you can chose a fixed valu
This allows to fine-tune vanilla gameplay.
diff --git a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
index 0eedaf7df86b7bdd22623231f9a49da8e798f204..cf910b466a4b75c0b9219abef5c9bff30793d7bf 100644
index f6286284b95df0ab6109ff14fda33a48b163f8c2..391ef1eb8c842a1a2dbce45eec8a030f615926d6 100644
--- a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
+++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
@@ -280,6 +280,13 @@ public class LevelChunk extends ChunkAccess {
@@ -281,6 +281,13 @@ public class LevelChunk extends ChunkAccess {
return new ChunkAccess.TicksToSave(this.blockTicks, this.fluidTicks);
}

View File

@ -9,10 +9,10 @@ from triggering monster spawns on a server.
Also a highly more effecient way to blanket block spawns in a world
diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java
index ea0b82165e452b7b82d1d9a58eef6059cba30552..cdcad9e1470a0b465ee96d1f2b4b8b31e8c3d219 100644
index e2510ee3f0cb93eae2452bec642855cd6c0c2974..c483acf248484220aaca2100c84e75f3b46fbd31 100644
--- a/src/main/java/net/minecraft/server/level/ChunkMap.java
+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java
@@ -687,7 +687,9 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
@@ -701,7 +701,9 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
chunkRange = (chunkRange > level.spigotConfig.viewDistance) ? (byte) level.spigotConfig.viewDistance : chunkRange;
chunkRange = (chunkRange > 8) ? 8 : chunkRange;
@ -23,7 +23,7 @@ index ea0b82165e452b7b82d1d9a58eef6059cba30552..cdcad9e1470a0b465ee96d1f2b4b8b31
// Spigot end
if (!this.distanceManager.hasPlayersNearby(chunkcoordintpair.toLong())) {
return false;
@@ -702,6 +704,15 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
@@ -716,6 +718,15 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
}
entityplayer = (ServerPlayer) iterator.next();

View File

@ -8,10 +8,10 @@ Add -Ddebug.entities=true to your JVM flags to gain more information
1.17: Needs to be reworked for new entity storage system
diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java
index cdcad9e1470a0b465ee96d1f2b4b8b31e8c3d219..165daf5e4b44425974703e9f603955fa09984f1b 100644
index c483acf248484220aaca2100c84e75f3b46fbd31..c69be9cb3f03ec50e4e57d7e1e93a83701e4cd6c 100644
--- a/src/main/java/net/minecraft/server/level/ChunkMap.java
+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java
@@ -865,6 +865,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
@@ -879,6 +879,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
} else {
ChunkMap.TrackedEntity playerchunkmap_entitytracker = new ChunkMap.TrackedEntity(entity, i, j, entitytypes.trackDeltas());
@ -19,7 +19,7 @@ index cdcad9e1470a0b465ee96d1f2b4b8b31e8c3d219..165daf5e4b44425974703e9f603955fa
this.entityMap.put(entity.getId(), playerchunkmap_entitytracker);
playerchunkmap_entitytracker.updatePlayers(this.level.players());
if (entity instanceof ServerPlayer) {
@@ -907,7 +908,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
@@ -921,7 +922,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
if (playerchunkmap_entitytracker1 != null) {
playerchunkmap_entitytracker1.broadcastRemoved();
}

View File

@ -8,10 +8,10 @@ This patch also adds a chunk status cache on region files (note that
its only purpose is to cache the status on DISK)
diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java
index 165daf5e4b44425974703e9f603955fa09984f1b..a8533bbac77c6024cd6163149affe4f4733019b5 100644
index c69be9cb3f03ec50e4e57d7e1e93a83701e4cd6c..5b7260b5a14cb9d2b90cf3c411d119e6bfa84046 100644
--- a/src/main/java/net/minecraft/server/level/ChunkMap.java
+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java
@@ -666,9 +666,13 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
@@ -680,9 +680,13 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
// Paper end
private CompletableFuture<Optional<CompoundTag>> readChunk(ChunkPos chunkPos) {
@ -28,7 +28,7 @@ index 165daf5e4b44425974703e9f603955fa09984f1b..a8533bbac77c6024cd6163149affe4f4
}
// CraftBukkit start
@@ -677,6 +681,63 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
@@ -691,6 +695,63 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
// CraftBukkit end
}

View File

@ -33,7 +33,7 @@ But for those who are ok with leaving this inconsistent behavior, you may use WA
It is recommended you regenerate the entities, as these were legit entities, and deserve your love.
diff --git a/src/main/java/io/papermc/paper/chunk/system/ChunkSystem.java b/src/main/java/io/papermc/paper/chunk/system/ChunkSystem.java
index 56c35149fd142af6ffe31434fec0064cf6ea3be5..14e24e3bd8695c7038e8e1f4fb92ca3fd20c6258 100644
index cbeaadaecf816070b3a37938c8e683180939afc4..95e5073a68e4dd38b70e8268daf2160922c3a12f 100644
--- a/src/main/java/io/papermc/paper/chunk/system/ChunkSystem.java
+++ b/src/main/java/io/papermc/paper/chunk/system/ChunkSystem.java
@@ -74,7 +74,17 @@ public final class ChunkSystem {
@ -56,10 +56,10 @@ index 56c35149fd142af6ffe31434fec0064cf6ea3be5..14e24e3bd8695c7038e8e1f4fb92ca3f
public static void onChunkHolderCreate(final ServerLevel level, final ChunkHolder holder) {
diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java
index a8533bbac77c6024cd6163149affe4f4733019b5..de89863bae07b6e1264b0c70287c085a716862e4 100644
index 5b7260b5a14cb9d2b90cf3c411d119e6bfa84046..0b1aadd3648f46680e4edc137de3e5ce52428383 100644
--- a/src/main/java/net/minecraft/server/level/ChunkMap.java
+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java
@@ -520,6 +520,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
@@ -534,6 +534,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
entity.discard();
needsRemoval = true;
}
@ -67,7 +67,7 @@ index a8533bbac77c6024cd6163149affe4f4733019b5..de89863bae07b6e1264b0c70287c085a
return !needsRemoval;
}), position); // Paper - rewrite chunk system
// CraftBukkit end
@@ -531,6 +532,49 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
@@ -545,6 +546,49 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
throw new UnsupportedOperationException(); // Paper - rewrite chunk system
}

View File

@ -8,10 +8,10 @@ Sets tracking range of watermobs to animals instead of misc and simplifies code
Also ignores Enderdragon, defaulting it to Mojang's setting
diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java
index de89863bae07b6e1264b0c70287c085a716862e4..ed43ade8c884f9fe7945ef20c1dd2cf5c70680d3 100644
index 0b1aadd3648f46680e4edc137de3e5ce52428383..06e53890fab287846c8d846f1f829650a1b3c09b 100644
--- a/src/main/java/net/minecraft/server/level/ChunkMap.java
+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java
@@ -1251,6 +1251,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
@@ -1265,6 +1265,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
while (iterator.hasNext()) {
Entity entity = (Entity) iterator.next();
int j = entity.getType().clientTrackingRange() * 16;

View File

@ -4,309 +4,11 @@ Date: Mon, 19 Aug 2019 01:27:58 +0500
Subject: [PATCH] implement optional per player mob spawns
diff --git a/src/main/java/com/destroystokyo/paper/util/PooledHashSets.java b/src/main/java/com/destroystokyo/paper/util/PooledHashSets.java
new file mode 100644
index 0000000000000000000000000000000000000000..11de56afaf059b00fa5bec293516bcdce7c4b2b9
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/util/PooledHashSets.java
@@ -0,0 +1,241 @@
+package com.destroystokyo.paper.util;
+
+import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
+import it.unimi.dsi.fastutil.objects.ObjectLinkedOpenHashSet;
+import java.lang.ref.WeakReference;
+import java.util.Iterator;
+
+/** @author Spottedleaf */
+public class PooledHashSets<E> {
+
+ // we really want to avoid that equals() check as much as possible...
+ protected final Object2ObjectOpenHashMap<PooledObjectLinkedOpenHashSet<E>, PooledObjectLinkedOpenHashSet<E>> mapPool = new Object2ObjectOpenHashMap<>(64, 0.25f);
+
+ protected void decrementReferenceCount(final PooledObjectLinkedOpenHashSet<E> current) {
+ if (current.referenceCount == 0) {
+ throw new IllegalStateException("Cannot decrement reference count for " + current);
+ }
+ if (current.referenceCount == -1 || --current.referenceCount > 0) {
+ return;
+ }
+
+ this.mapPool.remove(current);
+ return;
+ }
+
+ public PooledObjectLinkedOpenHashSet<E> findMapWith(final PooledObjectLinkedOpenHashSet<E> current, final E object) {
+ final PooledObjectLinkedOpenHashSet<E> cached = current.getAddCache(object);
+
+ if (cached != null) {
+ if (cached.referenceCount != -1) {
+ ++cached.referenceCount;
+ }
+
+ decrementReferenceCount(current);
+
+ return cached;
+ }
+
+ if (!current.add(object)) {
+ return current;
+ }
+
+ // we use get/put since we use a different key on put
+ PooledObjectLinkedOpenHashSet<E> ret = this.mapPool.get(current);
+
+ if (ret == null) {
+ ret = new PooledObjectLinkedOpenHashSet<>(current);
+ current.remove(object);
+ this.mapPool.put(ret, ret);
+ ret.referenceCount = 1;
+ } else {
+ if (ret.referenceCount != -1) {
+ ++ret.referenceCount;
+ }
+ current.remove(object);
+ }
+
+ current.updateAddCache(object, ret);
+
+ decrementReferenceCount(current);
+ return ret;
+ }
+
+ // rets null if current.size() == 1
+ public PooledObjectLinkedOpenHashSet<E> findMapWithout(final PooledObjectLinkedOpenHashSet<E> current, final E object) {
+ if (current.set.size() == 1) {
+ decrementReferenceCount(current);
+ return null;
+ }
+
+ final PooledObjectLinkedOpenHashSet<E> cached = current.getRemoveCache(object);
+
+ if (cached != null) {
+ if (cached.referenceCount != -1) {
+ ++cached.referenceCount;
+ }
+
+ decrementReferenceCount(current);
+
+ return cached;
+ }
+
+ if (!current.remove(object)) {
+ return current;
+ }
+
+ // we use get/put since we use a different key on put
+ PooledObjectLinkedOpenHashSet<E> ret = this.mapPool.get(current);
+
+ if (ret == null) {
+ ret = new PooledObjectLinkedOpenHashSet<>(current);
+ current.add(object);
+ this.mapPool.put(ret, ret);
+ ret.referenceCount = 1;
+ } else {
+ if (ret.referenceCount != -1) {
+ ++ret.referenceCount;
+ }
+ current.add(object);
+ }
+
+ current.updateRemoveCache(object, ret);
+
+ decrementReferenceCount(current);
+ return ret;
+ }
+
+ public static final class PooledObjectLinkedOpenHashSet<E> implements Iterable<E> {
+
+ private static final WeakReference NULL_REFERENCE = new WeakReference(null);
+
+ final ObjectLinkedOpenHashSet<E> set;
+ int referenceCount; // -1 if special
+ int hash; // optimize hashcode
+
+ // add cache
+ WeakReference<E> lastAddObject = NULL_REFERENCE;
+ WeakReference<PooledObjectLinkedOpenHashSet<E>> lastAddMap = NULL_REFERENCE;
+
+ // remove cache
+ WeakReference<E> lastRemoveObject = NULL_REFERENCE;
+ WeakReference<PooledObjectLinkedOpenHashSet<E>> lastRemoveMap = NULL_REFERENCE;
+
+ public PooledObjectLinkedOpenHashSet() {
+ this.set = new ObjectLinkedOpenHashSet<>(2, 0.6f);
+ }
+
+ public PooledObjectLinkedOpenHashSet(final E single) {
+ this();
+ this.referenceCount = -1;
+ this.add(single);
+ }
+
+ public PooledObjectLinkedOpenHashSet(final PooledObjectLinkedOpenHashSet<E> other) {
+ this.set = other.set.clone();
+ this.hash = other.hash;
+ }
+
+ // from https://github.com/Spottedleaf/ConcurrentUtil/blob/master/src/main/java/ca/spottedleaf/concurrentutil/util/IntegerUtil.java
+ // generated by https://github.com/skeeto/hash-prospector
+ static int hash0(int x) {
+ x *= 0x36935555;
+ x ^= x >>> 16;
+ return x;
+ }
+
+ public PooledObjectLinkedOpenHashSet<E> getAddCache(final E element) {
+ final E currentAdd = this.lastAddObject.get();
+
+ if (currentAdd == null || !(currentAdd == element || currentAdd.equals(element))) {
+ return null;
+ }
+
+ final PooledObjectLinkedOpenHashSet<E> map = this.lastAddMap.get();
+ if (map == null || map.referenceCount == 0) {
+ // we need to ret null if ref count is zero as calling code will assume the map is in use
+ return null;
+ }
+
+ return map;
+ }
+
+ public PooledObjectLinkedOpenHashSet<E> getRemoveCache(final E element) {
+ final E currentRemove = this.lastRemoveObject.get();
+
+ if (currentRemove == null || !(currentRemove == element || currentRemove.equals(element))) {
+ return null;
+ }
+
+ final PooledObjectLinkedOpenHashSet<E> map = this.lastRemoveMap.get();
+ if (map == null || map.referenceCount == 0) {
+ // we need to ret null if ref count is zero as calling code will assume the map is in use
+ return null;
+ }
+
+ return map;
+ }
+
+ public void updateAddCache(final E element, final PooledObjectLinkedOpenHashSet<E> map) {
+ this.lastAddObject = new WeakReference<>(element);
+ this.lastAddMap = new WeakReference<>(map);
+ }
+
+ public void updateRemoveCache(final E element, final PooledObjectLinkedOpenHashSet<E> map) {
+ this.lastRemoveObject = new WeakReference<>(element);
+ this.lastRemoveMap = new WeakReference<>(map);
+ }
+
+ boolean add(final E element) {
+ boolean added = this.set.add(element);
+
+ if (added) {
+ this.hash += hash0(element.hashCode());
+ }
+
+ return added;
+ }
+
+ boolean remove(Object element) {
+ boolean removed = this.set.remove(element);
+
+ if (removed) {
+ this.hash -= hash0(element.hashCode());
+ }
+
+ return removed;
+ }
+
+ @Override
+ public Iterator<E> iterator() {
+ return this.set.iterator();
+ }
+
+ @Override
+ public int hashCode() {
+ return this.hash;
+ }
+
+ @Override
+ public boolean equals(final Object other) {
+ if (!(other instanceof PooledObjectLinkedOpenHashSet)) {
+ return false;
+ }
+ if (this.referenceCount == 0) {
+ return other == this;
+ } else {
+ if (other == this) {
+ // Unfortunately we are never equal to our own instance while in use!
+ return false;
+ }
+ return this.hash == ((PooledObjectLinkedOpenHashSet)other).hash && this.set.equals(((PooledObjectLinkedOpenHashSet)other).set);
+ }
+ }
+
+ @Override
+ public String toString() {
+ return "PooledHashSet: size: " + this.set.size() + ", reference count: " + this.referenceCount + ", hash: " +
+ this.hashCode() + ", identity: " + System.identityHashCode(this) + " map: " + this.set.toString();
+ }
+ }
+}
diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java
index ed43ade8c884f9fe7945ef20c1dd2cf5c70680d3..1f30d06781cea0855be26784c239e71ed1a2f6c3 100644
index 06e53890fab287846c8d846f1f829650a1b3c09b..847019bf4a81b82e6e11a19aebd69b7270d81b06 100644
--- a/src/main/java/net/minecraft/server/level/ChunkMap.java
+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java
@@ -142,6 +142,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
private final Long2LongMap chunkSaveCooldowns;
private final Queue<Runnable> unloadQueue;
private int serverViewDistance;
+ public final com.destroystokyo.paper.util.misc.PlayerAreaMap playerMobDistanceMap; // Paper
// Paper - rewrite chunk system
@@ -153,11 +154,21 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
int chunkX = io.papermc.paper.util.MCUtil.getChunkCoordinate(player.getX());
int chunkZ = io.papermc.paper.util.MCUtil.getChunkCoordinate(player.getZ());
// Note: players need to be explicitly added to distance maps before they can be updated
+ // Paper start - per player mob spawning
+ if (this.playerMobDistanceMap != null) {
+ this.playerMobDistanceMap.add(player, chunkX, chunkZ, io.papermc.paper.chunk.system.ChunkSystem.getTickViewDistance(player));
+ }
+ // Paper end - per player mob spawning
}
void removePlayerFromDistanceMaps(ServerPlayer player) {
this.level.playerChunkLoader.removePlayer(player); // Paper - replace chunk loader
+ // Paper start - per player mob spawning
+ if (this.playerMobDistanceMap != null) {
+ this.playerMobDistanceMap.remove(player);
+ }
+ // Paper end - per player mob spawning
}
void updateMaps(ServerPlayer player) {
@@ -165,6 +176,12 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
int chunkZ = io.papermc.paper.util.MCUtil.getChunkCoordinate(player.getZ());
// Note: players need to be explicitly added to distance maps before they can be updated
this.level.playerChunkLoader.updatePlayer(player); // Paper - replace chunk loader
+
+ // Paper start - per player mob spawning
+ if (this.playerMobDistanceMap != null) {
+ this.playerMobDistanceMap.update(player, chunkX, chunkZ, io.papermc.paper.chunk.system.ChunkSystem.getTickViewDistance(player));
+ }
+ // Paper end - per player mob spawning
}
// Paper end
// Paper start
@@ -250,6 +267,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
this.dataRegionManager = new io.papermc.paper.chunk.SingleThreadChunkRegionManager(this.level, 2, (1.0 / 3.0), 1, 6, "Data", DataRegionData::new, DataRegionSectionData::new);
this.regionManagers.add(this.dataRegionManager);
// Paper end
+ this.playerMobDistanceMap = this.level.paperConfig().entities.spawning.perPlayerMobSpawns ? new com.destroystokyo.paper.util.misc.PlayerAreaMap(this.pooledLinkedPlayerHashSets) : null; // Paper
}
protected ChunkGenerator generator() {
@@ -275,6 +293,31 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
@@ -289,6 +289,29 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
});
}
@ -317,16 +19,14 @@ index ed43ade8c884f9fe7945ef20c1dd2cf5c70680d3..1f30d06781cea0855be26784c239e71e
+ }
+ int index = entity.getType().getCategory().ordinal();
+
+ final com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<ServerPlayer> inRange = this.playerMobDistanceMap.getObjectsInRange(entity.chunkPosition());
+ final com.destroystokyo.paper.util.maplist.ReferenceList<ServerPlayer> inRange =
+ this.getNearbyPlayers().getPlayers(entity.chunkPosition(), io.papermc.paper.util.player.NearbyPlayers.NearbyMapType.TICK_VIEW_DISTANCE);
+ if (inRange == null) {
+ return;
+ }
+ final Object[] backingSet = inRange.getBackingSet();
+ for (int i = 0; i < backingSet.length; i++) {
+ if (!(backingSet[i] instanceof final ServerPlayer player)) {
+ continue;
+ }
+ ++player.mobCounts[index];
+ final Object[] backingSet = inRange.getRawData();
+ for (int i = 0, len = inRange.size(); i < len; i++) {
+ ++((ServerPlayer)backingSet[i]).mobCounts[index];
+ }
+ }
+
@ -339,7 +39,7 @@ index ed43ade8c884f9fe7945ef20c1dd2cf5c70680d3..1f30d06781cea0855be26784c239e71e
double d0 = (double) SectionPos.sectionToBlockCoord(pos.x, 8);
double d1 = (double) SectionPos.sectionToBlockCoord(pos.z, 8);
diff --git a/src/main/java/net/minecraft/server/level/ServerChunkCache.java b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
index 4649e597b86335b33d9e9227d966dd7ad8208096..e655cf837f7bd7d4271dca80b9c6764372336910 100644
index 4649e597b86335b33d9e9227d966dd7ad8208096..b73d45c205db39ed3e97a127e53371db81e0d63f 100644
--- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java
+++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
@@ -543,7 +543,18 @@ public class ServerChunkCache extends ChunkSource {
@ -349,45 +49,36 @@ index 4649e597b86335b33d9e9227d966dd7ad8208096..e655cf837f7bd7d4271dca80b9c67643
- NaturalSpawner.SpawnState spawnercreature_d = NaturalSpawner.createState(l, this.level.getAllEntities(), this::getFullChunk, new LocalMobCapCalculator(this.chunkMap));
+ // Paper start - per player mob spawning
+ NaturalSpawner.SpawnState spawnercreature_d; // moved down
+ if ((this.spawnFriendlies || this.spawnEnemies) && this.chunkMap.playerMobDistanceMap != null) { // don't count mobs when animals and monsters are disabled
+ if ((this.spawnFriendlies || this.spawnEnemies) && this.level.paperConfig().entities.spawning.perPlayerMobSpawns) { // don't count mobs when animals and monsters are disabled
+ // re-set mob counts
+ for (ServerPlayer player : this.level.players) {
+ Arrays.fill(player.mobCounts, 0);
+ }
+ spawnercreature_d = NaturalSpawner.createState(l, this.level.getAllEntities(), this::getFullChunk, null, true);
+ } else {
+ spawnercreature_d = NaturalSpawner.createState(l, this.level.getAllEntities(), this::getFullChunk, this.chunkMap.playerMobDistanceMap == null ? new LocalMobCapCalculator(this.chunkMap) : null, false);
+ spawnercreature_d = NaturalSpawner.createState(l, this.level.getAllEntities(), this::getFullChunk, !this.level.paperConfig().entities.spawning.perPlayerMobSpawns ? new LocalMobCapCalculator(this.chunkMap) : null, false);
+ }
+ // Paper end
this.level.timings.countNaturalMobs.stopTiming(); // Paper - timings
this.lastSpawnState = spawnercreature_d;
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
index dcb6a1bd3774e63dd14fbd8ddd6ff09c68741379..ad34d1562131a5140c4cc83aa3ea94fab08d12da 100644
index dcb6a1bd3774e63dd14fbd8ddd6ff09c68741379..55c3416f209178a1a100228d9b1db620c79bc288 100644
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
@@ -246,6 +246,11 @@ public class ServerPlayer extends Player {
@@ -246,6 +246,10 @@ public class ServerPlayer extends Player {
public boolean queueHealthUpdatePacket = false;
public net.minecraft.network.protocol.game.ClientboundSetHealthPacket queuedHealthUpdatePacket;
// Paper end
+ // Paper start - mob spawning rework
+ public static final int MOBCATEGORY_TOTAL_ENUMS = net.minecraft.world.entity.MobCategory.values().length;
+ public final int[] mobCounts = new int[MOBCATEGORY_TOTAL_ENUMS]; // Paper
+ public final com.destroystokyo.paper.util.PooledHashSets.PooledObjectLinkedOpenHashSet<ServerPlayer> cachedSingleMobDistanceMap;
+ // Paper end
+ // Paper end - mob spawning rework
// CraftBukkit start
public String displayName;
@@ -383,6 +388,7 @@ public class ServerPlayer extends Player {
this.adventure$displayName = net.kyori.adventure.text.Component.text(this.getScoreboardName()); // Paper
this.bukkitPickUpLoot = true;
this.maxHealthCache = this.getMaxHealth();
+ this.cachedSingleMobDistanceMap = new com.destroystokyo.paper.util.PooledHashSets.PooledObjectLinkedOpenHashSet<>(this); // Paper
}
// Yes, this doesn't match Vanilla, but it's the best we can do for now.
diff --git a/src/main/java/net/minecraft/world/level/NaturalSpawner.java b/src/main/java/net/minecraft/world/level/NaturalSpawner.java
index fe38079d69f3e9987ad5ab077ae09d05017a681a..7983f9a21251cec4857529ad1180a62668ea5037 100644
index fe38079d69f3e9987ad5ab077ae09d05017a681a..9df761f5cf043e8d2dffa711c20ab32fe2992331 100644
--- a/src/main/java/net/minecraft/world/level/NaturalSpawner.java
+++ b/src/main/java/net/minecraft/world/level/NaturalSpawner.java
@@ -70,6 +70,12 @@ public final class NaturalSpawner {
@ -421,7 +112,7 @@ index fe38079d69f3e9987ad5ab077ae09d05017a681a..7983f9a21251cec4857529ad1180a626
});
}
}
@@ -143,13 +154,37 @@ public final class NaturalSpawner {
@@ -143,13 +154,35 @@ public final class NaturalSpawner {
continue;
}
@ -433,14 +124,12 @@ index fe38079d69f3e9987ad5ab077ae09d05017a681a..7983f9a21251cec4857529ad1180a626
+
+ if (world.paperConfig().entities.spawning.perPlayerMobSpawns) {
+ int minDiff = Integer.MAX_VALUE;
+ final com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<net.minecraft.server.level.ServerPlayer> inRange = world.getChunkSource().chunkMap.playerMobDistanceMap.getObjectsInRange(chunk.getPos());
+ final com.destroystokyo.paper.util.maplist.ReferenceList<net.minecraft.server.level.ServerPlayer> inRange =
+ world.chunkSource.chunkMap.getNearbyPlayers().getPlayers(chunk.getPos(), io.papermc.paper.util.player.NearbyPlayers.NearbyMapType.TICK_VIEW_DISTANCE);
+ if (inRange != null) {
+ final Object[] backingSet = inRange.getBackingSet();
+ for (int k = 0; k < backingSet.length; k++) {
+ if (!(backingSet[k] instanceof final net.minecraft.server.level.ServerPlayer player)) {
+ continue;
+ }
+ minDiff = Math.min(limit - world.getChunkSource().chunkMap.getMobCountNear(player, enumcreaturetype), minDiff);
+ final Object[] backingSet = inRange.getRawData();
+ for (int k = 0, len = inRange.size(); k < len; k++) {
+ minDiff = Math.min(limit - world.getChunkSource().chunkMap.getMobCountNear((net.minecraft.server.level.ServerPlayer)backingSet[k], enumcreaturetype), minDiff);
+ }
+ }
+ difference = (minDiff == Integer.MAX_VALUE) ? 0 : minDiff;
@ -461,7 +150,7 @@ index fe38079d69f3e9987ad5ab077ae09d05017a681a..7983f9a21251cec4857529ad1180a626
}
}
@@ -158,11 +193,17 @@ public final class NaturalSpawner {
@@ -158,11 +191,17 @@ public final class NaturalSpawner {
}
public static void spawnCategoryForChunk(MobCategory group, ServerLevel world, LevelChunk chunk, NaturalSpawner.SpawnPredicate checker, NaturalSpawner.AfterSpawnCallback runner) {
@ -480,7 +169,7 @@ index fe38079d69f3e9987ad5ab077ae09d05017a681a..7983f9a21251cec4857529ad1180a626
}
@VisibleForDebug
@@ -173,15 +214,21 @@ public final class NaturalSpawner {
@@ -173,15 +212,21 @@ public final class NaturalSpawner {
});
}
@ -503,7 +192,7 @@ index fe38079d69f3e9987ad5ab077ae09d05017a681a..7983f9a21251cec4857529ad1180a626
int k = 0;
while (k < 3) {
@@ -223,14 +270,14 @@ public final class NaturalSpawner {
@@ -223,14 +268,14 @@ public final class NaturalSpawner {
// Paper start
PreSpawnStatus doSpawning = isValidSpawnPostitionForType(world, group, structuremanager, chunkgenerator, biomesettingsmobs_c, blockposition_mutableblockposition, d2);
if (doSpawning == PreSpawnStatus.ABORT) {
@ -520,7 +209,7 @@ index fe38079d69f3e9987ad5ab077ae09d05017a681a..7983f9a21251cec4857529ad1180a626
}
entityinsentient.moveTo(d0, (double) i, d1, world.random.nextFloat() * 360.0F, 0.0F);
@@ -243,10 +290,15 @@ public final class NaturalSpawner {
@@ -243,10 +288,15 @@ public final class NaturalSpawner {
++j;
++k1;
runner.run(entityinsentient, chunk);
@ -538,7 +227,7 @@ index fe38079d69f3e9987ad5ab077ae09d05017a681a..7983f9a21251cec4857529ad1180a626
}
if (entityinsentient.isMaxGroupSizeReached(k1)) {
@@ -268,6 +320,7 @@ public final class NaturalSpawner {
@@ -268,6 +318,7 @@ public final class NaturalSpawner {
}
}
@ -546,7 +235,7 @@ index fe38079d69f3e9987ad5ab077ae09d05017a681a..7983f9a21251cec4857529ad1180a626
}
private static boolean isRightDistanceToPlayerAndSpawnPoint(ServerLevel world, ChunkAccess chunk, BlockPos.MutableBlockPos pos, double squaredDistance) {
@@ -567,7 +620,7 @@ public final class NaturalSpawner {
@@ -567,7 +618,7 @@ public final class NaturalSpawner {
MobCategory enumcreaturetype = entitytypes.getCategory();
this.mobCategoryCounts.addTo(enumcreaturetype, 1);
@ -555,7 +244,7 @@ index fe38079d69f3e9987ad5ab077ae09d05017a681a..7983f9a21251cec4857529ad1180a626
}
public int getSpawnableChunkCount() {
@@ -583,6 +636,7 @@ public final class NaturalSpawner {
@@ -583,6 +634,7 @@ public final class NaturalSpawner {
int i = limit * this.spawnableChunkCount / NaturalSpawner.MAGIC_NUMBER;
// CraftBukkit end

View File

@ -1213,10 +1213,10 @@ index 525c89bc926f13af6f94fc46c897525e37477eca..8b96d1b7548d354fbcabe6d1b5e9d6c3
}
diff --git a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
index cf910b466a4b75c0b9219abef5c9bff30793d7bf..1bb82df6602bddd3f5785c800124d2a3096c0f8d 100644
index 391ef1eb8c842a1a2dbce45eec8a030f615926d6..abb75d8bea8f975c5b04c9a9fff7187a3520ac26 100644
--- a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
+++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
@@ -90,7 +90,7 @@ public class LevelChunk extends ChunkAccess {
@@ -91,7 +91,7 @@ public class LevelChunk extends ChunkAccess {
}
public LevelChunk(Level world, ChunkPos pos, UpgradeData upgradeData, LevelChunkTicks<Block> blockTickScheduler, LevelChunkTicks<Fluid> fluidTickScheduler, long inhabitedTime, @Nullable LevelChunkSection[] sectionArrayInitializer, @Nullable LevelChunk.PostLoadProcessor entityLoader, @Nullable BlendingData blendingData) {

View File

@ -7,7 +7,7 @@ bypass the need to get a player chunk, then get the either,
then unwrap it...
diff --git a/src/main/java/net/minecraft/server/level/ServerChunkCache.java b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
index e655cf837f7bd7d4271dca80b9c6764372336910..2d44b8a98216f879f2bc89fba1dad53cd5558ff9 100644
index b73d45c205db39ed3e97a127e53371db81e0d63f..ab1a45f30930408a3e3c7172169ff648643ba54d 100644
--- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java
+++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
@@ -270,6 +270,12 @@ public class ServerChunkCache extends ChunkSource {

View File

@ -300,7 +300,7 @@ index 0000000000000000000000000000000000000000..95d6022c9cfb2e36ec5a71be6e343540
+ }
+}
diff --git a/src/main/java/net/minecraft/server/level/ServerChunkCache.java b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
index 2d44b8a98216f879f2bc89fba1dad53cd5558ff9..7881a34e01dd6c8e31b55577bb9323a0171d24bf 100644
index ab1a45f30930408a3e3c7172169ff648643ba54d..a8c1620ec48adcd2bb116d48f8bb2d4af50f5f43 100644
--- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java
+++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
@@ -294,6 +294,7 @@ public class ServerChunkCache extends ChunkSource {

View File

@ -8,10 +8,10 @@ faster on its own, however removing the try catch makes it
easier to inline due to code size
diff --git a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
index 1bb82df6602bddd3f5785c800124d2a3096c0f8d..95531e115f69f52cb6ec55c6e4bc34fb109758c4 100644
index abb75d8bea8f975c5b04c9a9fff7187a3520ac26..d2cdb8100fbbdc3d92eb7a61748340c40de343f7 100644
--- a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
+++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
@@ -380,18 +380,20 @@ public class LevelChunk extends ChunkAccess {
@@ -381,18 +381,20 @@ public class LevelChunk extends ChunkAccess {
}
public FluidState getFluidState(int x, int y, int z) {
@ -38,7 +38,7 @@ index 1bb82df6602bddd3f5785c800124d2a3096c0f8d..95531e115f69f52cb6ec55c6e4bc34fb
} catch (Throwable throwable) {
CrashReport crashreport = CrashReport.forThrowable(throwable, "Getting fluid state");
CrashReportCategory crashreportsystemdetails = crashreport.addCategory("Block being got");
@@ -401,6 +403,7 @@ public class LevelChunk extends ChunkAccess {
@@ -402,6 +404,7 @@ public class LevelChunk extends ChunkAccess {
});
throw new ReportedException(crashreport);
}

View File

@ -10,7 +10,7 @@ When not per player it will use the Vanilla mechanic of one delay per
world and the world age for the start day.
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
index ad34d1562131a5140c4cc83aa3ea94fab08d12da..a6b9f246ed2d59122c31ff212d99adc0602ef35b 100644
index 55c3416f209178a1a100228d9b1db620c79bc288..5c0b406214b7da3b33acf1f545105d4ecae1f783 100644
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
@@ -242,6 +242,7 @@ public class ServerPlayer extends Player {

View File

@ -7,10 +7,10 @@ Suspected case would be around the technique used in .stopRiding
Stack will identify any causer of this and warn instead of crashing.
diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java
index 1f30d06781cea0855be26784c239e71ed1a2f6c3..91373583904a22bc28c82cf3dfec9f60aebee9a3 100644
index 847019bf4a81b82e6e11a19aebd69b7270d81b06..41a6712d4c55907df1274f5a825e86d7fedb42bb 100644
--- a/src/main/java/net/minecraft/server/level/ChunkMap.java
+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java
@@ -1000,6 +1000,13 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
@@ -994,6 +994,13 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
public void addEntity(Entity entity) {
org.spigotmc.AsyncCatcher.catchOp("entity track"); // Spigot

View File

@ -7,10 +7,10 @@ Causes sync chunk loads and who knows what all else.
This is safe because Spectators are skipped in unloaded chunks too in vanilla.
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
index a6b9f246ed2d59122c31ff212d99adc0602ef35b..88152bb21f42f705f6d321f0f088e7f83ac66e62 100644
index 5c0b406214b7da3b33acf1f545105d4ecae1f783..40709c98687334b5383ad9d412d5b6ff7748b02b 100644
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
@@ -727,7 +727,7 @@ public class ServerPlayer extends Player {
@@ -725,7 +725,7 @@ public class ServerPlayer extends Player {
public void doTick() {
try {

View File

@ -13,10 +13,10 @@ By skipping this, we avoid potential for a large spike on server start.
public net.minecraft.server.level.ServerPlayer fudgeSpawnLocation(Lnet/minecraft/server/level/ServerLevel;)V
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
index 88152bb21f42f705f6d321f0f088e7f83ac66e62..99cabb83c54106ff39e89f9f138548aa734ccac3 100644
index 40709c98687334b5383ad9d412d5b6ff7748b02b..de8121b1e4a30e091ce6eb7d3e5beb6029fd95d8 100644
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
@@ -379,7 +379,7 @@ public class ServerPlayer extends Player {
@@ -378,7 +378,7 @@ public class ServerPlayer extends Player {
this.stats = server.getPlayerList().getPlayerStats(this);
this.advancements = server.getPlayerList().getPlayerAdvancements(this);
this.setMaxUpStep(1.0F);
@ -25,7 +25,7 @@ index 88152bb21f42f705f6d321f0f088e7f83ac66e62..99cabb83c54106ff39e89f9f138548aa
this.updateOptions(clientOptions);
this.cachedSingleHashSet = new com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<>(this); // Paper
@@ -614,7 +614,7 @@ public class ServerPlayer extends Player {
@@ -612,7 +612,7 @@ public class ServerPlayer extends Player {
position = Vec3.atCenterOf(world.getSharedSpawnPos());
}
this.setLevel(world);

View File

@ -308,10 +308,10 @@ index 7a1886585bd00dc8213ce22130b8b6fea52c5cf6..52a44510d0499df56d2ebef0963fe816
final String msg = String.format("Entity threw exception at %s:%s,%s,%s", entity.level().getWorld().getName(), entity.getX(), entity.getY(), entity.getZ());
MinecraftServer.LOGGER.error(msg, throwable);
diff --git a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
index 95531e115f69f52cb6ec55c6e4bc34fb109758c4..cd725cdfe37eb53eea78f110d5d3ca00342781c5 100644
index d2cdb8100fbbdc3d92eb7a61748340c40de343f7..535e71bdb2531432974dc91ec9d5edb2b3ebc744 100644
--- a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
+++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
@@ -1180,6 +1180,7 @@ public class LevelChunk extends ChunkAccess {
@@ -1181,6 +1181,7 @@ public class LevelChunk extends ChunkAccess {
gameprofilerfiller.pop();
} catch (Throwable throwable) {

View File

@ -5,10 +5,10 @@ Subject: [PATCH] Prevent opening inventories when frozen
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
index 99cabb83c54106ff39e89f9f138548aa734ccac3..1ff911085da7d1a2a378c60c66f8e5364b9774b4 100644
index de8121b1e4a30e091ce6eb7d3e5beb6029fd95d8..0bab5208a38e8e7c848e9162396df535eb7e5711 100644
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
@@ -696,7 +696,7 @@ public class ServerPlayer extends Player {
@@ -694,7 +694,7 @@ public class ServerPlayer extends Player {
containerUpdateDelay = this.level().paperConfig().tickRates.containerUpdate;
}
// Paper end
@ -17,7 +17,7 @@ index 99cabb83c54106ff39e89f9f138548aa734ccac3..1ff911085da7d1a2a378c60c66f8e536
this.closeContainer(org.bukkit.event.inventory.InventoryCloseEvent.Reason.CANT_USE); // Paper
this.containerMenu = this.inventoryMenu;
}
@@ -1545,7 +1545,7 @@ public class ServerPlayer extends Player {
@@ -1543,7 +1543,7 @@ public class ServerPlayer extends Player {
} else {
// CraftBukkit start
this.containerMenu = container;

View File

@ -87,10 +87,10 @@ index 0000000000000000000000000000000000000000..b6f4400df3d8ec7e06a996de54f8cabb
+ }
+}
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
index 1ff911085da7d1a2a378c60c66f8e5364b9774b4..c13f088a74448f80e111bdeeb712087a238ed2b8 100644
index 0bab5208a38e8e7c848e9162396df535eb7e5711..baec871645598c36cefda7478e91b560bdfdf6fe 100644
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
@@ -1952,7 +1952,23 @@ public class ServerPlayer extends Player {
@@ -1950,7 +1950,23 @@ public class ServerPlayer extends Player {
}
}

View File

@ -31,10 +31,10 @@ delays anymore.
public net.minecraft.server.level.ChunkMap addEntity(Lnet/minecraft/world/entity/Entity;)V
diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java
index 91373583904a22bc28c82cf3dfec9f60aebee9a3..463a82f08b7848a4b8a4eb89b201a6e8424c6831 100644
index 41a6712d4c55907df1274f5a825e86d7fedb42bb..c10ef2e6af3e6c52eeb8c96cdbf5352d9dd25dd2 100644
--- a/src/main/java/net/minecraft/server/level/ChunkMap.java
+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java
@@ -1006,6 +1006,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
@@ -1000,6 +1000,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
+ ": " + entity + (this.entityMap.containsKey(entity.getId()) ? " ALREADY CONTAINED (This would have crashed your server)" : ""), new Throwable());
return;
}
@ -43,10 +43,10 @@ index 91373583904a22bc28c82cf3dfec9f60aebee9a3..463a82f08b7848a4b8a4eb89b201a6e8
if (!(entity instanceof EnderDragonPart)) {
EntityType<?> entitytypes = entity.getType();
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
index c13f088a74448f80e111bdeeb712087a238ed2b8..db722b6c6d6d7c5b973f56a2da624514a76b53cd 100644
index baec871645598c36cefda7478e91b560bdfdf6fe..d31670aecc2ebe67bf6071c67126ce4142b93053 100644
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
@@ -265,6 +265,7 @@ public class ServerPlayer extends Player {
@@ -264,6 +264,7 @@ public class ServerPlayer extends Player {
public double maxHealthCache;
public boolean joining = true;
public boolean sentListPacket = false;

View File

@ -612,10 +612,10 @@ index 5db27d7bcaaa2eeaeeb08401513d8d23f6cb63c7..ce43cb0152ba07c6c21e08142d65813d
}
}
diff --git a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
index cd725cdfe37eb53eea78f110d5d3ca00342781c5..c4d2036d51fe16b640605ae26a2b71323758cc26 100644
index 535e71bdb2531432974dc91ec9d5edb2b3ebc744..4abec88caab4116cfa318f7b66c6b1a8346a7401 100644
--- a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
+++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
@@ -603,7 +603,7 @@ public class LevelChunk extends ChunkAccess {
@@ -604,7 +604,7 @@ public class LevelChunk extends ChunkAccess {
+ " (" + getBlockState(blockposition) + ") where there was no entity tile!\n" +
"Chunk coordinates: " + (this.chunkPos.x * 16) + "," + (this.chunkPos.z * 16) +
"\nWorld: " + level.getLevel().dimension().location());

View File

@ -76,10 +76,10 @@ index 1f8dcc331505890ba72777b5d0cda2427e0ccfd1..a661f8a83d4e57ca48bbf28dc668f8ff
@Override
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
index db722b6c6d6d7c5b973f56a2da624514a76b53cd..7b5496d3a21316a7410dfbfbf9335a432b466560 100644
index d31670aecc2ebe67bf6071c67126ce4142b93053..6de4e9f379fe0cb44f14fe68ae1dee55a73d2d99 100644
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
@@ -1206,7 +1206,7 @@ public class ServerPlayer extends Player {
@@ -1204,7 +1204,7 @@ public class ServerPlayer extends Player {
this.isChangingDimension = true; // CraftBukkit - Set teleport invulnerability only if player changing worlds
this.connection.send(new ClientboundRespawnPacket(this.createCommonSpawnInfo(worldserver), (byte) 3));

View File

@ -53,7 +53,7 @@ index a106f5f573c9eec1f56fa88f7398ac28d231b5e5..04258e07f806acd9a0d659b682e0119a
// Paper start - move executeAll() into full server tick timing
try (co.aikar.timings.Timing ignored = MinecraftTimings.processTasksTimer.startTiming()) {
diff --git a/src/main/java/net/minecraft/server/level/ServerChunkCache.java b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
index 7881a34e01dd6c8e31b55577bb9323a0171d24bf..7b5851cd4f5a91bf7609464d7d6c4bb5a3da14bf 100644
index a8c1620ec48adcd2bb116d48f8bb2d4af50f5f43..7d7dc8246f44d6ffd46b05f917ffbdb9cc24372b 100644
--- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java
+++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
@@ -452,6 +452,15 @@ public class ServerChunkCache extends ChunkSource {
@ -115,7 +115,7 @@ index 8467ea174dd48010b94b3f3c84ce097ecbb2ef14..5826536978724b54080d7d4ee61aa798
// Paper start - rewrite chunk system - add close param
this.save(progressListener, flush, savingDisabled, false);
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
index 7b5496d3a21316a7410dfbfbf9335a432b466560..4d96b44533d39962b60ee43c232d5aa80b88e185 100644
index 6de4e9f379fe0cb44f14fe68ae1dee55a73d2d99..4a4002b666c70c7065cad0743377cd13e443aa37 100644
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
@@ -184,6 +184,7 @@ import org.bukkit.inventory.MainHand;

View File

@ -25,10 +25,10 @@ index b9d1eefb2afbf24bdc902c6dea06e911e835d698..4f5216cb3ac323de1a79c2b9c4d2ddd7
Connection.LOGGER.debug("Failed to sent packet", throwable);
if (this.getSending() == PacketFlow.CLIENTBOUND) {
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
index 4d96b44533d39962b60ee43c232d5aa80b88e185..c70a7feab56fd63354ac2dd887a5d6157eaf8407 100644
index 4a4002b666c70c7065cad0743377cd13e443aa37..576fe4a114c7ad0edde3ce7b2cf1b397a287adcd 100644
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
@@ -272,6 +272,7 @@ public class ServerPlayer extends Player {
@@ -271,6 +271,7 @@ public class ServerPlayer extends Player {
public boolean isRealPlayer; // Paper
public final com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<ServerPlayer> cachedSingleHashSet; // Paper
public PlayerNaturallySpawnCreaturesEvent playerNaturallySpawnedEvent; // Paper

View File

@ -5,10 +5,10 @@ Subject: [PATCH] Reset shield blocking on dimension change
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
index c70a7feab56fd63354ac2dd887a5d6157eaf8407..cb2f86e0ad0edc54711826215df4406c5725f29c 100644
index 576fe4a114c7ad0edde3ce7b2cf1b397a287adcd..717e7d0cd5fd62058d5308fc15070bdf72a03bc4 100644
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
@@ -1243,6 +1243,11 @@ public class ServerPlayer extends Player {
@@ -1241,6 +1241,11 @@ public class ServerPlayer extends Player {
this.level().getCraftServer().getPluginManager().callEvent(changeEvent);
// CraftBukkit end
}

View File

@ -45,10 +45,10 @@ index aee8618e27b893b72931e925724dd683d2e6d2aa..5cb15e2209d7b315904a1fc6d650ce1e
}
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
index cb2f86e0ad0edc54711826215df4406c5725f29c..0abc9dfd73b3cb16b29bdbcc40f0d0ea1c022f34 100644
index 717e7d0cd5fd62058d5308fc15070bdf72a03bc4..327307404d336d0e66a265e79448f2342cc36220 100644
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
@@ -1888,8 +1888,16 @@ public class ServerPlayer extends Player {
@@ -1886,8 +1886,16 @@ public class ServerPlayer extends Player {
}
public boolean setGameMode(GameType gameMode) {
@ -67,7 +67,7 @@ index cb2f86e0ad0edc54711826215df4406c5725f29c..0abc9dfd73b3cb16b29bdbcc40f0d0ea
} else {
this.connection.send(new ClientboundGameEventPacket(ClientboundGameEventPacket.CHANGE_GAME_MODE, (float) gameMode.getId()));
if (gameMode == GameType.SPECTATOR) {
@@ -1901,7 +1909,7 @@ public class ServerPlayer extends Player {
@@ -1899,7 +1907,7 @@ public class ServerPlayer extends Player {
this.onUpdateAbilities();
this.updateEffectVisibility();
@ -76,7 +76,7 @@ index cb2f86e0ad0edc54711826215df4406c5725f29c..0abc9dfd73b3cb16b29bdbcc40f0d0ea
}
}
@@ -2305,6 +2313,16 @@ public class ServerPlayer extends Player {
@@ -2303,6 +2311,16 @@ public class ServerPlayer extends Player {
}
public void loadGameTypes(@Nullable CompoundTag nbt) {

View File

@ -5,10 +5,10 @@ Subject: [PATCH] Fix PlayerDropItemEvent using wrong item
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
index 0abc9dfd73b3cb16b29bdbcc40f0d0ea1c022f34..2265259b24ae27a85beea1d47ec2c1bae6baa2a7 100644
index 327307404d336d0e66a265e79448f2342cc36220..1d8328bc7acde64f3a0cff4d20bdca44baddd409 100644
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
@@ -2282,7 +2282,7 @@ public class ServerPlayer extends Player {
@@ -2280,7 +2280,7 @@ public class ServerPlayer extends Player {
if (retainOwnership) {
if (!itemstack1.isEmpty()) {

View File

@ -5,10 +5,10 @@ Subject: [PATCH] Fixes kick event leave message not being sent
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
index 2265259b24ae27a85beea1d47ec2c1bae6baa2a7..552d64e47f17d916a4e374b877d12ff7a583a9e7 100644
index 1d8328bc7acde64f3a0cff4d20bdca44baddd409..a75377cf94c70011a967e7ede93f903aae4f9f05 100644
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
@@ -267,7 +267,6 @@ public class ServerPlayer extends Player {
@@ -266,7 +266,6 @@ public class ServerPlayer extends Player {
public boolean joining = true;
public boolean sentListPacket = false;
public boolean supressTrackerForLogin = false; // Paper

View File

@ -11,7 +11,7 @@ It does not make a lot of sense to damage players if they get crammed,
For those who really want it a config option is provided.
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
index 552d64e47f17d916a4e374b877d12ff7a583a9e7..a59ac2011b85ff9b1185a14eca4d2796b2666df1 100644
index a75377cf94c70011a967e7ede93f903aae4f9f05..b8f60c2deb7e46f654d0169751c793b3b3408748 100644
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
@@ -95,6 +95,7 @@ import net.minecraft.util.Mth;
@ -22,7 +22,7 @@ index 552d64e47f17d916a4e374b877d12ff7a583a9e7..a59ac2011b85ff9b1185a14eca4d2796
import net.minecraft.world.effect.MobEffectInstance;
import net.minecraft.world.effect.MobEffects;
import net.minecraft.world.entity.Entity;
@@ -1475,7 +1476,7 @@ public class ServerPlayer extends Player {
@@ -1473,7 +1474,7 @@ public class ServerPlayer extends Player {
@Override
public boolean isInvulnerableTo(DamageSource damageSource) {

View File

@ -49,10 +49,10 @@ index a2d0699e8427b2262a2396495111125eccafbb66..d797637f61bdf8a424f56fbb48e28b7c
}
}
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
index a59ac2011b85ff9b1185a14eca4d2796b2666df1..c2b535c5b1d05d70a16e15283ff5c9e45c59d8e3 100644
index b8f60c2deb7e46f654d0169751c793b3b3408748..39515b81fd753c8c6d50d1efa4c5792f9f0abda9 100644
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
@@ -1352,7 +1352,7 @@ public class ServerPlayer extends Player {
@@ -1350,7 +1350,7 @@ public class ServerPlayer extends Player {
} else if (this.bedBlocked(blockposition, enumdirection)) {
return Either.left(Player.BedSleepingProblem.OBSTRUCTED);
} else {
@ -61,7 +61,7 @@ index a59ac2011b85ff9b1185a14eca4d2796b2666df1..c2b535c5b1d05d70a16e15283ff5c9e4
if (this.level().isDay()) {
return Either.left(Player.BedSleepingProblem.NOT_POSSIBLE_NOW);
} else {
@@ -2202,44 +2202,50 @@ public class ServerPlayer extends Player {
@@ -2200,44 +2200,50 @@ public class ServerPlayer extends Player {
return this.respawnForced;
}
@ -145,7 +145,7 @@ index a59ac2011b85ff9b1185a14eca4d2796b2666df1..c2b535c5b1d05d70a16e15283ff5c9e4
} else {
this.respawnPosition = null;
this.respawnDimension = Level.OVERWORLD;
@@ -2247,6 +2253,7 @@ public class ServerPlayer extends Player {
@@ -2245,6 +2251,7 @@ public class ServerPlayer extends Player {
this.respawnForced = false;
}

View File

@ -28,10 +28,10 @@ index a11bd2d9f5b2fb248cc322ea61886050fa2e73a9..80f2a1204bee79daf0cae9310ce8d552
}
// Spigot End
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
index c2b535c5b1d05d70a16e15283ff5c9e45c59d8e3..de9248f622834dc6df4af7016f0ddab864ed0264 100644
index 39515b81fd753c8c6d50d1efa4c5792f9f0abda9..5f0ff1b2466469eff0bf78042b9cdd2fcf747dc7 100644
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
@@ -1618,6 +1618,18 @@ public class ServerPlayer extends Player {
@@ -1616,6 +1616,18 @@ public class ServerPlayer extends Player {
this.connection.send(new ClientboundContainerClosePacket(this.containerMenu.containerId));
this.doCloseContainer();
}

View File

@ -257,10 +257,10 @@ index 0000000000000000000000000000000000000000..d3b39d88a72ca25057fd8574d32f28db
+ }
+}
diff --git a/src/main/java/net/minecraft/world/level/NaturalSpawner.java b/src/main/java/net/minecraft/world/level/NaturalSpawner.java
index 7983f9a21251cec4857529ad1180a62668ea5037..e1c4cf4b60b810837526c888ec82acbfc8fe540c 100644
index 9df761f5cf043e8d2dffa711c20ab32fe2992331..d08c7b0b52065980f1f13c5533ff6355028322db 100644
--- a/src/main/java/net/minecraft/world/level/NaturalSpawner.java
+++ b/src/main/java/net/minecraft/world/level/NaturalSpawner.java
@@ -192,6 +192,16 @@ public final class NaturalSpawner {
@@ -190,6 +190,16 @@ public final class NaturalSpawner {
world.getProfiler().pop();
}

View File

@ -106,7 +106,7 @@ index 7e4f3b7a5790292b3b8439fb4696d9d6cfec0167..6c02d5233c782b0e5049afdf84250687
+ // Paper end - execute chunk tasks mid tick
}
diff --git a/src/main/java/net/minecraft/server/level/ServerChunkCache.java b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
index 7b5851cd4f5a91bf7609464d7d6c4bb5a3da14bf..50da1f746edeff63f723776b8e30b041c8de0138 100644
index 7d7dc8246f44d6ffd46b05f917ffbdb9cc24372b..dbedc73039f53ddf042999524eec62f032a20d5d 100644
--- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java
+++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
@@ -571,6 +571,7 @@ public class ServerChunkCache extends ChunkSource {

View File

@ -7,10 +7,10 @@ Reference2BooleanOpenHashMap is going to have
better lookups than HashMap.
diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java
index 463a82f08b7848a4b8a4eb89b201a6e8424c6831..93a2dfca4484d1bdfa00dfb2cf8d94314123aeb8 100644
index c10ef2e6af3e6c52eeb8c96cdbf5352d9dd25dd2..c16e84ee54bf2a65d8bd41f8156b7a4edee5e941 100644
--- a/src/main/java/net/minecraft/server/level/ChunkMap.java
+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java
@@ -1210,7 +1210,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
@@ -1204,7 +1204,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
final Entity entity;
private final int range;
SectionPos lastSectionPos;

View File

@ -5,10 +5,10 @@ Subject: [PATCH] Ensure valid vehicle status
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
index de9248f622834dc6df4af7016f0ddab864ed0264..e498d339830d8fa6dcf0eeee4a27b6295c84ee2e 100644
index 5f0ff1b2466469eff0bf78042b9cdd2fcf747dc7..981a2b55a58f85f551991945adc7a202b4a4ec72 100644
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
@@ -570,7 +570,7 @@ public class ServerPlayer extends Player {
@@ -568,7 +568,7 @@ public class ServerPlayer extends Player {
}
}

View File

@ -2204,10 +2204,10 @@ index d0a8092bf57a29ab7c00ec0ddf52a9fdb2a33267..392406722b0a040c1d41fdc1154d75d3
private Direction(int id, int idOpposite, int idHorizontal, String name, Direction.AxisDirection direction, Direction.Axis axis, Vec3i vector) {
this.data3d = id;
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
index e498d339830d8fa6dcf0eeee4a27b6295c84ee2e..6a33fbfb4f7dbe4a54044ccc408e196e537d96fa 100644
index 981a2b55a58f85f551991945adc7a202b4a4ec72..24deceb51bc2892231dcd1745082d7f766eed4b5 100644
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
@@ -463,7 +463,7 @@ public class ServerPlayer extends Player {
@@ -461,7 +461,7 @@ public class ServerPlayer extends Player {
if (blockposition1 != null) {
this.moveTo(blockposition1, 0.0F, 0.0F);
@ -2216,7 +2216,7 @@ index e498d339830d8fa6dcf0eeee4a27b6295c84ee2e..6a33fbfb4f7dbe4a54044ccc408e196e
break;
}
}
@@ -471,7 +471,7 @@ public class ServerPlayer extends Player {
@@ -469,7 +469,7 @@ public class ServerPlayer extends Player {
} else {
this.moveTo(blockposition, 0.0F, 0.0F);

View File

@ -5,10 +5,10 @@ Subject: [PATCH] fix player loottables running when mob loot gamerule is false
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
index 6a33fbfb4f7dbe4a54044ccc408e196e537d96fa..6a9e1b3fd1d7d1964835c78808f5c71ba8a82af7 100644
index 24deceb51bc2892231dcd1745082d7f766eed4b5..d865907d4c5d1428d85e4bb63eb45529802d0c0d 100644
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
@@ -918,12 +918,14 @@ public class ServerPlayer extends Player {
@@ -916,12 +916,14 @@ public class ServerPlayer extends Player {
}
}
}

View File

@ -24,10 +24,10 @@ index d4a673a9fb604876c554f955ed13ad31a2adb217..e75b3df4db9cb618aef4837acb8cde92
} else {
BlockPos blockPos = BlockPos.containing(x, y, z);
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
index 6a9e1b3fd1d7d1964835c78808f5c71ba8a82af7..b3fa0a7e75a7f367ab491ffad22facb985d8085a 100644
index d865907d4c5d1428d85e4bb63eb45529802d0c0d..fc70531c97ce292a9964512008278bcf9377feb6 100644
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
@@ -1317,6 +1317,12 @@ public class ServerPlayer extends Player {
@@ -1315,6 +1315,12 @@ public class ServerPlayer extends Player {
ResourceKey<Level> maindimensionkey = CraftDimensionUtil.getMainDimensionKey(origin);
ResourceKey<Level> maindimensionkey1 = CraftDimensionUtil.getMainDimensionKey(this.level());

View File

@ -111,10 +111,10 @@ index 6cd6d69a20e95e344fc18ab67dc300824537a59b..2e2a7c2cf3081187da817479a9da3eb1
}
}
diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java
index 93a2dfca4484d1bdfa00dfb2cf8d94314123aeb8..8cda789284a30dab012bfda8f97409bdde861c7e 100644
index c16e84ee54bf2a65d8bd41f8156b7a4edee5e941..d7dcffde09e099ee2554ec201f553ee079f12274 100644
--- a/src/main/java/net/minecraft/server/level/ChunkMap.java
+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java
@@ -825,7 +825,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
@@ -819,7 +819,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
}
// Paper end

View File

@ -5,10 +5,10 @@ Subject: [PATCH] Add PlayerInventorySlotChangeEvent
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
index b3fa0a7e75a7f367ab491ffad22facb985d8085a..3e37684e3fbbb01ad006f2ae7f1e38ed63acc2b8 100644
index fc70531c97ce292a9964512008278bcf9377feb6..d882295abf739967fa5f8621945a5dcd0b730ee4 100644
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
@@ -372,6 +372,25 @@ public class ServerPlayer extends Player {
@@ -371,6 +371,25 @@ public class ServerPlayer extends Player {
}
}

View File

@ -8,10 +8,10 @@ offhand slot isn't sent. This is not correct because you *can* put stuff into th
by pressing the offhand swap item
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
index 3e37684e3fbbb01ad006f2ae7f1e38ed63acc2b8..215786e3991942ad5773306a68519946372e94d4 100644
index d882295abf739967fa5f8621945a5dcd0b730ee4..1021872e3ee489bc38e64bdea8bbe53284c87183 100644
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
@@ -341,6 +341,13 @@ public class ServerPlayer extends Player {
@@ -340,6 +340,13 @@ public class ServerPlayer extends Player {
}

View File

@ -5,10 +5,10 @@ Subject: [PATCH] Player Entity Tracking Events
diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java
index 8cda789284a30dab012bfda8f97409bdde861c7e..3d5f992c2f4a8df1cf0db1c209e2cce19e214b8a 100644
index d7dcffde09e099ee2554ec201f553ee079f12274..160e8175fcae33c6643c2f731cc20b397ee86be9 100644
--- a/src/main/java/net/minecraft/server/level/ChunkMap.java
+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java
@@ -1282,9 +1282,18 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
@@ -1276,9 +1276,18 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
// CraftBukkit end
if (flag) {
if (this.seenBy.add(player.connection)) {

View File

@ -6,10 +6,10 @@ Subject: [PATCH] Improve cancelling PreCreatureSpawnEvent with per player mob
diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java
index 3d5f992c2f4a8df1cf0db1c209e2cce19e214b8a..91549ce95c4829f2262ccddf51372b1c858da15c 100644
index 160e8175fcae33c6643c2f731cc20b397ee86be9..1e5ea1db14d7ae4ce25ba91e0bcd5245204af78b 100644
--- a/src/main/java/net/minecraft/server/level/ChunkMap.java
+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java
@@ -313,8 +313,27 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
@@ -307,8 +307,26 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
}
}
@ -19,15 +19,14 @@ index 3d5f992c2f4a8df1cf0db1c209e2cce19e214b8a..91549ce95c4829f2262ccddf51372b1c
+ return;
+ }
+ int idx = mobCategory.ordinal();
+ final com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<ServerPlayer> inRange = this.playerMobDistanceMap.getObjectsInRange(chunkX, chunkZ);
+ if (inRange != null) {
+ final Object[] set = inRange.getBackingSet();
+ for (int i = 0; i < set.length; i++) {
+ if (!(set[i] instanceof ServerPlayer serverPlayer)) {
+ continue;
+ }
+ ++serverPlayer.mobBackoffCounts[idx];
+ }
+ final com.destroystokyo.paper.util.maplist.ReferenceList<ServerPlayer> inRange =
+ this.getNearbyPlayers().getPlayersByChunk(chunkX, chunkZ, io.papermc.paper.util.player.NearbyPlayers.NearbyMapType.TICK_VIEW_DISTANCE);
+ if (inRange == null) {
+ return;
+ }
+ final Object[] backingSet = inRange.getRawData();
+ for (int i = 0, len = inRange.size(); i < len; i++) {
+ ++((ServerPlayer)backingSet[i]).mobBackoffCounts[idx];
+ }
+ }
+ // Paper end - per player mob count backoff
@ -39,11 +38,11 @@ index 3d5f992c2f4a8df1cf0db1c209e2cce19e214b8a..91549ce95c4829f2262ccddf51372b1c
// Paper end
diff --git a/src/main/java/net/minecraft/server/level/ServerChunkCache.java b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
index 50da1f746edeff63f723776b8e30b041c8de0138..2ab16e10323982e193e647246bd116e31f17bad2 100644
index dbedc73039f53ddf042999524eec62f032a20d5d..aaaf3a60696389b4e27a45de69743311c58e5829 100644
--- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java
+++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
@@ -532,7 +532,17 @@ public class ServerChunkCache extends ChunkSource {
if ((this.spawnFriendlies || this.spawnEnemies) && this.chunkMap.playerMobDistanceMap != null) { // don't count mobs when animals and monsters are disabled
if ((this.spawnFriendlies || this.spawnEnemies) && this.level.paperConfig().entities.spawning.perPlayerMobSpawns) { // don't count mobs when animals and monsters are disabled
// re-set mob counts
for (ServerPlayer player : this.level.players) {
- Arrays.fill(player.mobCounts, 0);
@ -62,22 +61,22 @@ index 50da1f746edeff63f723776b8e30b041c8de0138..2ab16e10323982e193e647246bd116e3
spawnercreature_d = NaturalSpawner.createState(l, this.level.getAllEntities(), this::getFullChunk, null, true);
} else {
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
index 215786e3991942ad5773306a68519946372e94d4..50dcbace6fea4669af904000df08ee6d13df77f8 100644
index 1021872e3ee489bc38e64bdea8bbe53284c87183..d2729c381632bc32ca915bf60614847db07e488b 100644
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
@@ -252,6 +252,7 @@ public class ServerPlayer extends Player {
// Paper start - mob spawning rework
@@ -253,6 +253,7 @@ public class ServerPlayer extends Player {
public static final int MOBCATEGORY_TOTAL_ENUMS = net.minecraft.world.entity.MobCategory.values().length;
public final int[] mobCounts = new int[MOBCATEGORY_TOTAL_ENUMS]; // Paper
// Paper end - mob spawning rework
+ public final int[] mobBackoffCounts = new int[MOBCATEGORY_TOTAL_ENUMS]; // Paper - per player mob count backoff
public final com.destroystokyo.paper.util.PooledHashSets.PooledObjectLinkedOpenHashSet<ServerPlayer> cachedSingleMobDistanceMap;
// Paper end
// CraftBukkit start
public String displayName;
diff --git a/src/main/java/net/minecraft/world/level/NaturalSpawner.java b/src/main/java/net/minecraft/world/level/NaturalSpawner.java
index e1c4cf4b60b810837526c888ec82acbfc8fe540c..64656c384863a6430e933e506d965ee628f08669 100644
index d08c7b0b52065980f1f13c5533ff6355028322db..3cdddda9c0618e95288b81b975d499c8dd30c05f 100644
--- a/src/main/java/net/minecraft/world/level/NaturalSpawner.java
+++ b/src/main/java/net/minecraft/world/level/NaturalSpawner.java
@@ -279,6 +279,11 @@ public final class NaturalSpawner {
@@ -277,6 +277,11 @@ public final class NaturalSpawner {
// Paper start
PreSpawnStatus doSpawning = isValidSpawnPostitionForType(world, group, structuremanager, chunkgenerator, biomesettingsmobs_c, blockposition_mutableblockposition, d2);

View File

@ -6,10 +6,10 @@ Subject: [PATCH] Configurable entity tracking range by Y coordinate
Options to configure entity tracking by Y coordinate, also for each entity category.
diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java
index 91549ce95c4829f2262ccddf51372b1c858da15c..dcf12bea1759d851d663896938ea101303ab63a5 100644
index 1e5ea1db14d7ae4ce25ba91e0bcd5245204af78b..edbd5d4e2dcf5112148dc3d7a9173bb4d0a5d445 100644
--- a/src/main/java/net/minecraft/server/level/ChunkMap.java
+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java
@@ -1293,6 +1293,15 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
@@ -1286,6 +1286,15 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
double d1 = vec3d.x * vec3d.x + vec3d.z * vec3d.z;
double d2 = d0 * d0;
boolean flag = d1 <= d2 && this.entity.broadcastToPlayer(player) && ChunkMap.this.isChunkTracked(player, this.entity.chunkPosition().x, this.entity.chunkPosition().z);

View File

@ -5,10 +5,10 @@ Subject: [PATCH] Add titleOverride to InventoryOpenEvent
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
index 50dcbace6fea4669af904000df08ee6d13df77f8..6a11b262a6f1cd5eba96471666098c82978027ff 100644
index d2729c381632bc32ca915bf60614847db07e488b..261d0cc1812831fa99358ec1c6438a4e89629bde 100644
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
@@ -1561,12 +1561,17 @@ public class ServerPlayer extends Player {
@@ -1559,12 +1559,17 @@ public class ServerPlayer extends Player {
this.nextContainerCounter();
AbstractContainerMenu container = factory.createMenu(this.containerCounter, this.getInventory(), this);
@ -27,7 +27,7 @@ index 50dcbace6fea4669af904000df08ee6d13df77f8..6a11b262a6f1cd5eba96471666098c82
if (container == null && !cancelled) { // Let pre-cancelled events fall through
// SPIGOT-5263 - close chest if cancelled
if (factory instanceof Container) {
@@ -1588,7 +1593,7 @@ public class ServerPlayer extends Player {
@@ -1586,7 +1591,7 @@ public class ServerPlayer extends Player {
} else {
// CraftBukkit start
this.containerMenu = container;

View File

@ -0,0 +1,374 @@
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 60c7680d678f9dc6a6a3109b1f6af8150ccd9100..d05195358a00e498e0184ab105ebb3dc7a39e15a 100644
--- 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));
+ players[NearbyMapType.SPAWN_RANGE.ordinal()].update(chunk.x, chunk.z, SPAWN_RANGE_VIEW_DISTANCE);
}
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 2b998bdbe49bf8211b755e0eb7c1bf13ac280eab..5afeb59ff25fed2d565407acacffec8383398006 100644
--- 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()) {
+ if (this.needsBroadcastChanges()) { // Paper - 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 edbd5d4e2dcf5112148dc3d7a9173bb4d0a5d445..0c2617574e21037d94ac56ad08b490f9bca5c5af 100644
--- a/src/main/java/net/minecraft/server/level/ChunkMap.java
+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java
@@ -162,6 +162,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
// Note: players need to be explicitly added to distance maps before they can be updated
this.nearbyPlayers.removePlayer(player);
this.level.playerChunkLoader.removePlayer(player); // Paper - replace chunk loader
+ this.playerMobSpawnMap.remove(player); // Paper - optimise chunk tick iteration
}
void updateMaps(ServerPlayer player) {
@@ -203,6 +204,10 @@ 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(session.getDimensionPath(world.dimension()).resolve("region"), dataFixer, dsync);
@@ -330,7 +335,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
}
// Paper end
- 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 68550d4497a5f10bf653482f79be77373df53f27..55f96545d6db95e3e657502a7910d96fded1113e 100644
--- 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
@@ -136,7 +136,7 @@ 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
}
@@ -150,7 +150,7 @@ 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
}
@@ -192,13 +192,11 @@ 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 aaaf3a60696389b4e27a45de69743311c58e5829..17b6925b46f8386dcfc561483693de516465ec12 100644
--- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java
+++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
@@ -553,52 +553,114 @@ public class ServerChunkCache extends ChunkSource {
this.lastSpawnState = spawnercreature_d;
gameprofilerfiller.popPush("filteringLoadedChunks");
- List<ServerChunkCache.ChunkAndHolder> list = Lists.newArrayListWithCapacity(l);
- Iterator iterator = this.chunkMap.getChunks().iterator();
+ // Paper - optimise chunk tick iteration
+ // Paper - optimise chunk tick iteration
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
gameprofilerfiller.popPush("spawnAndTick");
boolean flag2 = this.level.getGameRules().getBoolean(GameRules.RULE_DOMOBSPAWNING) && !this.level.players().isEmpty(); // CraftBukkit
- Collections.shuffle(list);
- // 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();
- };
- // Paper end
- Iterator iterator1 = list.iterator();
+ // 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 - optimise chunk tick iteration
int chunksTicked = 0; // Paper
+ // Paper start - optimise chunk tick iteration
+ io.papermc.paper.util.player.NearbyPlayers nearbyPlayers = this.chunkMap.getNearbyPlayers(); // Paper - optimise chunk tick iteration
+ Iterator<LevelChunk> iterator1;
+ if (this.level.paperConfig().entities.spawning.perPlayerMobSpawns) {
+ iterator1 = this.tickingChunks.iterator();
+ } else {
+ iterator1 = this.tickingChunks.unsafeIterator();
+ List<LevelChunk> shuffled = Lists.newArrayListWithCapacity(this.tickingChunks.size());
+ while (iterator1.hasNext()) {
+ shuffled.add(iterator1.next());
+ }
+ Collections.shuffle(shuffled);
+ iterator1 = shuffled.iterator();
+ }
+ try {
+ // Paper end - optimise chunk tick iteration
while (iterator1.hasNext()) {
- ServerChunkCache.ChunkAndHolder chunkproviderserver_a = (ServerChunkCache.ChunkAndHolder) iterator1.next();
- LevelChunk chunk1 = chunkproviderserver_a.chunk;
+ LevelChunk chunk1 = iterator1.next(); // Paper - 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;
+ }
+ }
+ // Paper end - optimise chunk tick iteration
+ if (tick && chunk1.chunkStatus.isOrAfter(net.minecraft.server.level.FullChunkStatus.ENTITY_TICKING)) { // Paper - optimise chunk tick iteration
chunk1.incrementInhabitedTime(j);
- if (flag2 && (this.spawnEnemies || this.spawnFriendlies) && this.level.getWorldBorder().isWithinBounds(chunkcoordintpair) && this.chunkMap.anyPlayerCloseEnoughForSpawning(chunkcoordintpair, true)) { // Spigot
+ if (spawn && flag2 && (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, k);
if ((chunksTicked++ & 1) == 0) net.minecraft.server.MinecraftServer.getServer().executeMidTickTasks(); // Paper
}
}
}
+ // Paper start - optimise chunk tick iteration
+ } finally {
+ if (iterator1 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");
if (flag2) {
@@ -608,11 +670,23 @@ 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();
this.chunkMap.tick();
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
index 261d0cc1812831fa99358ec1c6438a4e89629bde..d4aec99cac3f83d764e21946cc904c00e084704e 100644
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
@@ -317,6 +317,9 @@ 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);