Files
2026-06-22 16:18:34 +02:00

278 lines
11 KiB
C#

using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Audio;
using UnityEngine.Events;
using Ashwild.Core;
namespace Ashwild.Settings
{
public class SettingsManager : MonoBehaviour
{
public static SettingsManager Instance { get; private set; }
[Header("Audio Mixer")]
[SerializeField] private AudioMixer audioMixer;
[SerializeField] private string masterParam = "MasterVol";
[SerializeField] private string musicParam = "MusicVol";
[SerializeField] private string sfxParam = "SfxVol";
[Header("Events")]
public UnityEvent onSettingsChanged;
// ── Display ─────────────────────────────────────────────────
public int ResolutionIndex { get; private set; }
public FullScreenMode FullscreenMode { get; private set; }
public int MonitorIndex { get; private set; }
public float Brightness { get; private set; }
// ── Audio ───────────────────────────────────────────────────
public float MasterVolume { get; private set; }
public float MusicVolume { get; private set; }
public float SfxVolume { get; private set; }
// ── Graphics ────────────────────────────────────────────────
public int QualityLevel { get; private set; }
public bool VSync { get; private set; }
public int TargetFps { get; private set; }
public float Fov { get; private set; }
// ── Controls ────────────────────────────────────────────────
public float Sensitivity { get; private set; }
public bool InvertY { get; private set; }
public bool CrosshairEnabled { get; private set; }
// ── PlayerPrefs keys ────────────────────────────────────────
private const string K_RESOLUTION = "settings.display.resolutionIndex";
private const string K_FULLSCREEN = "settings.display.fullscreenMode";
private const string K_MONITOR = "settings.display.monitorIndex";
private const string K_BRIGHTNESS = "settings.display.brightness";
private const string K_MASTER = "settings.audio.master";
private const string K_MUSIC = "settings.audio.music";
private const string K_SFX = "settings.audio.sfx";
private const string K_QUALITY = "settings.graphics.qualityLevel";
private const string K_VSYNC = "settings.graphics.vsync";
private const string K_TARGET_FPS = "settings.graphics.targetFps";
private const string K_FOV = "settings.graphics.fov";
private const string K_SENS = "settings.controls.sensitivity";
private const string K_INVERT_Y = "settings.controls.invertY";
private const string K_CROSSHAIR = "settings.controls.crosshair";
private void Awake()
{
if (Instance != null && Instance != this)
{
Destroy(gameObject);
return;
}
Instance = this;
Persistence.Persist(gameObject);
LoadAll();
ApplyAll();
}
// ── Public setters ──────────────────────────────────────────
public void SetResolution(int index)
{
Resolution[] resolutions = Screen.resolutions;
if (index < 0 || index >= resolutions.Length) return;
ResolutionIndex = index;
Resolution r = resolutions[index];
Screen.SetResolution(r.width, r.height, FullscreenMode, r.refreshRateRatio);
Save();
onSettingsChanged?.Invoke();
}
public void SetFullscreenMode(FullScreenMode mode)
{
FullscreenMode = mode;
Screen.fullScreenMode = mode;
Save();
onSettingsChanged?.Invoke();
}
public void SetMonitor(int index)
{
List<DisplayInfo> displays = new List<DisplayInfo>();
Screen.GetDisplayLayout(displays);
if (index < 0 || index >= displays.Count) return;
MonitorIndex = index;
Screen.MoveMainWindowTo(displays[index], Vector2Int.zero);
Save();
onSettingsChanged?.Invoke();
}
public void SetBrightness(float value)
{
Brightness = Mathf.Clamp(value, 0.5f, 1.5f);
Save();
onSettingsChanged?.Invoke();
}
public void SetMasterVolume(float value)
{
MasterVolume = Mathf.Clamp01(value);
ApplyMasterVolume();
Save();
onSettingsChanged?.Invoke();
}
public void SetMusicVolume(float value)
{
MusicVolume = Mathf.Clamp01(value);
ApplyMusicVolume();
Save();
onSettingsChanged?.Invoke();
}
public void SetSfxVolume(float value)
{
SfxVolume = Mathf.Clamp01(value);
ApplySfxVolume();
Save();
onSettingsChanged?.Invoke();
}
public void SetQualityLevel(int level)
{
QualityLevel = Mathf.Clamp(level, 0, QualitySettings.names.Length - 1);
QualitySettings.SetQualityLevel(QualityLevel, true);
Save();
onSettingsChanged?.Invoke();
}
public void SetVSync(bool enabled)
{
VSync = enabled;
QualitySettings.vSyncCount = enabled ? 1 : 0;
Save();
onSettingsChanged?.Invoke();
}
public void SetTargetFps(int fps)
{
TargetFps = Mathf.Clamp(fps, 30, 360);
Application.targetFrameRate = TargetFps;
Save();
onSettingsChanged?.Invoke();
}
public void SetFov(float fov)
{
Fov = Mathf.Clamp(fov, 60f, 110f);
Save();
onSettingsChanged?.Invoke();
}
public void SetSensitivity(float value)
{
Sensitivity = Mathf.Clamp(value, 0.05f, 2f);
Save();
onSettingsChanged?.Invoke();
}
public void SetInvertY(bool enabled)
{
InvertY = enabled;
Save();
onSettingsChanged?.Invoke();
}
public void SetCrosshairEnabled(bool enabled)
{
CrosshairEnabled = enabled;
Save();
onSettingsChanged?.Invoke();
}
// ── Load / Save / Apply ─────────────────────────────────────
private void LoadAll()
{
int defaultResolution = Mathf.Max(0, Screen.resolutions.Length - 1);
ResolutionIndex = PlayerPrefs.GetInt(K_RESOLUTION, defaultResolution);
FullscreenMode = (FullScreenMode)PlayerPrefs.GetInt(K_FULLSCREEN, (int)FullScreenMode.FullScreenWindow);
MonitorIndex = PlayerPrefs.GetInt(K_MONITOR, 0);
Brightness = PlayerPrefs.GetFloat(K_BRIGHTNESS, 1f);
MasterVolume = PlayerPrefs.GetFloat(K_MASTER, 1f);
MusicVolume = PlayerPrefs.GetFloat(K_MUSIC, 0.8f);
SfxVolume = PlayerPrefs.GetFloat(K_SFX, 1f);
QualityLevel = PlayerPrefs.GetInt(K_QUALITY, QualitySettings.GetQualityLevel());
VSync = PlayerPrefs.GetInt(K_VSYNC, 1) == 1;
TargetFps = PlayerPrefs.GetInt(K_TARGET_FPS, 144);
Fov = PlayerPrefs.GetFloat(K_FOV, 75f);
Sensitivity = PlayerPrefs.GetFloat(K_SENS, 0.15f);
InvertY = PlayerPrefs.GetInt(K_INVERT_Y, 0) == 1;
CrosshairEnabled = PlayerPrefs.GetInt(K_CROSSHAIR, 1) == 1;
}
private void Save()
{
PlayerPrefs.SetInt(K_RESOLUTION, ResolutionIndex);
PlayerPrefs.SetInt(K_FULLSCREEN, (int)FullscreenMode);
PlayerPrefs.SetInt(K_MONITOR, MonitorIndex);
PlayerPrefs.SetFloat(K_BRIGHTNESS, Brightness);
PlayerPrefs.SetFloat(K_MASTER, MasterVolume);
PlayerPrefs.SetFloat(K_MUSIC, MusicVolume);
PlayerPrefs.SetFloat(K_SFX, SfxVolume);
PlayerPrefs.SetInt(K_QUALITY, QualityLevel);
PlayerPrefs.SetInt(K_VSYNC, VSync ? 1 : 0);
PlayerPrefs.SetInt(K_TARGET_FPS, TargetFps);
PlayerPrefs.SetFloat(K_FOV, Fov);
PlayerPrefs.SetFloat(K_SENS, Sensitivity);
PlayerPrefs.SetInt(K_INVERT_Y, InvertY ? 1 : 0);
PlayerPrefs.SetInt(K_CROSSHAIR, CrosshairEnabled ? 1 : 0);
PlayerPrefs.Save();
}
private void ApplyAll()
{
// Display
Resolution[] resolutions = Screen.resolutions;
if (ResolutionIndex >= 0 && ResolutionIndex < resolutions.Length)
{
Resolution r = resolutions[ResolutionIndex];
Screen.SetResolution(r.width, r.height, FullscreenMode, r.refreshRateRatio);
}
if (MonitorIndex > 0)
{
List<DisplayInfo> displays = new List<DisplayInfo>();
Screen.GetDisplayLayout(displays);
if (MonitorIndex < displays.Count)
Screen.MoveMainWindowTo(displays[MonitorIndex], Vector2Int.zero);
}
// Audio
ApplyMasterVolume();
ApplyMusicVolume();
ApplySfxVolume();
// Graphics
QualitySettings.SetQualityLevel(QualityLevel, true);
QualitySettings.vSyncCount = VSync ? 1 : 0;
Application.targetFrameRate = TargetFps;
}
// ── Audio helpers ───────────────────────────────────────────
private void ApplyMasterVolume() => SetMixer(masterParam, MasterVolume);
private void ApplyMusicVolume() => SetMixer(musicParam, MusicVolume);
private void ApplySfxVolume() => SetMixer(sfxParam, SfxVolume);
private void SetMixer(string param, float linear)
{
if (audioMixer == null || string.IsNullOrEmpty(param)) return;
audioMixer.SetFloat(param, Mathf.Log10(Mathf.Max(linear, 0.0001f)) * 20f);
}
}
}