Files
skate-3-rust-engine/docs/updates.md
T

105 lines
6.4 KiB
Markdown

# Player updates
Pause → **Updates** opens a native desktop update window. Select **Stable**
(default) or **Latest** (includes experimental prereleases), then **Check now**.
Release notes appear as plain, scrollable text. **Update** authorizes downloading,
verification, a clean game exit, replacement and restart. **Cancel** closes the
offer, or cancels a download before shutdown. No installation occurs on a check.
Save any gameplay you want to retain before choosing Update.
Startup checks run in a separate process, at most once per six hours per channel.
Offline/rate-limit/check failures are silent at startup and visible in manual
checks. Manual checks bypass the six-hour interval. Switching channels clears the
old offer and performs a fresh check; channel changes are disabled during work.
Switching to Stable never downgrades an already installed experimental build;
it waits for a newer stable build. Cancelled offers are checked again on a later
eligible startup, or through the menu.
The helper replaces only `skate3rust.exe`, `support/skate3setup.exe`,
`support/skate3update.exe`, and `release.json`. Assets, maps, settings, mods,
character libraries and setup's installation marker are never replaced. The same
working directory and arguments are used for restart; existing asset selection
continues to work. Packaged releases are required; developer binaries do not
silently adopt a downloaded build.
# Package protocol and release maintenance
`release.json` accompanies the ZIP and is also inside it. Schema 1 identifies the
repository, `windows-x64` target, tag, full source revision, monotonically increasing
release-workflow run number (`build`), and SHA-256 of all three program files.
The executable embeds its revision and build number; its local metadata and hash
must match before checking. Local builds use build 0 and are not update sources.
Build numbers, not lexical tags, timestamps, GitHub's chosen latest release, or
the workspace's currently fixed Cargo version, determine upgrade ordering. Never
reset/replace the release workflow's run-number sequence without a protocol
migration. Rerunning a build preserves its identity and does not offer an upgrade
to an installation of that build. Publish a new release/run to ship another build.
No downgrades are offered across channels. Equal build IDs are not upgrades.
The updater scans pages of 100 published releases, rejects drafts, filters the
channel, and requires the ZIP, checksum and compatible metadata. It selects the
highest build, using release ID only as a deterministic tie breaker. A scan that
exceeds its page/time bound fails rather than claiming the player is up to date.
Older releases without this metadata are skipped. Existing installations predating
the updater need one manual portable-package upgrade to bootstrap it.
At implementation time the configured repository was private with no releases.
Normal players need publicly accessible releases. For private testing, launch with
`SKATE_UPDATE_GITHUB_TOKEN` set to a token with read access to repository contents.
The updater does not store this credential; it uses authenticated API asset URLs
and strips authorization on redirects. Never place tokens in launch arguments,
tracked scripts or release packages. No repository visibility or release was
changed by this implementation.
The ZIP checksum is mandatory; GitHub's asset digest is also checked when present.
The internal/external manifests and individual executable hashes must agree.
This trusts the project's GitHub release publisher and HTTPS, not a separate
signing key. Archive paths, duplicate names, links and oversized expansion are
rejected. Only fixed program filenames are written; notes and manifest paths are
never executed. No shell is used. The helper runs from a temporary copy so its
installed binary can also be replaced.
# Failure recovery
Downloads stage under `.update-transaction/new` before requesting a successful
Bevy exit, which the crash supervisor treats as normal. Windows replacement is
retried for up to 45 seconds per file; other running game instances can prevent
replacement. An OS lock serializes updater instances in the same installation.
All four previous files are backed up before the durable journal is published.
Replacement failures restore those backups and restart the old program when
rollback succeeds. Do not close the installer during replacement.
If interrupted, the next normal launch detects the journal and exits to a copied
helper, which restores the old program before restarting. Close other game
instances if recovery cannot replace their locked binaries. Backups remain in
`.update-transaction/old`; keep this directory until recovery succeeds. If the
game executable itself is missing or externally damaged, restore those four backup
files manually or unpack the portable release over the program files. User data
does not need extraction again. Recovery cannot guarantee detection of semantic
bugs in a successfully installed new game; backups are retained for manual return.
# Validation
Automated, isolated checks: `python -m unittest discover -s tools -p test_updater.py -v`.
The release workflow runs these before packaging. Rust integration can be checked
with `cargo check -p skate-game --bin skate3rust --no-default-features`.
Player manual checklist (use a disposable copy of a packaged installation):
- Start an older packaged build: a newer eligible release shows notes and Update/Cancel;
playing remains possible while checking. Cancel leaves the executable unchanged.
- Open Pause → Updates, check manually, and switch Stable/Latest. Verify prerelease
filtering, persisted selection after restart, and no stale offer after switching.
- Choose Update, then cancel during download: game stays open and program files
remain unchanged. Check again and finish: progress, clean exit, one restart,
correct version, no crash dialog, no ISO/setup prompt, preserved player data.
- Disconnect networking: startup stays playable without a dialog; manual check
explains the failure. Repeat with a simulated rate-limit response.
- In an isolated fixture, corrupt the ZIP/checksum: failure must precede shutdown.
Hold a target file locked or deny a replacement: verify rollback and retained
backups. Interrupt after the journal is written, then launch again: verify recovery.
GitHub references: [release listing, pagination and latest-release semantics](https://docs.github.com/en/rest/releases/releases),
[asset digests](https://docs.github.com/en/rest/releases/assets).