using System.IO; using NeoModLoader.services; using UnityEngine; namespace IdleSpectator; /// /// One-shot automated session: enable spectator when a world is loaded, run for a while, /// log a pass/fail verdict from StateProbe, then quit. Arm with an empty .auto-test /// file in the mod folder (deleted when finished). /// public static class AutoTest { private const float DurationSeconds = 50f; private static bool _armed; private static bool _running; private static float _startedAt = -1f; private static bool _finished; public static void Update() { if (_finished) { return; } if (!_armed) { string path = AutoTestPath(); if (string.IsNullOrEmpty(path) || !File.Exists(path)) { return; } _armed = true; LogService.LogInfo("[IdleSpectator][AUTOTEST] armed - waiting for world load"); } if (!Config.game_loaded || World.world == null || SmoothLoader.isLoading()) { return; } if (!_running) { _running = true; _startedAt = Time.unscaledTime; StateProbe.ResetCounters(); if (!SpectatorMode.Active) { SpectatorMode.SetActive(true); } LogService.LogInfo( $"[IdleSpectator][AUTOTEST] started for {DurationSeconds:0}s (idle={SpectatorMode.Active})"); return; } if (Time.unscaledTime - _startedAt < DurationSeconds) { return; } _finished = true; int bad = StateProbe.BadEventCount; int states = StateProbe.StateEventCount; bool focusOk = MoveCamera.hasFocusUnit(); bool barHidden = !CanvasMain.isBottomBarShowing(); bool pass = bad == 0 && SpectatorMode.Active && focusOk && barHidden; string verdict = pass ? "PASS" : "FAIL"; LogService.LogInfo( $"[IdleSpectator][AUTOTEST] {verdict} duration={DurationSeconds:0}s states={states} bad={bad} idle={SpectatorMode.Active} focus={focusOk} powerBar={!barHidden}"); try { string path = AutoTestPath(); if (!string.IsNullOrEmpty(path) && File.Exists(path)) { File.Delete(path); } } catch { // ignore } // Do not Application.Quit() - that often freezes the Steam/Unity process on Linux. LogService.LogInfo("[IdleSpectator][AUTOTEST] finished (leaving game running)"); if (SpectatorMode.Active) { SpectatorMode.SetActive(false); } } private static string AutoTestPath() { string modFolder = ModClass.ModFolder; if (string.IsNullOrEmpty(modFolder)) { return null; } return Path.Combine(modFolder, ".auto-test"); } }