diff --git a/src/main/java/dev/anvilcraft/lib/block/IMoveableEntityBlock.java b/src/main/java/dev/anvilcraft/lib/block/IMoveableEntityBlock.java new file mode 100644 index 0000000..9550811 --- /dev/null +++ b/src/main/java/dev/anvilcraft/lib/block/IMoveableEntityBlock.java @@ -0,0 +1,33 @@ +package dev.anvilcraft.lib.block; + +import net.minecraft.MethodsReturnNonnullByDefault; +import net.minecraft.core.BlockPos; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.EntityBlock; + +import javax.annotation.ParametersAreNonnullByDefault; + +@MethodsReturnNonnullByDefault +@ParametersAreNonnullByDefault +@SuppressWarnings("unused") +public interface IMoveableEntityBlock extends EntityBlock { + /** + * 在可推动方块实体方块被推动时所会执行的,它的返回值是需要传递的方块实体数据 + * @param level 世界 + * @param pos 方块位置 + * @return 需要被传递的方块实体数据 + */ + default CompoundTag clearData(Level level, BlockPos pos) { + return new CompoundTag(); + } + + /** + * 在在可推动方块实体方块抵达被推动的位置停下时,将被传递的方块实体数据重新设置进入方块实体的方法 + * @param level 世界 + * @param pos 方块位置 + * @param nbt 需要被设置的方块实体数据 + */ + default void setData(Level level, BlockPos pos, CompoundTag nbt) { + } +} diff --git a/src/main/java/dev/anvilcraft/lib/injection/IPistonMovingBlockEntityExtension.java b/src/main/java/dev/anvilcraft/lib/injection/IPistonMovingBlockEntityExtension.java new file mode 100644 index 0000000..95b9760 --- /dev/null +++ b/src/main/java/dev/anvilcraft/lib/injection/IPistonMovingBlockEntityExtension.java @@ -0,0 +1,24 @@ +package dev.anvilcraft.lib.injection; + +import net.minecraft.MethodsReturnNonnullByDefault; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.world.level.block.state.BlockState; +import org.jetbrains.annotations.Nullable; + +import javax.annotation.ParametersAreNonnullByDefault; + +@MethodsReturnNonnullByDefault +@ParametersAreNonnullByDefault +public interface IPistonMovingBlockEntityExtension { + default @Nullable CompoundTag anvillib$clearData() { + throw new AssertionError(); + } + + default void anvillib$setData(@Nullable CompoundTag nbt) { + throw new AssertionError(); + } + + default @Nullable BlockState anvillib$getMoveState() { + throw new AssertionError(); + } +} diff --git a/src/main/java/dev/anvilcraft/lib/mixin/piston/PistonBaseBlockMixin.java b/src/main/java/dev/anvilcraft/lib/mixin/piston/PistonBaseBlockMixin.java new file mode 100644 index 0000000..56b2d82 --- /dev/null +++ b/src/main/java/dev/anvilcraft/lib/mixin/piston/PistonBaseBlockMixin.java @@ -0,0 +1,93 @@ +package dev.anvilcraft.lib.mixin.piston; + +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; +import com.llamalad7.mixinextras.sugar.Local; +import dev.anvilcraft.lib.block.IMoveableEntityBlock; +import dev.anvilcraft.lib.injection.IPistonMovingBlockEntityExtension; +import net.minecraft.MethodsReturnNonnullByDefault; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.piston.PistonBaseBlock; +import net.minecraft.world.level.block.state.BlockState; +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.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +import javax.annotation.ParametersAreNonnullByDefault; +import java.util.List; + +@MethodsReturnNonnullByDefault +@ParametersAreNonnullByDefault +@Mixin(value = PistonBaseBlock.class, priority = 943) +abstract class PistonBaseBlockMixin { + @Unique + private CompoundTag anvillib$nbt; + + @WrapOperation( + method = "isPushable", + at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/block/state/BlockState;hasBlockEntity()Z") + ) + private static boolean isPushable(BlockState instance, Operation original) { + return original.call(instance) && !(instance.getBlock() instanceof IMoveableEntityBlock); + } + + @Inject( + method = "moveBlocks", + at = @At( + value = "INVOKE", + target = "Lnet/minecraft/world/level/Level;setBlock(" + + "Lnet/minecraft/core/BlockPos;" + + "Lnet/minecraft/world/level/block/state/BlockState;" + + "I" + + ")Z", + ordinal = 1 + ) + ) + private void setBlock( + Level level, BlockPos pos, Direction facing, boolean extending, CallbackInfoReturnable cir, + @Local(ordinal = 2) BlockPos blockpos, + @Local(ordinal = 1) Direction direction, + @Local(ordinal = 1) List list1, + @Local(ordinal = 1) int k + ) { + if (level.isClientSide()) return; + this.anvillib$nbt = new CompoundTag(); + if (list1.get(k).getBlock() instanceof IMoveableEntityBlock block) { + this.anvillib$nbt = block.clearData(level, blockpos.relative(direction.getOpposite())); + } + } + + @WrapOperation( + method = "moveBlocks", + at = @At( + value = "INVOKE", + target = "Lnet/minecraft/world/level/block/piston/MovingPistonBlock;newMovingBlockEntity(" + + "Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/level/block/state/BlockState;" + + "Lnet/minecraft/world/level/block/state/BlockState;" + + "Lnet/minecraft/core/Direction;ZZ" + + ")Lnet/minecraft/world/level/block/entity/BlockEntity;", + ordinal = 0 + ) + ) + private BlockEntity newMovingBlockEntity( + BlockPos pos, + BlockState blockState, + BlockState movedState, + Direction direction, + boolean extending, + boolean isSourcePiston, + Operation original + ) { + BlockEntity blockEntity = original.call(pos, blockState, movedState, direction, extending, isSourcePiston); + if (blockEntity instanceof IPistonMovingBlockEntityExtension entity) { + entity.anvillib$setData(this.anvillib$nbt); + } + return blockEntity; + } +} diff --git a/src/main/java/dev/anvilcraft/lib/mixin/piston/PistonMovingBlockEntityMixin.java b/src/main/java/dev/anvilcraft/lib/mixin/piston/PistonMovingBlockEntityMixin.java new file mode 100644 index 0000000..b9eaff6 --- /dev/null +++ b/src/main/java/dev/anvilcraft/lib/mixin/piston/PistonMovingBlockEntityMixin.java @@ -0,0 +1,102 @@ +package dev.anvilcraft.lib.mixin.piston; + +import com.llamalad7.mixinextras.sugar.Local; +import dev.anvilcraft.lib.block.IMoveableEntityBlock; +import dev.anvilcraft.lib.injection.IPistonMovingBlockEntityExtension; +import net.minecraft.MethodsReturnNonnullByDefault; +import net.minecraft.core.BlockPos; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.piston.PistonMovingBlockEntity; +import net.minecraft.world.level.block.state.BlockState; +import org.jetbrains.annotations.Nullable; +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.CallbackInfo; + +import javax.annotation.ParametersAreNonnullByDefault; + +@MethodsReturnNonnullByDefault +@ParametersAreNonnullByDefault +@Mixin(PistonMovingBlockEntity.class) +abstract class PistonMovingBlockEntityMixin extends BlockEntity implements IPistonMovingBlockEntityExtension { + @Shadow + private BlockState movedState; + @Unique + private CompoundTag anvillib$nbt = new CompoundTag(); + + public PistonMovingBlockEntityMixin(BlockEntityType type, BlockPos pos, BlockState blockState) { + super(type, pos, blockState); + } + + @Override + public CompoundTag anvillib$clearData() { + CompoundTag nbt = this.anvillib$nbt; + this.anvillib$nbt = new CompoundTag(); + return nbt; + } + + @Override + public void anvillib$setData(@Nullable CompoundTag nbt) { + if (nbt == null) return; + this.anvillib$nbt.merge(nbt); + } + + @Override + public BlockState anvillib$getMoveState() { + return this.movedState; + } + + @Inject( + method = "tick", + at = @At( + value = "INVOKE", + target = "Lnet/minecraft/world/level/Level;" + + "setBlock(Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/level/block/state/BlockState;I)Z", + shift = At.Shift.AFTER, + ordinal = 1 + ) + ) + private static void tick( + Level level, + BlockPos pos, + BlockState state, + PistonMovingBlockEntity blockEntity, + CallbackInfo ci, + @Local(ordinal = 1) BlockState moveState + ) { + if (level.isClientSide()) return; + // noinspection ConstantValue + if (!(blockEntity instanceof IPistonMovingBlockEntityExtension blockEntity1)) return; + if (!(moveState.getBlock() instanceof IMoveableEntityBlock entityBlock)) return; + CompoundTag tag = blockEntity1.anvillib$clearData(); + if (tag != null) { + entityBlock.setData(level, pos, tag); + } + } + + @Inject( + method = "finalTick", at = @At( + value = "INVOKE", + target = "Lnet/minecraft/world/level/Level;" + + "setBlock(Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/level/block/state/BlockState;I)Z", + shift = At.Shift.AFTER + ) + ) + private void finalTick(CallbackInfo ci, @Local BlockState moveState) { + if (this.level == null || this.level.isClientSide()) return; + // noinspection ConstantValue + if (!(this instanceof IPistonMovingBlockEntityExtension blockEntity1)) return; + if (!(moveState.getBlock() instanceof IMoveableEntityBlock entityBlock)) return; + CompoundTag tag = blockEntity1.anvillib$clearData(); + // noinspection ConstantValue + if (tag != null) { + entityBlock.setData(level, this.worldPosition, tag); + } + } +} diff --git a/src/main/resources/anvillib.mixins.json b/src/main/resources/anvillib.mixins.json index 76a2a84..c1f3d59 100644 --- a/src/main/resources/anvillib.mixins.json +++ b/src/main/resources/anvillib.mixins.json @@ -6,7 +6,9 @@ "refmap": "anvillib.refmap.json", "mixins": [ "ItemEntityMixin", - "RecipeManagerMixin" + "RecipeManagerMixin", + "piston.PistonBaseBlockMixin", + "piston.PistonMovingBlockEntityMixin" ], "client": [ ], diff --git a/src/main/resources/interface_injections.json b/src/main/resources/interface_injections.json index 693ae4c..67fc7c9 100644 --- a/src/main/resources/interface_injections.json +++ b/src/main/resources/interface_injections.json @@ -1,5 +1,8 @@ { "net/minecraft/world/item/crafting/RecipeManager": [ "dev/anvilcraft/lib/injection/IRecipeManagerExtension" + ], + "net/minecraft/world/level/block/piston/PistonMovingBlockEntity": [ + "dev/anvilcraft/lib/injection/IPistonMovingBlockEntityExtension" ] } \ No newline at end of file