Files
Purpur/patches/server/0054-implement-optional-per-player-mob-spawns.patch
2019-08-02 12:26:54 -05:00

288 lines
16 KiB
Diff

From 691eea6b3c187ab8346fab6214379b82c0490055 Mon Sep 17 00:00:00 2001
From: kickash32 <kickash32@gmail.com>
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 318a470ee..72b77e27e 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 b1bea8f90..c03414f3f 100644
--- a/src/main/java/net/minecraft/server/ChunkProviderServer.java
+++ b/src/main/java/net/minecraft/server/ChunkProviderServer.java
@@ -601,9 +601,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<T extends Entity> {
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<EntityPlayer> a(ChunkCoordIntPair chunkcoordintpair, boolean flag) {
+ // Paper start
+ public List<EntityPlayer> getPlayersNear(ChunkCoordIntPair chunkcoordintpair) {
+ List<EntityPlayer> players = this.playerMap.getPlayers();
+ players.removeIf(
+ entityplayer -> distanceBetween(chunkcoordintpair, entityplayer) > this.viewDistance);
+ return players;
+ }
+ // Paper end
+
+ @Override public Stream<EntityPlayer> 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<EntityPlayer> getPlayers() { return new java.util.ArrayList<>(this.a.keySet()); } // Paper - Based on method below without streams
public Stream<EntityPlayer> 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<Entity> 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 787dc3e88..50fcab233 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<UUID, Map<EnumCreatureType, Integer>> playerMobTypeMap; // Paper
// CraftBukkit start
private int tickPosition;
@@ -964,6 +965,16 @@ public class WorldServer extends World {
}
public Object2IntMap<EnumCreatureType> 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<EnumCreatureType> object2intmap = new Object2IntOpenHashMap();
ObjectIterator objectiterator = this.entitiesById.values().iterator();
@@ -988,6 +999,7 @@ public class WorldServer extends World {
entity.spawnReason == CreatureSpawnEvent.SpawnReason.CHUNK_GEN)) {
continue;
}
+ updatePlayerMobCounts(entity);
// Paper end
object2intmap.mergeInt(enumcreaturetype, 1, Integer::sum);
}
@@ -996,6 +1008,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.20.1