diff --git a/GamecraftModdingAPI/Blocks/MovementEngine.cs b/GamecraftModdingAPI/Blocks/MovementEngine.cs index f501513..7fe10d4 100644 --- a/GamecraftModdingAPI/Blocks/MovementEngine.cs +++ b/GamecraftModdingAPI/Blocks/MovementEngine.cs @@ -81,7 +81,7 @@ namespace GamecraftModdingAPI.Blocks public bool IsBuildMode() { - return SimModeUtil.IsBuildMode(this.entitiesDB); + return GamecraftModdingAPI.Utility.GameState.IsBuildMode(); } } } diff --git a/GamecraftModdingAPI/Blocks/RotationEngine.cs b/GamecraftModdingAPI/Blocks/RotationEngine.cs index 079d08f..7827e33 100644 --- a/GamecraftModdingAPI/Blocks/RotationEngine.cs +++ b/GamecraftModdingAPI/Blocks/RotationEngine.cs @@ -80,7 +80,7 @@ namespace GamecraftModdingAPI.Blocks public bool IsBuildMode() { - return SimModeUtil.IsBuildMode(this.entitiesDB); + return GamecraftModdingAPI.Utility.GameState.IsBuildMode(); } } } diff --git a/GamecraftModdingAPI/Blocks/SignalEngine.cs b/GamecraftModdingAPI/Blocks/SignalEngine.cs index b16a10b..41c9328 100644 --- a/GamecraftModdingAPI/Blocks/SignalEngine.cs +++ b/GamecraftModdingAPI/Blocks/SignalEngine.cs @@ -113,37 +113,43 @@ namespace GamecraftModdingAPI.Blocks public EGID GetClusterEGID(uint blockID, uint channel) { - uint[] connectedCubeIDs = GetConductivelyConnectedBlocks(blockID); - uint index; - ElectricityEntityStruct[] structs; - Logging.CommandLog($"Found {connectedCubeIDs.Length} connected cubes"); - for (int i = 0; i < connectedCubeIDs.Length; i++) + //uint[] connectedCubeIDs = GetConductivelyConnectedBlocks(blockID); + //uint index; + //ElectricityEntityStruct[] structs; + EGID elecEGID = new EGID(blockID, CommonExclusiveGroups.OWNED_BLOCKS_GROUP); + if (!entitiesDB.Exists(elecEGID)) { - if (entitiesDB.TryQueryEntitiesAndIndex(new EGID(connectedCubeIDs[i], CommonExclusiveGroups.OWNED_BLOCKS_GROUP), out index, out structs) - || entitiesDB.TryQueryEntitiesAndIndex(new EGID(connectedCubeIDs[i], CommonExclusiveGroups.FUNCTIONAL_BLOCK_PART_GROUP), out index, out structs)) - { - ref ConductiveClusterID clusterId = ref entitiesDB.QueryEntity(structs[index].ID).clusterId; - uint operatingChannel = entitiesDB.QueryEntity(structs[index].ID).operatingChannel; - Logging.CommandLog($"Channel {operatingChannel} found"); - EGID eGID = new EGID(channel, BlockIdentifiers.OUTPUT_SIGNAL_CHANNELS + clusterId.ID); - if (clusterId.initialized && clusterId.isConductive && entitiesDB.Exists(eGID)) - { - return eGID; - } - } + elecEGID = new EGID(blockID, CommonExclusiveGroups.FUNCTIONAL_BLOCK_PART_GROUP); } - // failsafe; not 100% reliable - foreach (ref ConductiveClusterIdStruct clusterIdStruct in entitiesDB.QueryEntities(CommonExclusiveGroups.FUNCTIONAL_CUBES_IN_BOTH_SIM_AND_BUILD)) + if (!entitiesDB.Exists(elecEGID)) { - EGID eGID = new EGID(channel, BlockIdentifiers.OUTPUT_SIGNAL_CHANNELS + clusterIdStruct.clusterId.ID); - if (clusterIdStruct.clusterId.initialized && clusterIdStruct.clusterId.isConductive && entitiesDB.Exists(eGID)) - { - return eGID; - } + return default; + } + ref ElectricityEntityStruct eStruct = ref entitiesDB.QueryEntity(elecEGID); + ref ConductiveClusterID clusterId = ref entitiesDB.QueryEntity(eStruct.ID).clusterId; + uint operatingChannel = entitiesDB.QueryEntity(eStruct.ID).operatingChannel; + EGID eGID = new EGID(channel, BlockIdentifiers.OUTPUT_SIGNAL_CHANNELS + clusterId.ID); + if (clusterId.initialized && clusterId.isConductive && entitiesDB.Exists(eGID)) + { + return eGID; } return default; } + public uint[] GetElectricBlocks() + { + uint count = entitiesDB.Count(CommonExclusiveGroups.FUNCTIONAL_CUBES_IN_BOTH_SIM_AND_BUILD[0]) + + entitiesDB.Count(CommonExclusiveGroups.FUNCTIONAL_CUBES_IN_BOTH_SIM_AND_BUILD[1]); + uint i = 0; + uint[] res = new uint[count]; + foreach (ref var ees in entitiesDB.QueryEntities(CommonExclusiveGroups.FUNCTIONAL_CUBES_IN_BOTH_SIM_AND_BUILD)) + { + res[i] = ees.ID.entityID; + i++; + } + return res; + } + private uint[] GetConductivelyConnectedBlocks(uint blockID) { if (!(stackInUse || listInUse)) @@ -152,21 +158,34 @@ namespace GamecraftModdingAPI.Blocks listInUse = true; cubesStack.Clear(); cubesList.FastClear(); - ConnectedCubesUtility.TreeTraversal.GetConnectedCubes(entitiesDB, blockID, cubesStack, cubesList, (in GridConnectionsEntityStruct g) => { return false; }); + ConnectedCubesUtility.TreeTraversal.GetConnectedCubes(entitiesDB, blockID, cubesStack, cubesList, (in GridConnectionsEntityStruct g) => { return g.isIsolator; }); uint[] res = cubesList.ToArray(); stackInUse = false; listInUse = false; + foreach (var id in res) + { + entitiesDB.QueryEntity(id, CommonExclusiveGroups.OWNED_BLOCKS_GROUP).isProcessed = false; + } return res; } - Stack cubeStack = new Stack(); - Gamecraft.DataStructures.FasterList cubeList = new Gamecraft.DataStructures.FasterList(); - ConnectedCubesUtility.TreeTraversal.GetConnectedCubes(entitiesDB, blockID, cubesStack, cubesList, (in GridConnectionsEntityStruct g) => { return false; }); - return cubeList.ToArray(); + else + { + Stack cubeStack = new Stack(); + Gamecraft.DataStructures.FasterList cubeList = new Gamecraft.DataStructures.FasterList(); + ConnectedCubesUtility.TreeTraversal.GetConnectedCubes(entitiesDB, blockID, cubesStack, cubesList, (in GridConnectionsEntityStruct g) => { return g.isIsolator; }); + uint[] res = cubesList.ToArray(); + foreach (var id in res) + { + entitiesDB.QueryEntity(id, CommonExclusiveGroups.OWNED_BLOCKS_GROUP).isProcessed = false; + } + return res; + } + } public bool IsSimulationMode() { - return SimModeUtil.IsSimulationMode(this.entitiesDB); + return GamecraftModdingAPI.Utility.GameState.IsSimulationMode(); } } } diff --git a/GamecraftModdingAPI/Blocks/Signals.cs b/GamecraftModdingAPI/Blocks/Signals.cs index 58c2e7c..91d50d1 100644 --- a/GamecraftModdingAPI/Blocks/Signals.cs +++ b/GamecraftModdingAPI/Blocks/Signals.cs @@ -24,7 +24,7 @@ namespace GamecraftModdingAPI.Blocks private static SignalEngine signalEngine = new SignalEngine(); /// - /// Set a channel to a value in the block's conductive block cluster + /// Set the electric block's channel to a value /// /// The block's id /// The channel (1 to 99) @@ -51,7 +51,7 @@ namespace GamecraftModdingAPI.Blocks } /// - /// Add a value to a channel signal in the block's conductive block cluster + /// Add a value to an electric block's channel signal /// /// The block's id /// The channel (1 to 99) @@ -80,12 +80,12 @@ namespace GamecraftModdingAPI.Blocks } /// - /// Get a channel's signal value from the block's conductive block cluster + /// Get a electric block's channel's signal value /// /// The block's id /// The channel (1 to 99) /// The signal value - public static float GetSignalConnectedBlocks(uint id, uint channel) + public static float GetSignalBlock(uint id, uint channel) { if (signalEngine.IsInGame && signalEngine.IsSimulationMode()) { @@ -108,6 +108,21 @@ namespace GamecraftModdingAPI.Blocks return 0f; } + /// + /// Get the ID of every electricity consumer in the game world + /// + /// The block IDs + public static uint[] GetElectricBlocks() + { + return signalEngine.GetElectricBlocks(); + } + + /// + /// Get the conductive cluster's unique identifier for an electric block + /// + /// The block's id + /// + /// The unique ID public static EGID GetClusterID(uint id, uint channel) { return signalEngine.GetClusterEGID(id, channel); diff --git a/GamecraftModdingAPI/Commands/SimpleCustomCommandEngine.cs b/GamecraftModdingAPI/Commands/SimpleCustomCommandEngine.cs index 1f3ce79..52b2a74 100644 --- a/GamecraftModdingAPI/Commands/SimpleCustomCommandEngine.cs +++ b/GamecraftModdingAPI/Commands/SimpleCustomCommandEngine.cs @@ -33,11 +33,13 @@ namespace GamecraftModdingAPI.Commands public void Dispose() { + GamecraftModdingAPI.Utility.Logging.MetaDebugLog($"Unregistering SimpleCustomCommandEngine {this.Name}"); CommandRegistrationHelper.Unregister(this.Name); } public void Ready() { + GamecraftModdingAPI.Utility.Logging.MetaDebugLog($"Registering SimpleCustomCommandEngine {this.Name}"); CommandRegistrationHelper.Register(this.Name, this.runCommand, this.Description); } diff --git a/GamecraftModdingAPI/Commands/SimpleCustomCommandEngine1.cs b/GamecraftModdingAPI/Commands/SimpleCustomCommandEngine1.cs index eec29ad..92cdab9 100644 --- a/GamecraftModdingAPI/Commands/SimpleCustomCommandEngine1.cs +++ b/GamecraftModdingAPI/Commands/SimpleCustomCommandEngine1.cs @@ -24,11 +24,13 @@ namespace GamecraftModdingAPI.Commands public void Dispose() { + GamecraftModdingAPI.Utility.Logging.MetaDebugLog($"Unregistering SimpleCustomCommandEngine {this.Name}"); CommandRegistrationHelper.Unregister(this.Name); } public void Ready() { + GamecraftModdingAPI.Utility.Logging.MetaDebugLog($"Registering SimpleCustomCommandEngine {this.Name}"); CommandRegistrationHelper.Register(this.Name, this.runCommand, this.Description); } diff --git a/GamecraftModdingAPI/Commands/SimpleCustomCommandEngine2.cs b/GamecraftModdingAPI/Commands/SimpleCustomCommandEngine2.cs index 0d602e3..31ec0cb 100644 --- a/GamecraftModdingAPI/Commands/SimpleCustomCommandEngine2.cs +++ b/GamecraftModdingAPI/Commands/SimpleCustomCommandEngine2.cs @@ -24,11 +24,13 @@ namespace GamecraftModdingAPI.Commands public void Dispose() { + GamecraftModdingAPI.Utility.Logging.MetaDebugLog($"Unregistering SimpleCustomCommandEngine {this.Name}"); CommandRegistrationHelper.Unregister(this.Name); } public void Ready() { + GamecraftModdingAPI.Utility.Logging.MetaDebugLog($"Registering SimpleCustomCommandEngine {this.Name}"); CommandRegistrationHelper.Register(this.Name, this.runCommand, this.Description); } diff --git a/GamecraftModdingAPI/Commands/SimpleCustomCommandEngine3.cs b/GamecraftModdingAPI/Commands/SimpleCustomCommandEngine3.cs index a48f9e7..2ccd5db 100644 --- a/GamecraftModdingAPI/Commands/SimpleCustomCommandEngine3.cs +++ b/GamecraftModdingAPI/Commands/SimpleCustomCommandEngine3.cs @@ -24,11 +24,13 @@ namespace GamecraftModdingAPI.Commands public void Dispose() { + GamecraftModdingAPI.Utility.Logging.MetaDebugLog($"Unregistering SimpleCustomCommandEngine {this.Name}"); CommandRegistrationHelper.Unregister(this.Name); } public void Ready() { + GamecraftModdingAPI.Utility.Logging.MetaDebugLog($"Registering SimpleCustomCommandEngine {this.Name}"); CommandRegistrationHelper.Register(this.Name, this.runCommand, this.Description); } diff --git a/GamecraftModdingAPI/Main.cs b/GamecraftModdingAPI/Main.cs index 40b82b7..4cff5cf 100644 --- a/GamecraftModdingAPI/Main.cs +++ b/GamecraftModdingAPI/Main.cs @@ -25,6 +25,8 @@ namespace GamecraftModdingAPI get { return harmony != null; } } + private static int referenceCount = 0; + /// /// Initializes the GamecraftModdingAPI. /// Call this as soon as possible after Gamecraft starts up. @@ -32,6 +34,8 @@ namespace GamecraftModdingAPI /// public static void Init() { + referenceCount++; + if (referenceCount > 1) { return; } if (IsInitialized) { Logging.LogWarning("GamecraftModdingAPI.Main.Init() called but API is already initialized!"); @@ -41,6 +45,9 @@ namespace GamecraftModdingAPI var currentAssembly = Assembly.GetExecutingAssembly(); harmony = HarmonyInstance.Create(currentAssembly.GetName().Name); harmony.PatchAll(currentAssembly); + // init utility + Logging.MetaDebugLog($"Initializing Utility"); + Utility.GameState.Init(); // create default event emitters Logging.MetaDebugLog($"Initializing Events"); EventManager.AddEventEmitter(new SimpleEventEmitterEngine(EventType.ApplicationInitialized, "GamecraftModdingAPIApplicationInitializedEventEmitter", false)); @@ -64,16 +71,20 @@ namespace GamecraftModdingAPI /// public static void Shutdown() { - if (!IsInitialized) + if (referenceCount > 0) { referenceCount--; } + if (referenceCount == 0) { - Logging.LogWarning("GamecraftModdingAPI.Main.Shutdown() called but API is not initialized!"); - return; + if (!IsInitialized) + { + Logging.LogWarning("GamecraftModdingAPI.Main.Shutdown() called but API is not initialized!"); + return; + } + Scheduler.Dispose(); + var currentAssembly = Assembly.GetExecutingAssembly(); + harmony.UnpatchAll(currentAssembly.GetName().Name); + harmony = null; + Logging.MetaLog($"{currentAssembly.GetName().Name} v{currentAssembly.GetName().Version} shutdown"); } - Scheduler.Dispose(); - var currentAssembly = Assembly.GetExecutingAssembly(); - harmony.UnpatchAll(currentAssembly.GetName().Name); - harmony = null; - Logging.MetaLog($"{currentAssembly.GetName().Name} v{currentAssembly.GetName().Version} shutdown"); } } } diff --git a/GamecraftModdingAPI/Tasks/Scheduler.cs b/GamecraftModdingAPI/Tasks/Scheduler.cs index 523329c..fbc5e2d 100644 --- a/GamecraftModdingAPI/Tasks/Scheduler.cs +++ b/GamecraftModdingAPI/Tasks/Scheduler.cs @@ -31,15 +31,30 @@ namespace GamecraftModdingAPI.Tasks public static readonly Svelto.Tasks.Lean.Unity.UpdateMonoRunner leanRunner = new Svelto.Tasks.Lean.Unity.UpdateMonoRunner("GamecraftModdingAPILean"); - public static void Schedule(ISchedulable toRun, bool extraLean = false) + public static void Schedule(ISchedulable toRun, bool extraLean = false, bool ui = false) { if (extraLean) { - toRun.Run().RunOn(extraLeanRunner); + if (ui) + { + toRun.Run().RunOn(extraLeanRunnerUI); + } + else + { + toRun.Run().RunOn(extraLeanRunner); + } + } else { - toRun.Run().RunOn(leanRunner); + if (ui) + { + toRun.Run().RunOn(leanRunnerUI); + } + else + { + toRun.Run().RunOn(leanRunner); + } } } diff --git a/GamecraftModdingAPI/Utility/GameState.cs b/GamecraftModdingAPI/Utility/GameState.cs new file mode 100644 index 0000000..ed096c4 --- /dev/null +++ b/GamecraftModdingAPI/Utility/GameState.cs @@ -0,0 +1,48 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace GamecraftModdingAPI.Utility +{ + /// + /// Utility to get the state of the current Gamecraft game + /// + public static class GameState + { + private static GameStateEngine gameEngine = new GameStateEngine(); + + /// + /// Is the game in edit mode? + /// + /// Whether the game is in build mode + public static bool IsBuildMode() + { + return gameEngine.IsBuildMode(); + } + + /// + /// Is the game in simulation mode? + /// + /// Whether the game is in simulation mode + public static bool IsSimulationMode() + { + return gameEngine.IsSimulationMode(); + } + + /// + /// Is a game loaded? + /// + /// Whether Gamecraft has a game open (false = Main Menu) + public static bool IsInGame() + { + return gameEngine.IsInGame; + } + + public static void Init() + { + GameEngineManager.AddGameEngine(gameEngine); + } + } +} diff --git a/GamecraftModdingAPI/Utility/GameStateEngine.cs b/GamecraftModdingAPI/Utility/GameStateEngine.cs new file mode 100644 index 0000000..e86b902 --- /dev/null +++ b/GamecraftModdingAPI/Utility/GameStateEngine.cs @@ -0,0 +1,43 @@ +using Svelto.ECS; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +using RobocraftX.SimulationModeState; + +namespace GamecraftModdingAPI.Utility +{ + class GameStateEngine : IApiEngine + { + public string Name { get; } = "GamecraftModdingAPIGameStateGameEngine"; + + public IEntitiesDB entitiesDB { set; private get; } + + private bool _isInGame = false; + + public bool IsInGame { get { return _isInGame; } } + + public void Dispose() + { + _isInGame = false; + } + + public void Ready() + { + _isInGame = true; + } + + public bool IsBuildMode() + { + return _isInGame && SimModeUtil.IsBuildMode(entitiesDB); + } + + public bool IsSimulationMode() + { + return _isInGame && SimModeUtil.IsSimulationMode(entitiesDB); + } + + } +}