From c788b39465829a709e98d3d4a521b42286697d63 Mon Sep 17 00:00:00 2001 From: Benjamin Lefebvre Date: Sat, 13 Jun 2026 00:21:31 +0200 Subject: [PATCH 1/3] add villager pois mixins --- .../entity/villager_poi/AcquirePoiMixin.java | 29 +++++++++++++ .../AssignProfessionFromJobSiteMixin.java | 32 ++++++++++++++ .../villager_poi/ValidateNearbyPoiMixin.java | 42 +++++++++++++++++++ .../entity/villager_poi/WorkAtPoiMixin.java | 33 +++++++++++++++ .../ryanhcode/sable/util/SubLevelPoiUtil.java | 22 ++++++++++ common/src/main/resources/sable.mixins.json | 4 ++ 6 files changed, 162 insertions(+) create mode 100644 common/src/main/java/dev/ryanhcode/sable/mixin/entity/villager_poi/AcquirePoiMixin.java create mode 100644 common/src/main/java/dev/ryanhcode/sable/mixin/entity/villager_poi/AssignProfessionFromJobSiteMixin.java create mode 100644 common/src/main/java/dev/ryanhcode/sable/mixin/entity/villager_poi/ValidateNearbyPoiMixin.java create mode 100644 common/src/main/java/dev/ryanhcode/sable/mixin/entity/villager_poi/WorkAtPoiMixin.java create mode 100644 common/src/main/java/dev/ryanhcode/sable/util/SubLevelPoiUtil.java diff --git a/common/src/main/java/dev/ryanhcode/sable/mixin/entity/villager_poi/AcquirePoiMixin.java b/common/src/main/java/dev/ryanhcode/sable/mixin/entity/villager_poi/AcquirePoiMixin.java new file mode 100644 index 00000000..9d96ce7f --- /dev/null +++ b/common/src/main/java/dev/ryanhcode/sable/mixin/entity/villager_poi/AcquirePoiMixin.java @@ -0,0 +1,29 @@ +package dev.ryanhcode.sable.mixin.entity.villager_poi; + +import dev.ryanhcode.sable.Sable; +import dev.ryanhcode.sable.sublevel.SubLevel; +import dev.ryanhcode.sable.util.SubLevelPoiUtil; +import net.minecraft.core.BlockPos; +import net.minecraft.world.entity.PathfinderMob; +import net.minecraft.world.entity.ai.behavior.AcquirePoi; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +@Mixin(AcquirePoi.class) +public class AcquirePoiMixin { + + /** + * When a villager is standing on a contraption, redirect the PoiManager scan center from the + * villager's global position to its plotyard position so it can find job sites inside the sublevel. + */ + @Redirect( + method = "*", + at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/PathfinderMob;blockPosition()Lnet/minecraft/core/BlockPos;") + ) + private static BlockPos sable$redirectScanCenter(final PathfinderMob mob) { + final SubLevel sl = Sable.HELPER.getTrackingSubLevel(mob); + if (sl == null) return mob.blockPosition(); + return SubLevelPoiUtil.toPlotyard(sl, mob.position()); + } +} diff --git a/common/src/main/java/dev/ryanhcode/sable/mixin/entity/villager_poi/AssignProfessionFromJobSiteMixin.java b/common/src/main/java/dev/ryanhcode/sable/mixin/entity/villager_poi/AssignProfessionFromJobSiteMixin.java new file mode 100644 index 00000000..81ce3108 --- /dev/null +++ b/common/src/main/java/dev/ryanhcode/sable/mixin/entity/villager_poi/AssignProfessionFromJobSiteMixin.java @@ -0,0 +1,32 @@ +package dev.ryanhcode.sable.mixin.entity.villager_poi; + +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; +import com.llamalad7.mixinextras.sugar.Local; +import dev.ryanhcode.sable.sublevel.SubLevel; +import dev.ryanhcode.sable.util.SubLevelPoiUtil; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Position; +import net.minecraft.world.entity.ai.behavior.AssignProfessionFromJobSite; +import net.minecraft.world.entity.npc.Villager; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; + +@Mixin(AssignProfessionFromJobSite.class) +public class AssignProfessionFromJobSiteMixin { + + @WrapOperation( + method = "*", + at = @At(value = "INVOKE", target = "Lnet/minecraft/core/BlockPos;closerToCenterThan(Lnet/minecraft/core/Position;D)Z") + ) + private static boolean sable$fixProximityCheck( + final BlockPos potentialSitePos, final Position entityPos, final double dist, final Operation original, + @Local(argsOnly = true, ordinal = 0) final Villager villager + ) { + final SubLevel sl = SubLevelPoiUtil.getSubLevelForPos(villager.level(), potentialSitePos); + if (sl == null) return original.call(potentialSitePos, entityPos, dist); + return potentialSitePos.closerToCenterThan( + SubLevelPoiUtil.toPlotyard(sl, villager.position()).getCenter(), dist + ); + } +} diff --git a/common/src/main/java/dev/ryanhcode/sable/mixin/entity/villager_poi/ValidateNearbyPoiMixin.java b/common/src/main/java/dev/ryanhcode/sable/mixin/entity/villager_poi/ValidateNearbyPoiMixin.java new file mode 100644 index 00000000..19f22e98 --- /dev/null +++ b/common/src/main/java/dev/ryanhcode/sable/mixin/entity/villager_poi/ValidateNearbyPoiMixin.java @@ -0,0 +1,42 @@ +package dev.ryanhcode.sable.mixin.entity.villager_poi; + +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; +import com.llamalad7.mixinextras.sugar.Local; +import dev.ryanhcode.sable.Sable; +import dev.ryanhcode.sable.sublevel.SubLevel; +import dev.ryanhcode.sable.util.SubLevelPoiUtil; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Position; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.ai.behavior.ValidateNearbyPoi; +import net.minecraft.world.phys.Vec3; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; + +@Mixin(ValidateNearbyPoi.class) +public class ValidateNearbyPoiMixin { + + @WrapOperation( + method = "*", + at = @At(value = "INVOKE", target = "Lnet/minecraft/core/BlockPos;closerToCenterThan(Lnet/minecraft/core/Position;D)Z") + ) + private static boolean sable$fixProximityCheck( + final BlockPos storedPos, final Position entityPos, final double dist, final Operation original, + @Local(argsOnly = true, ordinal = 0) final LivingEntity entity + ) { + final SubLevel sl = SubLevelPoiUtil.getSubLevelForPos(entity.level(), storedPos); + if (sl == null) return original.call(storedPos, entityPos, dist); + + if (Sable.HELPER.getTrackingSubLevel(entity) == sl) { + // Entity is on the contraption — compare in plotyard space. + return storedPos.closerToCenterThan( + SubLevelPoiUtil.toPlotyard(sl, entity.position()).getCenter(), dist + ); + } + + // Entity is off the contraption — compare current global position of the job site. + final Vec3 globalJobSitePos = Sable.HELPER.projectOutOfSubLevel(entity.level(), storedPos.getCenter()); + return globalJobSitePos.closerThan(entity.position(), dist); + } +} diff --git a/common/src/main/java/dev/ryanhcode/sable/mixin/entity/villager_poi/WorkAtPoiMixin.java b/common/src/main/java/dev/ryanhcode/sable/mixin/entity/villager_poi/WorkAtPoiMixin.java new file mode 100644 index 00000000..ee23141e --- /dev/null +++ b/common/src/main/java/dev/ryanhcode/sable/mixin/entity/villager_poi/WorkAtPoiMixin.java @@ -0,0 +1,33 @@ +package dev.ryanhcode.sable.mixin.entity.villager_poi; + +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; +import com.llamalad7.mixinextras.sugar.Local; +import dev.ryanhcode.sable.sublevel.SubLevel; +import dev.ryanhcode.sable.util.SubLevelPoiUtil; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Position; +import net.minecraft.world.entity.ai.behavior.WorkAtPoi; +import net.minecraft.world.entity.npc.Villager; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; + +@Mixin(WorkAtPoi.class) +public class WorkAtPoiMixin { + + @WrapOperation( + method = {"checkExtraStartConditions(Lnet/minecraft/server/level/ServerLevel;Lnet/minecraft/world/entity/npc/Villager;)Z", + "canStillUse(Lnet/minecraft/server/level/ServerLevel;Lnet/minecraft/world/entity/npc/Villager;J)Z"}, + at = @At(value = "INVOKE", target = "Lnet/minecraft/core/BlockPos;closerToCenterThan(Lnet/minecraft/core/Position;D)Z") + ) + private boolean sable$fixProximityCheck( + final BlockPos jobSitePos, final Position entityPos, final double dist, final Operation original, + @Local(argsOnly = true, ordinal = 0) final Villager villager + ) { + final SubLevel sl = SubLevelPoiUtil.getSubLevelForPos(villager.level(), jobSitePos); + if (sl == null) return original.call(jobSitePos, entityPos, dist); + return jobSitePos.closerToCenterThan( + SubLevelPoiUtil.toPlotyard(sl, villager.position()).getCenter(), dist + ); + } +} diff --git a/common/src/main/java/dev/ryanhcode/sable/util/SubLevelPoiUtil.java b/common/src/main/java/dev/ryanhcode/sable/util/SubLevelPoiUtil.java new file mode 100644 index 00000000..b4644fcb --- /dev/null +++ b/common/src/main/java/dev/ryanhcode/sable/util/SubLevelPoiUtil.java @@ -0,0 +1,22 @@ +package dev.ryanhcode.sable.util; + +import dev.ryanhcode.sable.Sable; +import dev.ryanhcode.sable.sublevel.SubLevel; +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.Level; +import net.minecraft.world.phys.Vec3; +import org.jetbrains.annotations.Nullable; + +public final class SubLevelPoiUtil { + + private SubLevelPoiUtil() {} + + public static @Nullable SubLevel getSubLevelForPos(final Level level, final BlockPos pos) { + return Sable.HELPER.getContaining(level, pos); + } + + /** Converts a global entity position to the plotyard BlockPos within the given sublevel. */ + public static BlockPos toPlotyard(final SubLevel sl, final Vec3 globalPos) { + return BlockPos.containing(sl.logicalPose().transformPositionInverse(globalPos)); + } +} diff --git a/common/src/main/resources/sable.mixins.json b/common/src/main/resources/sable.mixins.json index faf5ee1b..2630989a 100644 --- a/common/src/main/resources/sable.mixins.json +++ b/common/src/main/resources/sable.mixins.json @@ -141,6 +141,10 @@ "entity.entity_pathfinding.PathNavigationMixin", "entity.entity_pathfinding.RandomPosMixin", "entity.entity_pathfinding.WalkNodeEvaluatorMixin", + "entity.villager_poi.AcquirePoiMixin", + "entity.villager_poi.AssignProfessionFromJobSiteMixin", + "entity.villager_poi.ValidateNearbyPoiMixin", + "entity.villager_poi.WorkAtPoiMixin", "entity.entity_rotations_and_riding.BlockMixin", "entity.entity_rotations_and_riding.EntityMixin", "entity.entity_rotations_and_riding.EntityTypeMixin", From 5479211c7c23bee63e5cb3ae8bc27146e03451e7 Mon Sep 17 00:00:00 2001 From: Benjamin Lefebvre Date: Mon, 15 Jun 2026 14:50:08 +0200 Subject: [PATCH 2/3] progress --- .../villager_poi/ValidateNearbyPoiMixin.java | 51 +++++++++++++++++-- common/src/main/resources/sable.mixins.json | 3 ++ 2 files changed, 50 insertions(+), 4 deletions(-) diff --git a/common/src/main/java/dev/ryanhcode/sable/mixin/entity/villager_poi/ValidateNearbyPoiMixin.java b/common/src/main/java/dev/ryanhcode/sable/mixin/entity/villager_poi/ValidateNearbyPoiMixin.java index 19f22e98..00afe6d5 100644 --- a/common/src/main/java/dev/ryanhcode/sable/mixin/entity/villager_poi/ValidateNearbyPoiMixin.java +++ b/common/src/main/java/dev/ryanhcode/sable/mixin/entity/villager_poi/ValidateNearbyPoiMixin.java @@ -7,16 +7,26 @@ import dev.ryanhcode.sable.sublevel.SubLevel; import dev.ryanhcode.sable.util.SubLevelPoiUtil; import net.minecraft.core.BlockPos; +import net.minecraft.core.Holder; import net.minecraft.core.Position; import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.ai.behavior.ValidateNearbyPoi; +import net.minecraft.world.entity.ai.village.poi.PoiManager; +import net.minecraft.world.entity.ai.village.poi.PoiType; +import net.minecraft.world.entity.npc.Villager; import net.minecraft.world.phys.Vec3; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; +import java.util.function.Predicate; + @Mixin(ValidateNearbyPoi.class) public class ValidateNearbyPoiMixin { + private static final Logger LOGGER = LoggerFactory.getLogger("sable.poi"); + @WrapOperation( method = "*", at = @At(value = "INVOKE", target = "Lnet/minecraft/core/BlockPos;closerToCenterThan(Lnet/minecraft/core/Position;D)Z") @@ -29,14 +39,47 @@ public class ValidateNearbyPoiMixin { if (sl == null) return original.call(storedPos, entityPos, dist); if (Sable.HELPER.getTrackingSubLevel(entity) == sl) { - // Entity is on the contraption — compare in plotyard space. - return storedPos.closerToCenterThan( + final boolean result = storedPos.closerToCenterThan( SubLevelPoiUtil.toPlotyard(sl, entity.position()).getCenter(), dist ); + if (!result && entity instanceof Villager v) { + final Vec3 global = Sable.HELPER.projectOutOfSubLevel(entity.level(), storedPos.getCenter()); + LOGGER.warn("[POI] {} @ {} lost job site: distance check failed (on-contraption) plotyard={} global={}", + v.getUUID(), v.blockPosition(), storedPos, global); + } + return result; } - // Entity is off the contraption — compare current global position of the job site. final Vec3 globalJobSitePos = Sable.HELPER.projectOutOfSubLevel(entity.level(), storedPos.getCenter()); - return globalJobSitePos.closerThan(entity.position(), dist); + final boolean result = globalJobSitePos.closerThan(entity.position(), dist); + if (!result && entity instanceof Villager v) { + LOGGER.warn("[POI] {} @ {} lost job site: distance check failed (off-contraption) plotyard={} global={}", + v.getUUID(), v.blockPosition(), storedPos, globalJobSitePos); + } + return result; + } + + /** Catches the "POI block no longer exists" path. */ + @WrapOperation( + method = "*", + at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/ai/village/poi/PoiManager;exists(Lnet/minecraft/core/BlockPos;Ljava/util/function/Predicate;)Z") + ) + private static boolean sable$logPoiNotFound( + final PoiManager poiManager, final BlockPos pos, final Predicate> predicate, + final Operation original, + @Local(argsOnly = true, ordinal = 0) final LivingEntity entity + ) { + final boolean exists = original.call(poiManager, pos, predicate); + if (!exists && entity instanceof Villager v) { + final SubLevel sl = SubLevelPoiUtil.getSubLevelForPos(entity.level(), pos); + if (sl != null) { + LOGGER.warn("[POI] {} @ {} lost job site: POI no longer exists in PoiManager plotyard={}", + v.getUUID(), v.blockPosition(), pos); + } else { + LOGGER.warn("[POI] {} @ {} lost job site: POI no longer exists in PoiManager pos={}", + v.getUUID(), v.blockPosition(), pos); + } + } + return exists; } } diff --git a/common/src/main/resources/sable.mixins.json b/common/src/main/resources/sable.mixins.json index 2630989a..745fc473 100644 --- a/common/src/main/resources/sable.mixins.json +++ b/common/src/main/resources/sable.mixins.json @@ -142,8 +142,11 @@ "entity.entity_pathfinding.RandomPosMixin", "entity.entity_pathfinding.WalkNodeEvaluatorMixin", "entity.villager_poi.AcquirePoiMixin", + "entity.villager_poi.BrainJobSiteEraseMixin", "entity.villager_poi.AssignProfessionFromJobSiteMixin", "entity.villager_poi.ValidateNearbyPoiMixin", + "entity.villager_poi.SetWalkTargetFromBlockMemoryMixin", + "entity.villager_poi.VillagerJobLossMixin", "entity.villager_poi.WorkAtPoiMixin", "entity.entity_rotations_and_riding.BlockMixin", "entity.entity_rotations_and_riding.EntityMixin", From f358aa65151c83fed08111292f681804efdd2a5f Mon Sep 17 00:00:00 2001 From: Benjamin Lefebvre Date: Mon, 15 Jun 2026 15:06:59 +0200 Subject: [PATCH 3/3] It works! --- .../SetWalkTargetFromBlockMemoryMixin.java | 25 ++++++++++ .../villager_poi/ValidateNearbyPoiMixin.java | 49 +------------------ common/src/main/resources/sable.mixins.json | 2 - 3 files changed, 27 insertions(+), 49 deletions(-) create mode 100644 common/src/main/java/dev/ryanhcode/sable/mixin/entity/villager_poi/SetWalkTargetFromBlockMemoryMixin.java diff --git a/common/src/main/java/dev/ryanhcode/sable/mixin/entity/villager_poi/SetWalkTargetFromBlockMemoryMixin.java b/common/src/main/java/dev/ryanhcode/sable/mixin/entity/villager_poi/SetWalkTargetFromBlockMemoryMixin.java new file mode 100644 index 00000000..29db2e2c --- /dev/null +++ b/common/src/main/java/dev/ryanhcode/sable/mixin/entity/villager_poi/SetWalkTargetFromBlockMemoryMixin.java @@ -0,0 +1,25 @@ +package dev.ryanhcode.sable.mixin.entity.villager_poi; + +import dev.ryanhcode.sable.Sable; +import dev.ryanhcode.sable.sublevel.SubLevel; +import dev.ryanhcode.sable.util.SubLevelPoiUtil; +import net.minecraft.core.BlockPos; +import net.minecraft.world.entity.ai.behavior.SetWalkTargetFromBlockMemory; +import net.minecraft.world.entity.npc.Villager; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +@Mixin(SetWalkTargetFromBlockMemory.class) +public class SetWalkTargetFromBlockMemoryMixin { + + @Redirect( + method = "*", + at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/npc/Villager;blockPosition()Lnet/minecraft/core/BlockPos;") + ) + private static BlockPos sable$redirectBlockPos(final Villager villager) { + final SubLevel sl = Sable.HELPER.getTrackingSubLevel(villager); + if (sl == null) return villager.blockPosition(); + return SubLevelPoiUtil.toPlotyard(sl, villager.position()); + } +} diff --git a/common/src/main/java/dev/ryanhcode/sable/mixin/entity/villager_poi/ValidateNearbyPoiMixin.java b/common/src/main/java/dev/ryanhcode/sable/mixin/entity/villager_poi/ValidateNearbyPoiMixin.java index 00afe6d5..c7534fea 100644 --- a/common/src/main/java/dev/ryanhcode/sable/mixin/entity/villager_poi/ValidateNearbyPoiMixin.java +++ b/common/src/main/java/dev/ryanhcode/sable/mixin/entity/villager_poi/ValidateNearbyPoiMixin.java @@ -7,26 +7,16 @@ import dev.ryanhcode.sable.sublevel.SubLevel; import dev.ryanhcode.sable.util.SubLevelPoiUtil; import net.minecraft.core.BlockPos; -import net.minecraft.core.Holder; import net.minecraft.core.Position; import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.ai.behavior.ValidateNearbyPoi; -import net.minecraft.world.entity.ai.village.poi.PoiManager; -import net.minecraft.world.entity.ai.village.poi.PoiType; -import net.minecraft.world.entity.npc.Villager; import net.minecraft.world.phys.Vec3; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; -import java.util.function.Predicate; - @Mixin(ValidateNearbyPoi.class) public class ValidateNearbyPoiMixin { - private static final Logger LOGGER = LoggerFactory.getLogger("sable.poi"); - @WrapOperation( method = "*", at = @At(value = "INVOKE", target = "Lnet/minecraft/core/BlockPos;closerToCenterThan(Lnet/minecraft/core/Position;D)Z") @@ -39,47 +29,12 @@ public class ValidateNearbyPoiMixin { if (sl == null) return original.call(storedPos, entityPos, dist); if (Sable.HELPER.getTrackingSubLevel(entity) == sl) { - final boolean result = storedPos.closerToCenterThan( + return storedPos.closerToCenterThan( SubLevelPoiUtil.toPlotyard(sl, entity.position()).getCenter(), dist ); - if (!result && entity instanceof Villager v) { - final Vec3 global = Sable.HELPER.projectOutOfSubLevel(entity.level(), storedPos.getCenter()); - LOGGER.warn("[POI] {} @ {} lost job site: distance check failed (on-contraption) plotyard={} global={}", - v.getUUID(), v.blockPosition(), storedPos, global); - } - return result; } final Vec3 globalJobSitePos = Sable.HELPER.projectOutOfSubLevel(entity.level(), storedPos.getCenter()); - final boolean result = globalJobSitePos.closerThan(entity.position(), dist); - if (!result && entity instanceof Villager v) { - LOGGER.warn("[POI] {} @ {} lost job site: distance check failed (off-contraption) plotyard={} global={}", - v.getUUID(), v.blockPosition(), storedPos, globalJobSitePos); - } - return result; - } - - /** Catches the "POI block no longer exists" path. */ - @WrapOperation( - method = "*", - at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/ai/village/poi/PoiManager;exists(Lnet/minecraft/core/BlockPos;Ljava/util/function/Predicate;)Z") - ) - private static boolean sable$logPoiNotFound( - final PoiManager poiManager, final BlockPos pos, final Predicate> predicate, - final Operation original, - @Local(argsOnly = true, ordinal = 0) final LivingEntity entity - ) { - final boolean exists = original.call(poiManager, pos, predicate); - if (!exists && entity instanceof Villager v) { - final SubLevel sl = SubLevelPoiUtil.getSubLevelForPos(entity.level(), pos); - if (sl != null) { - LOGGER.warn("[POI] {} @ {} lost job site: POI no longer exists in PoiManager plotyard={}", - v.getUUID(), v.blockPosition(), pos); - } else { - LOGGER.warn("[POI] {} @ {} lost job site: POI no longer exists in PoiManager pos={}", - v.getUUID(), v.blockPosition(), pos); - } - } - return exists; + return globalJobSitePos.closerThan(entity.position(), dist); } } diff --git a/common/src/main/resources/sable.mixins.json b/common/src/main/resources/sable.mixins.json index 745fc473..e9983cbb 100644 --- a/common/src/main/resources/sable.mixins.json +++ b/common/src/main/resources/sable.mixins.json @@ -142,11 +142,9 @@ "entity.entity_pathfinding.RandomPosMixin", "entity.entity_pathfinding.WalkNodeEvaluatorMixin", "entity.villager_poi.AcquirePoiMixin", - "entity.villager_poi.BrainJobSiteEraseMixin", "entity.villager_poi.AssignProfessionFromJobSiteMixin", "entity.villager_poi.ValidateNearbyPoiMixin", "entity.villager_poi.SetWalkTargetFromBlockMemoryMixin", - "entity.villager_poi.VillagerJobLossMixin", "entity.villager_poi.WorkAtPoiMixin", "entity.entity_rotations_and_riding.BlockMixin", "entity.entity_rotations_and_riding.EntityMixin",