From 8f853da998119d85f7a9359831d4df0ca63e0172 Mon Sep 17 00:00:00 2001
From: Potato <77798144+ThePlasticPotato@users.noreply.github.com>
Date: Fri, 27 Dec 2024 18:07:22 -0500
Subject: [PATCH] Improved Dragging & Entity Interactions on Ships
[Pathfinding, POIs, Raids, etc.] (#1027)
- Mobs & Players are now dragged perfectly, even at ludicrous speed
- Mob spawning on ships has been fixed
- Mob pathfinding on ships has been significantly improved
- Mob rotation on ships has been fixed
- POI finding on ships has been fixed (Villager stations, portals, bee hives, etc)
- Bee flower pathing on ships has been fixed.
- Villages can now be on ships and are tracked correctly.
- Raids can now target ships, and spawn around them.
- Zombie Sieges can now target ships, and spawn around them.
- Player targeting of blocks now works more reliably on ships while at high speeds or rotations.
- Players can now hold open GUIs while on ships at high speeds or rotations.
---
common/build.gradle | 2 +-
.../mod/mixin/client/MixinMinecraft.java | 14 +-
.../client/renderer/MixinEntityRenderer.java | 48 +++++++
.../client/renderer/MixinGameRenderer.java | 6 +-
.../mod/mixin/entity/MixinEntity.java | 87 ++++++++++++
.../ai/goal/JitteredLinearRetryAccessor.java | 14 ++
.../feature/ai/goal/MixinMoveToBlockGoal.java | 25 ++++
.../ai/goal/MixinMoveToTargetSink.java | 20 +++
.../ai/goal/MixinValidateNearbyPoi.java | 21 +++
.../mixin/feature/ai/goal/bees/MixinBee.java | 26 ++++
.../ai/goal/bees/MixinEnterHiveGoal.java | 24 ++++
.../ai/goal/bees/MixinGrowCropGoal.java | 30 +++++
.../ai/goal/bees/MixinLocateHiveGoal.java | 28 ++++
.../ai/goal/bees/MixinPollinateGoal.java | 49 +++++++
.../MixinAssignProfessionFromJobSite.java | 23 ++++
.../villagers/MixinGoToClosestVillage.java | 37 ++++++
.../MixinSetClosestHomeAsWalkTarget.java | 21 +++
.../ai/goal/villagers/MixinWorkAtPoi.java | 29 ++++
.../ai/node_evaluator/MixinPathFinder.java | 40 ++++++
.../node_evaluator/MixinPathNavigation.java | 27 ++++
.../SwimNodeEvaluatorMixin.java | 2 +-
.../WalkNodeEvaluatorMixin.java | 2 +-
.../MixinAirAndWaterRandomPos.java | 47 +++++++
.../MixinDefaultRandomPos.java | 83 ++++++++++++
.../path_retargeting/MixinLandRandomPos.java | 87 ++++++++++++
.../feature/entity_collision/MixinEntity.java | 69 ++++++++++
.../entity_collision/MixinLivingEntity.java | 47 +++++++
.../MixinLocalPlayer.java | 99 ++++++++++++++
.../MixinServerEntity.java | 91 +++++++++++++
.../mod/mixin/feature/poi/FEATURE.md | 1 +
.../mixin/feature/poi/MixinPOIManager.java | 85 ++++++++++++
.../MixinScreenHandler.java | 6 +-
.../mixin/feature/wave_spawning/FEATURE.md | 1 +
.../feature/wave_spawning/MixinRaid.java | 51 +++++++
.../feature/wave_spawning/MixinRaids.java | 31 +++++
.../wave_spawning/MixinVillageSiege.java | 36 +++++
.../MixinReachEntityAttributes.java | 7 +-
.../mixin/server/MixinMinecraftServer.java | 5 +-
.../MixinServerGamePacketListenerImpl.java | 21 +++
.../mod/mixin/server/world/MixinChunkMap.java | 15 +++
.../mixin/server/world/MixinServerLevel.java | 27 ++++
.../mod/mixin/world/entity/MixinPlayer.java | 27 ++++
.../mixinducks/world/entity/PlayerDuck.java | 6 +
.../valkyrienskies/mod/common/PlayerUtil.kt | 4 +-
.../valkyrienskies/mod/common/VSGameUtils.kt | 14 +-
.../mod/common/config/VSGameConfig.kt | 2 +-
.../networking/PacketEntityShipMotion.kt | 20 +++
.../networking/PacketMobShipRotation.kt | 8 ++
.../networking/PacketPlayerShipMotion.kt | 9 ++
.../mod/common/networking/VSGamePackets.kt | 124 ++++++++++++++++++
.../mod/common/util/EntityDragger.kt | 112 +++++++++++++---
.../common/util/EntityDraggingInformation.kt | 31 ++++-
.../mod/common/util/EntityLerper.kt | 110 ++++++++++++++++
.../common/util/EntityShipCollisionUtils.kt | 3 +
.../mod/common/world/POIChunkSearcher.kt | 48 +++++++
.../valkyrienskies-common.accesswidener | 8 ++
.../valkyrienskies-common.mixins.json | 27 +++-
.../forge_interact/MixinIForgePlayer.java | 14 +-
58 files changed, 1915 insertions(+), 36 deletions(-)
create mode 100644 common/src/main/java/org/valkyrienskies/mod/mixin/client/renderer/MixinEntityRenderer.java
create mode 100644 common/src/main/java/org/valkyrienskies/mod/mixin/feature/ai/goal/JitteredLinearRetryAccessor.java
create mode 100644 common/src/main/java/org/valkyrienskies/mod/mixin/feature/ai/goal/MixinMoveToBlockGoal.java
create mode 100644 common/src/main/java/org/valkyrienskies/mod/mixin/feature/ai/goal/MixinMoveToTargetSink.java
create mode 100644 common/src/main/java/org/valkyrienskies/mod/mixin/feature/ai/goal/MixinValidateNearbyPoi.java
create mode 100644 common/src/main/java/org/valkyrienskies/mod/mixin/feature/ai/goal/bees/MixinBee.java
create mode 100644 common/src/main/java/org/valkyrienskies/mod/mixin/feature/ai/goal/bees/MixinEnterHiveGoal.java
create mode 100644 common/src/main/java/org/valkyrienskies/mod/mixin/feature/ai/goal/bees/MixinGrowCropGoal.java
create mode 100644 common/src/main/java/org/valkyrienskies/mod/mixin/feature/ai/goal/bees/MixinLocateHiveGoal.java
create mode 100644 common/src/main/java/org/valkyrienskies/mod/mixin/feature/ai/goal/bees/MixinPollinateGoal.java
create mode 100644 common/src/main/java/org/valkyrienskies/mod/mixin/feature/ai/goal/villagers/MixinAssignProfessionFromJobSite.java
create mode 100644 common/src/main/java/org/valkyrienskies/mod/mixin/feature/ai/goal/villagers/MixinGoToClosestVillage.java
create mode 100644 common/src/main/java/org/valkyrienskies/mod/mixin/feature/ai/goal/villagers/MixinSetClosestHomeAsWalkTarget.java
create mode 100644 common/src/main/java/org/valkyrienskies/mod/mixin/feature/ai/goal/villagers/MixinWorkAtPoi.java
create mode 100644 common/src/main/java/org/valkyrienskies/mod/mixin/feature/ai/node_evaluator/MixinPathFinder.java
create mode 100644 common/src/main/java/org/valkyrienskies/mod/mixin/feature/ai/node_evaluator/MixinPathNavigation.java
create mode 100644 common/src/main/java/org/valkyrienskies/mod/mixin/feature/ai/path_retargeting/MixinAirAndWaterRandomPos.java
create mode 100644 common/src/main/java/org/valkyrienskies/mod/mixin/feature/ai/path_retargeting/MixinDefaultRandomPos.java
create mode 100644 common/src/main/java/org/valkyrienskies/mod/mixin/feature/ai/path_retargeting/MixinLandRandomPos.java
create mode 100644 common/src/main/java/org/valkyrienskies/mod/mixin/feature/entity_collision/MixinLivingEntity.java
create mode 100644 common/src/main/java/org/valkyrienskies/mod/mixin/feature/entity_movement_packets/MixinLocalPlayer.java
create mode 100644 common/src/main/java/org/valkyrienskies/mod/mixin/feature/entity_movement_packets/MixinServerEntity.java
create mode 100644 common/src/main/java/org/valkyrienskies/mod/mixin/feature/poi/FEATURE.md
create mode 100644 common/src/main/java/org/valkyrienskies/mod/mixin/feature/poi/MixinPOIManager.java
create mode 100644 common/src/main/java/org/valkyrienskies/mod/mixin/feature/wave_spawning/FEATURE.md
create mode 100644 common/src/main/java/org/valkyrienskies/mod/mixin/feature/wave_spawning/MixinRaid.java
create mode 100644 common/src/main/java/org/valkyrienskies/mod/mixin/feature/wave_spawning/MixinRaids.java
create mode 100644 common/src/main/java/org/valkyrienskies/mod/mixin/feature/wave_spawning/MixinVillageSiege.java
create mode 100644 common/src/main/kotlin/org/valkyrienskies/mod/common/networking/PacketEntityShipMotion.kt
create mode 100644 common/src/main/kotlin/org/valkyrienskies/mod/common/networking/PacketMobShipRotation.kt
create mode 100644 common/src/main/kotlin/org/valkyrienskies/mod/common/networking/PacketPlayerShipMotion.kt
create mode 100644 common/src/main/kotlin/org/valkyrienskies/mod/common/util/EntityLerper.kt
create mode 100644 common/src/main/kotlin/org/valkyrienskies/mod/common/world/POIChunkSearcher.kt
diff --git a/common/build.gradle b/common/build.gradle
index b62489b44..53a562e11 100644
--- a/common/build.gradle
+++ b/common/build.gradle
@@ -1,6 +1,6 @@
dependencies {
- annotationProcessor(implementation("com.github.LlamaLad7:MixinExtras:0.1.1"))
+ annotationProcessor(implementation("io.github.llamalad7:mixinextras-common:0.3.5"))
compileOnly 'com.google.code.findbugs:jsr305:3.0.2'
// We depend on fabric loader here to use the fabric @Environment annotations
diff --git a/common/src/main/java/org/valkyrienskies/mod/mixin/client/MixinMinecraft.java b/common/src/main/java/org/valkyrienskies/mod/mixin/client/MixinMinecraft.java
index ae6ed83a6..b119a032a 100644
--- a/common/src/main/java/org/valkyrienskies/mod/mixin/client/MixinMinecraft.java
+++ b/common/src/main/java/org/valkyrienskies/mod/mixin/client/MixinMinecraft.java
@@ -103,6 +103,17 @@ public ClientShipWorldCore getShipObjectWorld() {
@Shadow
public abstract ClientPacketListener getConnection();
+ @Inject(
+ method = "tick",
+ at = @At("HEAD")
+ )
+ public void preTick(final CallbackInfo ci) {
+ // Tick the ship world and then drag entities
+ if (!pause && shipObjectWorld != null && level != null && getConnection() != null) {
+ //EntityDragger.INSTANCE.dragEntitiesWithShips(level.entitiesForRendering(), true);
+ }
+ }
+
@Inject(
method = "tick",
at = @At("TAIL")
@@ -112,7 +123,8 @@ public void postTick(final CallbackInfo ci) {
if (!pause && shipObjectWorld != null && level != null && getConnection() != null) {
shipObjectWorld.tickNetworking(getConnection().getConnection().getRemoteAddress());
shipObjectWorld.postTick();
- EntityDragger.INSTANCE.dragEntitiesWithShips(level.entitiesForRendering());
+ //EntityDragger.INSTANCE.dragEntitiesWithShips(level.entitiesForRendering());
+ EntityDragger.INSTANCE.dragEntitiesWithShips(level.entitiesForRendering(), false);
}
}
diff --git a/common/src/main/java/org/valkyrienskies/mod/mixin/client/renderer/MixinEntityRenderer.java b/common/src/main/java/org/valkyrienskies/mod/mixin/client/renderer/MixinEntityRenderer.java
new file mode 100644
index 000000000..975c94f46
--- /dev/null
+++ b/common/src/main/java/org/valkyrienskies/mod/mixin/client/renderer/MixinEntityRenderer.java
@@ -0,0 +1,48 @@
+package org.valkyrienskies.mod.mixin.client.renderer;
+
+import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
+import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
+import net.minecraft.client.multiplayer.ClientLevel;
+import net.minecraft.client.renderer.entity.EntityRenderer;
+import net.minecraft.world.entity.Entity;
+import net.minecraft.world.phys.AABB;
+import org.joml.Vector3d;
+import org.joml.Vector3dc;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.injection.At;
+import org.valkyrienskies.core.api.ships.ClientShip;
+import org.valkyrienskies.mod.common.VSGameUtilsKt;
+import org.valkyrienskies.mod.common.util.EntityDraggingInformation;
+import org.valkyrienskies.mod.common.util.IEntityDraggingInformationProvider;
+
+@Mixin(EntityRenderer.class)
+public class MixinEntityRenderer {
+
+ /**
+ * This is necessary to avoid the vanilla flickering that occurs when entities are at high speeds.
+ *
+ * Presumably, it is caused by the culling AABB only being updated on a subsequent tick, so we bypass that.
+ * @param instance
+ * @param original
+ * @return
+ */
+ @WrapOperation(method = "shouldRender", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/Entity;getBoundingBoxForCulling()Lnet/minecraft/world/phys/AABB;"))
+ private AABB redirectAABBConstructor(Entity instance, Operation original) {
+ if (instance instanceof IEntityDraggingInformationProvider dragProvider && dragProvider.getDraggingInformation().isEntityBeingDraggedByAShip()) {
+ EntityDraggingInformation dragInfo = dragProvider.getDraggingInformation();
+ ClientShip ship = VSGameUtilsKt.getShipObjectWorld((ClientLevel) instance.level).getAllShips().getById(dragInfo.getLastShipStoodOn());
+ if (ship == null) {
+ return original.call(instance);
+ }
+ if (dragInfo.getLastShipStoodOn() != null && (dragInfo.getRelativePositionOnShip() != null || dragInfo.getServerRelativePlayerPosition() != null)) {
+ Vector3dc positionToTransform = dragInfo.bestRelativeEntityPosition();
+ if (positionToTransform != null) {
+ Vector3dc transformed = ship.getRenderTransform().getShipToWorld().transformPosition(positionToTransform,
+ new Vector3d());
+ return instance.getDimensions(instance.getPose()).makeBoundingBox(transformed.x(), transformed.y(), transformed.z()).inflate(0.5D);
+ }
+ }
+ }
+ return original.call(instance);
+ }
+}
diff --git a/common/src/main/java/org/valkyrienskies/mod/mixin/client/renderer/MixinGameRenderer.java b/common/src/main/java/org/valkyrienskies/mod/mixin/client/renderer/MixinGameRenderer.java
index 8b9c6fe44..e626dc4f4 100644
--- a/common/src/main/java/org/valkyrienskies/mod/mixin/client/renderer/MixinGameRenderer.java
+++ b/common/src/main/java/org/valkyrienskies/mod/mixin/client/renderer/MixinGameRenderer.java
@@ -158,7 +158,7 @@ private void preRender(final float tickDelta, final long startTime, final boolea
((IEntityDraggingInformationProvider) entity).getDraggingInformation();
final Long lastShipStoodOn = entityDraggingInformation.getLastShipStoodOn();
// Then try getting [entityShouldBeHere] from [entityDraggingInformation]
- if (lastShipStoodOn != null && entityDraggingInformation.isEntityBeingDraggedByAShip()) {
+ if (lastShipStoodOn != null && entityDraggingInformation.isEntityBeingDraggedByAShip()) { //for testing
final ClientShip shipObject =
VSGameUtilsKt.getShipObjectWorld(clientWorld).getLoadedShips().getById(lastShipStoodOn);
if (shipObject != null) {
@@ -200,6 +200,10 @@ private void preRender(final float tickDelta, final long startTime, final boolea
entity.xo = (entityShouldBeHere.x() - (entity.getX() * tickDelta)) / (1.0 - tickDelta);
entity.yo = (entityShouldBeHere.y() - (entity.getY() * tickDelta)) / (1.0 - tickDelta);
entity.zo = (entityShouldBeHere.z() - (entity.getZ() * tickDelta)) / (1.0 - tickDelta);
+ //why the fuck do we do this
+
+ //what if i just...
+ //dont
}
}
}
diff --git a/common/src/main/java/org/valkyrienskies/mod/mixin/entity/MixinEntity.java b/common/src/main/java/org/valkyrienskies/mod/mixin/entity/MixinEntity.java
index 7b5178cfc..e81068d6b 100644
--- a/common/src/main/java/org/valkyrienskies/mod/mixin/entity/MixinEntity.java
+++ b/common/src/main/java/org/valkyrienskies/mod/mixin/entity/MixinEntity.java
@@ -5,7 +5,9 @@
import net.minecraft.CrashReport;
import net.minecraft.CrashReportCategory;
import net.minecraft.ReportedException;
+import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.core.BlockPos;
+import net.minecraft.server.level.ServerPlayer;
import net.minecraft.util.Mth;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntityType;
@@ -33,6 +35,7 @@
import org.valkyrienskies.core.api.ships.properties.ShipTransform;
import org.valkyrienskies.mod.common.entity.ShipMountedToData;
import org.valkyrienskies.mod.common.VSGameUtilsKt;
+import org.valkyrienskies.mod.common.util.EntityDragger;
import org.valkyrienskies.mod.common.util.EntityDraggingInformation;
import org.valkyrienskies.mod.common.util.IEntityDraggingInformationProvider;
import org.valkyrienskies.mod.common.util.VectorConversionsMCKt;
@@ -127,11 +130,67 @@ private void preGetEyePosition(final float partialTicks, final CallbackInfoRetur
/**
* @reason Needed for players to pick blocks correctly when mounted to a ship
+ *
+ * Needed, because before we only fixed the clientside one.
+ */
+ @Inject(method = "getEyePosition()Lnet/minecraft/world/phys/Vec3;", at = @At("HEAD"), cancellable = true)
+ private void preGetEyePositionServer(final CallbackInfoReturnable cir) {
+ final ShipMountedToData shipMountedToData = VSGameUtilsKt.getShipMountedToData(Entity.class.cast(this), null);
+ if (shipMountedToData == null) {
+ return;
+ }
+ final LoadedShip shipMountedTo = shipMountedToData.getShipMountedTo();
+
+ final ShipTransform shipTransform;
+ if (shipMountedTo instanceof ClientShip) {
+ shipTransform = ((ClientShip) shipMountedTo).getRenderTransform();
+ } else {
+ shipTransform = shipMountedTo.getShipTransform();
+ }
+ final Vector3dc basePos = shipTransform.getShipToWorldMatrix()
+ .transformPosition(shipMountedToData.getMountPosInShip(), new Vector3d());
+ final Vector3dc eyeRelativePos = shipTransform.getShipCoordinatesToWorldCoordinatesRotation().transform(
+ new Vector3d(0.0, getEyeHeight(), 0.0)
+ );
+ final Vec3 newEyePos = VectorConversionsMCKt.toMinecraft(basePos.add(eyeRelativePos, new Vector3d()));
+ cir.setReturnValue(newEyePos);
+ }
+
+ /**
+ * @reason Needed for players to pick blocks correctly when mounted to a ship
+ *
+ * Additionally, this has to have dragging information included or it breaks. This is because of reasons that I literally
+ * do not know or understand, but minecraft's rendering pipeline is like that.
*/
@Inject(method = "calculateViewVector", at = @At("HEAD"), cancellable = true)
private void preCalculateViewVector(final float xRot, final float yRot, final CallbackInfoReturnable cir) {
final LoadedShip shipMountedTo = VSGameUtilsKt.getShipMountedTo(Entity.class.cast(this));
if (shipMountedTo == null) {
+ if (Entity.class.cast(this) instanceof final ServerPlayer sPlayer && sPlayer instanceof final IEntityDraggingInformationProvider dragProvider) {
+ if (dragProvider.getDraggingInformation().isEntityBeingDraggedByAShip() && dragProvider.getDraggingInformation().getServerRelativePlayerYaw() != null) {
+ final Ship shipDraggedBy = VSGameUtilsKt.getAllShips(level).getById(dragProvider.getDraggingInformation().getLastShipStoodOn());
+ if (shipDraggedBy != null) {
+ final float realYRot = (float) EntityDragger.INSTANCE.serversideEyeRotationOrDefault(sPlayer, yRot);
+ final float f = xRot * (float) (Math.PI / 180.0);
+ final float g = -realYRot * (float) (Math.PI / 180.0);
+ final float h = Mth.cos(g);
+ final float i = Mth.sin(g);
+ final float j = Mth.cos(f);
+ final float k = Mth.sin(f);
+ final Vector3dc originalViewVector = new Vector3d(i * j, -k, h * j);
+
+ final ShipTransform shipTransform;
+ if (shipDraggedBy instanceof ClientShip) {
+ shipTransform = ((ClientShip) shipDraggedBy).getRenderTransform();
+ } else {
+ shipTransform = shipDraggedBy.getShipTransform();
+ }
+ final Vec3 newViewVector = VectorConversionsMCKt.toMinecraft(
+ shipTransform.getShipCoordinatesToWorldCoordinatesRotation().transform(originalViewVector, new Vector3d()));
+ cir.setReturnValue(newViewVector);
+ }
+ }
+ }
return;
}
final float f = xRot * (float) (Math.PI / 180.0);
@@ -153,6 +212,28 @@ private void preCalculateViewVector(final float xRot, final float yRot, final Ca
cir.setReturnValue(newViewVector);
}
+ /**
+ * @reason Without this and that other mixin, things don't render correctly at high speeds.
+ * @see org.valkyrienskies.mod.mixin.client.renderer.MixinEntityRenderer
+ */
+ @Inject(method = "shouldRender", at = @At("HEAD"), cancellable = true)
+ private void onShouldRender(double d, double e, double f, CallbackInfoReturnable cir) {
+ if (this.draggingInformation.isEntityBeingDraggedByAShip() && this.level.isClientSide) {
+ final ClientShip ship = VSGameUtilsKt.getShipObjectWorld((ClientLevel) this.level).getAllShips().getById(this.draggingInformation.getLastShipStoodOn());
+ if (ship != null) {
+ final ShipTransform shipTransform = ship.getRenderTransform();
+ if (this.draggingInformation.getRelativePositionOnShip() != null) {
+ Vector3dc redir = shipTransform.getShipToWorld().transformPosition(this.draggingInformation.getRelativePositionOnShip(), new Vector3d());
+ double distX = redir.x() - d;
+ double distY = redir.y() - e;
+ double distZ = redir.z() - f;
+ double sqrDist = distX * distX + distY * distY + distZ * distZ;
+ cir.setReturnValue(shouldRenderAtSqrDistance(sqrDist));
+ }
+ }
+ }
+ }
+
// region shadow functions and fields
@Shadow
public Level level;
@@ -183,6 +264,12 @@ private void preCalculateViewVector(final float xRot, final float yRot, final Ca
@Shadow
public abstract EntityType> getType();
+ @Shadow
+ private float yRot;
+
+ @Shadow
+ public abstract boolean shouldRenderAtSqrDistance(double d);
+
@Override
@NotNull
public EntityDraggingInformation getDraggingInformation() {
diff --git a/common/src/main/java/org/valkyrienskies/mod/mixin/feature/ai/goal/JitteredLinearRetryAccessor.java b/common/src/main/java/org/valkyrienskies/mod/mixin/feature/ai/goal/JitteredLinearRetryAccessor.java
new file mode 100644
index 000000000..ce154c9e4
--- /dev/null
+++ b/common/src/main/java/org/valkyrienskies/mod/mixin/feature/ai/goal/JitteredLinearRetryAccessor.java
@@ -0,0 +1,14 @@
+package org.valkyrienskies.mod.mixin.feature.ai.goal;
+
+import java.util.Random;
+import net.minecraft.world.entity.ai.behavior.AcquirePoi.JitteredLinearRetry;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.gen.Invoker;
+
+@Mixin(JitteredLinearRetry.class)
+public interface JitteredLinearRetryAccessor {
+ @Invoker("")
+ static JitteredLinearRetry create(Random random, long l) {
+ throw new AssertionError();
+ }
+}
diff --git a/common/src/main/java/org/valkyrienskies/mod/mixin/feature/ai/goal/MixinMoveToBlockGoal.java b/common/src/main/java/org/valkyrienskies/mod/mixin/feature/ai/goal/MixinMoveToBlockGoal.java
new file mode 100644
index 000000000..da31ae88f
--- /dev/null
+++ b/common/src/main/java/org/valkyrienskies/mod/mixin/feature/ai/goal/MixinMoveToBlockGoal.java
@@ -0,0 +1,25 @@
+package org.valkyrienskies.mod.mixin.feature.ai.goal;
+
+import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
+import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
+import net.minecraft.core.BlockPos;
+import net.minecraft.core.Position;
+import net.minecraft.world.entity.PathfinderMob;
+import net.minecraft.world.entity.ai.goal.MoveToBlockGoal;
+import org.spongepowered.asm.mixin.Final;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.Shadow;
+import org.spongepowered.asm.mixin.injection.At;
+import org.valkyrienskies.mod.common.VSGameUtilsKt;
+
+@Mixin(MoveToBlockGoal.class)
+public class MixinMoveToBlockGoal {
+ @Shadow
+ @Final
+ protected PathfinderMob mob;
+
+ @WrapOperation(method = "tick", at = @At(value = "INVOKE", target = "Lnet/minecraft/core/BlockPos;closerToCenterThan(Lnet/minecraft/core/Position;D)Z"))
+ private boolean onCloserToCenterThan(BlockPos instance, Position position, double v, Operation original) {
+ return original.call(new BlockPos(VSGameUtilsKt.toWorldCoordinates(this.mob.level, instance)), position, v);
+ }
+}
diff --git a/common/src/main/java/org/valkyrienskies/mod/mixin/feature/ai/goal/MixinMoveToTargetSink.java b/common/src/main/java/org/valkyrienskies/mod/mixin/feature/ai/goal/MixinMoveToTargetSink.java
new file mode 100644
index 000000000..9f4c2e66e
--- /dev/null
+++ b/common/src/main/java/org/valkyrienskies/mod/mixin/feature/ai/goal/MixinMoveToTargetSink.java
@@ -0,0 +1,20 @@
+package org.valkyrienskies.mod.mixin.feature.ai.goal;
+
+import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
+import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
+import com.llamalad7.mixinextras.sugar.Local;
+import net.minecraft.core.BlockPos;
+import net.minecraft.core.Vec3i;
+import net.minecraft.world.entity.Mob;
+import net.minecraft.world.entity.ai.behavior.MoveToTargetSink;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.injection.At;
+import org.valkyrienskies.mod.common.VSGameUtilsKt;
+
+@Mixin(MoveToTargetSink.class)
+public class MixinMoveToTargetSink {
+ @WrapOperation(method = "reachedTarget", at = @At(value = "INVOKE", target = "Lnet/minecraft/core/BlockPos;distManhattan(Lnet/minecraft/core/Vec3i;)I"))
+ private int onDistManhattan(BlockPos instance, Vec3i vec3i, Operation original, @Local(argsOnly = true) Mob mob) {
+ return original.call(new BlockPos(VSGameUtilsKt.toWorldCoordinates(mob.level, instance)), vec3i);
+ }
+}
diff --git a/common/src/main/java/org/valkyrienskies/mod/mixin/feature/ai/goal/MixinValidateNearbyPoi.java b/common/src/main/java/org/valkyrienskies/mod/mixin/feature/ai/goal/MixinValidateNearbyPoi.java
new file mode 100644
index 000000000..c080e3ec1
--- /dev/null
+++ b/common/src/main/java/org/valkyrienskies/mod/mixin/feature/ai/goal/MixinValidateNearbyPoi.java
@@ -0,0 +1,21 @@
+package org.valkyrienskies.mod.mixin.feature.ai.goal;
+
+import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
+import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
+import com.llamalad7.mixinextras.sugar.Local;
+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 org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.injection.At;
+import org.valkyrienskies.mod.common.VSGameUtilsKt;
+
+@Mixin(ValidateNearbyPoi.class)
+public class MixinValidateNearbyPoi {
+ @WrapOperation(method = "checkExtraStartConditions", at = @At(value = "INVOKE", target = "Lnet/minecraft/core/BlockPos;closerToCenterThan(Lnet/minecraft/core/Position;D)Z"))
+ private boolean onCloserToCenterThan(BlockPos instance, Position position, double v, Operation original, @Local
+ LivingEntity livingEntity) {
+ return original.call(new BlockPos(VSGameUtilsKt.toWorldCoordinates(livingEntity.level, instance)), position, v);
+ }
+}
diff --git a/common/src/main/java/org/valkyrienskies/mod/mixin/feature/ai/goal/bees/MixinBee.java b/common/src/main/java/org/valkyrienskies/mod/mixin/feature/ai/goal/bees/MixinBee.java
new file mode 100644
index 000000000..32cb2d2d5
--- /dev/null
+++ b/common/src/main/java/org/valkyrienskies/mod/mixin/feature/ai/goal/bees/MixinBee.java
@@ -0,0 +1,26 @@
+package org.valkyrienskies.mod.mixin.feature.ai.goal.bees;
+
+import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
+import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
+import net.minecraft.core.BlockPos;
+import net.minecraft.core.Vec3i;
+import net.minecraft.world.entity.Entity;
+import net.minecraft.world.entity.EntityType;
+import net.minecraft.world.entity.animal.Bee;
+import net.minecraft.world.level.Level;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.injection.At;
+import org.valkyrienskies.mod.common.VSGameUtilsKt;
+
+@Mixin(Bee.class)
+public abstract class MixinBee extends Entity {
+
+ public MixinBee(EntityType> entityType, Level level) {
+ super(entityType, level);
+ }
+
+ @WrapOperation(method = "closerThan", at = @At(value = "INVOKE", target = "Lnet/minecraft/core/BlockPos;closerThan(Lnet/minecraft/core/Vec3i;D)Z"))
+ private boolean onCloserThan(BlockPos instance, Vec3i vec3i, double v, Operation original) {
+ return original.call(new BlockPos(VSGameUtilsKt.toWorldCoordinates(this.level, instance)), vec3i, v);
+ }
+}
diff --git a/common/src/main/java/org/valkyrienskies/mod/mixin/feature/ai/goal/bees/MixinEnterHiveGoal.java b/common/src/main/java/org/valkyrienskies/mod/mixin/feature/ai/goal/bees/MixinEnterHiveGoal.java
new file mode 100644
index 000000000..4822cff88
--- /dev/null
+++ b/common/src/main/java/org/valkyrienskies/mod/mixin/feature/ai/goal/bees/MixinEnterHiveGoal.java
@@ -0,0 +1,24 @@
+package org.valkyrienskies.mod.mixin.feature.ai.goal.bees;
+
+import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
+import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
+import net.minecraft.core.BlockPos;
+import net.minecraft.core.Position;
+import net.minecraft.world.entity.animal.Bee;
+import org.spongepowered.asm.mixin.Final;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.Shadow;
+import org.spongepowered.asm.mixin.injection.At;
+import org.valkyrienskies.mod.common.VSGameUtilsKt;
+
+@Mixin(Bee.BeeEnterHiveGoal.class)
+public class MixinEnterHiveGoal {
+ @Shadow
+ @Final
+ Bee field_20367;
+
+ @WrapOperation(method = "canBeeUse", at = @At(value = "INVOKE", target = "Lnet/minecraft/core/BlockPos;closerToCenterThan(Lnet/minecraft/core/Position;D)Z"))
+ private boolean onCloserToCenterThan(BlockPos instance, Position position, double v, Operation original) {
+ return original.call(new BlockPos(VSGameUtilsKt.toWorldCoordinates(this.field_20367.level, instance)), position, v);
+ }
+}
diff --git a/common/src/main/java/org/valkyrienskies/mod/mixin/feature/ai/goal/bees/MixinGrowCropGoal.java b/common/src/main/java/org/valkyrienskies/mod/mixin/feature/ai/goal/bees/MixinGrowCropGoal.java
new file mode 100644
index 000000000..8d04cea70
--- /dev/null
+++ b/common/src/main/java/org/valkyrienskies/mod/mixin/feature/ai/goal/bees/MixinGrowCropGoal.java
@@ -0,0 +1,30 @@
+package org.valkyrienskies.mod.mixin.feature.ai.goal.bees;
+
+import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
+import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
+import java.util.List;
+import net.minecraft.core.BlockPos;
+import net.minecraft.tags.BlockTags;
+import net.minecraft.world.entity.animal.Bee;
+import net.minecraft.world.level.Level;
+import net.minecraft.world.level.block.state.BlockState;
+import org.joml.Vector3d;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.injection.At;
+import org.valkyrienskies.mod.common.VSGameUtilsKt;
+
+@Mixin(Bee.BeeGrowCropGoal.class)
+public class MixinGrowCropGoal {
+ @WrapOperation(method = "tick", at = @At(value = "INVOKE",
+ target = "Lnet/minecraft/world/level/Level;getBlockState(Lnet/minecraft/core/BlockPos;)Lnet/minecraft/world/level/block/state/BlockState;"))
+ private BlockState onTick(Level instance, BlockPos blockPos, Operation original) {
+ List possibleCandidates = VSGameUtilsKt.transformToNearbyShipsAndWorld(instance, blockPos.getX(), blockPos.getY(), blockPos.getZ(), 1.5);
+ for (Vector3d candidate : possibleCandidates) {
+ BlockState blockState = instance.getBlockState(new BlockPos(candidate.x, candidate.y, candidate.z));
+ if (blockState.is(BlockTags.BEE_GROWABLES)) {
+ return blockState;
+ }
+ }
+ return original.call(instance, blockPos);
+ }
+}
diff --git a/common/src/main/java/org/valkyrienskies/mod/mixin/feature/ai/goal/bees/MixinLocateHiveGoal.java b/common/src/main/java/org/valkyrienskies/mod/mixin/feature/ai/goal/bees/MixinLocateHiveGoal.java
new file mode 100644
index 000000000..c70ea7cb5
--- /dev/null
+++ b/common/src/main/java/org/valkyrienskies/mod/mixin/feature/ai/goal/bees/MixinLocateHiveGoal.java
@@ -0,0 +1,28 @@
+package org.valkyrienskies.mod.mixin.feature.ai.goal.bees;
+
+import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
+import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
+import com.llamalad7.mixinextras.sugar.Local;
+import java.util.Comparator;
+import java.util.stream.Stream;
+import net.minecraft.core.BlockPos;
+import net.minecraft.world.entity.animal.Bee;
+import net.minecraft.world.entity.animal.Bee.BeeLocateHiveGoal;
+import org.spongepowered.asm.mixin.Final;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.Shadow;
+import org.spongepowered.asm.mixin.injection.At;
+import org.valkyrienskies.mod.common.VSGameUtilsKt;
+
+@Mixin(BeeLocateHiveGoal.class)
+public class MixinLocateHiveGoal {
+ @Shadow
+ @Final
+ Bee field_20375;
+
+ @WrapOperation(method = "findNearbyHivesWithSpace", at = @At(value = "INVOKE", target = "Ljava/util/stream/Stream;sorted(Ljava/util/Comparator;)Ljava/util/stream/Stream;"))
+ private Stream onComparingDouble(Stream instance, Comparator comparator,
+ Operation> original, @Local BlockPos blockPos) {
+ return original.call(instance, Comparator.comparingDouble( pos -> new BlockPos(VSGameUtilsKt.toWorldCoordinates(this.field_20375.level, (BlockPos) pos)).distSqr(blockPos)));
+ }
+}
diff --git a/common/src/main/java/org/valkyrienskies/mod/mixin/feature/ai/goal/bees/MixinPollinateGoal.java b/common/src/main/java/org/valkyrienskies/mod/mixin/feature/ai/goal/bees/MixinPollinateGoal.java
new file mode 100644
index 000000000..20d97823d
--- /dev/null
+++ b/common/src/main/java/org/valkyrienskies/mod/mixin/feature/ai/goal/bees/MixinPollinateGoal.java
@@ -0,0 +1,49 @@
+package org.valkyrienskies.mod.mixin.feature.ai.goal.bees;
+
+import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
+import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
+import java.util.Comparator;
+import java.util.Optional;
+import java.util.function.Predicate;
+import net.minecraft.core.BlockPos;
+import net.minecraft.world.entity.animal.Bee;
+import net.minecraft.world.level.block.state.BlockState;
+import org.spongepowered.asm.mixin.Final;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.Shadow;
+import org.spongepowered.asm.mixin.Unique;
+import org.spongepowered.asm.mixin.injection.At;
+import org.spongepowered.asm.mixin.injection.Inject;
+import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
+import org.valkyrienskies.mod.common.VSGameUtilsKt;
+
+@Mixin(Bee.BeePollinateGoal.class)
+public abstract class MixinPollinateGoal {
+ @Shadow
+ @Final
+ Bee field_20377;
+
+ @Shadow
+ protected abstract Optional findNearestBlock(Predicate predicate, double d);
+
+ @Shadow
+ @Final
+ private Predicate VALID_POLLINATION_BLOCKS;
+ @Unique
+ private BlockPos modifiedBeePosition = field_20377.blockPosition();
+
+ @Inject(method = "findNearbyFlower", at = @At("HEAD"), cancellable = true)
+ private void preFindNearbyFlower(CallbackInfoReturnable> cir) {
+ Optional res = VSGameUtilsKt.transformToNearbyShipsAndWorld(this.field_20377.level, modifiedBeePosition.getX(), modifiedBeePosition.getY(), modifiedBeePosition.getZ(), 5.0).stream().flatMap(pos -> {
+ this.modifiedBeePosition = new BlockPos(pos.x, pos.y, pos.z);
+ return findNearestBlock(VALID_POLLINATION_BLOCKS, 5.0).stream();
+ }).min(Comparator.comparingDouble(pos -> VSGameUtilsKt.squaredDistanceBetweenInclShips(this.field_20377.level, modifiedBeePosition.getX(), modifiedBeePosition.getY(), modifiedBeePosition.getZ(), pos.getX(), pos.getY(), pos.getZ())));
+ modifiedBeePosition = field_20377.blockPosition();
+ cir.setReturnValue(res);
+ }
+
+ @WrapOperation(method = "findNearestBlock", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/animal/Bee;blockPosition()Lnet/minecraft/core/BlockPos;"))
+ private BlockPos onBlockPosition(Bee instance, Operation original) {
+ return modifiedBeePosition;
+ }
+}
diff --git a/common/src/main/java/org/valkyrienskies/mod/mixin/feature/ai/goal/villagers/MixinAssignProfessionFromJobSite.java b/common/src/main/java/org/valkyrienskies/mod/mixin/feature/ai/goal/villagers/MixinAssignProfessionFromJobSite.java
new file mode 100644
index 000000000..9622b37e7
--- /dev/null
+++ b/common/src/main/java/org/valkyrienskies/mod/mixin/feature/ai/goal/villagers/MixinAssignProfessionFromJobSite.java
@@ -0,0 +1,23 @@
+package org.valkyrienskies.mod.mixin.feature.ai.goal.villagers;
+
+import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
+import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
+import com.llamalad7.mixinextras.sugar.Local;
+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;
+import org.valkyrienskies.mod.common.VSGameUtilsKt;
+
+@Mixin(AssignProfessionFromJobSite.class)
+public class MixinAssignProfessionFromJobSite {
+ @WrapOperation(method = "checkExtraStartConditions(Lnet/minecraft/server/level/ServerLevel;Lnet/minecraft/world/entity/npc/Villager;)Z", at = @At(
+ value = "INVOKE",
+ target = "Lnet/minecraft/core/BlockPos;closerToCenterThan(Lnet/minecraft/core/Position;D)Z"))
+ private boolean onCloserToCenterThan(BlockPos instance, Position position, double v, Operation original, @Local
+ Villager villager) {
+ return original.call(new BlockPos(VSGameUtilsKt.toWorldCoordinates(villager.level, instance)), position, v);
+ }
+}
diff --git a/common/src/main/java/org/valkyrienskies/mod/mixin/feature/ai/goal/villagers/MixinGoToClosestVillage.java b/common/src/main/java/org/valkyrienskies/mod/mixin/feature/ai/goal/villagers/MixinGoToClosestVillage.java
new file mode 100644
index 000000000..daeef208d
--- /dev/null
+++ b/common/src/main/java/org/valkyrienskies/mod/mixin/feature/ai/goal/villagers/MixinGoToClosestVillage.java
@@ -0,0 +1,37 @@
+package org.valkyrienskies.mod.mixin.feature.ai.goal.villagers;
+
+import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
+import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
+import com.llamalad7.mixinextras.sugar.Local;
+import net.minecraft.core.BlockPos;
+import net.minecraft.core.SectionPos;
+import net.minecraft.world.entity.ai.behavior.GoToClosestVillage;
+import net.minecraft.world.entity.ai.village.poi.PoiManager;
+import net.minecraft.world.entity.npc.Villager;
+import net.minecraft.world.phys.Vec3;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.injection.At;
+import org.valkyrienskies.mod.common.VSGameUtilsKt;
+
+@Mixin(GoToClosestVillage.class)
+public class MixinGoToClosestVillage {
+ @WrapOperation(method = "start(Lnet/minecraft/server/level/ServerLevel;Lnet/minecraft/world/entity/npc/Villager;J)V", at = @At(
+ value = "INVOKE", target = "Lnet/minecraft/world/entity/ai/village/poi/PoiManager;sectionsToVillage(Lnet/minecraft/core/SectionPos;)I", ordinal = 0))
+ private int onSectionsToVillageInitial(PoiManager poiManager, SectionPos sectionPos, Operation original, @Local Villager villager) {
+ int[] currentLevels = {original.call(poiManager, sectionPos)};
+ VSGameUtilsKt.transformToNearbyShipsAndWorld(villager.level, villager.getX(), villager.getY(), villager.getZ(), 100, (double x, double y, double z) -> {
+ currentLevels[0] = Math.min(currentLevels[0], original.call(poiManager, SectionPos.of(new BlockPos(x, y, z))));
+ });
+ return currentLevels[0];
+ }
+
+ @WrapOperation(method = "start(Lnet/minecraft/server/level/ServerLevel;Lnet/minecraft/world/entity/npc/Villager;J)V", at = @At(
+ value = "INVOKE", target = "Lnet/minecraft/world/entity/ai/village/poi/PoiManager;sectionsToVillage(Lnet/minecraft/core/SectionPos;)I", ordinal = 1))
+ private int onSectionsToVillageVec3(PoiManager poiManager, SectionPos sectionPos, Operation original, @Local Villager villager, @Local(ordinal = 1) Vec3 vec32) {
+ int[] currentLevels = {original.call(poiManager, sectionPos)};
+ VSGameUtilsKt.transformToNearbyShipsAndWorld(villager.level, vec32.x, vec32.y, vec32.z, 100, (double x, double y, double z) -> {
+ currentLevels[0] = Math.min(currentLevels[0], original.call(poiManager, SectionPos.of(new BlockPos(x, y, z))));
+ });
+ return currentLevels[0];
+ }
+}
diff --git a/common/src/main/java/org/valkyrienskies/mod/mixin/feature/ai/goal/villagers/MixinSetClosestHomeAsWalkTarget.java b/common/src/main/java/org/valkyrienskies/mod/mixin/feature/ai/goal/villagers/MixinSetClosestHomeAsWalkTarget.java
new file mode 100644
index 000000000..b438dad80
--- /dev/null
+++ b/common/src/main/java/org/valkyrienskies/mod/mixin/feature/ai/goal/villagers/MixinSetClosestHomeAsWalkTarget.java
@@ -0,0 +1,21 @@
+package org.valkyrienskies.mod.mixin.feature.ai.goal.villagers;
+
+import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
+import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
+import com.llamalad7.mixinextras.sugar.Local;
+
+import net.minecraft.core.BlockPos;
+import net.minecraft.core.Vec3i;
+import net.minecraft.world.entity.LivingEntity;
+import net.minecraft.world.entity.ai.behavior.SetClosestHomeAsWalkTarget;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.injection.At;
+import org.valkyrienskies.mod.common.VSGameUtilsKt;
+
+@Mixin(SetClosestHomeAsWalkTarget.class)
+public class MixinSetClosestHomeAsWalkTarget {
+ @WrapOperation(method = "checkExtraStartConditions", at = @At(value = "INVOKE", target = "Lnet/minecraft/core/BlockPos;distSqr(Lnet/minecraft/core/Vec3i;)D"))
+ private double onDistSqr(BlockPos instance, Vec3i vec3i, Operation original, @Local LivingEntity livingEntity) {
+ return original.call(new BlockPos(VSGameUtilsKt.toWorldCoordinates(livingEntity.level, instance)), vec3i);
+ }
+}
diff --git a/common/src/main/java/org/valkyrienskies/mod/mixin/feature/ai/goal/villagers/MixinWorkAtPoi.java b/common/src/main/java/org/valkyrienskies/mod/mixin/feature/ai/goal/villagers/MixinWorkAtPoi.java
new file mode 100644
index 000000000..0d3c1b5c4
--- /dev/null
+++ b/common/src/main/java/org/valkyrienskies/mod/mixin/feature/ai/goal/villagers/MixinWorkAtPoi.java
@@ -0,0 +1,29 @@
+package org.valkyrienskies.mod.mixin.feature.ai.goal.villagers;
+
+import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
+import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
+import com.llamalad7.mixinextras.sugar.Local;
+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;
+import org.valkyrienskies.mod.common.VSGameUtilsKt;
+
+@Mixin(WorkAtPoi.class)
+public class MixinWorkAtPoi {
+ @WrapOperation(method = "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 onCloserToCenterThan(BlockPos instance, Position position, double v, Operation original, @Local
+ Villager villager) {
+ return original.call(new BlockPos(VSGameUtilsKt.toWorldCoordinates(villager.level, instance)), position, v);
+ }
+ @WrapOperation(method = "checkExtraStartConditions(Lnet/minecraft/server/level/ServerLevel;Lnet/minecraft/world/entity/npc/Villager;)Z", at = @At(
+ value = "INVOKE", target = "Lnet/minecraft/core/BlockPos;closerToCenterThan(Lnet/minecraft/core/Position;D)Z"
+ ))
+ private boolean onCloserToCenterThan2(BlockPos instance, Position position, double v, Operation original, @Local
+ Villager villager) {
+ return original.call(new BlockPos(VSGameUtilsKt.toWorldCoordinates(villager.level, instance)), position, v);
+ }
+}
diff --git a/common/src/main/java/org/valkyrienskies/mod/mixin/feature/ai/node_evaluator/MixinPathFinder.java b/common/src/main/java/org/valkyrienskies/mod/mixin/feature/ai/node_evaluator/MixinPathFinder.java
new file mode 100644
index 000000000..491db5a3c
--- /dev/null
+++ b/common/src/main/java/org/valkyrienskies/mod/mixin/feature/ai/node_evaluator/MixinPathFinder.java
@@ -0,0 +1,40 @@
+package org.valkyrienskies.mod.mixin.feature.ai.node_evaluator;
+
+import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
+import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
+import com.llamalad7.mixinextras.sugar.Local;
+import java.util.Map;
+import java.util.function.Function;
+import java.util.stream.Collector;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+import net.minecraft.core.BlockPos;
+import net.minecraft.world.entity.Mob;
+import net.minecraft.world.level.pathfinder.NodeEvaluator;
+import net.minecraft.world.level.pathfinder.PathFinder;
+import net.minecraft.world.level.pathfinder.Target;
+import org.spongepowered.asm.mixin.Final;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.Shadow;
+import org.spongepowered.asm.mixin.injection.At;
+import org.valkyrienskies.mod.common.VSGameUtilsKt;
+
+@Mixin(PathFinder.class)
+public class MixinPathFinder {
+ @Shadow
+ @Final
+ private NodeEvaluator nodeEvaluator;
+
+ @WrapOperation(
+ method = "findPath(Lnet/minecraft/world/level/PathNavigationRegion;Lnet/minecraft/world/entity/Mob;Ljava/util/Set;FIF)Lnet/minecraft/world/level/pathfinder/Path;",
+ at = @At(
+ value = "INVOKE",
+ target = "Ljava/util/stream/Stream;collect(Ljava/util/stream/Collector;)Ljava/lang/Object;"))
+ private Object onCollectPath(Stream instance, Collector> arCollector, Operation