插件的发布与索引

打包、GitHub Release 自动更新与 plugins.jsonl 索引

发布包就是插件文件夹

发布包是一个 zip,内容就是插件文件夹:

代码
hello-stellaris-v0.2.0.zip
  stl-plugin.json
  hello_stellaris.dll
  defaults\hello_stellaris.ini
  data\…                  (如有)
  • 清单可以在 zip 根目录,也可以在其下一层的文件夹里;启动器解压后先找根目录,再找一层子文件夹。
  • 必须包含清单和 dll 指向的文件。
  • 不得包含 config\、logs\(它们属于用户),也不能有任何要放进游戏目录的文件。
  • 清单里的 version 要与发布版本一致。

玩家可以用三种方式安装:启动器自动更新或从索引安装(推荐);下载解压后在插件页「安装」那个文件夹;或直接解压到 Documents\Paradox Interactive\Stellaris\plugins\<id>\。

用脚本打包:stellaris-mcp 的做法

stellaris-mcp 的 scripts/make_plugin.py 把构建产物组装成插件文件夹,并可选地生成 zip 和校验文件:

PowerShell
python scripts/make_plugin.py --version v0.6.1 --zip build/stellaris-mcp-v0.6.1.zip

它做了几件值得照搬的事:

  1. --version 接受发布标签 vX.Y.Z,写进清单时去掉 v,并检查是否符合 X.Y.Z 格式;
  2. 检查清单的 exe_timestamps 是否包含 SDK 生成时对应的 exe 构建,不包含就拒绝打包;
  3. zip 里的文件放在根目录;
  4. 在 zip 旁边写出 <zip 文件名>.sha256,内容是 <十六进制摘要> <文件名>。

GitHub Release 与自动更新

清单里写了 update 的插件,启动器可以从 GitHub 自动更新:

JSON
"update": { "github": "Yidhar/stellaris-mcp", "asset": "stellaris-mcp-*.zip" }

按启动器 updates.rs 的实现:

  1. 通过 GitHub API 读取仓库的最新正式发布(/releases/latest,所以预发布和草稿不会被当作更新);
  2. 标签去掉开头的 v 作为版本号,比已安装的 version 新时才提供更新;
  3. 在附件里找名字匹配 update.asset(默认 *.zip)的 zip;
  4. 如果附件里还有 <zip 文件名>.sha256,下载后计算 SHA-256,取校验文件里第一个空白分隔的字段比对,不一致就拒绝安装;
  5. 解压,确认包里清单的 id 与已安装的一致,然后原子安装:新版本先在 plugins\.<id>.new\ 准备好,复制进旧的 config\ 与 logs\,再改名替换。游戏运行中 DLL 被占用时,替换失败,已安装的版本和设置原封不动。

命令行是 stl plugin update [<id>] [--check]。链接的开发中插件不会被更新。

版本比较规则

  • 去掉开头的 v,按点分隔逐段比较数字:0.10.0 比 0.9.2 新,1.0 比 0.9 新;
  • 缺的段按 0 处理:0.2.1 比 0.2 新;
  • - 或 + 之后的部分被忽略:0.2.0-rc1 与 0.2.0 视为相同,不会被当作更新。要发预览版,请在 GitHub 上标为预发布。

插件索引 plugins.jsonl

除了逐个仓库检查更新,启动器还能读取插件索引来浏览和安装插件。索引是一个 plugins.jsonl 文件,每行一个 JSON 对象,描述一个插件。官方默认索引是:

代码
https://raw.githubusercontent.com/Yidhar/stellaris-plugins/main/plugins.jsonl

其中一行(stellaris-live2d):

