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 1596fe3..6c222ba 100644 --- a/src/main/java/com/extendedae_plus/items/tools/MirrorPatternBindingToolItem.java +++ b/src/main/java/com/extendedae_plus/items/tools/MirrorPatternBindingToolItem.java @@ -24,6 +24,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"; @@ -46,10 +47,11 @@ public class MirrorPatternBindingToolItem extends Item { var player = context.getPlayer(); var blockEntity = level.getBlockEntity(context.getClickedPos()); - if (blockEntity instanceof PatternProviderBlockEntity master && !(blockEntity instanceof MirrorPatternProviderBlockEntity)) { + if (blockEntity instanceof PatternProviderBlockEntity && !(blockEntity instanceof MirrorPatternProviderBlockEntity)) { if (player != null && player.isShiftKeyDown()) { if (!level.isClientSide) { setSelectedMaster(stack, GlobalPos.of(level.dimension(), context.getClickedPos())); + clearSelectedRangeStart(stack); player.displayClientMessage( Component.translatable( "extendedae_plus.message.mirror_binding_tool.selected", @@ -65,6 +67,13 @@ 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) { var selectedMaster = getSelectedMaster(stack); if (selectedMaster == null) { @@ -100,6 +109,7 @@ 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.range")); var selectedMaster = getSelectedMaster(stack); if (selectedMaster != null) { @@ -115,14 +125,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.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); + tag.put(TAG_SELECTED_MASTER, createGlobalPosTag(master)); stack.set(DataComponents.CUSTOM_DATA, CustomData.of(tag)); } @@ -132,14 +149,43 @@ public class MirrorPatternBindingToolItem extends Item { stack.set(DataComponents.CUSTOM_DATA, CustomData.of(tag)); } + private static void setSelectedRangeStart(ItemStack stack, GlobalPos start) { + var tag = stack.getOrDefault(DataComponents.CUSTOM_DATA, CustomData.EMPTY).copyTag(); + tag.put(TAG_SELECTED_RANGE_START, createGlobalPosTag(start)); + stack.set(DataComponents.CUSTOM_DATA, CustomData.of(tag)); + } + + private static void clearSelectedRangeStart(ItemStack stack) { + var tag = stack.getOrDefault(DataComponents.CUSTOM_DATA, CustomData.EMPTY).copyTag(); + tag.remove(TAG_SELECTED_RANGE_START); + stack.set(DataComponents.CUSTOM_DATA, CustomData.of(tag)); + } + @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.getOrDefault(DataComponents.CUSTOM_DATA, CustomData.EMPTY).copyTag(); - if (!tag.contains(TAG_SELECTED_MASTER, Tag.TAG_COMPOUND)) { + if (!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) || !selectedTag.contains(TAG_POS)) { return null; } @@ -151,6 +197,71 @@ 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 bindResult = bindMirrorsInRange(level, rangeStart.pos(), clickedPos, 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", + 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); @@ -160,8 +271,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); @@ -174,4 +286,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 a9656b2..fe60294 100644 --- a/src/main/resources/assets/extendedae_plus/lang/en_us.json +++ b/src/main/resources/assets/extendedae_plus/lang/en_us.json @@ -31,10 +31,12 @@ "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": "Sneak-right-click a mirror pattern provider to bind it to the selected master", + "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.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.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.mirror_pattern_binding_tool.range_start": "Selected range start: (%d, %d, %d)", "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)", @@ -247,7 +249,10 @@ "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.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: found %d mirror pattern providers, bound %d successfully, failed %d.", + "extendedae_plus.message.mirror_binding_tool.cleared": "Cleared the stored master pattern provider and range selection from 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 b1898d3..74dc5cb 100644 --- a/src/main/resources/assets/extendedae_plus/lang/zh_cn.json +++ b/src/main/resources/assets/extendedae_plus/lang/zh_cn.json @@ -31,10 +31,12 @@ "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.tip.bind": "右键镜像样板供应器:绑定到当前选中的主供应器", + "item.extendedae_plus.mirror_pattern_binding_tool.tip.range": "潜行右键镜像样板供应器两次:选择起点和终点后批量范围绑定", "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.entity_speed_card": "实体加速卡", "item.extendedae_plus.entity_speed_card.x2": "实体加速卡 (x2)", "item.extendedae_plus.entity_speed_card.x4": "实体加速卡 (x4)", @@ -242,7 +244,10 @@ "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.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 个。", + "extendedae_plus.message.mirror_binding_tool.cleared": "已清空绑定工具中记录的主样板供应器和范围选择。", "extendedae_plus.state.master": "主模式", "extendedae_plus.state.slave": "从模式",