diff --git a/Spigot-Server-Patches/0004-MC-Utils.patch b/Spigot-Server-Patches/0004-MC-Utils.patch
index d4a9460d95..5684a4e733 100644
--- a/Spigot-Server-Patches/0004-MC-Utils.patch
+++ b/Spigot-Server-Patches/0004-MC-Utils.patch
@@ -1,4 +1,4 @@
-From c9458dab207ad176a4dc2eb7ca23055d54c0b22c Mon Sep 17 00:00:00 2001
+From 75ae35c120230e8fbc4a20f7472276d0f398e21a Mon Sep 17 00:00:00 2001
 From: Aikar <aikar@aikar.co>
 Date: Mon, 28 Mar 2016 20:55:47 -0400
 Subject: [PATCH] MC Utils
@@ -815,6 +815,242 @@ index 0000000000..c2f7e4ca0f
 +        return this.map.values().iterator();
 +    }
 +}
+diff --git a/src/main/java/com/destroystokyo/paper/util/math/IntegerUtil.java b/src/main/java/com/destroystokyo/paper/util/math/IntegerUtil.java
+new file mode 100644
+index 0000000000..c3b936f54b
+--- /dev/null
++++ b/src/main/java/com/destroystokyo/paper/util/math/IntegerUtil.java
+@@ -0,0 +1,230 @@
++package com.destroystokyo.paper.util.math;
++
++/**
++ * @author Spottedleaf <Spottedleaf@users.noreply.github.com>
++ */
++public final class IntegerUtil {
++
++    public static final int HIGH_BIT_U32 = Integer.MIN_VALUE;
++    public static final long HIGH_BIT_U64 = Long.MIN_VALUE;
++
++    public static int ceilLog2(final int value) {
++        return Integer.SIZE - Integer.numberOfLeadingZeros(value - 1); // see doc of numberOfLeadingZeros
++    }
++
++    public static long ceilLog2(final long value) {
++        return Long.SIZE - Long.numberOfLeadingZeros(value - 1); // see doc of numberOfLeadingZeros
++    }
++
++    public static int floorLog2(final int value) {
++        // xor is optimized subtract for 2^n -1
++        // note that (2^n -1) - k = (2^n -1) ^ k for k <= (2^n - 1)
++        return (Integer.SIZE - 1) ^ Integer.numberOfLeadingZeros(value); // see doc of numberOfLeadingZeros
++    }
++
++    public static int floorLog2(final long value) {
++        // xor is optimized subtract for 2^n -1
++        // note that (2^n -1) - k = (2^n -1) ^ k for k <= (2^n - 1)
++        return (Long.SIZE - 1) ^ Long.numberOfLeadingZeros(value); // see doc of numberOfLeadingZeros
++    }
++
++    public static int roundCeilLog2(final int value) {
++        // optimized variant of 1 << (32 - leading(val - 1))
++        // given
++        // 1 << n = HIGH_BIT_32 >>> (31 - n) for n [0, 32)
++        // 1 << (32 - leading(val - 1)) = HIGH_BIT_32 >>> (31 - (32 - leading(val - 1)))
++        // HIGH_BIT_32 >>> (31 - (32 - leading(val - 1)))
++        // HIGH_BIT_32 >>> (31 - 32 + leading(val - 1))
++        // HIGH_BIT_32 >>> (-1 + leading(val - 1))
++        return HIGH_BIT_U32 >>> (Integer.numberOfLeadingZeros(value - 1) - 1);
++    }
++
++    public static long roundCeilLog2(final long value) {
++        // see logic documented above
++        return HIGH_BIT_U64 >>> (Long.numberOfLeadingZeros(value - 1) - 1);
++    }
++
++    public static int roundFloorLog2(final int value) {
++        // optimized variant of 1 << (31 - leading(val))
++        // given
++        // 1 << n = HIGH_BIT_32 >>> (31 - n) for n [0, 32)
++        // 1 << (31 - leading(val)) = HIGH_BIT_32 >> (31 - (31 - leading(val)))
++        // HIGH_BIT_32 >> (31 - (31 - leading(val)))
++        // HIGH_BIT_32 >> (31 - 31 + leading(val))
++        return HIGH_BIT_U32 >>> Integer.numberOfLeadingZeros(value);
++    }
++
++    public static long roundFloorLog2(final long value) {
++        // see logic documented above
++        return HIGH_BIT_U64 >>> Long.numberOfLeadingZeros(value);
++    }
++
++    public static boolean isPowerOfTwo(final int n) {
++        // 2^n has one bit
++        // note: this rets true for 0 still
++        return IntegerUtil.getTrailingBit(n) == n;
++    }
++
++    public static boolean isPowerOfTwo(final long n) {
++        // 2^n has one bit
++        // note: this rets true for 0 still
++        return IntegerUtil.getTrailingBit(n) == n;
++    }
++
++
++    public static int getTrailingBit(final int n) {
++        return -n & n;
++    }
++
++    public static long getTrailingBit(final long n) {
++        return -n & n;
++    }
++
++    public static int trailingZeros(final int n) {
++        return Integer.numberOfTrailingZeros(n);
++    }
++
++    public static long trailingZeros(final long n) {
++        return Long.numberOfTrailingZeros(n);
++    }
++
++    // from hacker's delight (signed division magic value)
++    public static int getDivisorMultiple(final long numbers) {
++        return (int)(numbers >>> 32);
++    }
++
++    // from hacker's delight (signed division magic value)
++    public static int getDivisorShift(final long numbers) {
++        return (int)numbers;
++    }
++
++    // copied from hacker's delight (signed division magic value)
++    // http://www.hackersdelight.org/hdcodetxt/magic.c.txt
++    public static long getDivisorNumbers(final int d) {
++        final int ad = IntegerUtil.branchlessAbs(d);
++
++        if (ad < 2) {
++            throw new IllegalArgumentException("|number| must be in [2, 2^31 -1], not: " + d);
++        }
++
++        final int two31 = 0x80000000;
++        final long mask = 0xFFFFFFFFL; // mask for enforcing unsigned behaviour
++
++        int p = 31;
++
++        // all these variables are UNSIGNED!
++        int t = two31 + (d >>> 31);
++        int anc = t - 1 - t%ad;
++        int q1 = (int)((two31 & mask)/(anc & mask));
++        int r1 = two31 - q1*anc;
++        int q2 = (int)((two31 & mask)/(ad & mask));
++        int r2 = two31 - q2*ad;
++        int delta;
++
++        do {
++            p = p + 1;
++            q1 = 2*q1;                        // Update q1 = 2**p/|nc|.
++            r1 = 2*r1;                        // Update r1 = rem(2**p, |nc|).
++            if ((r1 & mask) >= (anc & mask)) {// (Must be an unsigned comparison here)
++                q1 = q1 + 1;
++                r1 = r1 - anc;
++            }
++            q2 = 2*q2;                       // Update q2 = 2**p/|d|.
++            r2 = 2*r2;                       // Update r2 = rem(2**p, |d|).
++            if ((r2 & mask) >= (ad & mask)) {// (Must be an unsigned comparison here)
++                q2 = q2 + 1;
++                r2 = r2 - ad;
++            }
++            delta = ad - r2;
++        } while ((q1 & mask) < (delta & mask) || (q1 == delta && r1 == 0));
++
++        int magicNum = q2 + 1;
++        if (d < 0) {
++            magicNum = -magicNum;
++        }
++        int shift = p - 32;
++        return ((long)magicNum << 32) | shift;
++    }
++
++    public static int branchlessAbs(final int val) {
++        // -n = -1 ^ n + 1
++        final int mask = val >> (Integer.SIZE - 1); // -1 if < 0, 0 if >= 0
++        return (mask ^ val) - mask; // if val < 0, then (0 ^ val) - 0 else (-1 ^ val) + 1
++    }
++
++    public static long branchlessAbs(final long val) {
++        // -n = -1 ^ n + 1
++        final long mask = val >> (Long.SIZE - 1); // -1 if < 0, 0 if >= 0
++        return (mask ^ val) - mask; // if val < 0, then (0 ^ val) - 0 else (-1 ^ val) + 1
++    }
++
++    //https://github.com/skeeto/hash-prospector for hash functions
++
++    //score = ~590.47984224483832
++    public static int hash0(int x) {
++        x *= 0x36935555;
++        x ^= x >>> 16;
++        return x;
++    }
++
++    //score = ~310.01596637036749
++    public static int hash1(int x) {
++        x ^= x >>> 15;
++        x *= 0x356aaaad;
++        x ^= x >>> 17;
++        return x;
++    }
++
++    public static int hash2(int x) {
++        x ^= x >>> 16;
++        x *= 0x7feb352d;
++        x ^= x >>> 15;
++        x *= 0x846ca68b;
++        x ^= x >>> 16;
++        return x;
++    }
++
++    public static int hash3(int x) {
++        x ^= x >>> 17;
++        x *= 0xed5ad4bb;
++        x ^= x >>> 11;
++        x *= 0xac4c1b51;
++        x ^= x >>> 15;
++        x *= 0x31848bab;
++        x ^= x >>> 14;
++        return x;
++    }
++
++    //score = ~365.79959673201887
++    public static long hash1(long x) {
++        x ^= x >>> 27;
++        x *= 0xb24924b71d2d354bL;
++        x ^= x >>> 28;
++        return x;
++    }
++
++    //h2 hash
++    public static long hash2(long x) {
++        x ^= x >>> 32;
++        x *= 0xd6e8feb86659fd93L;
++        x ^= x >>> 32;
++        x *= 0xd6e8feb86659fd93L;
++        x ^= x >>> 32;
++        return x;
++    }
++
++    public static long hash3(long x) {
++        x ^= x >>> 45;
++        x *= 0xc161abe5704b6c79L;
++        x ^= x >>> 41;
++        x *= 0xe3e5389aedbc90f7L;
++        x ^= x >>> 56;
++        x *= 0x1f9aba75a52db073L;
++        x ^= x >>> 53;
++        return x;
++    }
++
++    private IntegerUtil() {
++        throw new RuntimeException();
++    }
++}
 diff --git a/src/main/java/com/destroystokyo/paper/util/misc/AreaMap.java b/src/main/java/com/destroystokyo/paper/util/misc/AreaMap.java
 new file mode 100644
 index 0000000000..5a44bc644b
