7.5 KiB
7.5 KiB
RA3 Mod XML VSCode 插件 — 情况描述与需求清单
由
prompts中的零散描述整理而成。目标产物:一个用于编辑《命令与征服:红色警戒 3》Mod XML 文件的 VS Code 扩展。
一、情况描述(整理后)
红警 3 的 Mod 数据以 XML 文件组织,由 EA 的 BinaryAssetBuilder(BAB)编译。一个 Mod 项目通常包含两类数据:
- 基础数据(Static Data):单位、武器、建筑、贴图、音频、AI、UI 等绝大多数内容。入口文件是
Data/Mod.xml。 - 全局数据(Global Data):无法放进基础数据里的全局配置(游戏设置、全局单例等)。入口是
Data/additionalmaps/mapmetadata_*.xml这类文件——它们原本是 EA 的地图元数据文件,但因为加载最早且允许写任意标签,被 modder 用作“全局数据”入口。
XML 之间的组织靠 <Include> 标签,共有三种语义:
| type | 语义 | 说明 |
|---|---|---|
reference |
引用预编译 manifest | 不展开内容。典型用法是 DATA:static.xml / DATA:global.xml / DATA:audio.xml 这三个占位文件,实际对应 SDK builtmods 里已编译的 static.manifest / global.manifest / audio.manifest |
instance |
源码级可见 | 不展开进当前文件,但编译时“看得到”目标源码;典型用于 inheritFrom 继承 |
all |
内容合并 | 等价于把目标文件内容直接复制进来;Mod.xml 通过它递归聚合整个 Mod |
路径解析规则(来自现有工具 check_duplicate_ids.py 与编译脚本 defaultscript.cs):
- 带前缀
DATA:/ART:/AUDIO:的路径按固定搜索顺序查找; - 无前缀的路径相对于当前文件所在目录;
ART:路径支持“文件名前两个小写字母作为子目录”的匹配(如JUAntiShip→ju/JUAntiShip)。
继承机制:inheritFrom 让一个元素默认获得目标元素的所有内容;具体合并行为由 xai:joinAction(uri:ea.com:eala:asset:instance 命名空间)控制,实际项目中出现的取值为 Replace、Remove。
全部 XML 语法由 XSD 定义:SDK 自带 Schemas/xsd/CnC3Types.xsd(及其 800+ 个子 XSD)。大型 Mod 项目(如 Corona)还会携带自己修改过的 XSD 副本。
二、需求清单
P0:近期核心功能
- 语法高亮:为 RA3 Mod XML 提供可读的高亮;重点补充普通 XML 高亮之外的领域标记(如
$DEFINE常量引用、inheritFrom等)。 - 自动补全:
- 元素名(按当前父元素的 XSD 定义补全,含顶层资产元素);
- 属性名(按当前元素的 XSD 定义补全,
id必填者优先); - 属性值:
- 引用型属性(XSD 中带
xas:refType)补全已定义的资产 ID; inheritFrom补全可继承的资产 ID;- 枚举值(XSD
xs:enumeration); $DEFINE常量(如$CIV_HEALTH_SMALL);<Include source>补全可解析的文件路径(DATA:/ART:/AUDIO:)。
- 引用型属性(XSD 中带
- 引用提示(Hover):元素/属性悬停显示 XSD 文档、类型、默认值;资产 ID 悬停显示定义位置;
$DEFINE悬停显示值与定义位置。 - 引用导航:
- 从引用型属性值跳转到对应资产定义(Go to Definition);
- 查找某资产 ID 的所有引用(Find All References);
<Include source>/xi:include href直接打开目标文件;inheritFrom跳转到被继承元素;- 文档大纲:显示文件内的顶层资产元素。
- 错误检查(实时诊断):
- XML 格式错误(well-formedness);
- 未知元素 / 未知属性(相对 XSD 模型);
- 缺失必填
id(顶层资产); - 重复 ID(同类型 + 同 id,mod 文件之间;覆盖原版 SageXml 不算冲突);
- 引用未解析(引用了不存在的资产 ID,可配置是否忽略原版 manifest 中的 ID);
<Include>目标文件找不到、Include 循环;$DEFINE未定义。
补充(manifest 解析,支持 include reference 后的补全/导航/诊断):
- 当
Mod.xml(或其他文件)用<Include type="reference" source="DATA:static.xml" />引用占位文件时,实际内容来自 SDKbuiltmods下对应的已编译二进制 manifest(static.manifest/global.manifest/audio.manifest)。 - 通过解析这些 manifest,可以得到其包含的全部资产(名称、类型、来源文件),从而:
- 代码补全:例如 reference 了
audio.xml后,所有音频资产 ID 都能出现在引用型属性(如AudioEventRef)的补全里; - 引用导航/悬停:能定位资产来自哪个 manifest、哪个源文件;
- 诊断:能把“引用了 manifest 中的 ID”识别为已解析,而不是误报未解析引用。
- 代码补全:例如 reference 了
- manifest 为二进制格式,解析逻辑参考 OpenSAGE
ManifestFile.cs(用户已在本工作区OpenSAGE/克隆并切到指定 commit)。关键格式要点:- 头部含版本(5/6/7)、端序标志、各缓冲区大小、资产数量;
- 每个资产条目含
TypeId(哈希)、NameOffset、SourceFileNameOffset等; TypeId哈希 → 类型名的映射来自 OpenSAGE 的AssetType枚举(本工作区可提取);- 资产名与源文件名各自存放在独立的空字符结尾字符串缓冲区中。
补充(美术资产 .w3x 索引):
W3X.xml/ART:include 链中的.w3x是文本 XML(建模工具导出,BAB 同样按 XML 编译),其顶层资产(W3DContainer/W3DMesh/W3DHierarchy等)应参与 补全、悬停、导航与诊断——Model@Name、Hierarchy、Mesh等引用依赖这些定义;- 大模型文件(实测 Corona 最大 22.8 MB,顶点/三角形数据占大头)采用顶层浅扫描 (不建 DOM 树),结果在 workspace 级缓存并跨重建复用,避免每次保存都重读整个 美术资产目录(Corona 约 2.6 GB);索引记录与 include 解析结果同样跨重建缓存, 保存触发的重建零 stat、零重读(Corona 实测约 2 秒)。
P1:非近期目标(本期不做,但预留扩展点)
- 高效搜索:Mod 项目巨大(Corona 约 7500 个 XML、38MB)时直接全文搜索很慢,需要一个高效的 XML 内容索引机制。
- 索引机制的复用性:希望索引不仅能服务 VS Code 插件,也能被其他工具(如搜索、静态分析)复用,因此索引/解析核心应设计成与编辑器无关的纯模块。
三、环境与参考资源
- SDK:
C:\Apps\RA3-MODSDK-X(含defaultscript.cs编译脚本、Schemas/xsd、SageXml原版源码、builtmods编译产物)。 - 中小项目:
C:\Apps\RA3-MODSDK-X\Mods\AttachTest、D:\Mods\CoronaMod\mods\mods\GenEvoTest。 - 大型项目:
D:\Mods\CoronaMod\mods\mods\corona(自带xsd/)。 - 现有工具:工作区
check_duplicate_ids.py(include 解析与重复 ID 检测的参考实现)。 - manifest 格式参考:OpenSAGE
src/OpenSage.Game/Data/StreamFS/ManifestFile.cs(commitd45d361,最新分支已移除该文件)。本机网络受限未能拉取,且 manifest 为压缩/哈希的二进制,本期不实现其解析。
四、验收标准
- 在 AttachTest / GenEvoTest 上开箱即用(高亮、补全、跳转、诊断)。
- 在 Corona 规模的目录上不卡 UI:索引在后台执行、保存文件后增量更新。
- 纯解析/索引核心不依赖 VS Code API,可被其他工具复用。
- 可用
vsce package打出可安装的.vsix。