216 lines
		
	
	
	
		
			12 KiB
			
		
	
	
	
		
			Diff
		
	
	
	
	
	
			
		
		
	
	
			216 lines
		
	
	
	
		
			12 KiB
			
		
	
	
	
		
			Diff
		
	
	
	
	
	
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
 | 
						|
From: Spottedleaf <spottedleaf@spottedleaf.dev>
 | 
						|
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 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 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
 | 
						|
@@ -0,0 +0,0 @@ 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
 | 
						|
@@ -0,0 +0,0 @@ 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);
 | 
						|
     }
 | 
						|
 
 | 
						|
@@ -0,0 +0,0 @@ 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 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 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
 | 
						|
@@ -0,0 +0,0 @@ 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 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 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
 | 
						|
@@ -0,0 +0,0 @@ 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 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 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
 | 
						|
@@ -0,0 +0,0 @@ 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
 | 
						|
     }
 | 
						|
 }
 |