aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--feature-patches/1066-Incremental-chunk-and-player-saving.patch88
-rw-r--r--feature-patches/1071-Optional-per-player-mob-spawns.patch294
-rw-r--r--feature-patches/1072-Improve-cancelling-PreCreatureSpawnEvent-with-per-pl.patch76
-rw-r--r--paper-server/patches/sources/net/minecraft/world/level/NaturalSpawner.java.patch8
4 files changed, 235 insertions, 231 deletions
diff --git a/feature-patches/1066-Incremental-chunk-and-player-saving.patch b/feature-patches/1066-Incremental-chunk-and-player-saving.patch
index 9e117f351b..17ee1796ca 100644
--- a/feature-patches/1066-Incremental-chunk-and-player-saving.patch
+++ b/feature-patches/1066-Incremental-chunk-and-player-saving.patch
@@ -4,23 +4,23 @@ Date: Sun, 9 Jun 2019 03:53:22 +0100
Subject: [PATCH] Incremental chunk and player saving
-diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
-index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
---- a/src/main/java/net/minecraft/server/MinecraftServer.java
-+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
-@@ -0,0 +0,0 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
-
+diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java
+index f4fba4e2d12c7ab4b4eb9858cd738a9678a2d203..a0a75c84379432ccc525ab22d476c358c77f663b 100644
+--- a/net/minecraft/server/MinecraftServer.java
++++ b/net/minecraft/server/MinecraftServer.java
+@@ -862,7 +862,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
+ boolean var4;
try {
this.isSaving = true;
- this.getPlayerList().saveAll();
+ this.getPlayerList().saveAll(); // Paper - Incremental chunk and player saving; diff on change
- flag3 = this.saveAllChunks(suppressLogs, flush, force);
+ var4 = this.saveAllChunks(suppressLog, flush, forced);
} finally {
this.isSaving = false;
-@@ -0,0 +0,0 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
+@@ -1409,9 +1409,29 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
}
- --this.ticksUntilAutosave;
+ this.ticksUntilAutosave--;
- if (this.autosavePeriod > 0 && this.ticksUntilAutosave <= 0) { // CraftBukkit
- this.autoSave();
+ // Paper start - Incremental chunk and player saving
@@ -47,22 +47,20 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ profiler.pop();
+ // Paper end - Incremental chunk and player saving
- ProfilerFiller gameprofilerfiller = Profiler.get();
-
-diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
-index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
---- a/src/main/java/net/minecraft/server/level/ServerLevel.java
-+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
-@@ -0,0 +0,0 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
+ ProfilerFiller profilerFiller = Profiler.get();
+ this.runAllTasks(); // Paper - move runAllTasks() into full server tick (previously for timings)
+diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java
+index c38eda42b33cfa4792625f40ebde6f30e591119b..c8129f0d8218daff9123f1ad2d8ca321a02e1c7e 100644
+--- a/net/minecraft/server/level/ServerLevel.java
++++ b/net/minecraft/server/level/ServerLevel.java
+@@ -1007,6 +1007,28 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
return !this.server.isUnderSpawnProtection(this, pos, player) && this.getWorldBorder().isWithinBounds(pos);
}
+ // Paper start - Incremental chunk and player saving
+ public void saveIncrementally(boolean doFull) {
-+ ServerChunkCache chunkproviderserver = this.getChunkSource();
-+
+ if (doFull) {
-+ org.bukkit.Bukkit.getPluginManager().callEvent(new org.bukkit.event.world.WorldSaveEvent(getWorld()));
++ org.bukkit.Bukkit.getPluginManager().callEvent(new org.bukkit.event.world.WorldSaveEvent(this.getWorld()));
+ }
+
+ if (doFull) {
@@ -72,8 +70,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ // Copied from save()
+ // CraftBukkit start - moved from MinecraftServer.saveChunks
+ if (doFull) { // Paper
-+ ServerLevel worldserver1 = this;
-+ this.serverLevelData.setWorldBorder(worldserver1.getWorldBorder().createSettings());
++ ServerLevel serverLevel1 = this;
++ this.serverLevelData.setWorldBorder(serverLevel1.getWorldBorder().createSettings());
+ this.serverLevelData.setCustomBossEvents(this.server.getCustomBossEvents().save(this.registryAccess()));
+ this.convertable.saveDataTag(this.server.registryAccess(), this.serverLevelData, this.server.getPlayerList().getSingleplayerData());
+ }
@@ -81,34 +79,34 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ }
+ // Paper end - Incremental chunk and player saving
+
- public void save(@Nullable ProgressListener progressListener, boolean flush, boolean savingDisabled) {
- // Paper start - 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 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
---- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
-+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
-@@ -0,0 +0,0 @@ import org.bukkit.inventory.MainHand;
- public class ServerPlayer extends net.minecraft.world.entity.player.Player implements ca.spottedleaf.moonrise.patches.chunk_system.player.ChunkSystemServerPlayer { // Paper - rewrite chunk system
+ public void save(@Nullable ProgressListener progress, boolean flush, boolean skipSave) {
+ ServerChunkCache chunkSource = this.getChunkSource();
+ if (!skipSave) {
+diff --git a/net/minecraft/server/level/ServerPlayer.java b/net/minecraft/server/level/ServerPlayer.java
+index 92bd46cca1956f327fb0b407e988d68782f441a4..0f00db82e85c9e510c2e4fe4065291971c408dad 100644
+--- a/net/minecraft/server/level/ServerPlayer.java
++++ b/net/minecraft/server/level/ServerPlayer.java
+@@ -180,6 +180,7 @@ import org.slf4j.Logger;
+ public class ServerPlayer extends Player {
private static final Logger LOGGER = LogUtils.getLogger();
+ public long lastSave = MinecraftServer.currentTick; // Paper - Incremental chunk and player saving
private static final int NEUTRAL_MOB_DEATH_NOTIFICATION_RADII_XZ = 32;
private static final int NEUTRAL_MOB_DEATH_NOTIFICATION_RADII_Y = 10;
private static final int FLY_STAT_RECORDING_SPEED = 25;
-diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java
-index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
---- a/src/main/java/net/minecraft/server/players/PlayerList.java
-+++ b/src/main/java/net/minecraft/server/players/PlayerList.java
-@@ -0,0 +0,0 @@ public abstract class PlayerList {
+diff --git a/net/minecraft/server/players/PlayerList.java b/net/minecraft/server/players/PlayerList.java
+index bafeeab3edbc73f6f86474e18ab4a3d96ce17157..aaa6b8eee7b34fe6efa76f1fe997dcece827d5dd 100644
+--- a/net/minecraft/server/players/PlayerList.java
++++ b/net/minecraft/server/players/PlayerList.java
+@@ -483,6 +483,7 @@ public abstract class PlayerList {
protected void save(ServerPlayer player) {
if (!player.getBukkitEntity().isPersistent()) return; // CraftBukkit
+ player.lastSave = MinecraftServer.currentTick; // Paper - Incremental chunk and player saving
this.playerIo.save(player);
- ServerStatsCounter serverstatisticmanager = (ServerStatsCounter) player.getStats(); // CraftBukkit
-
-@@ -0,0 +0,0 @@ public abstract class PlayerList {
+ ServerStatsCounter serverStatsCounter = player.getStats(); // CraftBukkit
+ if (serverStatsCounter != null) {
+@@ -1070,9 +1071,23 @@ public abstract class PlayerList {
}
public void saveAll() {
@@ -116,18 +114,20 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ this.saveAll(-1);
+ }
+
-+ public void saveAll(int interval) {
++ public void saveAll(final int interval) {
io.papermc.paper.util.MCUtil.ensureMain("Save Players" , () -> { // Paper - Ensure main
+ int numSaved = 0;
-+ long now = MinecraftServer.currentTick;
- for (int i = 0; i < this.players.size(); ++i) {
-- this.save((ServerPlayer) this.players.get(i));
++ final long now = MinecraftServer.currentTick;
+ for (int i = 0; i < this.players.size(); i++) {
+- this.save(this.players.get(i));
+ final ServerPlayer player = this.players.get(i);
+ if (interval == -1 || now - player.lastSave >= interval) {
+ this.save(player);
-+ if (interval != -1 && ++numSaved >= io.papermc.paper.configuration.GlobalConfiguration.get().playerAutoSave.maxPerTick()) { break; }
++ if (interval != -1 && ++numSaved >= io.papermc.paper.configuration.GlobalConfiguration.get().playerAutoSave.maxPerTick()) {
++ break;
++ }
+ }
+ // Paper end - Incremental chunk and player saving
}
-
return null; }); // Paper - ensure main
+ }
diff --git a/feature-patches/1071-Optional-per-player-mob-spawns.patch b/feature-patches/1071-Optional-per-player-mob-spawns.patch
index dda7294b2a..2604d7bb97 100644
--- a/feature-patches/1071-Optional-per-player-mob-spawns.patch
+++ b/feature-patches/1071-Optional-per-player-mob-spawns.patch
@@ -4,229 +4,233 @@ Date: Mon, 19 Aug 2019 01:27:58 +0500
Subject: [PATCH] Optional per player mob spawns
-diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java
-index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
---- a/src/main/java/net/minecraft/server/level/ChunkMap.java
-+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java
-@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
+diff --git a/net/minecraft/server/level/ChunkMap.java b/net/minecraft/server/level/ChunkMap.java
+index 809f3fe1285e347f18709c2368923fcc8f953ded..6c5b2eb411fb60babbb0c74d5c075696ef70b38d 100644
+--- a/net/minecraft/server/level/ChunkMap.java
++++ b/net/minecraft/server/level/ChunkMap.java
+@@ -237,11 +237,29 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
+ this.chunksToEagerlySave.add(chunkPos.toLong());
}
- // Paper start
+- // Paper start
+- public int getMobCountNear(final ServerPlayer player, final net.minecraft.world.entity.MobCategory mobCategory) {
+- return -1;
+ // Paper start - Optional per player mob spawns
+ public void updatePlayerMobTypeMap(final Entity entity) {
+ if (!this.level.paperConfig().entities.spawning.perPlayerMobSpawns) {
+ return;
+ }
-+ final int index = entity.getType().getCategory().ordinal();
+
++ final int index = entity.getType().getCategory().ordinal();
+ final ca.spottedleaf.moonrise.common.list.ReferenceList<ServerPlayer> inRange =
+ this.level.moonrise$getNearbyPlayers().getPlayers(entity.chunkPosition(), ca.spottedleaf.moonrise.common.misc.NearbyPlayers.NearbyMapType.TICK_VIEW_DISTANCE);
+ if (inRange == null) {
+ return;
+ }
++
+ final ServerPlayer[] backingSet = inRange.getRawDataUnchecked();
+ for (int i = 0, len = inRange.size(); i < len; i++) {
+ ++(backingSet[i].mobCounts[index]);
+ }
-+ }
- public int getMobCountNear(final ServerPlayer player, final net.minecraft.world.entity.MobCategory mobCategory) {
-- return -1;
-+ return player.mobCounts[mobCategory.ordinal()];
-+ // Paper end - Optional per player mob spawns
}
- // Paper end
+- // Paper end
++
++ public int getMobCountNear(final ServerPlayer player, final net.minecraft.world.entity.MobCategory mobCategory) {
++ return player.mobCounts[mobCategory.ordinal()];
++ }
++ // Paper end - Optional per player mob spawns
-diff --git a/src/main/java/net/minecraft/server/level/ServerChunkCache.java b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
-index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
---- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java
-+++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
-@@ -0,0 +0,0 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon
- gameprofilerfiller.popPush("shuffleChunks");
- // Paper start - chunk tick iteration optimisation
- this.shuffleRandom.setSeed(this.level.random.nextLong());
-- Util.shuffle(list, this.shuffleRandom);
+ protected ChunkGenerator generator() {
+ return this.worldGenContext.generator();
+diff --git a/net/minecraft/server/level/ServerChunkCache.java b/net/minecraft/server/level/ServerChunkCache.java
+index 2f49dbc919f7f5eea9abce6106723c72f5ae45fb..078f208e104a652ce48458150389d19ede6808ef 100644
+--- a/net/minecraft/server/level/ServerChunkCache.java
++++ b/net/minecraft/server/level/ServerChunkCache.java
+@@ -435,7 +435,7 @@ public class ServerChunkCache extends ChunkSource {
+ profilerFiller.push("filteringTickingChunks");
+ this.collectTickingChunks(list);
+ profilerFiller.popPush("shuffleChunks");
+- Util.shuffle(list, this.level.random);
+ if (!this.level.paperConfig().entities.spawning.perPlayerMobSpawns) Util.shuffle(list, this.shuffleRandom); // Paper - Optional per player mob spawns; do not need this when per-player is enabled
- // Paper end - chunk tick iteration optimisation
- this.tickChunks(gameprofilerfiller, j, list);
- gameprofilerfiller.pop();
-@@ -0,0 +0,0 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon
- private void tickChunks(ProfilerFiller profiler, long timeDelta, List<LevelChunk> chunks) {
+ this.tickChunks(profilerFiller, l, list);
+ profilerFiller.pop();
+ } finally {
+@@ -474,9 +474,18 @@ public class ServerChunkCache extends ChunkSource {
+ private void tickChunks(ProfilerFiller profiler, long timeInhabited, List<LevelChunk> chunks) {
profiler.popPush("naturalSpawnCount");
- int j = this.distanceManager.getNaturalSpawnChunkCount();
-- NaturalSpawner.SpawnState spawnercreature_d = NaturalSpawner.createState(j, this.level.getAllEntities(), this::getFullChunk, new LocalMobCapCalculator(this.chunkMap));
+ int naturalSpawnChunkCount = this.distanceManager.getNaturalSpawnChunkCount();
+- NaturalSpawner.SpawnState spawnState = NaturalSpawner.createState(
+- naturalSpawnChunkCount, this.level.getAllEntities(), this::getFullChunk, new LocalMobCapCalculator(this.chunkMap)
+- );
+ // Paper start - Optional per player mob spawns
-+ final int naturalSpawnChunkCount = j;
-+ NaturalSpawner.SpawnState spawnercreature_d; // moved down
++ NaturalSpawner.SpawnState spawnState;
+ 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(naturalSpawnChunkCount, this.level.getAllEntities(), this::getFullChunk, null, true);
++ spawnState = NaturalSpawner.createState(naturalSpawnChunkCount, this.level.getAllEntities(), this::getFullChunk, null, true);
+ } else {
-+ spawnercreature_d = NaturalSpawner.createState(naturalSpawnChunkCount, this.level.getAllEntities(), this::getFullChunk, !this.level.paperConfig().entities.spawning.perPlayerMobSpawns ? new LocalMobCapCalculator(this.chunkMap) : null, false);
++ spawnState = NaturalSpawner.createState(naturalSpawnChunkCount, this.level.getAllEntities(), this::getFullChunk, !this.level.paperConfig().entities.spawning.perPlayerMobSpawns ? new LocalMobCapCalculator(this.chunkMap) : null, false);
+ }
+ // Paper end - Optional per player mob spawns
-
- this.lastSpawnState = spawnercreature_d;
+ this.lastSpawnState = spawnState;
profiler.popPush("spawnAndTick");
-diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
-index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
---- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
-+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
-@@ -0,0 +0,0 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player imple
+ boolean _boolean = this.level.getGameRules().getBoolean(GameRules.RULE_DOMOBSPAWNING) && !this.level.players().isEmpty(); // CraftBukkit
+diff --git a/net/minecraft/server/level/ServerPlayer.java b/net/minecraft/server/level/ServerPlayer.java
+index 0f00db82e85c9e510c2e4fe4065291971c408dad..dab58457ed02d3f8153c07de101262b1a0182d71 100644
+--- a/net/minecraft/server/level/ServerPlayer.java
++++ b/net/minecraft/server/level/ServerPlayer.java
+@@ -368,6 +368,10 @@ public class ServerPlayer extends Player {
public boolean queueHealthUpdatePacket;
public net.minecraft.network.protocol.game.ClientboundSetHealthPacket queuedHealthUpdatePacket;
// Paper end - cancellable death event
+ // Paper start - Optional per player mob spawns
+ 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 int[] mobCounts = new int[MOBCATEGORY_TOTAL_ENUMS];
+ // Paper end - Optional per player mob spawns
-
// CraftBukkit start
- public CraftPlayer.TransferCookieConnection transferCookieConnection;
-diff --git a/src/main/java/net/minecraft/world/level/NaturalSpawner.java b/src/main/java/net/minecraft/world/level/NaturalSpawner.java
-index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
---- a/src/main/java/net/minecraft/world/level/NaturalSpawner.java
-+++ b/src/main/java/net/minecraft/world/level/NaturalSpawner.java
-@@ -0,0 +0,0 @@ public final class NaturalSpawner {
- private NaturalSpawner() {}
-
- public static NaturalSpawner.SpawnState createState(int spawningChunkCount, Iterable<Entity> entities, NaturalSpawner.ChunkGetter chunkSource, LocalMobCapCalculator densityCapper) {
+ public org.bukkit.craftbukkit.entity.CraftPlayer.TransferCookieConnection transferCookieConnection;
+ public String displayName;
+diff --git a/net/minecraft/world/level/NaturalSpawner.java b/net/minecraft/world/level/NaturalSpawner.java
+index 6e6e028621ccc4597b2c24f54f53cb7f3de603e2..14e99450a8522b79e4c3805bd91439a950bc8f99 100644
+--- a/net/minecraft/world/level/NaturalSpawner.java
++++ b/net/minecraft/world/level/NaturalSpawner.java
+@@ -72,6 +72,14 @@ public final class NaturalSpawner {
+ public static NaturalSpawner.SpawnState createState(
+ int spawnableChunkCount, Iterable<Entity> entities, NaturalSpawner.ChunkGetter chunkGetter, LocalMobCapCalculator calculator
+ ) {
+ // Paper start - Optional per player mob spawns
-+ return createState(spawningChunkCount, entities, chunkSource, densityCapper, false);
++ return createState(spawnableChunkCount, entities, chunkGetter, calculator, false);
+ }
+
-+ public static NaturalSpawner.SpawnState createState(int spawningChunkCount, Iterable<Entity> entities, NaturalSpawner.ChunkGetter chunkSource, LocalMobCapCalculator densityCapper, boolean countMobs) {
++ public static NaturalSpawner.SpawnState createState(
++ int spawnableChunkCount, Iterable<Entity> entities, NaturalSpawner.ChunkGetter chunkGetter, LocalMobCapCalculator calculator, final boolean countMobs
++ ) {
+ // Paper end - Optional per player mob spawns
- PotentialCalculator spawnercreatureprobabilities = new PotentialCalculator();
- Object2IntOpenHashMap<MobCategory> object2intopenhashmap = new Object2IntOpenHashMap();
- Iterator iterator = entities.iterator();
-@@ -0,0 +0,0 @@ public final class NaturalSpawner {
- spawnercreatureprobabilities.addCharge(entity.blockPosition(), biomesettingsmobs_b.charge());
- }
-
-- if (entity instanceof Mob) {
-+ if (densityCapper != null && entity instanceof Mob) { // Paper - Optional per player mob spawns
- densityCapper.addMob(chunk.getPos(), enumcreaturetype);
- }
-
- object2intopenhashmap.addTo(enumcreaturetype, 1);
-+ // Paper start - Optional per player mob spawns
-+ if (countMobs) {
-+ chunk.level.getChunkSource().chunkMap.updatePlayerMobTypeMap(entity);
-+ }
-+ // Paper end - Optional per player mob spawns
- });
- }
- }
-@@ -0,0 +0,0 @@ public final class NaturalSpawner {
- continue;
+ PotentialCalculator potentialCalculator = new PotentialCalculator();
+ Object2IntOpenHashMap<MobCategory> map = new Object2IntOpenHashMap<>();
+
+@@ -93,11 +101,16 @@ public final class NaturalSpawner {
+ potentialCalculator.addCharge(entity.blockPosition(), mobSpawnCost.charge());
+ }
+
+- if (entity instanceof Mob) {
++ if (calculator != null && entity instanceof Mob) { // Paper - Optional per player mob spawns
+ calculator.addMob(chunk.getPos(), category);
+ }
+
+ map.addTo(category, 1);
++ // Paper start - Optional per player mob spawns
++ if (countMobs) {
++ chunk.level.getChunkSource().chunkMap.updatePlayerMobTypeMap(entity);
++ }
++ // Paper end - Optional per player mob spawns
+ });
+ }
}
-
-- if ((flag || !enumcreaturetype.isFriendly()) && (flag1 || enumcreaturetype.isFriendly()) && (flag2 || !enumcreaturetype.isPersistent()) && spawnercreature_d.canSpawnForCategoryGlobal(enumcreaturetype, limit)) {
-+ if ((flag || !enumcreaturetype.isFriendly()) && (flag1 || enumcreaturetype.isFriendly()) && (flag2 || !enumcreaturetype.isPersistent()) && (worldserver.paperConfig().entities.spawning.perPlayerMobSpawns || spawnercreature_d.canSpawnForCategoryGlobal(enumcreaturetype, limit))) { // Paper - Optional per player mob spawns; remove global check, check later during the local one
+@@ -135,7 +148,7 @@ public final class NaturalSpawner {
+ if ((spawnFriendlies || !mobCategory.isFriendly())
+ && (spawnEnemies || mobCategory.isFriendly())
+ && (spawnPassives || !mobCategory.isPersistent())
+- && spawnState.canSpawnForCategoryGlobal(mobCategory, limit)) { // Paper - Optional per player mob spawns; remove global check, check later during the local one
++ && (level.paperConfig().entities.spawning.perPlayerMobSpawns || spawnState.canSpawnForCategoryGlobal(mobCategory, limit))) { // Paper - Optional per player mob spawns; remove global check, check later during the local one
+ list.add(mobCategory);
// CraftBukkit end
- list.add(enumcreaturetype);
}
-@@ -0,0 +0,0 @@ public final class NaturalSpawner {
- while (iterator.hasNext()) {
- MobCategory enumcreaturetype = (MobCategory) iterator.next();
+@@ -149,8 +162,37 @@ public final class NaturalSpawner {
+ profilerFiller.push("spawner");
-- if (info.canSpawnForCategoryLocal(enumcreaturetype, chunk.getPos())) {
+ for (MobCategory mobCategory : categories) {
+- if (spawnState.canSpawnForCategoryLocal(mobCategory, chunk.getPos())) {
+- spawnCategoryForChunk(mobCategory, level, chunk, spawnState::canSpawn, spawnState::afterSpawn);
+ // Paper start - Optional per player mob spawns
+ final boolean canSpawn;
+ int maxSpawns = Integer.MAX_VALUE;
-+ if (world.paperConfig().entities.spawning.perPlayerMobSpawns) {
++ if (level.paperConfig().entities.spawning.perPlayerMobSpawns) {
+ // Copied from getFilteredSpawningCategories
-+ int limit = enumcreaturetype.getMaxInstancesPerChunk();
-+ SpawnCategory spawnCategory = CraftSpawnCategory.toBukkit(enumcreaturetype);
++ int limit = mobCategory.getMaxInstancesPerChunk();
++ SpawnCategory spawnCategory = CraftSpawnCategory.toBukkit(mobCategory);
+ if (CraftSpawnCategory.isValidForLimits(spawnCategory)) {
-+ limit = world.getWorld().getSpawnLimit(spawnCategory);
++ limit = level.getWorld().getSpawnLimit(spawnCategory);
+ }
+
+ // Apply per-player limit
+ int minDiff = Integer.MAX_VALUE;
+ final ca.spottedleaf.moonrise.common.list.ReferenceList<net.minecraft.server.level.ServerPlayer> inRange =
-+ world.moonrise$getNearbyPlayers().getPlayers(chunk.getPos(), ca.spottedleaf.moonrise.common.misc.NearbyPlayers.NearbyMapType.TICK_VIEW_DISTANCE);
++ level.moonrise$getNearbyPlayers().getPlayers(chunk.getPos(), ca.spottedleaf.moonrise.common.misc.NearbyPlayers.NearbyMapType.TICK_VIEW_DISTANCE);
+ if (inRange != null) {
+ final net.minecraft.server.level.ServerPlayer[] backingSet = inRange.getRawDataUnchecked();
+ for (int k = 0, len = inRange.size(); k < len; k++) {
-+ minDiff = Math.min(limit - world.getChunkSource().chunkMap.getMobCountNear(backingSet[k], enumcreaturetype), minDiff);
++ minDiff = Math.min(limit - level.getChunkSource().chunkMap.getMobCountNear(backingSet[k], mobCategory), minDiff);
+ }
+ }
+
+ maxSpawns = (minDiff == Integer.MAX_VALUE) ? 0 : minDiff;
+ canSpawn = maxSpawns > 0;
+ } else {
-+ canSpawn = info.canSpawnForCategoryLocal(enumcreaturetype, chunk.getPos());
++ canSpawn = spawnState.canSpawnForCategoryLocal(mobCategory, chunk.getPos());
+ }
+ if (canSpawn) {
-+ // Paper end - Optional per player mob spawns
- Objects.requireNonNull(info);
- NaturalSpawner.SpawnPredicate spawnercreature_c = info::canSpawn;
-
- Objects.requireNonNull(info);
-- NaturalSpawner.spawnCategoryForChunk(enumcreaturetype, world, chunk, spawnercreature_c, info::afterSpawn);
-+ // Paper start - Optional per player mob spawns
-+ NaturalSpawner.spawnCategoryForChunk(enumcreaturetype, world, chunk, spawnercreature_c, info::afterSpawn,
-+ maxSpawns, world.paperConfig().entities.spawning.perPlayerMobSpawns ? world.getChunkSource().chunkMap::updatePlayerMobTypeMap : null);
++ spawnCategoryForChunk(mobCategory, level, chunk, spawnState::canSpawn, spawnState::afterSpawn,
++ maxSpawns, level.paperConfig().entities.spawning.perPlayerMobSpawns ? level.getChunkSource().chunkMap::updatePlayerMobTypeMap : null);
+ // Paper end - Optional per player mob spawns
}
}
-@@ -0,0 +0,0 @@ public final class NaturalSpawner {
- // Paper end - Add mobcaps commands
-
- public static void spawnCategoryForChunk(MobCategory group, ServerLevel world, LevelChunk chunk, NaturalSpawner.SpawnPredicate checker, NaturalSpawner.AfterSpawnCallback runner) {
+@@ -170,9 +212,16 @@ public final class NaturalSpawner {
+ public static void spawnCategoryForChunk(
+ MobCategory category, ServerLevel level, LevelChunk chunk, NaturalSpawner.SpawnPredicate filter, NaturalSpawner.AfterSpawnCallback callback
+ ) {
+ // Paper start - Optional per player mob spawns
-+ spawnCategoryForChunk(group, world, chunk, checker, runner, Integer.MAX_VALUE, null);
++ spawnCategoryForChunk(category, level, chunk, filter, callback, Integer.MAX_VALUE, null);
+ }
-+ public static void spawnCategoryForChunk(MobCategory group, ServerLevel world, LevelChunk chunk, NaturalSpawner.SpawnPredicate checker, NaturalSpawner.AfterSpawnCallback runner, int maxSpawns, Consumer<Entity> trackEntity) {
++ public static void spawnCategoryForChunk(
++ MobCategory category, ServerLevel level, LevelChunk chunk, NaturalSpawner.SpawnPredicate filter, NaturalSpawner.AfterSpawnCallback callback, final int maxSpawns, final Consumer<Entity> trackEntity
++ ) {
+ // Paper end - Optional per player mob spawns
- BlockPos blockposition = NaturalSpawner.getRandomPosWithin(world, chunk);
-
- if (blockposition.getY() >= world.getMinY() + 1) {
-- NaturalSpawner.spawnCategoryForPosition(group, world, chunk, blockposition, checker, runner);
-+ NaturalSpawner.spawnCategoryForPosition(group, world, chunk, blockposition, checker, runner, maxSpawns, trackEntity); // Paper - Optional per player mob spawns
+ BlockPos randomPosWithin = getRandomPosWithin(level, chunk);
+ if (randomPosWithin.getY() >= level.getMinY() + 1) {
+- spawnCategoryForPosition(category, level, chunk, randomPosWithin, filter, callback);
++ spawnCategoryForPosition(category, level, chunk, randomPosWithin, filter, callback, maxSpawns, trackEntity); // Paper - Optional per player mob spawns
}
}
-@@ -0,0 +0,0 @@ public final class NaturalSpawner {
- });
- }
-
-+ // Paper start - Optional per player mob spawns
- public static void spawnCategoryForPosition(MobCategory group, ServerLevel world, ChunkAccess chunk, BlockPos pos, NaturalSpawner.SpawnPredicate checker, NaturalSpawner.AfterSpawnCallback runner) {
-+ spawnCategoryForPosition(group, world,chunk, pos, checker, runner, Integer.MAX_VALUE, null);
+@@ -189,6 +238,12 @@ public final class NaturalSpawner {
+ NaturalSpawner.SpawnPredicate filter,
+ NaturalSpawner.AfterSpawnCallback callback
+ ) {
++ spawnCategoryForPosition(category, level, chunk, pos, filter, callback, Integer.MAX_VALUE, null);
+ }
-+ public static void spawnCategoryForPosition(MobCategory group, ServerLevel world, ChunkAccess chunk, BlockPos pos, NaturalSpawner.SpawnPredicate checker, NaturalSpawner.AfterSpawnCallback runner, int maxSpawns, Consumer<Entity> trackEntity) {
-+ // Paper end - Optional per player mob spawns
- StructureManager structuremanager = world.structureManager();
- ChunkGenerator chunkgenerator = world.getChunkSource().getGenerator();
- int i = pos.getY();
-@@ -0,0 +0,0 @@ public final class NaturalSpawner {
- ++j;
- ++k1;
- runner.run(entityinsentient, chunk);
-+ // Paper start - Optional per player mob spawns
-+ if (trackEntity != null) {
-+ trackEntity.accept(entityinsentient);
-+ }
-+ // Paper end - Optional per player mob spawns
- }
- // CraftBukkit end
-- if (j >= entityinsentient.getMaxSpawnClusterSize()) {
-+ if (j >= entityinsentient.getMaxSpawnClusterSize() || j >= maxSpawns) { // Paper - Optional per player mob spawns
- return;
- }
-
-@@ -0,0 +0,0 @@ public final class NaturalSpawner {
- MobCategory enumcreaturetype = entitytypes.getCategory();
-
- this.mobCategoryCounts.addTo(enumcreaturetype, 1);
-- this.localMobCapCalculator.addMob(new ChunkPos(blockposition), enumcreaturetype);
-+ if (this.localMobCapCalculator != null) this.localMobCapCalculator.addMob(new ChunkPos(blockposition), enumcreaturetype); // Paper - Optional per player mob spawns
++ public static void spawnCategoryForPosition(
++ MobCategory category, ServerLevel level, ChunkAccess chunk, BlockPos pos, NaturalSpawner.SpawnPredicate filter, NaturalSpawner.AfterSpawnCallback callback, final int maxSpawns, final @Nullable Consumer<Entity> trackEntity
++ ) {
++ // Paper end - Optional per player mob spawns
+ StructureManager structureManager = level.structureManager();
+ ChunkGenerator generator = level.getChunkSource().getGenerator();
+ int y = pos.getY();
+@@ -252,9 +307,14 @@ public final class NaturalSpawner {
+ ++i;
+ ++i3;
+ callback.run(mobForSpawn, chunk);
++ // Paper start - Optional per player mob spawns
++ if (trackEntity != null) {
++ trackEntity.accept(mobForSpawn);
++ }
++ // Paper end - Optional per player mob spawns
+ }
+ // CraftBukkit end
+- if (i >= mobForSpawn.getMaxSpawnClusterSize()) {
++ if (i >= mobForSpawn.getMaxSpawnClusterSize() || i >= maxSpawns) { // Paper - Optional per player mob spawns
+ return;
+ }
+
+@@ -565,7 +625,7 @@ public final class NaturalSpawner {
+ this.spawnPotential.addCharge(blockPos, d);
+ MobCategory category = type.getCategory();
+ this.mobCategoryCounts.addTo(category, 1);
+- this.localMobCapCalculator.addMob(new ChunkPos(blockPos), category);
++ if (this.localMobCapCalculator != null) this.localMobCapCalculator.addMob(new ChunkPos(blockPos), category); // Paper - Optional per player mob spawns
}
public int getSpawnableChunkCount() {
diff --git a/feature-patches/1072-Improve-cancelling-PreCreatureSpawnEvent-with-per-pl.patch b/feature-patches/1072-Improve-cancelling-PreCreatureSpawnEvent-with-per-pl.patch
index 46e601aaff..d94b29471c 100644
--- a/feature-patches/1072-Improve-cancelling-PreCreatureSpawnEvent-with-per-pl.patch
+++ b/feature-patches/1072-Improve-cancelling-PreCreatureSpawnEvent-with-per-pl.patch
@@ -5,14 +5,14 @@ Subject: [PATCH] Improve cancelling PreCreatureSpawnEvent with per player mob
spawns
-diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java
-index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
---- a/src/main/java/net/minecraft/server/level/ChunkMap.java
-+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java
-@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
- ++(backingSet[i].mobCounts[index]);
+diff --git a/net/minecraft/server/level/ChunkMap.java b/net/minecraft/server/level/ChunkMap.java
+index 6c5b2eb411fb60babbb0c74d5c075696ef70b38d..cf439285e4ba9babda228c36aa81dfc49db2c22a 100644
+--- a/net/minecraft/server/level/ChunkMap.java
++++ b/net/minecraft/server/level/ChunkMap.java
+@@ -256,8 +256,25 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
}
}
+
+ // Paper start - per player mob count backoff
+ public void updateFailurePlayerMobTypeMap(int chunkX, int chunkZ, net.minecraft.world.entity.MobCategory mobCategory) {
+ if (!this.level.paperConfig().entities.spawning.perPlayerMobSpawns) {
@@ -33,14 +33,14 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
public int getMobCountNear(final ServerPlayer player, final net.minecraft.world.entity.MobCategory mobCategory) {
- return player.mobCounts[mobCategory.ordinal()];
+ return player.mobCounts[mobCategory.ordinal()] + player.mobBackoffCounts[mobCategory.ordinal()]; // Paper - per player mob count backoff
- // Paper end - Optional per player mob spawns
- }
- // 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 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
---- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java
-+++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
-@@ -0,0 +0,0 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon
+ }
+ // Paper end - Optional per player mob spawns
+
+diff --git a/net/minecraft/server/level/ServerChunkCache.java b/net/minecraft/server/level/ServerChunkCache.java
+index 078f208e104a652ce48458150389d19ede6808ef..aa141c00a41d49daee8e4ab7be70ce4e4767b105 100644
+--- a/net/minecraft/server/level/ServerChunkCache.java
++++ b/net/minecraft/server/level/ServerChunkCache.java
+@@ -479,7 +479,17 @@ public class ServerChunkCache extends ChunkSource {
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) {
@@ -57,33 +57,33 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ }
+ // Paper end - per player mob spawning backoff
}
- spawnercreature_d = NaturalSpawner.createState(naturalSpawnChunkCount, this.level.getAllEntities(), this::getFullChunk, null, true);
+ spawnState = NaturalSpawner.createState(naturalSpawnChunkCount, 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 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
---- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
-+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
-@@ -0,0 +0,0 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player imple
+diff --git a/net/minecraft/server/level/ServerPlayer.java b/net/minecraft/server/level/ServerPlayer.java
+index dab58457ed02d3f8153c07de101262b1a0182d71..2d20f42fbcfb67845323d994843d7b977aa867e0 100644
+--- a/net/minecraft/server/level/ServerPlayer.java
++++ b/net/minecraft/server/level/ServerPlayer.java
+@@ -372,6 +372,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
+ public final int[] mobCounts = new int[MOBCATEGORY_TOTAL_ENUMS];
// Paper end - Optional per player mob spawns
+ public final int[] mobBackoffCounts = new int[MOBCATEGORY_TOTAL_ENUMS]; // Paper - per player mob count backoff
-
// CraftBukkit start
- public CraftPlayer.TransferCookieConnection transferCookieConnection;
-diff --git a/src/main/java/net/minecraft/world/level/NaturalSpawner.java b/src/main/java/net/minecraft/world/level/NaturalSpawner.java
-index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
---- a/src/main/java/net/minecraft/world/level/NaturalSpawner.java
-+++ b/src/main/java/net/minecraft/world/level/NaturalSpawner.java
-@@ -0,0 +0,0 @@ public final class NaturalSpawner {
+ public org.bukkit.craftbukkit.entity.CraftPlayer.TransferCookieConnection transferCookieConnection;
+ public String displayName;
+diff --git a/net/minecraft/world/level/NaturalSpawner.java b/net/minecraft/world/level/NaturalSpawner.java
+index 5e82a8fdaec5a6750040ebb687aa35bba4dcc2ba..23f7fb22906e49babc7784f4b3d1f8ea8e187b1d 100644
+--- a/net/minecraft/world/level/NaturalSpawner.java
++++ b/net/minecraft/world/level/NaturalSpawner.java
+@@ -285,6 +285,11 @@ public final class NaturalSpawner {
- // Paper start - PreCreatureSpawnEvent
- PreSpawnStatus doSpawning = isValidSpawnPostitionForType(world, group, structuremanager, chunkgenerator, biomesettingsmobs_c, blockposition_mutableblockposition, d2);
-+ // Paper start - per player mob count backoff
-+ if (doSpawning == PreSpawnStatus.ABORT || doSpawning == PreSpawnStatus.CANCELLED) {
-+ world.getChunkSource().chunkMap.updateFailurePlayerMobTypeMap(blockposition_mutableblockposition.getX() >> 4, blockposition_mutableblockposition.getZ() >> 4, group);
-+ }
-+ // Paper end - per player mob count backoff
- if (doSpawning == PreSpawnStatus.ABORT) {
- return;
- }
+ // Paper start - PreCreatureSpawnEvent
+ PreSpawnStatus doSpawning = isValidSpawnPostitionForType(level, category, structureManager, generator, spawnerData, mutableBlockPos, d2);
++ // Paper start - per player mob count backoff
++ if (doSpawning == PreSpawnStatus.ABORT || doSpawning == PreSpawnStatus.CANCELLED) {
++ level.getChunkSource().chunkMap.updateFailurePlayerMobTypeMap(mutableBlockPos.getX() >> 4, mutableBlockPos.getZ() >> 4, category);
++ }
++ // Paper end - per player mob count backoff
+ if (doSpawning == PreSpawnStatus.ABORT) {
+ return;
+ }
diff --git a/paper-server/patches/sources/net/minecraft/world/level/NaturalSpawner.java.patch b/paper-server/patches/sources/net/minecraft/world/level/NaturalSpawner.java.patch
index d5a3311160..89849d7d70 100644
--- a/paper-server/patches/sources/net/minecraft/world/level/NaturalSpawner.java.patch
+++ b/paper-server/patches/sources/net/minecraft/world/level/NaturalSpawner.java.patch
@@ -35,9 +35,9 @@
+ // CraftBukkit start - add server
public static List<MobCategory> getFilteredSpawningCategories(
- NaturalSpawner.SpawnState spawnState, boolean spawnFriendlies, boolean spawnEnemies, boolean spawnPassives
-+ NaturalSpawner.SpawnState spawnState, boolean spawnFriendlies, boolean spawnEnemies, boolean spawnPassives, ServerLevel worldserver
++ NaturalSpawner.SpawnState spawnState, boolean spawnFriendlies, boolean spawnEnemies, boolean spawnPassives, ServerLevel level
) {
-+ LevelData worlddata = worldserver.getLevelData(); // CraftBukkit - Other mob type spawn tick rate
++ LevelData worlddata = level.getLevelData(); // CraftBukkit - Other mob type spawn tick rate
+ // CraftBukkit end
List<MobCategory> list = new ArrayList<>(SPAWNING_CATEGORIES.length);
@@ -47,8 +47,8 @@
+ int limit = mobCategory.getMaxInstancesPerChunk();
+ SpawnCategory spawnCategory = CraftSpawnCategory.toBukkit(mobCategory);
+ if (CraftSpawnCategory.isValidForLimits(spawnCategory)) {
-+ spawnThisTick = worldserver.ticksPerSpawnCategory.getLong(spawnCategory) != 0 && worlddata.getGameTime() % worldserver.ticksPerSpawnCategory.getLong(spawnCategory) == 0;
-+ limit = worldserver.getWorld().getSpawnLimit(spawnCategory);
++ spawnThisTick = level.ticksPerSpawnCategory.getLong(spawnCategory) != 0 && worlddata.getGameTime() % level.ticksPerSpawnCategory.getLong(spawnCategory) == 0;
++ limit = level.getWorld().getSpawnLimit(spawnCategory);
+ }
+
+ if (!spawnThisTick || limit == 0) {