From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Ivan Pekov <ivan@mrivanplays.com>
Date: Sat, 12 Sep 2020 19:17:05 +0300
Subject: [PATCH] Optimize Villagers

These changes aim to fix the following:
- Villagers trying to push farther POIs (Points Of Interest)
- Villagers ignoring doors most of the times
- Villagers pushing POIs (Points Of Interest) to unloaded chunks

The following has been done to fix the mentioned problems:
- Replaced stream off BehaviorFindPosition
- Made sure that chunks are loaded for the POIs (Points Of Interest) that are gonna be tried.
- Added a profession cache, which followed by a stream removal.

diff --git a/src/main/java/net/minecraft/server/BehaviorFindPosition.java b/src/main/java/net/minecraft/server/BehaviorFindPosition.java
index 0594b0bb12c553edbb6284b48328a3dcf5a64ba4..05e03c1643e1e161f8c2b6e5d4e65f60dc99cb26 100644
--- a/src/main/java/net/minecraft/server/BehaviorFindPosition.java
+++ b/src/main/java/net/minecraft/server/BehaviorFindPosition.java
@@ -48,7 +48,7 @@ public class BehaviorFindPosition extends Behavior<EntityCreature> {
         if (this.d && entitycreature.isBaby()) {
             return false;
         } else if (this.f == 0L) {
-            this.f = entitycreature.world.getTime() + (long) worldserver.random.nextInt(20);
+            this.f = entitycreature.world.getTime() + (long) java.util.concurrent.ThreadLocalRandom.current().nextInt(20); // Yatopia
             return false;
         } else {
             return worldserver.getTime() >= this.f;
@@ -277,7 +277,7 @@ public class BehaviorFindPosition extends Behavior<EntityCreature> {
     // Tuinity - remove streams entirely for poi search
 
     protected void a(WorldServer worldserver, EntityCreature entitycreature, long i) {
-        this.f = i + 20L + (long) worldserver.getRandom().nextInt(20);
+        this.f = i + 20L + (long) java.util.concurrent.ThreadLocalRandom.current().nextInt(20); // Yatopia
         if (entitycreature.getNavigation().isStuck()) this.f += 200L; // Airplane - wait an additional 10s to check again if they're stuck
         VillagePlace villageplace = worldserver.y();
 
@@ -288,12 +288,20 @@ public class BehaviorFindPosition extends Behavior<EntityCreature> {
             BehaviorFindPosition.a behaviorfindposition_a = (BehaviorFindPosition.a) this.g.get(blockposition.asLong());
 
             if (behaviorfindposition_a == null) {
-                return true;
+                return worldserver.getChunkIfLoaded(blockposition.getX() >> 4, blockposition.getZ() >> 4) != null; // Yatopia
             } else if (!behaviorfindposition_a.c(i)) {
                 return false;
             } else {
-                behaviorfindposition_a.a(i);
-                return true;
+                // Yatopia start - make sure chunks are loaded
+                int chunkX = blockposition.getX() >> 4;
+                int chunkZ = blockposition.getZ() >> 4;
+                if (worldserver.getChunkIfLoaded(chunkX, chunkZ) != null) {
+                    behaviorfindposition_a.a(i);
+                    return true;
+                } else {
+                    return false;
+                }
+                // Yatopia end
             }
         };
         Set<BlockPosition> set = findNearestPoi(villageplace, this.b.c(), predicate, entitycreature.getChunkCoordinates(), 48, VillagePlace.Occupancy.HAS_SPACE, 5); // Tuinity - remove streams entirely for poi search
@@ -320,7 +328,7 @@ public class BehaviorFindPosition extends Behavior<EntityCreature> {
                 BlockPosition blockposition1 = (BlockPosition) iterator.next();
 
                 this.g.computeIfAbsent(blockposition1.asLong(), (j) -> {
-                    return new BehaviorFindPosition.a(entitycreature.world.random, i);
+                    return new BehaviorFindPosition.a(java.util.concurrent.ThreadLocalRandom.current(), i); // Yatopia
                 });
             }
         }
diff --git a/src/main/java/net/minecraft/server/VillagePlaceType.java b/src/main/java/net/minecraft/server/VillagePlaceType.java
index b6b4c8c491d692f93d2c38d602ff99b0611b72aa..082b060407f2424c10f865e23feb60b970b851cb 100644
--- a/src/main/java/net/minecraft/server/VillagePlaceType.java
+++ b/src/main/java/net/minecraft/server/VillagePlaceType.java
@@ -14,11 +14,20 @@ import java.util.stream.Collectors;
 
 public class VillagePlaceType {
 
+    static Set<VillagePlaceType> professionCache; // Yatopia
     private static final Supplier<Set<VillagePlaceType>> y = Suppliers.memoize(() -> {
         return (Set) IRegistry.VILLAGER_PROFESSION.g().map(VillagerProfession::b).collect(Collectors.toSet());
     });
     public static final Predicate<VillagePlaceType> a = (villageplacetype) -> {
-        return ((Set) VillagePlaceType.y.get()).contains(villageplacetype);
+        // Yatopia start
+        if (professionCache == null) {
+            professionCache = new java.util.HashSet<>();
+            for (VillagerProfession profession : IRegistry.VILLAGER_PROFESSION) {
+                professionCache.add(profession.getPlaceType());
+            }
+        }
+        return professionCache.contains(villageplacetype);
+        // Yatopia end
     };
     public static final Predicate<VillagePlaceType> b = (villageplacetype) -> {
         return true;
diff --git a/src/main/java/net/minecraft/server/VillagerProfession.java b/src/main/java/net/minecraft/server/VillagerProfession.java
index 6493f220a0cf627e82e5f3f3c85e9934d9a9ebae..f4c8ba2d94e5875197b674a0e39e997b45186d63 100644
--- a/src/main/java/net/minecraft/server/VillagerProfession.java
+++ b/src/main/java/net/minecraft/server/VillagerProfession.java
@@ -35,6 +35,7 @@ public class VillagerProfession {
         this.t = soundeffect;
     }
 
+    public final VillagePlaceType getPlaceType() { return b(); } // Yatopia - OBFHELPER
     public VillagePlaceType b() {
         return this.q;
     }
@@ -61,6 +62,7 @@ public class VillagerProfession {
     }
 
     static VillagerProfession a(String s, VillagePlaceType villageplacetype, ImmutableSet<Item> immutableset, ImmutableSet<Block> immutableset1, @Nullable SoundEffect soundeffect) {
+        VillagePlaceType.professionCache = null; // Yatopia
         return (VillagerProfession) IRegistry.a((IRegistry) IRegistry.VILLAGER_PROFESSION, new MinecraftKey(s), (Object) (new VillagerProfession(s, villageplacetype, immutableset, immutableset1, soundeffect)));
     }
 }
