From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Spottedleaf 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 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 targetPredicate) { + if (maxDistance > 0.0D) { + io.papermc.paper.util.player.NearbyPlayers players = this.chunkSource.chunkMap.getNearbyPlayers(); + + com.destroystokyo.paper.util.maplist.ReferenceList 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 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 resourcekey, LevelStem worlddimension, ChunkProgressListener worldloadlistener, boolean flag, long i, List 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; }