Commit Graph

28 Commits

Author SHA1 Message Date
Jan Nedbal
9ffae5c7d9 Merge branch 'claude/m2pack-launcher'
Add m2pack-secure release format support to the launcher without
removing the legacy JSON-blob path. Manifests now carry an optional
'format' field; a ReleaseFormatFactory dispatches to either
LegacyJsonBlobFormat (default, unchanged behaviour) or M2PackFormat
(new, treats .m2p files as opaque content-addressed blobs and loads
a runtime-key.json sidecar to hand off to the game via env vars).
Unknown formats fail closed.

Adds RuntimeKey model + EnvVarKeyDelivery (cross-platform) + a stub
SharedMemoryKeyDelivery for the future Windows path, an opt-in
ClientAppliedReporter for Morion2 telemetry with 5s timeout and
graceful fallback, plus 60 new tests (total 92) covering every branch.
2026-04-14 21:18:12 +02:00
Jan Nedbal
1790502b58 docs: document m2pack launcher integration
adds docs/m2pack-integration.md covering the signature boundary,
runtime key env-var delivery, telemetry opt-in, backward compatibility
and expected on-disk layout. README gains a short "Release formats"
section pointing at the new doc, and CHANGELOG tracks the [Unreleased]
entries.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-14 21:12:08 +02:00
Jan Nedbal
0e95171e50 test: cover runtime key, release formats and telemetry
adds ~60 new tests across RuntimeKey parsing, EnvVarKeyDelivery, the
legacy and m2pack formats, ReleaseFormatFactory dispatch, manifest
loader tolerance of unknown top-level fields, orchestrator wiring and
the ClientAppliedReporter (disabled-by-default, success, 5xx, timeout,
connection refused). The telemetry tests spin up an in-process
HttpListener helper — no new NuGet dependency.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-14 21:10:48 +02:00
Jan Nedbal
6ad8e8db19 orchestration: dispatch through release format factory
UpdateOrchestrator now resolves an IReleaseFormat from the verified
manifest and uses it to filter applicable files, run the post-apply
hook (which loads the m2pack runtime key when present) and drive the
opt-in client-applied telemetry ping. GameProcess.BuildStartInfo
accepts a RuntimeKey? and forwards it through EnvVarKeyDelivery onto
the child ProcessStartInfo, scoped to the child environment only.
Program.cs wires the reporter and threads the key from the update
result into the game launch.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-14 21:05:57 +02:00
Jan Nedbal
3d98ac4470 telemetry: add opt-in client-applied reporter
adds ClientAppliedReporter that fires a single bounded (5s) best-effort
POST after a successful update, carrying only release format and
version. the launcher config exposes TelemetryUrlTemplate defaulted to
empty string — when empty the reporter short-circuits and nothing goes
over the network.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-14 21:05:49 +02:00
Jan Nedbal
ee7edfd990 formats: add release format strategy interface and implementations
adds IReleaseFormat with a legacy-json-blob implementation lifting the
existing per-file update behaviour, and an m2pack implementation that
loads runtime-key.json after apply. a central ReleaseFormatFactory
maps Manifest.EffectiveFormat onto concrete strategies and throws on
unknown values so a signed but unsupported format cannot silently
downgrade.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-14 21:05:43 +02:00
Jan Nedbal
dcc2b0fc42 runtime: add runtime-key model and delivery strategies
adds RuntimeKey DTO parsed from runtime-key.json, an IRuntimeKeyDelivery
strategy interface, and the env-var delivery used by the m2pack MVP
(M2PACK_MASTER_KEY_HEX / M2PACK_SIGN_PUBKEY_HEX / M2PACK_KEY_ID).
SharedMemoryKeyDelivery is a documented stub — will be wired once the
client-side receiver lands.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-14 21:05:37 +02:00
Jan Nedbal
5edd0c5aea manifest: add optional format field for release dispatch
introduces an optional top-level "format" field on the signed manifest,
defaulting to legacy-json-blob when absent so existing installs keep
parsing unchanged. follow-up commits wire the release format factory
and the m2pack strategy against this value.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-14 21:05:30 +02:00
Jan Nedbal
3d3129032a launcher: switch main window to dark theme with gradient banner
Replace the flat light theme with a dark palette built for a fantasy MMO
feel. Banner uses a crimson linear gradient and wider letter-spacing on
the title, the body is #0F0F12 with a #17171B left column, the Play
button is a red gradient with hover state and a disabled rust tone.
Status foreground defaults to white and turns a soft red only on
signature failure. The news panel gains an empty-state placeholder with
a diamond glyph so a missing manifest doesn't look like a bug.

