Paper/patches/server/1029-Optimise-nearby-player-retrieval.patch
Jake Potrebic 0cdce89d59
Fix a bunch of stuff with player spawn locations (#9887)
If a playerdata doesn't contain a valid, loaded world, reset
to the main world spawn point
2023-11-04 14:11:55 -07:00

163 lines
8.1 KiB
Diff

From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
Date: Sat, 23 Sep 2023 23:15:52 -0700
Subject: [PATCH] Optimise nearby player retrieval
Instead of searching/testing every player online on the server,
we can instead use the nearby player tracking system to reduce
the number of tests per search.
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
index ee6d9c19dbc01d46c60d0067664266c203087d8e..19ffb121934e9249d18fa53cae1ae892dfd7f8d4 100644
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
@@ -575,6 +575,115 @@ public class ServerLevel extends Level implements WorldGenLevel {
this.lagCompensationTick = (System.nanoTime() - net.minecraft.server.MinecraftServer.SERVER_INIT) / (java.util.concurrent.TimeUnit.MILLISECONDS.toNanos(50L));
}
// Paper end - lag compensation
+ // Paper start - optimise nearby player retrieval
+ @Override
+ public java.util.List<net.minecraft.world.entity.player.Player> getNearbyPlayers(net.minecraft.world.entity.ai.targeting.TargetingConditions targetPredicate,
+ net.minecraft.world.entity.LivingEntity entity,
+ net.minecraft.world.phys.AABB box) {
+ return this.getNearbyEntities(Player.class, targetPredicate, entity, box);
+ }
+
+ @Override
+ public Player getNearestPlayer(double x, double y, double z, double maxDistance, @Nullable Predicate<Entity> targetPredicate) {
+ if (maxDistance > 0.0D) {
+ io.papermc.paper.util.player.NearbyPlayers players = this.chunkSource.chunkMap.getNearbyPlayers();
+
+ com.destroystokyo.paper.util.maplist.ReferenceList<ServerPlayer> nearby = players.getPlayersByBlock(
+ io.papermc.paper.util.CoordinateUtils.getBlockCoordinate(x),
+ io.papermc.paper.util.CoordinateUtils.getBlockCoordinate(z),
+ io.papermc.paper.util.player.NearbyPlayers.NearbyMapType.GENERAL
+ );
+
+ if (nearby == null) {
+ return null;
+ }
+
+ ServerPlayer nearest = null;
+ double nearestDist = maxDistance * maxDistance;
+ Object[] rawData = nearby.getRawData();
+ for (int i = 0, len = nearby.size(); i < len; ++i) {
+ ServerPlayer player = (ServerPlayer)rawData[i];
+ double dist = player.distanceToSqr(x, y, z);
+ if (dist >= nearestDist) {
+ continue;
+ }
+
+ if (targetPredicate == null || targetPredicate.test(player)) {
+ nearest = player;
+ nearestDist = dist;
+ }
+ }
+
+ return nearest;
+ } else {
+ ServerPlayer nearest = null;
+ double nearestDist = Double.MAX_VALUE;
+
+ for (ServerPlayer player : this.players()) {
+ double dist = player.distanceToSqr(x, y, z);
+ if (dist >= nearestDist) {
+ continue;
+ }
+
+ if (targetPredicate == null || targetPredicate.test(player)) {
+ nearest = player;
+ nearestDist = dist;
+ }
+ }
+
+ return nearest;
+ }
+ }
+
+ @Override
+ public Player getNearestPlayer(net.minecraft.world.entity.ai.targeting.TargetingConditions targetPredicate, LivingEntity entity) {
+ return this.getNearestPlayer(targetPredicate, entity, entity.getX(), entity.getY(), entity.getZ());
+ }
+
+ @Override
+ public Player getNearestPlayer(net.minecraft.world.entity.ai.targeting.TargetingConditions targetPredicate, LivingEntity entity,
+ double x, double y, double z) {
+ double range = targetPredicate.range;
+ if (range > 0.0D) {
+ io.papermc.paper.util.player.NearbyPlayers players = this.chunkSource.chunkMap.getNearbyPlayers();
+
+ com.destroystokyo.paper.util.maplist.ReferenceList<ServerPlayer> nearby = players.getPlayersByBlock(
+ io.papermc.paper.util.CoordinateUtils.getBlockCoordinate(x),
+ io.papermc.paper.util.CoordinateUtils.getBlockCoordinate(z),
+ io.papermc.paper.util.player.NearbyPlayers.NearbyMapType.GENERAL
+ );
+
+ if (nearby == null) {
+ return null;
+ }
+
+ ServerPlayer nearest = null;
+ double nearestDist = Double.MAX_VALUE;
+ Object[] rawData = nearby.getRawData();
+ for (int i = 0, len = nearby.size(); i < len; ++i) {
+ ServerPlayer player = (ServerPlayer)rawData[i];
+ double dist = player.distanceToSqr(x, y, z);
+ if (dist >= nearestDist) {
+ continue;
+ }
+
+ if (targetPredicate.test(entity, player)) {
+ nearest = player;
+ nearestDist = dist;
+ }
+ }
+
+ return nearest;
+ } else {
+ return this.getNearestEntity(this.players(), targetPredicate, entity, x, y, z);
+ }
+ }
+
+ @Nullable
+ public Player getNearestPlayer(net.minecraft.world.entity.ai.targeting.TargetingConditions targetPredicate, double x, double y, double z) {
+ return this.getNearestPlayer(targetPredicate, null, x, y, z);
+ }
+ // Paper end - optimise nearby player retrieval
// 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) {
diff --git a/src/main/java/net/minecraft/world/entity/ai/targeting/TargetingConditions.java b/src/main/java/net/minecraft/world/entity/ai/targeting/TargetingConditions.java
index 58422f00c7d64dbd1cf6d7211c9838875cbe7778..c157309ac78e7af084d3acb6e8b2bcd469a39d5e 100644
--- a/src/main/java/net/minecraft/world/entity/ai/targeting/TargetingConditions.java
+++ b/src/main/java/net/minecraft/world/entity/ai/targeting/TargetingConditions.java
@@ -10,7 +10,7 @@ public class TargetingConditions {
public static final TargetingConditions DEFAULT = forCombat();
private static final double MIN_VISIBILITY_DISTANCE_FOR_INVISIBLE_TARGET = 2.0D;
private final boolean isCombat;
- private double range = -1.0D;
+ public double range = -1.0D; // Paper - public
private boolean checkLineOfSight = true;
private boolean testInvisible = true;
@Nullable
diff --git a/src/main/java/net/minecraft/world/level/EntityGetter.java b/src/main/java/net/minecraft/world/level/EntityGetter.java
index b3293a722fb5c5262a777402140c764c03367800..aaa07fcd4b32fe0de88142ab30378327a01f1729 100644
--- a/src/main/java/net/minecraft/world/level/EntityGetter.java
+++ b/src/main/java/net/minecraft/world/level/EntityGetter.java
@@ -230,9 +230,13 @@ public interface EntityGetter {
T livingEntity = null;
for(T livingEntity2 : entityList) {
+ // Paper start - move up
+ // don't check entities outside closest range
+ double e = livingEntity2.distanceToSqr(x, y, z);
+ if (d == -1.0D || e < d) {
+ // Paper end - move up
if (targetPredicate.test(entity, livingEntity2)) {
- double e = livingEntity2.distanceToSqr(x, y, z);
- if (d == -1.0D || e < d) {
+ // Paper - move up
d = e;
livingEntity = livingEntity2;
}