Files
Purpur/patches/server/0053-Implement-optional-per-player-mob-spawns.patch
2019-07-13 18:37:16 -05:00

250 lines
13 KiB
Diff

From 3ff085046cf1d3efc53b2dec884c4d5b75cd0df3 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 | 16 +++++++-
.../net/minecraft/server/PlayerChunkMap.java | 10 +++++
.../java/net/minecraft/server/PlayerMap.java | 1 +
.../net/minecraft/server/SpawnerCreature.java | 18 ++++-----
.../net/minecraft/server/WorldServer.java | 39 +++++++++++++++++++
6 files changed, 78 insertions(+), 11 deletions(-)
diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
index ff520d9e86..5ed02f6485 100644
--- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
@@ -519,6 +519,11 @@ public class PaperWorldConfig {
}
}
+ public boolean perPlayerMobSpawns = false;
+ private void perPlayerMobSpawns() {
+ perPlayerMobSpawns = getBoolean("per-player-mob-spawns", false);
+ }
+
public boolean antiXray;
public boolean asynchronous;
public EngineMode engineMode;
diff --git a/src/main/java/net/minecraft/server/ChunkProviderServer.java b/src/main/java/net/minecraft/server/ChunkProviderServer.java
index 4f7c442264..9f6c362dd1 100644
--- a/src/main/java/net/minecraft/server/ChunkProviderServer.java
+++ b/src/main/java/net/minecraft/server/ChunkProviderServer.java
@@ -582,9 +582,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 f25ca782b9..a235df4185 100644
--- a/src/main/java/net/minecraft/server/PlayerChunkMap.java
+++ b/src/main/java/net/minecraft/server/PlayerChunkMap.java
@@ -105,6 +105,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);
@@ -1157,6 +1158,15 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d {
}
+ // Paper start
+ public Stream<EntityPlayer> 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<EntityPlayer> 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 ad8181784e..0c8329bfd8 100644
--- a/src/main/java/net/minecraft/server/PlayerMap.java
+++ b/src/main/java/net/minecraft/server/PlayerMap.java
@@ -12,6 +12,7 @@ public final class PlayerMap {
public PlayerMap() {}
+ public Stream<EntityPlayer> getPlayers(long chunkCoord) { return this.a(chunkCoord); } // Paper - OBFHELPER
public Stream<EntityPlayer> a(long i) {
return Streams.concat(new Stream[]{this.a.stream(), this.b.stream()});
}
diff --git a/src/main/java/net/minecraft/server/SpawnerCreature.java b/src/main/java/net/minecraft/server/SpawnerCreature.java
index af397dd1f7..5e001733a9 100644
--- a/src/main/java/net/minecraft/server/SpawnerCreature.java
+++ b/src/main/java/net/minecraft/server/SpawnerCreature.java
@@ -21,7 +21,7 @@ public final class SpawnerCreature {
spawnMobs(enumcreaturetype, world, chunk, blockposition, Integer.MAX_VALUE);
}
- public static int spawnMobs(EnumCreatureType enumcreaturetype, World world, Chunk chunk, BlockPosition blockposition, int maxSpawns) {
+ public static List<Entity> spawnMobs(EnumCreatureType enumcreaturetype, World world, Chunk chunk, BlockPosition blockposition, int maxSpawns) {
// Paper end
ChunkGenerator<?> chunkgenerator = world.getChunkProvider().getChunkGenerator();
int i = 0;
@@ -29,7 +29,7 @@ public final class SpawnerCreature {
int j = blockposition1.getX();
int k = blockposition1.getY();
int l = blockposition1.getZ();
- int amountSpawned = 0; // Paper - keep track of mobs spawned
+ List<Entity> mobsSpawned = new java.util.ArrayList<>(); // Paper
if (k >= 1) {
IBlockData iblockdata = world.getTypeIfLoadedAndInBounds(blockposition1); // Paper - don't load chunks for mob spawn
@@ -101,7 +101,7 @@ public final class SpawnerCreature {
);
if (!event.callEvent()) {
if (event.shouldAbortSpawn()) {
- return amountSpawned; // Paper
+ return mobsSpawned; // Paper
}
++i2;
continue;
@@ -120,7 +120,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);
@@ -131,16 +131,16 @@ public final class SpawnerCreature {
++i;
++i2;
// Paper start - stop when limit is reached
- amountSpawned++;
+ mobsSpawned.add(entityinsentient);
}
- if (amountSpawned >= maxSpawns){
- return amountSpawned; // Paper
+ if (mobsSpawned.size() >= maxSpawns){
+ return mobsSpawned;
}
// Paper end
// CraftBukkit end
if (i >= entityinsentient.dD()) {
- return amountSpawned; // Paper
+ return mobsSpawned; // Paper
}
if (entityinsentient.c(i2)) {
@@ -165,7 +165,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 f7597d499f..2410db3353 100644
--- a/src/main/java/net/minecraft/server/WorldServer.java
+++ b/src/main/java/net/minecraft/server/WorldServer.java
@@ -17,6 +17,9 @@ import it.unimi.dsi.fastutil.objects.Object2IntMap;
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
import it.unimi.dsi.fastutil.objects.ObjectIterator;
import it.unimi.dsi.fastutil.objects.ObjectLinkedOpenHashSet;
+
+import java.util.ArrayList;
+import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
@@ -67,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;
@@ -932,6 +936,7 @@ public class WorldServer extends World {
}
public Object2IntMap<EnumCreatureType> l() {
+ List<Entity> filteredEntities = new ArrayList<>(); // Paper
Object2IntMap<EnumCreatureType> object2intmap = new Object2IntOpenHashMap();
ObjectIterator objectiterator = this.entitiesById.values().iterator();
@@ -959,13 +964,47 @@ public class WorldServer extends World {
}
// Paper end
object2intmap.mergeInt(enumcreaturetype, 1, Integer::sum);
+ filteredEntities.add(entity); // Paper
}
}
}
+ // Paper start
+ if(this.paperConfig.perPlayerMobSpawns) {
+ this.playerMobTypeMap = new HashMap<>();
+ updatePlayerMobTypeMap(filteredEntities);
+ }
+ // Paper end
return object2intmap;
}
+ // Paper start
+ public void updatePlayerMobTypeMap(List<Entity> 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<EnumCreatureType, Integer> tmpMap = this.playerMobTypeMap.get(player.uniqueID);
+ EnumCreatureType enumType = entity.getEntityType().d();
+ tmpMap.put(
+ enumType,
+ tmpMap.getOrDefault(enumType, 0) + 1);
+ });
+ }
+ }
+
+ public int getMobCountNear(EntityPlayer entityPlayer, EnumCreatureType enumCreatureType) {
+ int count = 0;
+ if (this.playerMobTypeMap != null) {
+ Map<EnumCreatureType, Integer> 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