package carpet.mixins; 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.Redirect; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; import org.spongepowered.asm.mixin.injection.callback.LocalCapture; import carpet.fakes.BlockPistonBehaviourInterface; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.piston.PistonStructureResolver; import net.minecraft.world.level.block.state.BlockState; @Mixin(PistonStructureResolver.class) public class PistonStructureResolver_customStickyMixin { @Shadow @Final private Level level; @Shadow @Final private Direction pushDirection; @Shadow private static boolean canStickToEachOther(BlockState blockState, BlockState blockState2) { throw new AssertionError(); } @Inject( method = "isSticky", cancellable = true, at = @At( value = "HEAD" ) ) private static void isSticky(BlockState state, CallbackInfoReturnable cir) { if (state.getBlock() instanceof BlockPistonBehaviourInterface behaviourInterface){ cir.setReturnValue(behaviourInterface.isSticky(state)); } } // fields that are needed because @Redirects cannot capture locals @Unique private BlockPos pos_addBlockLine; @Unique private BlockPos behindPos_addBlockLine; @Inject( method = "addBlockLine", locals = LocalCapture.CAPTURE_FAILHARD, at = @At( value = "INVOKE", ordinal = 1, target = "Lnet/minecraft/world/level/Level;getBlockState(Lnet/minecraft/core/BlockPos;)Lnet/minecraft/world/level/block/state/BlockState;" ) ) private void captureBlockLinePositions(BlockPos pos, Direction fromDir, CallbackInfoReturnable cir, BlockState state, int dst, BlockPos behindPos) { pos_addBlockLine = behindPos.relative(pushDirection); behindPos_addBlockLine = behindPos; } @Redirect( method = "addBlockLine", at = @At( value = "INVOKE", target = "Lnet/minecraft/world/level/block/piston/PistonStructureResolver;canStickToEachOther(Lnet/minecraft/world/level/block/state/BlockState;Lnet/minecraft/world/level/block/state/BlockState;)Z" ) ) private boolean onAddBlockLineCanStickToEachOther(BlockState state, BlockState behindState) { if (state.getBlock() instanceof BlockPistonBehaviourInterface behaviourInterface) { return behaviourInterface.isStickyToNeighbor(level, pos_addBlockLine, state, behindPos_addBlockLine, behindState, pushDirection.getOpposite(), pushDirection); } return canStickToEachOther(state, behindState); } // fields that are needed because @Redirects cannot capture locals @Unique private Direction dir_addBranchingBlocks; @Unique private BlockPos neighborPos_addBranchingBlocks; @Inject( method = "addBranchingBlocks", locals = LocalCapture.CAPTURE_FAILHARD, at = @At( value = "INVOKE", ordinal = 1, target = "Lnet/minecraft/world/level/Level;getBlockState(Lnet/minecraft/core/BlockPos;)Lnet/minecraft/world/level/block/state/BlockState;" ) ) private void captureNeighborPositions(BlockPos pos, CallbackInfoReturnable cir, BlockState state, Direction[] dirs, int i, int j, Direction dir, BlockPos neighborPos) { dir_addBranchingBlocks = dir; neighborPos_addBranchingBlocks = neighborPos; } @Redirect( method = "addBranchingBlocks", at = @At( value = "INVOKE", target = "Lnet/minecraft/world/level/block/piston/PistonStructureResolver;canStickToEachOther(Lnet/minecraft/world/level/block/state/BlockState;Lnet/minecraft/world/level/block/state/BlockState;)Z" ) ) private boolean onAddBranchingBlocksCanStickToEachOther(BlockState neighborState, BlockState state, BlockPos pos) { if (state.getBlock() instanceof BlockPistonBehaviourInterface behaviourInterface) { return behaviourInterface.isStickyToNeighbor(level, pos, state, neighborPos_addBranchingBlocks, neighborState, dir_addBranchingBlocks, pushDirection); } return canStickToEachOther(neighborState, state); } }