using System; using System.Collections.Generic; using System.IO; using Cthangover.BaseMenu; using Cthangover.Core.Bootstrap; using Cthangover.Core.Mods; using Cthangover.Core.Settings; using Cthangover.Core.Utils; using Godot; namespace Mods.DisplaySettingsTest { /// /// Display tab of the settings menu driven like a player, one step per tick /// so the window settles: windowed mode with a picked size gives a window of /// that size centred on the monitor; borderless fullscreen disables the size /// list; the frame rate cap and V-Sync are applied; every change is in the /// settings file at once; a "restart" (the file read anew and applied to a /// window put in another state) restores it all; reset returns the game /// defaults. The player's settings file is restored at the end. With a shots /// directory the main menu and every settings tab are saved as PNG. Prints /// [TEST_RESULT] name=display_settings. /// public partial class DisplaySettingsTestDriverNode : Node { private const string Display = "Window/Column/Body/Pages/Display/"; private const float TimeoutSeconds = 60f; private const string ResetButton = "Window/Column/Footer/Row/ResetButton"; private static readonly Vector2I WindowSize = new(1280, 720); private readonly List failures = new(); private readonly string settingsPath = ProjectSettings.GlobalizePath("user://settings.json"); private readonly string backup; private readonly string shotsDir; private SettingsMenu menu; private int passed; private int step; private int shotTab; private double elapsed; private double stepAt; private bool done; public DisplaySettingsTestDriverNode(string shotsDir) { this.shotsDir = shotsDir; backup = File.Exists(settingsPath) ? File.ReadAllText(settingsPath) : null; } public override void _Process(double delta) { if (done) return; elapsed += delta; if (elapsed > TimeoutSeconds) { failures.Add($"timeout at step {step}"); Finish(); return; } if (elapsed - stepAt < 0.5) return; stepAt = elapsed; try { RunStep(); } catch (Exception ex) { failures.Add($"step {step}: {ex.GetType().Name}: {ex.Message}"); Finish(); } } private void RunStep() { switch (step) { case 0: if (!Boot.IsReady) return; if (GetTree().CurrentScene?.FindChild("LauncherPlay", true, false) is Button launcherPlay) { launcherPlay.EmitSignal(BaseButton.SignalName.Pressed); return; } if (GetTree().CurrentScene is not MainMenu main) return; menu = main.GetNodeOrNull("SettingsPanel"); Check("settings panel exists", menu != null); if (menu == null) { Finish(); return; } Shot("main_menu"); menu.Open(); shotTab = 0; step = 100; return; case 100: // One tick per settings tab for the screenshots, then the Display tab checks. if (shotTab > 0) Shot("settings_" + shotTab); if (shotTab < 4 && !string.IsNullOrEmpty(shotsDir)) { menu.ShowTab(shotTab++); return; } menu.ShowTab(2); Check("the Display tab shows its page and the display reset", menu.GetNode("Window/Column/Body/Pages/Display").Visible && !menu.GetNode("Window/Column/Body/Pages/Audio").Visible && menu.GetNode