游戏事件 SDK · 参考

协议 v1

游戏与 Hovermate 之间的约定。本页由 SDK 下载包内的 PROTOCOL.md 生成。

目标:让游戏或模组向 Hovermate 发送事件,像内置游戏卡片一样生成时间轴标记并自动保存精彩时刻。三类传输方式覆盖可联网、仅可写文件和仅可写日志的模组环境。

1. 连接发现

SDK 开启时,Engine 写入 %LOCALAPPDATA%\Hovermate\Sdk\connection.json(设置 › 片段 › 游戏事件 SDK,默认开启):

{
  "version": 1,
  "url": "http://local.hovermate.gg/hovermate/v1/events",
  "token": "<random, base64url, 32 bytes>",
  "inbox": "C:\\Users\\<user>\\AppData\\Local\\Hovermate\\Sdk\\Inbox"
}
  • url 是事件的发送地址。请从此文件读取并按原样使用;切勿在代码中写死或更改主机、端口或路径。Hovermate 目前写入 http://local.hovermate.gg/hovermate/v1/events;SDK 测试服务器会写入自己的测试地址。
  • 客户端在启动时及每次收到 401 后读取该文件。令牌可能轮换。
  • HOVERMATE_SDK_CONNECTION=<path> 可为测试、工具和隔离数据目录覆盖文件位置。客户端必须读取文件中的 inbox 字段获取收件目录,不能自行推导。
  • 文件缺失表示未安装 Hovermate 或 SDK 已关闭。客户端保持静默,不向游戏抛出异常。

2. 传输方式