JSON
{"id":"stellaris-live2d","name":"Live2D portraits","author":"Yidhar","description":"Draws Live2D models into Stellaris' portraits (portrait mods declare them).","version":"0.2.0","download":"https://github.com/Yidhar/stellaris-live2d/releases/download/v0.2.0/stellaris-live2d-v0.2.0.zip","sha256":"a32e9817ac9ffa101a4d207bc7e4b009fc653390c259d4c6ef8182ee86dddc50","repository":"https://github.com/Yidhar/stellaris-live2d","game_builds":["0x6ABEAA3F"],"game_version":"4.5.2","tags":["portraits","live2d","ui"],"license":"MIT","updated":"2026-10-06"}
字段必填说明
id、name、author、description、version是插件信息;id 必须与 zip 内清单的 id 相同
download是zip 的下载地址,必须以 https:// 开头
sha256是zip 文件的 SHA-256,十六进制写法,长度必须是 64
repository是源码仓库地址
game_builds否适配的 exe 构建时间戳,如 "0x6ABEAA3F";为空表示插件自己检查
game_version否这些构建对应的游戏版本号,用于提示
tags、homepage、license、updated否展示信息;homepage 只有以 https:// 开头时才会被用作链接,否则链接到 repository

不满足必填要求的行会被跳过并计数;一个文件里一行有效的都没有时,整个地址会被判定为“不是插件索引”。

启动器如何使用索引

PowerShell
stl plugin index                                  # 列出正在读取的索引
stl plugin index --add https://example.com/plugins.jsonl
stl plugin index --remove https://example.com/plugins.jsonl
stl plugin index --reset                          # 恢复为默认索引
stl plugin search live2d                          # 在所有索引里搜索
stl plugin get stellaris-live2d                   # 下载、校验并安装
  • --add 只接受 https:// 地址,并会先实际读取一次验证。
  • 多个索引按顺序读取,同一个 id 出现在多个索引里时,以第一个索引为准。
  • get 安装时:下载 zip → 计算 SHA-256 并与索引中的值比对(不区分大小写),不一致就拒绝 → 解压找到清单 → 确认清单 id 与索引一致 → 若该插件是链接的开发版则拒绝 → 按普通安装流程原子安装,保留用户的 config\。
  • 索引里的 game_builds 与当前游戏不符时,get 只会提示“为其他游戏版本制作”;真正决定是否加载的,仍是启动时对清单 exe_timestamps 的检查。

两个 SHA-256,别弄混

在哪里算的是什么谁检查
索引行的 sha256发布 zipstl plugin get 安装时
Release 附件 <zip>.sha256发布 zip自动更新时(有才检查)
stl plugin info <id> 显示的 SHA-256已安装的 DLL不做校验,供人工核对

登记到官方索引

官方索引仓库 Yidhar/stellaris-plugins 不存放任何二进制文件,plugins.jsonl 由 GitHub Actions 每小时自动生成:取每个登记仓库的最新 Release,下载 zip、读出其中的 stl-plugin.json、算出 SHA-256。作者只需登记一次:

  1. 在自己的公开 GitHub 仓库发一个 Release,附上插件 zip;
  2. 在索引仓库的 sources.jsonl 里加一行并提 Pull Request:
JSON
{"repository":"https://github.com/你的用户名/仓库名","tags":["标签1","标签2"]}

Release 里有多个 zip 时加 "asset":"名字-v*.zip";作者名默认是仓库所有者,可用 "author" 修改。

  1. CI 检查你的最新 Release(zip、清单、DLL),合并后一小时内出现在索引里。

此后发新版本只要在自己仓库发 Release,索引会自动跟上;新 Release 无法使用时(例如 zip 里没有清单),索引保留上一个可用版本。可以先用 python scripts/plugin_entry.py <用户名/仓库名> 预览索引会怎么写你的插件。游戏更新后,索引仓库的 games.json 记录新的 exe 时间戳对应的游戏版本号。

索引仓库的规则:源码公开且 DLL 由该源码构建,zip 只能来自 repository 所写仓库的 Release;插件只在启动器加载时运行,不改游戏文件;不收集个人信息、不上传数据(确需联网的在简介里写明用途);一个仓库一个插件 id;plugins.jsonl 不要手改。

关于本站

本站的插件发布与索引订阅(/api/v1/plugins.jsonl 订阅源,以及 stl:// 一键订阅链接)目前尚未实现:后端只有一个用演示数据生成 plugins.jsonl 的原型接口,启动器也还不处理 stl:// 链接。现阶段请使用 GitHub Release + 官方索引的流程。

提示 发布前对照启动器手册的“发布前检查清单”过一遍:标签等于 v + version、附件名匹配 update.asset、附带 .sha256、是正式发布而非预发布,并实测一次“从上一版本自动更新后设置仍保留”。