三种格式处理器

基本信息

属性 值
三个类 ForgeConfigHandler / SimpleConfigHandler / INIConfigHandler
各自接口 各含 static backup(PrintWriter, List<LocalConfigEntry>, File) 与 static restore(List<LocalConfigEntry>, File)
选择依据 LocalConfigEntry.getFormat(),读条目的 $format= 参数,缺省 forge
分派点 EventHandler 的 switch (first.getFormat())(备份与恢复各一处)

对照表

维度 forge simple ini
注释符 # # ;
分类语法 { } 嵌套(. 连接) { } 嵌套(. 连接) [section] 单层
分类来源 嵌套层级栈 嵌套层级栈 最近的 [...] 段
键值分隔 = = =
类型前缀 有(B: / I: …) 无(传 "*") 无(传 "*")
列表支持 有(< … >) 无 无
未知 format 记 error 跳过整组 记 error 跳过整组 记 error 跳过整组

forge 格式的列表处理

ForgeConfigHandler 独有 isInList / consumeList / discardList 三个状态:

  • 备份:遇到 <(属性名以 < 开头表示列表)时,写出 标识符=,随后把列表内每行 , 分隔输出,并把每行里的 , 替换成 ,,(:52-58)——转义列表项本身含逗号的情况;遇到 > 结束并补一个空行。

  • 恢复:命中列表条目时 discardList = true,然后重建整个列表块(ForgeConfigHandler.java:206-244):

    1. 先 writer.println(line) 原样输出触发 < 的那一行;
    2. entry.value.replaceAll(",,", "\n") 把备份时转义的双逗号还原成换行;
    3. 按 , 切分并丢弃最后一个空 token(values.subList(0, size - 1));
    4. 每个值前打印缩进 = 分类层级数 × 4 空格,再加 4 空格;
    5. 值内的 \n 换回 ,;
    6. 最后按缩进输出 > 收尾。

    即列表恢复会丢弃原文件的列表缩进与排版,改用本模组的固定 4 空格缩进规范。

这是三个 handler 中唯一支持多行值的格式。

三者共同的骨架

backup(...):

  1. 建 foundProperty[] 与 notEntries;
  2. 逐字符扫描配置文件,命中 =(或 forge 的 <)时用 passesProperty 匹配条目;
  3. 通配条目再做 notEntries 否定检查;
  4. 命中即写 getIdentifier(...) + "=" + value 并跳过后续字符;
  5. 收尾对未命中且非 not 的条目记 warn("... property not found")。

restore(...) 在此之上多一步:

  1. 先 FileUtils.copyFile 出 <name>.bak;
  2. FileUtils.readLines 读全文件,逐行替换 = 右侧为 entry.value;
  3. 任一 IOException → 从 .bak 复制回原文件并记 error(Forge/INI/Simple 三者都有)。

已知实现问题

1. 同文件混用格式会被按首条处理

分派用的是 first.getFormat()(分组的第一个条目)。因此若 X.cfg 下既有 forge 条目又有 simple 条目,整组都按第一条的格式解析,另一种格式的条目会静默失配。

2. 列表恢复会重排原文件排版

ForgeConfigHandler.restore 命中 < 列表时按上文方式重建列表块,原文件列表项的缩进与空行不保留,统一变成「层级 × 4 空格 + 4 空格」的缩进。若模组作者依赖 Forge 生成的原始排版,diff 会变脏。

3. 分组代表条目决定一切

fileEntries.get(key) 返回的列表中,只有 first 的 file / getFormat() 被使用;其余条目自身的 file 若与 first 不同(理论上不会发生,因为 key 就是 file//format)则会访问错误文件。

限制

  • 三个 handler 均为纯文本逐字符解析,不理解 Forge Configuration 的真实写出规则,只按上述形状匹配。
  • 不处理 Configuration 的版本迁移写入(如 version = 11 头部),也不校验类型是否匹配(把字符串写进 B: 项不会报错)。
  • restore 会重写整个文件(连同未命中的行),因此文件内的注释、空行、缩进会被原样保留(按行原样输出),但换行符会被统一为平台默认。
  • 全部是 static 方法,无状态,不可在运行中热重载。

相关条目