2021-06-11 14:02:28 +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-11-09 21:44:55 +01:00
Feature patch
2021-06-11 14:02:28 +02:00
diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java
2024-10-29 16:54:40 +01:00
index f1999729cd1c00071c5e1835ee49ea5fcafa7b05..4896c3ba81ead769972fa9efdbe563d4006e4401 100644
2021-06-11 14:02:28 +02:00
--- a/src/main/java/net/minecraft/server/level/ChunkMap.java
+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java
2024-10-27 18:11:15 +01:00
@@ -229,8 +229,26 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
2021-11-24 10:01:27 +01:00
}
2022-09-26 10:02:51 +02:00
2024-07-17 19:24:53 +02:00
// Paper start
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-11 14:02:28 +02:00
+ return;
+ }
2024-06-15 14:12:22 +02:00
+ final int index = entity.getType().getCategory().ordinal();
2021-06-11 14:02:28 +02:00
+
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-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-11 14:02:28 +02:00
+ }
+ }
2024-01-23 18:01:39 +01:00
public int getMobCountNear(final ServerPlayer player, final net.minecraft.world.entity.MobCategory mobCategory) {
- return -1;
+ return player.mobCounts[mobCategory.ordinal()];
2024-06-15 14:12:22 +02:00
+ // Paper end - Optional per player mob spawns
2024-01-23 18:01:39 +01:00
}
2024-06-15 14:12:22 +02:00
// Paper end
2024-01-23 18:01:39 +01:00
2021-06-11 14:02:28 +02:00
diff --git a/src/main/java/net/minecraft/server/level/ServerChunkCache.java b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
2024-11-09 15:41:26 +01:00
index 1d75ad42bfe9324baafb5d60e2fd44ece660a5cd..6a59b3b98c99e5b1d8a2d4f5970fc782bdd0b29c 100644
2021-06-11 14:02:28 +02:00
--- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java
+++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
2024-11-09 15:41:26 +01:00
@@ -489,7 +489,7 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon
2024-10-27 11:56:51 +01:00
gameprofilerfiller.popPush("shuffleChunks");
// Paper start - chunk tick iteration optimisation
this.shuffleRandom.setSeed(this.level.random.nextLong());
- Util.shuffle(list, this.shuffleRandom);
+ 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();
2024-11-09 15:41:26 +01:00
@@ -546,7 +546,19 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon
2024-10-27 18:11:15 +01:00
private void tickChunks(ProfilerFiller profiler, long timeDelta, List<LevelChunk> chunks) {
2024-10-27 11:56:51 +01:00
profiler.popPush("naturalSpawnCount");
int j = this.distanceManager.getNaturalSpawnChunkCount();
- NaturalSpawner.SpawnState spawnercreature_d = NaturalSpawner.createState(j, 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
+ 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);
+ } else {
+ spawnercreature_d = 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
2024-07-17 20:33:13 +02:00
2024-10-27 11:56:51 +01:00
this.lastSpawnState = spawnercreature_d;
2024-10-27 18:11:15 +01:00
profiler.popPush("spawnAndTick");
2021-06-11 14:02:28 +02:00
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
2024-10-27 11:56:51 +01:00
index 8c9148426f23cbbdfaf7ae66657d1a620f8bd853..8cc02ee9b1a710e35eb65a5a095681cc7dc542bb 100644
2021-06-11 14:02:28 +02:00
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
2024-10-27 11:56:51 +01:00
@@ -303,6 +303,10 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player imple
2024-01-24 11:45:17 +01:00
public boolean queueHealthUpdatePacket;
2021-06-11 14:02:28 +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;
+ public final int[] mobCounts = new int[MOBCATEGORY_TOTAL_ENUMS]; // Paper
2024-01-21 12:53:04 +01:00
+ // Paper end - Optional per player mob spawns
2021-06-11 14:02:28 +02:00
// CraftBukkit start
2024-04-25 11:42:10 +02:00
public CraftPlayer.TransferCookieConnection transferCookieConnection;
2021-06-11 14:02:28 +02:00
diff --git a/src/main/java/net/minecraft/world/level/NaturalSpawner.java b/src/main/java/net/minecraft/world/level/NaturalSpawner.java
2024-10-27 18:11:15 +01:00
index bf943feca387b77a3154773a59da7190d38d8621..0beb5ab48c5405d9bc2ad8d0c430312f456d38c2 100644
2021-06-11 14:02:28 +02:00
--- a/src/main/java/net/minecraft/world/level/NaturalSpawner.java
+++ b/src/main/java/net/minecraft/world/level/NaturalSpawner.java
2024-10-27 11:56:51 +01:00
@@ -71,6 +71,12 @@ public final class NaturalSpawner {
2021-06-14 04:41:44 +02:00
private NaturalSpawner() {}
2022-11-12 21:57:41 +01:00
public static NaturalSpawner.SpawnState createState(int spawningChunkCount, Iterable<Entity> entities, NaturalSpawner.ChunkGetter chunkSource, LocalMobCapCalculator densityCapper) {
2024-01-21 12:53:04 +01:00
+ // Paper start - Optional per player mob spawns
2022-11-12 21:57:41 +01:00
+ return createState(spawningChunkCount, entities, chunkSource, densityCapper, false);
2021-06-11 14:02:28 +02:00
+ }
2021-11-24 10:01:27 +01:00
+
2022-11-12 21:57:41 +01:00
+ public static NaturalSpawner.SpawnState createState(int spawningChunkCount, Iterable<Entity> entities, NaturalSpawner.ChunkGetter chunkSource, LocalMobCapCalculator densityCapper, boolean countMobs) {
2024-01-21 12:53:04 +01:00
+ // Paper end - Optional per player mob spawns
2021-06-11 14:02:28 +02:00
PotentialCalculator spawnercreatureprobabilities = new PotentialCalculator();
Object2IntOpenHashMap<MobCategory> object2intopenhashmap = new Object2IntOpenHashMap();
2021-06-14 04:41:44 +02:00
Iterator iterator = entities.iterator();
2024-10-27 11:56:51 +01:00
@@ -103,11 +109,16 @@ public final class NaturalSpawner {
2023-03-14 20:54:57 +01:00
spawnercreatureprobabilities.addCharge(entity.blockPosition(), biomesettingsmobs_b.charge());
2022-01-01 03:07:21 +01:00
}
- if (entity instanceof Mob) {
2024-01-21 12:53:04 +01:00
+ if (densityCapper != null && entity instanceof Mob) { // Paper - Optional per player mob spawns
2022-11-12 21:57:41 +01:00
densityCapper.addMob(chunk.getPos(), enumcreaturetype);
2021-06-11 14:02:28 +02:00
}
object2intopenhashmap.addTo(enumcreaturetype, 1);
2024-01-21 12:53:04 +01:00
+ // Paper start - Optional per player mob spawns
2021-06-11 14:02:28 +02:00
+ if (countMobs) {
2021-06-14 04:41:44 +02:00
+ chunk.level.getChunkSource().chunkMap.updatePlayerMobTypeMap(entity);
2021-06-11 14:02:28 +02:00
+ }
2024-01-21 12:53:04 +01:00
+ // Paper end - Optional per player mob spawns
2021-06-11 14:02:28 +02:00
});
}
}
2024-10-27 11:56:51 +01:00
@@ -142,7 +153,7 @@ public final class NaturalSpawner {
2021-06-11 14:02:28 +02:00
continue;
}
2024-10-27 11:56:51 +01:00
- 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
// CraftBukkit end
list.add(enumcreaturetype);
}
2024-10-27 18:11:15 +01:00
@@ -160,12 +171,43 @@ public final class NaturalSpawner {
2024-10-27 11:56:51 +01:00
while (iterator.hasNext()) {
MobCategory enumcreaturetype = (MobCategory) iterator.next();
- if (info.canSpawnForCategoryLocal(enumcreaturetype, chunk.getPos())) {
+ // Paper start - Optional per player mob spawns
+ final boolean canSpawn;
+ int maxSpawns = Integer.MAX_VALUE;
2022-06-09 10:51:45 +02:00
+ if (world.paperConfig().entities.spawning.perPlayerMobSpawns) {
2024-10-27 11:56:51 +01:00
+ // Copied from getFilteredSpawningCategories
+ int limit = enumcreaturetype.getMaxInstancesPerChunk();
+ SpawnCategory spawnCategory = CraftSpawnCategory.toBukkit(enumcreaturetype);
+ if (CraftSpawnCategory.isValidForLimits(spawnCategory)) {
+ limit = world.getWorld().getSpawnLimit(spawnCategory);
+ }
+
+ // Apply per-player limit
2021-06-11 14:02:28 +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 =
+ world.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-07-17 19:24:53 +02:00
+ minDiff = Math.min(limit - world.getChunkSource().chunkMap.getMobCountNear(backingSet[k], enumcreaturetype), minDiff);
2022-01-02 20:06:08 +01:00
+ }
2021-06-11 14:02:28 +02:00
+ }
2024-10-27 11:56:51 +01:00
+
+ maxSpawns = (minDiff == Integer.MAX_VALUE) ? 0 : minDiff;
+ canSpawn = maxSpawns > 0;
+ } else {
+ canSpawn = info.canSpawnForCategoryLocal(enumcreaturetype, chunk.getPos());
2021-06-11 14:02:28 +02:00
+ }
2024-10-27 11:56:51 +01:00
+ if (canSpawn) {
2024-01-21 12:53:04 +01:00
+ // Paper end - Optional per player mob spawns
2021-06-14 04:41:44 +02:00
Objects.requireNonNull(info);
NaturalSpawner.SpawnPredicate spawnercreature_c = info::canSpawn;
Objects.requireNonNull(info);
- NaturalSpawner.spawnCategoryForChunk(enumcreaturetype, world, chunk, spawnercreature_c, info::afterSpawn);
2024-01-21 12:53:04 +01:00
+ // Paper start - Optional per player mob spawns
2024-10-27 11:56:51 +01:00
+ NaturalSpawner.spawnCategoryForChunk(enumcreaturetype, world, chunk, spawnercreature_c, info::afterSpawn,
+ maxSpawns, world.paperConfig().entities.spawning.perPlayerMobSpawns ? world.getChunkSource().chunkMap::updatePlayerMobTypeMap : null);
2024-01-21 12:53:04 +01:00
+ // Paper end - Optional per player mob spawns
2021-06-11 14:02:28 +02:00
}
}
2024-10-27 18:11:15 +01:00
@@ -183,10 +225,15 @@ public final class NaturalSpawner {
2024-01-23 15:43:48 +01:00
// Paper end - Add mobcaps commands
2021-06-11 14:02:28 +02:00
public static void spawnCategoryForChunk(MobCategory group, ServerLevel world, LevelChunk chunk, NaturalSpawner.SpawnPredicate checker, NaturalSpawner.AfterSpawnCallback runner) {
2024-01-21 12:53:04 +01:00
+ // Paper start - Optional per player mob spawns
2022-02-02 21:57:11 +01:00
+ spawnCategoryForChunk(group, world, chunk, checker, runner, Integer.MAX_VALUE, null);
2021-06-11 14:02:28 +02:00
+ }
2024-10-27 11:56:51 +01:00
+ public static void spawnCategoryForChunk(MobCategory group, ServerLevel world, LevelChunk chunk, NaturalSpawner.SpawnPredicate checker, NaturalSpawner.AfterSpawnCallback runner, int maxSpawns, Consumer<Entity> trackEntity) {
2024-01-21 12:53:04 +01:00
+ // Paper end - Optional per player mob spawns
2021-06-14 04:41:44 +02:00
BlockPos blockposition = NaturalSpawner.getRandomPosWithin(world, chunk);
2021-06-11 14:02:28 +02:00
2024-10-27 11:56:51 +01:00
if (blockposition.getY() >= world.getMinY() + 1) {
2021-11-24 10:01:27 +01:00
- NaturalSpawner.spawnCategoryForPosition(group, world, chunk, blockposition, checker, runner);
2024-10-27 11:56:51 +01:00
+ NaturalSpawner.spawnCategoryForPosition(group, world, chunk, blockposition, checker, runner, maxSpawns, trackEntity); // Paper - Optional per player mob spawns
2021-06-11 14:02:28 +02:00
}
}
2024-10-27 18:11:15 +01:00
@@ -198,7 +245,12 @@ public final class NaturalSpawner {
2021-06-14 04:41:44 +02:00
});
}
2024-01-21 12:53:04 +01:00
+ // Paper start - Optional per player mob spawns
2021-06-11 14:02:28 +02:00
public static void spawnCategoryForPosition(MobCategory group, ServerLevel world, ChunkAccess chunk, BlockPos pos, NaturalSpawner.SpawnPredicate checker, NaturalSpawner.AfterSpawnCallback runner) {
2022-02-02 21:57:11 +01:00
+ spawnCategoryForPosition(group, world,chunk, pos, checker, runner, Integer.MAX_VALUE, null);
2021-06-11 14:02:28 +02:00
+ }
2024-10-27 11:56:51 +01:00
+ public static void spawnCategoryForPosition(MobCategory group, ServerLevel world, ChunkAccess chunk, BlockPos pos, NaturalSpawner.SpawnPredicate checker, NaturalSpawner.AfterSpawnCallback runner, int maxSpawns, Consumer<Entity> trackEntity) {
2024-01-21 12:53:04 +01:00
+ // Paper end - Optional per player mob spawns
2022-06-08 06:06:41 +02:00
StructureManager structuremanager = world.structureManager();
2021-06-14 04:41:44 +02:00
ChunkGenerator chunkgenerator = world.getChunkSource().getGenerator();
int i = pos.getY();
2024-10-27 18:11:15 +01:00
@@ -268,9 +320,14 @@ public final class NaturalSpawner {
2021-06-14 04:41:44 +02:00
++j;
2021-06-11 14:02:28 +02:00
++k1;
2021-06-14 04:41:44 +02:00
runner.run(entityinsentient, chunk);
2024-01-21 12:53:04 +01:00
+ // Paper start - Optional per player mob spawns
2021-06-11 14:02:28 +02:00
+ if (trackEntity != null) {
+ trackEntity.accept(entityinsentient);
+ }
2024-01-21 12:53:04 +01:00
+ // Paper end - Optional per player mob spawns
2021-06-11 14:02:28 +02:00
}
// CraftBukkit end
- if (j >= entityinsentient.getMaxSpawnClusterSize()) {
2024-01-21 12:53:04 +01:00
+ if (j >= entityinsentient.getMaxSpawnClusterSize() || j >= maxSpawns) { // Paper - Optional per player mob spawns
2024-10-27 11:56:51 +01:00
return;
2021-06-11 14:02:28 +02:00
}
2024-10-27 18:11:15 +01:00
@@ -543,7 +600,7 @@ public final class NaturalSpawner {
2022-01-01 03:07:21 +01:00
MobCategory enumcreaturetype = entitytypes.getCategory();
this.mobCategoryCounts.addTo(enumcreaturetype, 1);
- this.localMobCapCalculator.addMob(new ChunkPos(blockposition), enumcreaturetype);
2024-01-21 12:53:04 +01:00
+ if (this.localMobCapCalculator != null) this.localMobCapCalculator.addMob(new ChunkPos(blockposition), enumcreaturetype); // Paper - Optional per player mob spawns
2022-01-01 03:07:21 +01:00
}
public int getSpawnableChunkCount() {