From ce29711614296403b1b3f2219084188818573f73 Mon Sep 17 00:00:00 2001 From: kziolkowski Date: Fri, 21 Nov 2025 20:33:52 +0100 Subject: [PATCH] :sparkle: Added Settings classes to save and load local configurations --- project.godot | 1 + scenes/Babushka_scene_bootstrap.tscn | 7 +- .../CSharp/Common/Savegame/SettingsData.cs | 31 +++++ .../Common/Savegame/SettingsData.cs.uid | 1 + .../Common/Savegame/SettingsSaveController.cs | 108 ++++++++++++++++++ .../Savegame/SettingsSaveController.cs.uid | 1 + .../Common/Savegame/WindowSettingsSync.cs | 101 ++++++++++++++++ .../Common/Savegame/WindowSettingsSync.cs.uid | 1 + scripts/CSharp/Common/SceneTransition.cs | 1 + 9 files changed, 250 insertions(+), 2 deletions(-) create mode 100644 scripts/CSharp/Common/Savegame/SettingsData.cs create mode 100644 scripts/CSharp/Common/Savegame/SettingsData.cs.uid create mode 100644 scripts/CSharp/Common/Savegame/SettingsSaveController.cs create mode 100644 scripts/CSharp/Common/Savegame/SettingsSaveController.cs.uid create mode 100644 scripts/CSharp/Common/Savegame/WindowSettingsSync.cs create mode 100644 scripts/CSharp/Common/Savegame/WindowSettingsSync.cs.uid diff --git a/project.godot b/project.godot index 759b354..2658752 100644 --- a/project.godot +++ b/project.godot @@ -34,6 +34,7 @@ Signal_Debugger="*res://addons/SignalVisualizer/Debugger/SignalDebugger.gd" FightWorldAutoload="*res://prefabs/fight/fight_world_autoload.tscn" FieldService="*res://scripts/CSharp/Common/Farming/FieldService.cs" SaveGameManager="*res://scripts/CSharp/Common/Savegame/SaveGameManager.cs" +SettingsSaveController="*res://scripts/CSharp/Common/Savegame/SettingsSaveController.cs" [dialogic] diff --git a/scenes/Babushka_scene_bootstrap.tscn b/scenes/Babushka_scene_bootstrap.tscn index 6ae60a7..f567a1b 100644 --- a/scenes/Babushka_scene_bootstrap.tscn +++ b/scenes/Babushka_scene_bootstrap.tscn @@ -1,10 +1,13 @@ -[gd_scene load_steps=2 format=3 uid="uid://bopv10dqm1knc"] +[gd_scene load_steps=3 format=3 uid="uid://bopv10dqm1knc"] [ext_resource type="PackedScene" uid="uid://c6wnoif01ltld" path="res://scenes/Babushka_scene_startMenu.tscn" id="1_15ton"] +[ext_resource type="Script" uid="uid://bbp0dyddwdbl8" path="res://scripts/CSharp/Common/Savegame/WindowSettingsSync.cs" id="2_d3jfo"] [node name="BabushkaSceneBootstrap" type="Node2D"] [node name="BabushkaSceneStartMenu" parent="." instance=ExtResource("1_15ton")] -_sceneNamesToLoad = PackedStringArray("res://scenes/Babushka_scene_farm_outside_2d.tscn") [node name="SceneParent" type="Node" parent="."] + +[node name="WindowSettings" type="Node" parent="."] +script = ExtResource("2_d3jfo") diff --git a/scripts/CSharp/Common/Savegame/SettingsData.cs b/scripts/CSharp/Common/Savegame/SettingsData.cs new file mode 100644 index 0000000..d97dd8c --- /dev/null +++ b/scripts/CSharp/Common/Savegame/SettingsData.cs @@ -0,0 +1,31 @@ + +namespace Babushka.scripts.CSharp.Common.Savegame; + +/// +/// Data structure for device-specific settings that should be saved / loaded to disk. +/// Will not be synced across devices. +/// +public class SettingsData +{ + /// + /// To be incremented (and migrated) on modification. + /// + public const int VERSION = 1; + public int version { get; set; } = VERSION; + + public bool IsVersionValid() + { + return VERSION == version; + } + + public double runtimeSeconds { get; set; } + public int windowSizeX { get; set; } = 800; + public int windowSizeY { get; set; } = 600; + public int windowPositionX { get; set; } = 100; + public int windowPositionY { get; set; } = 100; + public bool windowBorderless { get; set; } + public float volumeMaster { get; set; } = 1.0f; + public float volumeFx { get; set; } = 1.0f; + public float volumeMusic { get; set; } = 1.0f; + +} \ No newline at end of file diff --git a/scripts/CSharp/Common/Savegame/SettingsData.cs.uid b/scripts/CSharp/Common/Savegame/SettingsData.cs.uid new file mode 100644 index 0000000..aede861 --- /dev/null +++ b/scripts/CSharp/Common/Savegame/SettingsData.cs.uid @@ -0,0 +1 @@ +uid://ol8xw1ekx0c2 diff --git a/scripts/CSharp/Common/Savegame/SettingsSaveController.cs b/scripts/CSharp/Common/Savegame/SettingsSaveController.cs new file mode 100644 index 0000000..2596ed8 --- /dev/null +++ b/scripts/CSharp/Common/Savegame/SettingsSaveController.cs @@ -0,0 +1,108 @@ +using System; +using System.Text.Json; +using Godot; + +namespace Babushka.scripts.CSharp.Common.Savegame; + +/// +/// Handles the saving and loading of local settings data. +/// +[GlobalClass] +public partial class SettingsSaveController : Node +{ + public static string SETTINGS_FILE_PATH = "user://userSettings.json"; + public static SettingsSaveController Instance; + + public SettingsData? settings = new SettingsData(); + public SettingsData settingsDefault = new SettingsData(); + + public event Action OnSettingsReloaded; + + private bool _loadedData; + private DateTime _readyTime; + + public bool LoadedData => _loadedData; + + public override void _EnterTree() + { + SETTINGS_FILE_PATH = ProjectSettings.GlobalizePath(SETTINGS_FILE_PATH); + _readyTime = DateTime.Now; + Instance = this; + LoadSettings(); + } + + public override void _ExitTree() + { + if (settings != null) + settings.runtimeSeconds += (DateTime.Now - _readyTime).TotalSeconds; + SaveSettings(); + Instance = null; + } + + /// + /// Saves Settings Data onto disk. + /// + public void SaveSettings() + { + try + { + string jsonString = JsonSerializer.Serialize( + settings, + new JsonSerializerOptions() { WriteIndented = true} + ); + + System.IO.File.WriteAllText(SETTINGS_FILE_PATH, jsonString); + } + catch (Exception e) + { + GD.PrintErr("Error Saving Settings:", e); + Console.WriteLine(e); + } + } + + /// + /// Loads Settings data from disk. + /// + public void LoadSettings() + { + _loadedData = false; + + try + { + if (!System.IO.File.Exists(SETTINGS_FILE_PATH)) + { + settings = new SettingsData(); + } + else + { + string jsonString = System.IO.File.ReadAllText(SETTINGS_FILE_PATH); + SettingsData? loadedSettings = JsonSerializer.Deserialize(jsonString); + if (loadedSettings != null && !loadedSettings.IsVersionValid()) + { + _loadedData = false; + } + else + { + settings = loadedSettings; + _loadedData = true; + } + } + } + catch (Exception e) + { + GD.PrintErr("Loading Error:", e); + Console.WriteLine(e); + } + + } + + /// + /// Resets Settings to default. + /// + public void ResetSettings() + { + settings = JsonSerializer.Deserialize(JsonSerializer.Serialize(settingsDefault)); + OnSettingsReloaded?.Invoke(); + } + +} \ No newline at end of file diff --git a/scripts/CSharp/Common/Savegame/SettingsSaveController.cs.uid b/scripts/CSharp/Common/Savegame/SettingsSaveController.cs.uid new file mode 100644 index 0000000..eae620f --- /dev/null +++ b/scripts/CSharp/Common/Savegame/SettingsSaveController.cs.uid @@ -0,0 +1 @@ +uid://cc7gnydmbcft7 diff --git a/scripts/CSharp/Common/Savegame/WindowSettingsSync.cs b/scripts/CSharp/Common/Savegame/WindowSettingsSync.cs new file mode 100644 index 0000000..df1c165 --- /dev/null +++ b/scripts/CSharp/Common/Savegame/WindowSettingsSync.cs @@ -0,0 +1,101 @@ +using Godot; + +namespace Babushka.scripts.CSharp.Common.Savegame; + +/// +/// Tracks important window settings and communicates with the to save/load them. +/// +public partial class WindowSettingsSync : Node +{ + private Window window; + + public override void _Ready() + { + window = GetWindow(); + window.SizeChanged += SaveWindowSize; + + SyncSettings(); + SettingsSaveController.Instance.OnSettingsReloaded += SyncSettings; + } + + + public override void _ExitTree() + { + SaveWindowPosition(); + SaveWindowBorderless(); + SaveWindowSize(); + SettingsSaveController.Instance.SaveSettings(); + } + + /// + /// Tries to get previous settings from settings-savefile, if available. + /// + public void SyncSettings() + { + if (!SettingsSaveController.Instance.LoadedData) + { + SaveWindowPosition(); + SaveWindowSize(); + SaveWindowBorderless(); + return; + } + + SettingsData? settingsData = SettingsSaveController.Instance.settings; + if (settingsData != null) + { + window.Position = new Vector2I(settingsData.windowPositionX, settingsData.windowPositionY); + ValidateWindowPosition(); + + window.Size = new Vector2I(settingsData.windowSizeX, settingsData.windowSizeY); + window.Borderless = settingsData.windowBorderless; + } + } + + private void ValidateWindowPosition() + { + bool validWindowPosition = false; + foreach (Rect2I displayRect in DisplayServer.GetDisplayCutouts()) + { + if (displayRect.HasPoint(window.Position)) + { + validWindowPosition = true; + break; + } + } + + if (!validWindowPosition) + { + window.MoveToCenter(); + SaveWindowPosition(); + } + } + + private void SaveWindowPosition() + { + SettingsData? settingsData = SettingsSaveController.Instance.settings; + + if (settingsData != null) + { + settingsData.windowPositionX = window.Position.X; + settingsData.windowPositionY = window.Position.Y; + } + } + + private void SaveWindowSize() + { + SettingsData? settingsData = SettingsSaveController.Instance.settings; + if (settingsData != null) + { + settingsData.windowSizeX = window.Size.X; + settingsData.windowSizeY = window.Size.Y; + } + } + + private void SaveWindowBorderless() + { + SettingsData? settingsData = SettingsSaveController.Instance.settings; + if (settingsData != null) + settingsData.windowBorderless = window.Borderless; + } + +} \ No newline at end of file diff --git a/scripts/CSharp/Common/Savegame/WindowSettingsSync.cs.uid b/scripts/CSharp/Common/Savegame/WindowSettingsSync.cs.uid new file mode 100644 index 0000000..0382595 --- /dev/null +++ b/scripts/CSharp/Common/Savegame/WindowSettingsSync.cs.uid @@ -0,0 +1 @@ +uid://bbp0dyddwdbl8 diff --git a/scripts/CSharp/Common/SceneTransition.cs b/scripts/CSharp/Common/SceneTransition.cs index 7709acb..1aa3f88 100644 --- a/scripts/CSharp/Common/SceneTransition.cs +++ b/scripts/CSharp/Common/SceneTransition.cs @@ -34,6 +34,7 @@ public partial class SceneTransition : Node public void Quit() { + SettingsSaveController.Instance.SaveSettings(); GetTree().Quit(); }