Alle 86 Modelle der Godot-Referenz laufen durch die Blender→FBX-Pipeline
(nach bestandenem Vertical Function Test); jede Einheit zeigt ihr eigenes
Modell.
- Exportmanifest aus den Godot-Manifesten (tools/blender/make_manifest.py):
Units, Enemies, Props, Characters, Peoples, Buildings, Environment; die
drei Vergleichs-GLBs als Aliase. Neu in der Pipeline: Tangenten berechnet
Unity mit MikkTSpace, Generatoren laufen in einer temporären Kopie, die
Grüne Kluft wird wie das GLB zusammengefasst, Texturen kommen mit.
1.616 Blender- und 1.247 Unity-Prüfungen grün, zwei Exportläufe
byteidentisch; Kontaktbögen je Gruppe.
- Einheitenbibliothek nach Godots AssetLibrary: 70 Einträge der
Einheitengruppen, Figuren mit Skelett ersetzen das starre Modell ihrer ID.
Starre Modelle werden zur Laufzeit je Material zusammengefasst; Controller
werden an Ort und Stelle aktualisiert.
- Tests mit allen Modellen: EditMode 11/11, PlayMode 2/2. Vertical Function
Test Seed 2 DCE95C96556F3A1A und Seed 9 ab Runde 21 7B8E43AEFC0D60C5,
beide gleich dem Kern (Nachweise mit LUNE_EVIDENCE=u2a-batch; die Belege
von U2C und U2D bleiben unverändert).
- macOS-Player mit allen Modellen: 158-160 fps in der Übersicht
(116 Einheiten), 205-207 fps auf der Mid-Lane; Haupt- und Render-Thread
etwa doppelt so lang wie mit dem Platzhalter, Present-Ausreißer kürzer.
- Befund iCloud Drive: Konfliktkopien ("Name 2.ext") im Build-Cache ließen
den Build die Einheitenbibliothek mit altem Feldlayout schreiben; der
Player meldete sharedassets0.assets als beschädigt. LunePlayerBuild
entfernt solche Kopien vor dem Build und bricht ab, wenn während des
Builds neue entstehen. Bereits committete Kopien: Controller-Duplikate und
World/Generated 2.meta entfernt, drei U2D-Benchmarkläufe als -run1 bis
-run3 benannt.
- Dokumentation: U2-WORLD (Batch-Import), PORT-STATUS (Entscheidungen:
Modelle direkt in Git, Projektort außerhalb von iCloud Drive), PORT-QA.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
73 lines
3.9 KiB
C#
73 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.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));
|
|
}
|
|
}
|
|
}
|