模组的目录结构与 descriptor.mod

模组放在哪、两个描述文件各管什么、内容文件夹怎么摆

模组放在哪里

《群星》的用户数据目录是 Documents\Paradox Interactive\Stellaris\(游戏目录里的 launcher-settings.json 写的是 %USER_DOCUMENTS%/Paradox Interactive/Stellaris)。所有模组都通过这里的 mod\ 文件夹登记:

代码
Documents\Paradox Interactive\Stellaris\
  mod\
    my_first_mod.mod          ← 外层描述文件:告诉游戏“有这个模组、内容在哪”
    my_first_mod\             ← 内容文件夹
      descriptor.mod          ← 内层描述文件:随模组一起上传创意工坊
      common\
      events\
      localisation\
  dlc_load.json               ← 本次启动要加载哪些模组
  • 本地模组:mod\ 下任意名字的 .mod 文件,path= 指向内容文件夹。
  • 创意工坊模组:外层描述文件叫 ugc_<创意工坊ID>.mod,path= 指向 steamapps\workshop\content\281990\<ID>。
  • Paradox Mods 平台的模组:外层描述文件叫 pdx_<ID>.mod。

永远不要直接改游戏安装目录里的文件。模组的意义就是在不动原版文件的前提下,用同路径或同名对象覆盖原版内容(见加载顺序与覆盖规则)。

两个描述文件

一个本地模组有两份描述文件,内容几乎相同:

文件作用区别
mod\<名字>.mod游戏和启动器读取的登记文件,dlc_load.json 里引用的就是它必须有 path=(或 archive=)
mod\<名字>\descriptor.mod内容文件夹里的副本,上传创意工坊时随内容一起走不写 path=

一个真实的创意工坊模组的外层描述文件(巨构工程)长这样:

Clausewitz 脚本
version="3.40.4"
tags={
	"Gameplay"
}
name="Gigastructural Engineering & More (4.5)"
supported_version="v4.5.*"
path="E:/Program Files (x86)/Steam/steamapps/workshop/content/281990/1121692237"
remote_file_id="1121692237"

自己新建模组时,内层 descriptor.mod 可以这样写:

Clausewitz 脚本
version="1.0.0"
tags={
	"Events"
	"Gameplay"
}
name="My First Mod"
picture="thumbnail.png"
supported_version="v4.5.*"

常用字段

字段说明
name模组名,启动器里显示的名字;其他模组用它声明依赖
version你自己的模组版本号,随便写,但建议递增
supported_version适配的游戏版本,见下文
path内容文件夹的路径(只在外层描述文件里写),建议用 / 分隔
archive内容是一个 zip 时用它代替 path
tags创意工坊标签,如 "Events"、"Gameplay"、"Translation"
picture内容文件夹里的封面图文件名,通常是 thumbnail.png
remote_file_id上传到创意工坊后得到的物品 ID,由上传工具写入
dependencies依赖的其他模组,按 name 列出:dependencies = { "UI Overhaul Dynamic" }
replace_path整个替换某个文件夹,见下文

supported_version 怎么写

推荐写法是 v4.5.*(只锁主版本和次版本),或者写死某个具体版本如 v4.5.1。

在 4.5.2 上实测,游戏会在 error.log 里对次版本号用通配符的写法报错:

代码
[dlc.cpp:346]: Invalid supported_version in  file: mod/xxx.mod line: 7

被报错的写法包括 *、*.*、v4.*、v4.*.*、3.* 等;而 v4.5.*、v4.4.*、v4.5.1 都不会报错。

提示 不要为了“兼容所有版本”去写 *。如实写出你测试过的版本,玩家在启动器里看到的过期提示才有意义。

replace_path

replace_path = "common/technology" 表示:在本模组之前加载的所有内容(包括原版)里,这个文件夹整体不再读取,只用本模组及之后模组提供的文件。可以写多行。

注意 replace_path 会把原版这个文件夹里的一切都抹掉,玩家同时开的其他模组如果往同一文件夹加东西,也可能被你抹掉(取决于加载顺序)。只有大型总体转换模组才需要它,普通模组请用同名覆盖。

内容文件夹的结构

内容文件夹要照搬原版的目录结构,文件夹名一个字母都不能错,游戏只读它认识的路径:

代码
my_first_mod\
  descriptor.mod
  thumbnail.png
  common\
    scripted_effects\
      my_first_mod_effects.txt
    static_modifiers\
      my_first_mod_modifiers.txt
    on_actions\
      my_first_mod_on_actions.txt
  events\
    my_first_mod_events.txt
  localisation\
    simp_chinese\
      my_first_mod_l_simp_chinese.yml
  gfx\
  interface\

几条约定:

  1. 给文件加上自己的前缀(如 my_first_mod_),避免与原版或其他模组的文件同路径,否则会变成整文件覆盖。
  2. 脚本文件(.txt)用 UTF-8 保存。实测 4.5.2 会把文件开头的 BOM 当成第一个对象名字的一部分,导致第一个定义被“改名”而失效;如果编辑器非要加 BOM,就让文件第一行是注释。
  3. 本地化文件(.yml)则必须带 BOM,详见本地化。

dlc_load.json

游戏启动时读取 Documents\Paradox Interactive\Stellaris\dlc_load.json 决定加载哪些模组,顺序即加载顺序:

JSON
{"disabled_dlcs":[],"enabled_mods":["mod/my_first_mod.mod","mod/ugc_1121692237.mod"]}

这个文件通常由启动器根据“播放集(playset)”写出,手改的内容可能在启动器下次保存时被覆盖。开发阶段在启动器里新建一个只放自己模组的播放集,是最省事的做法。

下一步:了解加载顺序与覆盖规则,再学会调试。