using System.IO; using System.Text.Json; using System.Text.Json.Serialization; namespace DorkNet.Launcher.Backend; /// Persisted user choices that should survive across launches: /// host-vs-join mode (asked on first launch, switchable in settings), /// the picked Rec Room install path, the selected server version, and /// any Photon AppIds the user has configured. Serialized as JSON at /// . public sealed class AppState { [JsonPropertyName("mode")] public AppMode Mode { get; set; } = AppMode.Unset; /// Path to the user's Recroom_Release_Data folder. First /// run auto-fills via (scans /// common manual-install paths only, never Steam library); user /// can override via the folder dialog. [JsonPropertyName("recRoomPath")] public string? RecRoomPath { get; set; } /// The version key currently selected for host mode /// (e.g. december_2020_12_18). For join mode this is set /// from the parsed join code. [JsonPropertyName("selectedVersion")] public string? SelectedVersion { get; set; } /// Photon Realtime AppId for host mode. The user gets /// their own (free at dashboard.photonengine.com); DorkNet never /// ships one. Empty until set. [JsonPropertyName("photonAppId")] public string PhotonAppId { get; set; } = string.Empty; [JsonPropertyName("photonVoiceAppId")] public string PhotonVoiceAppId { get; set; } = string.Empty; [JsonPropertyName("photonRegion")] public string PhotonRegion { get; set; } = "us"; /// How the host exposes the server: Internet uses /// a Cloudflare quick-tunnel (works for friends anywhere with the /// join code); LocalNetwork binds the LAN IP and skips the /// tunnel entirely (no internet dependency, joiners must be on /// the same network). [JsonPropertyName("hostingMode")] public HostingMode HostingMode { get; set; } = HostingMode.Internet; /// Host's server name shown in the join code. Empty until /// the user fills it in on first-run host setup. [JsonPropertyName("serverName")] public string ServerName { get; set; } = string.Empty; private static readonly JsonSerializerOptions JsonOptions = new() { WriteIndented = true, PropertyNamingPolicy = JsonNamingPolicy.CamelCase, Converters = { new JsonStringEnumConverter(JsonNamingPolicy.CamelCase) }, }; public static AppState Load() { if (!File.Exists(AppPaths.StateFile)) return new AppState(); try { var json = File.ReadAllText(AppPaths.StateFile); return JsonSerializer.Deserialize(json, JsonOptions) ?? new AppState(); } catch { // Corrupt state file — start fresh rather than crash on every // launch. The user's mode pick + Photon config gets lost but // they can re-enter; the alternative is unrecoverable. return new AppState(); } } public void Save() { var json = JsonSerializer.Serialize(this, JsonOptions); File.WriteAllText(AppPaths.StateFile, json); } } public enum AppMode { /// First launch — show the host-vs-join wizard. Unset, Host, Join, } public enum HostingMode { /// Default — Cloudflare quick-tunnel, public over the /// internet, works for joiners anywhere. Internet, /// LAN only — bind the machine's local IP, skip the /// tunnel, no internet dependency. Joiners must be on the same /// network. LocalNetwork, }