mirror of
https://github.com/PaperMC/Paper.git
synced 2024-12-02 13:07:06 +01:00
2873869bb1
Signs no longer have a specific isEdiable state, the entire API in this regard needs updating/deprecation. The boolean field is completely gone, replaced by a uuid (which will need a new setEditingPlayer(UUID) method on the Sign interface), and the current upstream implementation of setEdiable simply flips the is_waxed state. This patch is hence not needed as it neither allows editing (which will be redone in a later patch) nor is required to copy the is_waxed boolean flag as it lives in the signs compound tag and is covered by applyTo.
426 lines
24 KiB
Diff
426 lines
24 KiB
Diff
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
|
Date: Thu, 27 Aug 2020 16:22:52 -0700
|
|
Subject: [PATCH] Optimise nearby player lookups
|
|
|
|
Use a distance map to map out close players.
|
|
Note that it's important that we cache the distance map value per chunk
|
|
since the penalty of a map lookup could outweigh the benefits of
|
|
searching less players (as it basically did in the outside range patch).
|
|
|
|
diff --git a/src/main/java/net/minecraft/server/level/ChunkHolder.java b/src/main/java/net/minecraft/server/level/ChunkHolder.java
|
|
index 3914fae62d3e0c0a9aeb8fd2bd48e76889c25a3a..25f983442b844465bde333131972d15df8e14415 100644
|
|
--- a/src/main/java/net/minecraft/server/level/ChunkHolder.java
|
|
+++ b/src/main/java/net/minecraft/server/level/ChunkHolder.java
|
|
@@ -96,6 +96,12 @@ public class ChunkHolder {
|
|
this.chunkMap.needsChangeBroadcasting.add(this);
|
|
}
|
|
// Paper end - optimise chunk tick iteration
|
|
+ // Paper start - optimise checkDespawn
|
|
+ LevelChunk chunk = this.getFullChunkNowUnchecked();
|
|
+ if (chunk != null) {
|
|
+ chunk.updateGeneralAreaCache();
|
|
+ }
|
|
+ // Paper end - optimise checkDespawn
|
|
}
|
|
|
|
public void onChunkRemove() {
|
|
@@ -108,6 +114,12 @@ public class ChunkHolder {
|
|
this.chunkMap.needsChangeBroadcasting.remove(this);
|
|
}
|
|
// Paper end - optimise chunk tick iteration
|
|
+ // Paper start - optimise checkDespawn
|
|
+ LevelChunk chunk = this.getFullChunkNowUnchecked();
|
|
+ if (chunk != null) {
|
|
+ chunk.removeGeneralAreaCache();
|
|
+ }
|
|
+ // Paper end - optimise checkDespawn
|
|
}
|
|
// Paper end
|
|
|
|
diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java
|
|
index 84dfa7efa4be86558c38ee9e6f70f87b5638173a..c2dec99102fa4c64c3c874f725cdc65845cd98d2 100644
|
|
--- a/src/main/java/net/minecraft/server/level/ChunkMap.java
|
|
+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java
|
|
@@ -157,6 +157,12 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
|
public final ReferenceOpenHashSet<ChunkHolder> needsChangeBroadcasting = new ReferenceOpenHashSet<>();
|
|
|
|
// Paper - rewrite chunk system
|
|
+ // Paper start - optimise checkDespawn
|
|
+ public static final int GENERAL_AREA_MAP_SQUARE_RADIUS = 40;
|
|
+ public static final double GENERAL_AREA_MAP_ACCEPTABLE_SEARCH_RANGE = 16.0 * (GENERAL_AREA_MAP_SQUARE_RADIUS - 1);
|
|
+ public static final double GENERAL_AREA_MAP_ACCEPTABLE_SEARCH_RANGE_SQUARED = GENERAL_AREA_MAP_ACCEPTABLE_SEARCH_RANGE * GENERAL_AREA_MAP_ACCEPTABLE_SEARCH_RANGE;
|
|
+ public final com.destroystokyo.paper.util.misc.PlayerAreaMap playerGeneralAreaMap;
|
|
+ // Paper end - optimise checkDespawn
|
|
|
|
// Paper start - distance maps
|
|
private final com.destroystokyo.paper.util.misc.PooledLinkedHashSets<ServerPlayer> pooledLinkedPlayerHashSets = new com.destroystokyo.paper.util.misc.PooledLinkedHashSets<>();
|
|
@@ -184,6 +190,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
|
this.playerMobDistanceMap.add(player, chunkX, chunkZ, io.papermc.paper.chunk.system.ChunkSystem.getTickViewDistance(player));
|
|
}
|
|
// Paper end - per player mob spawning
|
|
+ this.playerGeneralAreaMap.add(player, chunkX, chunkZ, GENERAL_AREA_MAP_SQUARE_RADIUS); // Paper - optimise checkDespawn
|
|
}
|
|
|
|
void removePlayerFromDistanceMaps(ServerPlayer player) {
|
|
@@ -193,6 +200,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
|
this.playerMobSpawnMap.remove(player);
|
|
this.playerChunkTickRangeMap.remove(player);
|
|
// Paper end - optimise ChunkMap#anyPlayerCloseEnoughForSpawning
|
|
+ this.playerGeneralAreaMap.remove(player); // Paper - optimise checkDespawns
|
|
// Paper start - per player mob spawning
|
|
if (this.playerMobDistanceMap != null) {
|
|
this.playerMobDistanceMap.remove(player);
|
|
@@ -211,6 +219,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
|
this.playerMobDistanceMap.update(player, chunkX, chunkZ, io.papermc.paper.chunk.system.ChunkSystem.getTickViewDistance(player));
|
|
}
|
|
// Paper end - per player mob spawning
|
|
+ this.playerGeneralAreaMap.update(player, chunkX, chunkZ, GENERAL_AREA_MAP_SQUARE_RADIUS); // Paper - optimise checkDespawn
|
|
}
|
|
// Paper end
|
|
// Paper start
|
|
@@ -329,6 +338,23 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
|
}
|
|
});
|
|
// Paper end - optimise ChunkMap#anyPlayerCloseEnoughForSpawning
|
|
+ // Paper start - optimise checkDespawn
|
|
+ this.playerGeneralAreaMap = 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) -> {
|
|
+ LevelChunk chunk = ChunkMap.this.level.getChunkSource().getChunkAtIfCachedImmediately(rangeX, rangeZ);
|
|
+ if (chunk != null) {
|
|
+ chunk.updateGeneralAreaCache(newState);
|
|
+ }
|
|
+ },
|
|
+ (ServerPlayer player, int rangeX, int rangeZ, int currPosX, int currPosZ, int prevPosX, int prevPosZ,
|
|
+ com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<ServerPlayer> newState) -> {
|
|
+ LevelChunk chunk = ChunkMap.this.level.getChunkSource().getChunkAtIfCachedImmediately(rangeX, rangeZ);
|
|
+ if (chunk != null) {
|
|
+ chunk.updateGeneralAreaCache(newState);
|
|
+ }
|
|
+ });
|
|
+ // Paper end - optimise checkDespawn
|
|
}
|
|
|
|
protected ChunkGenerator generator() {
|
|
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
|
index b1cc896a3f5d7e59a15969308d78d2ef036b0cb1..4bec4a6955d6c38c8bd8fb9a10d153209d693a01 100644
|
|
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
|
|
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
|
@@ -481,6 +481,84 @@ public class ServerLevel extends Level implements WorldGenLevel {
|
|
}
|
|
// Paper end
|
|
|
|
+ // Paper start - optimise checkDespawn
|
|
+ public final List<ServerPlayer> playersAffectingSpawning = new java.util.ArrayList<>();
|
|
+ // Paper end - optimise checkDespawn
|
|
+ // Paper start - optimise get nearest players for entity AI
|
|
+ @Override
|
|
+ public final ServerPlayer getNearestPlayer(net.minecraft.world.entity.ai.targeting.TargetingConditions condition, @Nullable LivingEntity source,
|
|
+ double centerX, double centerY, double centerZ) {
|
|
+ com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<ServerPlayer> nearby;
|
|
+ nearby = this.getChunkSource().chunkMap.playerGeneralAreaMap.getObjectsInRange(Mth.floor(centerX) >> 4, Mth.floor(centerZ) >> 4);
|
|
+
|
|
+ if (nearby == null) {
|
|
+ return null;
|
|
+ }
|
|
+
|
|
+ Object[] backingSet = nearby.getBackingSet();
|
|
+
|
|
+ double closestDistanceSquared = Double.MAX_VALUE;
|
|
+ ServerPlayer closest = null;
|
|
+
|
|
+ for (int i = 0, len = backingSet.length; i < len; ++i) {
|
|
+ Object _player = backingSet[i];
|
|
+ if (!(_player instanceof ServerPlayer)) {
|
|
+ continue;
|
|
+ }
|
|
+ ServerPlayer player = (ServerPlayer)_player;
|
|
+
|
|
+ double distanceSquared = player.distanceToSqr(centerX, centerY, centerZ);
|
|
+ if (distanceSquared < closestDistanceSquared && condition.test(source, player)) {
|
|
+ closest = player;
|
|
+ closestDistanceSquared = distanceSquared;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return closest;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public Player getNearestPlayer(net.minecraft.world.entity.ai.targeting.TargetingConditions pathfindertargetcondition, LivingEntity entityliving) {
|
|
+ return this.getNearestPlayer(pathfindertargetcondition, entityliving, entityliving.getX(), entityliving.getY(), entityliving.getZ());
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public Player getNearestPlayer(net.minecraft.world.entity.ai.targeting.TargetingConditions pathfindertargetcondition,
|
|
+ double d0, double d1, double d2) {
|
|
+ return this.getNearestPlayer(pathfindertargetcondition, null, d0, d1, d2);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public List<Player> getNearbyPlayers(net.minecraft.world.entity.ai.targeting.TargetingConditions condition, LivingEntity source, AABB axisalignedbb) {
|
|
+ com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<ServerPlayer> nearby;
|
|
+ double centerX = (axisalignedbb.maxX + axisalignedbb.minX) * 0.5;
|
|
+ double centerZ = (axisalignedbb.maxZ + axisalignedbb.minZ) * 0.5;
|
|
+ nearby = this.getChunkSource().chunkMap.playerGeneralAreaMap.getObjectsInRange(Mth.floor(centerX) >> 4, Mth.floor(centerZ) >> 4);
|
|
+
|
|
+ List<Player> ret = new java.util.ArrayList<>();
|
|
+
|
|
+ if (nearby == null) {
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
+ Object[] backingSet = nearby.getBackingSet();
|
|
+
|
|
+ for (int i = 0, len = backingSet.length; i < len; ++i) {
|
|
+ Object _player = backingSet[i];
|
|
+ if (!(_player instanceof ServerPlayer)) {
|
|
+ continue;
|
|
+ }
|
|
+ ServerPlayer player = (ServerPlayer)_player;
|
|
+
|
|
+ if (axisalignedbb.contains(player.getX(), player.getY(), player.getZ()) && condition.test(source, player)) {
|
|
+ ret.add(player);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return ret;
|
|
+ }
|
|
+ // Paper end - optimise get nearest players for entity AI
|
|
+
|
|
// Add env and gen to constructor, IWorldDataServer -> WorldDataServer
|
|
public ServerLevel(MinecraftServer minecraftserver, Executor executor, LevelStorageSource.LevelStorageAccess convertable_conversionsession, PrimaryLevelData iworlddataserver, ResourceKey<Level> resourcekey, LevelStem worlddimension, ChunkProgressListener worldloadlistener, boolean flag, long i, List<CustomSpawner> list, boolean flag1, @Nullable RandomSequences randomsequences, org.bukkit.World.Environment env, org.bukkit.generator.ChunkGenerator gen, org.bukkit.generator.BiomeProvider biomeProvider) {
|
|
// IRegistryCustom.Dimension iregistrycustom_dimension = minecraftserver.registryAccess(); // CraftBukkit - decompile error
|
|
@@ -606,6 +684,14 @@ public class ServerLevel extends Level implements WorldGenLevel {
|
|
}
|
|
|
|
public void tick(BooleanSupplier shouldKeepTicking) {
|
|
+ // Paper start - optimise checkDespawn
|
|
+ this.playersAffectingSpawning.clear();
|
|
+ for (ServerPlayer player : this.players) {
|
|
+ if (net.minecraft.world.entity.EntitySelector.PLAYER_AFFECTS_SPAWNING.test(player)) {
|
|
+ this.playersAffectingSpawning.add(player);
|
|
+ }
|
|
+ }
|
|
+ // Paper end - optimise checkDespawn
|
|
ProfilerFiller gameprofilerfiller = this.getProfiler();
|
|
|
|
this.handlingTick = true;
|
|
diff --git a/src/main/java/net/minecraft/world/entity/Mob.java b/src/main/java/net/minecraft/world/entity/Mob.java
|
|
index b6e48531a2a1316eef786e0476574eb1c3c29a9e..e2a25c29ec74147b3e66aa0b3deb85a8f6ee53a5 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/Mob.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/Mob.java
|
|
@@ -858,7 +858,12 @@ public abstract class Mob extends LivingEntity implements Targeting {
|
|
if (this.level().getDifficulty() == Difficulty.PEACEFUL && this.shouldDespawnInPeaceful()) {
|
|
this.discard();
|
|
} else if (!this.isPersistenceRequired() && !this.requiresCustomPersistence()) {
|
|
- Player entityhuman = this.level().findNearbyPlayer(this, -1.0D, EntitySelector.PLAYER_AFFECTS_SPAWNING); // Paper
|
|
+ // Paper start - optimise checkDespawn
|
|
+ Player entityhuman = this.level().findNearbyPlayer(this, level().paperConfig().entities.spawning.despawnRanges.get(this.getType().getCategory()).hard() + 1, EntitySelector.PLAYER_AFFECTS_SPAWNING); // Paper
|
|
+ if (entityhuman == null) {
|
|
+ entityhuman = ((ServerLevel)this.level()).playersAffectingSpawning.isEmpty() ? null : ((ServerLevel)this.level()).playersAffectingSpawning.get(0);
|
|
+ }
|
|
+ // Paper end - optimise checkDespawn
|
|
|
|
if (entityhuman != null) {
|
|
double d0 = entityhuman.distanceToSqr((Entity) this);
|
|
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
|
|
index 4847b6358e823bd53ecfaf7d82ed9e36d45b1233..799d31874be8a7498e71e7e01f84aa81a7f1eed4 100644
|
|
--- a/src/main/java/net/minecraft/world/level/Level.java
|
|
+++ b/src/main/java/net/minecraft/world/level/Level.java
|
|
@@ -206,6 +206,69 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
|
|
return this.getChunkIfLoaded(chunkX, chunkZ) != null;
|
|
}
|
|
// Paper end
|
|
+ // Paper start - optimise checkDespawn
|
|
+ public final List<net.minecraft.server.level.ServerPlayer> getNearbyPlayers(@Nullable Entity source, double sourceX, double sourceY,
|
|
+ double sourceZ, double maxRange, @Nullable Predicate<Entity> predicate) {
|
|
+ LevelChunk chunk;
|
|
+ if (maxRange < 0.0 || maxRange >= net.minecraft.server.level.ChunkMap.GENERAL_AREA_MAP_ACCEPTABLE_SEARCH_RANGE ||
|
|
+ (chunk = (LevelChunk)this.getChunkIfLoadedImmediately(Mth.floor(sourceX) >> 4, Mth.floor(sourceZ) >> 4)) == null) {
|
|
+ return this.getNearbyPlayersSlow(source, sourceX, sourceY, sourceZ, maxRange, predicate);
|
|
+ }
|
|
+
|
|
+ List<net.minecraft.server.level.ServerPlayer> ret = new java.util.ArrayList<>();
|
|
+ chunk.getNearestPlayers(sourceX, sourceY, sourceZ, predicate, maxRange, ret);
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
+ private List<net.minecraft.server.level.ServerPlayer> getNearbyPlayersSlow(@Nullable Entity source, double sourceX, double sourceY,
|
|
+ double sourceZ, double maxRange, @Nullable Predicate<Entity> predicate) {
|
|
+ List<net.minecraft.server.level.ServerPlayer> ret = new java.util.ArrayList<>();
|
|
+ double maxRangeSquared = maxRange * maxRange;
|
|
+
|
|
+ for (net.minecraft.server.level.ServerPlayer player : (List<net.minecraft.server.level.ServerPlayer>)this.players()) {
|
|
+ if ((maxRange < 0.0 || player.distanceToSqr(sourceX, sourceY, sourceZ) < maxRangeSquared)) {
|
|
+ if (predicate == null || predicate.test(player)) {
|
|
+ ret.add(player);
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
+ private net.minecraft.server.level.ServerPlayer getNearestPlayerSlow(@Nullable Entity source, double sourceX, double sourceY,
|
|
+ double sourceZ, double maxRange, @Nullable Predicate<Entity> predicate) {
|
|
+ net.minecraft.server.level.ServerPlayer closest = null;
|
|
+ double closestRangeSquared = maxRange < 0.0 ? Double.MAX_VALUE : maxRange * maxRange;
|
|
+
|
|
+ for (net.minecraft.server.level.ServerPlayer player : (List<net.minecraft.server.level.ServerPlayer>)this.players()) {
|
|
+ double distanceSquared = player.distanceToSqr(sourceX, sourceY, sourceZ);
|
|
+ if (distanceSquared < closestRangeSquared && (predicate == null || predicate.test(player))) {
|
|
+ closest = player;
|
|
+ closestRangeSquared = distanceSquared;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return closest;
|
|
+ }
|
|
+
|
|
+
|
|
+ public final net.minecraft.server.level.ServerPlayer getNearestPlayer(@Nullable Entity source, double sourceX, double sourceY,
|
|
+ double sourceZ, double maxRange, @Nullable Predicate<Entity> predicate) {
|
|
+ LevelChunk chunk;
|
|
+ if (maxRange < 0.0 || maxRange >= net.minecraft.server.level.ChunkMap.GENERAL_AREA_MAP_ACCEPTABLE_SEARCH_RANGE ||
|
|
+ (chunk = (LevelChunk)this.getChunkIfLoadedImmediately(Mth.floor(sourceX) >> 4, Mth.floor(sourceZ) >> 4)) == null) {
|
|
+ return this.getNearestPlayerSlow(source, sourceX, sourceY, sourceZ, maxRange, predicate);
|
|
+ }
|
|
+
|
|
+ return chunk.findNearestPlayer(sourceX, sourceY, sourceZ, maxRange, predicate);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public @Nullable Player getNearestPlayer(double d0, double d1, double d2, double d3, @Nullable Predicate<Entity> predicate) {
|
|
+ return this.getNearestPlayer(null, d0, d1, d2, d3, predicate);
|
|
+ }
|
|
+ // Paper end - optimise checkDespawn
|
|
|
|
public abstract ResourceKey<LevelStem> getTypeKey();
|
|
|
|
diff --git a/src/main/java/net/minecraft/world/level/NaturalSpawner.java b/src/main/java/net/minecraft/world/level/NaturalSpawner.java
|
|
index d4f99f4592a86e2d8344bc2c44711fef1543acdf..089dd93d4cd4c1f72e63c4944b3b82c1e2ba732d 100644
|
|
--- a/src/main/java/net/minecraft/world/level/NaturalSpawner.java
|
|
+++ b/src/main/java/net/minecraft/world/level/NaturalSpawner.java
|
|
@@ -260,7 +260,7 @@ public final class NaturalSpawner {
|
|
blockposition_mutableblockposition.set(l, i, i1);
|
|
double d0 = (double) l + 0.5D;
|
|
double d1 = (double) i1 + 0.5D;
|
|
- Player entityhuman = world.getNearestPlayer(d0, (double) i, d1, -1.0D, false);
|
|
+ Player entityhuman = (chunk instanceof LevelChunk) ? ((LevelChunk)chunk).findNearestPlayer(d0, i, d1, 576.0D, net.minecraft.world.entity.EntitySelector.NO_SPECTATORS) : world.getNearestPlayer(d0, (double) i, d1, -1.0D, false); // Paper - use chunk's player cache to optimize search in range
|
|
|
|
if (entityhuman != null) {
|
|
double d2 = entityhuman.distanceToSqr(d0, (double) i, d1);
|
|
@@ -334,7 +334,7 @@ public final class NaturalSpawner {
|
|
}
|
|
|
|
private static boolean isRightDistanceToPlayerAndSpawnPoint(ServerLevel world, ChunkAccess chunk, BlockPos.MutableBlockPos pos, double squaredDistance) {
|
|
- return squaredDistance <= 576.0D ? false : (world.getSharedSpawnPos().closerToCenterThan(new Vec3((double) pos.getX() + 0.5D, (double) pos.getY(), (double) pos.getZ() + 0.5D), 24.0D) ? false : Objects.equals(new ChunkPos(pos), chunk.getPos()) || world.isNaturalSpawningAllowed((BlockPos) pos));
|
|
+ return squaredDistance <= 576.0D ? false : (world.getSharedSpawnPos().closerToCenterThan(new Vec3((double) pos.getX() + 0.5D, (double) pos.getY(), (double) pos.getZ() + 0.5D), 24.0D) ? false : Objects.equals(new ChunkPos(pos), chunk.getPos()) || world.isNaturalSpawningAllowed((BlockPos) pos)); // Paper - diff on change, copy into caller
|
|
}
|
|
|
|
private static Boolean isValidSpawnPostitionForType(ServerLevel world, MobCategory group, StructureManager structureAccessor, ChunkGenerator chunkGenerator, MobSpawnSettings.SpawnerData spawnEntry, BlockPos.MutableBlockPos pos, double squaredDistance) { // Paper
|
|
diff --git a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
|
|
index 72da008040147bc080a3e61b926a9afaaca390dd..7568baab4bec3ded6456332ed0f6a20e2721b03f 100644
|
|
--- a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
|
|
+++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
|
|
@@ -221,6 +221,98 @@ public class LevelChunk extends ChunkAccess {
|
|
}
|
|
}
|
|
// Paper end
|
|
+ // Paper start - optimise checkDespawn
|
|
+ private boolean playerGeneralAreaCacheSet;
|
|
+ private com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<net.minecraft.server.level.ServerPlayer> playerGeneralAreaCache;
|
|
+
|
|
+ public com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<net.minecraft.server.level.ServerPlayer> getPlayerGeneralAreaCache() {
|
|
+ if (!this.playerGeneralAreaCacheSet) {
|
|
+ this.updateGeneralAreaCache();
|
|
+ }
|
|
+ return this.playerGeneralAreaCache;
|
|
+ }
|
|
+
|
|
+ public void updateGeneralAreaCache() {
|
|
+ this.updateGeneralAreaCache(((ServerLevel)this.level).getChunkSource().chunkMap.playerGeneralAreaMap.getObjectsInRange(this.coordinateKey));
|
|
+ }
|
|
+
|
|
+ public void removeGeneralAreaCache() {
|
|
+ this.playerGeneralAreaCacheSet = false;
|
|
+ this.playerGeneralAreaCache = null;
|
|
+ }
|
|
+
|
|
+ public void updateGeneralAreaCache(com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<net.minecraft.server.level.ServerPlayer> value) {
|
|
+ this.playerGeneralAreaCacheSet = true;
|
|
+ this.playerGeneralAreaCache = value;
|
|
+ }
|
|
+
|
|
+ public net.minecraft.server.level.ServerPlayer findNearestPlayer(double sourceX, double sourceY, double sourceZ,
|
|
+ double maxRange, java.util.function.Predicate<Entity> predicate) {
|
|
+ if (!this.playerGeneralAreaCacheSet) {
|
|
+ this.updateGeneralAreaCache();
|
|
+ }
|
|
+
|
|
+ com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<net.minecraft.server.level.ServerPlayer> nearby = this.playerGeneralAreaCache;
|
|
+
|
|
+ if (nearby == null) {
|
|
+ return null;
|
|
+ }
|
|
+
|
|
+ Object[] backingSet = nearby.getBackingSet();
|
|
+ double closestDistance = maxRange < 0.0 ? Double.MAX_VALUE : maxRange * maxRange;
|
|
+ net.minecraft.server.level.ServerPlayer closest = null;
|
|
+ for (int i = 0, len = backingSet.length; i < len; ++i) {
|
|
+ Object _player = backingSet[i];
|
|
+ if (!(_player instanceof net.minecraft.server.level.ServerPlayer)) {
|
|
+ continue;
|
|
+ }
|
|
+ net.minecraft.server.level.ServerPlayer player = (net.minecraft.server.level.ServerPlayer)_player;
|
|
+
|
|
+ double distance = player.distanceToSqr(sourceX, sourceY, sourceZ);
|
|
+ if (distance < closestDistance && predicate.test(player)) {
|
|
+ closest = player;
|
|
+ closestDistance = distance;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return closest;
|
|
+ }
|
|
+
|
|
+ public void getNearestPlayers(double sourceX, double sourceY, double sourceZ, java.util.function.Predicate<Entity> predicate,
|
|
+ double range, java.util.List<net.minecraft.server.level.ServerPlayer> ret) {
|
|
+ if (!this.playerGeneralAreaCacheSet) {
|
|
+ this.updateGeneralAreaCache();
|
|
+ }
|
|
+
|
|
+ com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<net.minecraft.server.level.ServerPlayer> nearby = this.playerGeneralAreaCache;
|
|
+
|
|
+ if (nearby == null) {
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ double rangeSquared = range * range;
|
|
+
|
|
+ Object[] backingSet = nearby.getBackingSet();
|
|
+ for (int i = 0, len = backingSet.length; i < len; ++i) {
|
|
+ Object _player = backingSet[i];
|
|
+ if (!(_player instanceof net.minecraft.server.level.ServerPlayer)) {
|
|
+ continue;
|
|
+ }
|
|
+ net.minecraft.server.level.ServerPlayer player = (net.minecraft.server.level.ServerPlayer)_player;
|
|
+
|
|
+ if (range >= 0.0) {
|
|
+ double distanceSquared = player.distanceToSqr(sourceX, sourceY, sourceZ);
|
|
+ if (distanceSquared > rangeSquared) {
|
|
+ continue;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (predicate == null || predicate.test(player)) {
|
|
+ ret.add(player);
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ // Paper end - optimise checkDespawn
|
|
|
|
public LevelChunk(ServerLevel world, ProtoChunk protoChunk, @Nullable LevelChunk.PostLoadProcessor entityLoader) {
|
|
this(world, protoChunk.getPos(), protoChunk.getUpgradeData(), protoChunk.unpackBlockTicks(), protoChunk.unpackFluidTicks(), protoChunk.getInhabitedTime(), protoChunk.getSections(), entityLoader, protoChunk.getBlendingData());
|