From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Spottedleaf Date: Thu, 27 Aug 2020 20:51:40 -0700 Subject: [PATCH] Remove streams for villager AI diff --git a/src/main/java/net/minecraft/world/entity/ai/behavior/GateBehavior.java b/src/main/java/net/minecraft/world/entity/ai/behavior/GateBehavior.java index b45c4f50705f80163d44d9e588f86a5770f5be38..879e16d4c881a97f95eeff8016f9900d6cfe10c2 100644 --- a/src/main/java/net/minecraft/world/entity/ai/behavior/GateBehavior.java +++ b/src/main/java/net/minecraft/world/entity/ai/behavior/GateBehavior.java @@ -52,7 +52,7 @@ public class GateBehavior implements BehaviorControl if (this.hasRequiredMemories(entity)) { this.status = Behavior.Status.RUNNING; this.orderPolicy.apply(this.behaviors); - this.runningPolicy.apply(this.behaviors.stream(), world, entity, time); + this.runningPolicy.apply(this.behaviors.entries, world, entity, time); return true; } else { return false; @@ -61,11 +61,13 @@ public class GateBehavior implements BehaviorControl @Override public final void tickOrStop(ServerLevel world, E entity, long time) { - this.behaviors.stream().filter((task) -> { - return task.getStatus() == Behavior.Status.RUNNING; - }).forEach((task) -> { - task.tickOrStop(world, entity, time); - }); + // Paper start + for (BehaviorControl task : this.behaviors) { + if (task.getStatus() == Behavior.Status.RUNNING) { + task.tickOrStop(world, entity, time); + } + } + // Paper end if (this.behaviors.stream().noneMatch((task) -> { return task.getStatus() == Behavior.Status.RUNNING; })) { @@ -77,11 +79,13 @@ public class GateBehavior implements BehaviorControl @Override public final void doStop(ServerLevel world, E entity, long time) { this.status = Behavior.Status.STOPPED; - this.behaviors.stream().filter((task) -> { - return task.getStatus() == Behavior.Status.RUNNING; - }).forEach((task) -> { - task.doStop(world, entity, time); - }); + // Paper start + for (BehaviorControl behavior : this.behaviors) { + if (behavior.getStatus() == Behavior.Status.RUNNING) { + behavior.doStop(world, entity, time); + } + } + // Paper end this.exitErasedMemories.forEach(entity.getBrain()::eraseMemory); } @@ -117,25 +121,31 @@ public class GateBehavior implements BehaviorControl public static enum RunningPolicy { RUN_ONE { @Override - public void apply(Stream> tasks, ServerLevel world, E entity, long time) { - tasks.filter((task) -> { - return task.getStatus() == Behavior.Status.STOPPED; - }).filter((task) -> { - return task.tryStart(world, entity, time); - }).findFirst(); + // Paper start - remove streams + public void apply(List>> tasks, ServerLevel world, E entity, long time) { + for (ShufflingList.WeightedEntry> task : tasks) { + final BehaviorControl behavior = task.getData(); + if (behavior.getStatus() == Behavior.Status.STOPPED && behavior.tryStart(world, entity, time)) { + break; + } + } + // Paper end - remove streams } }, TRY_ALL { @Override - public void apply(Stream> tasks, ServerLevel world, E entity, long time) { - tasks.filter((task) -> { - return task.getStatus() == Behavior.Status.STOPPED; - }).forEach((task) -> { - task.tryStart(world, entity, time); - }); + // Paper start - remove streams + public void apply(List>> tasks, ServerLevel world, E entity, long time) { + for (ShufflingList.WeightedEntry> task : tasks) { + final BehaviorControl behavior = task.getData(); + if (behavior.getStatus() == Behavior.Status.STOPPED) { + behavior.tryStart(world, entity, time); + } + } + // Paper end - remove streams } }; - public abstract void apply(Stream> tasks, ServerLevel world, E entity, long time); + public abstract void apply(List>> tasks, ServerLevel world, E entity, long time); // Paper - remove streams } } diff --git a/src/main/java/net/minecraft/world/entity/ai/behavior/ShufflingList.java b/src/main/java/net/minecraft/world/entity/ai/behavior/ShufflingList.java index 731ef21dbbd25d6924717de42f4569a9b5935643..fe3ab3d388f0481fb0db06b7f730f868dbf8e8a5 100644 --- a/src/main/java/net/minecraft/world/entity/ai/behavior/ShufflingList.java +++ b/src/main/java/net/minecraft/world/entity/ai/behavior/ShufflingList.java @@ -14,7 +14,7 @@ import java.util.stream.Stream; import net.minecraft.util.RandomSource; public class ShufflingList implements Iterable { - protected final List> entries; + public final List> entries; // Paper - public private final RandomSource random = RandomSource.create(); private final boolean isUnsafe; // Paper diff --git a/src/main/java/net/minecraft/world/entity/ai/sensing/NearestItemSensor.java b/src/main/java/net/minecraft/world/entity/ai/sensing/NearestItemSensor.java index 1dfcc5cba6ffb463acf161a23fff1ca452184290..61a164c5bfc86faa3f4d04a66e0257016cfd937d 100644 --- a/src/main/java/net/minecraft/world/entity/ai/sensing/NearestItemSensor.java +++ b/src/main/java/net/minecraft/world/entity/ai/sensing/NearestItemSensor.java @@ -25,13 +25,16 @@ public class NearestItemSensor extends Sensor { protected void doTick(ServerLevel world, Mob entity) { Brain brain = entity.getBrain(); List list = world.getEntitiesOfClass(ItemEntity.class, entity.getBoundingBox().inflate(32.0D, 16.0D, 32.0D), (itemEntity) -> { - return true; + return itemEntity.closerThan(entity, MAX_DISTANCE_TO_WANTED_ITEM) && entity.wantsToPickUp(itemEntity.getItem()); // Paper - move predicate into getEntities }); - list.sort(Comparator.comparingDouble(entity::distanceToSqr)); + list.sort((e1, e2) -> Double.compare(entity.distanceToSqr(e1), entity.distanceToSqr(e2))); // better to take the sort perf hit than using line of sight more than we need to. + // Paper start - remove streams // Paper start - remove streams in favour of lists ItemEntity nearest = null; - for (ItemEntity entityItem : list) { - if (entity.wantsToPickUp(entityItem.getItem()) && entityItem.closerThan(entity, 32.0D) && entity.hasLineOfSight(entityItem)) { + for (int i = 0; i < list.size(); i++) { + ItemEntity entityItem = list.get(i); + if (entity.hasLineOfSight(entityItem)) { + // Paper end - remove streams nearest = entityItem; break; } diff --git a/src/main/java/net/minecraft/world/entity/ai/sensing/PlayerSensor.java b/src/main/java/net/minecraft/world/entity/ai/sensing/PlayerSensor.java index 312775d0430f793720211dc29bb293503e799d11..9c6b1027dcda0ff4fd357d3cb70fcf5b9f6127a0 100644 --- a/src/main/java/net/minecraft/world/entity/ai/sensing/PlayerSensor.java +++ b/src/main/java/net/minecraft/world/entity/ai/sensing/PlayerSensor.java @@ -21,25 +21,51 @@ public class PlayerSensor extends Sensor { @Override protected void doTick(ServerLevel world, LivingEntity entity) { - List players = new java.util.ArrayList<>(world.players()); - players.removeIf(player -> !EntitySelector.NO_SPECTATORS.test(player) || !entity.closerThan(player, 16.0D)); - players.sort(Comparator.comparingDouble(entity::distanceTo)); + // Paper start - remove streams + io.papermc.paper.util.player.NearbyPlayers nearbyPlayers = world.chunkSource.chunkMap.getNearbyPlayers(); + net.minecraft.world.phys.Vec3 entityPos = entity.position(); + com.destroystokyo.paper.util.maplist.ReferenceList nearby = nearbyPlayers.getPlayersByChunk( + entity.chunkPosition().x, + entity.chunkPosition().z, + io.papermc.paper.util.player.NearbyPlayers.NearbyMapType.GENERAL_REALLY_SMALL + ); + + List players = new java.util.ArrayList<>(nearby == null ? 0 : nearby.size()); + if (nearby != null) { + Object[] rawData = nearby.getRawData(); + for (int index = 0, len = nearby.size(); index < len; ++index) { + net.minecraft.server.level.ServerPlayer player = (net.minecraft.server.level.ServerPlayer)rawData[index]; + if (player.isSpectator()) { + continue; + } + if (player.distanceToSqr(entityPos.x, entityPos.y, entityPos.z) >= (16.0 * 16.0)) { + continue; + } + players.add((Player)player); + } + } + players.sort((e1, e2) -> Double.compare(entity.distanceToSqr(e1), entity.distanceToSqr(e2))); Brain brain = entity.getBrain(); brain.setMemory(MemoryModuleType.NEAREST_PLAYERS, players); - Player nearest = null, nearestTargetable = null; - for (Player player : players) { - if (Sensor.isEntityTargetable(entity, player)) { - if (nearest == null) nearest = player; - if (Sensor.isEntityAttackable(entity, player)) { - nearestTargetable = player; - break; // Both variables are assigned, no reason to loop further - } + Player firstTargetable = null; + Player firstAttackable = null; + for (int index = 0, len = players.size(); index < len; ++index) { + Player player = players.get(index); + if (firstTargetable == null && isEntityTargetable(entity, player)) { + firstTargetable = player; + } + if (firstAttackable == null && isEntityAttackable(entity, player)) { + firstAttackable = player; + } + + if (firstAttackable != null && firstTargetable != null) { + break; } } - brain.setMemory(MemoryModuleType.NEAREST_VISIBLE_PLAYER, nearest); - brain.setMemory(MemoryModuleType.NEAREST_VISIBLE_ATTACKABLE_PLAYER, nearestTargetable); - // Paper end + brain.setMemory(MemoryModuleType.NEAREST_VISIBLE_PLAYER, firstTargetable); + brain.setMemory(MemoryModuleType.NEAREST_VISIBLE_ATTACKABLE_PLAYER, Optional.ofNullable(firstAttackable)); + // Paper end - remove streams } }