First commit for private source control. Older commits available on Github.
This commit is contained in:
BIN
Assets/Scripts/Framework/Services/Settings/.DS_Store
vendored
Normal file
BIN
Assets/Scripts/Framework/Services/Settings/.DS_Store
vendored
Normal file
Binary file not shown.
8
Assets/Scripts/Framework/Services/Settings/Data.meta
Normal file
8
Assets/Scripts/Framework/Services/Settings/Data.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b0c389726255940069bd3d699d642044
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
BIN
Assets/Scripts/Framework/Services/Settings/Data/.DS_Store
vendored
Normal file
BIN
Assets/Scripts/Framework/Services/Settings/Data/.DS_Store
vendored
Normal file
Binary file not shown.
@@ -0,0 +1,27 @@
|
||||
using System;
|
||||
|
||||
namespace BriarQueen.Framework.Services.Settings.Data
|
||||
{
|
||||
[Serializable]
|
||||
public class AudioSettings
|
||||
{
|
||||
public float MasterVolume;
|
||||
public float MusicVolume;
|
||||
public float SfxVolume;
|
||||
public float VoiceVolume;
|
||||
public float AmbienceVolume;
|
||||
public float UIVolume;
|
||||
public bool MuteWhenUnfocused;
|
||||
|
||||
public AudioSettings()
|
||||
{
|
||||
MasterVolume = 1.0f; // 100%
|
||||
MusicVolume = 0.75f; // 75%
|
||||
SfxVolume = 0.75f; // 75%
|
||||
VoiceVolume = 1.0f; // 100%
|
||||
AmbienceVolume = 0.75f; // 75%
|
||||
UIVolume = 0.5f; // 50%
|
||||
MuteWhenUnfocused = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f10f93ec9d8c48d18d41fcf1b8e2a160
|
||||
timeCreated: 1769800676
|
||||
@@ -0,0 +1,13 @@
|
||||
using System;
|
||||
|
||||
namespace BriarQueen.Framework.Services.Settings.Data
|
||||
{
|
||||
[Serializable]
|
||||
public class GameSettings
|
||||
{
|
||||
public float PopupDisplayDuration = 3f;
|
||||
public bool TutorialsEnabled = true;
|
||||
public bool TooltipsEnabled = true;
|
||||
public bool AutoUseTools = false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c89e0d84df0742999d88e7a33e8360c2
|
||||
timeCreated: 1772819897
|
||||
@@ -0,0 +1,27 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
namespace BriarQueen.Framework.Services.Settings.Data
|
||||
{
|
||||
[Serializable]
|
||||
public class VisualSettings
|
||||
{
|
||||
public int VSyncCount; // 0 = Off, 1 = Every V-Blank, 2 = Every second V-Blank
|
||||
|
||||
public FullScreenMode FullScreenMode;
|
||||
|
||||
/// <summary>
|
||||
/// Requested application framerate cap.
|
||||
/// Ignored or effectively overridden on many platforms when VSync is enabled.
|
||||
/// Use -1 for platform default / uncapped behavior.
|
||||
/// </summary>
|
||||
public int MaxFramerate;
|
||||
|
||||
public VisualSettings()
|
||||
{
|
||||
VSyncCount = 0;
|
||||
FullScreenMode = FullScreenMode.FullScreenWindow;
|
||||
MaxFramerate = 120;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6e288ada3e7b4b06a23bf0824f393543
|
||||
timeCreated: 1769800769
|
||||
228
Assets/Scripts/Framework/Services/Settings/SettingsService.cs
Normal file
228
Assets/Scripts/Framework/Services/Settings/SettingsService.cs
Normal file
@@ -0,0 +1,228 @@
|
||||
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}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6a9b8ee2440445a692de5a8e3851712c
|
||||
timeCreated: 1769800626
|
||||
Reference in New Issue
Block a user