From a588cde615cc358ee14a68296bd46ff6d278deed 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 | 17 +++++++++-- .../net/minecraft/server/EntityPlayer.java | 1 + .../net/minecraft/server/EntityTypes.java | 1 + .../net/minecraft/server/PlayerChunkMap.java | 14 +++++++-- .../java/net/minecraft/server/PlayerMap.java | 1 + .../net/minecraft/server/SpawnerCreature.java | 29 ++++++++----------- .../net/minecraft/server/WorldServer.java | 26 +++++++++++++++++ 8 files changed, 73 insertions(+), 21 deletions(-) diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java index e7bbeef74..ac9883a4b 100644 --- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java +++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java @@ -514,6 +514,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 46d38b924..4acc3c4c3 100644 --- a/src/main/java/net/minecraft/server/ChunkProviderServer.java +++ b/src/main/java/net/minecraft/server/ChunkProviderServer.java @@ -609,9 +609,22 @@ 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) { + int minDiff = Integer.MAX_VALUE; + for(EntityPlayer entityplayer : playerChunkMap.getPlayersNear(chunk.getPos())) { + if (entityplayer.isSpectator() || !entityplayer.affectsSpawning) { continue; } + minDiff = Math.min(limit - this.world.getMobCountNear(entityplayer, enumcreaturetype), minDiff); + } + difference = (minDiff == Integer.MAX_VALUE) ? 0 : minDiff; + } + if (difference > 0) { - object2intmap.put(enumcreaturetype, currEntityCount + SpawnerCreature.spawnMobs(enumcreaturetype, world, chunk, blockposition, difference)); - // Paper end + SpawnerCreature.spawnMobs(enumcreaturetype, this.world, chunk, blockposition, difference, entity -> { + this.world.updatePlayerMobCounts(entity); + object2intmap.put(enumcreaturetype, currEntityCount + 1); + }); + // Paper end } } } diff --git a/src/main/java/net/minecraft/server/EntityPlayer.java b/src/main/java/net/minecraft/server/EntityPlayer.java index d375069f3..622899d8f 100644 --- a/src/main/java/net/minecraft/server/EntityPlayer.java +++ b/src/main/java/net/minecraft/server/EntityPlayer.java @@ -80,6 +80,7 @@ public class EntityPlayer extends EntityHuman implements ICrafting { public boolean queueHealthUpdatePacket = false; public net.minecraft.server.PacketPlayOutUpdateHealth queuedHealthUpdatePacket; // Paper end + public int[] mobCounts = new int[EnumCreatureType.values().length]; // Paper // CraftBukkit start public String displayName; diff --git a/src/main/java/net/minecraft/server/EntityTypes.java b/src/main/java/net/minecraft/server/EntityTypes.java index 84aa1db72..7405d78c2 100644 --- a/src/main/java/net/minecraft/server/EntityTypes.java +++ b/src/main/java/net/minecraft/server/EntityTypes.java @@ -260,6 +260,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 4c774e31d..e069c2f32 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); @@ -146,6 +147,7 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d { return d2 * d2 + d3 * d3; } + private static int distanceBetween(ChunkCoordIntPair chunkcoordintpair, EntityPlayer entityplayer) { return b(chunkcoordintpair, entityplayer, true); } // Paper - OBFHELPER private static int b(ChunkCoordIntPair chunkcoordintpair, EntityPlayer entityplayer, boolean flag) { int i; int j; @@ -1340,8 +1342,16 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d { } - @Override - public Stream a(ChunkCoordIntPair chunkcoordintpair, boolean flag) { + // Paper start + public List getPlayersNear(ChunkCoordIntPair chunkcoordintpair) { + List players = this.playerMap.getPlayers(); + players.removeIf( + entityplayer -> distanceBetween(chunkcoordintpair, entityplayer) > this.viewDistance); + return players; + } + // Paper end + + @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/PlayerMap.java b/src/main/java/net/minecraft/server/PlayerMap.java index f386c4e99..f8f35b0e0 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 java.util.List getPlayers() { return new java.util.ArrayList<>(this.a.keySet()); } // Paper - Based on method below without streams 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 62fc61df2..b2a1999bb 100644 --- a/src/main/java/net/minecraft/server/SpawnerCreature.java +++ b/src/main/java/net/minecraft/server/SpawnerCreature.java @@ -18,18 +18,16 @@ public final class SpawnerCreature { // Paper start - add maxSpawns parameter and update counts public static void a(EnumCreatureType enumcreaturetype, World world, Chunk chunk, BlockPosition blockposition) { - spawnMobs(enumcreaturetype, world, chunk, blockposition, Integer.MAX_VALUE); + spawnMobs(enumcreaturetype, world, chunk, blockposition, Integer.MAX_VALUE, entity -> {}); } - - public static int spawnMobs(EnumCreatureType enumcreaturetype, World world, Chunk chunk, BlockPosition blockposition, int maxSpawns) { - // Paper end + public static void spawnMobs(EnumCreatureType enumcreaturetype, World world, Chunk chunk, BlockPosition blockposition, int maxSpawns, java.util.function.Consumer trackEntity) { + // Paper end ChunkGenerator chunkgenerator = world.getChunkProvider().getChunkGenerator(); - int i = 0; + int i = 0; // Paper - force diff on name change 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 @@ -81,11 +79,11 @@ public final class SpawnerCreature { // Purpur start if (entitytypes == EntityTypes.GIANT) { if (!net.pl3x.purpur.PurpurConfig.giantsNaturallySpawn) { - return amountSpawned; + return; } } else if (entitytypes == EntityTypes.ILLUSIONER) { if (!net.pl3x.purpur.PurpurConfig.illusionersNaturallySpawn) { - return amountSpawned; + return; } } // Purpur end @@ -107,7 +105,7 @@ public final class SpawnerCreature { ); if (!event.callEvent()) { if (event.shouldAbortSpawn()) { - return amountSpawned; // Paper + return; } ++i2; continue; @@ -126,7 +124,7 @@ public final class SpawnerCreature { } catch (Exception exception) { SpawnerCreature.LOGGER.warn("Failed to create mob", exception); ServerInternalException.reportInternalException(exception); // Paper - return amountSpawned; // Paper + return; } entityinsentient.setPositionRotation((double) f, (double) k, (double) f1, world.random.nextFloat() * 360.0F, 0.0F); @@ -134,18 +132,16 @@ public final class SpawnerCreature { groupdataentity = entityinsentient.prepare(world, world.getDamageScaler(new BlockPosition(entityinsentient)), EnumMobSpawn.NATURAL, groupdataentity, (NBTTagCompound) null); // CraftBukkit start if (world.addEntity(entityinsentient, SpawnReason.NATURAL)) { - ++i; + ++i; // Paper - force diff on name change ++i2; // Paper start - stop when limit is reached - ++amountSpawned; - } - if (amountSpawned >= maxSpawns) { - return amountSpawned; + trackEntity.accept(entityinsentient); } + if (i >= maxSpawns) { return; } // Paper end // CraftBukkit end if (i >= entityinsentient.dC()) { - return amountSpawned; // Paper + return; } if (entityinsentient.c(i2)) { @@ -171,7 +167,6 @@ public final class SpawnerCreature { } } - return amountSpawned; // Paper } @Nullable diff --git a/src/main/java/net/minecraft/server/WorldServer.java b/src/main/java/net/minecraft/server/WorldServer.java index 0e23eeb1f..0bbd28ed8 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; @@ -966,6 +967,16 @@ public class WorldServer extends World { } public Object2IntMap l() { + // Paper start + if (this.paperConfig.perPlayerMobSpawns) { + int maxI = EnumCreatureType.values().length; + for(EntityPlayer player : this.players){ + for(int i = 0; i < maxI; i++) { + player.mobCounts[i] = 0; + } + } + } + // Paper end Object2IntMap object2intmap = new Object2IntOpenHashMap(); ObjectIterator objectiterator = this.entitiesById.values().iterator(); @@ -990,6 +1001,7 @@ public class WorldServer extends World { entity.spawnReason == CreatureSpawnEvent.SpawnReason.CHUNK_GEN)) { continue; } + updatePlayerMobCounts(entity); // Paper end object2intmap.mergeInt(enumcreaturetype, 1, Integer::sum); } @@ -998,6 +1010,20 @@ public class WorldServer extends World { return object2intmap; } + // Paper start + public void updatePlayerMobCounts(Entity entity) { + if (!this.paperConfig.perPlayerMobSpawns) { return; } + for (EntityPlayer player : ((ChunkProviderServer) this.chunkProvider).playerChunkMap.getPlayersNear(entity.getChunkAtLocation().getPos())) { + EnumCreatureType enumType = entity.getEntityType().getEnumCreatureType(); + player.mobCounts[enumType.ordinal()]++; + } + } + + public int getMobCountNear(EntityPlayer entityPlayer, EnumCreatureType enumCreatureType) { + return entityPlayer.mobCounts[enumCreatureType.ordinal()]; + } + // Paper end + @Override public boolean addEntity(Entity entity) { // CraftBukkit start -- 2.23.0.rc1