PaperMC/patches/server/0734-Remove-streams-for-villager-AI.patch
Nassim Jahnke 928bcc8d3a
Updated Upstream (Bukkit/CraftBukkit) (#8430)
Upstream has released updates that appear to apply and compile correctly.
This update has not been tested by PaperMC and as with ANY update, please do your own testing

Bukkit Changes:
09943450 Update SnakeYAML version
5515734f SPIGOT-7162: Incorrect description for Entity#getVehicle javadoc
6f82b381 PR-788: Add getHand() to all relevant events

CraftBukkit Changes:
aaf484f6f SPIGOT-7163: CraftMerchantRecipe doesn't copy demand and specialPrice from BukkitMerchantRecipe
5329dd6fd PR-1107: Add getHand() to all relevant events
93061706e SPIGOT-7045: Ocelots never spawn with babies with spawn reason OCELOT_BABY
2022-10-02 09:56:36 +02:00

216 lines
12 KiB
Diff

From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
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 5a5d454b5987bb01d03f91c15b7a6bff46f1de71..c545539fc5d20cc69a0e5d2e261ef46a8f6fa4f0 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
@@ -30,11 +30,19 @@ public class GateBehavior<E extends LivingEntity> extends Behavior<E> {
@Override
protected boolean canStillUse(ServerLevel world, E entity, long time) {
- return this.behaviors.stream().filter((task) -> {
- return task.getStatus() == Behavior.Status.RUNNING;
- }).anyMatch((task) -> {
- return task.canStillUse(world, entity, time);
- });
+ // Paper start - remove streams
+ List<ShufflingList.WeightedEntry<Behavior<? super E>>> entries = this.behaviors.entries;
+ for (int i = 0; i < entries.size(); i++) {
+ ShufflingList.WeightedEntry<Behavior<? super E>> entry = entries.get(i);
+ Behavior<? super E> behavior = entry.getData();
+ if (behavior.getStatus() == Status.RUNNING) {
+ if (behavior.canStillUse(world, entity, time)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ // Paper end - remove streams
}
@Override
@@ -45,25 +53,35 @@ public class GateBehavior<E extends LivingEntity> extends Behavior<E> {
@Override
protected void start(ServerLevel world, E entity, long time) {
this.orderPolicy.apply(this.behaviors);
- this.runningPolicy.apply(this.behaviors.stream(), world, entity, time);
+ this.runningPolicy.apply(this.behaviors.entries, world, entity, time); // Paper - remove streams
}
@Override
protected void tick(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 - remove streams
+ List<ShufflingList.WeightedEntry<Behavior<? super E>>> entries = this.behaviors.entries;
+ for (int i = 0; i < entries.size(); i++) {
+ ShufflingList.WeightedEntry<Behavior<? super E>> entry = entries.get(i);
+ Behavior<? super E> behavior = entry.getData();
+ if (behavior.getStatus() == Status.RUNNING) {
+ behavior.tickOrStop(world, entity, time);
+ }
+ }
+ // Paper end - remove streams
}
@Override
protected void stop(ServerLevel world, E entity, long time) {
- this.behaviors.stream().filter((task) -> {
- return task.getStatus() == Behavior.Status.RUNNING;
- }).forEach((task) -> {
- task.doStop(world, entity, time);
- });
+ // Paper start - remove streams
+ List<ShufflingList.WeightedEntry<Behavior<? super E>>> entries = this.behaviors.entries;
+ for (int i = 0; i < entries.size(); i++) {
+ ShufflingList.WeightedEntry<Behavior<? super E>> entry = entries.get(i);
+ Behavior<? super E> behavior = entry.getData();
+ if (behavior.getStatus() == Status.RUNNING) {
+ behavior.doStop(world, entity, time);
+ }
+ }
+ // Paper end - remove streams
this.exitErasedMemories.forEach(entity.getBrain()::eraseMemory);
}
@@ -94,25 +112,33 @@ public class GateBehavior<E extends LivingEntity> extends Behavior<E> {
public static enum RunningPolicy {
RUN_ONE {
@Override
- public <E extends LivingEntity> void apply(Stream<Behavior<? super E>> 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 <E extends LivingEntity> void apply(List<ShufflingList.WeightedEntry<Behavior<? super E>>> tasks, ServerLevel world, E entity, long time) {
+ for (int i = 0; i < tasks.size(); i++) {
+ ShufflingList.WeightedEntry<Behavior<? super E>> task = tasks.get(i);
+ Behavior<? super E> behavior = task.getData();
+ if (behavior.getStatus() == Status.STOPPED && behavior.tryStart(world, entity, time)) {
+ break;
+ }
+ }
+ // Paper end - remove streams
}
},
TRY_ALL {
@Override
- public <E extends LivingEntity> void apply(Stream<Behavior<? super E>> 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 <E extends LivingEntity> void apply(List<ShufflingList.WeightedEntry<Behavior<? super E>>> tasks, ServerLevel world, E entity, long time) {
+ for (int i = 0; i < tasks.size(); i++) {
+ ShufflingList.WeightedEntry<Behavior<? super E>> task = tasks.get(i);
+ Behavior<? super E> behavior = task.getData();
+ if (behavior.getStatus() == Status.STOPPED) {
+ behavior.tryStart(world, entity, time);
+ }
+ }
+ // Paper end - remove streams
}
};
- public abstract <E extends LivingEntity> void apply(Stream<Behavior<? super E>> tasks, ServerLevel world, E entity, long time);
+ public abstract <E extends LivingEntity> void apply(List<ShufflingList.WeightedEntry<Behavior<? super E>>> 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 090bba46b6ecd7d0e1415feb678b9b23264fe5e9..ca771d60283d94c00aa65d06ef93071e412357e8 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
@@ -12,7 +12,7 @@ import java.util.stream.Stream;
import net.minecraft.util.RandomSource;
public class ShufflingList<U> {
- protected final List<ShufflingList.WeightedEntry<U>> entries;
+ public final List<ShufflingList.WeightedEntry<U>> 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..2c4517850a9692f1c2b1332b58e8312fe1166772 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<Mob> {
protected void doTick(ServerLevel world, Mob entity) {
Brain<?> brain = entity.getBrain();
List<ItemEntity> list = world.getEntitiesOfClass(ItemEntity.class, entity.getBoundingBox().inflate(32.0D, 16.0D, 32.0D), (itemEntity) -> {
- return true;
+ return itemEntity.closerThan(entity, 9.0D) && 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..75d9c4f011b5a97def215784c92bb57bbb35d06b 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,30 @@ public class PlayerSensor extends Sensor<LivingEntity> {
@Override
protected void doTick(ServerLevel world, LivingEntity entity) {
- List<Player> 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
+ List<Player> players = (List)world.getNearbyPlayers(entity, entity.getX(), entity.getY(), entity.getZ(), 16.0D, EntitySelector.NO_SPECTATORS);
+ 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
}
}