mirror of
https://github.com/PaperMC/Paper.git
synced 2024-12-03 21:44:40 +01:00
b31089a929
Upstream has released updates that appear to apply and compile correctly. This update has not been tested by PaperMC and as with ANY update, please do your own testing Bukkit Changes: d264e972 #591: Add option for a consumer before spawning an item 1c537fce #590: Add spawn and transform reasons for piglin zombification. CraftBukkit Changes: ee5006d1 #810: Add option for a consumer before spawning an item f6a39d3c #809: Add spawn and transform reasons for piglin zombification. 0c24068a Organise imports Spigot Changes: bff52619 Organise imports
384 lines
23 KiB
Diff
384 lines
23 KiB
Diff
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
|
Date: Tue, 5 May 2020 20:40:53 -0700
|
|
Subject: [PATCH] Optimize isOutsideRange to use distance maps
|
|
|
|
Use a distance map to find the players in range quickly
|
|
|
|
diff --git a/src/main/java/net/minecraft/server/ChunkMapDistance.java b/src/main/java/net/minecraft/server/ChunkMapDistance.java
|
|
index 52a69edcefb72a3908ecd522ef87e7eb989467a6..126eae36dc99c29b0d15be26bd68f00fe7e563fe 100644
|
|
--- a/src/main/java/net/minecraft/server/ChunkMapDistance.java
|
|
+++ b/src/main/java/net/minecraft/server/ChunkMapDistance.java
|
|
@@ -31,7 +31,7 @@ public abstract class ChunkMapDistance {
|
|
private final Long2ObjectMap<ObjectSet<EntityPlayer>> c = new Long2ObjectOpenHashMap();
|
|
public final Long2ObjectOpenHashMap<ArraySetSorted<Ticket<?>>> tickets = new Long2ObjectOpenHashMap();
|
|
private final ChunkMapDistance.a ticketLevelTracker = new ChunkMapDistance.a();
|
|
- private final ChunkMapDistance.b f = new ChunkMapDistance.b(8);
|
|
+ public static final int MOB_SPAWN_RANGE = 8; // private final ChunkMapDistance.b f = new ChunkMapDistance.b(8); // Paper - no longer used
|
|
private final ChunkMapDistance.c g = new ChunkMapDistance.c(33);
|
|
// Paper start use a queue, but still keep unique requirement
|
|
public final java.util.Queue<PlayerChunk> pendingChunkUpdates = new java.util.ArrayDeque<PlayerChunk>() {
|
|
@@ -50,6 +50,8 @@ public abstract class ChunkMapDistance {
|
|
private final Executor m;
|
|
private long currentTick;
|
|
|
|
+ PlayerChunkMap chunkMap; // Paper
|
|
+
|
|
protected ChunkMapDistance(Executor executor, Executor executor1) {
|
|
executor1.getClass();
|
|
Mailbox<Runnable> mailbox = Mailbox.a("player ticket throttler", executor1::execute);
|
|
@@ -94,7 +96,7 @@ public abstract class ChunkMapDistance {
|
|
protected abstract PlayerChunk a(long i, int j, @Nullable PlayerChunk playerchunk, int k);
|
|
|
|
public boolean a(PlayerChunkMap playerchunkmap) {
|
|
- this.f.a();
|
|
+ //this.f.a(); // Paper - no longer used
|
|
this.g.a();
|
|
int i = Integer.MAX_VALUE - this.ticketLevelTracker.a(Integer.MAX_VALUE);
|
|
boolean flag = i != 0;
|
|
@@ -230,7 +232,7 @@ public abstract class ChunkMapDistance {
|
|
((ObjectSet) this.c.computeIfAbsent(i, (j) -> {
|
|
return new ObjectOpenHashSet();
|
|
})).add(entityplayer);
|
|
- this.f.update(i, 0, true);
|
|
+ //this.f.update(i, 0, true); // Paper - no longer used
|
|
this.g.update(i, 0, true);
|
|
}
|
|
|
|
@@ -242,7 +244,7 @@ public abstract class ChunkMapDistance {
|
|
if (objectset != null) objectset.remove(entityplayer); // Paper - some state corruption happens here, don't crash, clean up gracefully.
|
|
if (objectset == null || objectset.isEmpty()) { // Paper
|
|
this.c.remove(i);
|
|
- this.f.update(i, Integer.MAX_VALUE, false);
|
|
+ //this.f.update(i, Integer.MAX_VALUE, false); // Paper - no longer used
|
|
this.g.update(i, Integer.MAX_VALUE, false);
|
|
}
|
|
|
|
@@ -266,13 +268,17 @@ public abstract class ChunkMapDistance {
|
|
}
|
|
|
|
public int b() {
|
|
- this.f.a();
|
|
- return this.f.a.size();
|
|
+ // Paper start - use distance map to implement
|
|
+ // note: this is the spawn chunk count
|
|
+ return this.chunkMap.playerChunkTickRangeMap.size();
|
|
+ // Paper end - use distance map to implement
|
|
}
|
|
|
|
public boolean d(long i) {
|
|
- this.f.a();
|
|
- return this.f.a.containsKey(i);
|
|
+ // Paper start - use distance map to implement
|
|
+ // note: this is the is spawn chunk method
|
|
+ return this.chunkMap.playerChunkTickRangeMap.getObjectsInRange(i) != null;
|
|
+ // Paper end - use distance map to implement
|
|
}
|
|
|
|
public String c() {
|
|
diff --git a/src/main/java/net/minecraft/server/ChunkProviderServer.java b/src/main/java/net/minecraft/server/ChunkProviderServer.java
|
|
index 322d0a7d127878ba49362454808b82172acf1600..5c092243e3e6f069f9ab6799de56dd60499b3b53 100644
|
|
--- a/src/main/java/net/minecraft/server/ChunkProviderServer.java
|
|
+++ b/src/main/java/net/minecraft/server/ChunkProviderServer.java
|
|
@@ -728,6 +728,37 @@ public class ChunkProviderServer extends IChunkProvider {
|
|
boolean flag1 = this.world.getGameRules().getBoolean(GameRules.DO_MOB_SPAWNING) && !world.getPlayers().isEmpty(); // CraftBukkit
|
|
|
|
if (!flag) {
|
|
+ // Paper start - optimize isOutisdeRange
|
|
+ PlayerChunkMap playerChunkMap = this.playerChunkMap;
|
|
+ for (EntityPlayer player : this.world.players) {
|
|
+ if (!player.affectsSpawning || player.isSpectator()) {
|
|
+ playerChunkMap.playerMobSpawnMap.remove(player);
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ int viewDistance = this.playerChunkMap.getEffectiveViewDistance();
|
|
+
|
|
+ // copied and modified from isOutisdeRange
|
|
+ int chunkRange = world.spigotConfig.mobSpawnRange;
|
|
+ chunkRange = (chunkRange > viewDistance) ? (byte)viewDistance : chunkRange;
|
|
+ chunkRange = (chunkRange > ChunkMapDistance.MOB_SPAWN_RANGE) ? ChunkMapDistance.MOB_SPAWN_RANGE : chunkRange;
|
|
+
|
|
+ com.destroystokyo.paper.event.entity.PlayerNaturallySpawnCreaturesEvent event = new com.destroystokyo.paper.event.entity.PlayerNaturallySpawnCreaturesEvent(player.getBukkitEntity(), (byte)chunkRange);
|
|
+ event.callEvent();
|
|
+ if (event.isCancelled() || event.getSpawnRadius() < 0 || playerChunkMap.playerChunkTickRangeMap.getLastViewDistance(player) == -1) {
|
|
+ playerChunkMap.playerMobSpawnMap.remove(player);
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ int range = Math.min(event.getSpawnRadius(), 32); // limit to max view distance
|
|
+ int chunkX = net.minecraft.server.MCUtil.getChunkCoordinate(player.locX());
|
|
+ int chunkZ = net.minecraft.server.MCUtil.getChunkCoordinate(player.locZ());
|
|
+
|
|
+ playerChunkMap.playerMobSpawnMap.addOrUpdate(player, chunkX, chunkZ, range);
|
|
+ player.lastEntitySpawnRadiusSquared = (double)((range << 4) * (range << 4)); // used in isOutsideRange
|
|
+ player.playerNaturallySpawnedEvent = event;
|
|
+ }
|
|
+ // Paper end - optimize isOutisdeRange
|
|
this.world.getMethodProfiler().enter("pollingChunks");
|
|
int k = this.world.getGameRules().getInt(GameRules.RANDOM_TICK_SPEED);
|
|
boolean flag2 = world.ticksPerAnimalSpawns != 0L && worlddata.getTime() % world.ticksPerAnimalSpawns == 0L; // CraftBukkit
|
|
@@ -757,15 +788,7 @@ public class ChunkProviderServer extends IChunkProvider {
|
|
this.world.getMethodProfiler().exit();
|
|
//List<PlayerChunk> list = Lists.newArrayList(this.playerChunkMap.f()); // Paper
|
|
//Collections.shuffle(list); // Paper
|
|
- //Paper start - call player naturally spawn event
|
|
- int chunkRange = world.spigotConfig.mobSpawnRange;
|
|
- chunkRange = (chunkRange > world.spigotConfig.viewDistance) ? (byte) world.spigotConfig.viewDistance : chunkRange;
|
|
- chunkRange = Math.min(chunkRange, 8);
|
|
- for (EntityPlayer entityPlayer : this.world.getPlayers()) {
|
|
- entityPlayer.playerNaturallySpawnedEvent = new com.destroystokyo.paper.event.entity.PlayerNaturallySpawnCreaturesEvent(entityPlayer.getBukkitEntity(), (byte) chunkRange);
|
|
- entityPlayer.playerNaturallySpawnedEvent.callEvent();
|
|
- };
|
|
- // Paper end
|
|
+ // Paper - moved up
|
|
final int[] chunksTicked = {0}; this.playerChunkMap.forEachVisibleChunk((playerchunk) -> { // Paper - safe iterator incase chunk loads, also no wrapping
|
|
Optional<Chunk> optional = ((Either) playerchunk.a().getNow(PlayerChunk.UNLOADED_CHUNK)).left();
|
|
|
|
@@ -781,9 +804,9 @@ public class ChunkProviderServer extends IChunkProvider {
|
|
Chunk chunk = (Chunk) optional1.get();
|
|
ChunkCoordIntPair chunkcoordintpair = playerchunk.i();
|
|
|
|
- if (!this.playerChunkMap.isOutsideOfRange(chunkcoordintpair)) {
|
|
+ if (!this.playerChunkMap.isOutsideOfRange(playerchunk, chunkcoordintpair, false)) { // Paper - optimise isOutsideOfRange
|
|
chunk.setInhabitedTime(chunk.getInhabitedTime() + j);
|
|
- if (flag1 && (this.allowMonsters || this.allowAnimals) && this.world.getWorldBorder().isInBounds(chunk.getPos()) && !this.playerChunkMap.isOutsideOfRange(chunkcoordintpair, true)) { // Spigot
|
|
+ if (flag1 && (this.allowMonsters || this.allowAnimals) && this.world.getWorldBorder().isInBounds(chunk.getPos()) && !this.playerChunkMap.isOutsideOfRange(playerchunk, chunkcoordintpair, true)) { // Spigot // Paper - optimise isOutsideOfRange
|
|
SpawnerCreature.a(this.world, chunk, spawnercreature_d, this.allowAnimals, this.allowMonsters, flag2);
|
|
}
|
|
|
|
diff --git a/src/main/java/net/minecraft/server/EntityPlayer.java b/src/main/java/net/minecraft/server/EntityPlayer.java
|
|
index 05483a9c5b8f77959fb44532f506e268b1676acd..97049fdce7a8d441c0277f8f296bca0ff057db01 100644
|
|
--- a/src/main/java/net/minecraft/server/EntityPlayer.java
|
|
+++ b/src/main/java/net/minecraft/server/EntityPlayer.java
|
|
@@ -120,6 +120,8 @@ public class EntityPlayer extends EntityHuman implements ICrafting {
|
|
|
|
public final com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<EntityPlayer> cachedSingleHashSet; // Paper
|
|
|
|
+ double lastEntitySpawnRadiusSquared; // Paper - optimise isOutsideRange, this field is in blocks
|
|
+
|
|
public EntityPlayer(MinecraftServer minecraftserver, WorldServer worldserver, GameProfile gameprofile, PlayerInteractManager playerinteractmanager) {
|
|
super(worldserver, worldserver.getSpawn(), worldserver.v(), gameprofile);
|
|
this.spawnDimension = World.OVERWORLD;
|
|
diff --git a/src/main/java/net/minecraft/server/PlayerChunk.java b/src/main/java/net/minecraft/server/PlayerChunk.java
|
|
index 5305da4c7253c7e259d7b08e9722145188adc513..7413e3dbaacc288a29d9499242cb8563b4169fd9 100644
|
|
--- a/src/main/java/net/minecraft/server/PlayerChunk.java
|
|
+++ b/src/main/java/net/minecraft/server/PlayerChunk.java
|
|
@@ -45,6 +45,18 @@ public class PlayerChunk {
|
|
long lastAutoSaveTime; // Paper - incremental autosave
|
|
long inactiveTimeStart; // Paper - incremental autosave
|
|
|
|
+ // Paper start - optimise isOutsideOfRange
|
|
+ // cached here to avoid a map lookup
|
|
+ com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<EntityPlayer> playersInMobSpawnRange;
|
|
+ com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<EntityPlayer> playersInChunkTickRange;
|
|
+
|
|
+ void updateRanges() {
|
|
+ long key = net.minecraft.server.MCUtil.getCoordinateKey(this.location);
|
|
+ this.playersInMobSpawnRange = this.chunkMap.playerMobSpawnMap.getObjectsInRange(key);
|
|
+ this.playersInChunkTickRange = this.chunkMap.playerChunkTickRangeMap.getObjectsInRange(key);
|
|
+ }
|
|
+ // Paper end - optimise isOutsideOfRange
|
|
+
|
|
public PlayerChunk(ChunkCoordIntPair chunkcoordintpair, int i, LightEngine lightengine, PlayerChunk.c playerchunk_c, PlayerChunk.d playerchunk_d) {
|
|
this.statusFutures = new AtomicReferenceArray(PlayerChunk.CHUNK_STATUSES.size());
|
|
this.fullChunkFuture = PlayerChunk.UNLOADED_CHUNK_FUTURE;
|
|
@@ -61,6 +73,7 @@ public class PlayerChunk {
|
|
this.n = this.oldTicketLevel;
|
|
this.a(i);
|
|
this.chunkMap = (PlayerChunkMap)playerchunk_d; // Paper
|
|
+ this.updateRanges(); // Paper - optimise isOutsideOfRange
|
|
}
|
|
|
|
// Paper start
|
|
diff --git a/src/main/java/net/minecraft/server/PlayerChunkMap.java b/src/main/java/net/minecraft/server/PlayerChunkMap.java
|
|
index c2bade51ed1d42e3850fc3d0b32790ea40250b64..cf83f105c4354fe6fa0c07b8c1bd160d5d2d9e4d 100644
|
|
--- a/src/main/java/net/minecraft/server/PlayerChunkMap.java
|
|
+++ b/src/main/java/net/minecraft/server/PlayerChunkMap.java
|
|
@@ -161,6 +161,17 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d {
|
|
return MinecraftServer.getServer().applyTrackingRangeScale(vanilla);
|
|
}
|
|
// Paper end - use distance map to optimise tracker
|
|
+ // Paper start - optimise PlayerChunkMap#isOutsideRange
|
|
+ // A note about the naming used here:
|
|
+ // Previously, mojang used a "spawn range" of 8 for controlling both ticking and
|
|
+ // mob spawn range. However, spigot makes the spawn range configurable by
|
|
+ // checking if the chunk is in the tick range (8) and the spawn range
|
|
+ // obviously this means a spawn range > 8 cannot be implemented
|
|
+
|
|
+ // these maps are named after spigot's uses
|
|
+ public final com.destroystokyo.paper.util.misc.PlayerAreaMap playerMobSpawnMap; // this map is absent from updateMaps since it's controlled at the start of the chunkproviderserver tick
|
|
+ public final com.destroystokyo.paper.util.misc.PlayerAreaMap playerChunkTickRangeMap;
|
|
+ // Paper end - optimise PlayerChunkMap#isOutsideRange
|
|
|
|
void addPlayerToDistanceMaps(EntityPlayer player) {
|
|
int chunkX = MCUtil.getChunkCoordinate(player.locX());
|
|
@@ -174,6 +185,9 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d {
|
|
trackMap.add(player, chunkX, chunkZ, Math.min(trackRange, this.getEffectiveViewDistance()));
|
|
}
|
|
// Paper end - use distance map to optimise entity tracker
|
|
+ // Paper start - optimise PlayerChunkMap#isOutsideRange
|
|
+ this.playerChunkTickRangeMap.add(player, chunkX, chunkZ, ChunkMapDistance.MOB_SPAWN_RANGE);
|
|
+ // Paper end - optimise PlayerChunkMap#isOutsideRange
|
|
}
|
|
|
|
void removePlayerFromDistanceMaps(EntityPlayer player) {
|
|
@@ -182,6 +196,10 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d {
|
|
this.playerEntityTrackerTrackMaps[i].remove(player);
|
|
}
|
|
// Paper end - use distance map to optimise tracker
|
|
+ // Paper start - optimise PlayerChunkMap#isOutsideRange
|
|
+ this.playerMobSpawnMap.remove(player);
|
|
+ this.playerChunkTickRangeMap.remove(player);
|
|
+ // Paper end - optimise PlayerChunkMap#isOutsideRange
|
|
}
|
|
|
|
void updateMaps(EntityPlayer player) {
|
|
@@ -196,6 +214,9 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d {
|
|
trackMap.update(player, chunkX, chunkZ, Math.min(trackRange, this.getEffectiveViewDistance()));
|
|
}
|
|
// Paper end - use distance map to optimise entity tracker
|
|
+ // Paper start - optimise PlayerChunkMap#isOutsideRange
|
|
+ this.playerChunkTickRangeMap.update(player, chunkX, chunkZ, ChunkMapDistance.MOB_SPAWN_RANGE);
|
|
+ // Paper end - optimise PlayerChunkMap#isOutsideRange
|
|
}
|
|
// Paper end
|
|
|
|
@@ -227,7 +248,7 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d {
|
|
this.mailboxWorldGen = this.p.a(threadedmailbox, false);
|
|
this.mailboxMain = this.p.a(mailbox, false);
|
|
this.lightEngine = new LightEngineThreaded(ilightaccess, this, this.world.getDimensionManager().hasSkyLight(), threadedmailbox1, this.p.a(threadedmailbox1, false));
|
|
- this.chunkDistanceManager = new PlayerChunkMap.a(executor, iasynctaskhandler);
|
|
+ this.chunkDistanceManager = new PlayerChunkMap.a(executor, iasynctaskhandler); this.chunkDistanceManager.chunkMap = this; // Paper
|
|
this.l = supplier;
|
|
this.m = new VillagePlace(new File(this.w, "poi"), datafixer, flag, this.world); // Paper
|
|
this.setViewDistance(i);
|
|
@@ -271,6 +292,38 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d {
|
|
this.playerEntityTrackerTrackMaps[ordinal] = new com.destroystokyo.paper.util.misc.PlayerAreaMap(this.pooledLinkedPlayerHashSets);
|
|
}
|
|
// Paper end - use distance map to optimise entity tracker
|
|
+ // Paper start - optimise PlayerChunkMap#isOutsideRange
|
|
+ this.playerChunkTickRangeMap = new com.destroystokyo.paper.util.misc.PlayerAreaMap(this.pooledLinkedPlayerHashSets,
|
|
+ (EntityPlayer player, int rangeX, int rangeZ, int currPosX, int currPosZ, int prevPosX, int prevPosZ,
|
|
+ com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<EntityPlayer> newState) -> {
|
|
+ PlayerChunk playerChunk = PlayerChunkMap.this.getUpdatingChunk(MCUtil.getCoordinateKey(rangeX, rangeZ));
|
|
+ if (playerChunk != null) {
|
|
+ playerChunk.playersInChunkTickRange = newState;
|
|
+ }
|
|
+ },
|
|
+ (EntityPlayer player, int rangeX, int rangeZ, int currPosX, int currPosZ, int prevPosX, int prevPosZ,
|
|
+ com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<EntityPlayer> newState) -> {
|
|
+ PlayerChunk playerChunk = PlayerChunkMap.this.getUpdatingChunk(MCUtil.getCoordinateKey(rangeX, rangeZ));
|
|
+ if (playerChunk != null) {
|
|
+ playerChunk.playersInChunkTickRange = newState;
|
|
+ }
|
|
+ });
|
|
+ this.playerMobSpawnMap = new com.destroystokyo.paper.util.misc.PlayerAreaMap(this.pooledLinkedPlayerHashSets,
|
|
+ (EntityPlayer player, int rangeX, int rangeZ, int currPosX, int currPosZ, int prevPosX, int prevPosZ,
|
|
+ com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<EntityPlayer> newState) -> {
|
|
+ PlayerChunk playerChunk = PlayerChunkMap.this.getUpdatingChunk(MCUtil.getCoordinateKey(rangeX, rangeZ));
|
|
+ if (playerChunk != null) {
|
|
+ playerChunk.playersInMobSpawnRange = newState;
|
|
+ }
|
|
+ },
|
|
+ (EntityPlayer player, int rangeX, int rangeZ, int currPosX, int currPosZ, int prevPosX, int prevPosZ,
|
|
+ com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<EntityPlayer> newState) -> {
|
|
+ PlayerChunk playerChunk = PlayerChunkMap.this.getUpdatingChunk(MCUtil.getCoordinateKey(rangeX, rangeZ));
|
|
+ if (playerChunk != null) {
|
|
+ playerChunk.playersInMobSpawnRange = newState;
|
|
+ }
|
|
+ });
|
|
+ // Paper end - optimise PlayerChunkMap#isOutsideRange
|
|
}
|
|
|
|
public void updatePlayerMobTypeMap(Entity entity) {
|
|
@@ -290,6 +343,7 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d {
|
|
return entityPlayer.mobCounts[enumCreatureType.ordinal()];
|
|
}
|
|
|
|
+ private static double getDistanceSquaredFromChunk(ChunkCoordIntPair chunkPos, Entity entity) { return a(chunkPos, 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);
|
|
@@ -468,6 +522,7 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d {
|
|
} else {
|
|
if (playerchunk != null) {
|
|
playerchunk.a(j);
|
|
+ playerchunk.updateRanges(); // Paper - optimise isOutsideOfRange
|
|
}
|
|
|
|
if (playerchunk != null) {
|
|
@@ -1438,30 +1493,53 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d {
|
|
return isOutsideOfRange(chunkcoordintpair, false);
|
|
}
|
|
|
|
- boolean isOutsideOfRange(ChunkCoordIntPair chunkcoordintpair, boolean reducedRange) {
|
|
- int chunkRange = world.spigotConfig.mobSpawnRange;
|
|
- chunkRange = (chunkRange > world.spigotConfig.viewDistance) ? (byte) world.spigotConfig.viewDistance : chunkRange;
|
|
- chunkRange = (chunkRange > 8) ? 8 : chunkRange;
|
|
+ // Paper start - optimise isOutsideOfRange
|
|
+ final boolean isOutsideOfRange(ChunkCoordIntPair chunkcoordintpair, boolean reducedRange) {
|
|
+ return this.isOutsideOfRange(this.getUpdatingChunk(chunkcoordintpair.pair()), chunkcoordintpair, reducedRange);
|
|
+ }
|
|
|
|
- final int finalChunkRange = chunkRange; // Paper for lambda below
|
|
- //double blockRange = (reducedRange) ? Math.pow(chunkRange << 4, 2) : 16384.0D; // Paper - use from event
|
|
- // Spigot end
|
|
- long i = chunkcoordintpair.pair();
|
|
+ final boolean isOutsideOfRange(PlayerChunk playerchunk, ChunkCoordIntPair chunkcoordintpair, boolean reducedRange) {
|
|
+ // this function is so hot that removing the map lookup call can have an order of magnitude impact on its performance
|
|
+ // tested and confirmed via System.nanoTime()
|
|
+ com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<EntityPlayer> playersInRange = reducedRange ? playerchunk.playersInMobSpawnRange : playerchunk.playersInChunkTickRange;
|
|
|
|
- return !this.chunkDistanceManager.d(i) ? true : this.playerMap.a(i).noneMatch((entityplayer) -> {
|
|
- // Paper start -
|
|
- com.destroystokyo.paper.event.entity.PlayerNaturallySpawnCreaturesEvent event;
|
|
- double blockRange = 16384.0D;
|
|
- if (reducedRange) {
|
|
- event = entityplayer.playerNaturallySpawnedEvent;
|
|
- if (event == null || event.isCancelled()) return false;
|
|
- blockRange = (double) ((event.getSpawnRadius() << 4) * (event.getSpawnRadius() << 4));
|
|
- }
|
|
+ if (playersInRange == null) {
|
|
+ return true;
|
|
+ }
|
|
|
|
- return (!entityplayer.isSpectator() && a(chunkcoordintpair, (Entity) entityplayer) < blockRange); // Spigot
|
|
- // Paper end
|
|
- });
|
|
+ Object[] backingSet = playersInRange.getBackingSet();
|
|
+
|
|
+ if (reducedRange) {
|
|
+ for (int i = 0, len = backingSet.length; i < len; ++i) {
|
|
+ Object raw = backingSet[i];
|
|
+ if (!(raw instanceof EntityPlayer)) {
|
|
+ continue;
|
|
+ }
|
|
+ EntityPlayer player = (EntityPlayer) raw;
|
|
+ // don't check spectator and whatnot, already handled by mob spawn map update
|
|
+ if (player.lastEntitySpawnRadiusSquared > getDistanceSquaredFromChunk(chunkcoordintpair, player)) {
|
|
+ return false; // in range
|
|
+ }
|
|
+ }
|
|
+ } else {
|
|
+ final double range = (ChunkMapDistance.MOB_SPAWN_RANGE * 16) * (ChunkMapDistance.MOB_SPAWN_RANGE * 16);
|
|
+ // before spigot, mob spawn range was actually mob spawn range + tick range, but it was split
|
|
+ for (int i = 0, len = backingSet.length; i < len; ++i) {
|
|
+ Object raw = backingSet[i];
|
|
+ if (!(raw instanceof EntityPlayer)) {
|
|
+ continue;
|
|
+ }
|
|
+ EntityPlayer player = (EntityPlayer) raw;
|
|
+ // don't check spectator and whatnot, already handled by mob spawn map update
|
|
+ if (range > getDistanceSquaredFromChunk(chunkcoordintpair, player)) {
|
|
+ return false; // in range
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ // no players in range
|
|
+ return true;
|
|
}
|
|
+ // Paper end - optimise isOutsideOfRange
|
|
|
|
private boolean b(EntityPlayer entityplayer) {
|
|
return entityplayer.isSpectator() && !this.world.getGameRules().getBoolean(GameRules.SPECTATORS_GENERATE_CHUNKS);
|