Files
metin-launcher/src/Metin2Launcher/Formats/IReleaseFormat.cs
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

53 lines
2.3 KiB
C#

using Metin2Launcher.Manifest;
namespace Metin2Launcher.Formats;
/// <summary>
/// Strategy that knows how to interpret the <c>files</c> array of a
/// signature-verified manifest. Added for the m2pack migration:
///
/// - <c>legacy-json-blob</c> ships individual files that replace their
/// counterparts inside the client root one-for-one.
/// - <c>m2pack</c> ships <c>.m2p</c> pack archives and a <c>runtime-key.json</c>
/// sidecar. The archives are placed next to the client root and the
/// runtime key is forwarded to the game process via env vars — the
/// launcher NEVER opens, decrypts or decompresses an <c>.m2p</c> archive.
///
/// Both implementations share the same download/apply plumbing in
/// <see cref="Orchestration.UpdateOrchestrator"/>. This interface only
/// captures the pieces that actually differ between the two formats.
/// </summary>
public interface IReleaseFormat
{
/// <summary>Identifier matching <see cref="Manifest.EffectiveFormat"/>.</summary>
string Name { get; }
/// <summary>
/// Filters the manifest file list down to entries that should be
/// downloaded on the given platform. Both formats currently delegate
/// to <see cref="ManifestFile.AppliesTo(string)"/>; the indirection
/// exists so a future format can special-case (e.g. exclude the
/// runtime key from platform filtering, or reject unknown kinds).
/// </summary>
IReadOnlyList<ManifestFile> FilterApplicable(Manifest.Manifest manifest, string platform);
/// <summary>
/// Runs after the apply phase succeeds. The legacy format is a no-op;
/// the m2pack format loads the runtime key from the client root and
/// stores it on <paramref name="outcome"/> so the caller can forward it
/// to the game process.
/// </summary>
void OnApplied(string clientRoot, LoadedManifest manifest, ReleaseOutcome outcome);
}
/// <summary>
/// Mutable bag of results emitted by <see cref="IReleaseFormat.OnApplied"/>.
/// Kept separate from the update orchestrator's own <c>Result</c> record so
/// format-specific data doesn't leak into the generic update flow.
/// </summary>
public sealed class ReleaseOutcome
{
/// <summary>Populated by the m2pack format; null for legacy releases.</summary>
public Runtime.RuntimeKey? RuntimeKey { get; set; }
}