mirror of
https://github.com/PaperMC/Paper.git
synced 2024-11-29 11:42:55 +01:00
4104545b11
"It was from a different time before books were as jank as they are now. As time has gone on they've only proven to be worse and worse."
375 lines
24 KiB
Diff
375 lines
24 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/level/ChunkHolder.java b/src/main/java/net/minecraft/server/level/ChunkHolder.java
|
|
index 55f355d1218ddb3f320752666407151291c0f398..948a817a1d6f4435655931357aa094b889771e82 100644
|
|
--- a/src/main/java/net/minecraft/server/level/ChunkHolder.java
|
|
+++ b/src/main/java/net/minecraft/server/level/ChunkHolder.java
|
|
@@ -100,6 +100,18 @@ public class ChunkHolder {
|
|
}
|
|
// Paper end
|
|
|
|
+ // Paper start - optimise isOutsideOfRange
|
|
+ // cached here to avoid a map lookup
|
|
+ com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<ServerPlayer> playersInMobSpawnRange;
|
|
+ com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<ServerPlayer> playersInChunkTickRange;
|
|
+
|
|
+ void updateRanges() {
|
|
+ long key = net.minecraft.server.MCUtil.getCoordinateKey(this.pos);
|
|
+ this.playersInMobSpawnRange = this.chunkMap.playerMobSpawnMap.getObjectsInRange(key);
|
|
+ this.playersInChunkTickRange = this.chunkMap.playerChunkTickRangeMap.getObjectsInRange(key);
|
|
+ }
|
|
+ // Paper end - optimise isOutsideOfRange
|
|
+
|
|
public ChunkHolder(ChunkPos pos, int level, LevelHeightAccessor world, LevelLightEngine lightingProvider, ChunkHolder.LevelChangeListener levelUpdateListener, ChunkHolder.PlayerProvider playersWatchingChunkProvider) {
|
|
this.futures = new AtomicReferenceArray(ChunkHolder.CHUNK_STATUSES.size());
|
|
this.fullChunkFuture = ChunkHolder.UNLOADED_LEVEL_CHUNK_FUTURE;
|
|
@@ -121,6 +133,7 @@ public class ChunkHolder {
|
|
this.setTicketLevel(level);
|
|
this.changedBlocksPerSection = new ShortSet[world.getSectionsCount()];
|
|
this.chunkMap = (ChunkMap)playersWatchingChunkProvider; // Paper
|
|
+ this.updateRanges(); // Paper - optimise isOutsideOfRange
|
|
}
|
|
|
|
// CraftBukkit start
|
|
diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java
|
|
index 9ce330be998f3392288d8eb0386a48237ff3a880..708c135fbdc5f071bd979dc496aefb1fac7a2284 100644
|
|
--- a/src/main/java/net/minecraft/server/level/ChunkMap.java
|
|
+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java
|
|
@@ -241,6 +241,17 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
|
return MinecraftServer.getServer().getScaledTrackingDistance(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(ServerPlayer player) {
|
|
int chunkX = MCUtil.getChunkCoordinate(player.getX());
|
|
@@ -254,6 +265,12 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
|
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.update(player, chunkX, chunkZ, DistanceManager.MOB_SPAWN_RANGE);
|
|
+ // Paper end - optimise PlayerChunkMap#isOutsideRange
|
|
+ // Paper start - optimise PlayerChunkMap#isOutsideRange
|
|
+ this.playerChunkTickRangeMap.add(player, chunkX, chunkZ, DistanceManager.MOB_SPAWN_RANGE);
|
|
+ // Paper end - optimise PlayerChunkMap#isOutsideRange
|
|
// Paper start - no-tick view distance
|
|
int effectiveTickViewDistance = this.getEffectiveViewDistance();
|
|
int effectiveNoTickViewDistance = Math.max(this.getEffectiveNoTickViewDistance(), effectiveTickViewDistance);
|
|
@@ -275,6 +292,10 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
|
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
|
|
// Paper start - no-tick view distance
|
|
this.playerViewDistanceBroadcastMap.remove(player);
|
|
this.playerViewDistanceTickMap.remove(player);
|
|
@@ -294,6 +315,9 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
|
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, DistanceManager.MOB_SPAWN_RANGE);
|
|
+ // Paper end - optimise PlayerChunkMap#isOutsideRange
|
|
// Paper start - no-tick view distance
|
|
int effectiveTickViewDistance = this.getEffectiveViewDistance();
|
|
int effectiveNoTickViewDistance = Math.max(this.getEffectiveNoTickViewDistance(), effectiveTickViewDistance);
|
|
@@ -340,7 +364,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
|
this.mainThreadMailbox = this.queueSorter.getProcessor(mailbox, false);
|
|
this.mailboxLight = this.queueSorter.getProcessor(lightthreaded, false);// Paper
|
|
this.lightEngine = new ThreadedLevelLightEngine(chunkProvider, this, this.level.dimensionType().hasSkyLight(), threadedmailbox1, this.queueSorter.getProcessor(threadedmailbox1, false));
|
|
- this.distanceManager = new ChunkMap.ChunkDistanceManager(executor, mainThreadExecutor);
|
|
+ this.distanceManager = new ChunkMap.ChunkDistanceManager(executor, mainThreadExecutor); this.distanceManager.chunkMap = this; // Paper
|
|
this.overworldDataStorage = persistentStateManagerFactory;
|
|
this.poiManager = new PoiManager(new File(this.storageFolder, "poi"), dataFixer, dsync, world);
|
|
this.setViewDistance(viewDistance);
|
|
@@ -384,6 +408,38 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
|
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,
|
|
+ (ServerPlayer player, int rangeX, int rangeZ, int currPosX, int currPosZ, int prevPosX, int prevPosZ,
|
|
+ com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<ServerPlayer> newState) -> {
|
|
+ ChunkHolder playerChunk = ChunkMap.this.getUpdatingChunkIfPresent(MCUtil.getCoordinateKey(rangeX, rangeZ));
|
|
+ if (playerChunk != null) {
|
|
+ playerChunk.playersInChunkTickRange = newState;
|
|
+ }
|
|
+ },
|
|
+ (ServerPlayer player, int rangeX, int rangeZ, int currPosX, int currPosZ, int prevPosX, int prevPosZ,
|
|
+ com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<ServerPlayer> newState) -> {
|
|
+ ChunkHolder playerChunk = ChunkMap.this.getUpdatingChunkIfPresent(MCUtil.getCoordinateKey(rangeX, rangeZ));
|
|
+ if (playerChunk != null) {
|
|
+ playerChunk.playersInChunkTickRange = newState;
|
|
+ }
|
|
+ });
|
|
+ this.playerMobSpawnMap = new com.destroystokyo.paper.util.misc.PlayerAreaMap(this.pooledLinkedPlayerHashSets,
|
|
+ (ServerPlayer player, int rangeX, int rangeZ, int currPosX, int currPosZ, int prevPosX, int prevPosZ,
|
|
+ com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<ServerPlayer> newState) -> {
|
|
+ ChunkHolder playerChunk = ChunkMap.this.getUpdatingChunkIfPresent(MCUtil.getCoordinateKey(rangeX, rangeZ));
|
|
+ if (playerChunk != null) {
|
|
+ playerChunk.playersInMobSpawnRange = newState;
|
|
+ }
|
|
+ },
|
|
+ (ServerPlayer player, int rangeX, int rangeZ, int currPosX, int currPosZ, int prevPosX, int prevPosZ,
|
|
+ com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<ServerPlayer> newState) -> {
|
|
+ ChunkHolder playerChunk = ChunkMap.this.getUpdatingChunkIfPresent(MCUtil.getCoordinateKey(rangeX, rangeZ));
|
|
+ if (playerChunk != null) {
|
|
+ playerChunk.playersInMobSpawnRange = newState;
|
|
+ }
|
|
+ });
|
|
+ // Paper end - optimise PlayerChunkMap#isOutsideRange
|
|
// Paper start - no-tick view distance
|
|
this.setNoTickViewDistance(this.level.paperConfig.noTickViewDistance);
|
|
this.playerViewDistanceTickMap = new com.destroystokyo.paper.util.misc.PlayerAreaMap(this.pooledLinkedPlayerHashSets,
|
|
@@ -653,6 +709,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
|
} else {
|
|
if (holder != null) {
|
|
holder.setTicketLevel(level);
|
|
+ holder.updateRanges(); // Paper - optimise isOutsideOfRange
|
|
}
|
|
|
|
if (holder != null) {
|
|
@@ -1474,29 +1531,50 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
|
return this.isOutsideOfRange(chunkPos, false);
|
|
}
|
|
|
|
- boolean isOutsideOfRange(ChunkPos chunkcoordintpair, boolean reducedRange) {
|
|
- int chunkRange = level.spigotConfig.mobSpawnRange;
|
|
- chunkRange = (chunkRange > level.spigotConfig.viewDistance) ? (byte) level.spigotConfig.viewDistance : chunkRange;
|
|
- chunkRange = (chunkRange > 8) ? 8 : chunkRange;
|
|
-
|
|
- 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.toLong();
|
|
+ // Paper start - optimise isOutsideOfRange
|
|
+ final boolean isOutsideOfRange(ChunkPos chunkcoordintpair, boolean reducedRange) {
|
|
+ return this.isOutsideOfRange(this.getUpdatingChunkIfPresent(chunkcoordintpair.toLong()), chunkcoordintpair, reducedRange);
|
|
+ }
|
|
+ final boolean isOutsideOfRange(ChunkHolder playerchunk, ChunkPos 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<ServerPlayer> playersInRange = reducedRange ? playerchunk.playersInMobSpawnRange : playerchunk.playersInChunkTickRange;
|
|
+ if (playersInRange == null) {
|
|
+ return true;
|
|
+ }
|
|
+ Object[] backingSet = playersInRange.getBackingSet();
|
|
|
|
- return !this.distanceManager.hasPlayersNearby(i) ? true : this.playerMap.getPlayers(i).noneMatch((entityplayer) -> {
|
|
- // Paper start - add PlayerNaturallySpawnCreaturesEvent
|
|
- 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 (reducedRange) {
|
|
+ for (int i = 0, len = backingSet.length; i < len; ++i) {
|
|
+ Object raw = backingSet[i];
|
|
+ if (!(raw instanceof ServerPlayer)) {
|
|
+ continue;
|
|
+ }
|
|
+ ServerPlayer player = (ServerPlayer) raw;
|
|
+ // don't check spectator and whatnot, already handled by mob spawn map update
|
|
+ if (player.lastEntitySpawnRadiusSquared > euclideanDistanceSquared(chunkcoordintpair, player)) {
|
|
+ return false; // in range
|
|
+ }
|
|
}
|
|
- // Paper end
|
|
- return !entityplayer.isSpectator() && ChunkMap.euclideanDistanceSquared(chunkcoordintpair, (Entity) entityplayer) < blockRange; // Spigot
|
|
- });
|
|
+ } else {
|
|
+ final double range = (DistanceManager.MOB_SPAWN_RANGE * 16) * (DistanceManager.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 ServerPlayer)) {
|
|
+ continue;
|
|
+ }
|
|
+ ServerPlayer player = (ServerPlayer) raw;
|
|
+ // don't check spectator and whatnot, already handled by mob spawn map update
|
|
+ if (range > euclideanDistanceSquared(chunkcoordintpair, player)) {
|
|
+ return false; // in range
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ // no players in range
|
|
+ return true;
|
|
}
|
|
+ // Paper end - optimise isOutsideOfRange
|
|
|
|
private boolean skipPlayer(ServerPlayer player) {
|
|
return player.isSpectator() && !this.level.getGameRules().getBoolean(GameRules.RULE_SPECTATORSGENERATECHUNKS);
|
|
diff --git a/src/main/java/net/minecraft/server/level/DistanceManager.java b/src/main/java/net/minecraft/server/level/DistanceManager.java
|
|
index b49d380ef088aed3204ec71abc437c348ef004fa..577b391dcba1db712c1e2c83296e1c87b3e34ab2 100644
|
|
--- a/src/main/java/net/minecraft/server/level/DistanceManager.java
|
|
+++ b/src/main/java/net/minecraft/server/level/DistanceManager.java
|
|
@@ -45,7 +45,7 @@ public abstract class DistanceManager {
|
|
final Long2ObjectMap<ObjectSet<ServerPlayer>> playersPerChunk = new Long2ObjectOpenHashMap();
|
|
public final Long2ObjectOpenHashMap<SortedArraySet<Ticket<?>>> tickets = new Long2ObjectOpenHashMap();
|
|
private final DistanceManager.ChunkTicketTracker ticketTracker = new DistanceManager.ChunkTicketTracker();
|
|
- private final DistanceManager.FixedPlayerDistanceChunkTracker naturalSpawnChunkCounter = new DistanceManager.FixedPlayerDistanceChunkTracker(8);
|
|
+ public static final int MOB_SPAWN_RANGE = 8; // private final ChunkMapDistance.b f = new ChunkMapDistance.b(8); // Paper - no longer used
|
|
private final DistanceManager.PlayerTicketTracker playerTicketManager = new DistanceManager.PlayerTicketTracker(33);
|
|
// Paper start use a queue, but still keep unique requirement
|
|
public final java.util.Queue<ChunkHolder> pendingChunkUpdates = new java.util.ArrayDeque<ChunkHolder>() {
|
|
@@ -64,6 +64,8 @@ public abstract class DistanceManager {
|
|
final Executor mainThreadExecutor;
|
|
private long ticketTickCounter;
|
|
|
|
+ ChunkMap chunkMap; // Paper
|
|
+
|
|
protected DistanceManager(Executor workerExecutor, Executor mainThreadExecutor) {
|
|
Objects.requireNonNull(mainThreadExecutor);
|
|
ProcessorHandle<Runnable> mailbox = ProcessorHandle.of("player ticket throttler", mainThreadExecutor::execute);
|
|
@@ -108,7 +110,7 @@ public abstract class DistanceManager {
|
|
protected abstract ChunkHolder updateChunkScheduling(long pos, int level, @Nullable ChunkHolder holder, int k);
|
|
|
|
public boolean runAllUpdates(ChunkMap playerchunkmap) {
|
|
- this.naturalSpawnChunkCounter.runAllUpdates();
|
|
+ //this.f.a(); // Paper - no longer used
|
|
this.playerTicketManager.runAllUpdates();
|
|
int i = Integer.MAX_VALUE - this.ticketTracker.runDistanceUpdates(Integer.MAX_VALUE);
|
|
boolean flag = i != 0;
|
|
@@ -244,7 +246,7 @@ public abstract class DistanceManager {
|
|
((ObjectSet) this.playersPerChunk.computeIfAbsent(i, (j) -> {
|
|
return new ObjectOpenHashSet();
|
|
})).add(player);
|
|
- this.naturalSpawnChunkCounter.update(i, 0, true);
|
|
+ //this.f.update(i, 0, true); // Paper - no longer used
|
|
this.playerTicketManager.update(i, 0, true);
|
|
}
|
|
|
|
@@ -256,7 +258,7 @@ public abstract class DistanceManager {
|
|
if (objectset != null) objectset.remove(player); // Paper - some state corruption happens here, don't crash, clean up gracefully.
|
|
if (objectset == null || objectset.isEmpty()) { // Paper
|
|
this.playersPerChunk.remove(i);
|
|
- this.naturalSpawnChunkCounter.update(i, Integer.MAX_VALUE, false);
|
|
+ //this.f.update(i, Integer.MAX_VALUE, false); // Paper - no longer used
|
|
this.playerTicketManager.update(i, Integer.MAX_VALUE, false);
|
|
}
|
|
|
|
@@ -280,13 +282,17 @@ public abstract class DistanceManager {
|
|
}
|
|
|
|
public int getNaturalSpawnChunkCount() {
|
|
- this.naturalSpawnChunkCounter.runAllUpdates();
|
|
- return this.naturalSpawnChunkCounter.chunks.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 hasPlayersNearby(long i) {
|
|
- this.naturalSpawnChunkCounter.runAllUpdates();
|
|
- return this.naturalSpawnChunkCounter.chunks.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 getDebugStatus() {
|
|
diff --git a/src/main/java/net/minecraft/server/level/ServerChunkCache.java b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
|
|
index 0bb931ae8faa8e1fe36895d8321a9b36d325c3ed..135d162a926bd258d2aa001b7d0ef880fd3f2fb9 100644
|
|
--- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java
|
|
+++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
|
|
@@ -730,6 +730,37 @@ public class ServerChunkCache extends ChunkSource {
|
|
boolean flag1 = this.level.getGameRules().getBoolean(GameRules.RULE_DOMOBSPAWNING) && !this.level.players().isEmpty(); // CraftBukkit
|
|
|
|
if (!flag) {
|
|
+ // Paper start - optimize isOutisdeRange
|
|
+ ChunkMap playerChunkMap = this.chunkMap;
|
|
+ for (ServerPlayer player : this.level.players) {
|
|
+ if (!player.affectsSpawning || player.isSpectator()) {
|
|
+ playerChunkMap.playerMobSpawnMap.remove(player);
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ int viewDistance = this.chunkMap.getEffectiveViewDistance();
|
|
+
|
|
+ // copied and modified from isOutisdeRange
|
|
+ int chunkRange = level.spigotConfig.mobSpawnRange;
|
|
+ chunkRange = (chunkRange > viewDistance) ? (byte)viewDistance : chunkRange;
|
|
+ chunkRange = (chunkRange > DistanceManager.MOB_SPAWN_RANGE) ? DistanceManager.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.getX());
|
|
+ int chunkZ = net.minecraft.server.MCUtil.getChunkCoordinate(player.getZ());
|
|
+
|
|
+ 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.level.getProfiler().push("pollingChunks");
|
|
int k = this.level.getGameRules().getInt(GameRules.RULE_RANDOMTICKING);
|
|
boolean flag2 = level.ticksPerAnimalSpawns != 0L && worlddata.getGameTime() % level.ticksPerAnimalSpawns == 0L; // CraftBukkit
|
|
@@ -759,15 +790,7 @@ public class ServerChunkCache extends ChunkSource {
|
|
this.level.getProfiler().pop();
|
|
//List<PlayerChunk> list = Lists.newArrayList(this.playerChunkMap.f()); // Paper
|
|
//Collections.shuffle(list); // Paper
|
|
- //Paper start - call player naturally spawn event
|
|
- int chunkRange = level.spigotConfig.mobSpawnRange;
|
|
- chunkRange = (chunkRange > level.spigotConfig.viewDistance) ? (byte) level.spigotConfig.viewDistance : chunkRange;
|
|
- chunkRange = Math.min(chunkRange, 8);
|
|
- for (ServerPlayer entityPlayer : this.level.players()) {
|
|
- entityPlayer.playerNaturallySpawnedEvent = new com.destroystokyo.paper.event.entity.PlayerNaturallySpawnCreaturesEvent(entityPlayer.getBukkitEntity(), (byte) chunkRange);
|
|
- entityPlayer.playerNaturallySpawnedEvent.callEvent();
|
|
- };
|
|
- // Paper end
|
|
+ // Paper - moved up
|
|
this.level.timings.chunkTicks.startTiming(); // Paper
|
|
final int[] chunksTicked = {0}; this.chunkMap.forEachVisibleChunk((playerchunk) -> { // Paper - safe iterator incase chunk loads, also no wrapping
|
|
Optional<LevelChunk> optional = ((Either) playerchunk.getTickingChunkFuture().getNow(ChunkHolder.UNLOADED_LEVEL_CHUNK)).left();
|
|
@@ -782,9 +805,9 @@ public class ServerChunkCache extends ChunkSource {
|
|
this.level.getProfiler().pop();
|
|
ChunkPos chunkcoordintpair = chunk.getPos();
|
|
|
|
- if (this.level.isPositionEntityTicking(chunkcoordintpair) && !this.chunkMap.noPlayersCloseForSpawning(chunkcoordintpair)) {
|
|
+ if (this.level.isPositionEntityTicking(chunkcoordintpair) && !this.chunkMap.isOutsideOfRange(playerchunk, chunkcoordintpair, false)) { // Paper - optimise isOutsideOfRange
|
|
chunk.setInhabitedTime(chunk.getInhabitedTime() + j);
|
|
- if (flag1 && (this.spawnEnemies || this.spawnFriendlies) && this.level.getWorldBorder().isWithinBounds(chunk.getPos()) && !this.chunkMap.isOutsideOfRange(chunkcoordintpair, true)) { // Spigot
|
|
+ if (flag1 && (this.spawnEnemies || this.spawnFriendlies) && this.level.getWorldBorder().isWithinBounds(chunk.getPos()) && !this.chunkMap.isOutsideOfRange(playerchunk, chunkcoordintpair, true)) { // Spigot // Paper - optimise isOutsideOfRange
|
|
NaturalSpawner.spawnForChunk(this.level, chunk, spawnercreature_d, this.spawnFriendlies, this.spawnEnemies, flag2);
|
|
if (chunksTicked[0]++ % 10 == 0) this.level.getServer().midTickLoadChunks(); // Paper
|
|
}
|
|
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
|
index 04260e1e8cf17d2af06504fae949958b91c86bef..384f38b3c7dd030f107991137912866ae045f811 100644
|
|
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
|
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
|
@@ -244,6 +244,7 @@ public class ServerPlayer extends Player {
|
|
// CraftBukkit end
|
|
public PlayerNaturallySpawnCreaturesEvent playerNaturallySpawnedEvent; // Paper
|
|
|
|
+ public double lastEntitySpawnRadiusSquared; // Paper - optimise isOutsideRange, this field is in blocks
|
|
public final com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<ServerPlayer> cachedSingleHashSet; // Paper
|
|
boolean needsChunkCenterUpdate; // Paper - no-tick view distance
|
|
|