装完两个 CA-MOD,启动器里两个绿灯亮得整整齐齐,进游戏苏联还是原版那套 AI,一点变化都没有。
这种事以前也撞上过,但这次值得写下来——因为问题不在模组,在启动器。

先看游戏到底读到了什么
HOI4 只认一个清单,在用户文档目录里:
D:/Users/AA/Documents/Paradox Interactive/Hearts of Iron IV/dlc_load.json
打开一看:
{"enabled_mods":[],"disabled_dlcs":[]}
空的。
而那两个模组本身没毛病。mod 目录下 ugc_2803543445.mod、ugc_3619247274.mod 都在;workshop 里的内容 common、events、gfx、interface、localisation 结构齐全,descriptor.mod 正常;Steam 侧的状态是 isSubscribed=true、isInstalled=true、needsUpdate=false。
文件全在、内容全对、清单为空。矛盾点就在这里。
绿灯是假的吗
不是假的,是问错了地方。
启动器数据库里有两张表,playsets 和 playsets_mods。查出来的结果是这样:
playset: Initial playset | active=0
playset: CA-MoD苏联 | active=0
CA-MoD苏联 → enabled=1 pos=0 steamId=2803543445
CA-MoD苏联 → enabled=1 pos=1 steamId=3619247274
界面上那个绿灯,读的是 playsets_mods.enabled,它确实是 1,所以显示已启用,没骗人。
但启动器在启动游戏时,是按 playsets.isActive 决定往 dlc_load.json 写哪一套模组列表。两个播放集的 isActive 都是 0——没有一个激活的播放集,写出来的自然就是空数组。
绿灯只说明模组被勾选了,不说明播放集被激活,更不说明游戏读到了它。这三件事得分开看。
为什么激活状态会掉成 0
这部分要看启动器自己的日志,位置在:
C:/Users/AA/AppData/Local/Paradox Interactive/launcher-v2/logs/launcher-日期.log

关键就三行:
[Sync Playsets (hoi4)]: Playset sync triggered
[ApiPlaysetToLocalSync (hoi4)]: Starting playset API-to-local sync
[LocalPlaysetToApiSync (hoi4)]: Skipping. Playsets sync is disabled
读法很直白:云端的播放集往下覆盖本地,本地的改动不往上走。
你在界面上做的每一次勾选、每一次拖排序,都只停留在本地库里;启动器一启动,就按云端数据把本地重算一遍。云端那边只有一个播放集,且不带激活标记,于是 isActive 每次同步回来都是 0。
三个让它更容易翻车的条件也在同一份日志里:
- 当时同时有 4 个 Paradox Launcher 进程在跑(pid 17512 / 22688 / 38236 / 42608),多实例并发写同一个 sqlite,状态互相踩
- 代理服务把
api.paradox-interactive.com的请求全部解析到http://127.0.0.1:7892,同步链路走了本地代理 - 轮询间隔被从 120000 毫秒改成 10000 毫秒,说明启动器自己在高频重试,同步那一侧并不健康
时间线也能对上:game.log 里那局游戏跑的是 17:12 到 18:29,setup.log(17:12:54)里模组加载记录零条;dlc_load.json 的写入时间是 18:38:41,内容是空的。整局游戏从头到尾没加载过任何模组。
修复:把激活状态和清单都钉住
第一步,关干净。 任务管理器里把 Paradox Launcher 全部结束,确认没有残留进程再往下做。多个实例是最直接的破坏源。
第二步,改激活标记。 有 sqlite 工具就两条语句:
update playsets set isActive = 0;
update playsets set isActive = 1 where name like 'CA-MoD%';
没装 sqlite 命令行也别急着下软件。同一个目的,四条路都能走,按省事程度排:
一、退掉 PDX 账号,回图形界面重来。 启动器右上角「我的帐户」退出登录,云同步整条链路就停了,isActive 不再被覆盖。然后回播放集里把两个模组关一次再打开,点播放。一行代码都不用敲,这是最省事、也最稳的一条。
二、手写清单加只读锁。 数据库干脆不碰,直接做第三步,再把文件锁成只读——启动器写不进去,自然清不空。资源管理器右键文件 → 属性 → 勾「只读」→ 确定;命令行的等价写法:
Set-ItemProperty -Path "D:/Users/AA/Documents/Paradox Interactive/Hearts of Iron IV/dlc_load.json" -Name IsReadOnly -Value $true
以后要调整模组组合,先取消只读、改完再锁回去。启动器偶尔会在写入时弹个错误框,关掉就行,游戏照样按这份清单加载。
三、装个带界面的数据库工具。 DB Browser for SQLite 有免安装版,解压即用:打开 launcher-v2.sqlite → 浏览数据 → 选 playsets 表 → 把 CA-MoD 那行的 isActive 双击改成 1,Initial playset 那行改成 0 → 写入更改 → 关闭。全程点鼠标,不用记 SQL。
四、用系统里现成的 Python。 装过 Python 或某些开发环境的机器一般都有。交互模式里贴这几行,跑完即走:
python
>>> import sqlite3
>>> db = r"D:/Users/AA/Documents/Paradox Interactive/Hearts of Iron IV/launcher-v2.sqlite"
>>> c = sqlite3.connect(db)
>>> c.execute("update playsets set isActive=0")
>>> c.execute("update playsets set isActive=1 where name like 'CA-MoD%'")
>>> c.commit(); print("done")
>>> exit()
四条都能落地,差别只是要不要多装一个工具。要是经常来回切播放集,建议直接把 PDX 账号退掉——那是唯一从根上断掉覆盖的做法,比每次手动修省心得多。
第三步,写一份清单兜底。 直接编辑 dlc_load.json:
{"enabled_mods":["mod/ugc_2803543445.mod","mod/ugc_3619247274.mod"],"disabled_dlcs":[]}

