From 23f0bd205b2a7a63750945482c8615504a6168e4 Mon Sep 17 00:00:00 2001 From: GaLi <3096147684@qq.com> Date: Tue, 7 Apr 2026 19:21:42 +0800 Subject: [PATCH] =?UTF-8?q?=E7=BB=91=E5=AE=9A=E5=99=A8=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E8=A7=A3=E7=BB=91=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ae2/MirrorPatternProviderBlockEntity.java | 32 ++++ .../tools/MirrorPatternBindingToolItem.java | 146 +++++++++++++++++- .../assets/extendedae_plus/lang/en_us.json | 9 +- .../assets/extendedae_plus/lang/zh_cn.json | 9 +- 4 files changed, 186 insertions(+), 10 deletions(-) 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 2d56c35..a004883 100644 --- a/src/main/java/com/extendedae_plus/content/ae2/MirrorPatternProviderBlockEntity.java +++ b/src/main/java/com/extendedae_plus/content/ae2/MirrorPatternProviderBlockEntity.java @@ -215,6 +215,31 @@ public class MirrorPatternProviderBlockEntity extends PatternProviderBlockEntity return Component.translatable("extendedae_plus.message.mirror_pattern_provider.missing_master"); } + public boolean hasMasterBinding() { + return this.masterDimension != null && this.masterPos != null; + } + + public boolean unbindFromMaster() { + if (!(this.getLevel() instanceof ServerLevel)) { + return false; + } + + if (!this.hasMasterBinding()) { + return false; + } + + var changed = this.clearMasterBinding(true); + if (changed) { + this.flushStateChanges(); + } + this.scheduleImmediateSync(); + return true; + } + + public Component createUnboundMessage() { + return Component.translatable("extendedae_plus.message.mirror_pattern_provider.unbound"); + } + private int syncBoundMaster() { if (this.masterDimension == null || this.masterPos == null) { if (this.needsUnboundPatternCleanup) { @@ -270,6 +295,7 @@ public class MirrorPatternProviderBlockEntity extends PatternProviderBlockEntity var changed = hadBinding; if (clearMirroredPatterns) { changed |= this.clearMirroredPatterns(); + changed |= this.resetMirroredSettingsToInitialState(); } return changed; @@ -327,6 +353,12 @@ public class MirrorPatternProviderBlockEntity extends PatternProviderBlockEntity return true; } + private boolean resetMirroredSettingsToInitialState() { + var defaultState = this.getBlockState().getBlock().defaultBlockState(); + var defaultMirror = new MirrorPatternProviderBlockEntity(this.getBlockPos(), defaultState); + return this.syncMirroredSettings(defaultMirror); + } + private boolean hasDifferentMirroredSettings(PatternProviderBlockEntity master) { var mirrorLogic = this.getLogic(); var masterLogic = master.getLogic(); diff --git a/src/main/java/com/extendedae_plus/items/tools/MirrorPatternBindingToolItem.java b/src/main/java/com/extendedae_plus/items/tools/MirrorPatternBindingToolItem.java index 524614e..aa280ed 100644 --- a/src/main/java/com/extendedae_plus/items/tools/MirrorPatternBindingToolItem.java +++ b/src/main/java/com/extendedae_plus/items/tools/MirrorPatternBindingToolItem.java @@ -25,6 +25,7 @@ import java.util.List; public class MirrorPatternBindingToolItem extends Item { private static final String TAG_SELECTED_MASTER = "selectedMaster"; + private static final String TAG_SELECTED_RANGE_START = "selectedRangeStart"; private static final String TAG_DIMENSION = "dimension"; private static final String TAG_POS = "pos"; @@ -42,7 +43,7 @@ public class MirrorPatternBindingToolItem extends Item { return this.handleBlockUse(context, context.getItemInHand()); } - public InteractionResult handleBlockUse(UseOnContext context,ItemStack stack) { + public InteractionResult handleBlockUse(UseOnContext context, ItemStack stack) { var level = context.getLevel(); var player = context.getPlayer(); var blockEntity = level.getBlockEntity(context.getClickedPos()); @@ -53,6 +54,7 @@ public class MirrorPatternBindingToolItem extends Item { if (!level.isClientSide) { if (MirrorPatternProviderBlockEntity.isSupportedMaster(blockEntity)) { setSelectedMaster(stack, GlobalPos.of(level.dimension(), context.getClickedPos())); + clearSelectedRangeStart(stack); player.displayClientMessage( Component.translatable( "extendedae_plus.message.mirror_binding_tool.selected", @@ -74,7 +76,21 @@ public class MirrorPatternBindingToolItem extends Item { } if (blockEntity instanceof MirrorPatternProviderBlockEntity mirror) { + if (player != null && player.isShiftKeyDown()) { + if (!level.isClientSide) { + this.handleRangeBinding(level, context.getClickedPos(), stack, player); + } + return InteractionResult.sidedSuccess(level.isClientSide); + } + if (!level.isClientSide) { + if (mirror.hasMasterBinding()) { + if (player != null && mirror.unbindFromMaster()) { + player.displayClientMessage(mirror.createUnboundMessage(), true); + } + return InteractionResult.SUCCESS; + } + var selectedMaster = getSelectedMaster(stack); if (selectedMaster == null) { if (player != null) { @@ -109,6 +125,8 @@ public class MirrorPatternBindingToolItem extends Item { 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")); + tooltipComponents.add(Component.translatable("item.extendedae_plus.mirror_pattern_binding_tool.tip.unbind")); + tooltipComponents.add(Component.translatable("item.extendedae_plus.mirror_pattern_binding_tool.tip.range")); tooltipComponents.add(Component.translatable("item.extendedae_plus.mirror_pattern_binding_tool.tip.clear")); var selectedMaster = getSelectedMaster(stack); @@ -125,14 +143,21 @@ public class MirrorPatternBindingToolItem extends Item { } else { tooltipComponents.add(Component.translatable("item.extendedae_plus.mirror_pattern_binding_tool.unset")); } + + var selectedRangeStart = getSelectedRangeStart(stack); + if (selectedRangeStart != null) { + var pos = selectedRangeStart.pos(); + tooltipComponents.add(Component.translatable( + "item.extendedae_plus.mirror_pattern_binding_tool.range_start", + pos.getX(), + pos.getY(), + pos.getZ())); + } } private static void setSelectedMaster(ItemStack stack, GlobalPos master) { var tag = stack.getOrCreateTag(); - 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); + tag.put(TAG_SELECTED_MASTER, createGlobalPosTag(master)); } private static void clearSelectedMaster(ItemStack stack) { @@ -142,14 +167,43 @@ public class MirrorPatternBindingToolItem extends Item { } } + private static void setSelectedRangeStart(ItemStack stack, GlobalPos start) { + var tag = stack.getOrCreateTag(); + tag.put(TAG_SELECTED_RANGE_START, createGlobalPosTag(start)); + } + + private static void clearSelectedRangeStart(ItemStack stack) { + var tag = stack.getTag(); + if (tag != null) { + tag.remove(TAG_SELECTED_RANGE_START); + } + } + @Nullable private static GlobalPos getSelectedMaster(ItemStack stack) { + return getStoredGlobalPos(stack, TAG_SELECTED_MASTER); + } + + @Nullable + private static GlobalPos getSelectedRangeStart(ItemStack stack) { + return getStoredGlobalPos(stack, TAG_SELECTED_RANGE_START); + } + + private static CompoundTag createGlobalPosTag(GlobalPos globalPos) { + var selectedTag = new CompoundTag(); + selectedTag.putString(TAG_DIMENSION, globalPos.dimension().location().toString()); + selectedTag.putLong(TAG_POS, globalPos.pos().asLong()); + return selectedTag; + } + + @Nullable + private static GlobalPos getStoredGlobalPos(ItemStack stack, String tagKey) { var tag = stack.getTag(); - if (tag == null || !tag.contains(TAG_SELECTED_MASTER, Tag.TAG_COMPOUND)) { + if (tag == null || !tag.contains(tagKey, Tag.TAG_COMPOUND)) { return null; } - var selectedTag = tag.getCompound(TAG_SELECTED_MASTER); + var selectedTag = tag.getCompound(tagKey); if (!selectedTag.contains(TAG_DIMENSION, Tag.TAG_STRING) || !selectedTag.contains(TAG_POS, Tag.TAG_LONG)) { return null; } @@ -159,6 +213,78 @@ public class MirrorPatternBindingToolItem extends Item { BlockPos.of(selectedTag.getLong(TAG_POS))); } + private void handleRangeBinding(Level level, BlockPos clickedPos, ItemStack stack, Player player) { + var selectedMaster = getSelectedMaster(stack); + if (selectedMaster == null) { + player.displayClientMessage( + Component.translatable("extendedae_plus.message.mirror_binding_tool.no_selection"), + true); + return; + } + + var rangeStart = getSelectedRangeStart(stack); + if (rangeStart == null || !rangeStart.dimension().equals(level.dimension())) { + setSelectedRangeStart(stack, GlobalPos.of(level.dimension(), clickedPos)); + player.displayClientMessage( + Component.translatable( + "extendedae_plus.message.mirror_binding_tool.range_start_selected", + clickedPos.getX(), + clickedPos.getY(), + clickedPos.getZ()), + true); + return; + } + + var rangeEnd = clickedPos.immutable(); + var bindResult = bindMirrorsInRange(level, rangeStart.pos(), rangeEnd, selectedMaster); + clearSelectedRangeStart(stack); + + if (bindResult.totalMirrors() == 0) { + player.displayClientMessage( + Component.translatable("extendedae_plus.message.mirror_binding_tool.range_no_mirror"), + true); + return; + } + + player.displayClientMessage( + Component.translatable( + "extendedae_plus.message.mirror_binding_tool.range_bound", + rangeStart.pos().getX(), + rangeStart.pos().getY(), + rangeStart.pos().getZ(), + rangeEnd.getX(), + rangeEnd.getY(), + rangeEnd.getZ(), + bindResult.totalMirrors(), + bindResult.boundMirrors(), + bindResult.failedMirrors()), + true); + } + + private static RangeBindResult bindMirrorsInRange(Level level, BlockPos start, BlockPos end, GlobalPos selectedMaster) { + int totalMirrors = 0; + int boundMirrors = 0; + + var minX = Math.min(start.getX(), end.getX()); + var minY = Math.min(start.getY(), end.getY()); + var minZ = Math.min(start.getZ(), end.getZ()); + var maxX = Math.max(start.getX(), end.getX()); + var maxY = Math.max(start.getY(), end.getY()); + var maxZ = Math.max(start.getZ(), end.getZ()); + + for (var pos : BlockPos.betweenClosed(minX, minY, minZ, maxX, maxY, maxZ)) { + var blockEntity = level.getBlockEntity(pos); + if (blockEntity instanceof MirrorPatternProviderBlockEntity mirror) { + totalMirrors++; + if (mirror.bindToMaster(selectedMaster)) { + boundMirrors++; + } + } + } + + return new RangeBindResult(totalMirrors, boundMirrors, totalMirrors - boundMirrors); + } + @Override public InteractionResultHolder use(Level level, Player player, InteractionHand usedHand) { var stack = player.getItemInHand(usedHand); @@ -168,8 +294,9 @@ public class MirrorPatternBindingToolItem extends Item { } if (!level.isClientSide) { - if (getSelectedMaster(stack) != null) { + if (getSelectedMaster(stack) != null || getSelectedRangeStart(stack) != null) { clearSelectedMaster(stack); + clearSelectedRangeStart(stack); player.displayClientMessage( Component.translatable("extendedae_plus.message.mirror_binding_tool.cleared"), true); @@ -182,4 +309,7 @@ public class MirrorPatternBindingToolItem extends Item { return InteractionResultHolder.sidedSuccess(stack, level.isClientSide); } + + private record RangeBindResult(int totalMirrors, int boundMirrors, int failedMirrors) { + } } 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 02208dc..853e52e 100644 --- a/src/main/resources/assets/extendedae_plus/lang/en_us.json +++ b/src/main/resources/assets/extendedae_plus/lang/en_us.json @@ -180,10 +180,13 @@ "item.extendedae_plus.mirror_pattern_binding_tool": "Mirror Pattern Binder", "item.extendedae_plus.mirror_pattern_binding_tool.tip.select": "Sneak-right-click a bindable pattern provider to record it", "item.extendedae_plus.mirror_pattern_binding_tool.tip.bind": "Right-click a mirror pattern provider to bind it to the recorded master", + "item.extendedae_plus.mirror_pattern_binding_tool.tip.unbind": "Right-click a bound mirror pattern provider to unbind it, even if a master is recorded", + "item.extendedae_plus.mirror_pattern_binding_tool.tip.range": "Sneak-right-click two mirror pattern providers to select a range and bind all mirrors inside it", "item.extendedae_plus.mirror_pattern_binding_tool.tip.clear": "Sneak-right-click air to clear the recorded master", "item.extendedae_plus.mirror_pattern_binding_tool.selected": "Recorded 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 pattern provider recorded", + "item.extendedae_plus.mirror_pattern_binding_tool.range_start": "Selected range start: (%d, %d, %d)", "item.extendedae_plus.virtual_crafting_card": "Virtual Crafting Card", "item.extendedae_plus.virtual_crafting_card.tooltip_main": "Auto-completes crafting jobs once the current pattern is about to finish", "item.extendedae_plus.virtual_crafting_card.tooltip_detail": "Install inside a Pattern Provider upgrade slot", @@ -213,12 +216,16 @@ "extendedae_plus.message.mirror_pattern_provider.bound": "Mirror pattern provider bound to master provider: (%d, %d, %d)", "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 master pattern provider is bound. Use the binder to bind one manually.", + "extendedae_plus.message.mirror_pattern_provider.unbound": "Mirror pattern provider unbound.", "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": "Recorded master pattern provider: (%d, %d, %d)", "extendedae_plus.message.mirror_binding_tool.no_selection": "Sneak-right-click a bindable pattern provider first to record it.", "extendedae_plus.message.mirror_binding_tool.bind_failed": "Binding failed: the recorded position is not a valid pattern provider.", "extendedae_plus.message.mirror_binding_tool.unsupported_provider": "This mirror binder only supports bindable pattern provider targets.", - "extendedae_plus.message.mirror_binding_tool.cleared": "Cleared the master pattern provider recorded in the binding tool.", + "extendedae_plus.message.mirror_binding_tool.range_start_selected": "Selected range start: (%d, %d, %d)", + "extendedae_plus.message.mirror_binding_tool.range_no_mirror": "No mirror pattern providers were found in the selected range.", + "extendedae_plus.message.mirror_binding_tool.range_bound": "Range binding complete: start (%d, %d, %d), end (%d, %d, %d); found %d mirror pattern providers, bound %d successfully, failed %d.", + "extendedae_plus.message.mirror_binding_tool.cleared": "Cleared the recorded master pattern provider and range selection from the binding tool.", "config.jade.plugin_extendedae_plus.wireless_transceiver_info": "Wireless Transceiver Info", "config.jade.plugin_extendedae_plus.wt_frequency": "Show Frequency", 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 4547bf5..b1c1833 100644 --- a/src/main/resources/assets/extendedae_plus/lang/zh_cn.json +++ b/src/main/resources/assets/extendedae_plus/lang/zh_cn.json @@ -179,10 +179,13 @@ "item.extendedae_plus.mirror_pattern_binding_tool": "镜像样板绑定器", "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.tip.unbind": "右键已绑定的镜像样板供应器:解除绑定(即使当前已记录主供应器)", + "item.extendedae_plus.mirror_pattern_binding_tool.tip.range": "潜行右键镜像样板供应器两次:选择起点和终点后批量范围绑定", "item.extendedae_plus.mirror_pattern_binding_tool.tip.clear": "潜行右键空气:清空当前记录的主供应器", "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.mirror_pattern_binding_tool.range_start": "当前范围起点:(%d, %d, %d)", "item.extendedae_plus.virtual_crafting_card": "虚拟合成卡", "item.extendedae_plus.virtual_crafting_card.tooltip_main": "当前样板即将完成时尝试终止剩余合成", "item.extendedae_plus.virtual_crafting_card.tooltip_detail": "需安装在样板供应器的升级槽内", @@ -212,12 +215,16 @@ "extendedae_plus.message.mirror_pattern_provider.bound": "镜像样板供应器已绑定到主供应器:(%d, %d, %d)", "extendedae_plus.message.mirror_pattern_provider.following": "镜像样板供应器当前跟随主供应器:(%d, %d, %d)", "extendedae_plus.message.mirror_pattern_provider.missing_master": "未绑定主样板供应器,请使用绑定器手动绑定", + "extendedae_plus.message.mirror_pattern_provider.unbound": "镜像样板供应器已解除绑定。", "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.unsupported_provider": "当前镜像样板绑定器仅支持可绑定的样板供应器目标", - "extendedae_plus.message.mirror_binding_tool.cleared": "已清空绑定工具中记录的主样板供应器", + "extendedae_plus.message.mirror_binding_tool.range_start_selected": "已选中范围起点:(%d, %d, %d)", + "extendedae_plus.message.mirror_binding_tool.range_no_mirror": "所选范围内未找到镜像样板供应器。", + "extendedae_plus.message.mirror_binding_tool.range_bound": "范围绑定完成:起点 (%d, %d, %d),终点 (%d, %d, %d);找到 %d 个镜像样板供应器,成功绑定 %d 个,失败 %d 个。", + "extendedae_plus.message.mirror_binding_tool.cleared": "已清空绑定工具中记录的主样板供应器和范围选择。", "config.jade.plugin_extendedae_plus.wireless_transceiver_info": "无线收发器信息", "config.jade.plugin_extendedae_plus.wt_frequency": "显示频率",