ゲームイベント SDK · プロトコル v1

ゲームイベントを Hovermate に送信

ゲームや MOD は、キル、ボス撃破、ラップ、ゴール、独自の出来事を通知できます。Hovermate は内蔵のゲームカードと同じように、タイムラインマーカーとハイライトクリップを自動作成します。

C#、C++、Java、Python、JavaScript、Lua のクライアント · 各 1 ファイル、依存関係なし · MIT ライセンス

仕組み

  1. MOD が出来事を通知します。event("bossKill") などの呼び出し 1 回で送信できます。クライアントはバックグラウンドで動作し、ゲームをブロックしません。
  2. Hovermate がマーカーを付けます。指定したラベル付きで、録画とセッションのタイムラインにイベントが表示されます。
  3. プレイヤーがハイライトを選びます。「クリップ」にゲーム専用カードが作られます。有効にした種類のイベントはクリップとしても保存されます。

SDK が有効な間、Hovermate はアドレス、トークン、受信フォルダーを connection.json に書き込みます。

connection.json
{
  "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 はこのファイルから読み取り、書かれているとおりに使ってください。ホスト、ポート、パスをコードに埋め込んだり変更したりしないでください。

クライアントは %LOCALAPPDATA%\Hovermate\Sdk\connection.json を読みます。テストや分離した環境では HOVERMATE_SDK_CONNECTION のパスを使用できます。SDK のオフ・オンでトークンが変わるため、401 の後は再読込します。ファイルがなければ Hovermate が未インストールか SDK が無効なので、何も送信しません。

イベントを送る 3 つの方法

MOD の環境で利用できる最初の方法を選んでください。

HTTP

MOD がローカルのネットワーク接続を開ける場合。

Authorization: Bearer <token> を付けて URL にイベントを POST します。Origin ヘッダーのあるリクエストは拒否されるため、ウェブページからは送信できません。

C#、C++、Java、Python、JavaScript に対応。GDScript では HTTPRequest を使用できます。

ファイル

MOD がファイルを書き込めるものの、ネットワークを利用できない場合。

{inbox}\<game.id>.jsonl に 1 行 1 件の JSON イベントを追記します。トークンは不要です。Cyber Engine Tweaks のように MOD フォルダーのみ書込み可能な環境では、その中の hovermate-events.jsonl に記録し、プレイヤーがゲームカードにファイルを追加します。

各クライアントは受信フォルダーへフォールバックします。Lua クライアントは MOD フォルダーに書き込みます。

ログ行

スクリプトがゲームのログにしか出力できない場合。

[HOVERMATE] に続けて JSON イベントオブジェクトを出力します。マーカーより前は無視されます。The Witcher 3 の scriptslog.txt、Skyrim と Fallout 4 の Papyrus.0.log はゲーム実行中に自動で読み込まれます。

Witcher 3 のスクリプト、Papyrus、またはスクリプトログのあるゲーム。

HTTP リクエスト

POST /hovermate/v1/events HTTP/1.1
Host: local.hovermate.gg
Authorization: Bearer <token from connection.json>
Content-Type: application/json
Content-Length: 95

{"v":1,"game":{"id":"com.example.mygame","name":"My Game"},"type":"kill","label":"Double kill"}

応答:202 {"accepted":1}。

ログ行の例

ゲームログ内の 1 行
[12:00:01] [Script] [HOVERMATE] {"v":1,"game":{"id":"com.example.mygame","name":"My Game"},"type":"bossKill","context":"Act 2"}

他のログは「クリップ」› ゲームカード › ファイルからイベントを読むで追加します。hello から提案することもできます。

クイックスタート

各サンプルは hello、kill、bossKill と独自の parry イベントを送ります。SDK の examples フォルダーにある実行可能なファイルを掲載しています。

C#

クライアント
HovermateEvents.cs
実行環境
netstandard2.0、.NET Framework 4.7.2+、.NET、C# 7.3:Unity、BepInEx、MelonLoader。
セットアップ
MOD プロジェクトに HovermateEvents.cs を追加します。
csharp/Program.cs
// Sends hello, kill, bossKill and a custom "parry" event to Hovermate (or to tools/mock-server.py).
// Run: dotnet run
using System;
using Hovermate.Sdk;

HovermateEvents.Log = Console.WriteLine;
HovermateEvents.Init("com.example.sdkdemo", "SDK Demo", "SdkDemo.exe");
HovermateEvents.Hello(new HovermateOffer[] { "kill", "bossKill", HovermateOffer.Custom("parry", "Parry") });
HovermateEvents.Event("kill", label: "Double kill", tags: new[] { "headshot" }, context: "Act 2");
HovermateEvents.Event("bossKill", label: "The Warden", context: "Act 2");
HovermateEvents.Custom("parry", "Parry", label: "Perfect parry");
Console.WriteLine(HovermateEvents.Flush(2000) ? "sent" : "timed out");
HovermateEvents.Shutdown();

examples/csharp で実行します(サンプルは .NET 8 以降が対象)。

dotnet run

C++

クライアント
hovermate_events.h
実行環境
Windows 上の C++17。ヘッダーのみで、WinHTTP を使い winhttp.lib をリンクします。
セットアップ
hovermate_events.h をインクルードします。DLL のアンロード前に hovermate::shutdown() を呼び出してください。DllMain 内では呼び出さないでください。
cpp/example.cpp
// Sends hello, kill, bossKill and a custom "parry" event to Hovermate (or to tools/mock-server.py).
// Build (Developer Command Prompt): cl /std:c++17 /EHsc /utf-8 /I..\..\cpp example.cpp
#include <cstdio>
#include "hovermate_events.h"

int main() {
    hovermate::set_log([](const std::string& message) { std::printf("%s\n", message.c_str()); });
    hovermate::init("com.example.sdkdemo", "SDK Demo", "SdkDemo.exe");
    hovermate::hello({ "kill", "bossKill", hovermate::Offer::custom("parry", "Parry") });
    hovermate::event("kill", { "Double kill", { "headshot" }, "Act 2" });
    hovermate::event("bossKill", { "The Warden", {}, "Act 2" });
    hovermate::custom("parry", "Parry", { "Perfect parry", {}, {} });
    std::printf("%s\n", hovermate::flush(2000) ? "sent" : "timed out");
    hovermate::shutdown();
    return 0;
}

開発者コマンドプロンプトで examples/cpp から実行します。

cl /std:c++17 /EHsc /utf-8 /I..\..\cpp example.cpp

Java

クライアント
HovermateEvents.java
実行環境
Java 8 以降:ModTheSpire、Forge、Fabric。
セットアップ
HovermateEvents.java を MOD にコピーし、パッケージを変更するか shading 時に再配置して、他の MOD 内のコピーとの衝突を防ぎます。
java/Example.java
// Sends hello, kill, bossKill and a custom "parry" event to Hovermate (or to tools/mock-server.py).
// Run (Java 8+): javac -d out ../../java/HovermateEvents.java Example.java && java -cp out Example
import gg.hovermate.sdk.HovermateEvents;
import gg.hovermate.sdk.HovermateEvents.Offer;
import java.util.Arrays;

public class Example {
    public static void main(String[] args) {
        HovermateEvents.log = System.out::println;
        HovermateEvents.init("com.example.sdkdemo", "SDK Demo", "SdkDemo.exe");
        HovermateEvents.hello(Offer.of("kill"), Offer.of("bossKill"), Offer.custom("parry", "Parry"));
        HovermateEvents.event("kill", "Double kill", Arrays.asList("headshot"), "Act 2");
        HovermateEvents.event("bossKill", "The Warden", null, "Act 2");
        HovermateEvents.custom("parry", "Parry", "Perfect parry", null, null);
        System.out.println(HovermateEvents.flush(2000) ? "sent" : "timed out");
        HovermateEvents.shutdown(1000);
    }
}

examples/java で実行します。

javac -d out ../../java/HovermateEvents.java Example.java && java -cp out Example

Python

クライアント
hovermate_events.py
実行環境
Python 3.7 以降。標準ライブラリのみを使用します。
セットアップ
スクリプトと同じ場所に hovermate_events.py を置きます。
python/example.py
"""Sends hello, kill, bossKill and a custom "parry" event to Hovermate (or to tools/mock-server.py).

Run from any folder: python example.py
"""
import os
import sys

sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', '..', 'python'))
import hovermate_events as hovermate  # noqa: E402

hovermate.set_log(print)
hovermate.init('com.example.sdkdemo', 'SDK Demo', 'SdkDemo.exe')
hovermate.hello(['kill', 'bossKill', hovermate.custom_offer('parry', 'Parry')])
hovermate.event('kill', label='Double kill', tags=['headshot'], context='Act 2')
hovermate.event('bossKill', label='The Warden', context='Act 2')
hovermate.custom('parry', 'Parry', label='Perfect parry')
print('sent' if hovermate.flush(2.0) else 'timed out')
hovermate.shutdown()

examples/python で実行します。

python example.py

JavaScript

クライアント
hovermate-events.mjs
実行環境
Node.js 18 以降。ES モジュールとして使用します。
セットアップ
hovermate-events.mjs をインポートします。
js/example.mjs
// Sends hello, kill, bossKill and a custom "parry" event to Hovermate (or to tools/mock-server.py).
// Run with Node.js 18+: node example.mjs
import * as hovermate from '../../js/hovermate-events.mjs';

hovermate.setLog(console.log);
hovermate.init('com.example.sdkdemo', 'SDK Demo', 'SdkDemo.exe');
hovermate.hello(['kill', 'bossKill', hovermate.customOffer('parry', 'Parry')]);
hovermate.event('kill', { label: 'Double kill', tags: ['headshot'], context: 'Act 2' });
hovermate.event('bossKill', { label: 'The Warden', context: 'Act 2' });
hovermate.custom('parry', 'Parry', { label: 'Perfect parry' });
console.log((await hovermate.flush(2000)) ? 'sent' : 'timed out');
await hovermate.shutdown();

examples/js で実行します。

node example.mjs

Lua

クライアント
hovermate_events.lua
実行環境
Lua 5.1+、LuaJIT:Cyber Engine Tweaks などネットワークのないサンドボックス。
セットアップ
init.lua の隣に hovermate_events.lua を置きます。イベントは MOD フォルダーの hovermate-events.jsonl に出力されます。このファイルを Hovermate に追加するようプレイヤーに案内してください。
lua/example.lua
-- Sends hello, kill, bossKill and a custom "parry" event to Hovermate (or to tools/mock-server.py --watch).
-- Run from the folder that stands in for your mod folder: lua path/to/example.lua
-- It writes hovermate-events.jsonl into the current folder.
--
-- In a Cyber Engine Tweaks mod, copy hovermate_events.lua next to init.lua and call it from your events:
--   local hovermate = require("hovermate_events")
--   registerForEvent("onInit", function()
--     hovermate.init("com.example.mymod", "My Mod", "Cyberpunk2077.exe", { log = print })
--     hovermate.hello({ "kill", "bossKill", hovermate.customOffer("parry", "Parry") })
--   end)
-- Then tell your users to add <game>\bin\x64\plugins\cyber_engine_tweaks\mods\<your mod>\hovermate-events.jsonl
-- in Hovermate: Clips > the game's card > Read events from a file.

local here = (arg and arg[0] or ''):match('^(.*[\\/])') or './'
package.path = here .. '../../lua/?.lua;' .. package.path
local hovermate = require('hovermate_events')

hovermate.init('com.example.sdkdemo', 'SDK Demo', 'SdkDemo.exe', { log = print, writer = print })
print('transport', hovermate.transport())
hovermate.hello({ 'kill', 'bossKill', hovermate.customOffer('parry', 'Parry') })
hovermate.event('kill', { label = 'Double kill', tags = { 'headshot' }, context = 'Act 2' })
hovermate.event('bossKill', { label = 'The Warden', context = 'Act 2' })
hovermate.custom('parry', 'Parry', { label = 'Perfect parry' })
print('log line for script-only mods:', hovermate.logLine('kill', { label = 'Double kill' }))
hovermate.shutdown()

MOD フォルダーに相当するフォルダーで実行します。

lua example.lua

クライアントの動作

呼び出し動作
init(gameId, gameName, exe?)クライアントを開始します。gameId は [a-z0-9._-]{3,64} に一致し、MOD のバージョン間で変更しません。exe はゲームの実行ファイル名です。
hello(offers, log?, files?)送信可能なイベントの種類と、任意で読み取るログや MOD フォルダーのファイルを通知します。
event(type, {label, tags, context})標準タイプのイベントを送信します。
custom(customType, customLabel, {…})独自タイプを送信します。customLabel がハイライト切り替えの表示名になります。
flush() / shutdown()キュー内のイベントを待ち、MOD のアンロード時にバックグラウンドワーカーを停止します。
  • 呼び出しはすぐに戻り、ゲームへ例外を送出しません。
  • バックグラウンドワーカーがタイムアウト 250 ms で送信し、失敗したリクエストは 1 回だけ再試行します。
  • キューは 256 イベントを保持し、超過時は最も古いものを破棄します。
  • HTTP に接続できない場合、数秒間は受信フォルダーにイベントを送信します。
  • connection.json がない場合は何もせず、5 秒ごとに再確認します。
  • すべてのイベントに game.name が含まれます。文字列は以下の上限で切り詰められ、不正なタグはエラーにせず削除されます。

Lua クライアント(hovermate_events.lua)は各イベントを即座に書き込みます。MOD フォルダーの hovermate-events.jsonl、絶対パスが許可される場合は受信フォルダー、最後に渡された writer 関数(例:print)による [HOVERMATE] 行の順で試します。logLine(type, options) は手動で出力できる行を返します。

イベントオブジェクト

{ "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 名または短い識別子。MOD のバージョン間で固定
game.name最初のイベントセッション最初のイベントまたは hello で必須。最大 64 文字
game.exeいいえファイル名のみ。検出したゲームフォルダーにイベントを関連付け、その実行ファイルによるリプレイバッファの開始を可能にします
typeはい以下の標準タイプ、または custom
customType, customLabelcustom の場合[a-z0-9_.-]{1,32} と最大 40 文字の切り替え名
labelいいえマーカーのツールチップやクリップ名に使うイベントの表示文。最大 80 文字
tagsいいえ最大 8 個。それぞれ [a-z0-9_-]{1,24} に一致するタグ
contextいいえハイライトのタイトルに使うマップ、レベル、エリア。最大 64 文字
timeいいえISO-8601 UTC。Hovermate が受信時刻を記録し、その前後 5 秒以内の time で補正します

長さは UTF-16 コード単位で数えるため、絵文字は 2 です。テキストの制御文字は拒否されます。未知のフィールドは無視し、将来の版はフィールドを追加する方式です。個人情報は送らないでください。ラベルやコンテキストはクリップ名やファイル名に表示される場合があります。

標準タイプ

Hovermate 内蔵のゲームカードと共通の 29 タイプ。リストは追加のみで、未知の標準タイプは拒否されます。

  • kill
  • death
  • assist
  • multikill
  • roundWon
  • roundLost
  • matchWon
  • matchLost
  • mvp
  • goal
  • save
  • objective
  • mission
  • lap
  • bestLap
  • position
  • crash
  • incident
  • penalty
  • pit
  • finish
  • raceWon
  • landing
  • takeoff
  • fightWon
  • levelUp
  • bossKill
  • zone
  • achievement

独自タイプ

標準リストにない出来事に使用します。各タイプに customLabel の名前でハイライト切り替えを作成します。1 ゲームあたり最大 200 タイプです。

{ "v": 1, "game": { "id": "com.example.mygame" },
  "type": "custom", "customType": "parry", "customLabel": "Parry", "label": "Perfect parry" }

hello

任意ですが推奨します。最初の実イベントより前にカードと切り替えを作り、プレイヤーが先に設定できるようにします。

{ "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",
  "files": ["C:\\Games\\MyGame\\mods\\my_mod\\hovermate-events.jsonl"] }
  • offers は標準タイプと { "customType", "customLabel" } オブジェクトを列挙します。
  • log は [HOVERMATE] 行を含むゲームログ、files は MOD フォルダーのイベントファイルを提案します。Hovermate は提案されたパスを読む前にプレイヤーへ確認します。
  • hello はすべての送信方法で使用でき、[HOVERMATE] ログ行にも対応します。

制限と応答

制限値
ゲームごとのイベント数毎秒 20 件。超過すると 429 となり、そのリクエスト全体を拒否します。hello は数えません
バッチ{ "events": [ … ] } に 1~100 イベント。全件受理または全件拒否です。新しいゲームの名前は、バッチ内で最初にそのゲームを参照するイベントで指定します
HTTP 本文64 KB
受信・ファイルの行4 KB。長い行は破棄します
独自タイプ1 ゲームにつき 200
クライアントのタイムアウト最大 250 ms、再試行は最大 1 回。上限付きキューから最古のイベントを削除します
ステータス意味
202受理:{"accepted": n}
400不正:{"error", "detail", "index"}。index はバッチ内の最初の不正イベントを示します
401トークンがない、または不正:connection.json を再読込してください
403リクエストに Origin ヘッダーがあります
413本文が 64 KB を超えています
4291 ゲームで毎秒 20 イベントを超えています
405, 411, 415POST 以外、Content-Length の欠落、または JSON 以外のコンテンツタイプ

エラーコード:invalid_json、version、game、type、custom、label、tags、context、offers、log、files、batch。ファイル内の不正な行はゲームカードの不正イベント数に加算します。Hovermate は内容をそのままログに記録しません。

Hovermate なしでテスト

テスト受信機 mock-server.py(Python 3.8+、標準ライブラリ)は Hovermate と同じ応答を返します。一時フォルダーに専用の connection.json を作成し、同じルールとエラーコードを適用します。受信フォルダーと --watch のファイルを監視し、各イベントとエラーを表示します。

Hovermate と異なり、テスト受信機は数値のループバックポートで待ち受け、そのアドレスを自分の connection.json に書き込みます。テスト用のツールにすぎません。クライアントはファイルにある url をそのまま使います。

python tools/mock-server.py
# In another terminal, with the path it printed:
$env:HOVERMATE_SDK_CONNECTION = "C:\Users\you\AppData\Local\Temp\hovermate-sdk-mock-…\connection.json"
python examples/python/example.py
テスト受信機の出力
Hovermate SDK mock listening on http://127.0.0.1:52777/hovermate/v1/events
[21:15:03.120] http  com.example.sdkdemo hello offers=kill,bossKill,custom:parry
[21:15:03.131] http  com.example.sdkdemo kill "Double kill" tags=headshot context="Act 2"
[21:15:03.140] http  com.example.sdkdemo bossKill "The Warden" context="Act 2"
[21:15:03.148] http  com.example.sdkdemo custom:parry "Parry" "Perfect parry"
  • --watch FILE は MOD フォルダーの hovermate-events.jsonl、または [HOVERMATE] 行のあるゲームログの追記を読み取ります。
  • --follow-proposals はプレイヤーが許可したものとして、hello が提案するパスを読みます。
  • --record FILE は受理・拒否した各イベントを JSON の 1 行として追記し、自動検証に利用できます。

HOVERMATE_SDK_CONNECTION は Hovermate 本体でも同じように使えるため、テストで本番の接続ファイルを変更しません。

適合性テスト

SDK の conformance/cases.json には、正常なイベントから各エラーコードまで、リクエストと Hovermate の期待応答が含まれます。conformance/run.py でテスト受信機や他の受信機へ送れます。Hovermate 自身のテストでも同じファイルを使用します。

python conformance/run.py
# or against a running receiver:
python conformance/run.py --connection path\to\connection.json

プレイヤーからの見え方

  • 新しい game.id の最初の正常なイベントまたは hello で「クリップ」に SDK カードを作成します。ゲーム名、exe がインストール済みゲームに一致する場合のフォルダーとカバー、通知・受信した各タイプの切り替えが表示されます。
  • ハイライトの切り替えは最初はオフです。どのタイプでクリップを保存するかはプレイヤーが選びます。マーカーは常に記録されます。
  • イベントは内蔵カードと同じ経路で処理されます。履歴、クリップとセッションのマーカー、ハイライトウィンドウ、通知が対象です。
  • game.exe が前面のゲームに一致する場合、そのゲームのイベントとして扱います。それ以外は録画中またはリプレイバッファの動作中のみ受理します。
  • 不正なイベント数がカードの状態に表示されるため、プレイヤーが問題を報告できます。

プロトコルとファイル

プロトコル v1 は、接続検出、4 つの配信方法、イベントオブジェクト、hello、Hovermate の動作を規定します。

SDK(クライアント、サンプル、ツール、適合性テスト、プロトコル)は MIT ライセンスのため、MOD にクライアントを同梱できます。Hovermate 本体にはこのライセンスは適用されません。