正则表达式驱动冲突检测:xcom2-launcher解析ScreenClass覆盖算法全拆解
【免费下载链接】xcom2-launcherThe Alternative Mod Launcher (AML) is a replacement for the default game launchers from XCOM 2 and XCOM Chimera Squad.项目地址: https://gitcode.com/gh_mirrors/xc/xcom2-launcher
你是否曾在 XCOM 2 里同时装上多个 MOD,却莫名出现游戏崩溃或界面错乱?xcom2-launcher(即 AML,Alternative Mod Launcher)正是为 XCOM 2 与 XCOM Chimera Squad 打造的一款第三方 MOD 启动器,它能自动识别 MOD 之间的类覆盖冲突。本文将拆解它如何用两条正则表达式解析ScreenClass与ModClassOverrides,并通过四重过滤条件精准判定 MOD 冲突——让你彻底看懂"冲突检测"背后的完整算法。
一、为什么 XCOM 2 MOD 启动器需要冲突检测?
XCOM 2 的 MOD 生态中,许多 MOD 会"替换"游戏原有的 C++ 类:两个 MOD 若修改了同一个类,后加载的那个会覆盖前者,轻则功能失效,重则游戏崩溃。
AML 启动器在 MainForm.cs 中内置了一个专门的"Overrides"选项卡,实时展示:
- 每个启用 MOD 覆盖了哪些游戏类
- 哪些类被多个 MOD 同时修改(即冲突)
- 在 MOD 列表上用
ModState.ModConflict状态标记出"惹事"的 MOD,并可通过"Conflicts (N)"过滤器一键筛选
要做到这些,第一步就是把每个 MOD 的"覆盖声明"从文件里准确抓出来。AML 的答案是:正则表达式。
二、两种类覆盖机制:两条正则各司其职
XCOM 2 的 MOD 修改游戏类的途径有两种,AML 在 ModEntry.cs 中各准备了一条编译期正则:
| 覆盖类型 | 声明位置 | 典型写法 |
|---|---|---|
| UIScreenListener | MOD 的Src目录下.uc源文件 | ScreenClass = someclass |
| 类替换(Class) | MOD 的Config/XComEngine.ini | ModClassOverrides=(BaseGameClass="...",ModClass="...") |
1️⃣ 解析 ScreenClass:容忍任意缩进与大小写
UIScreenListener 是 XCOM 2 的"UI 监听器"机制:一个.uc文件中声明了ScreenClass = xxx,就意味着该监听器挂在xxx这个界面上。对应正则为:
(?i)^\s*ScreenClass\s*=\s*(?:class')?([a-z_]+)
细节很值得玩味:
(?i)忽略大小写,[a-z_]因此能同时匹配MainMenu、mainmenu等写法;^\s*容忍行首任意缩进,=两边的\s*容忍空格差异;(?:class')?是一个非捕获组,兼容 UE 脚本中class'Xxx'的类字面量写法;- 捕获组
([a-z_]+)只留下类名本身。
扫描逻辑在 ModEntry.cs 的 GetUIScreenListenerOverrides 中:
- 用
Parallel.ForEach并行遍历所有.uc文件,加快大型 MOD 集合的扫描速度; - 跳过
Src\XComGame目录——那里通常放着整个游戏的全部源码,作者误放进去会制造海量假覆盖; - 特殊值
ScreenClass = none表示监听器作用于所有UI 界面,属于正常用法,直接跳过不计入覆盖。
2️⃣ 解析 ModClassOverrides:先清洗,再匹配
引擎级的类替换写在 INI 里,格式严格但容易夹杂多余空白。AML 先用空白正则\s+把整行压缩(见 s_whitespaceRegex),再交给主正则(GetClassOverrides):
^[+]?ModClassOverrides=\(BaseGameClass="([^"]+)",ModClass="([^"]+)"\)
[+]?兼容 INI 数组行首的+号;- 两个捕获组分别取出"被替换的原类"(BaseGameClass)与"替换类"(ModClass)。
扫描范围只限 MOD 目录下Config中的XComEngine.ini文件,避免误伤其他配置。
3️⃣ 统一模型:ModClassOverride
两种来源最终汇入同一个数据结构 ModClassOverride:
OldClass/NewClass:原类与新类;OverrideType:枚举Class或UIScreenListener(ModClassOverrideType);TextLine:原始文本行,注释里明确写着"保留未处理的原文,以避免误报(#102)"——这是冲突判定的关键伏笔。
所有覆盖通过 LoadOverridesAsync 异步加载并缓存在 MOD 条目中,供后续检测随时取用。
三、冲突判定算法:四重过滤条件逐一拆解
真正的"裁判逻辑"在 ModList.cs 的 GetActiveConflictsImplementation。算法非常干脆:
- 汇总所有已启用MOD 的覆盖记录;
- 按
OldClass(忽略大小写)分组; - 一组内同时满足以下 4 个条件,才判定为冲突:
| 条件 | 含义 | 排除的场景 |
|---|---|---|
| ① 覆盖数 > 1 | 至少两个 MOD 动了同一个类 | 单一来源,天然无冲突 |
② 至少一条是Class类型 | 若全部只是 UIScreenListener,不算冲突 | 监听器可并存,同界面挂多个监听器完全合法 |
| ③ 来源 MOD ID 不全相同 | 必须来自不同MOD | 同一 MOD 内部分多行覆盖自身负责 |
| ④ 原始文本行不全相同 | 各 MOD 写的内容要有差异 | 多个 MOD 声明了完全相同的覆盖行,说明内容一致,实际行为相同 |
条件②是 XCOM 2 MODding 的领域知识直接写进了代码:引擎级类替换是"你死我活"的,而 UI 监听器是"各挂各的"。条件④则解释了为何 ModClassOverride 要刻意保留TextLine原文——它正是消除误报的最后一道闸门。
最终结果封装为 ModConflict 对象(冲突类名 + 全部相关覆盖记录),交给界面层。
四、从检测到界面:冲突状态如何呈现
UpdateModsConflictState 负责"增量刷新":先清除全部旧冲突标记,再为每个冲突涉及的 MOD 打上ModConflict状态,并只返回状态发生变化的 MOD 列表,让界面高效局部刷新。
回到主界面(UpdateConflictInfo):
- "Overrides"选项卡标题动态追加
(N Conflicts),并显示警告图标; - 表格中逐行列出
MOD 名称 → 原类 → 新类,UIScreenListener 类型会带(UIScreenListener)后缀以示区分; - 文本日志打印
Conflict found for 'xxx',方便进阶用户定位到具体 MOD; - MOD 列表支持按"Conflicts (N)"筛选,一眼锁定问题 MOD。
整套流程形成了"扫描 → 建模 → 判定 → 呈现"的完整闭环,且每次启用/停用 MOD 都会即时重算。
五、给 MOD 使用者的 3 条实用建议
- 先看 Overrides 选项卡再排错:遇到界面异常或功能"互相打架",优先检查哪个原类被多个 MOD 覆盖,而不是盲目禁用;
- 善用 Conflicts 过滤器:它只标记真正存在引擎级类冲突的 MOD,UIScreenListener 类"同屏监听"不会误伤;
- 注意
Src\XComGame陷阱:如果你自制 MOD,切勿把游戏全量源码留在Src下,AML 会主动跳过它,但其他工具可能不会。
总结
xcom2-launcher(AML)用两条编译期正则分别解析ScreenClass与ModClassOverrides,把两类覆盖统一为ModClassOverride模型,再经过"多来源、含引擎级替换、内容不同"四重过滤判定冲突——这正是它比普通启动器更能"未卜先知"的关键。想深入了解实现细节,可以顺着源码读下去:
- 正则定义与扫描逻辑:ModEntry.cs
- 冲突判定核心:ModList.cs
- 覆盖与冲突数据模型:ModClassOverride.cs、ModConflict.cs
- 界面呈现:MainForm.cs
掌握这套算法后,你不仅能更高效地管理自己的 MOD 组合,也能看懂 AML 这类工具是如何把"游戏崩溃玄学"变成一条条可验证的规则。
【免费下载链接】xcom2-launcherThe Alternative Mod Launcher (AML) is a replacement for the default game launchers from XCOM 2 and XCOM Chimera Squad.项目地址: https://gitcode.com/gh_mirrors/xc/xcom2-launcher
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考