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 { /// /// 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. /// 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(); 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(); 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(); 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)); } } }