@@ -0,0 +1,49 @@
|
||||
package com.dynamitos.mixin;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
import net.minecraft.block.Blocks;
|
||||
import net.minecraft.entity.ai.brain.task.MoveItemsTask;
|
||||
import net.minecraft.entity.passive.CopperGolemBrain;
|
||||
import net.minecraft.entity.passive.CopperGolemEntity;
|
||||
import net.minecraft.entity.passive.CopperGolemState;
|
||||
import net.minecraft.inventory.Inventory;
|
||||
import net.minecraft.sound.SoundEvent;
|
||||
|
||||
@Mixin(CopperGolemBrain.class)
|
||||
public abstract class CopperGolemBrainMixin {
|
||||
@Inject(method = "createInteractionCallback", at = @At("HEAD"), cancellable = true)
|
||||
private static void createInteractionCallback(CopperGolemState state, @Nullable SoundEvent soundEvent,
|
||||
CallbackInfoReturnable<MoveItemsTask.InteractionCallback> callbackInfo) {
|
||||
callbackInfo.setReturnValue((pathAwareEntity, storage, interactionTicks) -> {
|
||||
if (pathAwareEntity instanceof CopperGolemEntity copperGolemEntity) {
|
||||
Inventory inventory = storage.inventory();
|
||||
if (interactionTicks == 1) {
|
||||
if (!storage.state().isOf(Blocks.FARMLAND)) {
|
||||
inventory.onOpen(copperGolemEntity);
|
||||
}
|
||||
copperGolemEntity.setTargetContainerPos(storage.pos());
|
||||
copperGolemEntity.setState(state);
|
||||
}
|
||||
|
||||
if (interactionTicks == 9 && soundEvent != null) {
|
||||
copperGolemEntity.playSoundIfNotSilent(soundEvent);
|
||||
}
|
||||
|
||||
if (interactionTicks == 60) {
|
||||
if (!storage.state().isOf(Blocks.FARMLAND)) {
|
||||
if (inventory.getViewingUsers().contains(pathAwareEntity)) {
|
||||
inventory.onClose(copperGolemEntity);
|
||||
}
|
||||
}
|
||||
|
||||
copperGolemEntity.resetTargetContainerPos();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
package com.dynamitos.mixin;
|
||||
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
@Mixin(MinecraftServer.class)
|
||||
public class ExampleMixin {
|
||||
@Inject(at = @At("HEAD"), method = "loadWorld")
|
||||
private void init(CallbackInfo info) {
|
||||
// This code is injected into the start of MinecraftServer.loadWorld()V
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
package com.dynamitos.mixin;
|
||||
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.gen.Accessor;
|
||||
import org.spongepowered.asm.mixin.gen.Invoker;
|
||||
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.entity.ai.brain.task.MoveItemsTask;
|
||||
import net.minecraft.entity.mob.PathAwareEntity;
|
||||
import net.minecraft.inventory.Inventory;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.math.Box;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
@Mixin(MoveItemsTask.class)
|
||||
public interface MoveItemsTaskAccessor {
|
||||
@Accessor("interactionState")
|
||||
void copperfarmers$setInteractionState(MoveItemsTask.InteractionState state);
|
||||
|
||||
@Accessor("interactionTicks")
|
||||
int copperfarmers$getInteractionTicks();
|
||||
|
||||
@Accessor("interactionTicks")
|
||||
void copperfarmers$setInteractionTicks(int ticks);
|
||||
|
||||
@Invoker("getSearchBoundingBox")
|
||||
Box copperfarmers$getSearchBoundingBox(PathAwareEntity entity);
|
||||
|
||||
@Invoker("atCenterY")
|
||||
Vec3d copperfarmers$atCenterY(PathAwareEntity entity);
|
||||
|
||||
@Invoker("isWithinRange")
|
||||
boolean copperfarmers$isWithinRange(double range, MoveItemsTask.Storage storage, World world, PathAwareEntity entity, Vec3d pos);
|
||||
|
||||
@Invoker("transitionToTravelling")
|
||||
void copperfarmers$transitionToTravelling(PathAwareEntity entity);
|
||||
|
||||
@Invoker("setLookTarget")
|
||||
void copperfarmers$setLookTarget(MoveItemsTask.Storage storage, PathAwareEntity entity);
|
||||
|
||||
@Invoker("extractStack")
|
||||
static ItemStack copperfarmers$extractStack(Inventory inventory) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Invoker("resetVisitedPositions")
|
||||
void copperfarmers$resetVisitedPositions(PathAwareEntity entity);
|
||||
|
||||
@Invoker("insertStack")
|
||||
static ItemStack copperfarmers$insertStack(PathAwareEntity entity, Inventory inventory) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Invoker("invalidateTargetStorage")
|
||||
void copperfarmers$invalidateTargetStorage(PathAwareEntity entity);
|
||||
|
||||
@Invoker("canPickUpItem")
|
||||
static boolean copperfarmers$canPickUpItem(PathAwareEntity entity) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Invoker("hasItem")
|
||||
static boolean copperfarmers$hasItem(Inventory inventory) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Invoker("canInsert")
|
||||
static boolean copperfarmers$canInsert(PathAwareEntity entity, Inventory inventory) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Invoker("setNavigationState")
|
||||
void copperfarmers$setNavigationState(MoveItemsTask.NavigationState state);
|
||||
}
|
||||
@@ -0,0 +1,188 @@
|
||||
package com.dynamitos.mixin;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import org.spongepowered.asm.mixin.Debug;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
import com.dynamitos.Copperfarmers;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
|
||||
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.block.Blocks;
|
||||
import net.minecraft.entity.EquipmentSlot;
|
||||
import net.minecraft.entity.ai.brain.MemoryModuleState;
|
||||
import net.minecraft.entity.ai.brain.MemoryModuleType;
|
||||
import net.minecraft.entity.ai.brain.task.MoveItemsTask;
|
||||
import net.minecraft.entity.ai.brain.task.MultiTickTask;
|
||||
import net.minecraft.entity.mob.PathAwareEntity;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.item.Items;
|
||||
import net.minecraft.server.world.ServerWorld;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.Box;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
@Mixin(MoveItemsTask.class)
|
||||
public abstract class MoveItemsTaskMixin extends MultiTickTask<PathAwareEntity> {
|
||||
public MoveItemsTaskMixin(Map<MemoryModuleType<?>, MemoryModuleState> requiredMemoryState) {
|
||||
super(requiredMemoryState);
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
@Inject(method = "findStorage", at = @At("HEAD"), cancellable = true)
|
||||
private void findStorage(ServerWorld world, PathAwareEntity entity,
|
||||
CallbackInfoReturnable<Optional<MoveItemsTask.Storage>> callbackInfo) {
|
||||
Copperfarmers.LOGGER.info("Wrapped findStorage called");
|
||||
|
||||
Box box = ((MoveItemsTaskAccessor) this).copperfarmers$getSearchBoundingBox(entity);
|
||||
if (!entity.getEquippedStack(EquipmentSlot.MAINHAND).isOf(Items.WHEAT_SEEDS)) {
|
||||
return;
|
||||
}
|
||||
for (int x = (int) box.minX; x <= box.maxX; x++) {
|
||||
for (int y = (int) box.minY; y <= box.maxY; y++) {
|
||||
for (int z = (int) box.minZ; z <= box.maxZ; z++) {
|
||||
var pos = new BlockPos(x, y, z);
|
||||
var blockState = world.getBlockState(pos);
|
||||
// if block is farmland
|
||||
if(blockState.isOf(Blocks.FARMLAND) && world.isAir(pos.up())) {
|
||||
Copperfarmers.LOGGER.info("Found farmland at " + pos);
|
||||
callbackInfo.setReturnValue(Optional.of(new MoveItemsTask.Storage(pos, null, null, blockState)));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(method = "testContainer", at = @At("HEAD"), cancellable = true)
|
||||
private void testContainer(PathAwareEntity entity, BlockState state, CallbackInfoReturnable<Boolean> callbackInfo) {
|
||||
Copperfarmers.LOGGER.info("Wrapped testContainer called");
|
||||
if(state.isOf(Blocks.FARMLAND)) {
|
||||
callbackInfo.setReturnValue(true);
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(method = "tickInteracting", at = @At("HEAD"), cancellable = true)
|
||||
private void tickInteracting(MoveItemsTask.Storage storage, World world, PathAwareEntity entity, CallbackInfo callbackInfo) {
|
||||
Copperfarmers.LOGGER.info("Wrapped tickInteracting called");
|
||||
MoveItemsTaskAccessor thisAccessor = (MoveItemsTaskAccessor)this;
|
||||
if (!thisAccessor.copperfarmers$isWithinRange(2.0, storage, world, entity, thisAccessor.copperfarmers$atCenterY(entity))) {
|
||||
thisAccessor.copperfarmers$transitionToTravelling(entity);
|
||||
} else {
|
||||
thisAccessor.copperfarmers$setInteractionTicks(thisAccessor.copperfarmers$getInteractionTicks() + 1);
|
||||
thisAccessor.copperfarmers$setLookTarget(storage, entity);
|
||||
Copperfarmers.LOGGER.info("Interaction ticks: " + thisAccessor.copperfarmers$getInteractionTicks());
|
||||
if (thisAccessor.copperfarmers$getInteractionTicks() >= 60) {
|
||||
Copperfarmers.LOGGER.info("Interacting with storage at " + storage.pos());
|
||||
this.selectInteractionState2(
|
||||
entity,
|
||||
storage,
|
||||
this::takeStack2,
|
||||
(entityxx, inventory) -> thisAccessor.copperfarmers$invalidateTargetStorage(entity),
|
||||
this::placeStack2,
|
||||
(entityxx, inventory) -> thisAccessor.copperfarmers$invalidateTargetStorage(entity)
|
||||
);
|
||||
thisAccessor.copperfarmers$transitionToTravelling(entity);
|
||||
}
|
||||
}
|
||||
callbackInfo.cancel();
|
||||
}
|
||||
|
||||
@Inject(method = "transitionToInteracting", at = @At("HEAD"), cancellable = true)
|
||||
private void transitionToInteracting(MoveItemsTask.Storage storage, PathAwareEntity entity, CallbackInfo callbackInfo) {
|
||||
Copperfarmers.LOGGER.info("Wrapped transitionToInteracting called");
|
||||
this.selectInteractionState2(
|
||||
entity,
|
||||
storage,
|
||||
this.createSetInteractionStateCallback2(MoveItemsTask.InteractionState.PICKUP_ITEM),
|
||||
this.createSetInteractionStateCallback2(MoveItemsTask.InteractionState.PICKUP_NO_ITEM),
|
||||
this.createSetInteractionStateCallback2(MoveItemsTask.InteractionState.PLACE_ITEM),
|
||||
this.createSetInteractionStateCallback2(MoveItemsTask.InteractionState.PLACE_NO_ITEM)
|
||||
);
|
||||
((MoveItemsTaskAccessor)this).copperfarmers$setNavigationState(MoveItemsTask.NavigationState.INTERACTING);
|
||||
callbackInfo.cancel();
|
||||
}
|
||||
|
||||
@Inject(method = "isUnchanged", at = @At("HEAD"), cancellable = true)
|
||||
private void isUnchanged(World world, MoveItemsTask.Storage storage, CallbackInfoReturnable<Boolean> callbackInfo) {
|
||||
Copperfarmers.LOGGER.info("Wrapped isUnchanged called");
|
||||
if(storage.state().isOf(Blocks.FARMLAND)) {
|
||||
callbackInfo.setReturnValue(true);
|
||||
}
|
||||
}
|
||||
|
||||
private void placeStack2(PathAwareEntity entity, MoveItemsTask.Storage storage) {
|
||||
Copperfarmers.LOGGER.info("Wrapped placeStack called");
|
||||
MoveItemsTaskAccessor thisAccessor = (MoveItemsTaskAccessor)this;
|
||||
BlockPos pos = storage.pos();
|
||||
ServerWorld world = (ServerWorld) entity.getEntityWorld();
|
||||
if (world.getBlockState(pos).isOf(Blocks.FARMLAND) && world.isAir(pos.up())
|
||||
&& entity.getEquippedStack(EquipmentSlot.MAINHAND).isOf(Items.WHEAT_SEEDS)) {
|
||||
world.setBlockState(pos.up(), Blocks.WHEAT.getDefaultState());
|
||||
entity.getEquippedStack(EquipmentSlot.MAINHAND).decrement(1);
|
||||
if (entity.getEquippedStack(EquipmentSlot.MAINHAND).isEmpty()) {
|
||||
thisAccessor.copperfarmers$resetVisitedPositions(entity);
|
||||
} else {
|
||||
thisAccessor.copperfarmers$invalidateTargetStorage(entity);
|
||||
}
|
||||
Copperfarmers.LOGGER.info("Placed wheat seeds at " + pos.up());
|
||||
return;
|
||||
}
|
||||
ItemStack itemStack = MoveItemsTaskAccessor.copperfarmers$insertStack(entity, storage.inventory());
|
||||
storage.inventory().markDirty();
|
||||
entity.equipStack(EquipmentSlot.MAINHAND, itemStack);
|
||||
if (itemStack.isEmpty()) {
|
||||
thisAccessor.copperfarmers$resetVisitedPositions(entity);
|
||||
} else {
|
||||
thisAccessor.copperfarmers$invalidateTargetStorage(entity);
|
||||
}
|
||||
}
|
||||
|
||||
private void takeStack2(PathAwareEntity entity, MoveItemsTask.Storage storage) {
|
||||
MoveItemsTaskAccessor thisAccessor = (MoveItemsTaskAccessor)this;
|
||||
entity.equipStack(EquipmentSlot.MAINHAND, MoveItemsTaskAccessor.copperfarmers$extractStack(storage.inventory()));
|
||||
entity.setDropGuaranteed(EquipmentSlot.MAINHAND);
|
||||
storage.inventory().markDirty();
|
||||
thisAccessor.copperfarmers$resetVisitedPositions(entity);
|
||||
}
|
||||
|
||||
private void selectInteractionState2(
|
||||
PathAwareEntity entity,
|
||||
MoveItemsTask.Storage storage,
|
||||
BiConsumer<PathAwareEntity, MoveItemsTask.Storage> pickupItemCallback,
|
||||
BiConsumer<PathAwareEntity, MoveItemsTask.Storage> pickupNoItemCallback,
|
||||
BiConsumer<PathAwareEntity, MoveItemsTask.Storage> placeItemCallback,
|
||||
BiConsumer<PathAwareEntity, MoveItemsTask.Storage> placeNoItemCallback)
|
||||
{
|
||||
Copperfarmers.LOGGER.info("Wrapped selectInteractionState called");
|
||||
if (storage == null && entity.getEquippedStack(EquipmentSlot.MAINHAND).isOf(Items.WHEAT_SEEDS)) {
|
||||
placeItemCallback.accept(entity, storage);
|
||||
}
|
||||
if (MoveItemsTaskAccessor.copperfarmers$canPickUpItem(entity)) {
|
||||
if (MoveItemsTaskAccessor.copperfarmers$hasItem(storage.inventory())) {
|
||||
pickupItemCallback.accept(entity, storage);
|
||||
} else {
|
||||
pickupNoItemCallback.accept(entity, storage);
|
||||
}
|
||||
} else if (storage.state().isOf(Blocks.FARMLAND)
|
||||
|| MoveItemsTaskAccessor.copperfarmers$canInsert(entity, storage.inventory())) {
|
||||
placeItemCallback.accept(entity, storage);
|
||||
} else {
|
||||
placeNoItemCallback.accept(entity, storage);
|
||||
}
|
||||
}
|
||||
|
||||
private BiConsumer<PathAwareEntity, MoveItemsTask.Storage> createSetInteractionStateCallback2(MoveItemsTask.InteractionState state) {
|
||||
return (entity, inventory) -> ((MoveItemsTaskAccessor)this).copperfarmers$setInteractionState(state);
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,9 @@
|
||||
"package": "com.dynamitos.mixin",
|
||||
"compatibilityLevel": "JAVA_21",
|
||||
"mixins": [
|
||||
"ExampleMixin"
|
||||
"CopperGolemBrainMixin",
|
||||
"MoveItemsTaskMixin",
|
||||
"MoveItemsTaskAccessor"
|
||||
],
|
||||
"injectors": {
|
||||
"defaultRequire": 1
|
||||
|
||||
Reference in New Issue
Block a user