镜像供应器范围绑定

This commit is contained in:
GaLi 2026-04-07 17:46:02 +08:00
parent 854f026623
commit 80779b9d3c
3 changed files with 137 additions and 12 deletions

View File

@ -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<ItemStack> 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) {
}
}

View File

@ -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",

View File

@ -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": "从模式",