/help 命令修复
HelpFixer 的核心机制:替换并清洗 Minecraft 的
CommandHelp,同时扫描所有已注册命令的compareTo实现。
基本信息
| 属性 | 值 |
|---|---|
| 触发阶段 | 服务端启动 (FMLServerStartingEvent) 与启动完成 (FMLServerStartedEvent) |
| 钩入对象 | net.minecraft.command.CommandHelp |
| 行为 | 替换默认实现 + 扫描并警告 compareTo 错误的命令 |
| 来源 | com.matthewprenger.helpfixer.HelpFixer(modid = HelpFixer,MC 1.7.10) |
行为
HelpFixer 在 FMLServerStartingEvent 期间调用 event.registerServerCommand(new CommandHelp() { ... }),用一个匿名子类覆盖原版的 CommandHelp。该子类重写的方法是 getSortedPossibleCommands(ICommandSender),返回执行 /help 时实际列出的命令列表。
随后在 FMLServerStartedEvent 期间,遍历 MinecraftServer.getCommandManager().getCommands().values(),对每个命令调用 validCompareTo(command),把任何 compareTo 实现存在缺陷的命令以 [HelpFixer] 前缀写入 FML 日志告警(不会真正修复或替换它们)。
替换的 CommandHelp.getSortedPossibleCommands 行为
该方法对 MinecraftServer.getServer().getCommandManager().getPossibleCommands(sender) 的返回列表依次做以下处理:
- 剔除
getCommandName() == null的命令(防止NullPointerException出现在后面的排序/格式化中)—— 日志[HelpFixer] Identified command with null name, Ignoring: <类名>。 - 剔除
getCommandUsage(sender) == null的命令 —— 日志[HelpFixer] Identified command with null usage, Ignoring: <类名>。 - 剔除任何
getCommandName()或getCommandUsage()抛CommandException的命令 —— 日志[HelpFixer] Command to throw exception <异常类>, Ignoring: <类名>。 - 按命令名字符串对剩余命令执行
Collections.sort(Comparator直接调用o1.getCommandName().compareTo(o2.getCommandName()))。
最后返回排序后的列表。这是实际 /help 在屏幕/聊天框中显示的依据。
compareTo 缺陷扫描
检测原理
validCompareTo(ICommand command) 用两个内部测试命令 testCmd1(getCommandName() = "a")与 testCmd2(getCommandName() = "z")做差值对比:
public static boolean validCompareTo(@Nonnull ICommand command) {
return command.compareTo(testCmd1) != command.compareTo(testCmd2);
}
判定规则
command.compareTo(testCmd1) |
command.compareTo(testCmd2) |
validCompareTo 结果 |
|---|---|---|
| 不等于 | 不等于 | true(实现正确) |
| 相等(不论值) | 相等(不论值) | false(实现错误) |
按 ICommand 排序契约,compareTo 应满足 反对称性:当 a < b(按 getCommandName 比较)时,c.compareTo(a) 与 c.compareTo(b) 至少方向相反或绝对值不同。如果命令的 compareTo 重写把这两个比较都返回常量(例如 return 0),就会被检测出来。
触发的日志
[HelpFixer] Command <命令名> incorrectly overrides compareTo: <命令类全名>
仅记录日志,不抛异常、不阻止服务器启动、也不替换实现。被检测的命令如果参与
/help之外的命令管理器其它排序路径,仍会按错误的compareTo排序。
数值
| 数值 | 默认值 | 来源 |
|---|---|---|
testCmd1.getCommandName() |
"a" |
HelpFixer.java:115 |
testCmd2.getCommandName() |
"z" |
HelpFixer.java:131 |
MOD_ID |
"HelpFixer" |
HelpFixer.java:31 |
acceptedMinecraftVersions |
[1.7.10] |
HelpFixer.java:27 |
acceptableRemoteVersions |
* |
HelpFixer.java:26 |
限制
- 未修改被检测命令的
compareTo—— 只在日志里告警,不重写实现。被错写compareTo的命令如果进入其他需要排序的代码路径仍然会出错。 - 不修复命令本身的
getCommandName()/getCommandUsage()抛CommandException的根本原因 —— 只是把该命令从/help输出中剔除。 - 仅 MC 1.7.10 + Forge(
acceptedMinecraftVersions = "[1.7.10]")。acceptableRemoteVersions = "*"允许任意客户端版本连接到服务器。
相关条目
- HelpFixer 分类页 - 本条目所属分类总览