From 8cb838081c45a72e9c439db8bb595293349a88f7 Mon Sep 17 00:00:00 2001 From: psyGamer Date: Sat, 30 Nov 2024 17:33:04 +0100 Subject: [PATCH] feat(SyncCheck): Detect desnycs caused by unsafe-actions or failed assertions --- .../Source/SyncCheck/SyncChecker.cs | 28 +++++++++++++++++-- .../TAS/Input/Commands/AssertCommand.cs | 9 ++++++ .../Source/TAS/Manager.cs | 5 +++- 3 files changed, 38 insertions(+), 4 deletions(-) diff --git a/CelesteTAS-EverestInterop/Source/SyncCheck/SyncChecker.cs b/CelesteTAS-EverestInterop/Source/SyncCheck/SyncChecker.cs index f8ea2d99..6811aa85 100644 --- a/CelesteTAS-EverestInterop/Source/SyncCheck/SyncChecker.cs +++ b/CelesteTAS-EverestInterop/Source/SyncCheck/SyncChecker.cs @@ -21,6 +21,8 @@ internal static class SyncChecker { private static string resultFile = string.Empty; private static List wrongTimes = []; + private static bool wasUnsafe = false; + private static bool wasAssert = false; private static SyncCheckResult result = new(); @@ -45,7 +47,7 @@ public static void SetResultFile(string file) { resultFile = file; } - /// Indicates the current TAS has finished executing + /// Indicates that the current TAS has finished executing public static void ReportRunFinished() { if (!Active) { return; @@ -55,7 +57,13 @@ public static void ReportRunFinished() { // Check for desyncs SyncCheckResult.Entry entry; - if (Engine.Scene is not (Level { Completed: true } or LevelExit or AreaComplete)) { + if (wasUnsafe) { + // Performed unsafe action in safe-mode + entry = new SyncCheckResult.Entry(InputController.StudioTasFilePath, SyncCheckResult.Status.UnsafeAction, GameInfo.ExactStatus); + } else if (wasAssert) { + // Assertion failure + entry = new SyncCheckResult.Entry(InputController.StudioTasFilePath, SyncCheckResult.Status.AssertFailed, GameInfo.ExactStatus); + } else if (Engine.Scene is not (Level { Completed: true } or LevelExit or AreaComplete)) { // TAS did not finish GameInfo.Update(updateVel: false); entry = new SyncCheckResult.Entry(InputController.StudioTasFilePath, SyncCheckResult.Status.NotFinished, GameInfo.ExactStatus); @@ -81,12 +89,24 @@ public static void ReportRunFinished() { } } - /// Indicates a time command was updated with another time + /// Indicates that a time command was updated with another time public static void ReportWrongTime(string filePath, int fileLine, string oldTime, string newTime) { Logger.Error("CelesteTAS/SyncCheck", $"Detected wrong time in file '{filePath}' line {fileLine}: '{oldTime}' vs '{newTime}'"); wrongTimes.Add($"{filePath}\t{fileLine}\t{oldTime}\t{newTime}"); } + /// Indicates that an unsafe action was performed in safe-mode + public static void ReportUnsafeAction() { + Logger.Error("CelesteTAS/SyncCheck", $"Detected unsafe action"); + wasUnsafe = true; + } + + /// Indicates that an Assert-command failed + public static void ReportAssertFailed(string lineText, string filePath, int fileLine, string expected, string actual) { + Logger.Error("CelesteTAS/SyncCheck", $"Detected failed assertion '{lineText}' in file '{filePath}' line {fileLine}: Expected '{expected}', got '{actual}'"); + wasAssert = true; + } + [Initialize] private static void Initialize() { On.Celeste.Celeste.OnSceneTransition += On_Celeste_OnSceneTransition; @@ -118,6 +138,8 @@ private static void On_Celeste_OnSceneTransition(On.Celeste.Celeste.orig_OnScene private static void CheckFile(string file) { // Reset state wrongTimes.Clear(); + wasUnsafe = false; + wasAssert = false; Logger.Info("CelesteTAS/SyncCheck", $"Starting check for file: '{file}'"); diff --git a/CelesteTAS-EverestInterop/Source/TAS/Input/Commands/AssertCommand.cs b/CelesteTAS-EverestInterop/Source/TAS/Input/Commands/AssertCommand.cs index fb8e70f8..2462fd54 100644 --- a/CelesteTAS-EverestInterop/Source/TAS/Input/Commands/AssertCommand.cs +++ b/CelesteTAS-EverestInterop/Source/TAS/Input/Commands/AssertCommand.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.IO; using TAS.EverestInterop.InfoHUD; +using TAS.SyncCheck; using TAS.Utils; namespace TAS.Input.Commands; @@ -73,6 +74,7 @@ private static void Assert(CommandLine commandLine, int studioLine, string fileP Expected equal: {expected} But was: {actual}" """; + SyncChecker.ReportAssertFailed(commandLine.OriginalText, filePath, fileLine, expected, actual); AbortTas($"{prefix}{failureMessage}", true, 4f); } break; @@ -83,6 +85,7 @@ private static void Assert(CommandLine commandLine, int studioLine, string fileP Expected not equal: {expected} But was: {actual}" """; + SyncChecker.ReportAssertFailed(commandLine.OriginalText, filePath, fileLine, expected, actual); AbortTas($"{prefix}{failureMessage}", true, 4f); } break; @@ -93,6 +96,7 @@ private static void Assert(CommandLine commandLine, int studioLine, string fileP Expected contain: {expected} But was: {actual}" """; + SyncChecker.ReportAssertFailed(commandLine.OriginalText, filePath, fileLine, expected, actual); AbortTas($"{prefix}{failureMessage}", true, 4f); } break; @@ -102,6 +106,7 @@ private static void Assert(CommandLine commandLine, int studioLine, string fileP Expected not contain: {expected} But was: {actual}" """; + SyncChecker.ReportAssertFailed(commandLine.OriginalText, filePath, fileLine, expected, actual); AbortTas($"{prefix}{failureMessage}", true, 4f); } break; @@ -111,6 +116,7 @@ private static void Assert(CommandLine commandLine, int studioLine, string fileP Expected starts with: {expected} But was: {actual}" """; + SyncChecker.ReportAssertFailed(commandLine.OriginalText, filePath, fileLine, expected, actual); AbortTas($"{prefix}{failureMessage}", true, 4f); } break; @@ -120,6 +126,7 @@ private static void Assert(CommandLine commandLine, int studioLine, string fileP Expected not starts with: {expected} But was: {actual}" """; + SyncChecker.ReportAssertFailed(commandLine.OriginalText, filePath, fileLine, expected, actual); AbortTas($"{prefix}{failureMessage}", true, 4f); } break; @@ -129,6 +136,7 @@ private static void Assert(CommandLine commandLine, int studioLine, string fileP Expected ends with: {expected} But was: {actual}" """; + SyncChecker.ReportAssertFailed(commandLine.OriginalText, filePath, fileLine, expected, actual); AbortTas($"{prefix}{failureMessage}", true, 4f); } break; @@ -138,6 +146,7 @@ private static void Assert(CommandLine commandLine, int studioLine, string fileP Expected not ends with: {expected} But was: {actual}" """; + SyncChecker.ReportAssertFailed(commandLine.OriginalText, filePath, fileLine, expected, actual); AbortTas($"{prefix}{failureMessage}", true, 4f); } break; diff --git a/CelesteTAS-EverestInterop/Source/TAS/Manager.cs b/CelesteTAS-EverestInterop/Source/TAS/Manager.cs index 987c7960..8f6c61c2 100644 --- a/CelesteTAS-EverestInterop/Source/TAS/Manager.cs +++ b/CelesteTAS-EverestInterop/Source/TAS/Manager.cs @@ -89,7 +89,10 @@ public static void Update() { if (item is TextMenu.Header {Title: { } title} && (title == Dialog.Clean("OPTIONS_TITLE") || title == Dialog.Clean("MENU_VARIANT_TITLE") || title == Dialog.Clean("MODOPTIONS_EXTENDEDVARIANTS_PAUSEMENU_BUTTON").ToUpperInvariant()) || - item is TextMenuExt.HeaderImage {Image: "menu/everest"}) { + item is TextMenuExt.HeaderImage {Image: "menu/everest"}) + { + // TODO: Retrieve file-path and file-line + SyncChecker.ReportUnsafeAction(); DisableRun(); } }