Scenario play-test returns to the screen the editor was opened from
The play-test loads the game shell, which frees the screen the editor was opened from (the novel_editor hub). Both the scenario's end and Stop used to switch to the engine's main menu; the editor now remembers the route it left and switches back to it, falling back to the main menu only when it was not opened from a route. The tools_hub run of the windows suite plays its own scenario and checks both ways back.
This commit is contained in:
1 parent
55ef9416ef
commit
7b6ae80616
4 files changed
+142
-7
No files matched your search
@@ -36,6 +36,7 @@ namespace Cthangover.Core.UI.Tool.ScenarioEditor
|
||||
private Label _filePathLabel;
|
||||
|
||||
private bool _playActive;
|
||||
private string _returnRoute;
|
||||
private CanvasLayer _stopOverlay;
|
||||
|
||||
public ScenarioEditorWindow() : base("tools/scenario_editor/title")
|
||||
@@ -294,6 +295,13 @@ namespace Cthangover.Core.UI.Tool.ScenarioEditor
|
||||
|
||||
Visible = false;
|
||||
|
||||
// The screen the editor was opened from (the novel_editor hub, a
|
||||
// mod menu) is freed by the shell load below; remember its route so
|
||||
// the play-test returns there instead of to the engine's main menu.
|
||||
var sceneService = GetNodeOrNull<GodotSceneService>("/root/GodotSceneService");
|
||||
var current = sceneService?.CurrentGodotSceneName;
|
||||
_returnRoute = !string.IsNullOrEmpty(current) && SceneRouteRegistry.TryGet(current, out _) ? current : null;
|
||||
|
||||
_stopOverlay = CreateStopOverlay();
|
||||
var tree = Godot.Engine.GetMainLoop() as SceneTree;
|
||||
tree?.Root.AddChild(_stopOverlay);
|
||||
@@ -305,7 +313,6 @@ namespace Cthangover.Core.UI.Tool.ScenarioEditor
|
||||
sceneManager.PendingSceneName = metadata.Scene;
|
||||
}
|
||||
|
||||
var sceneService = GetNodeOrNull<GodotSceneService>("/root/GodotSceneService");
|
||||
sceneService?.LoadShell();
|
||||
|
||||
_playActive = true;
|
||||
@@ -329,7 +336,11 @@ namespace Cthangover.Core.UI.Tool.ScenarioEditor
|
||||
}
|
||||
|
||||
var sceneService = GetNodeOrNull<GodotSceneService>("/root/GodotSceneService");
|
||||
sceneService?.SwitchToMenu();
|
||||
if (_returnRoute != null && SceneRouteRegistry.TryGet(_returnRoute, out var route))
|
||||
sceneService?.SwitchRoute(route);
|
||||
else
|
||||
sceneService?.SwitchToMenu();
|
||||
_returnRoute = null;
|
||||
SetStatus(ToolUi.Tr("tools/scenario_editor/play_stopped"));
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
scene: home_basement
|
||||
priority: 0
|
||||
---
|
||||
delay 60 hidden=true
|
||||
end
|
||||
@@ -0,0 +1,105 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Cthangover.Core.Scenes;
|
||||
using Cthangover.Core.UI.Tool.ScenarioEditor;
|
||||
using Cthangover.Mods.Interface.Tool;
|
||||
using Cthangover.Tools.Common;
|
||||
using Cthangover.Tools.Hub;
|
||||
using Cthangover.Tools.Services;
|
||||
using Godot;
|
||||
|
||||
namespace Cthangover.Tools.Tests.Windows
|
||||
{
|
||||
/// <summary>
|
||||
/// Play-test round trip of the scenario editor opened from the
|
||||
/// <see cref="NovelEditorHub"/>: plays this suite's own scenario (so the
|
||||
/// editor's save-before-play rewrites a test file, not game content), lets
|
||||
/// the play end the way a finished dialog ends it
|
||||
/// (<see cref="SceneManager.IsTestPlayActive"/> drops), then plays again and
|
||||
/// presses Stop. Both times the game must come back to the hub with the
|
||||
/// editor visible — not to the engine's main menu. Advanced one step per
|
||||
/// driver tick; <see cref="Tick"/> returns true when done.
|
||||
/// </summary>
|
||||
public class ScenarioPlayReturnCheck
|
||||
{
|
||||
private const string SuiteModId = "tools__windows";
|
||||
private const string ScenarioPath = "scenarios/playtest_return.scenario";
|
||||
private const int ShellSettleTicks = 3;
|
||||
|
||||
private readonly Action<bool, string> _check;
|
||||
private ScenarioEditorWindow _window;
|
||||
private int _step;
|
||||
private int _settle;
|
||||
|
||||
/// <summary>Creates the check; <paramref name="check"/> records one assertion.</summary>
|
||||
public ScenarioPlayReturnCheck(Action<bool, string> check)
|
||||
{
|
||||
_check = check;
|
||||
}
|
||||
|
||||
/// <summary>Advances the round trip by one step; true once finished.</summary>
|
||||
public bool Tick(SceneTree tree)
|
||||
{
|
||||
switch (_step)
|
||||
{
|
||||
case 0:
|
||||
_window = (ScenarioEditorWindow)ToolWindow.ShowWindow(new ScenarioEditorWindow());
|
||||
var tabs = _window.FindChildren("*", "", true, false).OfType<ScenarioEditTabs>().FirstOrDefault();
|
||||
tabs?.OpenFile(ScenarioFileService.MakeKey(SuiteModId, ScenarioPath));
|
||||
_check(tabs?.HasActiveFile == true, "scenario_editor: test scenario opened");
|
||||
break;
|
||||
|
||||
case 1:
|
||||
case 4:
|
||||
PressButton(_window, "tools/scenario_editor/play");
|
||||
_settle = ShellSettleTicks;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
if (!InGame(tree))
|
||||
return false;
|
||||
SceneManager.IsTestPlayActive = false;
|
||||
break;
|
||||
|
||||
case 5:
|
||||
if (!InGame(tree))
|
||||
return false;
|
||||
PressButton(tree.Root, "tools/scenario_editor/stop");
|
||||
break;
|
||||
|
||||
case 3:
|
||||
case 6:
|
||||
if (tree.CurrentScene is not NovelEditorHub || !_window.Visible)
|
||||
return false;
|
||||
_check(true, _step == 3
|
||||
? "scenario_editor: the scenario's end returns to the editor hub"
|
||||
: "scenario_editor: Stop returns to the editor hub");
|
||||
if (_step == 6)
|
||||
{
|
||||
_window.QueueFree();
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
_step++;
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>The play-test left the hub for the game shell and the shell settled.</summary>
|
||||
private bool InGame(SceneTree tree)
|
||||
{
|
||||
if (tree.CurrentScene is NovelEditorHub || GodotSceneService.IsTransitioning || --_settle > 0)
|
||||
return false;
|
||||
_check(!_window.Visible, "scenario_editor: play hides the editor and enters the game");
|
||||
return true;
|
||||
}
|
||||
|
||||
private static void PressButton(Node root, string textKey)
|
||||
{
|
||||
var text = ToolUi.Tr(textKey);
|
||||
var button = root.FindChildren("*", nameof(Button), true, false).OfType<Button>().FirstOrDefault(b => b.Text == text);
|
||||
button?.EmitSignal(BaseButton.SignalName.Pressed);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -23,7 +23,9 @@ namespace Cthangover.Tools.Tests.Windows
|
||||
/// Launched as the <c>novel_editor</c> game (<c>--game=novel_editor --new</c>)
|
||||
/// it first waits for the collection's entry scene, the
|
||||
/// <see cref="NovelEditorHub"/>, and checks it lists a launcher button for
|
||||
/// every registered tool before opening the windows.
|
||||
/// every registered tool before opening the windows; after the windows it
|
||||
/// plays a scenario from the editor and checks that both the scenario's
|
||||
/// end and Stop return to the hub (<see cref="ScenarioPlayReturnCheck"/>).
|
||||
/// </summary>
|
||||
public partial class ToolWindowsTestDriverNode : Node
|
||||
{
|
||||
@@ -42,6 +44,8 @@ namespace Cthangover.Tools.Tests.Windows
|
||||
private double _elapsed;
|
||||
private bool _finished;
|
||||
private Window _window;
|
||||
private bool _inHub;
|
||||
private ScenarioPlayReturnCheck _playCheck;
|
||||
private readonly ToolWindowsErrorLogger _errors = new();
|
||||
|
||||
/// <summary>Creates the driver; <paramref name="shotsDir"/> null or empty disables screenshots.</summary>
|
||||
@@ -73,18 +77,25 @@ namespace Cthangover.Tools.Tests.Windows
|
||||
if (!Boot.IsReady || tree?.CurrentScene == null)
|
||||
return;
|
||||
|
||||
var inHub = ActiveGame.Id == NovelEditorHub.SceneName;
|
||||
if (inHub && tree.CurrentScene is not NovelEditorHub)
|
||||
_inHub = ActiveGame.Id == NovelEditorHub.SceneName;
|
||||
if (_inHub && tree.CurrentScene is not NovelEditorHub)
|
||||
return;
|
||||
|
||||
_tools.AddRange(ToolFactory.Instance.GetAll());
|
||||
Check(_tools.Count > 0, $"tools registered ({_tools.Count})");
|
||||
if (inHub)
|
||||
if (_inHub)
|
||||
CheckHub(tree.CurrentScene);
|
||||
OpenNext();
|
||||
return;
|
||||
}
|
||||
|
||||
if (_playCheck != null)
|
||||
{
|
||||
if (_playCheck.Tick(GetTree()))
|
||||
Finish();
|
||||
return;
|
||||
}
|
||||
|
||||
if (_window == null)
|
||||
return;
|
||||
|
||||
@@ -112,7 +123,10 @@ namespace Cthangover.Tools.Tests.Windows
|
||||
_toolIndex++;
|
||||
if (_toolIndex >= _tools.Count)
|
||||
{
|
||||
Finish();
|
||||
if (_inHub)
|
||||
_playCheck = new ScenarioPlayReturnCheck(Check);
|
||||
else
|
||||
Finish();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user