Files
unity/Assets/Editor/RecoverySmoke.cs
RCiBot eb819c6688 feat: improve map lighting and expand the playable training range
Add real-time lighting and shadows, training courses and targets, and animated salvage crates. Include bilingual assets and curated verification results.
2026-11-12 18:03:04 +08:00

158 lines
6.0 KiB
C#

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;
static string folder;
public static string Begin(string outputFolder = "Docs/QA/Prototype")
{
folder = outputFolder;
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<Keyboard>("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<CharacterController>();
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<EnemyUnit>())
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<EnemyUnit>())
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(folder + "/TestResults");
File.WriteAllText(folder + "/TestResults/RecoveryPlayback.json", JsonUtility.ToJson(result, true));
}
[Serializable]
sealed class Result
{
public bool passed, search, interruption, shipped, crossZone, loss, arrivalDoesNotBank, boarding;
public string error;
}
}
}