2021-06-14 04:41:44 +02:00
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: kickash32 <kickash32@gmail.com>
Date: Mon, 19 Aug 2019 01:27:58 +0500
2024-01-21 12:53:04 +01:00
Subject: [PATCH] Optional per player mob spawns
2021-06-14 04:41:44 +02:00
2024-12-19 12:03:16 +01:00
diff --git a/net/minecraft/server/level/ChunkMap.java b/net/minecraft/server/level/ChunkMap.java
2024-12-20 23:18:34 +01:00
index ff6503bf8eb88d1264c3d848a89d0255b4b3ae68..9eed24939fc09f00a9dbce1be2ab9c34d024fd29 100644
2024-12-19 12:03:16 +01:00
--- a/net/minecraft/server/level/ChunkMap.java
+++ b/net/minecraft/server/level/ChunkMap.java
2024-12-20 23:18:34 +01:00
@@ -236,11 +236,29 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
// Paper - rewrite chunk system
2021-11-24 10:01:27 +01:00
}
2022-09-26 10:02:51 +02:00
2024-12-19 12:03:16 +01:00
- // Paper start
- public int getMobCountNear(final ServerPlayer player, final net.minecraft.world.entity.MobCategory mobCategory) {
- return -1;
2024-01-21 12:53:04 +01:00
+ // Paper start - Optional per player mob spawns
2024-01-23 18:01:39 +01:00
+ public void updatePlayerMobTypeMap(final Entity entity) {
2022-06-09 10:51:45 +02:00
+ if (!this.level.paperConfig().entities.spawning.perPlayerMobSpawns) {
2021-06-14 04:41:44 +02:00
+ return;
+ }
+
2024-12-19 12:03:16 +01:00
+ final int index = entity.getType().getCategory().ordinal();
2024-07-17 19:24:53 +02:00
+ 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);
2022-01-02 20:06:08 +01:00
+ if (inRange == null) {
+ return;
+ }
2024-12-19 12:03:16 +01:00
+
2024-07-17 19:24:53 +02:00
+ final ServerPlayer[] backingSet = inRange.getRawDataUnchecked();
2023-09-24 06:43:10 +02:00
+ for (int i = 0, len = inRange.size(); i < len; i++) {
2024-07-17 19:24:53 +02:00
+ ++(backingSet[i].mobCounts[index]);
2021-06-14 04:41:44 +02:00
+ }
2024-01-23 18:01:39 +01:00
}
2024-12-19 12:03:16 +01:00
- // 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
2024-01-23 18:01:39 +01:00
2024-12-19 12:03:16 +01:00
protected ChunkGenerator generator() {
return this.worldGenContext.generator();
diff --git a/net/minecraft/server/level/ServerChunkCache.java b/net/minecraft/server/level/ServerChunkCache.java
2024-12-20 23:18:34 +01:00
index 87d4291a3944f706a694536da6de0f28c548ab8d..5576bf1d1d70ab7a010653d3207909b5de867e70 100644
2024-12-19 12:03:16 +01:00
--- a/net/minecraft/server/level/ServerChunkCache.java
+++ b/net/minecraft/server/level/ServerChunkCache.java
2024-12-20 23:18:34 +01:00
@@ -517,7 +517,7 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon
2024-12-19 12:03:16 +01:00
profilerFiller.popPush("shuffleChunks");
2024-12-20 23:18:34 +01:00
// Paper start - chunk tick iteration optimisation
this.shuffleRandom.setSeed(this.level.random.nextLong());
- Util.shuffle(list, this.shuffleRandom);
2024-10-27 11:56:51 +01:00
+ 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
2024-12-20 23:18:34 +01:00
// Paper end - chunk tick iteration optimisation
2024-12-19 12:03:16 +01:00
this.tickChunks(profilerFiller, l, list);
profilerFiller.pop();
2024-12-20 23:18:34 +01:00
@@ -571,9 +571,18 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon
2024-12-19 12:03:16 +01:00
private void tickChunks(ProfilerFiller profiler, long timeInhabited, List<LevelChunk> chunks) {
2024-10-27 11:56:51 +01:00
profiler.popPush("naturalSpawnCount");
2024-12-19 12:03:16 +01:00
int naturalSpawnChunkCount = this.distanceManager.getNaturalSpawnChunkCount();
- NaturalSpawner.SpawnState spawnState = NaturalSpawner.createState(
- naturalSpawnChunkCount, this.level.getAllEntities(), this::getFullChunk, new LocalMobCapCalculator(this.chunkMap)
- );
2024-10-27 11:56:51 +01:00
+ // Paper start - Optional per player mob spawns
2024-12-19 12:03:16 +01:00
+ NaturalSpawner.SpawnState spawnState;
2024-10-27 11:56:51 +01:00
+ 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);
+ }
2024-12-19 12:03:16 +01:00
+ spawnState = NaturalSpawner.createState(naturalSpawnChunkCount, this.level.getAllEntities(), this::getFullChunk, null, true);
2024-10-27 11:56:51 +01:00
+ } else {
2024-12-19 12:03:16 +01:00
+ spawnState = NaturalSpawner.createState(naturalSpawnChunkCount, this.level.getAllEntities(), this::getFullChunk, !this.level.paperConfig().entities.spawning.perPlayerMobSpawns ? new LocalMobCapCalculator(this.chunkMap) : null, false);
2024-10-27 11:56:51 +01:00
+ }
+ // Paper end - Optional per player mob spawns
2024-12-19 12:03:16 +01:00
this.lastSpawnState = spawnState;
2024-10-27 18:11:15 +01:00
profiler.popPush("spawnAndTick");
2024-12-19 12:03:16 +01:00
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
2024-12-21 13:45:04 +01:00
index 0a7e5106a1d39150326e7c323030df5d32ecef1e..a63702dd7e86fc8b9f78c2ae23e23b65b6b2ee24 100644
2024-12-19 12:03:16 +01:00
--- a/net/minecraft/server/level/ServerPlayer.java
+++ b/net/minecraft/server/level/ServerPlayer.java
2024-12-20 23:18:34 +01:00
@@ -368,6 +368,10 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
2024-01-24 11:45:17 +01:00
public boolean queueHealthUpdatePacket;
2021-06-14 04:41:44 +02:00
public net.minecraft.network.protocol.game.ClientboundSetHealthPacket queuedHealthUpdatePacket;
2024-01-24 11:45:17 +01:00
// Paper end - cancellable death event
2024-01-21 12:53:04 +01:00
+ // Paper start - Optional per player mob spawns
2021-07-04 18:30:59 +02:00
+ public static final int MOBCATEGORY_TOTAL_ENUMS = net.minecraft.world.entity.MobCategory.values().length;
2024-12-19 12:03:16 +01:00
+ public final int[] mobCounts = new int[MOBCATEGORY_TOTAL_ENUMS];
2024-01-21 12:53:04 +01:00
+ // Paper end - Optional per player mob spawns
2021-06-14 04:41:44 +02:00
// CraftBukkit start
2024-12-19 12:03:16 +01:00
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
2024-12-20 23:18:34 +01:00
index 913ea92ace9d610c25bf28f703a3b227044aea63..ef8bacbbb43a9b80281a313ca43b7efff5a93e03 100644
2024-12-19 12:03:16 +01:00
--- 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
) {
2024-01-21 12:53:04 +01:00
+ // Paper start - Optional per player mob spawns
2024-12-19 12:03:16 +01:00
+ return createState(spawnableChunkCount, entities, chunkGetter, calculator, false);
2021-06-14 04:41:44 +02:00
+ }
2021-11-24 10:01:27 +01:00
+
2024-12-19 12:03:16 +01:00
+ public static NaturalSpawner.SpawnState createState(
+ int spawnableChunkCount, Iterable<Entity> entities, NaturalSpawner.ChunkGetter chunkGetter, LocalMobCapCalculator calculator, final boolean countMobs
+ ) {
2024-01-21 12:53:04 +01:00
+ // Paper end - Optional per player mob spawns
2024-12-19 12:03:16 +01:00
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
});
}
2021-06-14 04:41:44 +02:00
}
2024-12-19 12:03:16 +01:00
@@ -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);
2024-10-27 11:56:51 +01:00
// CraftBukkit end
}
2024-12-19 12:03:16 +01:00
@@ -149,8 +162,37 @@ public final class NaturalSpawner {
profilerFiller.push("spawner");
2024-10-27 11:56:51 +01:00
2024-12-19 12:03:16 +01:00
for (MobCategory mobCategory : categories) {
- if (spawnState.canSpawnForCategoryLocal(mobCategory, chunk.getPos())) {
- spawnCategoryForChunk(mobCategory, level, chunk, spawnState::canSpawn, spawnState::afterSpawn);
2024-10-27 11:56:51 +01:00
+ // Paper start - Optional per player mob spawns
+ final boolean canSpawn;
+ int maxSpawns = Integer.MAX_VALUE;
2024-12-19 12:03:16 +01:00
+ if (level.paperConfig().entities.spawning.perPlayerMobSpawns) {
2024-10-27 11:56:51 +01:00
+ // Copied from getFilteredSpawningCategories
2024-12-19 12:03:16 +01:00
+ int limit = mobCategory.getMaxInstancesPerChunk();
+ SpawnCategory spawnCategory = CraftSpawnCategory.toBukkit(mobCategory);
2024-10-27 11:56:51 +01:00
+ if (CraftSpawnCategory.isValidForLimits(spawnCategory)) {
2024-12-19 12:03:16 +01:00
+ limit = level.getWorld().getSpawnLimit(spawnCategory);
2024-10-27 11:56:51 +01:00
+ }
+
+ // Apply per-player limit
2021-06-14 04:41:44 +02:00
+ int minDiff = Integer.MAX_VALUE;
2024-07-17 19:24:53 +02:00
+ final ca.spottedleaf.moonrise.common.list.ReferenceList<net.minecraft.server.level.ServerPlayer> inRange =
2024-12-19 12:03:16 +01:00
+ level.moonrise$getNearbyPlayers().getPlayers(chunk.getPos(), ca.spottedleaf.moonrise.common.misc.NearbyPlayers.NearbyMapType.TICK_VIEW_DISTANCE);
2022-01-02 20:06:08 +01:00
+ if (inRange != null) {
2024-07-17 19:24:53 +02:00
+ final net.minecraft.server.level.ServerPlayer[] backingSet = inRange.getRawDataUnchecked();
2023-09-24 06:43:10 +02:00
+ for (int k = 0, len = inRange.size(); k < len; k++) {
2024-12-19 12:03:16 +01:00
+ minDiff = Math.min(limit - level.getChunkSource().chunkMap.getMobCountNear(backingSet[k], mobCategory), minDiff);
2022-01-02 20:06:08 +01:00
+ }
2021-06-14 04:41:44 +02:00
+ }
2024-10-27 11:56:51 +01:00
+
+ maxSpawns = (minDiff == Integer.MAX_VALUE) ? 0 : minDiff;
+ canSpawn = maxSpawns > 0;
+ } else {
2024-12-19 12:03:16 +01:00
+ canSpawn = spawnState.canSpawnForCategoryLocal(mobCategory, chunk.getPos());
2021-06-14 04:41:44 +02:00
+ }
2024-10-27 11:56:51 +01:00
+ if (canSpawn) {
2024-12-19 12:03:16 +01:00
+ spawnCategoryForChunk(mobCategory, level, chunk, spawnState::canSpawn, spawnState::afterSpawn,
+ maxSpawns, level.paperConfig().entities.spawning.perPlayerMobSpawns ? level.getChunkSource().chunkMap::updatePlayerMobTypeMap : null);
2024-01-21 12:53:04 +01:00
+ // Paper end - Optional per player mob spawns
2021-06-14 04:41:44 +02:00
}
}
2024-12-19 12:03:16 +01:00
@@ -170,9 +212,16 @@ public final class NaturalSpawner {
public static void spawnCategoryForChunk(
MobCategory category, ServerLevel level, LevelChunk chunk, NaturalSpawner.SpawnPredicate filter, NaturalSpawner.AfterSpawnCallback callback
) {
2024-01-21 12:53:04 +01:00
+ // Paper start - Optional per player mob spawns
2024-12-19 12:03:16 +01:00
+ spawnCategoryForChunk(category, level, chunk, filter, callback, Integer.MAX_VALUE, null);
2021-06-14 04:41:44 +02:00
+ }
2024-12-19 12:03:16 +01:00
+ public static void spawnCategoryForChunk(
+ MobCategory category, ServerLevel level, LevelChunk chunk, NaturalSpawner.SpawnPredicate filter, NaturalSpawner.AfterSpawnCallback callback, final int maxSpawns, final Consumer<Entity> trackEntity
+ ) {
2024-01-21 12:53:04 +01:00
+ // Paper end - Optional per player mob spawns
2024-12-19 12:03:16 +01:00
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
2021-06-14 04:41:44 +02:00
}
}
2024-12-19 12:03:16 +01:00
@@ -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);
2021-06-14 04:41:44 +02:00
+ }
2024-12-19 12:03:16 +01:00
+ 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
2022-01-01 03:07:21 +01:00
}
public int getSpawnableChunkCount() {