Files
mod_dialog_base/test_suites/autoplay/src/TestRunnerInitializer.cs
T

105 lines
5.2 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System.Collections.Generic;
using System.Linq;
using Cthangover.Core.Mods;
using Cthangover.Core.Utils;
using Godot;
namespace Mods.TestRunner
{
/// <summary>
/// Точка входа тестового мода: переносит интеграционную обвязку диалогов
/// (tests DialogAutoDriver + SceneSwitcher) в engine-мод. Активируется
/// только при наличии пользовательских флагов <c>--choices=</c> или
/// <c>--timeout=</c> (как <c>OS.GetCmdlineUserArgs()</c>; флаг <c>--scene=</c>
/// мод не читает — навигацией по сценам управляет ядро). При активации
/// создаёт <see cref="DialogAutoDriverNode"/> и добавляет его в корень
/// дерева через deferred-вызов: <c>OnModResourcesReady</c> срабатывает до
/// окончания построения сцены, прямой AddChild в этот момент отклоняется
/// движком, а драйверу всё равно нужно дождаться диалога (та же задержка
/// 0.5с, что у SceneSwitcher.ScheduleDriverAttach). Повторный
/// <c>ModManager.Reload()</c> не должен плодить драйверы — защищено
/// статическим флагом.
/// </summary>
public class TestRunnerInitializer : IModInitializer
{
private static bool driverQueued;
/// <summary>Инициализация per-mod не требуется — драйвер ставится на resources-ready.</summary>
public void OnModLoaded(string modId) { }
/// <summary>
/// Разбирает пользовательские аргументы командной строки и при
/// активационном флаге ставит драйвер автопроигрывания в корень дерева.
/// </summary>
public void OnModResourcesReady()
{
if (driverQueued)
return;
var args = OS.GetCmdlineUserArgs();
var hasChoices = args.Any(a => a.StartsWith("--choices=", System.StringComparison.Ordinal));
var hasTimeout = args.Any(a => a.StartsWith("--timeout=", System.StringComparison.Ordinal));
if (!hasChoices && !hasTimeout)
return;
var choices = ParseChoices(args);
var timeout = ParseTimeout(args);
var dialogs = ParseDialogs(args);
// Godot. квалифицирован: в dev-компиляции модов (ToolsModCompileTests)
// в глобальном пространстве имён существует namespace Engine из тестовой сборки,
// и неквалифицированное имя резолвится в него вместо Godot.Engine.
var root = (Godot.Engine.GetMainLoop() as SceneTree)?.Root;
if (root == null)
{
GameLogger.Log("TEST", "TestRunnerInitializer: tree root not available, driver not attached", LogLevel.Error);
return;
}
driverQueued = true;
GameLogger.Log("TEST",
$"TestRunnerInitializer: activating dialog auto-driver, choices=[{string.Join(",", choices)}], timeout={timeout?.ToString() ?? "none"}s, dialogs={dialogs?.ToString() ?? "idle"}");
// Deferred: сцена ещё строится; драйвер внутри сам выдерживает
// стартовую паузу и лениво ищет DialogBox, поэтому порядок с
// загрузкой сцены не важен.
ModRoot.AddDeferred(new DialogAutoDriverNode(choices, timeout, dialogs));
}
private static List<int> ParseChoices(string[] args)
{
var raw = args
.Where(a => a.StartsWith("--choices=", System.StringComparison.Ordinal))
.Select(a => a.Substring("--choices=".Length))
.FirstOrDefault();
if (string.IsNullOrEmpty(raw))
return new List<int>();
return raw.Split(',')
.Select(s => int.TryParse(s.Trim(), out var n) ? n : -1)
.Where(n => n >= 0)
.ToList();
}
private static int? ParseDialogs(string[] args)
{
var raw = args
.Where(a => a.StartsWith("--dialogs=", System.StringComparison.Ordinal))
.Select(a => a.Substring("--dialogs=".Length))
.FirstOrDefault();
return int.TryParse(raw, out var n) && n > 0 ? n : null;
}
private static float? ParseTimeout(string[] args)
{
var raw = args
.Where(a => a.StartsWith("--timeout=", System.StringComparison.Ordinal))
.Select(a => a.Substring("--timeout=".Length))
.FirstOrDefault();
return float.TryParse(raw, System.Globalization.CultureInfo.InvariantCulture, out var t) && t > 0
? t
: null;
}
}
}