using System.Collections.Generic; using System.IO; using System.Linq; using Cthangover.Core.Bootstrap; using Cthangover.Core.Scenes; using Cthangover.Core.Utils; using Cthangover.Mods.Interface.Tool; using Cthangover.Mods.Rpg; using Cthangover.Tools.Common; using Cthangover.Tools.Services; using Cthangover.Mods.Interface.View; using Godot; namespace Cthangover.Tools.RpgEditor.Tests { /// /// Drives the RPG map editor through its controls like an author: layer /// buttons are pressed, the palette and the canvas get mouse events through /// their gui_input signal, Ctrl+Z goes into the window. That window is /// freed without saving, so the demo maps never change. A second window then /// creates a new map through the file selector's "+" and saves it: the game must /// know the map's scene at once (no mod reload); its files are deleted again. /// Result line: [TEST_RESULT] name=rpg_editor_edit passed=N failed=M. /// public partial class RpgEditorTestDriver : Node { private const float TickSeconds = 0.15f; private const float TimeoutSeconds = 60f; private const int RockTile = 11; private const string NewMap = "zz_editor_test_map"; private static readonly Vector2I PaintCell = new(3, 5); private static readonly Vector2I EventCell = new(2, 6); private readonly string shotsDir; private readonly List failures = new(); private int passed; private int step; private double elapsed; private RpgMapEditorWindow window; private RpgMapEditorCanvas canvas; private int eventsBefore; private string newMapMod; /// Creates the driver; null disables screenshots. public RpgEditorTestDriver(string shotsDir) { this.shotsDir = shotsDir; Name = "RpgEditorTestDriver"; var timer = new Timer { WaitTime = TickSeconds, Autostart = true }; AddChild(timer); timer.Timeout += Tick; } private void Tick() { if (step < 0) return; elapsed += TickSeconds; if (elapsed > TimeoutSeconds) { Fail($"timeout at step {step}"); Finish(); return; } try { RunStep(); } catch (System.Exception ex) { Fail($"step {step}: {ex.GetType().Name}: {ex.Message}"); Finish(); } } private void RunStep() { switch (step) { case 0: if (!Boot.IsReady || RpgWorldHost.Current?.View == null) return; var box = RpgInput.FindDialogBox(); if (box != null && box.IsRunning) { box.NextAction(); return; } window = ToolWindow.Open(); step++; return; case 1: canvas = window.FindChildren("*", "", true, false).OfType().FirstOrDefault(); if (canvas?.Document == null || canvas.Tileset == null) return; Check(canvas.Document.Map.ID.StartsWith("rpg_"), $"the editor opened a demo map ({canvas.Document.Map.ID})"); Shot("editor"); Press("tools/rpg_editor/layer_main"); Check(canvas.ActiveLayer == RpgEditLayer.Main, "the layer button switches the brush to the main layer"); ClickPalette(RockTile); Check(canvas.SelectedTile == RockTile, $"a palette click picks tile {RockTile}, got {canvas.SelectedTile}"); step++; return; case 2: var before = canvas.Document.Grid.GetTile(RpgLayer.Main, PaintCell.X, PaintCell.Y); ClickCanvas(PaintCell, false); Check(canvas.Document.Grid.GetTile(RpgLayer.Main, PaintCell.X, PaintCell.Y) == RockTile, "a canvas click paints the tile"); Check(window.Title.StartsWith("* "), "the window is marked dirty"); window.PushInput(new InputEventKey { Keycode = Key.Z, PhysicalKeycode = Key.Z, CtrlPressed = true, Pressed = true }); Check(canvas.Document.Grid.GetTile(RpgLayer.Main, PaintCell.X, PaintCell.Y) == before, "Ctrl+Z undoes the stroke"); Press("tools/rpg_editor/layer_events"); eventsBefore = canvas.Document.Map.Events.Count; ClickCanvas(EventCell, true); Check(canvas.Document.Map.Events.Count == eventsBefore + 1 && canvas.SelectedEvent != null, "a double click adds and selects an event"); step++; return; case 3: // Screenshots one tick after the action, when the frame shows it. Shot("events"); Press("tools/rpg_editor/layer_collision"); step++; return; case 4: Shot("collision"); window.QueueFree(); window = ToolWindow.Open(); step++; return; case 5: canvas = window.FindChildren("*", "", true, false).OfType().FirstOrDefault(); if (canvas?.Document == null) return; newMapMod = Selector().CurrentMod; DeleteNewMapFiles(); Selector().FindChildren("*", "", true, false).OfType