From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Spottedleaf <spottedleaf@spottedleaf.dev>
Date: Mon, 6 Apr 2020 17:53:29 -0700
Subject: [PATCH] Remove streams from Mob AI System

The streams hurt performance and allocate tons of garbage, so
replace them with the standard iterator.

Also optimise the stream.anyMatch statement to move to a bitset
where we can replace the call with a single bitwise operation.

diff --git a/src/main/java/net/minecraft/world/entity/ai/goal/PathfinderGoal.java b/src/main/java/net/minecraft/world/entity/ai/goal/PathfinderGoal.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/world/entity/ai/goal/PathfinderGoal.java
+++ b/src/main/java/net/minecraft/world/entity/ai/goal/PathfinderGoal.java
@@ -0,0 +0,0 @@
 package net.minecraft.world.entity.ai.goal;
 
+import com.destroystokyo.paper.util.set.OptimizedSmallEnumSet; // Paper - remove streams from pathfindergoalselector
 import java.util.EnumSet;
 
 public abstract class PathfinderGoal {
 
-    private final EnumSet<PathfinderGoal.Type> a = EnumSet.noneOf(PathfinderGoal.Type.class);
+    private final EnumSet<PathfinderGoal.Type> a = EnumSet.noneOf(PathfinderGoal.Type.class); // Paper unused, but dummy to prevent plugins from crashing as hard. Theyll need to support paper in a special case if this is super important, but really doesn't seem like it would be.
+    private final OptimizedSmallEnumSet<Type> goalTypes = new OptimizedSmallEnumSet<>(PathfinderGoal.Type.class); // Paper - remove streams from pathfindergoalselector
 
     public PathfinderGoal() {}
 
@@ -0,0 +0,0 @@ public abstract class PathfinderGoal {
     public void e() {}
 
     public void a(EnumSet<PathfinderGoal.Type> enumset) {
-        this.a.clear();
-        this.a.addAll(enumset);
+        // Paper start - remove streams from pathfindergoalselector
+        this.goalTypes.clear();
+        this.goalTypes.addAllUnchecked(enumset);
+        // Paper end - remove streams from pathfindergoalselector
     }
 
     public String toString() {
         return this.getClass().getSimpleName();
     }
 
-    public EnumSet<PathfinderGoal.Type> i() {
-        return this.a;
+    // Paper start - remove streams from pathfindergoalselector
+    public com.destroystokyo.paper.util.set.OptimizedSmallEnumSet<PathfinderGoal.Type> getGoalTypes() {
+        return this.goalTypes;
+        // Paper end - remove streams from pathfindergoalselector
     }
 
     public static enum Type {
diff --git a/src/main/java/net/minecraft/world/entity/ai/goal/PathfinderGoalSelector.java b/src/main/java/net/minecraft/world/entity/ai/goal/PathfinderGoalSelector.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/world/entity/ai/goal/PathfinderGoalSelector.java
+++ b/src/main/java/net/minecraft/world/entity/ai/goal/PathfinderGoalSelector.java
@@ -0,0 +0,0 @@
 package net.minecraft.world.entity.ai.goal;
 
+import com.destroystokyo.paper.util.set.OptimizedSmallEnumSet; // Paper - remove streams from pathfindergoalselector
 import com.google.common.collect.Sets;
 import java.util.EnumMap;
 import java.util.EnumSet;
+import java.util.Iterator; // Paper - remove streams from pathfindergoalselector
 import java.util.Map;
 import java.util.Set;
 import java.util.function.Supplier;
@@ -0,0 +0,0 @@ public class PathfinderGoalSelector {
     private final Map<PathfinderGoal.Type, PathfinderGoalWrapped> c = new EnumMap(PathfinderGoal.Type.class);
     private final Set<PathfinderGoalWrapped> d = Sets.newLinkedHashSet(); private Set<PathfinderGoalWrapped> getTasks() { return d; }// Paper - OBFHELPER
     private final Supplier<GameProfilerFiller> e;
-    private final EnumSet<PathfinderGoal.Type> f = EnumSet.noneOf(PathfinderGoal.Type.class);
+    private final EnumSet<PathfinderGoal.Type> f = EnumSet.noneOf(PathfinderGoal.Type.class); // Paper unused, but dummy to prevent plugins from crashing as hard. Theyll need to support paper in a special case if this is super important, but really doesn't seem like it would be.
+    private final OptimizedSmallEnumSet<PathfinderGoal.Type> goalTypes = new OptimizedSmallEnumSet<>(PathfinderGoal.Type.class); // Paper - remove streams from pathfindergoalselector
     private int g = 3;private int getTickRate() { return g; } // Paper - OBFHELPER
     private int curRate;private int getCurRate() { return curRate; } private void incRate() { this.curRate++; } // Paper TODO
 
@@ -0,0 +0,0 @@ public class PathfinderGoalSelector {
     // Paper end
 
     public void a(PathfinderGoal pathfindergoal) {
-        this.d.stream().filter((pathfindergoalwrapped) -> {
-            return pathfindergoalwrapped.j() == pathfindergoal;
-        }).filter(PathfinderGoalWrapped::g).forEach(PathfinderGoalWrapped::d);
-        this.d.removeIf((pathfindergoalwrapped) -> {
-            return pathfindergoalwrapped.j() == pathfindergoal;
-        });
+        // Paper start - remove streams from pathfindergoalselector
+        for (Iterator<PathfinderGoalWrapped> iterator = this.d.iterator(); iterator.hasNext();) {
+            PathfinderGoalWrapped goalWrapped = iterator.next();
+            if (goalWrapped.j() != pathfindergoal) {
+                continue;
+            }
+            if (goalWrapped.g()) {
+                goalWrapped.d();
+            }
+            iterator.remove();
+        }
+        // Paper end - remove streams from pathfindergoalselector
     }
 
+    private static final PathfinderGoal.Type[] PATHFINDER_GOAL_TYPES = PathfinderGoal.Type.values(); // Paper - remove streams from pathfindergoalselector
+
     public void doTick() {
         GameProfilerFiller gameprofilerfiller = (GameProfilerFiller) this.e.get();
 
         gameprofilerfiller.enter("goalCleanup");
-        this.d().filter((pathfindergoalwrapped) -> {
-            boolean flag;
-
-            if (pathfindergoalwrapped.g()) {
-                Stream stream = pathfindergoalwrapped.i().stream();
-                EnumSet enumset = this.f;
-
-                this.f.getClass();
-                if (!stream.anyMatch(enumset::contains) && pathfindergoalwrapped.b()) {
-                    flag = false;
-                    return flag;
-                }
+        // Paper start - remove streams from pathfindergoalselector
+        for (Iterator<PathfinderGoalWrapped> iterator = this.d.iterator(); iterator.hasNext();) {
+            PathfinderGoalWrapped wrappedGoal = iterator.next();
+            if (!wrappedGoal.g()) {
+                continue;
             }
-
-            flag = true;
-            return flag;
-        }).forEach(PathfinderGoal::d);
+            if (!this.goalTypes.hasCommonElements(wrappedGoal.getGoalTypes()) && wrappedGoal.b()) {
+                continue;
+            }
+            wrappedGoal.d();
+        }
+        // Paper end - remove streams from pathfindergoalselector
         this.c.forEach((pathfindergoal_type, pathfindergoalwrapped) -> {
             if (!pathfindergoalwrapped.g()) {
                 this.c.remove(pathfindergoal_type);
@@ -0,0 +0,0 @@ public class PathfinderGoalSelector {
         });
         gameprofilerfiller.exit();
         gameprofilerfiller.enter("goalUpdate");
-        this.d.stream().filter((pathfindergoalwrapped) -> {
-            return !pathfindergoalwrapped.g();
-        }).filter((pathfindergoalwrapped) -> {
-            Stream stream = pathfindergoalwrapped.i().stream();
-            EnumSet enumset = this.f;
-
-            this.f.getClass();
-            return stream.noneMatch(enumset::contains);
-        }).filter((pathfindergoalwrapped) -> {
-            return pathfindergoalwrapped.i().stream().allMatch((pathfindergoal_type) -> {
-                return ((PathfinderGoalWrapped) this.c.getOrDefault(pathfindergoal_type, PathfinderGoalSelector.b)).a(pathfindergoalwrapped);
-            });
-        }).filter(PathfinderGoalWrapped::a).forEach((pathfindergoalwrapped) -> {
-            pathfindergoalwrapped.i().forEach((pathfindergoal_type) -> {
-                PathfinderGoalWrapped pathfindergoalwrapped1 = (PathfinderGoalWrapped) this.c.getOrDefault(pathfindergoal_type, PathfinderGoalSelector.b);
-
-                pathfindergoalwrapped1.d();
-                this.c.put(pathfindergoal_type, pathfindergoalwrapped);
-            });
-            pathfindergoalwrapped.c();
-        });
+        // Paper start - remove streams from pathfindergoalselector
+        goal_update_loop: for (Iterator<PathfinderGoalWrapped> iterator = this.d.iterator(); iterator.hasNext();) {
+            PathfinderGoalWrapped wrappedGoal = iterator.next();
+            if (wrappedGoal.g()) {
+                continue;
+            }
+
+            OptimizedSmallEnumSet<PathfinderGoal.Type> wrappedGoalSet = wrappedGoal.getGoalTypes();
+
+            if (this.goalTypes.hasCommonElements(wrappedGoalSet)) {
+                continue;
+            }
+
+            long iterator1 = wrappedGoalSet.getBackingSet();
+            int wrappedGoalSize = wrappedGoalSet.size();
+            for (int i = 0; i < wrappedGoalSize; ++i) {
+                PathfinderGoal.Type type = PATHFINDER_GOAL_TYPES[Long.numberOfTrailingZeros(iterator1)];
+                iterator1 ^= com.destroystokyo.paper.util.math.IntegerUtil.getTrailingBit(iterator1);
+                PathfinderGoalWrapped wrapped = this.c.getOrDefault(type, PathfinderGoalSelector.b);
+                if (!wrapped.a(wrappedGoal)) {
+                    continue goal_update_loop;
+                }
+            }
+
+            if (!wrappedGoal.a()) {
+                continue;
+            }
+
+            iterator1 = wrappedGoalSet.getBackingSet();
+            wrappedGoalSize = wrappedGoalSet.size();
+            for (int i = 0; i < wrappedGoalSize; ++i) {
+                PathfinderGoal.Type type = PATHFINDER_GOAL_TYPES[Long.numberOfTrailingZeros(iterator1)];
+                iterator1 ^= com.destroystokyo.paper.util.math.IntegerUtil.getTrailingBit(iterator1);
+                PathfinderGoalWrapped wrapped = this.c.getOrDefault(type, PathfinderGoalSelector.b);
+
+                wrapped.d();
+                this.c.put(type, wrappedGoal);
+            }
+
+            wrappedGoal.c();
+        }
+        // Paper end - remove streams from pathfindergoalselector
         gameprofilerfiller.exit();
         gameprofilerfiller.enter("goalTick");
-        this.d().forEach(PathfinderGoalWrapped::e);
+        // Paper start - remove streams from pathfindergoalselector
+        for (Iterator<PathfinderGoalWrapped> iterator = this.d.iterator(); iterator.hasNext();) {
+            PathfinderGoalWrapped wrappedGoal = iterator.next();
+            if (wrappedGoal.g()) {
+                wrappedGoal.e();
+            }
+        }
+        // Paper end - remove streams from pathfindergoalselector
         gameprofilerfiller.exit();
     }
 
@@ -0,0 +0,0 @@ public class PathfinderGoalSelector {
     }
 
     public void a(PathfinderGoal.Type pathfindergoal_type) {
-        this.f.add(pathfindergoal_type);
+        this.goalTypes.addUnchecked(pathfindergoal_type); // Paper - remove streams from pathfindergoalselector
     }
 
     public void b(PathfinderGoal.Type pathfindergoal_type) {
-        this.f.remove(pathfindergoal_type);
+        this.goalTypes.removeUnchecked(pathfindergoal_type); // Paper - remove streams from pathfindergoalselector
     }
 
     public void a(PathfinderGoal.Type pathfindergoal_type, boolean flag) {
diff --git a/src/main/java/net/minecraft/world/entity/ai/goal/PathfinderGoalWrapped.java b/src/main/java/net/minecraft/world/entity/ai/goal/PathfinderGoalWrapped.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/world/entity/ai/goal/PathfinderGoalWrapped.java
+++ b/src/main/java/net/minecraft/world/entity/ai/goal/PathfinderGoalWrapped.java
@@ -0,0 +0,0 @@ public class PathfinderGoalWrapped extends PathfinderGoal {
         this.a.a(enumset);
     }
 
-    @Override
-    public EnumSet<PathfinderGoal.Type> i() {
-        return this.a.i();
+    // Paper start - remove streams from pathfindergoalselector
+    public com.destroystokyo.paper.util.set.OptimizedSmallEnumSet<PathfinderGoal.Type> getGoalTypes() {
+        return this.a.getGoalTypes();
+        // Paper end - remove streams from pathfindergoalselector
     }
 
     public boolean isRunning() { return this.g(); } // Paper - OBFHELPER