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();
}