feat: add SettingsManager autoload for display, gamepad and input binding settings
This commit is contained in:
195
Autoloads/SettingsManager.cs
Normal file
195
Autoloads/SettingsManager.cs
Normal file
@@ -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<Vector2I> 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<Vector2I> _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<Vector2I> GetAllResolutions()
|
||||
{
|
||||
var all = new List<Vector2I>(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<string>();
|
||||
foreach (var r in _customResolutions)
|
||||
parts.Add($"{r.X}x{r.Y}");
|
||||
return string.Join(",", parts);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user