using System.Collections.Generic; using UnityEngine; namespace Ashwild.Settings { /// /// Authored data for a float setting driven by a : its default /// value, clamp range, and the label presentation hints the widget needs. /// [System.Serializable] public struct FloatSetting { [SerializeField] private float defaultValue; [SerializeField] private float min; [SerializeField] private float max; [Tooltip("Value is multiplied by this before formatting (e.g. 100 to show a 0–1 value as a percentage).")] [SerializeField] private float labelScale; [Tooltip("Composite format applied to the scaled value, e.g. \"{0:F0}%\" or \"{0:F0}°\".")] [SerializeField] private string labelFormat; public float DefaultValue => defaultValue; public float Min => min; public float Max => max; public float LabelScale => labelScale; public string LabelFormat => labelFormat; } /// /// One stepper entry: a value plus the text shown for it. Mirrors the (value, label) pair the /// consumes. /// [System.Serializable] public struct StepperPreset { [SerializeField] private int value; [SerializeField] private string label; public int Value => value; public string Label => label; } /// /// Authored data for a discrete int setting driven by a : its /// default value and the ordered preset list. /// [System.Serializable] public struct StepperSetting { [SerializeField] private int defaultValue; [SerializeField] private List presets; public int DefaultValue => defaultValue; public IReadOnlyList Presets => presets; /// /// Adapts the authored presets to the (value, label) tuples the stepper widget consumes, /// keeping the widget decoupled from this settings-data type. /// public IReadOnlyList<(int value, string label)> ToWidgetPresets() { List<(int, string)> result = new List<(int, string)>(presets != null ? presets.Count : 0); if (presets != null) foreach (StepperPreset preset in presets) result.Add((preset.Value, preset.Label)); return result; } } /// /// Single source of truth for all authored settings data: per-setting defaults, clamp ranges, /// label formatting and the FPS preset list. Read by (defaults + /// clamps) and by the settings sub-panels (widget configuration), so no magic numbers or UI /// hints live in code. Resolution/monitor indices are intentionally absent — they are derived /// from the running hardware and resolved at runtime. /// [CreateAssetMenu(fileName = "SettingsDefinition", menuName = "Settings/Settings Definition")] public class SettingsDefinition : ScriptableObject { #region Display [Header("Display")] [SerializeField] private FloatSetting brightness; [SerializeField] private FullScreenMode defaultFullscreenMode = FullScreenMode.FullScreenWindow; public FloatSetting Brightness => brightness; public FullScreenMode DefaultFullscreenMode => defaultFullscreenMode; #endregion #region Audio [Header("Audio")] [SerializeField] private FloatSetting masterVolume; [SerializeField] private FloatSetting musicVolume; [SerializeField] private FloatSetting sfxVolume; public FloatSetting MasterVolume => masterVolume; public FloatSetting MusicVolume => musicVolume; public FloatSetting SfxVolume => sfxVolume; #endregion #region Graphics [Header("Graphics")] [Tooltip("-1 keeps the project's current quality level on first run.")] [SerializeField] private int defaultQualityLevel = -1; [SerializeField] private bool defaultVSync = true; [SerializeField] private StepperSetting targetFps; [SerializeField] private FloatSetting fov; public int DefaultQualityLevel => defaultQualityLevel; public bool DefaultVSync => defaultVSync; public StepperSetting TargetFps => targetFps; public FloatSetting Fov => fov; #endregion #region Controls [Header("Controls")] [SerializeField] private FloatSetting sensitivity; [SerializeField] private bool defaultInvertY; [SerializeField] private bool defaultCrosshairEnabled = true; public FloatSetting Sensitivity => sensitivity; public bool DefaultInvertY => defaultInvertY; public bool DefaultCrosshairEnabled => defaultCrosshairEnabled; #endregion } }