diff --git a/common/src/main/java/com/copycatsplus/copycats/foundation/copycat/ICopycatBlockEntity.java b/common/src/main/java/com/copycatsplus/copycats/foundation/copycat/ICopycatBlockEntity.java index 474c73119..54b5d9b16 100644 --- a/common/src/main/java/com/copycatsplus/copycats/foundation/copycat/ICopycatBlockEntity.java +++ b/common/src/main/java/com/copycatsplus/copycats/foundation/copycat/ICopycatBlockEntity.java @@ -8,6 +8,7 @@ import com.simibubi.create.content.redstone.RoseQuartzLampBlock; import com.simibubi.create.content.schematics.requirement.ISpecialBlockEntityItemRequirement; import com.simibubi.create.content.schematics.requirement.ItemRequirement; +import com.simibubi.create.foundation.blockEntity.IMergeableBE; import com.simibubi.create.foundation.utility.IPartialSafeNBT; import com.simibubi.create.foundation.utility.Iterate; import net.minecraft.MethodsReturnNonnullByDefault; @@ -45,7 +46,7 @@ */ @ParametersAreNonnullByDefault @MethodsReturnNonnullByDefault -public interface ICopycatBlockEntity extends ISpecialBlockEntityItemRequirement, ITransformableBlockEntity, IPartialSafeNBT { +public interface ICopycatBlockEntity extends ISpecialBlockEntityItemRequirement, ITransformableBlockEntity, IPartialSafeNBT, IMergeableBE { void notifyUpdate(); @@ -168,6 +169,16 @@ default ItemRequirement getRequiredItems(BlockState state) { return new ItemRequirement(ItemRequirement.ItemUseType.CONSUME, getConsumedItem()); } + @Override + default void accept(BlockEntity other) { + if (other instanceof ICopycatBlockEntity be) { + setMaterial(be.getMaterial()); + setConsumedItem(be.getConsumedItem()); + setCTEnabled(be.isCTEnabled()); + BlockEntityUtils.redraw((BlockEntity) this); + } + } + @Override default void transform(StructureTransform transform) { setMaterialInternal(transform.apply(getMaterial())); @@ -211,6 +222,7 @@ static void read(ICopycatBlockEntity self, CompoundTag tag, boolean clientPacket static void writeSafe(ICopycatBlockEntity self, CompoundTag tag) { ItemStack stackWithoutNBT = self.getConsumedItem().copy(); stackWithoutNBT.setTag(null); + BlockEntityUtils.saveMetadata((BlockEntity) self, tag); write(tag, stackWithoutNBT, self.getMaterial(), self.isCTEnabled()); } diff --git a/common/src/main/java/com/copycatsplus/copycats/foundation/copycat/multistate/IMultiStateCopycatBlockEntity.java b/common/src/main/java/com/copycatsplus/copycats/foundation/copycat/multistate/IMultiStateCopycatBlockEntity.java index 75f7ef7ce..37d1fa79c 100644 --- a/common/src/main/java/com/copycatsplus/copycats/foundation/copycat/multistate/IMultiStateCopycatBlockEntity.java +++ b/common/src/main/java/com/copycatsplus/copycats/foundation/copycat/multistate/IMultiStateCopycatBlockEntity.java @@ -242,6 +242,7 @@ static void read(IMultiStateCopycatBlockEntity self, CompoundTag tag, boolean cl } static void writeSafe(IMultiStateCopycatBlockEntity self, CompoundTag tag) { + BlockEntityUtils.saveMetadata((BlockEntity) self, tag); tag.put("material_data", self.getMaterialItemStorage().serializeSafe()); } diff --git a/common/src/main/java/com/copycatsplus/copycats/mixin/copycat/door/BlockHelperMixin.java b/common/src/main/java/com/copycatsplus/copycats/mixin/copycat/door/BlockHelperMixin.java new file mode 100644 index 000000000..7a342a388 --- /dev/null +++ b/common/src/main/java/com/copycatsplus/copycats/mixin/copycat/door/BlockHelperMixin.java @@ -0,0 +1,34 @@ +package com.copycatsplus.copycats.mixin.copycat.door; + +import com.simibubi.create.foundation.utility.BlockHelper; +import net.minecraft.core.BlockPos; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.item.ItemStack; +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.state.BlockState; +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; + +/** + * Fix a hidden bug in Create which causes a crash due to missing ID when merging block entities in schematic printing. + */ +@Mixin(BlockHelper.class) +public class BlockHelperMixin { + @Inject( + method = "placeSchematicBlock", + at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/block/entity/BlockEntity;loadStatic(Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/level/block/state/BlockState;Lnet/minecraft/nbt/CompoundTag;)Lnet/minecraft/world/level/block/entity/BlockEntity;") + ) + private static void placeSchematicBlock(Level world, BlockState state, BlockPos target, ItemStack stack, CompoundTag data, CallbackInfo ci) { + BlockEntity existingBlockEntity = world.getBlockEntity(target); + if (existingBlockEntity != null && existingBlockEntity.getBlockState().getBlock().equals(state.getBlock())) { + ResourceLocation resourceLocation = BlockEntityType.getKey(existingBlockEntity.getType()); + assert resourceLocation != null; + data.putString("id", resourceLocation.toString()); + } + } +} diff --git a/common/src/main/java/com/copycatsplus/copycats/mixin/copycat/door/SchematicannonBlockEntityMixin.java b/common/src/main/java/com/copycatsplus/copycats/mixin/copycat/door/SchematicannonBlockEntityMixin.java new file mode 100644 index 000000000..ea0a112c5 --- /dev/null +++ b/common/src/main/java/com/copycatsplus/copycats/mixin/copycat/door/SchematicannonBlockEntityMixin.java @@ -0,0 +1,47 @@ +package com.copycatsplus.copycats.mixin.copycat.door; + +import com.copycatsplus.copycats.foundation.copycat.ICopycatBlock; +import com.copycatsplus.copycats.foundation.copycat.ICopycatBlockEntity; +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; +import com.simibubi.create.content.schematics.cannon.SchematicannonBlockEntity; +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.properties.DoubleBlockHalf; +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 static net.minecraft.world.level.block.state.properties.BlockStateProperties.DOUBLE_BLOCK_HALF; + +/** + * Force the schematicannon to place both the upper and lower halves of copycat doors + */ +@Mixin(SchematicannonBlockEntity.class) +public class SchematicannonBlockEntityMixin { + @Inject( + method = "shouldIgnoreBlockState", + at = @At("RETURN"), + cancellable = true + ) + private void shouldIgnoreBlockStateMixin(BlockState state, BlockEntity be, CallbackInfoReturnable cir) { + if (state.hasProperty(DOUBLE_BLOCK_HALF) && be instanceof ICopycatBlockEntity) { + cir.setReturnValue(false); + } + } + + /** + * Make an exception for the "protect block entities" setting so that the upper half of a copycat door can be placed + */ + @WrapOperation( + method = "shouldPlace", + at = @At(value = "FIELD", target = "Lcom/simibubi/create/content/schematics/cannon/SchematicannonBlockEntity;replaceBlockEntities:Z") + ) + private boolean shouldPlace(SchematicannonBlockEntity instance, Operation original, BlockPos pos, BlockState state, BlockEntity be, BlockState toReplace, + BlockState toReplaceOther, boolean isNormalCube) { + boolean originalReplace = original.call(instance); + return originalReplace || (state.getBlock() instanceof ICopycatBlock && state.hasProperty(DOUBLE_BLOCK_HALF) && state.getValue(DOUBLE_BLOCK_HALF) == DoubleBlockHalf.UPPER); + } +} diff --git a/common/src/main/java/com/copycatsplus/copycats/mixin/foundation/copycat/BlockEntityAccessor.java b/common/src/main/java/com/copycatsplus/copycats/mixin/foundation/copycat/BlockEntityAccessor.java new file mode 100644 index 000000000..2d9d9b192 --- /dev/null +++ b/common/src/main/java/com/copycatsplus/copycats/mixin/foundation/copycat/BlockEntityAccessor.java @@ -0,0 +1,12 @@ +package com.copycatsplus.copycats.mixin.foundation.copycat; + +import net.minecraft.nbt.CompoundTag; +import net.minecraft.world.level.block.entity.BlockEntity; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Invoker; + +@Mixin(BlockEntity.class) +public interface BlockEntityAccessor { + @Invoker + void callSaveMetadata(CompoundTag tag); +} diff --git a/common/src/main/java/com/copycatsplus/copycats/utility/BlockEntityUtils.java b/common/src/main/java/com/copycatsplus/copycats/utility/BlockEntityUtils.java index 78c7fbb47..6a12c7c18 100644 --- a/common/src/main/java/com/copycatsplus/copycats/utility/BlockEntityUtils.java +++ b/common/src/main/java/com/copycatsplus/copycats/utility/BlockEntityUtils.java @@ -3,9 +3,11 @@ import com.copycatsplus.copycats.foundation.copycat.CopycatMaterialStore; import com.copycatsplus.copycats.foundation.copycat.ICopycatBlockEntity; import com.copycatsplus.copycats.foundation.copycat.multistate.IMultiStateCopycatBlockEntity; +import com.copycatsplus.copycats.mixin.foundation.copycat.BlockEntityAccessor; import dev.architectury.injectables.annotations.ExpectPlatform; import net.minecraft.MethodsReturnNonnullByDefault; import net.minecraft.core.BlockPos; +import net.minecraft.nbt.CompoundTag; import net.minecraft.util.profiling.ProfilerFiller; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.entity.BlockEntity; @@ -38,6 +40,10 @@ public static void redraw(BlockEntity blockEntity) { } } + public static void saveMetadata(BlockEntity blockEntity, CompoundTag tag) { + ((BlockEntityAccessor) blockEntity).callSaveMetadata(tag); + } + @ExpectPlatform public static void requestModelDataUpdate(BlockEntity blockEntity) { diff --git a/common/src/main/resources/copycats-common.mixins.json b/common/src/main/resources/copycats-common.mixins.json index 8ce25ef62..5b9005ea2 100644 --- a/common/src/main/resources/copycats-common.mixins.json +++ b/common/src/main/resources/copycats-common.mixins.json @@ -13,6 +13,8 @@ "compat.rubidium.BlockRendererMixin", "copycat.VoxelShapeAccessor", "copycat.cogwheel.CogWheelBlockItemMixin", + "copycat.door.BlockHelperMixin", + "copycat.door.SchematicannonBlockEntityMixin", "copycat.fluid_pipe.FluidPipeBlockMixin", "copycat.panel.CopycatPanelBlockMixin", "copycat.slab.SeatMovementBehaviourMixin", @@ -23,6 +25,7 @@ "entity.CatMixin", "feature_toggle.CreativeModeTabsAccessor", "foundation.copycat.BearingContraptionMixin", + "foundation.copycat.BlockEntityAccessor", "foundation.copycat.BlockMixin", "foundation.copycat.BlockStateBaseCacheMixin", "foundation.copycat.BlockStateBaseMixin",