From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: BillyGalbreath <blake.galbreath@gmail.com>
Date: Thu, 3 Dec 2020 17:56:18 -0600
Subject: [PATCH] Lobotomize stuck villagers


diff --git a/src/main/java/net/minecraft/server/Entity.java b/src/main/java/net/minecraft/server/Entity.java
index fb78ae9c89b035fdac213b7294f94d425a7f57f4..1ec8dcfcbacf373682cb46fee354e3cfd6d3f1b5 100644
--- a/src/main/java/net/minecraft/server/Entity.java
+++ b/src/main/java/net/minecraft/server/Entity.java
@@ -114,7 +114,7 @@ public abstract class Entity implements INamableTileEntity, ICommandListener, Ke
     public double lastY;
     public double lastZ;
     private Vec3D loc;
-    private BlockPosition locBlock;
+    private BlockPosition locBlock; public BlockPosition getBlockLocation() { return locBlock; } // Purpur
     private Vec3D mot;
     public float yaw;
     public float pitch;
diff --git a/src/main/java/net/minecraft/server/EntityVillager.java b/src/main/java/net/minecraft/server/EntityVillager.java
index 15e052cb844df310c62d8a5695e8da6c633d94b6..a04123b5897a150439846abe5b25a3a13419f00e 100644
--- a/src/main/java/net/minecraft/server/EntityVillager.java
+++ b/src/main/java/net/minecraft/server/EntityVillager.java
@@ -185,15 +185,37 @@ public class EntityVillager extends EntityVillagerAbstract implements Reputation
     }
     // Spigot End
 
+    // Purpur start
+    boolean lobotomized = false;
+
+    private boolean isLobotomized() {
+        if ((world.getTime() + brainTickOffset) % world.purpurConfig.villagerLobotomizeCheck == 0) {
+            this.lobotomized = !canTravelFrom(getBlockLocation().up());
+        }
+        return this.lobotomized;
+    }
+
+    private boolean canTravelFrom(BlockPosition pos) {
+        return canTravelTo(pos.east()) || canTravelTo(pos.west()) || canTravelTo(pos.north()) || canTravelTo(pos.south());
+    }
+
+    private boolean canTravelTo(BlockPosition pos) {
+        PathEntity to = navigation.calculateDestination(pos, 0);
+        return to != null && to.getPoints().size() > 1;
+    }
+    // Purpur end
+
     @Override
     protected void mobTick() { mobTick(false); }
     protected void mobTick(boolean inactive) {
         this.world.getMethodProfiler().enter("villagerBrain");
         // Purpur start
+        if (world.purpurConfig.villagerLobotomizeEnabled) inactive = inactive || isLobotomized();
         boolean tick = (world.getTime() + brainTickOffset) % world.purpurConfig.villagerBrainTicks == 0;
         if (((WorldServer) world).getMinecraftServer().lagging ? tick : world.purpurConfig.villagerUseBrainTicksOnlyWhenLagging || tick)
         // Purpur end
         if (!inactive) this.getBehaviorController().a((WorldServer) this.world, this); // CraftBukkit - decompile error // Paper
+        else if (shouldRestock()) doRestock(); // Purpur
         this.world.getMethodProfiler().exit();
         if (this.bF) {
             this.bF = false;
@@ -325,6 +347,7 @@ public class EntityVillager extends EntityVillagerAbstract implements Reputation
         return true;
     }
 
+    public void doRestock() { fb(); } // Purpur - OBFHELPER
     public void fb() {
         this.fp();
         Iterator iterator = this.getOffers().iterator();
@@ -359,6 +382,7 @@ public class EntityVillager extends EntityVillagerAbstract implements Reputation
         return this.bD == 0 || this.bD < 2 && this.world.getTime() > this.bC + 2400L;
     }
 
+    public boolean shouldRestock() { return fc(); } // Purpur - OBFHELPER
     public boolean fc() {
         long i = this.bC + 12000L;
         long j = this.world.getTime();
diff --git a/src/main/java/net/minecraft/server/NavigationAbstract.java b/src/main/java/net/minecraft/server/NavigationAbstract.java
index b92ca4a6de01f3f86367fb8dfe3591b08a3e9218..1208464fba96daf276c9cc0c1c9b18db75b03abc 100644
--- a/src/main/java/net/minecraft/server/NavigationAbstract.java
+++ b/src/main/java/net/minecraft/server/NavigationAbstract.java
@@ -101,6 +101,7 @@ public abstract class NavigationAbstract {
     }
 
     @Nullable
+    public PathEntity calculateDestination(BlockPosition blockposition, int i) { return a(blockposition, i); } // Purpur - OBFHELPER
     public PathEntity a(BlockPosition blockposition, int i) {
         // Paper start - add target parameter
         return this.a(blockposition, null, i);
diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
index 4b291b6bd8e74a4affd6a6ea7e1ace50d78ff7eb..dd8c9cd8e45b49bcee4825abb4e30537ef3dafd4 100644
--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
+++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
@@ -1076,6 +1076,8 @@ public class PurpurWorldConfig {
     public int villagerSpawnIronGolemLimit = 0;
     public boolean villagerCanBreed = true;
     public int villagerBreedingTicks = 6000;
+    public boolean villagerLobotomizeEnabled = false;
+    public int villagerLobotomizeCheck = 60;
     private void villagerSettings() {
         villagerRidable = getBoolean("mobs.villager.ridable", villagerRidable);
         villagerRidableInWater = getBoolean("mobs.villager.ridable-in-water", villagerRidableInWater);
@@ -1088,6 +1090,13 @@ public class PurpurWorldConfig {
         villagerSpawnIronGolemLimit = getInt("mobs.villager.spawn-iron-golem.limit", villagerSpawnIronGolemLimit);
         villagerCanBreed = getBoolean("mobs.villager.can-breed", villagerCanBreed);
         villagerBreedingTicks = getInt("mobs.villager.breeding-delay-ticks", villagerBreedingTicks);
+        if (PurpurConfig.version < 9) {
+            boolean oldValue = getBoolean("mobs.villager.lobotomize-1x1", villagerLobotomizeEnabled);
+            set("mobs.villager.lobotomize.enabled", oldValue);
+            set("mobs.villager.lobotomize-1x1", null);
+        }
+        villagerLobotomizeEnabled = getBoolean("mobs.villager.lobotomize.enabled", villagerLobotomizeEnabled);
+        villagerLobotomizeCheck = getInt("mobs.villager.lobotomize.check-interval", villagerLobotomizeCheck);
     }
 
     public boolean villagerTraderRidable = false;
