mirror of
https://github.com/PaperMC/Paper.git
synced 2024-08-26 22:50:23 +02:00
Upstream has released updates that appears 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:
565a5727 #533: Add consumed item, hand and consumeItem boolean to EntityShootBowEvent
CraftBukkit Changes:
927200a9
#718: Add consumed item, hand and consumeItem boolean to EntityShootBowEvent
385 lines
23 KiB
Diff
385 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 275c2b23b4d1ff09ee2b1823d0780700f773659e..ef61f8e784b7ebd26293d627e8b8e1aef1be6e21 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);
|
|
}
|
|
|
|
@@ -241,7 +243,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);
|
|
}
|
|
|
|
@@ -265,13 +267,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 893a835593af2ea95a50607c8c2f2cdb9af6c944..c54175eaad6230a1098e9b912e0b4788afe4b9c8 100644
|
|
--- a/src/main/java/net/minecraft/server/ChunkProviderServer.java
|
|
+++ b/src/main/java/net/minecraft/server/ChunkProviderServer.java
|
|
@@ -729,6 +729,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
|
|
@@ -758,15 +789,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();
|
|
|
|
@@ -782,9 +805,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 824f074740ad063815ca80dce679ceb532c8edc2..474bb8ee2548a90c74b458c9952ddf1e465a11ef 100644
|
|
--- a/src/main/java/net/minecraft/server/EntityPlayer.java
|
|
+++ b/src/main/java/net/minecraft/server/EntityPlayer.java
|
|
@@ -115,6 +115,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 844f5b204b0f8c4474b4b9ffdc9cb7f3564b1336..4074c1f8f8b71544df9aa6e8d59c5703f2036fd9 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 21a9a0364ec6cfd28fcfc0a62d3465993dac1a1c..b4067657eefe6a418b76b599b4c8ffb8359c3f89 100644
|
|
--- a/src/main/java/net/minecraft/server/PlayerChunkMap.java
|
|
+++ b/src/main/java/net/minecraft/server/PlayerChunkMap.java
|
|
@@ -160,6 +160,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());
|
|
@@ -173,6 +184,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) {
|
|
@@ -181,6 +195,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) {
|
|
@@ -195,6 +213,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
|
|
|
|
@@ -226,7 +247,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);
|
|
@@ -270,6 +291,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) {
|
|
@@ -289,6 +342,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);
|
|
@@ -467,6 +521,7 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d {
|
|
} else {
|
|
if (playerchunk != null) {
|
|
playerchunk.a(j);
|
|
+ playerchunk.updateRanges(); // Paper - optimise isOutsideOfRange
|
|
}
|
|
|
|
if (playerchunk != null) {
|
|
@@ -1437,30 +1492,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);
|