Add real-time lighting and shadows, training courses and targets, and animated salvage crates. Include bilingual assets and curated verification results.
96 lines
4.3 KiB
C#
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;
|
|
}
|
|
}
|
|
}
|