diff --git a/Utility Mods/Stable/SCDefenseBlocks/Data/BlockVariantGroups_FieldGen.sbc b/Utility Mods/Stable/SCDefenseBlocks/Data/BlockVariantGroups_FieldGen.sbc index 3f121acfa..5887ed448 100644 --- a/Utility Mods/Stable/SCDefenseBlocks/Data/BlockVariantGroups_FieldGen.sbc +++ b/Utility Mods/Stable/SCDefenseBlocks/Data/BlockVariantGroups_FieldGen.sbc @@ -5,7 +5,7 @@ - Textures\GUI\Icons\MyGat.dds + Textures\GUI\Icons\Cubes\Core_Icon.dds [SI] Field Generator diff --git a/Utility Mods/Stable/SCDefenseBlocks/Data/Scripts/OneFuckingFolderDeeper/FieldGenerator/API/APIBase.cs b/Utility Mods/Stable/SCDefenseBlocks/Data/Scripts/OneFuckingFolderDeeper/FieldGenerator/API/APIBase.cs new file mode 100644 index 000000000..f16891d7f --- /dev/null +++ b/Utility Mods/Stable/SCDefenseBlocks/Data/Scripts/OneFuckingFolderDeeper/FieldGenerator/API/APIBase.cs @@ -0,0 +1,232 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Sandbox.ModAPI; +using VRage.Game.Entity; + +namespace FieldGenerator.API +{ + public class FieldGeneratorAPI + { + private bool _initialized; + + private Func _getFirstFieldGeneratorOnGrid; + + private Func _isSiegeActive; + private Action _setSiegeActive; + + private Func _isSiegeCooldownActive; + private Action _setSiegeCooldownActive; + + private Func _getSiegeCooldown; + private Action _setSiegeCooldown; + + private Func _getFieldPower; + private Action _setFieldPower; + + private Func _getMaximumFieldPower; + private Func_getMinimumFieldPower; + + private Func _getPowerDraw; + + private Func _getStability; + private Action _setStability; + + /// + /// Returns first valid field generator for the specified grid EntityID. + /// + /// EntityID of the cubegrid to check against. + /// IMyFunctionalBlock of the first field generator if one exists; otherwise, null. + public IMyFunctionalBlock GetFirstFieldGeneratorOnGrid(long entityID) => _getFirstFieldGeneratorOnGrid?.Invoke(entityID) ?? null; + + /// + /// Returns whether or not the specified block is in siege mode. + /// + /// Block to check. + /// true if siege mode is active; otherwise, false. + public bool IsSiegeActive(IMyFunctionalBlock block) => _isSiegeActive?.Invoke(block) ?? false; + + /// + /// Sets the siege mode state on the given block. + /// + /// Block whose siege state will be modified. + /// Whether siege mode should be active (true) or inactive (false). + public void SetSiegeActive(IMyFunctionalBlock block, bool Active) => _setSiegeActive?.Invoke(block, Active); + + /// + /// Returns whether or not the specified blocks siege mode is on cooldown. + /// + /// Block to check. + /// true if the cooldown is active; otherwise, false. + public bool IsSiegeCooldownActive(IMyFunctionalBlock block) => _isSiegeCooldownActive?.Invoke(block) ?? false; + + /// + /// Sets the siege mode cooldown state on the given block. + /// + /// Block whose cooldown state will be modified. + /// Whether the cooldown should be active (true) or inactive (false). + public void SetSiegeCooldownActive(IMyFunctionalBlock block, bool Active) => _setSiegeCooldownActive?.Invoke(block, Active); + + /// + /// Returns the specified blocks current cooldown time. + /// + /// Block to check. + /// The siege cooldown time, or 0 if no cooldown is active. + public int GetSiegeCooldown(IMyFunctionalBlock block) => _getSiegeCooldown?.Invoke(block) ?? 0; + + /// + /// Sets the cooldown time on the given block. + /// + /// Block whose cooldown will be modified. + /// Time to set the cooldown to, in seconds. + public void SetSiegeCooldown(IMyFunctionalBlock block, int Time) => _setSiegeCooldown?.Invoke(block, Time); + + /// + /// Returns the specified block current field power. + /// + /// Block to check. + /// The current field power. + public float GetFieldPower(IMyFunctionalBlock block) => _getFieldPower?.Invoke(block) ?? 0; + + /// + /// Sets the field power on the given block. + /// + /// Block whose field power will be modified. + /// + /// The field power to set as a float, expressed as a percentage and capped by minimum/maximum field power. + /// + public void SetFieldPower(IMyFunctionalBlock block, float Power) => _setFieldPower?.Invoke(block, Power); + + /// + /// Returns the specified blocks maximum field power. + /// + /// Block to check. + /// The maximum field power. + public float GetMaximumFieldPower(IMyFunctionalBlock block) => _getMaximumFieldPower?.Invoke(block) ?? 0; + + /// + /// Returns the specified block minimum field power. + /// + /// Block to check. + /// The minimum field power. + public float GetMinimumFieldPower(IMyFunctionalBlock block) => _getMinimumFieldPower?.Invoke(block) ?? 0; + + /// + /// Returns the specified blocks current power draw. + /// + /// Block to check. + /// The current power draw. + public float GetPowerDraw(IMyFunctionalBlock block) => _getPowerDraw?.Invoke(block) ?? 0; + + /// + /// Returns the specified blocks current stability. + /// + /// Block to check. + /// The current stability. + public float GetStability(IMyFunctionalBlock block) => _getStability?.Invoke(block) ?? 0; + + /// + /// Sets the stability on the given block. + /// + /// Block whose stability will be modified. + /// + /// The stability to set as a float, expressed as a percentage with a maximum of 100. + /// + public void SetStability(IMyFunctionalBlock block, float Stability) => _setStability?.Invoke(block, Stability); + + + private const long HandlerID = 917632; + private bool _APIRegistered; + private Action _ReadyCallback; + + public bool IsReady { get; private set; } + + + public void LoadAPI(Action ReadyCallback = null) + { + if (_APIRegistered) + throw new Exception($"{GetType().Name}.LoadAPI() should not be called multiple times!"); + + _ReadyCallback = ReadyCallback; + _APIRegistered = true; + MyAPIGateway.Utilities.RegisterMessageHandler(HandlerID, HandleMessage); + MyAPIGateway.Utilities.SendModMessage(HandlerID, "APIRequest"); + } + + public void UnloadAPI() + { + MyAPIGateway.Utilities.UnregisterMessageHandler(HandlerID, HandleMessage); + + ApiAssign(null); + + _APIRegistered = false; + _initialized = false; + IsReady = false; + } + + private void HandleMessage(object obj) + { + if (_initialized || obj is string) + return; + + var dict = obj as IReadOnlyDictionary; + + if (dict == null) + return; + + ApiAssign(dict); + + IsReady = true; + _ReadyCallback?.Invoke(); + } + + public void ApiAssign(IReadOnlyDictionary delegates) + { + _initialized = delegates != null; + + AssignMethod(delegates, "GetFirstFieldGeneratorOnGrid", ref _getFirstFieldGeneratorOnGrid); + + AssignMethod(delegates, "IsSiegeActive", ref _isSiegeActive); + AssignMethod(delegates, "SetSiegeActive", ref _setSiegeActive); + + AssignMethod(delegates, "IsSiegeCooldownActive", ref _isSiegeCooldownActive); + AssignMethod(delegates, "SetSiegeCooldownActive", ref _setSiegeCooldownActive); + + AssignMethod(delegates, "GetSiegeCooldown", ref _getSiegeCooldown); + AssignMethod(delegates, "SetSiegeCooldown", ref _setSiegeCooldown); + + AssignMethod(delegates, "GetFieldPower", ref _getFieldPower); + AssignMethod(delegates, "SetFieldPower", ref _setFieldPower); + + AssignMethod(delegates, "GetMaximumFieldPower", ref _getMaximumFieldPower); + AssignMethod(delegates, "GetMinimumFieldPower", ref _getMinimumFieldPower); + + AssignMethod(delegates, "GetPowerDraw", ref _getPowerDraw); + + AssignMethod(delegates, "GetStability", ref _getStability); + AssignMethod(delegates, "SetStability", ref _setStability); + } + + private void AssignMethod(IReadOnlyDictionary delegates, string name, ref T field) + where T : class + { + if (delegates == null) + { + field = null; + return; + } + + Delegate del; + if (!delegates.TryGetValue(name, out del)) + throw new Exception($"{GetType().Name} :: Couldn't find {name} delegate of type {typeof(T)}"); + + field = del as T; + + if (field == null) + throw new Exception( + $"{GetType().Name} :: Delegate {name} is not type {typeof(T)}, instead it's: {del.GetType()}"); + } + } +} diff --git a/Utility Mods/Stable/SCDefenseBlocks/Data/Scripts/OneFuckingFolderDeeper/FieldGenerator/API/APIServer.cs b/Utility Mods/Stable/SCDefenseBlocks/Data/Scripts/OneFuckingFolderDeeper/FieldGenerator/API/APIServer.cs new file mode 100644 index 000000000..106649c4a --- /dev/null +++ b/Utility Mods/Stable/SCDefenseBlocks/Data/Scripts/OneFuckingFolderDeeper/FieldGenerator/API/APIServer.cs @@ -0,0 +1,242 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Sandbox.ModAPI; +using VRage.Game.Entity; +using VRage.ModAPI; +using FieldGeneratorCore = Starcore.FieldGenerator.FieldGenerator; + +namespace Starcore.FieldGenerator.API +{ + public class APIProvider + { + private const long HandlerID = 917632; + private bool _registered; + + public bool IsReady { get; private set; } + + public void LoadAPI() + { + if (!_registered) + { + _registered = true; + MyAPIGateway.Utilities.RegisterMessageHandler(HandlerID, HandleMessage); + } + + IsReady = true; + + try + { + MyAPIGateway.Utilities.SendModMessage(HandlerID, FieldGeneratorSession.I.APIBackend.APIMethods); + } + catch (Exception ex) + { + Log.Error($"Field Generator API Load Failed!" + "\n" + ex); + } + } + + public void UnloadAPI() + { + if (_registered) + { + _registered = false; + MyAPIGateway.Utilities.UnregisterMessageHandler(HandlerID, HandleMessage); + } + IsReady = false; + } + + private void HandleMessage(object o) + { + if ((o as string) == "APIRequest") + MyAPIGateway.Utilities.SendModMessage(HandlerID, FieldGeneratorSession.I.APIBackend.APIMethods); + } + } + + internal class APIBackend + { + internal readonly Dictionary APIMethods; + + internal APIBackend() + { + APIMethods = new Dictionary() + { + ["GetFirstFieldGeneratorOnGrid"] = new Func(GetFirstFieldGeneratorOnGrid), + + ["IsSiegeActive"] = new Func(IsSiegeActive), + ["SetSiegeActive"] = new Action(SetSiegeActive), + + ["IsSiegeCooldownActive"] = new Func(IsSiegeCooldownActive), + ["SetSiegeCooldownActive"] = new Action(SetSiegeCooldownActive), + + ["GetSiegeCooldown"] = new Func(GetSiegeCooldown), + ["SetSiegeCooldown"] = new Action(SetSiegeCooldown), + + ["GetFieldPower"] = new Func(GetFieldPower), + ["SetFieldPower"] = new Action(SetFieldPower), + + ["GetMaximumFieldPower"] = new Func(GetMaximumFieldPower), + ["GetMinimumFieldPower"] = new Func(GetMinimumFieldPower), + + ["GetPowerDraw"] = new Func(GetPowerDraw), + + ["GetStability"] = new Func(GetStability), + ["SetStability"] = new Action(SetStability), + }; + } + + private IMyFunctionalBlock GetFirstFieldGeneratorOnGrid(long entityID) + { + if (entityID == 0) + return null; + + HashSet generators; + if (!FieldGeneratorSession.ActiveGenerators.TryGetValue(entityID, out generators)) + { + return null; + } + + var fieldGeneratorID = generators.FirstOrDefault(); + if (fieldGeneratorID == 0) + { + return null; + } + + IMyEntity generatorEntity; + if (!MyAPIGateway.Entities.TryGetEntityById(fieldGeneratorID, out generatorEntity)) + { + return null; + } + + return generatorEntity as IMyFunctionalBlock; + } + + private bool IsSiegeActive(IMyFunctionalBlock block) + { + var logic = FieldGeneratorCore.GetLogic(block.EntityId); + if (logic != null) + { + return logic.SiegeMode.Value; + } + + return false; + } + private void SetSiegeActive(IMyFunctionalBlock block, bool Active) + { + var logic = FieldGeneratorCore.GetLogic(block.EntityId); + if (logic != null) + { + logic.SiegeMode.Value = Active; + } + } + + private bool IsSiegeCooldownActive(IMyFunctionalBlock block) + { + var logic = FieldGeneratorCore.GetLogic(block.EntityId); + if (logic != null) + { + return logic.SiegeCooldownActive.Value; + } + + return false; + } + private void SetSiegeCooldownActive(IMyFunctionalBlock block, bool Active) + { + var logic = FieldGeneratorCore.GetLogic(block.EntityId); + if (logic != null) + { + logic.SiegeCooldownActive.Value = Active; + } + } + + private int GetSiegeCooldown(IMyFunctionalBlock block) + { + var logic = FieldGeneratorCore.GetLogic(block.EntityId); + if (logic != null) + { + return logic.SiegeCooldownTime.Value; + } + + return 0; + } + private void SetSiegeCooldown(IMyFunctionalBlock block, int Time) + { + var logic = FieldGeneratorCore.GetLogic(block.EntityId); + if (logic != null) + { + logic.SiegeCooldownTime.Value = Time; + } + } + + private float GetFieldPower (IMyFunctionalBlock block) + { + var logic = FieldGeneratorCore.GetLogic(block.EntityId); + if (logic != null) + { + return logic.FieldPower.Value; + } + + return 0; + } + private void SetFieldPower(IMyFunctionalBlock block, float Power) + { + var logic = FieldGeneratorCore.GetLogic(block.EntityId); + if (logic != null) + { + logic.FieldPower.Value = Power; + } + } + + private float GetMaximumFieldPower(IMyFunctionalBlock block) + { + var logic = FieldGeneratorCore.GetLogic(block.EntityId); + if (logic != null) + { + return logic.MaxFieldPower.Value; + } + + return 0; + } + private float GetMinimumFieldPower(IMyFunctionalBlock block) + { + var logic = FieldGeneratorCore.GetLogic(block.EntityId); + if (logic != null) + { + return logic.MinFieldPower.Value; + } + + return 0; + } + + private float GetPowerDraw(IMyFunctionalBlock block) + { + var logic = FieldGeneratorCore.GetLogic(block.EntityId); + if (logic != null) + { + return logic.CalculatePowerDraw(); + } + + return 0; + } + + private float GetStability(IMyFunctionalBlock block) + { + var logic = FieldGeneratorCore.GetLogic(block.EntityId); + if (logic != null) + { + return logic.Stability.Value; + } + + return 0; + } + private void SetStability(IMyFunctionalBlock block, float Stability) + { + var logic = FieldGeneratorCore.GetLogic(block.EntityId); + if (logic != null) + { + logic.Stability.Value = Stability; + } + } + } +} diff --git a/Utility Mods/Stable/SCDefenseBlocks/Data/Scripts/OneFuckingFolderDeeper/FieldGenerator/FieldGenerator_Core.cs b/Utility Mods/Stable/SCDefenseBlocks/Data/Scripts/OneFuckingFolderDeeper/FieldGenerator/FieldGenerator_Core.cs index 66b2e4743..5275154c1 100644 --- a/Utility Mods/Stable/SCDefenseBlocks/Data/Scripts/OneFuckingFolderDeeper/FieldGenerator/FieldGenerator_Core.cs +++ b/Utility Mods/Stable/SCDefenseBlocks/Data/Scripts/OneFuckingFolderDeeper/FieldGenerator/FieldGenerator_Core.cs @@ -614,7 +614,7 @@ private float CalculateSizeModifier() return Config.SizeModifierMin + t * (Config.SizeModifierMax - Config.SizeModifierMin); } - private float CalculatePowerDraw() + public float CalculatePowerDraw() { if (SiegeMode.Value) { diff --git a/Utility Mods/Stable/SCDefenseBlocks/Data/Scripts/OneFuckingFolderDeeper/FieldGenerator/FieldGenerator_Session.cs b/Utility Mods/Stable/SCDefenseBlocks/Data/Scripts/OneFuckingFolderDeeper/FieldGenerator/FieldGenerator_Session.cs index 0da744ce0..f78d81277 100644 --- a/Utility Mods/Stable/SCDefenseBlocks/Data/Scripts/OneFuckingFolderDeeper/FieldGenerator/FieldGenerator_Session.cs +++ b/Utility Mods/Stable/SCDefenseBlocks/Data/Scripts/OneFuckingFolderDeeper/FieldGenerator/FieldGenerator_Session.cs @@ -3,20 +3,45 @@ using System.Linq; using System.Text; using System.Threading.Tasks; + +using Sandbox.Game.Entities; +using Sandbox.ModAPI; using VRage.Game.Components; +using VRage.Game.ModAPI; +using VRage.ModAPI; + +using Starcore.FieldGenerator.API; using CoreSystems.Api; using Draygo.API; +using Sandbox.Game.Entities.Cube; namespace Starcore.FieldGenerator { [MySessionComponentDescriptor(MyUpdateOrder.AfterSimulation)] public class FieldGeneratorSession : MySessionComponentBase { + public static FieldGeneratorSession I; + public static APIProvider APIProvider; public static WcApi CoreSysAPI; public static HudAPIv2 HudAPI; + internal APIBackend APIBackend; + internal static readonly Dictionary> ActiveGenerators = new Dictionary>(); + public override void LoadData() { + I = this; + + InitExistingGeneratorCounts(); + + MyCubeGrid.OnBlockAddedGlobally += OnBlockAddedGlobally; + MyCubeGrid.OnBlockRemovedGlobally += OnBlockRemovedGlobally; + MyAPIGateway.Entities.OnEntityAdd += OnEntityAdd; + + APIBackend = new APIBackend(); + APIProvider = new APIProvider(); + APIProvider.LoadAPI(); + HudAPI = new HudAPIv2(); CoreSysAPI = new WcApi(); @@ -24,7 +49,7 @@ public override void LoadData() } protected override void UnloadData() - { + { if (HudAPI.Heartbeat) { HudAPI.Unload(); @@ -36,6 +61,118 @@ protected override void UnloadData() CoreSysAPI.Unload(); CoreSysAPI = null; } + + APIProvider.UnloadAPI(); + APIProvider = null; + APIBackend = null; + + MyCubeGrid.OnBlockAddedGlobally -= OnBlockAddedGlobally; + MyCubeGrid.OnBlockRemovedGlobally -= OnBlockRemovedGlobally; + MyAPIGateway.Entities.OnEntityAdd -= OnEntityAdd; + + I = null; + } + + private void OnBlockAddedGlobally(T slimBlock) where T : IMySlimBlock + { + if (slimBlock?.FatBlock == null) + return; + if (!string.Equals(slimBlock.FatBlock.BlockDefinition.SubtypeName, "FieldGen_Core", + StringComparison.OrdinalIgnoreCase)) + return; + + var gridId = slimBlock.CubeGrid?.EntityId ?? 0; + if (gridId == 0) + return; + + HashSet set; + if (!ActiveGenerators.TryGetValue(gridId, out set)) + { + set = new HashSet(); + ActiveGenerators[gridId] = set; + } + + set.Add(slimBlock.FatBlock.EntityId); + } + + private void OnBlockRemovedGlobally(T slimBlock) where T : IMySlimBlock + { + if (slimBlock?.FatBlock == null) + return; + if (!string.Equals(slimBlock.FatBlock.BlockDefinition.SubtypeName, "FieldGen_Core", StringComparison.OrdinalIgnoreCase)) + return; + + var gridId = slimBlock.CubeGrid?.EntityId ?? 0; + if (gridId == 0) return; + + HashSet set; + if (ActiveGenerators.TryGetValue(gridId, out set)) + { + set.Remove(slimBlock.FatBlock.EntityId); + if (set.Count == 0) + ActiveGenerators.Remove(gridId); + } + } + + private void OnEntityAdd(IMyEntity ent) + { + var grid = ent as IMyCubeGrid; + if (grid == null) + return; + + var slimBlocks = new List(); + grid.GetBlocks(slimBlocks); + + foreach (var slimBlock in slimBlocks) + { + if (slimBlock?.FatBlock == null) + continue; + + if (string.Equals(slimBlock.FatBlock.BlockDefinition.SubtypeName, "FieldGen_Core", StringComparison.OrdinalIgnoreCase)) + { + var gridId = grid.EntityId; + HashSet set; + if (!ActiveGenerators.TryGetValue(gridId, out set)) + { + set = new HashSet(); + ActiveGenerators[gridId] = set; + } + set.Add(slimBlock.FatBlock.EntityId); + } + } + } + + private void InitExistingGeneratorCounts() + { + var allEntities = new HashSet(); + MyAPIGateway.Entities.GetEntities(allEntities); + foreach (var entity in allEntities) + { + var grid = entity as IMyCubeGrid; + if (grid == null) + continue; + + var slimBlocks = new List(); + grid.GetBlocks(slimBlocks); + + foreach (var slimBlock in slimBlocks) + { + if (slimBlock?.FatBlock == null) + continue; + + if (string.Equals(slimBlock.FatBlock.BlockDefinition.SubtypeName, "FieldGen_Core", StringComparison.OrdinalIgnoreCase)) + { + var gridId = grid.EntityId; + HashSet set; + if (!ActiveGenerators.TryGetValue(gridId, out set)) + { + set = new HashSet(); + ActiveGenerators[gridId] = set; + } + set.Add(slimBlock.FatBlock.EntityId); + } + } + } } } }