localconfig 保护机制

基本信息

属性 值
概念 模组包更新时,保护玩家本地自行修改过的配置项,不让它们被新版本覆盖
定义文件 config/localconfig.txt(声明要保护哪些项,无值)
值文件 localconfig.cfg(游戏根目录,每次启动自动生成的快照,有值)
触发开关 config/modpack-update 哨兵文件存在
实现类 EventHandler.backupLocalConfig() / EventHandler.restoreLocalConfig()

两阶段模型

正常启动(无哨兵文件)→ backupLocalConfig()

把 config/localconfig.txt 中声明的项,从当前各配置文件里读出实际值,汇总写入 localconfig.cfg(:96-151):

  1. 解析 config/localconfig.txt,得到 List<LocalConfigEntry>;
  2. 按 file + "//" + format 分组(Guava ArrayListMultimap);
  3. 每组取 first 作为代表,若 config/<file> 不存在则记 warn 并跳过整组;
  4. 按 first.getFormat() 分派到 ForgeConfigHandler / SimpleConfigHandler / INIConfigHandler 的 backup(...);
  5. 写入 localconfig.cfg,文件头带 3 行"自动生成、勿改"注释。

更新启动(有哨兵文件)→ restoreLocalConfig() + 删除哨兵

把 localconfig.cfg 中的旧值写回各配置文件,然后删除 config/modpack-update(:153-219 + :80-90):

  1. 同时读 config/localconfig.txt(定义)与 localconfig.cfg(旧值);
  2. 对每条旧值,用 defEntry.passesProperty(entry.category, entry.name, entry.type) 找到匹配的定义项,把定义的 parameters 合并进旧值;
  3. 按同样的 file//format 分组,分派到各 handler 的 restore(...)。

效果:模组包更新后,玩家在 localconfig.txt 声明过的那些项回到更新前的玩家值,其余项正常跟随新版本。

三种格式处理器

format 处理器 解析结构
forge(默认) ForgeConfigHandler { } 嵌套分类 + B:xxx = value,额外支持 < 到 > 的列表
simple SimpleConfigHandler { } 嵌套分类 + name = value
ini INIConfigHandler [section] 单层分类 + name = value,注释符 ;

格式由条目的 $format= 参数选择;未指定时 getFormat() 返回 "forge"(LocalConfigEntry.java:150)。

安全措施

三个 handler 的 restore(...) 都有统一模式:

  1. 先把原配置文件复制为 <name>.bak;
  2. 读全部行 → 逐行替换命中项的 =右侧 → 重写整个文件;
  3. 任何 IOException → 从 .bak 回滚并记 error;
  4. 条目没匹配到 → 记 warn("Failed to ... local value {}: property not found")。

SimpleConfigHandler 与两个 Forge/INI handler 的 backup 在条目未命中时同样 warn(但排除了 not 条目,避免对"排除项"误报警告)。

限制

  • 备份与恢复不对称:备份写 localconfig.cfg(游戏根),恢复读它,但定义文件 config/localconfig.txt 缺失时恢复直接跳过(if (defs.exists() && values.exists()),:158)。
  • restoreLocalConfig() 返回 true 只表示流程走完,不代表每条都成功;哨兵文件仍会被删除,失败不可重试。
  • 分组时用 first.getFormat() 决定整个分组的格式——同一文件下混用格式的条目会被按第一条的格式处理。
  • 条目顺序敏感:每个 handler 都在 for (j...) 中首个匹配即 break,重叠的通配条目只有第一个生效。
  • 通配条目会被 ! 否定条目二次否决(notEntries),但仅当该条目 containsWildcard() 为真时才检查。

相关条目