From 01d5f91c38f2f0136371f0a6bfc024c70c594809 Mon Sep 17 00:00:00 2001 From: kickash32 Date: Tue, 11 Jun 2019 22:22:16 -0400 Subject: [PATCH] implement optional per player mob spawns --- .../destroystokyo/paper/PaperWorldConfig.java | 5 +++ .../minecraft/server/ChunkProviderServer.java | 16 +++++++-- .../net/minecraft/server/EntityTypes.java | 1 + .../net/minecraft/server/PlayerChunkMap.java | 5 +-- .../net/minecraft/server/SpawnerCreature.java | 21 ++++++----- .../net/minecraft/server/WorldServer.java | 36 +++++++++++++++++++ 6 files changed, 69 insertions(+), 15 deletions(-) diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java index 318a470eea..72b77e27e8 100644 --- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java +++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java @@ -509,6 +509,11 @@ public class PaperWorldConfig { maxAutoSaveChunksPerTick = getInt("max-auto-save-chunks-per-tick", 24); } + public boolean perPlayerMobSpawns = false; + private void perPlayerMobSpawns() { + perPlayerMobSpawns = getBoolean("per-player-mob-spawns", false); + } + public boolean countAllMobsForSpawning = false; private void countAllMobsForSpawning() { countAllMobsForSpawning = getBoolean("count-all-mobs-for-spawning", false); diff --git a/src/main/java/net/minecraft/server/ChunkProviderServer.java b/src/main/java/net/minecraft/server/ChunkProviderServer.java index ed0ff8573b..b3936caf45 100644 --- a/src/main/java/net/minecraft/server/ChunkProviderServer.java +++ b/src/main/java/net/minecraft/server/ChunkProviderServer.java @@ -592,9 +592,21 @@ public class ChunkProviderServer extends IChunkProvider { // Paper start - only allow spawns upto the limit per chunk and update count afterwards int currEntityCount = object2intmap.getInt(enumcreaturetype); int difference = k1 - currEntityCount; + if(this.world.paperConfig.perPlayerMobSpawns){ + final int[] min = {Integer.MAX_VALUE}; + final int finalLimit = limit; + playerChunkMap.getPlayersNear(chunk.getPos()) + .forEach((entityplayer) -> min[0] = Math.min( + finalLimit - ((WorldServer)chunk.getWorld()).getMobCountNear(entityplayer, enumcreaturetype), + min[0])); + difference = (min[0] == Integer.MAX_VALUE) ? 0 : min[0]; + } + if (difference > 0) { - object2intmap.put(enumcreaturetype, currEntityCount + SpawnerCreature.spawnMobs(enumcreaturetype, world, chunk, blockposition, difference)); - // Paper end + List spawned = SpawnerCreature.spawnMobs(enumcreaturetype, this.world, chunk, blockposition, difference); + object2intmap.put(enumcreaturetype, currEntityCount + spawned.size()); + this.world.updatePlayerMobTypeMap(spawned); + // Paper end } } } diff --git a/src/main/java/net/minecraft/server/EntityTypes.java b/src/main/java/net/minecraft/server/EntityTypes.java index d92fbea4c7..f9bc2ab66e 100644 --- a/src/main/java/net/minecraft/server/EntityTypes.java +++ b/src/main/java/net/minecraft/server/EntityTypes.java @@ -267,6 +267,7 @@ public class EntityTypes { return this.be; } + public EnumCreatureType getEnumCreatureType(){ return this.e(); } // Paper - OBFHELPER public EnumCreatureType e() { return this.ba; } diff --git a/src/main/java/net/minecraft/server/PlayerChunkMap.java b/src/main/java/net/minecraft/server/PlayerChunkMap.java index 7d2808aa29..c2c4224385 100644 --- a/src/main/java/net/minecraft/server/PlayerChunkMap.java +++ b/src/main/java/net/minecraft/server/PlayerChunkMap.java @@ -137,6 +137,7 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d { this.setViewDistance(i); } + private static double squareDist(ChunkCoordIntPair chunkcoord, Entity entity) { return a(chunkcoord, entity); } // Paper - OBFHELPER private static double a(ChunkCoordIntPair chunkcoordintpair, Entity entity) { double d0 = (double) (chunkcoordintpair.x * 16 + 8); double d1 = (double) (chunkcoordintpair.z * 16 + 8); @@ -1327,8 +1328,8 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d { } - @Override - public Stream a(ChunkCoordIntPair chunkcoordintpair, boolean flag) { + public Stream getPlayersNear(ChunkCoordIntPair coordIntPair) { return a(coordIntPair, false); } // Paper - OBFHELPER + @Override public Stream a(ChunkCoordIntPair chunkcoordintpair, boolean flag) { return this.playerMap.a(chunkcoordintpair.pair()).filter((entityplayer) -> { int i = b(chunkcoordintpair, entityplayer, true); diff --git a/src/main/java/net/minecraft/server/SpawnerCreature.java b/src/main/java/net/minecraft/server/SpawnerCreature.java index 925efd4a15..70580355c6 100644 --- a/src/main/java/net/minecraft/server/SpawnerCreature.java +++ b/src/main/java/net/minecraft/server/SpawnerCreature.java @@ -20,16 +20,15 @@ public final class SpawnerCreature { public static void a(EnumCreatureType enumcreaturetype, World world, Chunk chunk, BlockPosition blockposition) { spawnMobs(enumcreaturetype, world, chunk, blockposition, Integer.MAX_VALUE); } - - public static int spawnMobs(EnumCreatureType enumcreaturetype, World world, Chunk chunk, BlockPosition blockposition, int maxSpawns) { - // Paper end + public static List spawnMobs(EnumCreatureType enumcreaturetype, World world, Chunk chunk, BlockPosition blockposition, int maxSpawns) { + List mobsSpawned = new java.util.ArrayList<>(); + // Paper end ChunkGenerator chunkgenerator = world.getChunkProvider().getChunkGenerator(); int i = 0; BlockPosition blockposition1 = getRandomPosition(world, chunk); int j = blockposition1.getX(); int k = blockposition1.getY(); int l = blockposition1.getZ(); - int amountSpawned = 0; // Paper - keep track of mobs spawned if (k >= 1) { IBlockData iblockdata = world.getTypeIfLoadedAndInBounds(blockposition1); // Paper - don't load chunks for mob spawn @@ -104,7 +103,7 @@ public final class SpawnerCreature { ); if (!event.callEvent()) { if (event.shouldAbortSpawn()) { - return amountSpawned; // Paper + return mobsSpawned; // Paper } ++i2; continue; @@ -123,7 +122,7 @@ public final class SpawnerCreature { } catch (Exception exception) { SpawnerCreature.LOGGER.warn("Failed to create mob", exception); ServerInternalException.reportInternalException(exception); // Paper - return amountSpawned; // Paper + return mobsSpawned; // Paper } entityinsentient.setPositionRotation((double) f, (double) k, (double) f1, world.random.nextFloat() * 360.0F, 0.0F); @@ -134,15 +133,15 @@ public final class SpawnerCreature { ++i; ++i2; // Paper start - stop when limit is reached - ++amountSpawned; + mobsSpawned.add(entityinsentient); } - if (amountSpawned >= maxSpawns) { - return amountSpawned; + if (mobsSpawned.size() >= maxSpawns) { + return mobsSpawned; } // Paper end // CraftBukkit end if (i >= entityinsentient.dC()) { - return amountSpawned; // Paper + return mobsSpawned; // Paper } if (entityinsentient.c(i2)) { @@ -168,7 +167,7 @@ public final class SpawnerCreature { } } - return amountSpawned; // Paper + return mobsSpawned; // Paper } @Nullable diff --git a/src/main/java/net/minecraft/server/WorldServer.java b/src/main/java/net/minecraft/server/WorldServer.java index c039d4f884..1331baf584 100644 --- a/src/main/java/net/minecraft/server/WorldServer.java +++ b/src/main/java/net/minecraft/server/WorldServer.java @@ -70,6 +70,7 @@ public class WorldServer extends World { private boolean ticking; @Nullable private final MobSpawnerTrader mobSpawnerTrader; + private Map> playerMobTypeMap; // Paper // CraftBukkit start private int tickPosition; @@ -937,6 +938,7 @@ public class WorldServer extends World { } public Object2IntMap l() { + List filteredEntities = new java.util.ArrayList<>(); // Paper Object2IntMap object2intmap = new Object2IntOpenHashMap(); ObjectIterator objectiterator = this.entitiesById.values().iterator(); @@ -961,14 +963,48 @@ public class WorldServer extends World { entity.spawnReason == CreatureSpawnEvent.SpawnReason.CHUNK_GEN)) { continue; } + filteredEntities.add(entity); // Paper // Paper end object2intmap.mergeInt(enumcreaturetype, 1, Integer::sum); } } + // Paper start + if(this.paperConfig.perPlayerMobSpawns) { + this.playerMobTypeMap = new java.util.HashMap<>(this.players.size()); + updatePlayerMobTypeMap(filteredEntities); + } + // Paper end return object2intmap; } + // Paper start + public void updatePlayerMobTypeMap(List entities) { + if (this.playerMobTypeMap == null) { return; } + for (Entity entity : entities) { + ((ChunkProviderServer) this.chunkProvider).playerChunkMap.getPlayersNear(entity.getChunkAtLocation().getPos()).forEach( (player) -> { + if (!this.playerMobTypeMap.containsKey(player.uniqueID)) { this.playerMobTypeMap.put(player.uniqueID, new java.util.EnumMap<>(EnumCreatureType.class)); } + Map tmpMap = this.playerMobTypeMap.get(player.uniqueID); + EnumCreatureType enumType = entity.getEntityType().getEnumCreatureType(); + tmpMap.put( + enumType, + tmpMap.getOrDefault(enumType, 0) + 1); + }); + } + } + + public int getMobCountNear(EntityPlayer entityPlayer, EnumCreatureType enumCreatureType) { + int count = 0; + if (this.playerMobTypeMap != null) { + Map map = this.playerMobTypeMap.get(entityPlayer.uniqueID); + if (map != null) { + count = map.getOrDefault(enumCreatureType, 0); + } + } + return count; + } + // Paper end + @Override public boolean addEntity(Entity entity) { // CraftBukkit start -- 2.20.1