From 92a3c4f79a15a0c0bb0b1f5332822cc6f86a1d86 Mon Sep 17 00:00:00 2001 From: Gabriel Kaszewski Date: Thu, 19 Mar 2026 03:17:26 +0100 Subject: [PATCH] feat: add SettingsManager autoload for display, gamepad and input binding settings --- Autoloads/SettingsManager.cs | 195 +++++++++++++++++++++++++++++++++++ project.godot | 1 + 2 files changed, 196 insertions(+) create mode 100644 Autoloads/SettingsManager.cs diff --git a/Autoloads/SettingsManager.cs b/Autoloads/SettingsManager.cs new file mode 100644 index 0000000..5a581a3 --- /dev/null +++ b/Autoloads/SettingsManager.cs @@ -0,0 +1,195 @@ +using Godot; +using System.Collections.Generic; + +namespace Mr.BrickAdventures.Autoloads; + +public partial class SettingsManager : Node +{ + public static SettingsManager Instance { get; private set; } + + public float GamepadDeadzone { get; private set; } = 0.2f; + public float GamepadSensitivity { get; private set; } = 1.0f; + public string WindowMode { get; private set; } = "fullscreen"; + public Vector2I Resolution { get; private set; } = new Vector2I(1920, 1080); + + private static readonly List CuratedResolutions = new() + { + // 4:3 + new Vector2I(640, 480), + new Vector2I(800, 600), + new Vector2I(1024, 768), + new Vector2I(1280, 960), + new Vector2I(1600, 1200), + // 16:9 + new Vector2I(1280, 720), + new Vector2I(1366, 768), + new Vector2I(1600, 900), + new Vector2I(1920, 1080), + new Vector2I(2560, 1440), + new Vector2I(3840, 2160), + // 16:10 + new Vector2I(1280, 800), + new Vector2I(1440, 900), + new Vector2I(1920, 1200), + new Vector2I(2560, 1600), + }; + + private readonly List _customResolutions = new(); + + private static readonly string[] DeadzoneActions = { "left", "right", "up", "down" }; + + public override void _Ready() + { + Instance = this; + + var cfg = ConfigFileHandler.Instance.SettingsConfig; + + // --- display_settings --- + WindowMode = cfg.GetValue("display_settings", "window_mode", Variant.From("fullscreen")).AsString(); + var resStr = cfg.GetValue("display_settings", "resolution", Variant.From("1920x1080")).AsString(); + Resolution = ParseResolution(resStr, new Vector2I(1920, 1080)); + + var customResStr = cfg.GetValue("display_settings", "custom_resolutions", Variant.From("")).AsString(); + if (!string.IsNullOrWhiteSpace(customResStr)) + { + foreach (var part in customResStr.Split(',')) + { + var r = ParseResolution(part.Trim(), Vector2I.Zero); + if (r != Vector2I.Zero) + _customResolutions.Add(r); + } + } + + ApplyDisplaySettings(); + + // --- gameplay_settings --- + GamepadDeadzone = (float)cfg.GetValue("gameplay_settings", "gamepad_deadzone", Variant.From(0.2)).AsDouble(); + GamepadSensitivity = (float)cfg.GetValue("gameplay_settings", "gamepad_sensitivity", Variant.From(1.0)).AsDouble(); + + ApplyGamepadDeadzone(); + + // --- input_settings --- + ApplyInputBindings(cfg); + } + + public override void _ExitTree() + { + if (Instance == this) Instance = null; + } + + // ── public API ─────────────────────────────────────────────────────────── + + public List GetAllResolutions() + { + var all = new List(CuratedResolutions); + all.AddRange(_customResolutions); + return all; + } + + public void SaveDisplaySettings() + { + var cfg = ConfigFileHandler.Instance.SettingsConfig; + cfg.SetValue("display_settings", "window_mode", WindowMode); + cfg.SetValue("display_settings", "resolution", $"{Resolution.X}x{Resolution.Y}"); + cfg.SetValue("display_settings", "custom_resolutions", BuildCustomResolutionsString()); + cfg.Save(ConfigFileHandler.SettingsPath); + } + + public void SaveGameplaySettings() + { + var cfg = ConfigFileHandler.Instance.SettingsConfig; + cfg.SetValue("gameplay_settings", "gamepad_deadzone", GamepadDeadzone); + cfg.SetValue("gameplay_settings", "gamepad_sensitivity", GamepadSensitivity); + cfg.Save(ConfigFileHandler.SettingsPath); + } + + public void SaveInputSettings() + { + var cfg = ConfigFileHandler.Instance.SettingsConfig; + foreach (var action in InputMap.GetActions()) + { + foreach (var ev in InputMap.ActionGetEvents(action)) + { + if (ev is InputEventKey key) + { + cfg.SetValue("input_settings", action, (long)key.PhysicalKeycode); + break; + } + } + } + cfg.Save(ConfigFileHandler.SettingsPath); + } + + // ── apply helpers ──────────────────────────────────────────────────────── + + private void ApplyDisplaySettings() + { + switch (WindowMode) + { + case "fullscreen": + DisplayServer.WindowSetMode(DisplayServer.WindowMode.Fullscreen); + break; + case "borderless": + DisplayServer.WindowSetMode(DisplayServer.WindowMode.Windowed); + DisplayServer.WindowSetFlag(DisplayServer.WindowFlags.Borderless, true); + DisplayServer.WindowSetSize(Resolution); + break; + default: // "windowed" + DisplayServer.WindowSetMode(DisplayServer.WindowMode.Windowed); + DisplayServer.WindowSetFlag(DisplayServer.WindowFlags.Borderless, false); + DisplayServer.WindowSetSize(Resolution); + break; + } + } + + private void ApplyGamepadDeadzone() + { + foreach (var action in DeadzoneActions) + { + if (InputMap.HasAction(action)) + InputMap.ActionSetDeadzone(action, GamepadDeadzone); + } + } + + private static void ApplyInputBindings(ConfigFile cfg) + { + if (!cfg.HasSection("input_settings")) return; + + foreach (var actionName in cfg.GetSectionKeys("input_settings")) + { + if (!InputMap.HasAction(actionName)) continue; + + var scancode = (Key)(long)cfg.GetValue("input_settings", actionName); + + // Remove existing keyboard events for this action + var events = InputMap.ActionGetEvents(actionName); + foreach (var ev in events) + { + if (ev is InputEventKey) + InputMap.ActionEraseEvent(actionName, ev); + } + + // Add the saved key + var newKey = new InputEventKey { PhysicalKeycode = scancode }; + InputMap.ActionAddEvent(actionName, newKey); + } + } + + // ── util ───────────────────────────────────────────────────────────────── + + private static Vector2I ParseResolution(string s, Vector2I fallback) + { + var parts = s.Split('x'); + if (parts.Length == 2 && int.TryParse(parts[0], out var w) && int.TryParse(parts[1], out var h)) + return new Vector2I(w, h); + return fallback; + } + + private string BuildCustomResolutionsString() + { + var parts = new List(); + foreach (var r in _customResolutions) + parts.Add($"{r.X}x{r.Y}"); + return string.Join(",", parts); + } +} diff --git a/project.godot b/project.godot index 71cd161..35d8795 100644 --- a/project.godot +++ b/project.godot @@ -37,6 +37,7 @@ PhantomCameraManager="*res://addons/phantom_camera/scripts/managers/phantom_came AudioController="*res://objects/audio_controller.tscn" UIManager="*res://Autoloads/UIManager.cs" ConfigFileHandler="*res://Autoloads/ConfigFileHandler.cs" +SettingsManager="*res://Autoloads/SettingsManager.cs" SaveSystem="*res://Autoloads/SaveSystem.cs" ConsoleManager="*res://Autoloads/ConsoleManager.cs" LimboConsole="*uid://dyxornv8vwibg"