默认键位下发

基本信息

属性 值
下发源文件 config/defaultkeys.txt(打包作者编写)
记录文件 knownkeys.txt(游戏根目录,自动生成)
加载函数 EventHandler.reloadDefaultMappings()(EventHandler.java:316-381)
触发时机 主菜单首次打开时(GuiOpenEvent + initialized 标志)
依赖 Access Transformer 把 KeyBinding.keyCodeDefault 提升为 public

文件格式

config/defaultkeys.txt 每行一条:

key_<KeyBinding.getKeyDescription()>:<keyCode>

由 saveDefaultMappings 生成(:303-314):

for (KeyBinding keyBinding : gameSettings.keyBindings) {
    writer.println("key_" + keyBinding.getKeyDescription() + ":" + keyBinding.getKeyCode());
}

键位描述即 lang key(如 key.forward),因此该文件是全语言无关的。

加载流程

reloadDefaultMappings()
  ├─ clear defaultKeys / knownKeys
  ├─ 读 config/defaultkeys.txt → Map<描述(去掉 "key_" 前缀), keyCode>
  │     跳过空行;split(":") 后长度必须为 2 且 s[0] 以 "key_" 开头,否则跳过
  │     解析失败只 printStackTrace
  ├─ 读 knownkeys.txt → List<String>
  └─ 遍历 gameSettings.keyBindings:
        若 defaultKeys 含该描述 →
            keyBinding.keyCodeDefault = 默认值      ← 依赖 AT
            若 knownKeys 不含该描述 →
                keyBinding.setKeyCode(keyCodeDefault)
                knownKeys.add(描述)
  然后 KeyBinding.resetKeyBindingArrayAndHash()
  最后重写 knownkeys.txt

设计意图

knownkeys.txt 记录"本模组已经为哪些键位下发过默认值":

  • 键位第一次出现时(模组包刚加了这个绑定)→ 套用默认值;
  • 之后玩家自行改键 → 该描述已在 knownKeys 中 → 绝不覆盖。

这使得打包作者新增键位绑定时能自动下发默认值,同时不破坏玩家已有习惯。若删掉 knownkeys.txt,下次启动会把所有 defaultkeys.txt 里的键位重置一遍。

触发点

@SubscribeEvent
public void finishMinecraftLoading(GuiOpenEvent event) {
    if (!initialized && event.gui instanceof GuiMainMenu) {
        reloadDefaultMappings();
        initialized = true;
    }
}

initialized 是 static 布尔,保证整个进程只执行一次。事件注册在 MinecraftForge.EVENT_BUS 上,且仅客户端(DefaultKeys.java:28-32)。

限制

  • keyCodeDefault 的写入依赖 AT;若 AT 失效,IllegalAccessError 会直接抛出(无 try/catch)。
  • 键位描述硬绑定 lang key。若某个 mod 改名其键位描述,条目会静默失效(defaultKeys.containsKey 为 false,无任何日志)。
  • knownkeys.txt 按描述记录,不区分 mod。同名描述的键位会被当作同一个处理。
  • 本模组不注册任何 KeyBinding(new KeyBinding 全仓 0 处),只改写别人的。
  • 无配置开关,无法禁用这套键位下发。

相关条目