using System; using System.IO; using System.Reflection; using System.Text.Json; using System.Text.Json.Serialization; namespace ModpackLauncher.Models; public sealed class LauncherConfig { [JsonPropertyName("packName")] public string PackName { get; set; } = "Modpack"; [JsonPropertyName("manifestUrl")] public string ManifestUrl { get; set; } = ""; /// /// Subfolder name appended under the install location (sidecar exe folder /// by default, or the folder the user picked via "Change..."). Acts as /// a safety net so picking a generic location like "D:\" doesn't dump /// thousands of files at the drive root, and signals at a glance that /// this is the launcher's data, not the launcher itself. /// [JsonPropertyName("installDirName")] public string InstallDirName { get; set; } = "BrassAndSigilData"; [JsonPropertyName("memoryMB")] public int MemoryMB { get; set; } = 8192; [JsonPropertyName("msalClientId")] public string MsalClientId { get; set; } = ""; /// Optional HTTP Basic auth username for the manifest URL and mod file URLs. [JsonPropertyName("httpUsername")] public string? HttpUsername { get; set; } /// Optional HTTP Basic auth password (paired with HttpUsername). [JsonPropertyName("httpPassword")] public string? HttpPassword { get; set; } public static LauncherConfig Load() { // 1. External override beside the exe (dev convenience / per-deploy override) var sidecar = Path.Combine(AppContext.BaseDirectory, "launcher-config.json"); if (File.Exists(sidecar)) { return ParseSafe(File.ReadAllText(sidecar)); } // 2. Embedded launcher-config.json (set at build time from local copy) var asm = typeof(LauncherConfig).Assembly; using (var stream = asm.GetManifestResourceStream("launcher-config.json")) { if (stream != null) { using var reader = new StreamReader(stream); return ParseSafe(reader.ReadToEnd()); } } // 3. Fall back to embedded template (so fresh clones still run, with placeholders) using (var stream = asm.GetManifestResourceStream("launcher-config.template.json")) { if (stream != null) { using var reader = new StreamReader(stream); return ParseSafe(reader.ReadToEnd()); } } return new LauncherConfig(); } private static LauncherConfig ParseSafe(string json) { var opts = new JsonSerializerOptions { PropertyNameCaseInsensitive = true }; return JsonSerializer.Deserialize(json, opts) ?? new LauncherConfig(); } /// /// Resolve the absolute install directory. The launcher behaves as a /// portable app: by default it installs alongside the exe in /// <exe-folder>/<InstallDirName>/. The user can override /// via the "Change..." picker, which stores the chosen *parent* folder /// in InstallDirOverride; we then append /// to it (same safety reasoning as the default). /// /// Smart-skip: if the parent path already ends in InstallDirName, we /// don't double up. Lets users re-pick their existing install folder /// (e.g. "D:\Games\BrassAndSigilData") without ending up at /// "D:\Games\BrassAndSigilData\BrassAndSigilData". /// public string GetInstallDir(string? overrideDir = null) { var parent = !string.IsNullOrWhiteSpace(overrideDir) ? overrideDir! : AppContext.BaseDirectory; var trimmed = parent.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar); if (string.Equals(Path.GetFileName(trimmed), InstallDirName, StringComparison.OrdinalIgnoreCase)) { return trimmed; } return Path.Combine(parent, InstallDirName); } }