schemas

Stoker schemas

JSON Schemas for the formats Stoker shares between hosts, published at https://schemas.stokerhq.app/.

Metadata — v1

JSON Schemas (draft 2020-12) for the Stoker metadata repository: a public git repository that any Stoker host reads to find games, their store pages, achievements, how their builds are laid out and started, and the fixes, mods and quirks they need to run under Stoker.

metadata/
  v1/                          the schemas, served as https://schemas.stokerhq.app/metadata/v1/<file>
  examples/                    a small, fictional metadata repository that validates
validate.py                    checks a metadata repository against them

Layout of a metadata repository

games/
  <game id>/
    game.json                  identity, external ids, store page, tags, cloud saves, settings, plugins, fixes
    media.json                 artwork and the media reel (images inlined)
    achievements.json          achievement definitions, each with the other names it is granted under
    stats.json                 stat definitions
    leaderboards.json          leaderboard definitions
    dlc/
      <dlc id>.json            one DLC: external ids, store page, artwork, the other DLC it needs
    releases/
      <release id>.json        one version, its fixes, and every known build of it with the build's own fixes
Document Schema
game.json metadata/v1/game.schema.json
media.json metadata/v1/media.schema.json
achievements.json metadata/v1/achievements.schema.json
stats.json metadata/v1/stats.schema.json
leaderboards.json metadata/v1/leaderboards.schema.json
dlc/*.json metadata/v1/dlc.schema.json
releases/*.json metadata/v1/release.schema.json

metadata/v1/common.schema.json holds the types the others share. Only game.json is required.

DLC are not games. A DLC has no releases, nothing to start and no achievements of its own (the stores keep those in its game’s list); it is what a store sells — a name, ids, a page, artwork — and lives in its game’s folder. Whether a build carries it, and with which files, is that build’s dlc fix, which names it by dlcId.

Rules the format is built on

How a copy finds its fixes

A Stoker instance holds a copy of a game from some store, or from somebody’s disk. To make it run:

  1. Match it to a build. First by its sources — a store’s ids for those files; for Steam the depot manifests, never the build id alone, which every depot of a branch shares — then by the fingerprint of all its files (content), then by markers: a few files nothing writes to, such as the executables, which still match when configs, saves or a hand-applied patch changed the rest. A copy that matches nothing still gets its game’s fixes.
  2. Collect the fixes, in order: the build’s own (setup, languagePack, dlc, unpacked, and patches only this copy needs), then the release’s, then the game’s — leaving out those a release or build lists in disableFixes, the optional ones nobody chose, and the answers to a selectionGroup nobody picked.
  3. Apply each fix whose when holds, checked against the files as they are at that point, and skip one whose appliedWhen already holds. A fix’s steps — files, delete, rename, iniSet, hexEdit, binaryPatch, unpack, registry, firewall, run — change the install once; environment, arguments and windowsCompatibility apply every time the game starts, for every launch or for the one whose key they name.

unpack runs an unpacker plugin over the instance’s own copy and keeps the result only when it hashes as recorded; it appears only in a build’s unpacked fix, which comes first, so a game’s fix written against the unpacked executable finds it unpacked.

Values the installing machine fills in — registry values, iniSet values, run and arguments arguments, environment values — may hold %INSTALLDIR%, the install’s root in the machine’s own form; %% is a literal %, and any other % is refused.

Trust

Hosts apply what this repository says to their players’ machines, so what a fix may do is limited by the schema, not by review alone:

A step read from the publisher’s own install script (source) is exempt from the first two, because the publisher’s installer would have done the same. Code a fix needs goes into the install as files, named by hash.

Only the maintainer pushes to this repository. Signed releases, which a host could verify instead of trusting the place it cloned from, come with the plugin catalogue — plugins and hooks are code that runs inside games.

Because when names files by hash, a fix written once on the game serves every copy that has those bytes, whichever store it came from.

Versions

Every document carries schemaVersion, "<major>.<minor>". The schemas under metadata/v1/ are always the newest minor of major 1, and a minor version only adds: fields, enum values, kinds. It never changes what an existing field means or makes an optional one required, so every document that was valid stays valid.

A reader:

The schemas themselves stay strict (additionalProperties: false), so this repository’s checks catch a misspelt field; it is readers that are lenient, not the schemas.

Checks beyond the schemas

validate.py runs every document against its schema, then checks what a schema cannot see:

python -I validate.py <metadata repository root>
python -I validate.py metadata/examples

Needs jsonschema[format-nongpl] 4.18 or newer. Without the format-nongpl extra jsonschema passes every URI unchecked, so the validator refuses to run without it.

Not decided yet