using System; using System.Collections.Generic; using System.Linq; using TMPro; using UnityEditor; using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.UI; // The picker's selection and keyboard rules, driven through the events the game delivers: Move and Cancel reach the // focused Launch button through ExecuteEvents, as the Input System UI module sends them, and a click is Button.onClick. // // Unity -batchmode -projectPath -executeMethod ScenarioPickerVerify.Run -logFile // // Exits the Editor itself, 0 when every rule holds and 1 on the first that does not. public static class ScenarioPickerVerify { private sealed class Fake : Scenario { private readonly uint _seed; private readonly bool _ambient; public Fake(string name, uint seed = 0, bool ambient = true) { Name = name; _seed = seed; _ambient = ambient; } public override string Name { get; } public override string Id => Name.ToLowerInvariant(); public override string Brief => $"brief of {Name}"; public override uint Seed => _seed; public override bool Ambient => _ambient; public override Galaxy Generate(GalaxyStage stage) => throw new NotSupportedException(); public override void Stage(ScenarioStage stage) => throw new NotSupportedException(); } private sealed class Screen { public ScenarioPicker Picker; public PropertiesPanel List, Detail; public Button[] Rows; public Button Back, Launch; public readonly List Launched = new List(); public int Backs; public Scenario[] A, B, C; } public static void Run() { try { SelectionFollowsClicksAndArrows(); ArrowsStopAtTheEnds(); LeftAndRightAreIgnored(); LaunchIsOnePathAndFocusClears(); CancelAndBackAreOnePath(); DetailPaneFollowsSelection(); OneGroupHasNoSectionLabel(); LaunchesOnceHoweverItIsReached(); ArrowingThroughTheRealListKeepsTheSelectionVisible(); Debug.Log("[ScenarioPickerVerify] ok"); EditorApplication.Exit(0); } catch (Exception exception) { Debug.LogException(exception); EditorApplication.Exit(1); } } private static void Require(bool condition, string what) { if (!condition) throw new InvalidOperationException(what); } private static Screen Build(bool oneGroup = false, bool real = false) { var (menu, list, detail) = ScenarioPickerCapture.Build(); // Build opens the scene afresh, which destroys the previous EventSystem. var events = new GameObject("verify EventSystem").AddComponent(); // Edit mode never calls OnEnable, which is what registers an EventSystem as current. typeof(EventSystem).GetMethod("OnEnable", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance).Invoke(events, null); var screen = new Screen { List = list, Detail = detail, A = new Scenario[] { new Fake("Alpha", 7), new Fake("Beta") }, B = new Scenario[] { new Fake("Gamma", ambient: false) }, C = new Scenario[] { new Fake("Delta"), new Fake("Echo") } }; var groups = real ? ScenarioPickerCapture.AllGroups() : oneGroup ? new List<(string label, Scenario[] scenarios)> { ("modes", screen.A) } : new List<(string label, Scenario[] scenarios)> { ("modes", screen.A), ("development", screen.B), ("test arenas", screen.C) }; // The menu builds a panel while it is inactive and shows it afterwards; the picker must find its scroll all the same. if (real) list.gameObject.SetActive(false); screen.Picker = ScenarioPicker.Show(list, detail, groups, screen.Launched.Add, () => screen.Backs++, menu.Dialog.Confirm); var buttons = list.GetComponentsInChildren(false).Where(button => !button.transform.IsChildOf(detail.transform)).Select(button => button.Button).ToArray(); screen.Rows = buttons.Take(buttons.Length - 1).ToArray(); screen.Back = buttons.Last(); screen.Launch = detail.GetComponentsInChildren