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; } } }