228 lines
7.8 KiB
C#
228 lines
7.8 KiB
C#
using System;
|
|
using System.IO;
|
|
using BriarQueen.Data.Identifiers;
|
|
using BriarQueen.Data.IO;
|
|
using BriarQueen.Framework.Coordinators.Events;
|
|
using BriarQueen.Framework.Events.Save;
|
|
using BriarQueen.Framework.Managers.Audio;
|
|
using BriarQueen.Framework.Services.Settings.Data;
|
|
using Cysharp.Threading.Tasks;
|
|
using Newtonsoft.Json;
|
|
using UnityEngine;
|
|
using VContainer;
|
|
using AudioSettings = BriarQueen.Framework.Services.Settings.Data.AudioSettings;
|
|
|
|
namespace BriarQueen.Framework.Services.Settings
|
|
{
|
|
public class SettingsService
|
|
{
|
|
private const string AUDIO_FILE = "Audio.json";
|
|
private const string VISUAL_FILE = "Visual.json";
|
|
private const string GAME_FILE = "Game.json";
|
|
|
|
private readonly AudioManager _audioManager;
|
|
private readonly EventCoordinator _eventCoordinator;
|
|
|
|
|
|
[Inject]
|
|
public SettingsService(EventCoordinator eventCoordinator, AudioManager audioManager)
|
|
{
|
|
_eventCoordinator = eventCoordinator;
|
|
_audioManager = audioManager;
|
|
}
|
|
|
|
public AudioSettings Audio { get; private set; }
|
|
public VisualSettings Visual { get; private set; }
|
|
public GameSettings Game { get; private set; }
|
|
|
|
public async UniTask InitializeAsync()
|
|
{
|
|
#if UNITY_EDITOR
|
|
Debug.Log($"[{nameof(SettingsService)}] Initializing...");
|
|
#endif
|
|
EnsureDirectories();
|
|
await LoadAllSettings();
|
|
Apply(Audio, Visual, Game, false, false);
|
|
|
|
#if UNITY_EDITOR
|
|
Debug.Log($"[{nameof(SettingsService)}] Initialized.");
|
|
#endif
|
|
}
|
|
|
|
private void EnsureDirectories()
|
|
{
|
|
Directory.CreateDirectory(FilePaths.ConfigFolder);
|
|
Directory.CreateDirectory(FilePaths.SaveDataFolder);
|
|
Directory.CreateDirectory(FilePaths.SaveBackupDataFolder);
|
|
}
|
|
|
|
public void Apply(
|
|
AudioSettings audio,
|
|
VisualSettings visual,
|
|
GameSettings game,
|
|
bool saveToDisk = true,
|
|
bool fireEvent = true)
|
|
{
|
|
Audio = audio ?? new AudioSettings();
|
|
Visual = visual ?? new VisualSettings();
|
|
Game = game ?? new GameSettings();
|
|
|
|
ApplyAudio(Audio);
|
|
ApplyVisual(Visual);
|
|
ApplyGame(Game);
|
|
|
|
if (saveToDisk)
|
|
{
|
|
SaveSettingsFile(Audio, AUDIO_FILE).Forget();
|
|
SaveSettingsFile(Visual, VISUAL_FILE).Forget();
|
|
SaveSettingsFile(Game, GAME_FILE).Forget();
|
|
}
|
|
|
|
if (fireEvent)
|
|
_eventCoordinator.Publish(new SettingsChangedEvent());
|
|
}
|
|
|
|
public float GetVolume(string mixerGroup)
|
|
{
|
|
return mixerGroup switch
|
|
{
|
|
AudioMixerGroups.MASTER_GROUP => Audio.MasterVolume,
|
|
AudioMixerGroups.MUSIC_GROUP => Audio.MusicVolume,
|
|
AudioMixerGroups.SFX_GROUP => Audio.SfxVolume,
|
|
AudioMixerGroups.UI_GROUP => Audio.UIVolume,
|
|
AudioMixerGroups.VOICE_GROUP => Audio.VoiceVolume,
|
|
_ => Audio.MasterVolume
|
|
};
|
|
}
|
|
|
|
public bool AreTutorialsEnabled()
|
|
{
|
|
return Game != null && Game.TutorialsEnabled;
|
|
}
|
|
|
|
public bool AreTooltipsEnabled()
|
|
{
|
|
return Game != null && Game.TooltipsEnabled;
|
|
}
|
|
|
|
private void ApplyAudio(AudioSettings a)
|
|
{
|
|
_audioManager.SetVolume(AudioMixerParameters.MASTER_VOLUME, a.MasterVolume);
|
|
_audioManager.SetVolume(AudioMixerParameters.MUSIC_VOLUME, a.MusicVolume);
|
|
_audioManager.SetVolume(AudioMixerParameters.SFX_VOLUME, a.SfxVolume);
|
|
_audioManager.SetVolume(AudioMixerParameters.VOICE_VOLUME, a.VoiceVolume);
|
|
_audioManager.SetVolume(AudioMixerParameters.AMBIENCE_VOLUME, a.AmbienceVolume);
|
|
_audioManager.SetVolume(AudioMixerParameters.UI_VOLUME, a.UIVolume);
|
|
|
|
Application.runInBackground = !a.MuteWhenUnfocused;
|
|
}
|
|
|
|
private void ApplyVisual(VisualSettings v)
|
|
{
|
|
SanitizeVisualSettings(v);
|
|
|
|
var currentRes = Screen.currentResolution;
|
|
var rr = new RefreshRate
|
|
{
|
|
numerator = currentRes.refreshRateRatio.numerator,
|
|
denominator = currentRes.refreshRateRatio.denominator
|
|
};
|
|
|
|
Screen.SetResolution(currentRes.width, currentRes.height, v.FullScreenMode, rr);
|
|
QualitySettings.vSyncCount = v.VSyncCount;
|
|
|
|
// On many desktop platforms, VSync will take precedence over targetFrameRate.
|
|
Application.targetFrameRate = v.MaxFramerate;
|
|
}
|
|
|
|
private void ApplyGame(GameSettings g)
|
|
{
|
|
if (g.PopupDisplayDuration <= 0f)
|
|
g.PopupDisplayDuration = 3f;
|
|
|
|
// TutorialsEnabled and TooltipsEnabled are gameplay/UI preferences.
|
|
// They do not need an immediate engine-level apply step here.
|
|
// Systems that show tutorials/tooltips should query SettingsManager.Game
|
|
// or use the helper methods above.
|
|
}
|
|
|
|
private async UniTask LoadAllSettings()
|
|
{
|
|
Audio = await LoadOrCreateSettingsFiles<AudioSettings>(AUDIO_FILE);
|
|
Visual = await LoadOrCreateSettingsFiles<VisualSettings>(VISUAL_FILE);
|
|
Game = await LoadOrCreateSettingsFiles<GameSettings>(GAME_FILE);
|
|
|
|
Audio ??= new AudioSettings();
|
|
Visual ??= new VisualSettings();
|
|
Game ??= new GameSettings();
|
|
|
|
SanitizeVisualSettings(Visual);
|
|
|
|
if (Game.PopupDisplayDuration <= 0f)
|
|
Game.PopupDisplayDuration = 3f;
|
|
}
|
|
|
|
private void SanitizeVisualSettings(VisualSettings v)
|
|
{
|
|
if (v == null)
|
|
return;
|
|
|
|
v.VSyncCount = Mathf.Clamp(v.VSyncCount, 0, 2);
|
|
|
|
// Treat 0 or any negative value other than -1 as invalid and fall back to 120.
|
|
// If you want to support -1 as "platform default", keep it. Otherwise, normalize it too.
|
|
if (v.MaxFramerate == 0 || v.MaxFramerate < -1)
|
|
v.MaxFramerate = 120;
|
|
|
|
if (v.MaxFramerate > 0)
|
|
v.MaxFramerate = Mathf.Clamp(v.MaxFramerate, 30, 240);
|
|
}
|
|
|
|
private async UniTask<T> LoadOrCreateSettingsFiles<T>(string fileName) where T : class, new()
|
|
{
|
|
var filePath = Path.Combine(FilePaths.ConfigFolder, fileName);
|
|
T settings;
|
|
|
|
if (File.Exists(filePath))
|
|
{
|
|
try
|
|
{
|
|
var jsonString = await File.ReadAllTextAsync(filePath);
|
|
settings = JsonConvert.DeserializeObject<T>(jsonString);
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
Debug.LogError($"[SettingsManager] Failed to load {fileName}. Creating new. Error: {e.Message}");
|
|
settings = new T();
|
|
await SaveSettingsFile(settings, fileName);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
settings = new T();
|
|
await SaveSettingsFile(settings, fileName);
|
|
}
|
|
|
|
return settings ?? new T();
|
|
}
|
|
|
|
private async UniTask SaveSettingsFile<T>(T settings, string fileName) where T : class
|
|
{
|
|
if (settings == null)
|
|
return;
|
|
|
|
var filePath = Path.Combine(FilePaths.ConfigFolder, fileName);
|
|
Directory.CreateDirectory(FilePaths.ConfigFolder);
|
|
|
|
try
|
|
{
|
|
var jsonString = JsonConvert.SerializeObject(settings, Formatting.Indented);
|
|
await File.WriteAllTextAsync(filePath, jsonString);
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
Debug.LogError($"[SettingsManager] Failed to save {fileName}. Error: {e.Message}");
|
|
}
|
|
}
|
|
}
|
|
} |