添加扳手调整无线收发器频率
This commit is contained in:
parent
2732a9aee1
commit
0622767f10
|
|
@ -0,0 +1,209 @@
|
|||
package com.extendedae_plus.client.ui;
|
||||
|
||||
import com.extendedae_plus.network.SetWirelessFrequencyC2SPacket;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.GuiGraphics;
|
||||
import net.minecraft.client.gui.components.Button;
|
||||
import net.minecraft.client.gui.components.EditBox;
|
||||
import net.minecraft.client.gui.screens.Screen;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.neoforged.neoforge.network.PacketDistributor;
|
||||
|
||||
/**
|
||||
* 频率输入GUI界面
|
||||
* 用于设置无线收发器的频率
|
||||
*
|
||||
* API变化说明:
|
||||
* 1. @OnlyIn(Dist.CLIENT)在1.21.1中已移除,不再需要
|
||||
* 2. GuiGraphics替代了PoseStack作为渲染参数(1.20+的变化)
|
||||
* 3. 网络数据包通过PacketDistributor发送
|
||||
* 4. EditBox的API在1.21.1中保持稳定
|
||||
*/
|
||||
public class FrequencyInputScreen extends Screen {
|
||||
|
||||
private static final int WINDOW_WIDTH = 200;
|
||||
private static final int WINDOW_HEIGHT = 80;
|
||||
|
||||
private final BlockPos pos;
|
||||
private final long currentFrequency;
|
||||
private EditBox frequencyInput;
|
||||
private Button confirmButton;
|
||||
|
||||
/**
|
||||
* 构造函数
|
||||
* @param pos 无线收发器的位置
|
||||
* @param currentFrequency 当前频率
|
||||
*/
|
||||
public FrequencyInputScreen(BlockPos pos, long currentFrequency) {
|
||||
super(Component.translatable("gui.extendedae_plus.frequency_input.title"));
|
||||
this.pos = pos;
|
||||
this.currentFrequency = currentFrequency;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void init() {
|
||||
super.init();
|
||||
|
||||
// 计算居中位置
|
||||
int x = (this.width - WINDOW_WIDTH) / 2;
|
||||
int y = (this.height - WINDOW_HEIGHT) / 2;
|
||||
|
||||
// 创建输入框
|
||||
// API说明:EditBox构造函数参数:font, x, y, width, height, component
|
||||
this.frequencyInput = new EditBox(
|
||||
this.font,
|
||||
x + 10,
|
||||
y + 30,
|
||||
WINDOW_WIDTH - 20,
|
||||
20,
|
||||
Component.translatable("gui.extendedae_plus.frequency_input.field")
|
||||
);
|
||||
|
||||
// 设置输入框属性
|
||||
this.frequencyInput.setMaxLength(19); // long类型最大19位数字
|
||||
this.frequencyInput.setValue(String.valueOf(currentFrequency));
|
||||
this.frequencyInput.setFilter(this::isValidInput); // 只允许数字和负号
|
||||
this.frequencyInput.setFocused(true);
|
||||
|
||||
// 添加输入框到组件列表
|
||||
this.addRenderableWidget(this.frequencyInput);
|
||||
|
||||
// 创建确认按钮
|
||||
// API说明:Button.builder方法在1.21.1中使用
|
||||
this.confirmButton = Button.builder(
|
||||
Component.translatable("gui.extendedae_plus.frequency_input.confirm"),
|
||||
button -> this.onConfirm()
|
||||
)
|
||||
.bounds(x + 10, y + 55, 80, 20)
|
||||
.build();
|
||||
|
||||
this.addRenderableWidget(this.confirmButton);
|
||||
|
||||
// 创建取消按钮
|
||||
Button cancelButton = Button.builder(
|
||||
Component.translatable("gui.extendedae_plus.frequency_input.cancel"),
|
||||
button -> this.onClose()
|
||||
)
|
||||
.bounds(x + 110, y + 55, 80, 20)
|
||||
.build();
|
||||
|
||||
this.addRenderableWidget(cancelButton);
|
||||
}
|
||||
|
||||
/**
|
||||
* 输入验证:只允许数字和负号
|
||||
*/
|
||||
private boolean isValidInput(String input) {
|
||||
if (input.isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
// 允许负号在开头
|
||||
if (input.equals("-")) {
|
||||
return true;
|
||||
}
|
||||
try {
|
||||
Long.parseLong(input);
|
||||
return true;
|
||||
} catch (NumberFormatException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 按键处理:回车键确认,ESC键取消
|
||||
*
|
||||
* API说明:keyPressed方法在1.21.1中保持一致
|
||||
*/
|
||||
@Override
|
||||
public boolean keyPressed(int keyCode, int scanCode, int modifiers) {
|
||||
// 回车键确认
|
||||
if (keyCode == 257 || keyCode == 335) { // ENTER or NUMPAD_ENTER
|
||||
this.onConfirm();
|
||||
return true;
|
||||
}
|
||||
// ESC键取消
|
||||
if (keyCode == 256) { // ESC
|
||||
this.onClose();
|
||||
return true;
|
||||
}
|
||||
return super.keyPressed(keyCode, scanCode, modifiers);
|
||||
}
|
||||
|
||||
/**
|
||||
* 渲染背景
|
||||
*
|
||||
* API变化说明:
|
||||
* - GuiGraphics替代了旧的PoseStack + BufferSource组合
|
||||
* - renderBackground方法签名在1.21.1中简化
|
||||
*/
|
||||
@Override
|
||||
public void render(GuiGraphics guiGraphics, int mouseX, int mouseY, float partialTick) {
|
||||
// 渲染暗色背景
|
||||
super.render(guiGraphics, mouseX, mouseY, partialTick);
|
||||
|
||||
// 计算窗口位置
|
||||
int x = (this.width - WINDOW_WIDTH) / 2;
|
||||
int y = (this.height - WINDOW_HEIGHT) / 2;
|
||||
|
||||
// 绘制窗口背景
|
||||
guiGraphics.fill(x, y, x + WINDOW_WIDTH, y + WINDOW_HEIGHT, 0xC0000000);
|
||||
|
||||
// 绘制窗口边框
|
||||
guiGraphics.fill(x, y, x + WINDOW_WIDTH, y + 1, 0xFFFFFFFF); // 顶部
|
||||
guiGraphics.fill(x, y + WINDOW_HEIGHT - 1, x + WINDOW_WIDTH, y + WINDOW_HEIGHT, 0xFFFFFFFF); // 底部
|
||||
guiGraphics.fill(x, y, x + 1, y + WINDOW_HEIGHT, 0xFFFFFFFF); // 左侧
|
||||
guiGraphics.fill(x + WINDOW_WIDTH - 1, y, x + WINDOW_WIDTH, y + WINDOW_HEIGHT, 0xFFFFFFFF); // 右侧
|
||||
|
||||
// 绘制标题
|
||||
Component title = Component.translatable("gui.extendedae_plus.frequency_input.title");
|
||||
guiGraphics.drawString(
|
||||
this.font,
|
||||
title,
|
||||
x + (WINDOW_WIDTH - this.font.width(title)) / 2,
|
||||
y + 10,
|
||||
0xFFFFFFFF,
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 确认按钮处理
|
||||
*/
|
||||
private void onConfirm() {
|
||||
String input = this.frequencyInput.getValue();
|
||||
if (input.isEmpty()) {
|
||||
this.onClose();
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
long frequency = Long.parseLong(input);
|
||||
|
||||
// 发送数据包到服务端
|
||||
// API说明:NeoForge使用PacketDistributor.sendToServer
|
||||
PacketDistributor.sendToServer(new SetWirelessFrequencyC2SPacket(pos, frequency));
|
||||
|
||||
this.onClose();
|
||||
} catch (NumberFormatException e) {
|
||||
// 输入无效,不做处理
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 暂停游戏状态
|
||||
* 返回false表示不暂停游戏(允许多人游戏中正常使用)
|
||||
*/
|
||||
@Override
|
||||
public boolean isPauseScreen() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 静态工厂方法:打开频率输入界面
|
||||
*/
|
||||
public static void open(BlockPos pos, long currentFrequency) {
|
||||
Minecraft.getInstance().setScreen(new FrequencyInputScreen(pos, currentFrequency));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -156,6 +156,21 @@ public class WirelessTransceiverBlockEntity extends AEBaseBlockEntity implements
|
|||
setChanged();
|
||||
}
|
||||
|
||||
/**
|
||||
* 强制设置频率,忽略锁定状态
|
||||
* 用于扳手GUI等管理工具
|
||||
*/
|
||||
public void setFrequencyForced(long frequency) {
|
||||
if (this.frequency == frequency) return;
|
||||
this.frequency = frequency;
|
||||
if (isMasterMode()) {
|
||||
masterLink.setFrequency(frequency);
|
||||
} else {
|
||||
slaveLink.setFrequency(frequency);
|
||||
}
|
||||
setChanged();
|
||||
}
|
||||
|
||||
public boolean isMasterMode() {
|
||||
return masterMode;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package com.extendedae_plus.hooks;
|
|||
|
||||
import appeng.util.InteractionUtil;
|
||||
import com.extendedae_plus.ExtendedAEPlus;
|
||||
import com.extendedae_plus.client.ui.FrequencyInputScreen;
|
||||
import com.extendedae_plus.content.wireless.WirelessTransceiverBlockEntity;
|
||||
import appeng.block.crafting.CraftingUnitBlock;
|
||||
import appeng.blockentity.crafting.CraftingBlockEntity;
|
||||
|
|
@ -14,6 +15,7 @@ import net.minecraft.world.item.ItemStack;
|
|||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.neoforged.api.distmarker.Dist;
|
||||
import net.neoforged.bus.api.Event;
|
||||
import net.neoforged.bus.api.SubscribeEvent;
|
||||
import net.neoforged.fml.common.EventBusSubscriber;
|
||||
|
|
@ -90,7 +92,7 @@ public final class WrenchHook {
|
|||
// 未潜行 + 扳手:切换锁定状态
|
||||
BlockEntity be = level.getBlockEntity(hit.getBlockPos());
|
||||
if (be instanceof WirelessTransceiverBlockEntity te) {
|
||||
// 仅在服务端切换与同步,避免仅客户端生效导致看起来“无效果”
|
||||
// 仅在服务端切换与同步,避免仅客户端生效导致看起来"无效果"
|
||||
if (!level.isClientSide) {
|
||||
boolean newLocked = !te.isLocked();
|
||||
te.setLocked(newLocked);
|
||||
|
|
@ -103,7 +105,9 @@ public final class WrenchHook {
|
|||
ExtendedAEPlus.LOGGER.debug("sendBlockUpdated failed: {}", t.toString());
|
||||
}
|
||||
// 提示玩家(服务端消息下发到客户端)
|
||||
player.displayClientMessage(Component.literal(newLocked ? "已锁定收发器" : "已解锁收发器"), true);
|
||||
player.displayClientMessage(Component.translatable(
|
||||
newLocked ? "extendedae_plus.wireless.locked" : "extendedae_plus.wireless.unlocked"
|
||||
), true);
|
||||
// 轻微反馈音效
|
||||
level.playSound(player, hit.getBlockPos(), SoundEvents.LEVER_CLICK, SoundSource.BLOCKS, 0.5F, newLocked ? 0.6F : 0.9F);
|
||||
ExtendedAEPlus.LOGGER.debug("Wrench toggle lock at {} -> {}", pos, newLocked);
|
||||
|
|
@ -116,4 +120,37 @@ public final class WrenchHook {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onPlayerLeftClickBlock(PlayerInteractEvent.LeftClickBlock event) {
|
||||
// 潜行左键触发:打开频率设置GUI
|
||||
if (event.isCanceled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
var player = event.getEntity();
|
||||
var level = event.getLevel();
|
||||
var pos = event.getPos();
|
||||
|
||||
// 非旁观者
|
||||
if (player.isSpectator()) {
|
||||
return;
|
||||
}
|
||||
|
||||
ItemStack stack = player.getMainHandItem();
|
||||
|
||||
// 潜行 + 扳手:打开频率输入GUI
|
||||
if (InteractionUtil.isInAlternateUseMode(player) && InteractionUtil.canWrenchRotate(stack)) {
|
||||
BlockEntity be = level.getBlockEntity(pos);
|
||||
if (be instanceof WirelessTransceiverBlockEntity te) {
|
||||
if (level.isClientSide) {
|
||||
// 客户端:打开频率输入GUI
|
||||
FrequencyInputScreen.open(pos, te.getFrequency());
|
||||
ExtendedAEPlus.LOGGER.debug("Opening frequency input GUI for transceiver at {}", pos);
|
||||
}
|
||||
|
||||
event.setCanceled(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,5 +38,9 @@ public class ModNetwork {
|
|||
registrar.playToServer(com.extendedae_plus.network.ChannelCardBindPacket.TYPE,
|
||||
com.extendedae_plus.network.ChannelCardBindPacket.STREAM_CODEC,
|
||||
com.extendedae_plus.network.ChannelCardBindPacket::handle);
|
||||
// 无线收发器频率设置
|
||||
registrar.playToServer(com.extendedae_plus.network.SetWirelessFrequencyC2SPacket.TYPE,
|
||||
com.extendedae_plus.network.SetWirelessFrequencyC2SPacket.STREAM_CODEC,
|
||||
com.extendedae_plus.network.SetWirelessFrequencyC2SPacket::handle);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,89 @@
|
|||
package com.extendedae_plus.network;
|
||||
|
||||
import com.extendedae_plus.ExtendedAEPlus;
|
||||
import com.extendedae_plus.content.wireless.WirelessTransceiverBlockEntity;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.network.codec.StreamCodec;
|
||||
import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.neoforged.neoforge.network.handling.IPayloadContext;
|
||||
|
||||
/**
|
||||
* C2S: 客户端发送到服务端,用于设置无线收发器的频率
|
||||
*
|
||||
* API变化说明:
|
||||
* - 1.20.1 Forge使用SimpleChannel.messageBuilder
|
||||
* - 1.21.1 NeoForge使用CustomPacketPayload + StreamCodec
|
||||
* - FriendlyByteBuf的读写方法保持一致
|
||||
*/
|
||||
public class SetWirelessFrequencyC2SPacket implements CustomPacketPayload {
|
||||
|
||||
public static final Type<SetWirelessFrequencyC2SPacket> TYPE = new Type<>(
|
||||
ResourceLocation.fromNamespaceAndPath(ExtendedAEPlus.MODID, "set_wireless_frequency"));
|
||||
|
||||
/**
|
||||
* StreamCodec用于序列化和反序列化数据包
|
||||
* 第一个函数:编码(写入)
|
||||
* 第二个函数:解码(读取)
|
||||
*/
|
||||
public static final StreamCodec<FriendlyByteBuf, SetWirelessFrequencyC2SPacket> STREAM_CODEC = StreamCodec.of(
|
||||
(buf, pkt) -> {
|
||||
buf.writeBlockPos(pkt.pos);
|
||||
buf.writeLong(pkt.frequency);
|
||||
},
|
||||
buf -> new SetWirelessFrequencyC2SPacket(
|
||||
buf.readBlockPos(),
|
||||
buf.readLong()
|
||||
)
|
||||
);
|
||||
|
||||
private final BlockPos pos;
|
||||
private final long frequency;
|
||||
|
||||
public SetWirelessFrequencyC2SPacket(BlockPos pos, long frequency) {
|
||||
this.pos = pos;
|
||||
this.frequency = frequency;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type<? extends CustomPacketPayload> type() {
|
||||
return TYPE;
|
||||
}
|
||||
|
||||
/**
|
||||
* 服务端处理逻辑
|
||||
*
|
||||
* API变化说明:
|
||||
* - ctx.enqueueWork确保线程安全(在主线程执行)
|
||||
* - IPayloadContext替代了Forge的NetworkEvent.Context
|
||||
*/
|
||||
public static void handle(final SetWirelessFrequencyC2SPacket msg, final IPayloadContext ctx) {
|
||||
ctx.enqueueWork(() -> {
|
||||
if (!(ctx.player() instanceof ServerPlayer player)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 验证玩家是否在附近(防止作弊)
|
||||
if (player.distanceToSqr(msg.pos.getX() + 0.5, msg.pos.getY() + 0.5, msg.pos.getZ() + 0.5) > 64.0) {
|
||||
ExtendedAEPlus.LOGGER.warn("Player {} tried to set frequency from too far away", player.getName().getString());
|
||||
return;
|
||||
}
|
||||
|
||||
// 获取方块实体
|
||||
BlockEntity be = player.level().getBlockEntity(msg.pos);
|
||||
if (!(be instanceof WirelessTransceiverBlockEntity transceiver)) {
|
||||
ExtendedAEPlus.LOGGER.warn("Invalid block entity at {} for frequency setting", msg.pos);
|
||||
return;
|
||||
}
|
||||
|
||||
// 使用强制设置方法,忽略锁定状态
|
||||
// 扳手GUI调整频率时应该能够绕过锁定限制
|
||||
transceiver.setFrequencyForced(msg.frequency);
|
||||
ExtendedAEPlus.LOGGER.debug("Set transceiver frequency at {} to {} (forced)", msg.pos, msg.frequency);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -118,6 +118,13 @@
|
|||
"extendedae_plus.tooltip.master_mode": "Mode: %s",
|
||||
"extendedae_plus.tooltip.locked": "Status: %s",
|
||||
|
||||
"gui.extendedae_plus.frequency_input.title": "Set Frequency",
|
||||
"gui.extendedae_plus.frequency_input.field": "Frequency",
|
||||
"gui.extendedae_plus.frequency_input.confirm": "Confirm",
|
||||
"gui.extendedae_plus.frequency_input.cancel": "Cancel",
|
||||
"extendedae_plus.wireless.locked": "Transceiver Locked",
|
||||
"extendedae_plus.wireless.unlocked": "Transceiver Unlocked",
|
||||
|
||||
"group.pattern_provider.name": "Pattern Provider",
|
||||
"group.storage.name": "Storage Bus",
|
||||
"group.entity_ticker.name": "Entity Ticker"
|
||||
|
|
|
|||
|
|
@ -118,6 +118,13 @@
|
|||
"extendedae_plus.tooltip.master_mode": "模式: %s",
|
||||
"extendedae_plus.tooltip.locked": "状态: %s",
|
||||
|
||||
"gui.extendedae_plus.frequency_input.title": "设置频率",
|
||||
"gui.extendedae_plus.frequency_input.field": "频率",
|
||||
"gui.extendedae_plus.frequency_input.confirm": "确认",
|
||||
"gui.extendedae_plus.frequency_input.cancel": "取消",
|
||||
"extendedae_plus.wireless.locked": "已锁定收发器",
|
||||
"extendedae_plus.wireless.unlocked": "已解锁收发器",
|
||||
|
||||
"group.pattern_provider.name": "样板供应器",
|
||||
"group.storage.name": "存储总线",
|
||||
"group.entity_ticker.name": "实体加速器"
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user