@@ -1540,15 +1776,17 @@ index 0000000000..5f2d88797d
 +}
 diff --git a/src/main/java/com/destroystokyo/paper/util/set/OptimizedSmallEnumSet.java b/src/main/java/com/destroystokyo/paper/util/set/OptimizedSmallEnumSet.java
 new file mode 100644
-index 0000000000..4d74a7a908
+index 0000000000..9df0006c1a
 --- /dev/null
 +++ b/src/main/java/com/destroystokyo/paper/util/set/OptimizedSmallEnumSet.java
-@@ -0,0 +1,65 @@
+@@ -0,0 +1,67 @@
 +package com.destroystokyo.paper.util.set;
 +
 +import java.util.Collection;
 +
-+// containing utils to work on small numbers of enums
++/**
++ * @author Spottedleaf <Spottedleaf@users.noreply.github.com>
++ */
 +public final class OptimizedSmallEnumSet<E extends Enum<E>> {
 +
 +    private final Class<E> enumClass;
@@ -2145,7 +2383,7 @@ index ce48210922..57ce9bde64 100644
          this.displayName = this.getName();
          this.canPickUpLoot = true;
 diff --git a/src/main/java/net/minecraft/server/EntityTypes.java b/src/main/java/net/minecraft/server/EntityTypes.java
-index f937b72945..cbf0c2f25d 100644
+index 29e776ca19..4328273b1f 100644
 --- a/src/main/java/net/minecraft/server/EntityTypes.java
 +++ b/src/main/java/net/minecraft/server/EntityTypes.java
 @@ -4,6 +4,7 @@ import com.mojang.datafixers.DataFixUtils;
diff --git a/Spigot-Server-Patches/0467-Remove-streams-from-Mob-AI-System.patch b/Spigot-Server-Patches/0467-Remove-streams-from-Mob-AI-System.patch
new file mode 100644
index 0000000000..ec98605403
--- /dev/null
+++ b/Spigot-Server-Patches/0467-Remove-streams-from-Mob-AI-System.patch
@@ -0,0 +1,252 @@
+From 31cd409fd68946bc43008a237ff6627c905d6633 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/server/PathfinderGoal.java b/src/main/java/net/minecraft/server/PathfinderGoal.java
+index bdb90a3466..134f7d0013 100644
+--- a/src/main/java/net/minecraft/server/PathfinderGoal.java
++++ b/src/main/java/net/minecraft/server/PathfinderGoal.java
+@@ -1,10 +1,11 @@
+ package net.minecraft.server;
+ 
++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 OptimizedSmallEnumSet<Type> goalTypes = new OptimizedSmallEnumSet<>(PathfinderGoal.Type.class); // Paper - remove streams from pathfindergoalselector
+ 
+     public PathfinderGoal() {}
+ 
+@@ -28,16 +29,20 @@ 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/server/PathfinderGoalSelector.java b/src/main/java/net/minecraft/server/PathfinderGoalSelector.java
+index 935136771e..90319909e5 100644
+--- a/src/main/java/net/minecraft/server/PathfinderGoalSelector.java
++++ b/src/main/java/net/minecraft/server/PathfinderGoalSelector.java
+@@ -1,8 +1,10 @@
+ package net.minecraft.server;
+ 
++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.stream.Stream;
+@@ -26,7 +28,7 @@ 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 GameProfilerFiller e;
+-    private final EnumSet<PathfinderGoal.Type> f = EnumSet.noneOf(PathfinderGoal.Type.class);
++    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
+ 
+@@ -58,33 +60,36 @@ 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() {
+         this.e.enter("goalCleanup");
+-        this.c().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);
+@@ -93,30 +98,58 @@ public class PathfinderGoalSelector {
+         });
+         this.e.exit();
+         this.e.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
+         this.e.exit();
+         this.e.enter("goalTick");
+-        this.c().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
+         this.e.exit();
+     }
+ 
+@@ -125,11 +158,11 @@ 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/server/PathfinderGoalWrapped.java b/src/main/java/net/minecraft/server/PathfinderGoalWrapped.java
+index 29657fed75..1b800c558f 100644
+--- a/src/main/java/net/minecraft/server/PathfinderGoalWrapped.java
++++ b/src/main/java/net/minecraft/server/PathfinderGoalWrapped.java
+@@ -59,9 +59,10 @@ 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
+-- 
+2.25.1
+