using System; using System.IO; using UnityEditor; using UnityEngine; using UnityEngine.InputSystem; using UnityEngine.InputSystem.LowLevel; namespace Ironspore.Editor { public static class RecoverySmoke { static Keyboard keyboard; static float began; static int step; static ProfileStore testStore; static Result result; public static string Begin() { var game = GameSession.Active; if (!EditorApplication.isPlaying || !game) throw new Exception("Play mode required"); if (game.InField) game.EndSortie(true); game.SelectedChassis = 2; game.StartTrial(); game.Store.Commit(s => { s.alloy = 0; s.cells = 0; s.blueprints.Clear(); s.unlocked.Clear(); return true; }); testStore = game.Store; result = new Result(); step = 0; began = Time.realtimeSinceStartup; keyboard = InputSystem.AddDevice("RecoverySmokeKeyboard"); Application.runInBackground = true; EditorWindow.GetWindow(Type.GetType("UnityEditor.GameView,UnityEditor")).Focus(); EditorApplication.update += Tick; return "Recovery playback running for approximately 30 seconds."; } static void Teleport(Vector3 position) { var pilot = GameSession.Active.Pilot; var controller = pilot.GetComponent(); controller.enabled = false; pilot.transform.position = position; controller.enabled = true; } static void Tick() { try { Advance(); } catch (Exception ex) { result.error = ex.ToString(); Finish(); } } static void Advance() { var game = GameSession.Active; float t = Time.realtimeSinceStartup - began; var state = new KeyboardState(); if (t >= 1 && step == 0) { Teleport(new Vector3(-8, .1f, -8.3f)); step++; } if (t >= 1.2f && t < 1.35f) state.Press(Key.E); if (t >= 2 && step == 1) { Teleport(new Vector3(9, .1f, -2.3f)); step++; } if (t >= 2.2f && t < 2.35f) state.Press(Key.E); if (t >= 3 && step == 2) { result.search = game.Run.cargo.Count == 2; if (!result.search) throw new Exception("Two real crate interactions did not produce two stacks."); game.SelectedCargo.Add(game.Run.cargo[0].uid); game.CloseMenu(); step++; } if (t >= 3.5f && t < 9.5f) state.Press(Key.G); if (t >= 4.3f && step == 3) { game.Pilot.Damage(5); step++; } if (t >= 4.6f && step == 4) { result.interruption = game.CargoProgress < .5f && !game.Run.podUsed && game.Run.cargo.Count == 2; foreach (var enemy in UnityEngine.Object.FindObjectsByType()) enemy.Damage(10000); step++; } if (t >= 9.5f && step == 5) { result.shipped = game.Run.podUsed && game.Store.Data.blueprints.Count == 1 && game.Run.cargo.Count == 1; game.CompleteObjective(); game.NextZone(0); result.crossZone = game.Run.podUsed && game.Run.cargo.Count == 1; step++; } if (t >= 10.5f && step == 6) { game.Pilot.Damage(10000); step++; } if (t >= 11.5f && step == 7) { result.loss = testStore.Data.blueprints.Count == 1 && testStore.Data.cells == 0 && testStore.Data.run.cargo.Count == 0 && !testStore.Data.run.active; game.StartTrial(); testStore = game.Store; game.Store.Commit(s => { s.cells = 0; return true; }); foreach (var enemy in UnityEngine.Object.FindObjectsByType()) enemy.Damage(10000); game.Store.AddCargo("cells", 3, "extraction_sample"); Teleport(new Vector3(-19, .1f, -8)); game.World.CallExtraction(); step++; } if (t >= 27.5f && step == 8) { result.arrivalDoesNotBank = game.World.TransportReady && game.Run.active && game.Store.Data.cells == 0; step++; } if (t >= 28 && t < 28.2f) state.Press(Key.E); if (t >= 29 && step == 9) { result.boarding = testStore.Data.cells == 3 && !testStore.Data.run.active; result.passed = result.search && result.interruption && result.shipped && result.crossZone && result.loss && result.arrivalDoesNotBank && result.boarding; Finish(); return; } InputSystem.QueueStateEvent(keyboard, state); if (t > 35) throw new Exception("Recovery playback timeout"); } static void Finish() { EditorApplication.update -= Tick; if (keyboard != null && keyboard.added) InputSystem.RemoveDevice(keyboard); keyboard = null; Directory.CreateDirectory("Docs/QA/Prototype/TestResults"); File.WriteAllText("Docs/QA/Prototype/TestResults/RecoveryPlayback.json", JsonUtility.ToJson(result, true)); } [Serializable] sealed class Result { public bool passed, search, interruption, shipped, crossZone, loss, arrivalDoesNotBank, boarding; public string error; } } }