Files
unity/Assets/Editor/LightingSmoke.cs
T
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

96 lines
4.3 KiB
C#

using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using UnityEditor;
using UnityEngine;
using UnityEngine.Profiling;
using UnityEngine.Rendering;
namespace Ironspore.Editor
{
public static class LightingSmoke
{
static int step, initialChassis;
static double nextAt;
static Result result;
const string Output = "Docs/QA/Lighting/TestResults/WorldCycles.json";
public static string Begin()
{
if (!EditorApplication.isPlaying || !GameSession.Active || result != null)
throw new InvalidOperationException("A playing, idle GameSession is required.");
initialChassis = GameSession.Active.SelectedChassis;
if (GameSession.Active.InField) GameSession.Active.EndSortie(true);
result = new Result();
step = 0;
nextAt = EditorApplication.timeSinceStartup + 1;
EditorApplication.update += Tick;
return "Three chassis and three field/hangar cycles scheduled; report in about 14 seconds.";
}
static void Tick()
{
if (EditorApplication.timeSinceStartup < nextAt) return;
nextAt = EditorApplication.timeSinceStartup + 1;
try
{
var game = GameSession.Active;
if (step >= 12)
{
result.passed = result.rows.TrueForAll(row => row.passed);
Finish();
return;
}
int phase = step % 4;
if (phase == 0) { game.SelectedChassis = step / 4; game.StartTrial(); }
if (phase == 1)
{
Snapshot("field", false);
typeof(MechPilot).GetProperty("FirstPerson").SetValue(game.Pilot, true);
}
if (phase == 2) { Snapshot("first-person", true); game.EndSortie(true); }
if (phase == 3) Snapshot("hangar", false);
step++;
}
catch (Exception error) { result.error = error.ToString(); Finish(); }
}
static void Snapshot(string phase, bool requireShadowOnly)
{
var world = GameObject.Find("World");
int roots = 0, suns = 0, spots = 0, shadowOnly = 0;
foreach (var candidate in UnityEngine.Object.FindObjectsByType<WorldLighting>())
if (candidate.gameObject.activeInHierarchy) roots++;
foreach (var light in world.GetComponentsInChildren<Light>())
{
if (light.type == LightType.Directional) suns++;
if (light.type == LightType.Spot && light.enabled) spots++;
}
foreach (var renderer in world.GetComponentsInChildren<Renderer>())
if (renderer.enabled && renderer.shadowCastingMode == ShadowCastingMode.ShadowsOnly) shadowOnly++;
int probes = world.GetComponentsInChildren<ReflectionProbe>().Length;
int cameras = world.GetComponentsInChildren<Camera>().Length;
result.rows.Add(new Row { phase = phase, chassis = GameSession.Active.SelectedChassis, worlds = roots, suns = suns, enabledSpots = spots, probes = probes, cameras = cameras, shadowOnlyRenderers = shadowOnly, allocatedMiB = Profiler.GetTotalAllocatedMemoryLong() / 1048576.0, reflectionReady = world.GetComponent<WorldLighting>().ReflectionReady, passed = roots == 1 && suns == 1 && probes == 1 && cameras == 1 && spots <= 1 && (!requireShadowOnly || shadowOnly > 0) });
}
static void Finish()
{
EditorApplication.update -= Tick;
if (GameSession.Active) GameSession.Active.SelectedChassis = initialChassis;
Directory.CreateDirectory(Path.GetDirectoryName(Output));
File.WriteAllText(Output, JsonUtility.ToJson(result, true));
result = null;
}
[Serializable] sealed class Result { public bool passed; public string error; public List<Row> rows = new List<Row>(); }
[Serializable] sealed class Row
{
public string phase;
public int chassis, worlds, suns, enabledSpots, probes, cameras, shadowOnlyRenderers;
public double allocatedMiB;
public bool passed, reflectionReady;
}
}
}