From 7b879f573461472f310216d5c2e133462d71506f 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/PlayerChunkMap.java | 10 ++++++ .../java/net/minecraft/server/PlayerMap.java | 1 + .../net/minecraft/server/SpawnerCreature.java | 21 ++++++----- .../net/minecraft/server/WorldServer.java | 36 +++++++++++++++++++ 6 files changed, 76 insertions(+), 13 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..882e1d007c 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(), this.world.spigotConfig.mobSpawnRange) + .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/PlayerChunkMap.java b/src/main/java/net/minecraft/server/PlayerChunkMap.java index 7d2808aa29..45594250de 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,6 +1328,15 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d { } + // Paper start + public Stream getPlayersNear(ChunkCoordIntPair coordIntPair, int rangeChunks) { + int squareRangeBlocks = ((rangeChunks << 4) * (rangeChunks << 4)); + + return this.playerMap.getPlayers(coordIntPair.pair()).filter( (entityplayer) -> + (!entityplayer.isSpectator() && squareDist(coordIntPair, entityplayer) < squareRangeBlocks)); + } + // Paper end + @Override public Stream a(ChunkCoordIntPair chunkcoordintpair, boolean flag) { return this.playerMap.a(chunkcoordintpair.pair()).filter((entityplayer) -> { diff --git a/src/main/java/net/minecraft/server/PlayerMap.java b/src/main/java/net/minecraft/server/PlayerMap.java index f386c4e997..c896a0b85f 100644 --- a/src/main/java/net/minecraft/server/PlayerMap.java +++ b/src/main/java/net/minecraft/server/PlayerMap.java @@ -10,6 +10,7 @@ public final class PlayerMap { public PlayerMap() {} + public Stream getPlayers(long chunkCoord) { return this.a(chunkCoord); } // Paper - OBFHELPER public Stream a(long i) { return this.a.keySet().stream(); } 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 dc710b2fbd..c28df6137b 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(); @@ -955,6 +957,7 @@ public class WorldServer extends World { EnumCreatureType enumcreaturetype = entity.getEntityType().e(); if (enumcreaturetype != EnumCreatureType.MISC && this.getChunkProvider().b(entity)) { + filteredEntities.add(entity); // Paper // Paper start - Only count natural spawns if (!this.paperConfig.countAllMobsForSpawning && !(entity.spawnReason == CreatureSpawnEvent.SpawnReason.NATURAL || @@ -966,9 +969,42 @@ public class WorldServer extends World { } } + // Paper start + if(this.paperConfig.perPlayerMobSpawns) { + this.playerMobTypeMap = new java.util.HashMap<>(); + 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(), this.spigotConfig.mobSpawnRange).forEach( (player) -> { + if (!this.playerMobTypeMap.containsKey(player.uniqueID)) { this.playerMobTypeMap.put(player.uniqueID, new Object2IntOpenHashMap()); } + Map tmpMap = this.playerMobTypeMap.get(player.uniqueID); + EnumCreatureType enumType = entity.getEntityType().e(); + 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