diff options
Diffstat (limited to 'paper-server/patches/features/0034-Optional-per-player-mob-spawns.patch')
-rw-r--r-- | paper-server/patches/features/0034-Optional-per-player-mob-spawns.patch | 236 |
1 files changed, 236 insertions, 0 deletions
diff --git a/paper-server/patches/features/0034-Optional-per-player-mob-spawns.patch b/paper-server/patches/features/0034-Optional-per-player-mob-spawns.patch new file mode 100644 index 0000000000..6ee8bdf5ed --- /dev/null +++ b/paper-server/patches/features/0034-Optional-per-player-mob-spawns.patch @@ -0,0 +1,236 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: kickash32 <[email protected]> +Date: Mon, 19 Aug 2019 01:27:58 +0500 +Subject: [PATCH] Optional per player mob spawns + + +diff --git a/net/minecraft/server/level/ChunkMap.java b/net/minecraft/server/level/ChunkMap.java +index ff6503bf8eb88d1264c3d848a89d0255b4b3ae68..9eed24939fc09f00a9dbce1be2ab9c34d024fd29 100644 +--- a/net/minecraft/server/level/ChunkMap.java ++++ b/net/minecraft/server/level/ChunkMap.java +@@ -236,11 +236,29 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider + // Paper - rewrite chunk system + } + +- // 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 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]); ++ } + } +- // 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 + + protected ChunkGenerator generator() { + return this.worldGenContext.generator(); +diff --git a/net/minecraft/server/level/ServerChunkCache.java b/net/minecraft/server/level/ServerChunkCache.java +index 87d4291a3944f706a694536da6de0f28c548ab8d..5576bf1d1d70ab7a010653d3207909b5de867e70 100644 +--- a/net/minecraft/server/level/ServerChunkCache.java ++++ b/net/minecraft/server/level/ServerChunkCache.java +@@ -517,7 +517,7 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon + profilerFiller.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(profilerFiller, l, list); + profilerFiller.pop(); +@@ -571,9 +571,18 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon + private void tickChunks(ProfilerFiller profiler, long timeInhabited, List<LevelChunk> chunks) { + profiler.popPush("naturalSpawnCount"); + 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 ++ 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); ++ } ++ spawnState = NaturalSpawner.createState(naturalSpawnChunkCount, this.level.getAllEntities(), this::getFullChunk, null, true); ++ } else { ++ 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 = spawnState; + profiler.popPush("spawnAndTick"); + 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 a97b0b177a1fb0557af2af4d1f192513d7c0390d..4f8ef57d66a4562df0f5447988797cbdfbd3c9d5 100644 +--- a/net/minecraft/server/level/ServerPlayer.java ++++ b/net/minecraft/server/level/ServerPlayer.java +@@ -368,6 +368,10 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc + 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 end - Optional per player mob spawns + // CraftBukkit start + 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 913ea92ace9d610c25bf28f703a3b227044aea63..ef8bacbbb43a9b80281a313ca43b7efff5a93e03 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(spawnableChunkCount, entities, chunkGetter, calculator, false); ++ } ++ ++ 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 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 + }); + } + } +@@ -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 + } +@@ -149,8 +162,37 @@ public final class NaturalSpawner { + profilerFiller.push("spawner"); + + 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 (level.paperConfig().entities.spawning.perPlayerMobSpawns) { ++ // Copied from getFilteredSpawningCategories ++ int limit = mobCategory.getMaxInstancesPerChunk(); ++ SpawnCategory spawnCategory = CraftSpawnCategory.toBukkit(mobCategory); ++ if (CraftSpawnCategory.isValidForLimits(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 = ++ 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 - level.getChunkSource().chunkMap.getMobCountNear(backingSet[k], mobCategory), minDiff); ++ } ++ } ++ ++ maxSpawns = (minDiff == Integer.MAX_VALUE) ? 0 : minDiff; ++ canSpawn = maxSpawns > 0; ++ } else { ++ canSpawn = spawnState.canSpawnForCategoryLocal(mobCategory, chunk.getPos()); ++ } ++ if (canSpawn) { ++ 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 + } + } + +@@ -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(category, level, chunk, filter, callback, Integer.MAX_VALUE, null); ++ } ++ 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 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 + } + } + +@@ -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 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() { |