From e8515ef42b5606875cf3aff8628585c8598eb575 Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Sun, 23 May 2021 20:53:55 +0200 Subject: [PATCH] Fix events not firing and event exception handling Copying to Plugins folder on build Registering deterministic game engines automatically Each event handler is wrapped so if one fails it will still trigger the rest --- TechbloxModdingAPI/App/Client.cs | 6 +- TechbloxModdingAPI/App/Game.cs | 14 ++--- TechbloxModdingAPI/App/StateSyncRegPatch.cs | 26 --------- TechbloxModdingAPI/Block.cs | 4 +- TechbloxModdingAPI/Engines/EnginePatches.cs | 55 +++++++++++++++++++ TechbloxModdingAPI/Main.cs | 2 +- TechbloxModdingAPI/TechbloxModdingAPI.csproj | 4 ++ .../Tests/TechbloxModdingAPIPluginTest.cs | 7 ++- TechbloxModdingAPI/Tests/TestRoot.cs | 2 +- TechbloxModdingAPI/Utility/ExceptionUtil.cs | 34 ++++++++---- .../Utility/GameEngineManager.cs | 17 +++--- .../Utility/MenuEngineManager.cs | 4 +- 12 files changed, 111 insertions(+), 64 deletions(-) delete mode 100644 TechbloxModdingAPI/App/StateSyncRegPatch.cs create mode 100644 TechbloxModdingAPI/Engines/EnginePatches.cs diff --git a/TechbloxModdingAPI/App/Client.cs b/TechbloxModdingAPI/App/Client.cs index 420f004..9d636eb 100644 --- a/TechbloxModdingAPI/App/Client.cs +++ b/TechbloxModdingAPI/App/Client.cs @@ -27,8 +27,8 @@ namespace TechbloxModdingAPI.App /// An event that fires whenever the main menu is loaded. /// public static event EventHandler EnterMenu - { - add => appEngine.EnterMenu += value; + { + add => appEngine.EnterMenu += ExceptionUtil.WrapHandler(value); remove => appEngine.EnterMenu -= value; } @@ -37,7 +37,7 @@ namespace TechbloxModdingAPI.App /// public static event EventHandler ExitMenu { - add => appEngine.ExitMenu += value; + add => appEngine.ExitMenu += ExceptionUtil.WrapHandler(value); remove => appEngine.ExitMenu -= value; } diff --git a/TechbloxModdingAPI/App/Game.cs b/TechbloxModdingAPI/App/Game.cs index 8866165..4630ed9 100644 --- a/TechbloxModdingAPI/App/Game.cs +++ b/TechbloxModdingAPI/App/Game.cs @@ -93,7 +93,7 @@ namespace TechbloxModdingAPI.App /// public static event EventHandler Simulate { - add => buildSimEventEngine.SimulationMode += value; + add => buildSimEventEngine.SimulationMode += ExceptionUtil.WrapHandler(value); remove => buildSimEventEngine.SimulationMode -= value; } @@ -103,7 +103,7 @@ namespace TechbloxModdingAPI.App /// public static event EventHandler Edit { - add => buildSimEventEngine.BuildMode += value; + add => buildSimEventEngine.BuildMode += ExceptionUtil.WrapHandler(value); remove => buildSimEventEngine.BuildMode -= value; } @@ -112,7 +112,7 @@ namespace TechbloxModdingAPI.App /// public static event EventHandler Enter { - add => gameEngine.EnterGame += value; + add => gameEngine.EnterGame += ExceptionUtil.WrapHandler(value); remove => gameEngine.EnterGame -= value; } @@ -122,7 +122,7 @@ namespace TechbloxModdingAPI.App /// public static event EventHandler Exit { - add => gameEngine.ExitGame += value; + add => gameEngine.ExitGame += ExceptionUtil.WrapHandler(value); remove => gameEngine.ExitGame -= value; } @@ -478,12 +478,8 @@ namespace TechbloxModdingAPI.App { GameEngineManager.AddGameEngine(gameEngine); GameEngineManager.AddGameEngine(debugOverlayEngine); + GameEngineManager.AddGameEngine(buildSimEventEngine); MenuEngineManager.AddMenuEngine(menuEngine); } - - internal static void InitDeterministic(StateSyncRegistrationHelper stateSyncReg) - { - stateSyncReg.AddDeterministicEngine(buildSimEventEngine); - } } } diff --git a/TechbloxModdingAPI/App/StateSyncRegPatch.cs b/TechbloxModdingAPI/App/StateSyncRegPatch.cs deleted file mode 100644 index 87842d2..0000000 --- a/TechbloxModdingAPI/App/StateSyncRegPatch.cs +++ /dev/null @@ -1,26 +0,0 @@ -using System; -using System.Reflection; - -using RobocraftX.CR.MainGame; -using RobocraftX.StateSync; - -using HarmonyLib; - -namespace TechbloxModdingAPI.App -{ - [HarmonyPatch] - class StateSyncRegPatch - { - public static void Postfix(StateSyncRegistrationHelper stateSyncReg) - { - // register sim/build events engines - Game.InitDeterministic(stateSyncReg); - } - - [HarmonyTargetMethod] - public static MethodBase Target() - { - return AccessTools.Method(typeof(MainGameCompositionRoot), "DeterministicCompose").MakeGenericMethod(typeof(object)); - } - } -} diff --git a/TechbloxModdingAPI/Block.cs b/TechbloxModdingAPI/Block.cs index 432938c..ed4e2aa 100644 --- a/TechbloxModdingAPI/Block.cs +++ b/TechbloxModdingAPI/Block.cs @@ -74,7 +74,7 @@ namespace TechbloxModdingAPI /// public static event EventHandler Placed { - add => BlockEventsEngine.Placed += value; + add => BlockEventsEngine.Placed += ExceptionUtil.WrapHandler(value); remove => BlockEventsEngine.Placed -= value; } @@ -83,7 +83,7 @@ namespace TechbloxModdingAPI /// public static event EventHandler Removed { - add => BlockEventsEngine.Removed += value; + add => BlockEventsEngine.Removed += ExceptionUtil.WrapHandler(value); remove => BlockEventsEngine.Removed -= value; } diff --git a/TechbloxModdingAPI/Engines/EnginePatches.cs b/TechbloxModdingAPI/Engines/EnginePatches.cs new file mode 100644 index 0000000..f5774d9 --- /dev/null +++ b/TechbloxModdingAPI/Engines/EnginePatches.cs @@ -0,0 +1,55 @@ +using System.Reflection; +using HarmonyLib; +using RobocraftX; +using RobocraftX.CR.MainGame; +using RobocraftX.FrontEnd; +using RobocraftX.StateSync; +using Svelto.ECS; +using TechbloxModdingAPI.Utility; + +namespace TechbloxModdingAPI.Engines +{ + [HarmonyPatch] + class GameLoadedEnginePatch + { + public static void Postfix(StateSyncRegistrationHelper stateSyncReg) + { + // register all game engines, including deterministic + GameEngineManager.RegisterEngines(stateSyncReg); + } + + public static MethodBase TargetMethod() + { + return AccessTools.Method(typeof(MainGameCompositionRoot), "DeterministicCompose").MakeGenericMethod(typeof(object)); + } + } + + [HarmonyPatch] + class MenuLoadedEnginePatch + { + public static void Postfix(EnginesRoot enginesRoot) + { + // register menu engines + MenuEngineManager.RegisterEngines(enginesRoot); + } + + public static MethodBase TargetMethod() + { + return AccessTools.Method(typeof(FrontEndCompositionRoot), "Compose").MakeGenericMethod(typeof(object)); + } + } + + [HarmonyPatch] + class FullGameCreatedEnginePatch + { + public static void Postfix(FullGameCompositionRoot __instance) + { + FullGameFields.Init(__instance); + } + + public static MethodBase TargetMethod() + { + return AccessTools.DeclaredConstructor(typeof(FullGameCompositionRoot)); + } + } +} diff --git a/TechbloxModdingAPI/Main.cs b/TechbloxModdingAPI/Main.cs index 85637cd..af25bde 100644 --- a/TechbloxModdingAPI/Main.cs +++ b/TechbloxModdingAPI/Main.cs @@ -75,10 +75,10 @@ namespace TechbloxModdingAPI Block.Init(); BlockGroup.Init(); Wire.Init(); + Logging.MetaDebugLog($"Initializing Client"); GameClient.Init(); Client.Init(); Game.Init(); - //CustomBlock.Init(); // init UI Interface.IMGUI.Constants.Init(); Interface.IMGUI.IMGUIManager.Init(); diff --git a/TechbloxModdingAPI/TechbloxModdingAPI.csproj b/TechbloxModdingAPI/TechbloxModdingAPI.csproj index cb9d605..8af0a13 100644 --- a/TechbloxModdingAPI/TechbloxModdingAPI.csproj +++ b/TechbloxModdingAPI/TechbloxModdingAPI.csproj @@ -1085,4 +1085,8 @@ + + + + \ No newline at end of file diff --git a/TechbloxModdingAPI/Tests/TechbloxModdingAPIPluginTest.cs b/TechbloxModdingAPI/Tests/TechbloxModdingAPIPluginTest.cs index 03d03a5..8f5298f 100644 --- a/TechbloxModdingAPI/Tests/TechbloxModdingAPIPluginTest.cs +++ b/TechbloxModdingAPI/Tests/TechbloxModdingAPIPluginTest.cs @@ -13,6 +13,7 @@ using RobocraftX.Common.Input; using TechbloxModdingAPI.Blocks; using TechbloxModdingAPI.Commands; using TechbloxModdingAPI.Input; +using TechbloxModdingAPI.Interface.IMGUI; using TechbloxModdingAPI.Players; using TechbloxModdingAPI.Utility; @@ -210,10 +211,10 @@ namespace TechbloxModdingAPI.Tests Logging.Log("Compatible TechbloxScripting detected"); } // Interface test - /*Interface.IMGUI.Group uiGroup = new Group(new Rect(20, 20, 200, 500), "TechbloxModdingAPI_UITestGroup", true); - Interface.IMGUI.Button button = new Button("TEST"); + /*Group uiGroup = new Group(new Rect(20, 20, 200, 500), "TechbloxModdingAPI_UITestGroup", true); + var button = new Button("TEST"); button.OnClick += (b, __) => { Logging.MetaDebugLog($"Click on {((Interface.IMGUI.Button)b).Name}");}; - Interface.IMGUI.Button button2 = new Button("TEST2"); + var button2 = new Button("TEST2"); button2.OnClick += (b, __) => { Logging.MetaDebugLog($"Click on {((Interface.IMGUI.Button)b).Name}");}; Text uiText = new Text("This is text!", multiline: true); uiText.OnEdit += (t, txt) => { Logging.MetaDebugLog($"Text in {((Text)t).Name} is now '{txt}'"); }; diff --git a/TechbloxModdingAPI/Tests/TestRoot.cs b/TechbloxModdingAPI/Tests/TestRoot.cs index 2ac7c62..7177818 100644 --- a/TechbloxModdingAPI/Tests/TestRoot.cs +++ b/TechbloxModdingAPI/Tests/TestRoot.cs @@ -66,7 +66,7 @@ namespace TechbloxModdingAPI.Tests // flow control Game.Enter += (sender, args) => { GameTests().RunOn(RobocraftX.Schedulers.Lean.EveryFrameStepRunner_TimeRunningAndStopped); }; Game.Exit += (s, a) => state = "ReturningFromGame"; - Client.EnterMenu += (sender, args) => + Client.EnterMenu += (sender, args) => { if (state == "EnteringMenu") { diff --git a/TechbloxModdingAPI/Utility/ExceptionUtil.cs b/TechbloxModdingAPI/Utility/ExceptionUtil.cs index 0809e43..d11508b 100644 --- a/TechbloxModdingAPI/Utility/ExceptionUtil.cs +++ b/TechbloxModdingAPI/Utility/ExceptionUtil.cs @@ -6,7 +6,7 @@ namespace TechbloxModdingAPI.Utility public static class ExceptionUtil { /// - /// Invokes an event in a try-catch block to avoid propagating exceptions. + /// Invokes an event with a null-check. /// /// The event to emit, can be null /// Event sender @@ -14,16 +14,30 @@ namespace TechbloxModdingAPI.Utility /// Type of the event arguments public static void InvokeEvent(EventHandler handler, object sender, T args) { - try - { - handler?.Invoke(sender, args); - } - catch (Exception e) + handler?.Invoke(sender, args); + } + + /// + /// Wraps the event handler in a try-catch block to avoid propagating exceptions. + /// + /// The handler to wrap (not null) + /// Type of the event arguments + /// The wrapped handler + public static EventHandler WrapHandler(EventHandler handler) + { + return (sender, e) => { - EventRuntimeException wrappedException = - new EventRuntimeException($"EventHandler with arg type {typeof(T).Name} threw an exception", e); - Logging.LogWarning(wrappedException.ToString()); - } + try + { + handler(sender, e); + } + catch (Exception e1) + { + EventRuntimeException wrappedException = + new EventRuntimeException($"EventHandler with arg type {typeof(T).Name} threw an exception", e1); + Logging.LogWarning(wrappedException.ToString()); + } + }; } } } \ No newline at end of file diff --git a/TechbloxModdingAPI/Utility/GameEngineManager.cs b/TechbloxModdingAPI/Utility/GameEngineManager.cs index 603170c..fc51861 100644 --- a/TechbloxModdingAPI/Utility/GameEngineManager.cs +++ b/TechbloxModdingAPI/Utility/GameEngineManager.cs @@ -4,6 +4,7 @@ using System.Linq; using System.Text; using System.Threading.Tasks; +using RobocraftX.StateSync; using Svelto.ECS; using TechbloxModdingAPI.Engines; @@ -60,18 +61,20 @@ namespace TechbloxModdingAPI.Utility } } - public static void RegisterEngines(EnginesRoot enginesRoot) + public static void RegisterEngines(StateSyncRegistrationHelper helper) { + var enginesRoot = helper.enginesRoot; _lastEngineRoot = enginesRoot; - IEntityFactory factory = enginesRoot.GenerateEntityFactory(); + IEntityFactory factory = enginesRoot.GenerateEntityFactory(); foreach (var key in _gameEngines.Keys) { Logging.MetaDebugLog($"Registering Game IApiEngine {_gameEngines[key].Name}"); - enginesRoot.AddEngine(_gameEngines[key]); - if (typeof(IFactoryEngine).IsAssignableFrom(_gameEngines[key].GetType())) - { - ((IFactoryEngine)_gameEngines[key]).Factory = factory; - } + if (_gameEngines[key] is IDeterministicEngine detEngine) + helper.AddDeterministicEngine(detEngine); + else + enginesRoot.AddEngine(_gameEngines[key]); + if (_gameEngines[key] is IFactoryEngine factEngine) + factEngine.Factory = factory; } } } diff --git a/TechbloxModdingAPI/Utility/MenuEngineManager.cs b/TechbloxModdingAPI/Utility/MenuEngineManager.cs index c3dd29c..3260563 100644 --- a/TechbloxModdingAPI/Utility/MenuEngineManager.cs +++ b/TechbloxModdingAPI/Utility/MenuEngineManager.cs @@ -69,9 +69,9 @@ namespace TechbloxModdingAPI.Utility { Logging.MetaDebugLog($"Registering Menu IApiEngine {_menuEngines[key].Name}"); enginesRoot.AddEngine(_menuEngines[key]); - if (typeof(IFactoryEngine).IsAssignableFrom(_menuEngines[key].GetType())) + if (_menuEngines[key] is IFactoryEngine factEngine) { - ((IFactoryEngine)_menuEngines[key]).Factory = factory; + factEngine.Factory = factory; } } }