diff --git a/src/main/java/com/extendedae_plus/content/ae2/MirrorPatternProviderBlock.java b/src/main/java/com/extendedae_plus/content/ae2/MirrorPatternProviderBlock.java index 30a7f81..73b69d1 100644 --- a/src/main/java/com/extendedae_plus/content/ae2/MirrorPatternProviderBlock.java +++ b/src/main/java/com/extendedae_plus/content/ae2/MirrorPatternProviderBlock.java @@ -8,7 +8,6 @@ import net.minecraft.network.chat.Component; import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionResult; import net.minecraft.world.ItemInteractionResult; -import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.Level; @@ -22,26 +21,6 @@ public class MirrorPatternProviderBlock extends PatternProviderBlock { super(); } - @Override - public void setPlacedBy(Level level, BlockPos pos, BlockState state, @Nullable LivingEntity placer, ItemStack stack) { - super.setPlacedBy(level, pos, state, placer, stack); - - if (level.isClientSide) { - return; - } - - var mirror = this.getMirror(level, pos); - if (mirror == null) { - return; - } - - if (mirror.tryBindToAdjacentMaster()) { - this.notifyPlayer(placer, mirror.createBoundMessage()); - } else { - this.notifyPlayer(placer, Component.translatable("extendedae_plus.message.mirror_pattern_provider.missing_master")); - } - } - @Override protected ItemInteractionResult useItemOn(ItemStack heldItem, BlockState state, Level level, BlockPos pos, Player player, InteractionHand hand, BlockHitResult hit) { @@ -92,10 +71,4 @@ public class MirrorPatternProviderBlock extends PatternProviderBlock { var blockEntity = this.getBlockEntity(level, pos); return blockEntity instanceof MirrorPatternProviderBlockEntity mirror ? mirror : null; } - - private void notifyPlayer(@Nullable LivingEntity entity, Component message) { - if (entity instanceof Player player) { - player.displayClientMessage(message, true); - } - } } diff --git a/src/main/java/com/extendedae_plus/content/ae2/MirrorPatternProviderBlockEntity.java b/src/main/java/com/extendedae_plus/content/ae2/MirrorPatternProviderBlockEntity.java index 76bf309..b23373d 100644 --- a/src/main/java/com/extendedae_plus/content/ae2/MirrorPatternProviderBlockEntity.java +++ b/src/main/java/com/extendedae_plus/content/ae2/MirrorPatternProviderBlockEntity.java @@ -13,6 +13,7 @@ import appeng.util.inv.AppEngInternalInventory; import com.extendedae_plus.init.ModBlockEntities; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; +import net.minecraft.core.GlobalPos; import net.minecraft.core.HolderLookup; import net.minecraft.core.component.DataComponentMap; import net.minecraft.core.registries.Registries; @@ -64,14 +65,14 @@ public class MirrorPatternProviderBlockEntity extends PatternProviderBlockEntity return; } - this.syncOrRebind(false); + this.syncBoundMaster(); } @Override public void onReady() { super.onReady(); if (this.getLevel() instanceof ServerLevel serverLevel) { - this.syncOrRebind(true); + this.syncBoundMaster(); } } @@ -139,6 +140,34 @@ public class MirrorPatternProviderBlockEntity extends PatternProviderBlockEntity return true; } + public boolean bindToMaster(GlobalPos master) { + if (!(this.getLevel() instanceof ServerLevel serverLevel)) { + return false; + } + + if (master.pos().equals(this.getBlockPos()) && master.dimension().equals(serverLevel.dimension())) { + return false; + } + + var masterLevel = serverLevel.getServer().getLevel(master.dimension()); + if (masterLevel != null && masterLevel.hasChunkAt(master.pos())) { + var blockEntity = masterLevel.getBlockEntity(master.pos()); + if (isValidMaster(blockEntity)) { + return this.syncFromMaster((PatternProviderBlockEntity) blockEntity); + } + return false; + } + + var changed = !Objects.equals(this.masterDimension, master.dimension()) || !Objects.equals(this.masterPos, master.pos()); + this.masterDimension = master.dimension(); + this.masterPos = master.pos().immutable(); + if (changed) { + this.saveChanges(); + this.markForClientUpdate(); + } + return true; + } + @Nullable public PatternProviderBlockEntity getMaster() { if (this.masterDimension == null || this.masterPos == null || !(this.getLevel() instanceof ServerLevel serverLevel)) { @@ -184,28 +213,18 @@ public class MirrorPatternProviderBlockEntity extends PatternProviderBlockEntity return Component.translatable("extendedae_plus.message.mirror_pattern_provider.missing_master"); } - private void syncOrRebind(boolean allowRebind) { + private void syncBoundMaster() { var master = this.getMaster(); if (master != null) { this.syncFromMaster(master); return; } - if (allowRebind || this.hasNoBoundMaster()) { - if (this.tryBindToAdjacentMaster()) { - return; - } - } - if (this.shouldClearBrokenBinding()) { this.clearMasterBinding(true); } } - private boolean hasNoBoundMaster() { - return this.masterDimension == null || this.masterPos == null; - } - private boolean shouldClearBrokenBinding() { if (this.masterDimension == null || this.masterPos == null || !(this.getLevel() instanceof ServerLevel serverLevel)) { return true; diff --git a/src/main/java/com/extendedae_plus/init/ModCreativeTabs.java b/src/main/java/com/extendedae_plus/init/ModCreativeTabs.java index c056b67..093cd58 100644 --- a/src/main/java/com/extendedae_plus/init/ModCreativeTabs.java +++ b/src/main/java/com/extendedae_plus/init/ModCreativeTabs.java @@ -35,7 +35,8 @@ public final class ModCreativeTabs { ModItems.ASSEMBLER_MATRIX_SPEED_PLUS.get().getDefaultInstance(), ModItems.ASSEMBLER_MATRIX_CRAFTER_PLUS.get().getDefaultInstance(), ModItems.ASSEMBLER_MATRIX_PATTERN_PLUS.get().getDefaultInstance(), - ModItems.MIRROR_PATTERN_PROVIDER.get().getDefaultInstance() + ModItems.MIRROR_PATTERN_PROVIDER.get().getDefaultInstance(), + ModItems.MIRROR_PATTERN_BINDING_TOOL.get().getDefaultInstance() ).forEach(output::accept); // 放入四个预设的 stacks(x2,x4,x8,x16),使用 ModItems 工厂创建 diff --git a/src/main/java/com/extendedae_plus/init/ModItems.java b/src/main/java/com/extendedae_plus/init/ModItems.java index 18d73ff..547618e 100644 --- a/src/main/java/com/extendedae_plus/init/ModItems.java +++ b/src/main/java/com/extendedae_plus/init/ModItems.java @@ -6,6 +6,7 @@ import com.extendedae_plus.items.InfinityBigIntegerCellItem; import com.extendedae_plus.items.materials.ChannelCardItem; import com.extendedae_plus.items.materials.EntitySpeedCardItem; import com.extendedae_plus.items.materials.VirtualCraftingCardItem; +import com.extendedae_plus.items.tools.MirrorPatternBindingToolItem; import net.minecraft.world.item.BlockItem; import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; @@ -84,6 +85,10 @@ public final class ModItems { "mirror_pattern_provider", () -> new BlockItem(ModBlocks.MIRROR_PATTERN_PROVIDER_BLOCK.get(), new Item.Properties()) ); + public static final DeferredItem MIRROR_PATTERN_BINDING_TOOL = ITEMS.register( + "mirror_pattern_binding_tool", + () -> new MirrorPatternBindingToolItem(new Item.Properties()) + ); static final DeferredItem NETWORK_PATTERN_CONTROLLER = ITEMS.register( "network_pattern_controller", () -> new BlockItem(ModBlocks.NETWORK_PATTERN_CONTROLLER.get(), new Item.Properties()) diff --git a/src/main/java/com/extendedae_plus/items/tools/MirrorPatternBindingToolItem.java b/src/main/java/com/extendedae_plus/items/tools/MirrorPatternBindingToolItem.java new file mode 100644 index 0000000..039f244 --- /dev/null +++ b/src/main/java/com/extendedae_plus/items/tools/MirrorPatternBindingToolItem.java @@ -0,0 +1,169 @@ +package com.extendedae_plus.items.tools; + +import appeng.blockentity.crafting.PatternProviderBlockEntity; +import com.extendedae_plus.content.ae2.MirrorPatternProviderBlockEntity; +import net.minecraft.core.BlockPos; +import net.minecraft.core.GlobalPos; +import net.minecraft.core.component.DataComponents; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.Tag; +import net.minecraft.network.chat.Component; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.InteractionResultHolder; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.TooltipFlag; +import net.minecraft.world.item.component.CustomData; +import net.minecraft.world.item.context.UseOnContext; +import net.minecraft.world.level.Level; +import org.jetbrains.annotations.Nullable; + +import java.util.List; + +public class MirrorPatternBindingToolItem extends Item { + private static final String TAG_SELECTED_MASTER = "selectedMaster"; + private static final String TAG_DIMENSION = "dimension"; + private static final String TAG_POS = "pos"; + + public MirrorPatternBindingToolItem(Properties properties) { + super(properties.stacksTo(1)); + } + + @Override + public InteractionResult useOn(UseOnContext context) { + var level = context.getLevel(); + var player = context.getPlayer(); + var blockEntity = level.getBlockEntity(context.getClickedPos()); + var stack = context.getItemInHand(); + + if (blockEntity instanceof PatternProviderBlockEntity master && !(blockEntity instanceof MirrorPatternProviderBlockEntity)) { + if (player != null && player.isShiftKeyDown()) { + if (!level.isClientSide) { + setSelectedMaster(stack, GlobalPos.of(level.dimension(), context.getClickedPos())); + player.displayClientMessage( + Component.translatable( + "extendedae_plus.message.mirror_binding_tool.selected", + context.getClickedPos().getX(), + context.getClickedPos().getY(), + context.getClickedPos().getZ()), + true); + } + return InteractionResult.sidedSuccess(level.isClientSide); + } + + return InteractionResult.PASS; + } + + if (blockEntity instanceof MirrorPatternProviderBlockEntity mirror) { + if (!level.isClientSide) { + var selectedMaster = getSelectedMaster(stack); + if (selectedMaster == null) { + if (player != null) { + player.displayClientMessage( + Component.translatable("extendedae_plus.message.mirror_binding_tool.no_selection"), + true); + } + return InteractionResult.SUCCESS; + } + + if (mirror.bindToMaster(selectedMaster)) { + if (player != null) { + player.displayClientMessage(mirror.createBoundMessage(), true); + } + } else if (player != null) { + player.displayClientMessage( + Component.translatable("extendedae_plus.message.mirror_binding_tool.bind_failed"), + true); + } + } + + return InteractionResult.sidedSuccess(level.isClientSide); + } + + return InteractionResult.PASS; + } + + @Override + public void appendHoverText(ItemStack stack, Item.TooltipContext context, List tooltipComponents, + TooltipFlag tooltipFlag) { + super.appendHoverText(stack, context, tooltipComponents, tooltipFlag); + + tooltipComponents.add(Component.translatable("item.extendedae_plus.mirror_pattern_binding_tool.tip.select")); + tooltipComponents.add(Component.translatable("item.extendedae_plus.mirror_pattern_binding_tool.tip.bind")); + + var selectedMaster = getSelectedMaster(stack); + if (selectedMaster != null) { + var pos = selectedMaster.pos(); + tooltipComponents.add(Component.translatable( + "item.extendedae_plus.mirror_pattern_binding_tool.selected", + pos.getX(), + pos.getY(), + pos.getZ())); + tooltipComponents.add(Component.translatable( + "item.extendedae_plus.mirror_pattern_binding_tool.dimension", + selectedMaster.dimension().location().toString())); + } else { + tooltipComponents.add(Component.translatable("item.extendedae_plus.mirror_pattern_binding_tool.unset")); + } + } + + private static void setSelectedMaster(ItemStack stack, GlobalPos master) { + var tag = stack.getOrDefault(DataComponents.CUSTOM_DATA, CustomData.EMPTY).copyTag(); + var selectedTag = new CompoundTag(); + selectedTag.putString(TAG_DIMENSION, master.dimension().location().toString()); + selectedTag.putLong(TAG_POS, master.pos().asLong()); + tag.put(TAG_SELECTED_MASTER, selectedTag); + stack.set(DataComponents.CUSTOM_DATA, CustomData.of(tag)); + } + + private static void clearSelectedMaster(ItemStack stack) { + var tag = stack.getOrDefault(DataComponents.CUSTOM_DATA, CustomData.EMPTY).copyTag(); + tag.remove(TAG_SELECTED_MASTER); + stack.set(DataComponents.CUSTOM_DATA, CustomData.of(tag)); + } + + @Nullable + private static GlobalPos getSelectedMaster(ItemStack stack) { + var tag = stack.getOrDefault(DataComponents.CUSTOM_DATA, CustomData.EMPTY).copyTag(); + if (!tag.contains(TAG_SELECTED_MASTER, Tag.TAG_COMPOUND)) { + return null; + } + + var selectedTag = tag.getCompound(TAG_SELECTED_MASTER); + if (!selectedTag.contains(TAG_DIMENSION) || !selectedTag.contains(TAG_POS)) { + return null; + } + + return GlobalPos.of( + net.minecraft.resources.ResourceKey.create( + net.minecraft.core.registries.Registries.DIMENSION, + net.minecraft.resources.ResourceLocation.parse(selectedTag.getString(TAG_DIMENSION))), + BlockPos.of(selectedTag.getLong(TAG_POS))); + } + + @Override + public InteractionResultHolder use(Level level, Player player, InteractionHand usedHand) { + var stack = player.getItemInHand(usedHand); + + if (!player.isShiftKeyDown()) { + return InteractionResultHolder.pass(stack); + } + + if (!level.isClientSide) { + if (getSelectedMaster(stack) != null) { + clearSelectedMaster(stack); + player.displayClientMessage( + Component.translatable("extendedae_plus.message.mirror_binding_tool.cleared"), + true); + } else { + player.displayClientMessage( + Component.translatable("extendedae_plus.message.mirror_binding_tool.no_selection"), + true); + } + } + + return InteractionResultHolder.sidedSuccess(stack, level.isClientSide); + } +} diff --git a/src/main/resources/assets/extendedae_plus/lang/en_us.json b/src/main/resources/assets/extendedae_plus/lang/en_us.json index aa13bb5..ef3f961 100644 --- a/src/main/resources/assets/extendedae_plus/lang/en_us.json +++ b/src/main/resources/assets/extendedae_plus/lang/en_us.json @@ -20,6 +20,7 @@ "item.extendedae_plus.mirror_pattern_provider": "Mirror Pattern Provider", "item.extendedae_plus.assembler_matrix_upload_core": "Assembly Matrix Upload Core", "item.extendedae_plus.channel_card": "Channel Card", + "item.extendedae_plus.mirror_pattern_binding_tool": "Mirror Pattern Binder", "item.extendedae_plus.virtual_crafting_card": "Virtual Crafting Card", "item.extendedae_plus.channel_card.channel": "Channel: %d", "item.extendedae_plus.channel_card.channel.unset": "Channel: Unset", @@ -29,6 +30,11 @@ "item.extendedae_plus.channel_card.owner.player": "Owner: %s", "item.extendedae_plus.channel_card.owner.bound": "Bound to: %s", "item.extendedae_plus.channel_card.owner.cleared": "Binding cleared", + "item.extendedae_plus.mirror_pattern_binding_tool.tip.select": "Sneak-right-click a master pattern provider to select it", + "item.extendedae_plus.mirror_pattern_binding_tool.tip.bind": "Right-click a mirror pattern provider to bind it to the selected master", + "item.extendedae_plus.mirror_pattern_binding_tool.selected": "Selected master provider: (%d, %d, %d)", + "item.extendedae_plus.mirror_pattern_binding_tool.dimension": "Dimension: %s", + "item.extendedae_plus.mirror_pattern_binding_tool.unset": "No master provider selected", "item.extendedae_plus.entity_speed_card": "Entity Speed Card", "item.extendedae_plus.entity_speed_card.x2": "Entity Speed Card (x2)", "item.extendedae_plus.entity_speed_card.x4": "Entity Speed Card (x4)", @@ -234,6 +240,10 @@ "extendedae_plus.message.mirror_pattern_provider.following": "Mirror pattern provider is following master provider: (%d, %d, %d)", "extendedae_plus.message.mirror_pattern_provider.missing_master": "No adjacent master pattern provider was found.", "extendedae_plus.message.mirror_pattern_provider.readonly": "Mirror pattern provider has no standalone UI and follows the master's state and direction.", + "extendedae_plus.message.mirror_binding_tool.selected": "Selected master pattern provider: (%d, %d, %d)", + "extendedae_plus.message.mirror_binding_tool.no_selection": "Sneak-right-click a master pattern provider first to select it.", + "extendedae_plus.message.mirror_binding_tool.bind_failed": "Binding failed: the selected target is not a valid master pattern provider.", + "extendedae_plus.message.mirror_binding_tool.cleared": "Cleared the master pattern provider stored in the binding tool.", "extendedae_plus.state.master": "Master", "extendedae_plus.state.slave": "Slave", diff --git a/src/main/resources/assets/extendedae_plus/lang/zh_cn.json b/src/main/resources/assets/extendedae_plus/lang/zh_cn.json index fef5a55..166b583 100644 --- a/src/main/resources/assets/extendedae_plus/lang/zh_cn.json +++ b/src/main/resources/assets/extendedae_plus/lang/zh_cn.json @@ -20,6 +20,7 @@ "item.extendedae_plus.mirror_pattern_provider": "镜像样板供应器", "item.extendedae_plus.assembler_matrix_upload_core": "装配矩阵上传核心", "item.extendedae_plus.channel_card": "频道卡", + "item.extendedae_plus.mirror_pattern_binding_tool": "镜像样板绑定器", "item.extendedae_plus.virtual_crafting_card": "虚拟合成卡", "item.extendedae_plus.channel_card.channel": "频道: %d", "item.extendedae_plus.channel_card.channel.unset": "频道: 未设置", @@ -29,6 +30,11 @@ "item.extendedae_plus.channel_card.owner.player": "所有者: %s", "item.extendedae_plus.channel_card.owner.bound": "已绑定到: %s", "item.extendedae_plus.channel_card.owner.cleared": "已清除绑定", + "item.extendedae_plus.mirror_pattern_binding_tool.tip.select": "潜行右键主样板供应器:选中主供应器", + "item.extendedae_plus.mirror_pattern_binding_tool.tip.bind": "右键镜像样板供应器:绑定到当前选中的主供应器", + "item.extendedae_plus.mirror_pattern_binding_tool.selected": "当前选中主供应器:(%d, %d, %d)", + "item.extendedae_plus.mirror_pattern_binding_tool.dimension": "维度:%s", + "item.extendedae_plus.mirror_pattern_binding_tool.unset": "当前未选中主供应器", "item.extendedae_plus.entity_speed_card": "实体加速卡", "item.extendedae_plus.entity_speed_card.x2": "实体加速卡 (x2)", "item.extendedae_plus.entity_speed_card.x4": "实体加速卡 (x4)", @@ -229,6 +235,10 @@ "extendedae_plus.message.mirror_pattern_provider.following": "镜像样板供应器当前跟随主供应器:(%d, %d, %d)", "extendedae_plus.message.mirror_pattern_provider.missing_master": "未找到相邻的主样板供应器。", "extendedae_plus.message.mirror_pattern_provider.readonly": "镜像样板供应器没有独立界面,状态与朝向会跟随主供应器。", + "extendedae_plus.message.mirror_binding_tool.selected": "已选中主样板供应器:(%d, %d, %d)", + "extendedae_plus.message.mirror_binding_tool.no_selection": "请先潜行右键一个主样板供应器进行选中。", + "extendedae_plus.message.mirror_binding_tool.bind_failed": "绑定失败:所选目标不是可用的主样板供应器。", + "extendedae_plus.message.mirror_binding_tool.cleared": "已清空绑定工具中记录的主样板供应器。", "extendedae_plus.state.master": "主模式", "extendedae_plus.state.slave": "从模式", diff --git a/src/main/resources/assets/extendedae_plus/models/item/mirror_pattern_binding_tool.json b/src/main/resources/assets/extendedae_plus/models/item/mirror_pattern_binding_tool.json new file mode 100644 index 0000000..fc45941 --- /dev/null +++ b/src/main/resources/assets/extendedae_plus/models/item/mirror_pattern_binding_tool.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "extendedae_plus:item/mirror_pattern_binding_tool" + } +} diff --git a/src/main/resources/assets/extendedae_plus/textures/item/mirror_pattern_binding_tool.png b/src/main/resources/assets/extendedae_plus/textures/item/mirror_pattern_binding_tool.png new file mode 100644 index 0000000..11c5e3e Binary files /dev/null and b/src/main/resources/assets/extendedae_plus/textures/item/mirror_pattern_binding_tool.png differ