服务端指令

基本信息

属性 值
注册位置 FMLServerStartingEvent,hooks/HEHooksShared.java:151-153
指令总数 3
权限 全部未覆写 getRequiredPermissionLevel() → 继承 CommandBase 默认值 4(OP)
别名 全部未覆写 getCommandAliases() → 无别名

HEServer 实例在同一次事件里初始化 (hooks/HEHooksShared.java:154-156):

if (event.getSide() == Side.SERVER || event.getServer().isSingleplayer()) {
    HEServer.instance = HEServer.load(event.getServer().worldServers[0]);
}

3 个指令

指令 用法 实现类 行
/hesetwater /hesetwater <controllerId> <waterLevel> server/commands/HECommandSetWater.java HECommandSetWater.java:20
/hedebug /hedebug <id> <on|off> server/commands/HECommandDebug.java HECommandDebug.java:19
/helistcontrollers /helistcontrollers server/commands/HECommandListControllers.java HECommandListControllers.java:20

/hedebug 的用法串没有前导斜杠(getCommandName() + " <id> <on|off>"), 另外两个有("/" + getCommandName() + ...)。仅影响报错提示文案。

/hesetwater <controllerId> <waterLevel>

HECommandSetWater.java:24-52:

float waterLevel = Float.parseFloat(params[1]);
int controllerId = Integer.parseInt(params[0]);
if (controllerId >= 0 || controllerId < HEConfig.maxDams) {
    HEServer.instance.setWaterLevel(controllerId, waterLevel);
    sender.addChatMessage(new ChatComponentText(
            "Set water level of controller " + controllerId + " to " + waterLevel));
    HE.info(sender.getCommandSenderName() + " set water level of controller "
            + controllerId + " to " + waterLevel);
} else {
    flag = false;
}
行为 说明
waterLevel Float.parseFloat → 接受小数(如 64.5)
controllerId Integer.parseInt
副作用 调 HEServer.setWaterLevel(int, float) → HEDam.setWaterLevel(float)(受 minimalWaterUpdateInterval 节流)
日志 同时发聊天消息与 HE.info 日志(含执行者名 getCommandSenderName())
失败提示 "Could not parse command!\n" + getCommandUsage(null)

⚠️ 源码缺陷:边界检查用了 ||,恒为真

HECommandSetWater.java:31:

if (controllerId >= 0 || controllerId < HEConfig.maxDams) {

应为 &&,实际写成了 ||。

|| 的语义是「非负 或 小于 maxDams」—— 对任何 int 都至少满足其中一个,因此这个边界检查恒为真,等于完全失效。

正确写法应是:

if (controllerId >= 0 && controllerId < HEConfig.maxDams) {

实际后果:

输入 走向
controllerId 超出 [0, maxDams) 仍然进入分支 → HEServer.setWaterLevel(controllerId, ...) → HEServer.java:119 dams[waterId].setWaterLevel(...) → ArrayIndexOutOfBoundsException
异常去向 被同方法的 catch (Exception ex) 捕获(HECommandSetWater.java:44)→ flag = false
用户看到 "Could not parse command!" —— 误导性提示(实际是 ID 越界,不是「无法解析」)
负数 ID 同样越界(dams[-1]),表现一致

dams 数组长度 = HEConfig.maxDams(HEServer.java:27), HEServer.setWaterLevel / setMode 等访问器均无边界检查(如 HEServer.java:118-126)。

/hedebug <id> <on|off>

HECommandDebug.java:23-56:

int controllerId = Integer.parseInt(params[0]);
boolean debugState = false;
if (params[1].equalsIgnoreCase("on")) {
    debugState = true;
} else if (params[1].equalsIgnoreCase("off")) {
    debugState = false;
} else {
    flag = false;
}
if (flag) {
    HEServer.instance.setMode(controllerId, debugState ? HE.DamMode.DEBUG : HE.DamMode.SPREAD);
    ...
}
on / off 映射到的 DamMode
on HE.DamMode.DEBUG(getValue() == 2)
off HE.DamMode.SPREAD(getValue() == 3)

⚠️ 不能切回 DRAIN——off 映射到 SPREAD 而非 DRAIN。 排水模式只能通过坝 GUI 设置。

⚠️ 完全没有 ID 边界检查(grep 'controllerId >=\|maxDams' 在本文件无命中), 越界 ID 直接进 dams[waterId] → ArrayIndexOutOfBoundsException → 被 catch (Exception ex) 吞掉 → 同样显示 "Could not parse command!"。

⚠️ DEBUG 模式无法持久化:HEDam.writeToNBTFull 只存 drainState = (mode == DRAIN) 布尔(HEDam.java:72), 重载后 DEBUG 会变成 SPREAD(HEDam.java:63-67)。见 水体方块与扩散系统。

/helistcontrollers

HECommandListControllers.java:24 起。遍历 dams, 对 dam.isPlaced() 为真的项输出一条描述串:

public String getShortDescription() {
    return "HEController @(" + blockX + ", " + blockY + ", " + blockZ + ")";
}

(HEDam.java:316-318)

配套 HEServer.getControllerCoordinates()(HEServer.java:241+)返回 List<String>。

helistcontrollers 是查到合法 controllerId 的正规途径—— 因为 hesetwater / hedebug 的边界检查都不可靠。

三个指令的共同缺陷

# 位置 问题
1 HECommandSetWater.java:31 || 应为 &&,边界检查恒真
2 HECommandDebug.java 无 ID 边界检查
3 三个指令的 catch (Exception ex) 把越界、数值格式错误等所有异常统一报成 "Could not parse command!",无法区分
4 三个指令 无中文本地化(addChatMessage(new ChatComponentText(...)) 全是硬编码英文,且 en_US.lang 中无对应键)

关联