champions-of-luneraria/Assets/Luneraria/Tests/View/PlayMode/SceneFrameRateTests.cs
Martin Stickelbroeck 2b86c0d3b5 U3B/U3C Zwischenstand: HUD-Bereiche, Eingabe und Befehle
Das G3-HUD steht im Spiel; die Abnahme (U3D) folgt.

- U3B: alle Bereiche und Komponenten aus Godot übertragen (LuneHud,
  Lanes, Bossgrotte, nächste Welle, Kaufkarten, Armee, Held mit Items und
  Talenten, Angriffschampions, Team, Ereignisse, Minimap, Tooltip,
  Optionen, Partieende). Porträts aus den echten Modellen, einmal gerendert.
- Offene G3-Punkte umgesetzt: „1 WELLE“ als Band am Porträtrand,
  Schadens- und Rüstungssymbole auf den Karten, Armeewert, Heldenporträts
  auf der Minimap. Befehlsplatz für die Ultimates der geplanten Helden
  reserviert (verborgen).
- U3C: LuneGame verdrahtet Befehle (gleiche Schnittstelle wie die Bots),
  Bereit mit 1-s-Sperre nach dem Kampf, Tempo und Pause, Tasten wie in G3,
  Kamera-Ziele, Auswahl im Feld, Planungsvorschau und Aufstellungsflächen.
  Ersetzt die U2-Debug-Anzeige. Bot-Partien und Benchmark unverändert.
- Szenen- und Bibliotheksbauer idempotent: Animator-Controller und
  Post-Processing-Profil werden an Ort und Stelle aktualisiert. Die Szene
  bekommt bei jedem Bau neue Objekt-IDs, der Inhalt ist gleich.
- Prüfung (Port von verify_g3, Teile A–H): 699 Prüfungen ohne Fehler.
  EditMode 23/23, PlayMode 12/12, Fingerabdrücke der Bot-Partien
  unverändert (DCE95C96556F3A1A, 7B8E43AEFC0D60C5).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 01:45:02 +02:00

74 lines
3.9 KiB
C#

using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Text;
using Luneraria.Core;
using NUnit.Framework;
using UnityEngine;
using UnityEngine.TestTools;
namespace Luneraria.View.Tests
{
/// <summary>
/// U2C in the real scene: the bot match of seed 2 runs with every view attached while the
/// player loop runs at 30, 60, 120 FPS and unlimited (Application.targetFrameRate, VSync off).
/// Each run must reproduce the core's fingerprint. The measured frame rates show that the
/// frame timing really differed. Writes docs/port/logs/u2c/scene-frame-rates.json.
/// </summary>
public sealed class SceneFrameRateTests
{
const float Speed = 24f;
[UnityTest]
public IEnumerator SceneMatchIsTheSameAtRealFrameRates()
{
var options = new MatchOptions { Seed = 2, HumanSlot = -1 };
LuneTrace core = LuneTrace.RunCore(options, 1, 0, "");
var report = new StringBuilder("{\n \"match\": \"seed 2, bots, speed " + Speed + "x\",\n \"core_hash\": \"" + core.Hash.ToString("X16") + "\",\n \"core_steps\": " + core.Steps + ",\n \"runs\": [\n");
var failures = new List<string>();
int[] rates = { 30, 60, 120, -1 };
for (int index = 0; index < rates.Length; index++)
{
QualitySettings.vSyncCount = 0;
Application.targetFrameRate = rates[index];
yield return PlayModeSupport.Load();
var driver = Object.FindAnyObjectByType<LuneMatchDriver>();
driver.HumanSlot = -1;
driver.Seed = 2;
driver.StartRound = 1;
driver.ExtraGold = 0;
driver.Speed = Speed;
driver.Restart();
driver.Runner.PlanningSeconds = .5;
driver.Runner.SettledSeconds = .5;
var rig = Object.FindAnyObjectByType<LuneCameraRig>();
rig.Interactive = false;
rig.LookAt(new Vec2(0, 0), 60f, true);
float start = Time.realtimeSinceStartup;
int frames = 0;
int maxSteps = 0;
while (driver.Runner.Current != LuneMatchRunner.Stage.Over && Time.realtimeSinceStartup - start < 600f)
{
yield return null;
frames++;
maxSteps = Mathf.Max(maxSteps, driver.Runner.StepsThisFrame);
}
float seconds = Time.realtimeSinceStartup - start;
LuneTrace trace = driver.Runner.Trace;
string label = rates[index] > 0 ? rates[index] + " fps" : "unlimited";
bool same = trace.Hash == core.Hash && trace.Steps == core.Steps;
if (!same)
failures.Add(label + ": " + trace.Hash.ToString("X16") + " / " + trace.Steps + " steps");
Debug.Log(string.Format("LUNE_SCENE_FPS {0}: {1} frames in {2:0.0} s = {3:0.0} fps, up to {4} steps per frame, hash {5:X16}, same={6}", label, frames, seconds, frames / seconds, maxSteps, trace.Hash, same));
report.AppendFormat(" {{\"target\": \"{0}\", \"frames\": {1}, \"seconds\": {2}, \"measured_fps\": {3}, \"max_steps_per_frame\": {4}, \"steps\": {5}, \"hash\": \"{6:X16}\", \"winner\": {7}, \"same_as_core\": {8}}}{9}\n",
label, frames, PlayModeSupport.Number(seconds), PlayModeSupport.Number(frames / seconds), maxSteps, trace.Steps, trace.Hash, driver.Runner.Match.Winner, same ? "true" : "false", index < rates.Length - 1 ? "," : "");
}
Application.targetFrameRate = -1;
report.Append(" ]\n}\n");
string logs = PlayModeSupport.Evidence("logs", "u2c");
Directory.CreateDirectory(logs);
File.WriteAllText(Path.Combine(logs, "scene-frame-rates.json"), report.ToString());
Assert.IsEmpty(failures, string.Join("\n", failures));
}
}
}