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

94 lines
2.6 KiB
C#

using System.IO;
using System.Text.Json;
using Metin2Launcher.Logging;
namespace Metin2Launcher.Config;
/// <summary>
/// User-editable settings persisted to .updates/launcher-settings.json.
/// Only honored when DevMode == true for the URL override (defense in depth: a
/// tampered local file alone cannot redirect updates).
/// </summary>
public sealed class LauncherSettings
{
public string Locale { get; set; } = "cs";
public bool DevMode { get; set; } = false;
public string? ManifestUrlOverride { get; set; }
private static readonly JsonSerializerOptions _opts = new()
{
WriteIndented = true,
};
public static LauncherSettings Load(string path)
{
try
{
if (!File.Exists(path))
return new LauncherSettings();
var json = File.ReadAllText(path);
return JsonSerializer.Deserialize<LauncherSettings>(json) ?? new LauncherSettings();
}
catch (Exception ex)
{
Log.Warn("failed to read launcher settings, using defaults: " + ex.Message);
return new LauncherSettings();
}
}
public void Save(string path)
{
try
{
Directory.CreateDirectory(Path.GetDirectoryName(path)!);
var json = JsonSerializer.Serialize(this, _opts);
File.WriteAllText(path, json);
}
catch (Exception ex)
{
Log.Warn("failed to save launcher settings: " + ex.Message);
}
}
/// <summary>
/// Effective manifest URL respecting dev-mode gating.
/// </summary>
public string EffectiveManifestUrl()
{
if (DevMode && !string.IsNullOrWhiteSpace(ManifestUrlOverride))
return ManifestUrlOverride!;
return LauncherConfig.ManifestUrl;
}
/// <summary>
/// Derives signature URL from the (possibly overridden) manifest URL.
/// </summary>
public string EffectiveSignatureUrl()
{
var m = EffectiveManifestUrl();
if (m == LauncherConfig.ManifestUrl)
return LauncherConfig.SignatureUrl;
return m + ".sig";
}
/// <summary>
/// Derives the blob base URL from the (possibly overridden) manifest URL.
/// Same host, sibling /files path.
/// </summary>
public string EffectiveBlobBaseUrl()
{
var m = EffectiveManifestUrl();
if (m == LauncherConfig.ManifestUrl)
return LauncherConfig.BlobBaseUrl;
try
{
var u = new Uri(m);
return $"{u.Scheme}://{u.Authority}/files";
}
catch
{
return LauncherConfig.BlobBaseUrl;
}
}
}