2.1 HTTP(可联网模组:C#、C++、Java、Python、JS)

  • POST {url};请求头为 Authorization: Bearer <token>、Content-Type: application/json。
  • 携带 Origin 请求头的请求会以 403 拒绝,防止浏览器发送事件。
  • 请求体为单个事件对象,或最多包含 100 个事件的 { "events": [ ... ] }。最大请求体为 64 KB。
  • 批次采用全有或全无原则。Hovermate 先验证全部事件;若有一个无效,则全部不接收,并在 400 响应体中给出位置:{ "error": "<code>", "detail": "...", "index": 3 }。本会话中的新游戏,必须在批次首个提及它的事件中提供 game.name。
  • 响应:
    • 202 已接收;
    • 400 无效,响应体为 { "error": "<code>", "detail": "...", "index": <n, batches only> };
    • 401 令牌错误或缺失;
    • 403 请求包含 Origin 请求头;
    • 413 请求体过大。会先读取并丢弃最多 1 MB,以便客户端收到状态;更大的请求体可能在读取前即被拒绝,并关闭连接;
    • 429 每个游戏每秒超过 20 个事件;
    • 405、411、415 表示方法错误、缺少长度或内容类型错误。
  • 客户端从后台发送,无需等待,不阻塞游戏线程。超时不超过 250 ms,队列有容量限制并丢弃最早事件,最多重试一次。

2.2 JSONL 收件目录(可写文件但不能联网的模组)

  • 向 {inbox}\<game.id>.jsonl 追加 UTF-8 行,每行一个事件对象,不带 BOM。
  • 无需令牌:文件夹属于用户。
  • Engine 启动时从收件目录内每个 *.jsonl 文件的末尾开始监视追加内容。模组可在会话开始时清空自己的文件。

2.3 日志行约定(只能写游戏日志的脚本模组)

  • 一行中包含标记 [HOVERMATE] ,后面紧跟一个 JSON 事件对象。时间戳、频道名等标记前内容均被忽略。
  • SDK 卡片中的“从文件读取事件”列表供用户添加日志路径。通过其他方式收到的 hello 事件(§4)也可提议路径。Engine 使用现有的日志追踪适配器读取文件。
  • 对于脚本日志位置已知的游戏,Hovermate 会在游戏运行时自动监视。列表位于游戏目录数据(sdkLogs)中,例如 Documents\The Witcher 3\scriptslog.txt 以及 Skyrim/Fallout 的 Papyrus 日志。这些模组只需开启游戏脚本日志,无需其他用户设置。

2.4 模组目录事件文件(仅能写入自身目录的沙箱)

  • 一些模组环境只允许写入模组目录,例如 Cyber Engine Tweaks Lua 模组。此类模组向目录中的 hovermate-events.jsonl 追加 JSONL 行(§2.2)。
  • 用户将文件加入 SDK 卡片的“从文件读取事件”列表。模组 README 应说明文件位置。Hovermate 像监视收件文件一样读取其新增内容。
  • 模组也可将自身路径以 [HOVERMATE] 日志行输出一次,或在有其他传输方式时,通过路径数组 hello.files 发送。Hovermate 随后提议添加。

3. 事件对象

{
  "v": 1,
  "game": { "id": "com.example.mygame", "name": "My Game", "exe": "MyGame.exe" },
  "type": "kill",
  "label": "Double kill",
  "tags": ["headshot"],
  "context": "Act 2 · The City",
  "time": "2026-11-09T21:15:03.120Z"
}
  • v — 必填,值为 1。
  • game.id — 必填,符合 [a-z0-9._-]{3,64}。反向 DNS 名称或简短标识符,须在模组版本间保持稳定。
  • game.name — 每个会话的首个事件或 hello 中必填;最多 64 个字符。
  • game.exe — 可选,仅文件名。关联已检测的游戏目录,并允许该可执行文件启动回放缓冲。
  • type — 必填。使用 Docs/CLIPS.md 中共享列表的标准类型:kill, death, assist, multikill, roundWon, roundLost, matchWon, matchLost, mvp, objective, lap, bestLap, position, crash, incident, levelUp, bossKill, zone, achievement, goal, save, mission, fightWon, penalty, pit, finish, raceWon, landing, takeoff;或 "custom"。Docs/CLIPS.md 中的列表为权威定义,只会扩充。未知标准类型以 400 拒绝。
  • customType / customLabel — 当 type 为 "custom" 时必填。customType 符合 [a-z0-9_.-]{1,32};customLabel 最多 40 个字符,是卡片中的开关显示名。
  • label — 可选,事件显示文本,用于标记提示或片段标题,最多 80 个字符。
  • tags — 可选,最多 8 个标签,每个符合 [a-z0-9_-]{1,24}。
  • context — 可选,用于精彩片段标题的地图、关卡或区域,最多 64 个字符。
  • time — 可选,ISO-8601 UTC。Engine 记录接收时刻;与其相差 ±5 秒内的 time 可修正该时刻,其他值忽略。
  • 未知字段会被忽略,因此未来版本仅新增字段。
  • 字符限制按 UTF-16 代码单元计算,与 JavaScript 的 length 和 .NET 的 string.Length 一致。模式须匹配整个值,尾随换行不合法。空字符串或仅空白的字符串视为缺失。
  • 不要发送个人数据。标签和上下文可能出现在片段标题和文件名中。
{ "v": 1, "game": { "id": "com.example.mygame", "name": "My Game", "exe": "MyGame.exe" },
  "type": "hello",
  "offers": ["kill", "death", "bossKill", { "customType": "parry", "customLabel": "Parry" }],
  "log": "%LOCALAPPDATA%\\MyGame\\Saved\\Logs\\MyGame.log" }
  • 允许 Hovermate 在首个真实事件到达前创建游戏卡片与精彩片段开关。
  • offers 列出标准类型和/或自定义类型对象。
  • 可选的 log 提议日志行方式的日志文件;可选的 files 提议模组事件文件(§2.4)。Hovermate 读取任何提议路径之前都会询问用户。
  • hello 可通过所有方式接收,包括 [HOVERMATE] 日志行。

5. Hovermate 行为

  • 新 game.id 的首个有效事件或 hello 创建一张“SDK”游戏卡片。它使用名称、exe;若 exe 匹配已安装游戏,则显示目录和封面;每种声明或收到的类型有独立开关,并提供事件前后时长设置。用户开启类型之前不保存精彩片段,但始终写入标记。
  • 事件经过与内置卡片相同的处理流程:事件记录、片段和会话标记、精彩时刻窗口、通知。
  • 当 game.exe 匹配检测到的前台游戏时,事件归属于该游戏;否则仅在录制或缓冲运行时接收,并标记为 SDK 游戏。
  • 限制:
    • 每个游戏每秒 20 个事件;
    • 每个游戏 200 个自定义类型;
    • 超过 4 KB 的收件行将被丢弃;
    • 错误行会计数,并显示在卡片状态中(“N 个无效事件”),绝不原样记录其内容。