diff --git a/patches/api/0047-Lobotomize-stuck-villagers.patch b/patches/api/0047-Lobotomize-stuck-villagers.patch new file mode 100644 index 000000000..d74a4720b --- /dev/null +++ b/patches/api/0047-Lobotomize-stuck-villagers.patch @@ -0,0 +1,25 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: BillyGalbreath +Date: Mon, 24 Jan 2022 20:42:22 -0600 +Subject: [PATCH] Lobotomize stuck villagers + + +diff --git a/src/main/java/org/bukkit/entity/Villager.java b/src/main/java/org/bukkit/entity/Villager.java +index 02ecc87a90bbd81e7d21279fac701ba41c74fd9f..5b1d1403c5cf57a797e80ecd5442499ba666f8d3 100644 +--- a/src/main/java/org/bukkit/entity/Villager.java ++++ b/src/main/java/org/bukkit/entity/Villager.java +@@ -285,4 +285,14 @@ public interface Villager extends AbstractVillager { + */ + public void clearReputations(); + // Paper end ++ ++ // Purpur start ++ ++ /** ++ * Check if villager is currently lobotomized ++ * ++ * @return True if lobotomized ++ */ ++ boolean isLobotomized(); ++ // Purpur end + } diff --git a/patches/server/0003-Purpur-config-files.patch b/patches/server/0003-Purpur-config-files.patch index 2cecc4c58..d62e81e4a 100644 --- a/patches/server/0003-Purpur-config-files.patch +++ b/patches/server/0003-Purpur-config-files.patch @@ -172,7 +172,7 @@ index 55bae3efbc630be6d40d415509de4c3e744a5004..9d649923e28f4839106b336fce41bd3f .withRequiredArg() diff --git a/src/main/java/org/purpurmc/purpur/PurpurConfig.java b/src/main/java/org/purpurmc/purpur/PurpurConfig.java new file mode 100644 -index 0000000000000000000000000000000000000000..96802b86828522006d4a25ab61e6630173688679 +index 0000000000000000000000000000000000000000..b3bfc56859d00f9e27bd1d230dd19b92985b5718 --- /dev/null +++ b/src/main/java/org/purpurmc/purpur/PurpurConfig.java @@ -0,0 +1,170 @@ @@ -250,8 +250,8 @@ index 0000000000000000000000000000000000000000..96802b86828522006d4a25ab61e66301 + commands = new HashMap<>(); + commands.put("purpur", new PurpurCommand("purpur")); + -+ version = getInt("config-version", 26); -+ set("config-version", 26); ++ version = getInt("config-version", 27); ++ set("config-version", 27); + + readConfig(PurpurConfig.class, null); + } diff --git a/patches/server/0264-Lobotomize-stuck-villagers.patch b/patches/server/0264-Lobotomize-stuck-villagers.patch new file mode 100644 index 000000000..2d3c33562 --- /dev/null +++ b/patches/server/0264-Lobotomize-stuck-villagers.patch @@ -0,0 +1,143 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Thu, 3 Dec 2020 17:56:18 -0600 +Subject: [PATCH] Lobotomize stuck villagers + + +diff --git a/src/main/java/net/minecraft/world/entity/npc/Villager.java b/src/main/java/net/minecraft/world/entity/npc/Villager.java +index b9f228d660b2279284e64fc3bbfa90fc7d2d20b0..3cf27428820e9cd96cd54abe3bfc80d9e6bbf96a 100644 +--- a/src/main/java/net/minecraft/world/entity/npc/Villager.java ++++ b/src/main/java/net/minecraft/world/entity/npc/Villager.java +@@ -138,6 +138,8 @@ public class Villager extends AbstractVillager implements ReputationEventHandler + return villageplacetype == PoiType.MEETING; + }); + private final int brainTickOffset; // Purpur ++ private boolean isLobotomized = false; public boolean isLobotomized() { return this.isLobotomized; } // Purpur ++ private int notLobotomizedCount = 0; // Purpur + + public long nextGolemPanic = -1; // Pufferfish + +@@ -196,6 +198,47 @@ public class Villager extends AbstractVillager implements ReputationEventHandler + protected boolean isAlwaysExperienceDropper() { + return this.level.purpurConfig.villagerAlwaysDropExp; + } ++ ++ private boolean checkLobotomized() { ++ int interval = this.level.purpurConfig.villagerLobotomizeCheckInterval; ++ if (this.notLobotomizedCount > 3) { ++ // check half as often if not lobotomized for the last 3+ consecutive checks ++ interval *= 2; ++ } ++ if ((this.level.getGameTime() + brainTickOffset) % interval == 0) { ++ // offset Y for short blocks like dirt_path/farmland ++ this.isLobotomized = !canTravelFrom(new BlockPos(getX(), getY() + 0.0625D, getZ())); ++ ++ if (this.isLobotomized) { ++ this.notLobotomizedCount = 0; ++ } else { ++ this.notLobotomizedCount++; ++ } ++ } ++ return this.isLobotomized; ++ } ++ ++ private boolean canTravelFrom(BlockPos pos) { ++ return canTravelTo(pos.east()) || canTravelTo(pos.west()) || canTravelTo(pos.north()) || canTravelTo(pos.south()); ++ } ++ ++ private boolean canTravelTo(BlockPos pos) { ++ BlockState state = this.level.getBlockStateIfLoaded(pos); ++ if (state == null) { ++ // chunk not loaded ++ return false; ++ } ++ net.minecraft.world.level.block.Block bottom = state.getBlock(); ++ if (bottom instanceof net.minecraft.world.level.block.FenceBlock || ++ bottom instanceof net.minecraft.world.level.block.FenceGateBlock || ++ bottom instanceof net.minecraft.world.level.block.WallBlock) { ++ // bottom block is too tall to get over ++ return false; ++ } ++ net.minecraft.world.level.block.Block top = level.getBlockState(pos.above()).getBlock(); ++ // only if both blocks have no collision ++ return !bottom.hasCollision && !top.hasCollision; ++ } + // Purpur end + + @Override +@@ -293,6 +336,15 @@ public class Villager extends AbstractVillager implements ReputationEventHandler + protected void customServerAiStep() { mobTick(false); } + protected void mobTick(boolean inactive) { + this.level.getProfiler().push("villagerBrain"); ++ // Purpur start ++ if (this.level.purpurConfig.villagerLobotomizeEnabled) { ++ // treat as inactive if lobotomized ++ inactive = inactive || checkLobotomized(); ++ } else { ++ // clean up state for API ++ this.isLobotomized = false; ++ } ++ // Purpur end + // Pufferfish start + if (!inactive) { + // Purpur start +@@ -303,6 +355,12 @@ public class Villager extends AbstractVillager implements ReputationEventHandler + this.getBrain().tick((ServerLevel) this.level, this); // Paper + } + // Pufferfish end ++ // Purpur start ++ else if (this.isLobotomized && shouldRestock()) { ++ // make sure we restock if needed when lobotomized ++ restock(); ++ } ++ // Purpur end + this.level.getProfiler().pop(); + if (this.assignProfessionWhenSpawned) { + this.assignProfessionWhenSpawned = false; +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftVillager.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftVillager.java +index dbc1ea96223675fbe03585598a9c7f51acc61d2e..dde09a8495270d9038f55974e252576095259ca9 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftVillager.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftVillager.java +@@ -187,4 +187,11 @@ public class CraftVillager extends CraftAbstractVillager implements Villager { + getHandle().getGossips().getReputations().clear(); + } + // Paper end ++ ++ // Purpur start ++ @Override ++ public boolean isLobotomized() { ++ return getHandle().isLobotomized(); ++ } ++ // Purpur end + } +diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java +index e4e75914042b6e1024662ef59b2190865a879759..973cec1676fe533a8e4aa268aa15dda135d43367 100644 +--- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java ++++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java +@@ -2666,6 +2666,8 @@ public class PurpurWorldConfig { + public boolean villagerAllowTrading = true; + public boolean villagerAlwaysDropExp = false; + public int villagerMinimumDemand = 0; ++ public boolean villagerLobotomizeEnabled = false; ++ public int villagerLobotomizeCheckInterval = 100; + private void villagerSettings() { + villagerRidable = getBoolean("mobs.villager.ridable", villagerRidable); + villagerRidableInWater = getBoolean("mobs.villager.ridable-in-water", villagerRidableInWater); +@@ -2691,6 +2693,17 @@ public class PurpurWorldConfig { + villagerAllowTrading = getBoolean("mobs.villager.allow-trading", villagerAllowTrading); + villagerAlwaysDropExp = getBoolean("mobs.villager.always-drop-exp", villagerAlwaysDropExp); + villagerMinimumDemand = getInt("mobs.villager.minimum-demand", villagerMinimumDemand); ++ if (PurpurConfig.version < 9) { ++ boolean oldValue = getBoolean("mobs.villager.lobotomize-1x1", villagerLobotomizeEnabled); ++ set("mobs.villager.lobotomize.enabled", oldValue); ++ set("mobs.villager.lobotomize-1x1", null); ++ } ++ if (PurpurConfig.version < 27) { ++ int oldValue = getInt("mobs.villager.lobotomize.check-interval", villagerLobotomizeCheckInterval); ++ set("mobs.villager.lobotomize.check-interval", oldValue == 60 ? 100 : oldValue); ++ } ++ villagerLobotomizeEnabled = getBoolean("mobs.villager.lobotomize.enabled", villagerLobotomizeEnabled); ++ villagerLobotomizeCheckInterval = getInt("mobs.villager.lobotomize.check-interval", villagerLobotomizeCheckInterval); + } + + public boolean vindicatorRidable = false;