Localization strings for the empty state switch from 'Žádné novinky.' to
'Zatím žádné novinky' / 'No news yet' to read more like a UI state than
an error. The view model exposes IsNewsEmpty / IsNewsPresent so the
XAML can toggle between the placeholder and the real news body without
touching the flush timer.
2026-04-14 20:59:06 +02:00
root
0526ac2ef9 docs: add metin release cli plan 2026-04-14 18:30:43 +02:00
Jan Nedbal
3f8acfc597 launcher: document publish-launcher.sh in readme 2026-04-14 13:57:22 +02:00
Jan Nedbal
d9d45d0010 launcher: add velopack publish script 2026-04-14 13:57:22 +02:00
Jan Nedbal
ad78f8f139 Merge branch 'avalonia-gui'
Add Avalonia GUI to the launcher with a proper windowed flow, progress bar,
news panel, settings dialog, Czech/English localization, and a refactored
UpdateOrchestrator with progress events. Keeps the headless --nogui path
working. Fixes the Linux-native game launch path to spawn wine explicitly so
the child inherits WINEPREFIX.
2026-04-14 13:26:27 +02:00
Jan Nedbal
2471e973c2 launcher: run velopack self-update from gui flow
The extracted orchestrator and the new GUI view model didn't call
Velopack's self-update path, leaving that behaviour only in the headless
--nogui branch. Wire the same TrySelfUpdateAsync helper into the GUI
orchestration so the launcher keeps itself current regardless of which
mode the user runs.
2026-04-14 13:25:50 +02:00
Jan Nedbal
3ceab286f5 launcher: wire avalonia gui as default entry, keep --nogui headless mode
Program.Main now starts the Avalonia desktop lifetime by default and
falls back to a headless orchestrator run that logs progress and launches
the game when --nogui is passed. README documents both modes and the new
launcher-settings.json store.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-14 13:15:49 +02:00
Jan Nedbal
e28b243100 launcher: scaffold avalonia main window, view models, and settings dialog
Adds the Avalonia App, MainWindow (900x560 fixed, dark-red banner, left
status/progress column, right news panel) and a modal SettingsDialog with
language + dev-mode override. MainWindowViewModel binds to the orchestrator
through IProgress, throttles UI updates to ~10 Hz via a DispatcherTimer
flush, drives state-specific status text and Play-button gating, fetches
previous-manifest notes best-effort, and forces a red status banner with
Play disabled on a SignatureFailed result.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-14 13:15:44 +02:00
Jan Nedbal
d4b9f56cb3 launcher: extract update orchestrator with progress events
Lifts the manifest fetch / verify / diff / download / apply pipeline out
of Program.cs into a reusable UpdateOrchestrator that emits typed
LauncherState progress events through IProgress<UpdateProgress>. The
existing logic, error handling, and signature-failure semantics are
preserved verbatim; the orchestrator just drives a sink instead of the
console so the GUI and the headless --nogui path can share one pipeline.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-14 13:15:33 +02:00
Jan Nedbal
1e6ab386cb launcher: add avalonia packages, settings, locale, and progress hook
Adds Avalonia 11 + CommunityToolkit.Mvvm package references (no UI code
yet), a flat-key Loc resource loader with embedded cs.json/en.json, the
LauncherSettings JSON store with dev-mode-gated manifest URL override,
and an optional IProgress<long> bytesProgress hook on BlobDownloader so
the upcoming GUI can drive a progress bar from per-blob byte counts.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-14 13:15:07 +02:00
Jan Nedbal
a134e7548f launcher: swap placeholder key for real production public key
Replace the MVP placeholder Ed25519 public key with the real one that
corresponds to ~/.config/metin/launcher-signing-key on the release
machine. Update README to document where the private half lives and
how rotation works. Private key is not committed anywhere; the only
code path that touches it is scripts/sign-manifest.py in m2dev-client.
2026-04-14 11:21:07 +02:00
Jan Nedbal
cc904fb881 launcher: reject manifest paths that escape the client root
Defence-in-depth against a buggy or crafted manifest that points
outside the client directory. Path resolution is centralised in
PathSafety.ResolveInside so the orchestration code cannot forget the
check; the applier still sees already-validated absolute paths.
Rejected cases: parent traversal, mixed traversal, absolute paths,
sibling-root lexical escapes. Required files that fail the check
abort the update; optional files are skipped and logged.
2026-04-14 11:17:12 +02:00
Jan Nedbal
99bdf855a0 launcher: refuse to launch on invalid manifest signature
The previous flow threw InvalidOperationException on signature
failure, which was caught by the outer catch(Exception) and silently
fell through to the offline launch branch — the exact bypass the
design doc forbids ('server is lying' is more dangerous than 'server
is down'). Introduce ManifestSignatureException and handle it in a
dedicated catch above the generic fallback, exiting with code 2
without launching the game.
2026-04-14 11:17:12 +02:00
Jan Nedbal
e1268e7cce launcher: document build, run, and placeholder key in readme 2026-04-14 11:13:03 +02:00
Jan Nedbal
8e288fd18e launcher: orchestrate update flow and wire velopack self-update 2026-04-14 11:12:57 +02:00
Jan Nedbal
ae33470f7f launcher: add atomic staging-to-final applier 2026-04-14 11:12:41 +02:00
Jan Nedbal
80e1450df9 launcher: add streaming hasher and range-resume blob downloader 2026-04-14 11:12:35 +02:00
Jan Nedbal
18271a71db launcher: add manifest loader and ed25519 verification 2026-04-14 11:12:30 +02:00
Jan Nedbal
9f3ad79320 launcher: scaffold csproj and solution 2026-04-14 11:12:04 +02:00
82e472f5bc Initial commit 2026-04-14 11:02:30 +02:00