using System; using UnityEngine; namespace ProjectM.Client { /// /// Serializable client settings model (Graphics + Audio) persisted to JSON by . /// Flat fields only (an enum stored as an int) so JsonUtility round-trips it without Newtonsoft. /// gates forward-compatible migration. Purely client-local — never replicated (the /// server has no opinion on a player's resolution or volume). /// [Serializable] public struct GameSettings { public const int CurrentVersion = 1; public int Version; // ---- Graphics ---- public int ResWidth; public int ResHeight; public int RefreshHz; // 0 = platform default public int FullScreenMode; // (int)UnityEngine.FullScreenMode (0 Exclusive,1 FullScreenWindow,2 Maximized,3 Windowed) public int QualityLevel; public int VSync; // QualitySettings.vSyncCount: 0/1/2 public int TargetFps; // Application.targetFrameRate: -1 = uncapped // ---- Audio (0..1) ---- public float Master; public float Music; public float Sfx; /// Sensible defaults derived from the current display + active quality level. public static GameSettings Defaults() { var r = Screen.currentResolution; return new GameSettings { Version = CurrentVersion, ResWidth = r.width > 0 ? r.width : 1920, ResHeight = r.height > 0 ? r.height : 1080, RefreshHz = 0, FullScreenMode = (int)UnityEngine.FullScreenMode.FullScreenWindow, QualityLevel = QualitySettings.GetQualityLevel(), VSync = 1, TargetFps = -1, Master = 1f, Music = 1f, Sfx = 1f, }; } /// Clamp every field into a safe range (defensive against hand-edited / corrupt JSON). public GameSettings Clamped() { var s = this; s.ResWidth = Mathf.Clamp(s.ResWidth <= 0 ? 1920 : s.ResWidth, 640, 7680); s.ResHeight = Mathf.Clamp(s.ResHeight <= 0 ? 1080 : s.ResHeight, 480, 4320); s.RefreshHz = Mathf.Max(0, s.RefreshHz); s.FullScreenMode = Mathf.Clamp(s.FullScreenMode, 0, 3); int qn = (QualitySettings.names != null && QualitySettings.names.Length > 0) ? QualitySettings.names.Length : 1; s.QualityLevel = Mathf.Clamp(s.QualityLevel, 0, qn - 1); s.VSync = Mathf.Clamp(s.VSync, 0, 2); s.TargetFps = s.TargetFps <= 0 ? -1 : Mathf.Clamp(s.TargetFps, 20, 1000); s.Master = Mathf.Clamp01(s.Master); s.Music = Mathf.Clamp01(s.Music); s.Sfx = Mathf.Clamp01(s.Sfx); return s; } } }