插件清单格式(stl-plugin.json)
stl-plugin.json 每个字段的含义,以及启动器如何校验与判断版本兼容
清单放在哪
每个插件一个文件夹,清单 stl-plugin.json 放在文件夹根目录,与主 DLL 并列。安装后的位置是:
Documents\Paradox Interactive\Stellaris\plugins\
<id>\ 文件夹名 = 插件 id
stl-plugin.json 清单(必须)
<你的>.dll 主 DLL(必须);它依赖的其他 DLL 放在旁边
defaults\ 设置文件的默认版本(随包,更新时被替换)
data\ 插件自己的只读数据(可选)
config\ 用户的设置(启动器生成;更新时保留)
logs\ 插件写日志的地方清单是 UTF-8 编码的 JSON,开头允许带 BOM(启动器解析前会去掉)。
一个真实的清单
stellaris-mcp 仓库的 plugin/stl-plugin.json:
{
"schema": 2,
"id": "stellaris-mcp",
"name": "Stellaris MCP bridge",
"version": "0.6.1",
"description": "Lets AI agents read and play the game over MCP: reads engine state and posts the game's own commands. The MCP server is in mcp-server\\.",
"dll": "stellaris_bridge.dll",
"game": { "exe_timestamps": ["0x6ABEAA3F"] },
"load": { "wait": "window", "delay_ms": 1500 },
"config": [
{ "file": "stellaris_mcp.ini", "default": "defaults/stellaris_mcp.ini", "title": "Stellaris MCP", "substitute": false }
],
"update": { "github": "Yidhar/stellaris-mcp", "asset": "stellaris-mcp-*.zip" },
"homepage": "https://github.com/Yidhar/stellaris-mcp"
}字段
下表按启动器 stl-core 中 Manifest 结构的实际定义整理:
| 字段 | 必填 | 类型 | 说明 |
|---|---|---|---|
schema | 应当 | 整数 | 写 2;缺省为 0 |
id | 是 | 字符串 | 只能是 ASCII 字母、数字、-、_、.。同时是安装后的文件夹名、播放集里的引用和命令行里的名字。发布后不要改 |
name | 是 | 字符串 | 给人看的名字 |
version | 应当 | 字符串 | 点分数字版本,如 0.6.1;自动更新靠它比较新旧 |
description | 可以 | 字符串 | 一句话说明,显示在插件页 |
dll | 是 | 字符串 | 主 DLL 在插件文件夹内的相对路径;不能是绝对路径,不能含 .. |
game.exe_timestamps | 应当 | 字符串数组 | 适配的 stellaris.exe 构建的 PE 时间戳,见下文 |
load.wait | 可以 | 字符串 | "window"(默认):等游戏出现可见窗口;"none":进程一存在就加载 |
load.delay_ms | 可以 | 整数 | 满足 wait 后再等多少毫秒,默认 0 |
config | 可以 | 数组 | 设置文件列表,见下文 |
update.github | 可以 | 字符串 | GitHub 仓库 owner/repo(也接受 https://github.com/owner/repo),有它才能自动更新 |
update.asset | 可以 | 字符串 | 要安装的发布附件名,* 是通配符,默认 *.zip |
homepage | 可以 | 字符串 | 主页;为空时插件页链接 update.github 的仓库 |
seed_files | 不要用 | 数组 | schema 1 遗留:往游戏目录写文件。仍兼容,新插件不得使用 |
未知字段会被忽略。不要靠这一点在清单里放自己的数据,自己的数据放 data\。
config:设置文件
"config": [
{ "file": "hello_stellaris.ini", "default": "defaults/hello_stellaris.ini", "title": "Hello", "substitute": true }
]| 字段 | 说明 |
|---|---|
file | config\ 里的文件名;**不能有子目录**,不能含 .. |
default | 插件文件夹内的默认文件。config\ 里缺这个文件时,启动器从它复制一份;不写则只在文件存在时列出 |
title | 设置编辑器里显示的标题;为空时用文件名 |
substitute | 为 true 时,复制默认文件的同时把文本中的 {plugin_dir}、{config_dir} 替换成实际的绝对路径 |
启动器在安装、更新和每次启动前补齐 config\ 里缺的文件,**已存在的文件绝不覆盖**。config\ 里没在清单中声明的文件也会出现在设置编辑器里(排在声明的文件之后)。
exe_timestamps:版本兼容
插件通常依赖 stellaris.exe 内部的地址,游戏一更新就可能读错内存。exe_timestamps 填的是 exe 的 PE 头时间戳(IMAGE_FILE_HEADER.TimeDateStamp),每个构建都不同。用 stl status 查看当前游戏的值:
> stl status
game Cygnus v4.5.2 (9776) (…\Stellaris)
exe build 0x6ABEAA3F (2026-10-01 18:45 UTC)启动时的判断:
| 情况 | 结果 |
|---|---|
| 列出的构建中包含当前构建 | 加载 |
| 列出了构建,但不含当前构建 | 跳过,提示 made for the build 0x…, the game is 0x… |
| 没有列出任何构建 | 加载,不检查 |
dll 指向的文件不存在 | 跳过 |
注意 时间戳的解析规则:带
0x前缀按十六进制;不带前缀但含字母也按十六进制;只有数字且不带前缀时按十进制解析。解析失败的条目会被直接丢弃——如果全部写错,结果等同于“没有列出任何构建”,启动器将不做检查。请一律写成"0x6ABEAA3F"这样的形式。
不列构建表示“我自己检查或与版本无关”,这时 DLL 必须在运行时自行判断(如特征码找不到就停用),绝不能对未知构建盲目读写内存。手册建议两层都做:清单里列出构建,DLL 里再检查一次,因为手动注入时不会经过启动器的检查。
启动器的校验
清单不满足下列任一条,插件会被列为问题、不会加载:
- 是合法 JSON,且含
id、name、dll; id非空,只含允许的字符;dll非空、是相对路径、不含..;config每项的file非空、不含/、\、..;default(如有)是插件文件夹内的相对路径;seed_files的路径不越界。
此外,安装时 dll 指向的文件必须存在;从更新包或索引安装时,包里清单的 id 必须与预期相同。
编辑器里可以给 stl-plugin.json 挂上启动器手册附录 B 的 JSON Schema 获得补全,但一切以启动器的实际校验为准。