From a12efb59e33343259d37077d56c614d8f8500523 Mon Sep 17 00:00:00 2001 From: Ocelot Date: Tue, 21 Apr 2026 21:13:19 -0600 Subject: [PATCH 1/2] Reapply "Improve harvester block entity compatibility" This reverts commit a6c868cd024a54a1752da13b896b0797c69e9fca. --- .../HarvesterBlockEntityMixin.java | 29 ++++------ .../HarvesterBlockEntityUsageMixin.java | 53 ++----------------- .../DummyMovementContext.java | 24 +++++++++ .../HarvesterMovementBehaviourExtension.java | 15 ------ .../create/harvester/HarvesterTicker.java | 2 + 5 files changed, 40 insertions(+), 83 deletions(-) create mode 100644 neoforge/src/main/java/dev/ryanhcode/sable/neoforge/mixinhelper/compatibility/create/behavior_compatibility/harvester_block_entity/DummyMovementContext.java delete mode 100644 neoforge/src/main/java/dev/ryanhcode/sable/neoforge/mixinhelper/compatibility/create/harvester/HarvesterMovementBehaviourExtension.java diff --git a/neoforge/src/main/java/dev/ryanhcode/sable/neoforge/mixin/compatibility/create/behaviour_compatibility/harvester_block_entity/HarvesterBlockEntityMixin.java b/neoforge/src/main/java/dev/ryanhcode/sable/neoforge/mixin/compatibility/create/behaviour_compatibility/harvester_block_entity/HarvesterBlockEntityMixin.java index 9b8ee77..02357aa 100644 --- a/neoforge/src/main/java/dev/ryanhcode/sable/neoforge/mixin/compatibility/create/behaviour_compatibility/harvester_block_entity/HarvesterBlockEntityMixin.java +++ b/neoforge/src/main/java/dev/ryanhcode/sable/neoforge/mixin/compatibility/create/behaviour_compatibility/harvester_block_entity/HarvesterBlockEntityMixin.java @@ -7,18 +7,16 @@ import dev.ryanhcode.sable.api.block.BlockEntitySubLevelActor; import dev.ryanhcode.sable.companion.math.JOMLConversion; import dev.ryanhcode.sable.neoforge.mixinhelper.compatibility.create.harvester.HarvesterLerpedSpeed; -import dev.ryanhcode.sable.neoforge.mixinhelper.compatibility.create.harvester.HarvesterMovementBehaviourExtension; +import dev.ryanhcode.sable.neoforge.mixinhelper.compatibility.create.harvester.HarvesterTicker; import dev.ryanhcode.sable.sublevel.ServerSubLevel; import net.createmod.catnip.animation.LerpedFloat; import net.minecraft.core.BlockPos; +import net.minecraft.core.Position; import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.phys.Vec3; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Unique; -import static dev.ryanhcode.sable.neoforge.mixinhelper.compatibility.create.harvester.HarvesterTicker.blockEntityBehaviour; - @Mixin(HarvesterBlockEntity.class) public abstract class HarvesterBlockEntityMixin extends CachedRenderBBBlockEntity implements HarvesterLerpedSpeed, BlockEntitySubLevelActor { @@ -46,30 +44,23 @@ public HarvesterBlockEntityMixin(final BlockEntityType type, final BlockPos p @Override public void sable$tick(final ServerSubLevel subLevel) { final ActiveSableCompanion helper = Sable.HELPER; - final Vec3 center = this.getBlockPos().getCenter(); - BlockPos gatheredPos = helper.runIncludingSubLevels(this.getLevel(), center, false, helper.getContaining(this), (sublevel, pos) -> { - if (blockEntityBehaviour.isValidCrop(this.getLevel(), pos, this.getLevel().getBlockState(pos))) { + final Position center = this.getBlockPos().getCenter(); + BlockPos gatheredPos = helper.runIncludingSubLevels(this.level, center, false, helper.getContaining(this), (sublevel, pos) -> { + if (HarvesterTicker.blockEntityBehaviour.isValidCrop(this.level, pos, this.level.getBlockState(pos))) { return pos; - } else { - return null; } + + return null; }); if (gatheredPos == null) { - gatheredPos = BlockPos.containing(helper.projectOutOfSubLevel(this.getLevel(), center)); + gatheredPos = BlockPos.containing(helper.projectOutOfSubLevel(this.level, center)); } if (!this.sable$previousPos.equals(gatheredPos)) { this.sable$previousPos = gatheredPos; - - final HarvesterMovementBehaviourExtension duck = (HarvesterMovementBehaviourExtension) blockEntityBehaviour; - duck.sable$setManualLevel(this.getLevel()); - duck.sable$setSelfPos(this.getBlockPos()); - - blockEntityBehaviour.visitNewPosition(null, this.sable$previousPos); - - duck.sable$setManualLevel(null); - duck.sable$setSelfPos(null); + HarvesterTicker.dummyMovementContext.update(this.level, this.getBlockPos(), this.getBlockState(), null); + HarvesterTicker.blockEntityBehaviour.visitNewPosition(HarvesterTicker.dummyMovementContext, this.sable$previousPos); } } diff --git a/neoforge/src/main/java/dev/ryanhcode/sable/neoforge/mixin/compatibility/create/behaviour_compatibility/harvester_block_entity/HarvesterBlockEntityUsageMixin.java b/neoforge/src/main/java/dev/ryanhcode/sable/neoforge/mixin/compatibility/create/behaviour_compatibility/harvester_block_entity/HarvesterBlockEntityUsageMixin.java index 3b68b1b..0cc64ef 100644 --- a/neoforge/src/main/java/dev/ryanhcode/sable/neoforge/mixin/compatibility/create/behaviour_compatibility/harvester_block_entity/HarvesterBlockEntityUsageMixin.java +++ b/neoforge/src/main/java/dev/ryanhcode/sable/neoforge/mixin/compatibility/create/behaviour_compatibility/harvester_block_entity/HarvesterBlockEntityUsageMixin.java @@ -4,64 +4,19 @@ import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; import com.simibubi.create.content.contraptions.actors.harvester.HarvesterMovementBehaviour; import com.simibubi.create.content.contraptions.behaviour.MovementContext; -import dev.ryanhcode.sable.neoforge.mixinhelper.compatibility.create.harvester.HarvesterMovementBehaviourExtension; +import dev.ryanhcode.sable.neoforge.mixinhelper.compatibility.create.behavior_compatibility.harvester_block_entity.DummyMovementContext; import dev.ryanhcode.sable.neoforge.mixinhelper.compatibility.create.harvester.HarvesterTicker; -import net.minecraft.core.BlockPos; import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.Level; -import org.objectweb.asm.Opcodes; import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Redirect; - -import java.lang.ref.Reference; -import java.lang.ref.WeakReference; @Mixin(HarvesterMovementBehaviour.class) -public class HarvesterBlockEntityUsageMixin implements HarvesterMovementBehaviourExtension { - - @Unique - private Reference sable$manualLevel; - - @Unique - private BlockPos sable$selfPos = null; - - @Override - public BlockPos sable$getSelfPos() { - return this.sable$selfPos; - } - - @Override - public void sable$setSelfPos(final BlockPos sable$selfPos) { - this.sable$selfPos = sable$selfPos; - } - - @Override - public Level sable$getManualLevel() { - return this.sable$manualLevel.get(); - } - - @Override - public void sable$setManualLevel(final Level level) { - this.sable$manualLevel = new WeakReference<>(level); - } - - @Redirect(method = "visitNewPosition", at = @At(value = "FIELD", target = "Lcom/simibubi/create/content/contraptions/behaviour/MovementContext;world:Lnet/minecraft/world/level/Level;", opcode = Opcodes.GETFIELD)) - public Level sable$replaceWorld(final MovementContext instance) { - if (instance == null) { // we're only going to be passing in null from our mixin, so this is valid - return this.sable$getManualLevel(); - } else { - return instance.world; - } - } +public class HarvesterBlockEntityUsageMixin { @WrapOperation(method = "lambda$visitNewPosition$0", at = @At(value = "INVOKE", target = "Lcom/simibubi/create/content/contraptions/actors/harvester/HarvesterMovementBehaviour;collectOrDropItem(Lcom/simibubi/create/content/contraptions/behaviour/MovementContext;Lnet/minecraft/world/item/ItemStack;)V")) public void sable$replaceDropItem(final HarvesterMovementBehaviour instance, final MovementContext movementContext, final ItemStack itemStack, final Operation original) { - if (movementContext == null) { - if (this.sable$getManualLevel() != null && this.sable$getSelfPos() != null) { - HarvesterTicker.dropItem(this.sable$getManualLevel(), itemStack, this.sable$getSelfPos()); - } + if (movementContext instanceof DummyMovementContext) { + HarvesterTicker.dropItem(movementContext.world, itemStack, movementContext.localPos); } else { original.call(instance, movementContext, itemStack); } diff --git a/neoforge/src/main/java/dev/ryanhcode/sable/neoforge/mixinhelper/compatibility/create/behavior_compatibility/harvester_block_entity/DummyMovementContext.java b/neoforge/src/main/java/dev/ryanhcode/sable/neoforge/mixinhelper/compatibility/create/behavior_compatibility/harvester_block_entity/DummyMovementContext.java new file mode 100644 index 0000000..ecd0d00 --- /dev/null +++ b/neoforge/src/main/java/dev/ryanhcode/sable/neoforge/mixinhelper/compatibility/create/behavior_compatibility/harvester_block_entity/DummyMovementContext.java @@ -0,0 +1,24 @@ +package dev.ryanhcode.sable.neoforge.mixinhelper.compatibility.create.behavior_compatibility.harvester_block_entity; + +import com.simibubi.create.content.contraptions.behaviour.MovementContext; +import net.minecraft.core.BlockPos; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate; +import org.jetbrains.annotations.Nullable; + +public class DummyMovementContext extends MovementContext { + + public DummyMovementContext() { + super(null, new StructureTemplate.StructureBlockInfo(BlockPos.ZERO, Blocks.AIR.defaultBlockState(), null), null); + } + + public void update(final Level level, final BlockPos pos, final BlockState state, @Nullable final CompoundTag blockEntityData) { + this.world = level; + this.state = state; + this.localPos = pos; + this.blockEntityData = blockEntityData; + } +} diff --git a/neoforge/src/main/java/dev/ryanhcode/sable/neoforge/mixinhelper/compatibility/create/harvester/HarvesterMovementBehaviourExtension.java b/neoforge/src/main/java/dev/ryanhcode/sable/neoforge/mixinhelper/compatibility/create/harvester/HarvesterMovementBehaviourExtension.java deleted file mode 100644 index 77b0ab0..0000000 --- a/neoforge/src/main/java/dev/ryanhcode/sable/neoforge/mixinhelper/compatibility/create/harvester/HarvesterMovementBehaviourExtension.java +++ /dev/null @@ -1,15 +0,0 @@ -package dev.ryanhcode.sable.neoforge.mixinhelper.compatibility.create.harvester; - -import net.minecraft.core.BlockPos; -import net.minecraft.world.level.Level; - -public interface HarvesterMovementBehaviourExtension { - - BlockPos sable$getSelfPos(); - - void sable$setSelfPos(BlockPos sable$selfPos); - - Level sable$getManualLevel(); - void sable$setManualLevel(Level level); - -} diff --git a/neoforge/src/main/java/dev/ryanhcode/sable/neoforge/mixinhelper/compatibility/create/harvester/HarvesterTicker.java b/neoforge/src/main/java/dev/ryanhcode/sable/neoforge/mixinhelper/compatibility/create/harvester/HarvesterTicker.java index 355915d..5724781 100644 --- a/neoforge/src/main/java/dev/ryanhcode/sable/neoforge/mixinhelper/compatibility/create/harvester/HarvesterTicker.java +++ b/neoforge/src/main/java/dev/ryanhcode/sable/neoforge/mixinhelper/compatibility/create/harvester/HarvesterTicker.java @@ -1,6 +1,7 @@ package dev.ryanhcode.sable.neoforge.mixinhelper.compatibility.create.harvester; import com.simibubi.create.content.contraptions.actors.harvester.HarvesterMovementBehaviour; +import dev.ryanhcode.sable.neoforge.mixinhelper.compatibility.create.behavior_compatibility.harvester_block_entity.DummyMovementContext; import net.minecraft.core.BlockPos; import net.minecraft.world.entity.item.ItemEntity; import net.minecraft.world.item.ItemStack; @@ -13,6 +14,7 @@ public class HarvesterTicker implements BlockEntityTicker { public static final HarvesterMovementBehaviour blockEntityBehaviour = new HarvesterMovementBehaviour(); + public static final DummyMovementContext dummyMovementContext = new DummyMovementContext(); @Override public void tick(final Level level, final BlockPos arg2, final BlockState arg3, final T be) { From 8c655d1ac4b5251b4f933a0e222372bba981d653 Mon Sep 17 00:00:00 2001 From: Ocelot Date: Tue, 21 Apr 2026 21:17:26 -0600 Subject: [PATCH 2/2] Fix harvester block entity crash --- .../HarvesterMovementBehaviourMixin.java | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/neoforge/src/main/java/dev/ryanhcode/sable/neoforge/mixin/compatibility/create/behaviour_compatibility/harvester_behaviour/HarvesterMovementBehaviourMixin.java b/neoforge/src/main/java/dev/ryanhcode/sable/neoforge/mixin/compatibility/create/behaviour_compatibility/harvester_behaviour/HarvesterMovementBehaviourMixin.java index 4253409..72d4de1 100644 --- a/neoforge/src/main/java/dev/ryanhcode/sable/neoforge/mixin/compatibility/create/behaviour_compatibility/harvester_behaviour/HarvesterMovementBehaviourMixin.java +++ b/neoforge/src/main/java/dev/ryanhcode/sable/neoforge/mixin/compatibility/create/behaviour_compatibility/harvester_behaviour/HarvesterMovementBehaviourMixin.java @@ -6,6 +6,7 @@ import com.simibubi.create.content.contraptions.behaviour.MovementContext; import dev.ryanhcode.sable.ActiveSableCompanion; import dev.ryanhcode.sable.Sable; +import dev.ryanhcode.sable.neoforge.mixinhelper.compatibility.create.behavior_compatibility.harvester_block_entity.DummyMovementContext; import net.minecraft.core.BlockPos; import org.spongepowered.asm.mixin.Mixin; @@ -15,14 +16,15 @@ public class HarvesterMovementBehaviourMixin { @SuppressWarnings("ResultOfMethodCallIgnored") @WrapMethod(method = "visitNewPosition") public void sable$checkAllPositions(final MovementContext context, final BlockPos pos, final Operation original) { - if (context != null) { - final ActiveSableCompanion helper = Sable.HELPER; - helper.runIncludingSubLevels(context.world, pos.getCenter(), true, helper.getContaining(context.contraption.entity), (sublevel, blockPos) -> { - original.call(context, blockPos); - return null; - }); - } else { - original.call(null, pos); + if (context instanceof DummyMovementContext) { + original.call(context, pos); + return; } + + final ActiveSableCompanion helper = Sable.HELPER; + helper.runIncludingSubLevels(context.world, pos.getCenter(), true, helper.getContaining(context.contraption.entity), (sublevel, blockPos) -> { + original.call(context, blockPos); + return null; + }); } }