diff --git a/GamecraftModdingAPI/Blocks/BlockIdentifiers.cs b/GamecraftModdingAPI/Blocks/BlockIdentifiers.cs new file mode 100644 index 0000000..3c433e4 --- /dev/null +++ b/GamecraftModdingAPI/Blocks/BlockIdentifiers.cs @@ -0,0 +1,41 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +using Svelto.ECS; +using RobocraftX.Common; + +namespace GamecraftModdingAPI.Blocks +{ + /// + /// ExclusiveGroups and IDs used with blocks + /// + public static class BlockIdentifiers + { + /// + /// Blocks placed by the player + /// + public static ExclusiveGroup OWNED_BLOCKS { get { return CommonExclusiveGroups.OWNED_BLOCKS_GROUP; } } + + /// + /// Extra parts used in functional blocks + /// + public static ExclusiveGroup FUNCTIONAL_BLOCK_PARTS { get { return CommonExclusiveGroups.FUNCTIONAL_BLOCK_PART_GROUP; } } + + /// + /// Blocks which are disabled in Simulation mode + /// + public static ExclusiveGroup SIM_BLOCKS_DISABLED { get { return CommonExclusiveGroups.BLOCKS_DISABLED_IN_SIM_GROUP; } } + + public static ExclusiveGroup SPAWN_POINTS { get { return CommonExclusiveGroups.SPAWN_POINTS_GROUP; } } + + public static ExclusiveGroup SPAWN_POINTS_DISABLED { get { return CommonExclusiveGroups.SPAWN_POINTS_DISABLED_GROUP; } } + + /// + /// The ID of the most recently placed block + /// + public static uint LatestBlockID { get { return CommonExclusiveGroups.CurrentBlockEntityID - 1; } } + } +} diff --git a/GamecraftModdingAPI/Blocks/Movement.cs b/GamecraftModdingAPI/Blocks/Movement.cs new file mode 100644 index 0000000..1222b09 --- /dev/null +++ b/GamecraftModdingAPI/Blocks/Movement.cs @@ -0,0 +1,55 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +using Unity.Mathematics; + +namespace GamecraftModdingAPI.Blocks +{ + /// + /// Common block movement operations + /// + public static class Movement + { + private static MovementEngine movementEngine = new MovementEngine(); + + /// + /// Move a single block by a specific (x,y,z) amount + /// + /// The block's id + /// The movement amount (x,y,z) + /// + public static bool MoveBlock(uint id, float3 vector) + { + if (movementEngine.IsInGame && movementEngine.IsBuildMode()) + { + movementEngine.MoveBlock(id, vector); + return true; + } + return false; + } + + /// + /// Move all connected blocks by a specific (x,y,z) amount + /// + /// The starting block's id + /// The movement amount (x,y,z) + /// + public static bool MoveConnectedBlocks(uint id, float3 vector) + { + if (movementEngine.IsInGame && movementEngine.IsBuildMode()) + { + movementEngine.MoveConnectedBlocks(id, vector); + return true; + } + return false; + } + + public static void Init() + { + GamecraftModdingAPI.Utility.GameEngineManager.AddGameEngine(movementEngine); + } + } +} diff --git a/GamecraftModdingAPI/Blocks/MovementEngine.cs b/GamecraftModdingAPI/Blocks/MovementEngine.cs new file mode 100644 index 0000000..c644d15 --- /dev/null +++ b/GamecraftModdingAPI/Blocks/MovementEngine.cs @@ -0,0 +1,87 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +using RobocraftX; +using RobocraftX.Blocks; +using RobocraftX.Blocks.Ghost; +using RobocraftX.Common; +using RobocraftX.Multiplayer; +using RobocraftX.SimulationModeState; +using RobocraftX.UECS; +using Unity.Entities; +using Svelto.Context; +using Svelto.ECS; +using Svelto.ECS.EntityStructs; +using Unity.Transforms; +using Unity.Mathematics; +using UnityEngine; + +using GamecraftModdingAPI.Utility; + +namespace GamecraftModdingAPI.Blocks +{ + /// + /// Engine which executes block movement actions + /// + class MovementEngine : IApiEngine + { + public string Name { get; } = "GamecraftModdingAPIMovementGameEngine"; + + public IEntitiesDB entitiesDB { set; private get; } + + public bool IsInGame = false; + + public void Dispose() + { + IsInGame = false; + } + + public void Ready() + { + IsInGame = true; + } + + // implementations for Movement static class + + public float3 MoveBlock(uint blockID, float3 vector) + { + ref PositionEntityStruct posStruct = ref this.entitiesDB.QueryEntity(blockID, CommonExclusiveGroups.OWNED_BLOCKS_GROUP); + ref GridRotationStruct gridStruct = ref this.entitiesDB.QueryEntity(blockID, CommonExclusiveGroups.OWNED_BLOCKS_GROUP); + ref LocalTransformEntityStruct transStruct = ref this.entitiesDB.QueryEntity(blockID, CommonExclusiveGroups.OWNED_BLOCKS_GROUP); + ref UECSPhysicsEntityStruct phyStruct = ref this.entitiesDB.QueryEntity(blockID, CommonExclusiveGroups.OWNED_BLOCKS_GROUP); + // main (persistent) position + posStruct.position += vector; + // placement grid position + gridStruct.position += vector; + // rendered position + transStruct.position += vector; + // collision position + FullGameFields._physicsWorld.EntityManager.SetComponentData(phyStruct.uecsEntity, new Translation + { + Value = posStruct.position + }); + return posStruct.position; + } + + public float3 MoveConnectedBlocks(uint blockID, float3 vector) + { + Stack cubeStack = new Stack(); + Svelto.DataStructures.FasterList cubesToMove = new Svelto.DataStructures.FasterList(); + ConnectedCubesUtility.TreeTraversal.GetConnectedCubes(entitiesDB, blockID, cubeStack, cubesToMove, (in GridConnectionsEntityStruct g) => { return false; }); + for (int i = 0; i < cubesToMove.Count; i++) + { + MoveBlock(cubesToMove[i], vector); + entitiesDB.QueryEntity(cubesToMove[i], CommonExclusiveGroups.OWNED_BLOCKS_GROUP).isProcessed = false; + } + return this.entitiesDB.QueryEntity(blockID, CommonExclusiveGroups.OWNED_BLOCKS_GROUP).position; + } + + public bool IsBuildMode() + { + return this.entitiesDB.QueryUniqueEntity(SimulationModeStateExclusiveGroups.GAME_STATE_GROUP).simulationMode == SimulationMode.Build; + } + } +} diff --git a/GamecraftModdingAPI/Blocks/Rotation.cs b/GamecraftModdingAPI/Blocks/Rotation.cs new file mode 100644 index 0000000..4cf1a00 --- /dev/null +++ b/GamecraftModdingAPI/Blocks/Rotation.cs @@ -0,0 +1,55 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +using Unity.Mathematics; + +namespace GamecraftModdingAPI.Blocks +{ + /// + /// Common block movement operations + /// + public static class Rotation + { + private static RotationEngine rotationEngine = new RotationEngine(); + + /// + /// Rotate a single block by a specific amount in degrees + /// + /// The block's id + /// The rotation amount around the x,y,z-planes + /// + public static bool MoveBlock(uint id, float3 vector) + { + if (rotationEngine.IsInGame && rotationEngine.IsBuildMode()) + { + rotationEngine.RotateBlock(id, vector); + return true; + } + return false; + } + + /// + /// Rotate all connected blocks by a specific amount in degrees + /// + /// The starting block's id + /// The rotation around the x,y,z-planes + /// + public static bool MoveRotateBlocks(uint id, float3 vector) + { + if (rotationEngine.IsInGame && rotationEngine.IsBuildMode()) + { + rotationEngine.MoveConnectedBlocks(id, vector); + return true; + } + return false; + } + + public static void Init() + { + GamecraftModdingAPI.Utility.GameEngineManager.AddGameEngine(rotationEngine); + } + } +} diff --git a/GamecraftModdingAPI/Blocks/RotationEngine.cs b/GamecraftModdingAPI/Blocks/RotationEngine.cs new file mode 100644 index 0000000..09f61e2 --- /dev/null +++ b/GamecraftModdingAPI/Blocks/RotationEngine.cs @@ -0,0 +1,86 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +using RobocraftX; +using RobocraftX.Blocks; +using RobocraftX.Blocks.Ghost; +using RobocraftX.Common; +using RobocraftX.Multiplayer; +using RobocraftX.SimulationModeState; +using RobocraftX.UECS; +using Unity.Entities; +using Svelto.Context; +using Svelto.ECS; +using Svelto.ECS.EntityStructs; +using Unity.Transforms; +using Unity.Mathematics; +using UnityEngine; + +using GamecraftModdingAPI.Utility; + +namespace GamecraftModdingAPI.Blocks +{ + /// + /// Engine which executes block movement actions + /// + class RotationEngine : IApiEngine + { + public string Name { get; } = "GamecraftModdingAPIRotationGameEngine"; + + public IEntitiesDB entitiesDB { set; private get; } + + public bool IsInGame = false; + + public void Dispose() + { + IsInGame = false; + } + + public void Ready() + { + IsInGame = true; + } + + // implementations for Movement static class + + public float3 RotateBlock(uint blockID, Vector3 vector) + { + ref RotationEntityStruct rotStruct = ref this.entitiesDB.QueryEntity(blockID, CommonExclusiveGroups.OWNED_BLOCKS_GROUP); + ref GridRotationStruct gridStruct = ref this.entitiesDB.QueryEntity(blockID, CommonExclusiveGroups.OWNED_BLOCKS_GROUP); + ref LocalTransformEntityStruct transStruct = ref this.entitiesDB.QueryEntity(blockID, CommonExclusiveGroups.OWNED_BLOCKS_GROUP); + ref UECSPhysicsEntityStruct phyStruct = ref this.entitiesDB.QueryEntity(blockID, CommonExclusiveGroups.OWNED_BLOCKS_GROUP); + // main (persistent) position + Quaternion newRotation = (Quaternion)rotStruct.rotation; + newRotation.eulerAngles += vector; + rotStruct.rotation = (quaternion)newRotation; + // placement grid rotation + Quaternion newGridRotation = (Quaternion)gridStruct.rotation; + newGridRotation.eulerAngles += vector; + gridStruct.rotation = (quaternion)newGridRotation; + // rendered position + Quaternion newTransRotation = (Quaternion)rotStruct.rotation; + newTransRotation.eulerAngles += vector; + transStruct.rotation = newTransRotation; + // collision position + FullGameFields._physicsWorld.EntityManager.SetComponentData(phyStruct.uecsEntity, new Unity.Transforms.Rotation + { + Value = rotStruct.rotation + }); + return ((Quaternion)rotStruct.rotation).eulerAngles; + + } + + public float3 MoveConnectedBlocks(uint blockID, Vector3 vector) + { + throw new NotImplementedException(); + } + + public bool IsBuildMode() + { + return this.entitiesDB.QueryUniqueEntity(SimulationModeStateExclusiveGroups.GAME_STATE_GROUP).simulationMode == SimulationMode.Build; + } + } +} diff --git a/GamecraftModdingAPI/Commands/CommandManager.cs b/GamecraftModdingAPI/Commands/CommandManager.cs index 32af704..fe411a3 100644 --- a/GamecraftModdingAPI/Commands/CommandManager.cs +++ b/GamecraftModdingAPI/Commands/CommandManager.cs @@ -6,6 +6,8 @@ using System.Threading.Tasks; using Svelto.ECS; +using GamecraftModdingAPI.Utility; + namespace GamecraftModdingAPI.Commands { /// @@ -50,6 +52,7 @@ namespace GamecraftModdingAPI.Commands { foreach (var key in _customCommands.Keys) { + Logging.MetaDebugLog($"Registering ICustomCommandEngine {_customCommands[key].Name}"); enginesRoot.AddEngine(_customCommands[key]); } } diff --git a/GamecraftModdingAPI/Events/EventManager.cs b/GamecraftModdingAPI/Events/EventManager.cs index 11d012b..06bcffc 100644 --- a/GamecraftModdingAPI/Events/EventManager.cs +++ b/GamecraftModdingAPI/Events/EventManager.cs @@ -6,6 +6,8 @@ using System.Threading.Tasks; using Svelto.ECS; +using GamecraftModdingAPI.Utility; + namespace GamecraftModdingAPI.Events { /// @@ -91,10 +93,12 @@ namespace GamecraftModdingAPI.Events var entityFactory = enginesRoot.GenerateEntityFactory(); foreach (var key in _eventHandlers.Keys) { + Logging.MetaDebugLog($"Registering IEventHandlerEngine {_eventHandlers[key].Name}"); enginesRoot.AddEngine(_eventHandlers[key]); } foreach (var key in _eventEmitters.Keys) { + Logging.MetaDebugLog($"Registering IEventEmitterEngine {_eventEmitters[key].Name}"); _eventEmitters[key].Factory = entityFactory; enginesRoot.AddEngine(_eventEmitters[key]); } diff --git a/GamecraftModdingAPI/Events/MenuActivatedPatch.cs b/GamecraftModdingAPI/Events/MenuActivatedPatch.cs index accc1b1..451e71e 100644 --- a/GamecraftModdingAPI/Events/MenuActivatedPatch.cs +++ b/GamecraftModdingAPI/Events/MenuActivatedPatch.cs @@ -20,7 +20,7 @@ namespace GamecraftModdingAPI.Events { private static bool firstLoad = true; - public static void Postfix(ref EnginesRoot ____frontEndEnginesRoot) + public static void Postfix(ref EnginesRoot ____frontEndEnginesRoot, FullGameCompositionRoot __instance) { // register custom menu engines MenuEngineManager.RegisterEngines(____frontEndEnginesRoot); @@ -30,6 +30,7 @@ namespace GamecraftModdingAPI.Events if (firstLoad) { firstLoad = false; + FullGameFields.Init(__instance); Logging.Log("Dispatching App Init event"); EventManager.GetEventEmitter("GamecraftModdingAPIApplicationInitializedEventEmitter").Emit(); } diff --git a/GamecraftModdingAPI/Main.cs b/GamecraftModdingAPI/Main.cs index dd8bf54..6da21e3 100644 --- a/GamecraftModdingAPI/Main.cs +++ b/GamecraftModdingAPI/Main.cs @@ -20,39 +20,51 @@ namespace GamecraftModdingAPI { private static HarmonyInstance harmony; + public static bool IsInitialized { + get { return harmony != null; } + } + /// /// Initializes the GamecraftModdingAPI. - /// This should be called ASAP after Gamecraft starts up. + /// Call this as soon as possible after Gamecraft starts up. /// Ideally, this should be called from your main Plugin class's OnApplicationStart() method. /// public static void Init() { - var currentAssembly = Assembly.GetExecutingAssembly(); - if (harmony == null) + if (IsInitialized) { - harmony = HarmonyInstance.Create(currentAssembly.GetName().Name); - harmony.PatchAll(currentAssembly); + Logging.LogWarning("GamecraftModdingAPI.Main.Init() called but API is already initialized!"); + return; } + Logging.MetaDebugLog($"Patching Gamecraft"); + var currentAssembly = Assembly.GetExecutingAssembly(); + harmony = HarmonyInstance.Create(currentAssembly.GetName().Name); + harmony.PatchAll(currentAssembly); // create default event emitters + Logging.MetaDebugLog($"Initializing Events"); EventManager.AddEventEmitter(new SimpleEventEmitterEngine(EventType.ApplicationInitialized, "GamecraftModdingAPIApplicationInitializedEventEmitter", false)); EventManager.AddEventEmitter(new SimpleEventEmitterEngine(EventType.Menu, "GamecraftModdingAPIMenuActivatedEventEmitter", false)); - EventManager.AddEventEmitter(new SimpleEventEmitterEngine(EventType.MenuSwitchedTo, "GamecraftModdingAPIMenuSwitchedToEventEmitter", false)); // TODO + EventManager.AddEventEmitter(new SimpleEventEmitterEngine(EventType.MenuSwitchedTo, "GamecraftModdingAPIMenuSwitchedToEventEmitter", false)); EventManager.AddEventEmitter(new SimpleEventEmitterEngine(EventType.Game, "GamecraftModdingAPIGameActivatedEventEmitter", false)); - EventManager.AddEventEmitter(new SimpleEventEmitterEngine(EventType.GameReloaded, "GamecraftModdingAPIGameReloadedEventEmitter", false)); // TODO - EventManager.AddEventEmitter(new SimpleEventEmitterEngine(EventType.GameSwitchedTo, "GamecraftModdingAPIGameSwitchedToEventEmitter", false)); // TODO - Logging.Log($"{currentAssembly.GetName().Name} {currentAssembly.GetName().Version} init & patch complete"); + EventManager.AddEventEmitter(new SimpleEventEmitterEngine(EventType.GameReloaded, "GamecraftModdingAPIGameReloadedEventEmitter", false)); + EventManager.AddEventEmitter(new SimpleEventEmitterEngine(EventType.GameSwitchedTo, "GamecraftModdingAPIGameSwitchedToEventEmitter", false)); + // init block implementors + Logging.MetaDebugLog($"Initializing Blocks"); + Blocks.Movement.Init(); + Blocks.Rotation.Init(); + Logging.MetaLog($"{currentAssembly.GetName().Name} v{currentAssembly.GetName().Version} initialized"); } /// /// Shuts down & cleans up the GamecraftModdingAPI. - /// This should be called ASAP before Gamecraft quits. + /// Call this as late as possible before Gamecraft quits. /// Ideally, this should be called from your main Plugin class's OnApplicationQuit() method. /// public static void Shutdown() { var currentAssembly = Assembly.GetExecutingAssembly(); harmony.UnpatchAll(currentAssembly.GetName().Name); - Logging.Log($"{currentAssembly.GetName().Name} {currentAssembly.GetName().Version} shutdown & unpatch complete"); + Logging.MetaLog($"{currentAssembly.GetName().Name} v{currentAssembly.GetName().Version} shutdown"); } } } diff --git a/GamecraftModdingAPI/Tests/GamecraftModdingAPIPluginTest.cs b/GamecraftModdingAPI/Tests/GamecraftModdingAPIPluginTest.cs index bea2d9a..cdafb76 100644 --- a/GamecraftModdingAPI/Tests/GamecraftModdingAPIPluginTest.cs +++ b/GamecraftModdingAPI/Tests/GamecraftModdingAPIPluginTest.cs @@ -19,7 +19,7 @@ namespace GamecraftModdingAPI.Tests : IllusionPlugin.IEnhancedPlugin #endif { - public static HarmonyInstance harmony { get; protected set; } + private static HarmonyInstance harmony { get; set; } public string[] Filter { get; } = new string[] { "Gamecraft" }; @@ -64,6 +64,16 @@ namespace GamecraftModdingAPI.Tests "Exit", "Close Gamecraft without any prompts")); CommandManager.AddCommand(new SimpleCustomCommandEngine((float d) => { UnityEngine.Camera.main.fieldOfView = d; }, "SetFOV", "Set the player camera's field of view")); + CommandManager.AddCommand(new SimpleCustomCommandEngine( + (x,y,z) => { + bool success = GamecraftModdingAPI.Blocks.Movement.MoveConnectedBlocks( + GamecraftModdingAPI.Blocks.BlockIdentifiers.LatestBlockID, + new Unity.Mathematics.float3(x, y, z)); + if (!success) + { + GamecraftModdingAPI.Utility.Logging.CommandLogError("Blocks can only be moved in Build mode!"); + } + }, "MoveLastBlock", "Move the most-recently-placed block, and any connected blocks by the given offset")); } diff --git a/GamecraftModdingAPI/Utility/FullGameFields.cs b/GamecraftModdingAPI/Utility/FullGameFields.cs new file mode 100644 index 0000000..c90dbbe --- /dev/null +++ b/GamecraftModdingAPI/Utility/FullGameFields.cs @@ -0,0 +1,179 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +using DataLoader; +using Harmony; +using RobocraftX; +using RobocraftX.Blocks.GUI; +using RobocraftX.Common.Utilities; +using RobocraftX.GUI; +using RobocraftX.Multiplayer; +using RobocraftX.Rendering; +using Svelto.Context; +using Svelto.ECS; +using Svelto.ECS.Schedulers.Unity; +using UnityEngine; +using Unity.Entities; +using Unity.Physics.Systems; + +namespace GamecraftModdingAPI.Utility +{ + /// + /// Public access to the private variables in RobocraftX.FullGameCompositionRoot + /// + public static class FullGameFields + { + public static MultiplayerInitParameters _multiplayerParams + { get + { + return (MultiplayerInitParameters)fgcr?.Field("_multiplayerParams").GetValue(); + } + } + + public static EnginesRoot _frontEndEnginesRoot + { + get + { + return (EnginesRoot)fgcr?.Field("_frontEndEnginesRoot").GetValue(); + } + } + + public static EnginesRoot _mainGameEnginesRoot + { + get + { + return (EnginesRoot)fgcr?.Field("_mainGameEnginesRoot").GetValue(); + } + } + + public static World _physicsWorld + { + get + { + return (World)fgcr?.Field("_physicsWorld").GetValue(); + } + } + + public static World _renderingWorld + { + get + { + return (World)fgcr?.Field("_renderingWorld").GetValue(); + } + } + + public static SimpleSubmissionEntityViewScheduler _mainGameSubmissionScheduler + { + get + { + return (SimpleSubmissionEntityViewScheduler)fgcr?.Field("_mainGameSubmissionScheduler").GetValue(); + } + } + + public static BuildPhysicsWorld _physicsWorldSystem + { + get + { + return (BuildPhysicsWorld)fgcr?.Field("_physicsWorldSystem").GetValue(); + } + } + + public static UnityContext _contextHolder + { + get + { + return (UnityContext)fgcr?.Field("_contextHolder").GetValue(); + } + } + + public static GameObject _frontEndGo + { + get + { + return (GameObject)fgcr?.Field("_frontEndGo").GetValue(); + } + } + + public static GameObject _mainGameGo + { + get + { + return (GameObject)fgcr?.Field("_mainGameGo").GetValue(); + } + } + + public static PhysicsUtility _physicsUtility + { + get + { + return (PhysicsUtility)fgcr?.Field("_physicsUtility").GetValue(); + } + } + + public static UnityEntitySubmissionScheduler _frontEndSubmissionScheduler + { + get + { + return (UnityEntitySubmissionScheduler)fgcr?.Field("_frontEndSubmissionScheduler").GetValue(); + } + } + + public static LoadingScreenImplementer _loadingScreen + { + get + { + return (LoadingScreenImplementer)fgcr?.Field("_loadingScreen").GetValue(); + } + } + + public static IDataDB _dataDb + { + get + { + return (IDataDB)fgcr?.Field("_dataDb").GetValue(); + } + } + + public static LabelResourceManager _textBlockLabelResourceManager + { + get + { + return (LabelResourceManager)fgcr?.Field("_textBlockLabelResourceManager").GetValue(); + } + } + + public static LabelResourceManager _labelResourceManager + { + get + { + return (LabelResourceManager)fgcr?.Field("_labelResourceManager").GetValue(); + } + } + + public static ECSGameObjectResourceManager _eCsGameObjectResourceManager + { + get + { + return (ECSGameObjectResourceManager)fgcr?.Field("_eCsGameObjectResourceManager").GetValue(); + } + } + + public static bool _isQuitting + { + get + { + return (bool)fgcr?.Field("_isQuitting").GetValue(); + } + } + + private static Traverse fgcr; + + public static void Init(FullGameCompositionRoot instance) + { + fgcr = new Traverse(instance); + } + } +} diff --git a/GamecraftModdingAPI/Utility/GameEngineManager.cs b/GamecraftModdingAPI/Utility/GameEngineManager.cs index f3ba5d3..b50d37c 100644 --- a/GamecraftModdingAPI/Utility/GameEngineManager.cs +++ b/GamecraftModdingAPI/Utility/GameEngineManager.cs @@ -8,6 +8,9 @@ using Svelto.ECS; namespace GamecraftModdingAPI.Utility { + /// + /// Keeps track of custom game-modifying engines + /// public static class GameEngineManager { private static Dictionary _gameEngines = new Dictionary(); @@ -46,6 +49,7 @@ namespace GamecraftModdingAPI.Utility { foreach (var key in _gameEngines.Keys) { + Logging.MetaDebugLog($"Registering Game IApiEngine {_gameEngines[key].Name}"); enginesRoot.AddEngine(_gameEngines[key]); } } diff --git a/GamecraftModdingAPI/Utility/MenuEngineManager.cs b/GamecraftModdingAPI/Utility/MenuEngineManager.cs index d5c7458..aedc77c 100644 --- a/GamecraftModdingAPI/Utility/MenuEngineManager.cs +++ b/GamecraftModdingAPI/Utility/MenuEngineManager.cs @@ -50,6 +50,7 @@ namespace GamecraftModdingAPI.Utility { foreach (var key in _menuEngines.Keys) { + Logging.MetaDebugLog($"Registering Menu IApiEngine {_menuEngines[key].Name}"); enginesRoot.AddEngine(_menuEngines[key]); } }