数组顺序照着你播放集里的排列写,和界面保持一致。
改之前记得备份 launcher-v2.sqlite 和 dlc_load.json,出问题直接覆盖回去。
做完这三步,重新打开启动器,顶部确认是 CA-MoD苏联,直接点播放,不要再切换播放集。
验证是不是真的吃上了
主菜单右下角版本号后面的校验标记,会跟裸版不一样;单人游戏界面能看到已启用的模组数量。想要硬证据就翻日志:logs/setup.log 里会出现模组的读取记录,error.log 里会出现模组目录路径。

最直观的判据还是这个:读档后弹出 CA-MOD 的总菜单,说明模组这次真的被吃进去了。
顺带说个容易误判的坑
ugc_2803543445.mod 里声明了五个依赖:人名和部队名称汉化补充、苏联-最美好的愿景、苏联国策优化、sov-3.61、日共重置:内容拓展。
第一轮排查时我把它当成主要嫌疑。后来对比了 workshop 里的 descriptor.mod(333 字节)和本地 mod/ugc_2803543445.mod(401 字节),两个文件的 dependencies 块逐字一致,差的 68 字节正好是 path= 那一行——这些依赖是作者自己写进描述文件的,不是启动器附加的残留。
再查内容,对那五个模组的特征 id 搜索零命中;它自身覆盖的是本体文件(common/national_focus/soviet.txt、events/NSB_Soviet.txt、common/decisions/SOV.txt)。
结论:属于声明冗余,缺了不影响加载。但如果碰到这个模组功能表现异常,而它又覆盖了国策树,那要考虑它跟本体版本之间的差异——那是另一个问题,跟播放集无关,别混在一起查。
顺带一句,玩钢4基本离不开控制台。之前整理过一份 1.19.3 的命令速查,常用的几条放在最前面:钢铁雄心4控制台命令大全(1.19.3)。刷国策、补装备、关天气这些都在那里。
防复发
- 只开一个启动器窗口,关游戏前别再开第二个
- 不依赖云端播放集的话,直接把启动器里的 PDX 账号退掉。
Api/Playset同步整条链路停掉,isActive就稳了 - 必须保留登录态,就让
api.paradox-interactive.com直连,别过本地代理 - 每次启动前先查一眼
isActive,看到 0 就先修再点播放
这次真正花时间的不是技术,是那个“界面上明明是好的”的假象。把「模组是否勾选」「播放集是否激活」「游戏是否读到」拆成三个独立问题去看,一轮就定位了。
如果你觉得这篇文章不错,有用的话可以点击下面的“赞赏”支持作者,你的支持是我更新的动力(饿饿吃饭)。


Comments NOTHING