13
0
geforkt von Mirrors/Paper
Paper/patches/server/0999-Optional-per-player-mob-spawns.patch

254 Zeilen
16 KiB
Diff

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
Subject: [PATCH] Optional per player mob spawns
2021-06-14 04:41:44 +02:00
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
index d843bc04ae93d11d7820cab5ed18617193568f0d..152cd6b1671785b495caeb7e535f58df864ce24c 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
@@ -256,8 +256,26 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
2024-06-15 14:12:22 +02:00
return this.nearbyPlayers;
}
Rewrite chunk system (#8177) Patch documentation to come Issues with the old system that are fixed now: - World generation does not scale with cpu cores effectively. - Relies on the main thread for scheduling and maintaining chunk state, dropping chunk load/generate rates at lower tps. - Unreliable prioritisation of chunk gen/load calls that block the main thread. - Shutdown logic is utterly unreliable, as it has to wait for all chunks to unload - is it guaranteed that the chunk system is in a state on shutdown that it can reliably do this? Watchdog shutdown also typically failed due to thread checks, which is now resolved. - Saving of data is not unified (i.e can save chunk data without saving entity data, poses problems for desync if shutdown is really abnormal. - Entities are not loaded with chunks. This caused quite a bit of headache for Chunk#getEntities API, but now the new chunk system loads entities with chunks so that they are ready whenever the chunk loads in. Effectively brings the behavior back to 1.16 era, but still storing entities in their own separate regionfiles. The above list is not complete. The patch documentation will complete it. New chunk system hard relies on starlight and dataconverter, and most importantly the new concurrent utilities in ConcurrentUtil. Some of the old async chunk i/o interface (i.e the old file io thread reroutes _some_ calls to the new file io thread) is kept for plugin compat reasons. It will be removed in the next major version of minecraft. The old legacy chunk system patches have been moved to the removed folder in case we need them again.
2022-09-26 10:02:51 +02:00
+ // Paper start - Optional per player mob spawns
+ public void updatePlayerMobTypeMap(final Entity entity) {
+ 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
+
+ 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.getRawData();
+ for (int i = 0, len = inRange.size(); i < len; i++) {
+ ++((ServerPlayer)backingSet[i]).mobCounts[index];
2021-06-11 14:02:28 +02: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-06-15 14:12:22 +02:00
// Paper end
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
index d2cb358c340bcf7532fd25eccdd33c6945d16de4..2211c054f55e962082eac82aedf5ca625e5b25f2 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
@@ -439,7 +439,19 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon
2023-12-05 23:32:41 +01:00
gameprofilerfiller.popPush("naturalSpawnCount");
this.level.timings.countNaturalMobs.startTiming(); // Paper - timings
int k = this.distanceManager.getNaturalSpawnChunkCount();
- NaturalSpawner.SpawnState spawnercreature_d = NaturalSpawner.createState(k, this.level.getAllEntities(), this::getFullChunk, new LocalMobCapCalculator(this.chunkMap));
+ // Paper start - Optional per player mob spawns
2023-12-05 23:32:41 +01:00
+ int naturalSpawnChunkCount = k;
+ 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);
2021-06-11 14:02:28 +02:00
+ }
+ // Paper end - Optional per player mob spawns
2023-12-05 23:32:41 +01:00
this.level.timings.countNaturalMobs.stopTiming(); // Paper - timings
2021-06-11 14:02:28 +02:00
2023-12-05 23:32:41 +01:00
this.lastSpawnState = spawnercreature_d;
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
index ba64e42a58b4b760815f54228ebf7a46fd14734e..6277ec3353c6e552b898b525ce2af76a0c84943d 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-06-15 15:22:06 +02:00
@@ -275,6 +275,10 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player imple
public boolean queueHealthUpdatePacket;
2021-06-11 14:02:28 +02:00
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
+ // 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-04-25 11:42:10 +02:00
index ea6533c1ac218aa075da3401807a06fcb7892321..0679636530ca1afd077c43b0fa605a2ac74e0522 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-04-25 11:42:10 +02:00
@@ -67,6 +67,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) {
+ // 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
+ }
+
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) {
+ // 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-04-25 11:42:10 +02:00
@@ -99,11 +105,16 @@ public final class NaturalSpawner {
2023-03-14 20:54:57 +01:00
spawnercreatureprobabilities.addCharge(entity.blockPosition(), biomesettingsmobs_b.charge());
}
- if (entity instanceof Mob) {
+ 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);
+ // 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
+ }
+ // Paper end - Optional per player mob spawns
2021-06-11 14:02:28 +02:00
});
}
}
2024-04-25 11:42:10 +02:00
@@ -138,13 +149,35 @@ public final class NaturalSpawner {
2021-06-11 14:02:28 +02:00
continue;
}
- if ((spawnAnimals || !enumcreaturetype.isFriendly()) && (spawnMonsters || enumcreaturetype.isFriendly()) && (rareSpawn || !enumcreaturetype.isPersistent()) && info.canSpawnForCategory(enumcreaturetype, chunk.getPos(), limit)) {
+ // Paper start - Optional per player mob spawns; only allow spawns upto the limit per chunk and update count afterwards
2021-06-14 06:29:25 +02:00
+ int currEntityCount = info.mobCategoryCounts.getInt(enumcreaturetype);
2021-06-14 04:41:44 +02:00
+ int k1 = limit * info.getSpawnableChunkCount() / NaturalSpawner.MAGIC_NUMBER;
2021-06-11 14:02:28 +02:00
+ int difference = k1 - currEntityCount;
+
+ if (world.paperConfig().entities.spawning.perPlayerMobSpawns) {
2021-06-11 14:02:28 +02:00
+ int minDiff = Integer.MAX_VALUE;
+ 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.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);
+ }
2021-06-11 14:02:28 +02:00
+ }
+ difference = (minDiff == Integer.MAX_VALUE) ? 0 : minDiff;
+ }
+ if ((spawnAnimals || !enumcreaturetype.isFriendly()) && (spawnMonsters || enumcreaturetype.isFriendly()) && (rareSpawn || !enumcreaturetype.isPersistent()) && difference > 0) {
+ // Paper end - Optional per player mob spawns
2021-06-11 14:02:28 +02:00
// CraftBukkit end
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);
+ // Paper start - Optional per player mob spawns
2021-06-14 04:41:44 +02:00
+ int spawnCount = NaturalSpawner.spawnCategoryForChunk(enumcreaturetype, world, chunk, spawnercreature_c, info::afterSpawn,
+ difference, world.paperConfig().entities.spawning.perPlayerMobSpawns ? world.getChunkSource().chunkMap::updatePlayerMobTypeMap : null);
2021-06-14 06:29:25 +02:00
+ info.mobCategoryCounts.mergeInt(enumcreaturetype, spawnCount, Integer::sum);
+ // Paper end - Optional per player mob spawns
2021-06-11 14:02:28 +02:00
}
}
2024-04-25 11:42:10 +02:00
@@ -163,11 +196,17 @@ public final class NaturalSpawner {
// 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) {
+ // Paper start - Optional per player mob spawns
+ spawnCategoryForChunk(group, world, chunk, checker, runner, Integer.MAX_VALUE, null);
2021-06-11 14:02:28 +02:00
+ }
2021-06-14 04:41:44 +02:00
+ public static int spawnCategoryForChunk(MobCategory group, ServerLevel world, LevelChunk chunk, NaturalSpawner.SpawnPredicate checker, NaturalSpawner.AfterSpawnCallback runner, int maxSpawns, Consumer<Entity> trackEntity) {
+ // 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
2021-06-14 04:41:44 +02:00
if (blockposition.getY() >= world.getMinBuildHeight() + 1) {
- NaturalSpawner.spawnCategoryForPosition(group, world, chunk, blockposition, checker, runner);
+ return NaturalSpawner.spawnCategoryForPosition(group, world, chunk, blockposition, checker, runner, maxSpawns, trackEntity); // Paper - Optional per player mob spawns
2021-06-11 14:02:28 +02:00
}
+ return 0; // Paper - Optional per player mob spawns
2021-06-11 14:02:28 +02:00
}
2021-06-14 04:41:44 +02:00
@VisibleForDebug
2024-04-25 11:42:10 +02:00
@@ -178,15 +217,21 @@ public final class NaturalSpawner {
2021-06-14 04:41:44 +02: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) {
+ spawnCategoryForPosition(group, world,chunk, pos, checker, runner, Integer.MAX_VALUE, null);
2021-06-11 14:02:28 +02:00
+ }
2021-06-14 04:41:44 +02:00
+ public static int 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
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();
BlockState iblockdata = world.getBlockStateIfLoadedAndInBounds(pos); // Paper - don't load chunks for mob spawn
+ int j = 0; // Paper - Optional per player mob spawns; moved up
2021-06-14 04:41:44 +02:00
if (iblockdata != null && !iblockdata.isRedstoneConductor(chunk, pos)) { // Paper - don't load chunks for mob spawn
2021-06-11 14:02:28 +02:00
BlockPos.MutableBlockPos blockposition_mutableblockposition = new BlockPos.MutableBlockPos();
- int j = 0;
+ //int j = 0; // Paper - Optional per player mob spawns; moved up
2021-06-11 14:02:28 +02:00
int k = 0;
while (k < 3) {
2024-04-25 11:42:10 +02:00
@@ -228,14 +273,14 @@ public final class NaturalSpawner {
// Paper start - PreCreatureSpawnEvent
PreSpawnStatus doSpawning = isValidSpawnPostitionForType(world, group, structuremanager, chunkgenerator, biomesettingsmobs_c, blockposition_mutableblockposition, d2);
if (doSpawning == PreSpawnStatus.ABORT) {
2021-06-14 08:45:29 +02:00
- return;
+ return j; // Paper - Optional per player mob spawns
2021-06-14 08:45:29 +02:00
}
if (doSpawning == PreSpawnStatus.SUCCESS && checker.test(biomesettingsmobs_c.type, blockposition_mutableblockposition, chunk)) {
// Paper end - PreCreatureSpawnEvent
2021-06-14 04:41:44 +02:00
Mob entityinsentient = NaturalSpawner.getMobForSpawn(world, biomesettingsmobs_c.type);
2021-06-11 14:02:28 +02:00
if (entityinsentient == null) {
- return;
+ return j; // Paper - Optional per player mob spawns
2021-06-11 14:02:28 +02:00
}
2021-06-14 04:41:44 +02:00
entityinsentient.moveTo(d0, (double) i, d1, world.random.nextFloat() * 360.0F, 0.0F);
2024-04-25 11:42:10 +02:00
@@ -248,10 +293,15 @@ 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);
+ // Paper start - Optional per player mob spawns
2021-06-11 14:02:28 +02:00
+ if (trackEntity != null) {
+ trackEntity.accept(entityinsentient);
+ }
+ // Paper end - Optional per player mob spawns
2021-06-11 14:02:28 +02:00
}
// CraftBukkit end
- if (j >= entityinsentient.getMaxSpawnClusterSize()) {
- return;
+ if (j >= entityinsentient.getMaxSpawnClusterSize() || j >= maxSpawns) { // Paper - Optional per player mob spawns
+ return j; // Paper - Optional per player mob spawns
2021-06-11 14:02:28 +02:00
}
if (entityinsentient.isMaxGroupSizeReached(k1)) {
2024-04-25 11:42:10 +02:00
@@ -273,6 +323,7 @@ public final class NaturalSpawner {
2021-06-11 14:02:28 +02:00
}
}
+ return j; // Paper - Optional per player mob spawns
2021-06-11 14:02:28 +02:00
}
private static boolean isRightDistanceToPlayerAndSpawnPoint(ServerLevel world, ChunkAccess chunk, BlockPos.MutableBlockPos pos, double squaredDistance) {
2024-04-25 11:42:10 +02:00
@@ -523,7 +574,7 @@ 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 int getSpawnableChunkCount() {
2024-04-25 11:42:10 +02:00
@@ -539,6 +590,7 @@ public final class NaturalSpawner {
int i = limit * this.spawnableChunkCount / NaturalSpawner.MAGIC_NUMBER;
// CraftBukkit end
+ if (this.localMobCapCalculator == null) return this.mobCategoryCounts.getInt(enumcreaturetype) < i; // Paper - Optional per player mob spawns
return this.mobCategoryCounts.getInt(enumcreaturetype) >= i ? false : this.localMobCapCalculator.canSpawn(enumcreaturetype, chunkcoordintpair);
}
}