diff --git a/TSTSSESHangar/Data/Scripts/FactionHangar/Config.cs b/TSTSSESHangar/Data/Scripts/FactionHangar/Config.cs new file mode 100644 index 00000000..658a0b8b --- /dev/null +++ b/TSTSSESHangar/Data/Scripts/FactionHangar/Config.cs @@ -0,0 +1,374 @@ +using ProtoBuf; +using Sandbox.ModAPI; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Xml.Serialization; +using VRageMath; + +namespace CustomHangar +{ + [ProtoContract] + public class Config + { + [ProtoIgnore][XmlIgnore] public string version = "1.00"; + [ProtoMember(1)][XmlElement("AutoHangarConfig")] public AutoHangarConfig autoHangarConfig; + [ProtoMember(2)][XmlElement("FactionHangarConfig")] public FactionHangarConfig factionHangarConfig; + [ProtoMember(3)][XmlElement("PrivateHangarConfig")] public PrivateHangarConfig privateHangarConfig; + [ProtoMember(4)][XmlElement("SpawningConfigLimits")] public SpawnConfigLimits spawnConfig; + [ProtoMember(5)][XmlElement("SetSmallGridsStaticOnSpawn")] public bool spawnSGStatic; + [ProtoMember(6)][XmlElement("SpawnNearbyConfig")] public SpawnNearbyConfig spawnNearbyConfig; + [ProtoMember(7)][XmlElement("DynamicSpawningConfig")] public DynamicSpawning dynamicSpawningConfig; + [ProtoMember(8)][XmlElement("OriginalSpawningConfig")] public SpawnOriginalConfig spawnOriginalConfig; + [ProtoMember(9)][XmlElement("EnemyCheckSettings")] public EnemyCheckConfig enemyCheckConfig; + [ProtoMember(10)][XmlElement("SpawnAreas")] public SpawnAreas[] spawnAreas; + + public static Config LoadConfig() + { + if (MyAPIGateway.Utilities.FileExistsInWorldStorage("!FactionHangarConfig.xml", typeof(Config)) == true) + { + try + { + Config defaults = new Config(); + var reader = MyAPIGateway.Utilities.ReadFileInWorldStorage("!FactionHangarConfig.xml", typeof(Config)); + string content = reader.ReadToEnd(); + + reader.Close(); + defaults = MyAPIGateway.Utilities.SerializeFromXML(content); + if (defaults == null) + return CreateNewFile(); + + //if (settings.version == defaults.version) + //eturn settings; + + //settings.version = defaults.version; + SaveConfig(defaults); + return defaults; + } + catch (Exception ex) + { + return CreateNewFile(); + } + } + + return CreateNewFile(); + } + + public static Config CreateNewFile() + { + Config defaults = new Config(); + + BlockType blocktype = new BlockType() + { + blockType = "Type", + blockSubtypes = new BlockSubtypes() + { + subtype = new string[] { "Subtype", "Subtype" } + } + }; + defaults.autoHangarConfig = new AutoHangarConfig() + { + enableAutoHangar = false, + daysFactionLogin = 8, + autoBypassSpawnLimits = true, + autoBypassSpawnCost = true, + exclusions = new Exclusions() + { + excludedBlockTypes = new BlockType[] { blocktype }, + excludedFactions = new ExcludedFactions() + { + excludedFaction = new string[] { "FACTIONTAG" } + } + } + }; + var list = defaults.autoHangarConfig.exclusions.excludedBlockTypes.ToList(); + list.Add(blocktype); + defaults.autoHangarConfig.exclusions.excludedBlockTypes = list.ToArray(); + + var list2 = defaults.autoHangarConfig.exclusions.excludedFactions.excludedFaction.ToList(); + list2.Add("FACTIONTAG"); + defaults.autoHangarConfig.exclusions.excludedFactions.excludedFaction = list2.ToArray(); + + defaults.factionHangarConfig = new FactionHangarConfig() + { + maxFactionSlots = 20, + factionRetrievalCooldown = 60, + factionHangarCooldown = 60, + factionStoreDelay = 60, + factionToPrivateTransfer = true, + factionHangarEnemyCheck = new EnemyChecks() + { + checkEnemiesNearby = true, + enemyDistanceCheck = 1500, + alliesFriendly = true, + omitNPCs = true + } + }; + + defaults.privateHangarConfig = new PrivateHangarConfig() + { + maxPrivateSlots = 5, + privateRetrievalCooldown = 60, + privateHangarCooldown = 60, + privateStoreDelay = 60, + privateToFactionTransfer = true, + privateHangarEnemyCheck = new EnemyChecks() + { + checkEnemiesNearby = true, + enemyDistanceCheck = 1500, + alliesFriendly = true, + omitNPCs = true + } + }; + + defaults.spawnConfig = new SpawnConfigLimits() + { + removeUranium = false, + removeIce = false, + removeAmmo = false, + h2Percentage = -1, + batteryPercentage = -1, + }; + + defaults.spawnNearbyConfig = new SpawnNearbyConfig() + { + allowSpawnNearby = true, + nearbyRadius = 50, + nearbyEnemyCheck = new EnemyChecks() + { + checkEnemiesNearby = true, + enemyDistanceCheck = 1500, + alliesFriendly = true, + omitNPCs = true + }, + + nearbySpawnBypass = true, + nearbySpawnCost = 0 + }; + + defaults.dynamicSpawningConfig = new DynamicSpawning() + { + enableDynamicSpawning = true, + costMultiplier = 0.0001f, + dynamicEnemyCheck = new EnemyChecks() + { + checkEnemiesNearby = true, + enemyDistanceCheck = 1500, + alliesFriendly = true, + omitNPCs = true + }, + + dynamicSpawnBypass = true, + }; + + defaults.spawnOriginalConfig = new SpawnOriginalConfig() + { + allowSpawnOriginal = true, + originalEnemyCheck = new EnemyChecks() + { + checkEnemiesNearby = true, + enemyDistanceCheck = 1500, + alliesFriendly = true, + omitNPCs = true + }, + + originalSpawnBypass = true, + originalSpawnCost = 0 + }; + + BlockType blockConfig = new BlockType() + { + blockType = "Beacon", + blockSubtypes = new BlockSubtypes() + { + subtype = new string[] { "LargeBlockBeacon", "SmallBlockBeacon" } + } + }; + + defaults.enemyCheckConfig = new EnemyCheckConfig() + { + enableBlockCheck = false, + blockTypes = new BlockType[] { blockConfig }, + }; + var list3 = defaults.enemyCheckConfig.blockTypes.ToList(); + list3.Add(blockConfig); + defaults.enemyCheckConfig.blockTypes = list3.ToArray(); + + defaults.spawnSGStatic = false; + + SpawnAreas spawnArea = new SpawnAreas() + { + enableSpawnArea = false, + areaCenter = new Vector3D(0, 0, 0), + areaRadius = 7500, + inverseArea = false, + spawnAreaBypass = true, + spawnAreaCost = 0, + spawnAreasEnemyCheck = new EnemyChecks() + { + checkEnemiesNearby = false, + enemyDistanceCheck = 1500, + alliesFriendly = true, + omitNPCs = true + } + }; + defaults.spawnAreas = new SpawnAreas[] { spawnArea }; + + SaveConfig(defaults); + return defaults; + } + + public static void SaveConfig(Config config) + { + if (config == null) return; + try + { + using (var writer = MyAPIGateway.Utilities.WriteFileInWorldStorage("!FactionHangarConfig.xml", typeof(Config))) + { + writer.Write(MyAPIGateway.Utilities.SerializeToXML(config)); + writer.Close(); + } + } + catch (Exception ex) + { + VRage.Utils.MyLog.Default.WriteLineAndConsole($"FactionHangar: Error trying to save config!\n {ex.ToString()}"); + } + } + } + + [ProtoContract] + public struct AutoHangarConfig + { + [ProtoMember(1)][XmlElement("EnableAutoHangar")] public bool enableAutoHangar; + [ProtoMember(2)][XmlElement("DaysSinceFactionLogin")] public float daysFactionLogin; + [ProtoMember(3)][XmlElement("BypassSpawnConfigLimits")] public bool autoBypassSpawnLimits; + [ProtoMember(4)][XmlElement("BypassSpawningCost")] public bool autoBypassSpawnCost; + [ProtoMember(5)][XmlElement("AutoHangarExclusions")] public Exclusions exclusions; + + //public AutoHangarConfig() { } + } + + [ProtoContract] + public struct FactionHangarConfig + { + [ProtoMember(1)][XmlElement("MaxFactionHangarSlots")] public int maxFactionSlots; + [ProtoMember(2)][XmlElement("FactionRetrievalCooldown")] public int factionRetrievalCooldown; + [ProtoMember(3)][XmlElement("FactionHangarCooldown")] public int factionHangarCooldown; + [ProtoMember(4)][XmlElement("StorageDelayInSeconds")] public int factionStoreDelay; + [ProtoMember(5)][XmlElement("AllowFactionToPrivateTransfer")] public bool factionToPrivateTransfer; + [ProtoMember(6)][XmlElement("EnemyCheckConfig")] public EnemyChecks factionHangarEnemyCheck; + //[ProtoMember(5)][XmlElement("FactionLeadersObtainAllOwnership")] public bool factionLeadersObtainAllOwnership = false; + + //public FactionHangarConfig() { } + } + + [ProtoContract] + public struct PrivateHangarConfig + { + [ProtoMember(1)][XmlElement("MaxPrivateHangarSlots")] public int maxPrivateSlots; + [ProtoMember(2)][XmlElement("PrivateRetrievalCooldown")] public int privateRetrievalCooldown; + [ProtoMember(3)][XmlElement("PrivateHangarCooldown")] public int privateHangarCooldown; + [ProtoMember(4)][XmlElement("StorageDelayInSeconds")] public int privateStoreDelay; + [ProtoMember(5)][XmlElement("AllowPrivateToFactionTransfer")] public bool privateToFactionTransfer; + [ProtoMember(6)][XmlElement("EnemyCheckConfig")] public EnemyChecks privateHangarEnemyCheck; + + //public PrivateHangarConfig() { } + } + + [ProtoContract] + public struct DynamicSpawning + { + [ProtoMember(1)][XmlElement("AllowDynamicSpawning")] public bool enableDynamicSpawning; + [ProtoMember(2)][XmlElement("CostMultiplier")] public float costMultiplier; + [ProtoMember(3)][XmlElement("EnemyCheckConfig")] public EnemyChecks dynamicEnemyCheck; + [ProtoMember(4)][XmlElement("BypassSpawnConfigLimits")] public bool dynamicSpawnBypass; + } + + [ProtoContract] + public struct SpawnConfigLimits + { + [ProtoMember(1)][XmlElement("RemoveUranium")] public bool removeUranium; + [ProtoMember(2)][XmlElement("RemoveIce")] public bool removeIce; + [ProtoMember(3)][XmlElement("RemoveAmmo")] public bool removeAmmo; + [ProtoMember(4)][XmlElement("SetH2Percentage")] public float h2Percentage; + [ProtoMember(5)][XmlElement("SetBatteryPercentage")] public float batteryPercentage; + } + + [ProtoContract] + + public struct SpawnAreas + { + [ProtoMember(1)][XmlElement("EnableSpawnArea")] public bool enableSpawnArea; + [ProtoMember(2)][XmlElement("AreaCenterLocation")] public Vector3D areaCenter; + [ProtoMember(3)][XmlElement("AreaRadius")] public float areaRadius; + [ProtoMember(4)][XmlElement("InverseArea")] public bool inverseArea; + [ProtoMember(5)][XmlElement("EnemyCheckConfig")] public EnemyChecks spawnAreasEnemyCheck; + [ProtoMember(6)][XmlElement("BypassSpawnConfigLimits")] public bool spawnAreaBypass; + [ProtoMember(7)][XmlElement("CostToSpawn")] public long spawnAreaCost; + + } + + [ProtoContract] + + public struct SpawnNearbyConfig + { + [ProtoMember(1)][XmlElement("AllowSpawningNearbyOriginal")] public bool allowSpawnNearby; + [ProtoMember(2)][XmlElement("NearbyRadius")] public float nearbyRadius; + [ProtoMember(3)][XmlElement("EnemyCheckConfig")] public EnemyChecks nearbyEnemyCheck; + [ProtoMember(4)][XmlElement("BypassSpawnConfigLimits")] public bool nearbySpawnBypass; + [ProtoMember(5)][XmlElement("CostToSpawn")] public long nearbySpawnCost; + } + + [ProtoContract] + public struct SpawnOriginalConfig + { + [ProtoMember(1)][XmlElement("AllowSpawnAtOriginalLocation")] public bool allowSpawnOriginal; + [ProtoMember(2)][XmlElement("EnemyCheckConfig")] public EnemyChecks originalEnemyCheck; + [ProtoMember(3)][XmlElement("BypassSpawnConfigLimits")] public bool originalSpawnBypass; + [ProtoMember(4)][XmlElement("CostToSpawn")] public long originalSpawnCost; + } + + [ProtoContract] + public struct EnemyChecks + { + [ProtoMember(1)][XmlElement("CheckEnemiesNearby")] public bool checkEnemiesNearby; + [ProtoMember(2)][XmlElement("EnemyDistanceCheck")] public float enemyDistanceCheck; + [ProtoMember(3)][XmlElement("AlliesAreFriendly")] public bool alliesFriendly; + [ProtoMember(4)][XmlElement("OmitNPCs")] public bool omitNPCs; + } + + [ProtoContract] + public struct EnemyCheckConfig + { + [ProtoMember(1)][XmlElement("EnableBlockChecking")] public bool enableBlockCheck; + [ProtoMember(2)][XmlElement("BlockTypes")] public BlockType[] blockTypes; + } + + [ProtoContract] + public struct BlockType + { + [ProtoMember(1)][XmlElement("BlockType")] public string blockType; + [ProtoMember(2)][XmlElement("BlockSubtypes")] public BlockSubtypes blockSubtypes; + } + + [ProtoContract] + public struct Exclusions + { + [ProtoMember(1)][XmlElement("ExcludedBlockTypes")] public BlockType[] excludedBlockTypes; + [ProtoMember(2)][XmlElement("ExcludedFactions")] public ExcludedFactions excludedFactions; + } + + [ProtoContract] + public struct ExcludedFactions + { + [ProtoMember(1)][XmlElement("ExcludedFaction")] public string[] excludedFaction; + } + + [ProtoContract] + public struct BlockSubtypes + { + [ProtoMember(1)][XmlElement("BlockSubtype")] public string[] subtype; + } +} \ No newline at end of file diff --git a/TSTSSESHangar/Data/Scripts/FactionHangar/HangarData.cs b/TSTSSESHangar/Data/Scripts/FactionHangar/HangarData.cs new file mode 100644 index 00000000..93230172 --- /dev/null +++ b/TSTSSESHangar/Data/Scripts/FactionHangar/HangarData.cs @@ -0,0 +1,451 @@ +using ProtoBuf; +using Sandbox.Game; +using Sandbox.ModAPI; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection.Metadata.Ecma335; +using System.Text; +using System.Threading.Tasks; +using System.Xml.Serialization; +using VRage.Game.ModAPI; +using VRage.GameServices; +using VRageMath; + +namespace CustomHangar +{ + + public enum HangarType + { + Private, + Faction + } + + public enum SpawnType + { + None, + Dynamic, + Nearby, + SpawnArea, + Original + } + + [XmlRoot("HangarData")] + public class AllHangarData + { + [XmlElement("FactionData")] public List factionData = new List(); + [XmlElement("PrivateData")] public List privateData = new List(); + + public AllHangarData() { } + + public void AddFactionData(long factionId, string gridName, long gridId, long playerId, string path, string playerName, bool autoHangar) + { + IMyFaction faction = MyAPIGateway.Session.Factions.TryGetFactionById(factionId); + if (faction == null) return; + + GridData gData = new GridData() + { + gridId = gridId, + gridName = gridName, + owner = playerId, + gridPath = path, + ownerName = playerName, + autoHangared = autoHangar + }; + + FactionData fData = GetFactionData(factionId); + if (fData == null) + { + HangarData hData = new HangarData() + { + gridData = new List() { gData }, + type = HangarType.Faction + }; + + FactionData data = new FactionData() + { + factionId = factionId, + factionHangarData = hData, + factionName = faction.Name + }; + + factionData.Add(data); + } + else + fData.factionHangarData.gridData.Add(gData); + + + } + + public void RemoveFactionData(long factionId, int index, bool nullBlueprint = false) + { + if (factionData == null) return; + + foreach (var fData in factionData) + if (fData.factionId == factionId) + if (index <= fData.factionHangarData.gridData.Count - 1) + { + if (nullBlueprint) + Session.Instance.cacheGridPaths.Add(fData.factionHangarData.gridData[index].gridPath); + + fData.factionHangarData.gridData.RemoveAt(index); + return; + } + } + + public int GetFactionSlots(long factionId) + { + if (factionData == null) return 0; + + foreach (var fData in factionData) + { + int slots = 0; + if (fData.factionId == factionId) + { + foreach(var gData in fData.factionHangarData.gridData) + { + if (!gData.autoHangared) + slots++; + } + + return slots; + } + } + + return 0; + } + + public FactionData GetFactionData(long factionId) + { + if (factionData == null) return null; + + foreach (var fData in factionData) + if (fData.factionId == factionId) return fData; + + return null; + } + + public GridData GetFactionGridData(long factionId, int index) + { + FactionData fData = GetFactionData(factionId); + if (fData == null) return null; + + if (index >= 0) + { + if (index > fData.factionHangarData.gridData.Count - 1) return null; + return fData.factionHangarData.gridData[index]; + } + + return null; + } + + public string GetFactionsGridNames(long factionId, long playerId, bool isLeader = true) + { + if (factionData == null) return null; + + string names = ""; + foreach (var fData in factionData) + { + if (fData.factionId == factionId) + { + if (fData.factionHangarData.gridData.Count == 0) + return names; + + for (int i = 0; i < fData.factionHangarData.gridData.Count; i++) + { + names += "\n"; + if (isLeader) + names += $"[{i}] {fData.factionHangarData.gridData[i].gridName}"; + else + { + if (fData.factionHangarData.gridData[i].owner == playerId) + names += $"[{i}] {fData.factionHangarData.gridData[i].gridName}"; + } + + if (fData.factionHangarData.gridData[i].autoHangared) + names += " [AutoHangar]"; + } + + names += $"\nFaction Hangar Totals: {GetFactionSlots(factionId)}/{Session.Instance.config.factionHangarConfig.maxFactionSlots}"; + } + + } + + return names; + } + + public bool IsFactionGridAutoHangared(long factionId, int index) + { + FactionData fData = GetFactionData(factionId); + if (fData == null) return false; + + if (index >= 0) + { + if (index > fData.factionHangarData.gridData.Count - 1) return false; + return fData.factionHangarData.gridData[index].autoHangared; + } + + return false; + } + + public int GetPrivateSlots(long playerId) + { + if (privateData == null) return 0; + foreach (var pData in privateData) + { + if (pData.playerId == playerId) + { + int slots = 0; + foreach(var gData in pData.privateHangarData.gridData) + { + if (!gData.autoHangared) + slots++; + } + + return slots; + } + } + + return 0; + } + + public string GetPrivateGridNames(long playerId) + { + if (privateData == null) return null; + + string names = ""; + foreach (var pData in privateData) + { + if (pData.playerId == playerId) + { + if (pData.privateHangarData.gridData.Count == 0) + return names; + + for (int i = 0; i < pData.privateHangarData.gridData.Count; i++) + { + names += "\n"; + if (pData.privateHangarData.gridData[i].owner == playerId) + names += $"[{i}] {pData.privateHangarData.gridData[i].gridName}"; + + if (pData.privateHangarData.gridData[i].autoHangared) + names += " [AutoHangar]"; + } + + names += $"\nPrivate Hangar Totals: {GetPrivateSlots(playerId)}/{Session.Instance.config.privateHangarConfig.maxPrivateSlots}"; + } + } + + return names; + } + + public PrivateData GetPrivateData(long playerId) + { + if (privateData == null) return null; + + foreach (var pData in privateData) + if (pData.playerId == playerId) return pData; + + return null; + } + + public GridData GetPrivateGridData(long playerId, int index) + { + PrivateData pData = GetPrivateData(playerId); + if (pData == null) return null; + + if (index >= 0) + { + if (index > pData.privateHangarData.gridData.Count - 1) return null; + return pData.privateHangarData.gridData[index]; + } + + return null; + } + + public bool IsPrivateGridAutoHangared(long playerId, int index) + { + PrivateData pData = GetPrivateData(playerId); + if (pData == null) return false; + + if (index >= 0) + { + if (index > pData.privateHangarData.gridData.Count - 1) return false; + return pData.privateHangarData.gridData[index].autoHangared; + } + + return false; + } + + public bool TransferFactionToPrivate(long factionId, int index, long playerId) + { + if (!Session.Instance.config.factionHangarConfig.factionToPrivateTransfer) + { + MyVisualScriptLogicProvider.SendChatMessageColored($"Faction to private transfers are not allowed.", Color.Red, "[FactionHangar]", playerId, "Red"); + return false; + } + + GridData gridData = GetFactionGridData(factionId, index); + if (gridData == null) return false; + + if (gridData.owner != playerId) + { + MyVisualScriptLogicProvider.SendChatMessageColored($"You can only transfer grids that you own.", Color.Red, "[FactionHangar]", playerId, "Red"); + return false; + } + + if (GetPrivateSlots(playerId) >= Session.Instance.config.privateHangarConfig.maxPrivateSlots) + { + MyVisualScriptLogicProvider.SendChatMessageColored($"Failed to transfer grid, you have exceeded your private hangar slots.", Color.Red, "[FactionHangar]", playerId, "Red"); + return false; + } + + RemoveFactionData(factionId, index); + AddPrivateData(gridData.gridName, gridData.gridId, playerId, gridData.gridPath, gridData.ownerName, gridData.autoHangared); + return true; + } + + public bool TransferPrivateToFaction(long factionId, int index, long playerId) + { + if (!Session.Instance.config.privateHangarConfig.privateToFactionTransfer) + { + MyVisualScriptLogicProvider.SendChatMessageColored($"Private to faction transfers are not allowed.", Color.Red, "[FactionHangar]", playerId, "Red"); + return false; + } + + GridData gridData = GetPrivateGridData(playerId, index); + if (gridData == null) return false; + + if (GetFactionSlots(factionId) >= Session.Instance.config.factionHangarConfig.maxFactionSlots) + { + MyVisualScriptLogicProvider.SendChatMessageColored($"Failed to transfer grid, you have exceeded the faction hangar slots.", Color.Red, "[FactionHangar]", playerId, "Red"); + return false; + } + + RemovePrivateData(playerId, index); + AddFactionData(factionId, gridData.gridName, gridData.gridId, playerId, gridData.gridPath, gridData.ownerName, gridData.autoHangared); + return true; + } + + public void AddPrivateData(string gridName, long gridId, long playerId, string path, string playerName, bool autoHangar) + { + GridData gData = new GridData() + { + gridId = gridId, + gridName = gridName, + owner = playerId, + gridPath = path, + ownerName = playerName, + autoHangared = autoHangar + }; + + PrivateData pData = GetPrivateData(playerId); + if (pData == null) + { + HangarData hData = new HangarData() + { + gridData = new List() { gData }, + type = HangarType.Private + }; + + PrivateData data = new PrivateData() + { + privateHangarData = hData, + playerId = playerId, + playerNameRef = playerName, + }; + + privateData.Add(data); + } + else + pData.privateHangarData.gridData.Add(gData); + } + + public void RemovePrivateData(long playerId, int index, bool nullBlueprint = false) + { + if (privateData == null) return; + + foreach (var pData in privateData) + if (pData.playerId == playerId) + if (index <= pData.privateHangarData.gridData.Count - 1) + { + if (nullBlueprint) + Session.Instance.cacheGridPaths.Add(pData.privateHangarData.gridData[index].gridPath); + + pData.privateHangarData.gridData.RemoveAt(index); + return; + } + } + + public static AllHangarData LoadHangarData() + { + if (MyAPIGateway.Utilities.FileExistsInWorldStorage("FactionHangarStorage.xml", typeof(AllHangarData)) == true) + { + try + { + AllHangarData data = new AllHangarData(); + var reader = MyAPIGateway.Utilities.ReadFileInWorldStorage("FactionHangarStorage.xml", typeof(AllHangarData)); + string content = reader.ReadToEnd(); + + reader.Close(); + return data = MyAPIGateway.Utilities.SerializeFromXML(content); + } + catch (Exception ex) + { + return new AllHangarData(); + } + } + + return new AllHangarData(); + } + } + + public class FactionData + { + [XmlElement("Faction")] public string factionName; + [XmlElement("FactionId")] public long factionId; + [XmlElement("FactionHangarData")] public HangarData factionHangarData; + } + + public class PrivateData + { + [XmlElement("Private")] public HangarData privateHangarData; + [XmlElement("PlayerId")] public long playerId; + [XmlElement("Player")] public string playerNameRef; + } + + public class HangarData + { + [XmlElement("HangarType")] public HangarType type; + [XmlElement("StoredGrid")] public List gridData = new List(); + } + + [ProtoContract] + public class HangarDelayData + { + [ProtoMember(1)] public long playerId; + [ProtoMember(2)] public List gridData; + [ProtoMember(3)] public int timer; + [ProtoMember(4)] public string playerName; + [ProtoMember(5)] public HangarType hangarType; + [ProtoMember(6)] public long requesterId; + } + + [ProtoContract] + public class GridData + { + [XmlElement("GridId")] [ProtoMember(1)] public long gridId; + [XmlElement("GridName")] [ProtoMember(2)] public string gridName; + [XmlElement("StoredPath")] [ProtoMember(3)] public string gridPath; + [XmlElement("Owner")] [ProtoMember(4)] public long owner; + [XmlElement("OwnerName")] [ProtoMember(5)] public string ownerName; + [XmlElement("AutoHangared")][ProtoMember(6)] public bool autoHangared; + } + + public class CacheGridsForStorage + { + public long ownerId; + public long requesterId; + public List grids; + } +} + diff --git a/TSTSSESHangar/Data/Scripts/FactionHangar/MassGatherWorkData.cs b/TSTSSESHangar/Data/Scripts/FactionHangar/MassGatherWorkData.cs new file mode 100644 index 00000000..5c88ff64 --- /dev/null +++ b/TSTSSESHangar/Data/Scripts/FactionHangar/MassGatherWorkData.cs @@ -0,0 +1,120 @@ +using ParallelTasks; +using Sandbox.Game; +using Sandbox.Game.Entities; +using Sandbox.ModAPI; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using VRage.Game.ModAPI; +using VRage.Utils; + +namespace CustomHangar +{ + public class MassGathererWorkData : WorkData + { + public List grids = new List(); + public double massSum = 0; + public long factionWalletData = -1; + public IMyFaction faction = null; + public long playerWalletData = -1; + + public void ScanGridMassAction(WorkData data) + { + int attempts = 0; + var workData = (MassGathererWorkData)data; + + var blocks = new List(); + foreach (var cubeGrid in workData.grids) + { + if (cubeGrid.MarkedForClose) + continue; + + blocks.Clear(); + blocks.EnsureCapacity(cubeGrid.BlocksCount); + ((IMyCubeGrid)cubeGrid).GetBlocks(blocks); + GatherMass(blocks, workData); + } + + GatherWalletData: + if (!GatherWalletData(workData)) + MyAPIGateway.Parallel.Sleep(500); + else + return; + + if (attempts > 5) + return; + + attempts++; + goto GatherWalletData; + } + + private void GatherMass(List blocks, MassGathererWorkData workData) + { + foreach (var block in blocks) + { + var fat = block.FatBlock; + if (fat != null) + { + var remote = fat as IMyRemoteControl; + var flightControl = fat as IMyFlightMovementBlock; + if (remote != null) + remote.SetAutoPilotEnabled(false); + + if (flightControl != null) + flightControl.Enabled = false; + } + + workData.massSum += block.Mass; + if (block.FatBlock?.GetInventory() != null) + { + var fatBlock = block.FatBlock; + for (int i = 0; i < fatBlock.InventoryCount; i++) + { + var inv = (MyInventory)fatBlock.GetInventory(i); + if (inv.ExternalMass != 0) + { + workData.massSum += (double)(inv.CurrentMass - inv.ExternalMass); + } + else + { + workData.massSum += (double)inv.CurrentMass; + } + } + } + } + } + + public void ScanGridMassCallback(WorkData data) + { + var workData = (MassGathererWorkData)data; + Session.Instance.previewMass = (float)workData.massSum; + + foreach(var grid in workData.grids) + { + MyAPIGateway.Entities.AddEntity(grid, true); + Session.Instance.previewGrids.Add(grid); + } + + Session.Instance.factionWallet = workData.factionWalletData; + Session.Instance.playerWallet = workData.playerWalletData; + Session.Instance.ToolEquipped(Session.Instance.playerCache.IdentityId, "", ""); + } + + private bool GatherWalletData(MassGathererWorkData workData) + { + if (workData.faction != null) + if (!workData.faction.TryGetBalanceInfo(out workData.factionWalletData)) return false; + + if (!Session.Instance.playerCache.TryGetBalanceInfo(out workData.playerWalletData)) return false; + + if (workData.faction != null) + if (workData.factionWalletData != -1 && workData.playerWalletData != -1) return true; + + if (workData.playerWalletData != -1) return true; + + return false; + } + } +} diff --git a/TSTSSESHangar/Data/Scripts/FactionHangar/Network.cs b/TSTSSESHangar/Data/Scripts/FactionHangar/Network.cs new file mode 100644 index 00000000..87276078 --- /dev/null +++ b/TSTSSESHangar/Data/Scripts/FactionHangar/Network.cs @@ -0,0 +1,573 @@ +using ProtoBuf; +using Sandbox.ModAPI; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using VRage; +using VRage.Game; +using VRage.Game.ModAPI; +using VRage.Utils; +using Sandbox.Game; +using VRageMath; +using Sandbox.Engine.Utils; +using VRage.ObjectBuilders; +using System.Reflection; + +namespace CustomHangar +{ + + public enum DataType + { + Sync, + StoreGrid, + FactionList, + PrivateList, + LoadFactionGrid, + RequestGridData, + SendGridData, + SendObToSpawn, + RequestConfig, + SendConfig, + ClientRequestTransfer, + AddClientCooldown, + UpdateIdentities, + RequestGridRemoval, + FactionToPrivateTransfer, + PrivateToFactionTransfer, + SendChatMessage, + AddTime + + } + + [ProtoContract] + public class ObjectContainer + { + [ProtoMember(1)] public Config settings; + [ProtoMember(2)] public long playerId; + [ProtoMember(3)] public List gridData; + [ProtoMember(4)] public string stringData; + [ProtoMember(5)] public bool boolValue; + [ProtoMember(6)] public int intValue; + [ProtoMember(7)] public HangarType hangarType; + [ProtoMember(8)] public long factionId; + [ProtoMember(9)] public ulong steamId; + [ProtoMember(10)] public MyObjectBuilder_Base ob; + [ProtoMember(11)] public List cubeGridObs; + [ProtoMember(12)] public Config config; + [ProtoMember(13)] public TimerType timerType; + [ProtoMember(14)] public List identityObs; + [ProtoMember(15)] public long requesterId; + [ProtoMember(16)] public bool originalLocation; + [ProtoMember(17)] public long cost; + [ProtoMember(18)] public SpawnType spawnType; + [ProtoMember(19)] public bool force; + } + + [ProtoContract] + public class ChatMessage + { + [ProtoMember(1)] public string message; + [ProtoMember(2)] public string color; + [ProtoMember(3)] public long playerId; + [ProtoMember(4)] public Color col; + } + + [ProtoContract] + public class CommsPackage + { + [ProtoMember(1)] + public DataType Type; + + [ProtoMember(2)] + public byte[] Data; + + public CommsPackage() + { + Type = DataType.Sync; + Data = new byte[0]; + } + + public CommsPackage(DataType type, ObjectContainer oc) + { + Type = type; + Data = MyAPIGateway.Utilities.SerializeToBinary(oc); + } + + public CommsPackage(DataType type, ChatMessage cm) + { + Type = type; + Data = MyAPIGateway.Utilities.SerializeToBinary(cm); + } + } + + public static class Comms + { + private static readonly ushort handler = Session.Instance.NetworkHandle; + + public static void MessageHandler(byte[] data) + { + try + { + var package = MyAPIGateway.Utilities.SerializeFromBinary(data); + if (package == null) return; + + // Server + if (package.Type == DataType.StoreGrid) + { + var packet = MyAPIGateway.Utilities.SerializeFromBinary(package.Data); + if (packet == null) return; + + Utils.Storegrid(packet); + return; + } + + // Server + if (package.Type == DataType.FactionList) + { + var packet = MyAPIGateway.Utilities.SerializeFromBinary(package.Data); + if (packet == null) return; + + Utils.GetFactionList(packet); + return; + } + + // Server + if (package.Type == DataType.PrivateList) + { + var packet = MyAPIGateway.Utilities.SerializeFromBinary(package.Data); + if (packet == null) return; + + Utils.GetPrivateList(packet); + return; + } + + // Server + if (package.Type == DataType.RequestGridRemoval) + { + var packet = MyAPIGateway.Utilities.SerializeFromBinary(package.Data); + if (packet == null) return; + + Utils.TryHangarGridRemoval(packet); + return; + } + + // Server + if (package.Type == DataType.FactionToPrivateTransfer) + { + var packet = MyAPIGateway.Utilities.SerializeFromBinary(package.Data); + if (packet == null) return; + + IMyFaction faction = MyAPIGateway.Session.Factions.TryGetPlayerFaction(packet.playerId); + if (faction != null) + Session.Instance.allHangarData.TransferFactionToPrivate(faction.FactionId, packet.intValue, packet.playerId); + + return; + } + + // Server + if (package.Type == DataType.PrivateToFactionTransfer) + { + var packet = MyAPIGateway.Utilities.SerializeFromBinary(package.Data); + if (packet == null) return; + + IMyFaction faction = MyAPIGateway.Session.Factions.TryGetPlayerFaction(packet.playerId); + if (faction != null) + Session.Instance.allHangarData.TransferPrivateToFaction(faction.FactionId, packet.intValue, packet.playerId); + + return; + } + + // Server + if (package.Type == DataType.RequestGridData) + { + var packet = MyAPIGateway.Utilities.SerializeFromBinary(package.Data); + if (packet == null) return; + + Utils.GetGridData(packet); + return; + } + + // Client + if (package.Type == DataType.SendGridData) + { + var packet = MyAPIGateway.Utilities.SerializeFromBinary(package.Data); + if (packet == null) return; + + MyObjectBuilder_CubeGrid[] cubeGridObs = Session.Instance.GetGridFromGridData(packet.ob, packet.intValue, packet.hangarType); + if (cubeGridObs == null) + { + MyVisualScriptLogicProvider.SendChatMessageColored($"Failed to get grids", Color.Red, "[FactionHangar]", MyAPIGateway.Session.Player.IdentityId, "Red"); + return; + } + + Session.Instance.SpawnClientSideProjectedGrid(cubeGridObs); + } + + // Server + if (package.Type == DataType.SendObToSpawn) + { + var packet = MyAPIGateway.Utilities.SerializeFromBinary(package.Data); + if (packet == null) return; + + Session.Instance.SpawnGridsFromOb(packet.cubeGridObs, packet.intValue, packet.hangarType, packet.playerId, packet.cost, packet.spawnType, false); + } + + // Server + if (package.Type == DataType.RequestConfig) + { + var packet = MyAPIGateway.Utilities.SerializeFromBinary(package.Data); + if (packet == null) return; + + ServerSendConfig(Session.Instance.config, packet.steamId); + } + + // Client + if (package.Type == DataType.SendConfig) + { + var packet = MyAPIGateway.Utilities.SerializeFromBinary(package.Data); + if (packet == null) return; + + Session.Instance.config = packet.config; + foreach(var area in packet.config.spawnAreas) + { + if (area.inverseArea) + { + Session.Instance.useInverseSpawnArea = true; + return; + } + } + } + + // Server + if (package.Type == DataType.ClientRequestTransfer) + { + var packet = MyAPIGateway.Utilities.SerializeFromBinary(package.Data); + if (packet == null) return; + + IMyFaction faction = MyAPIGateway.Session.Factions.TryGetPlayerFaction(packet.playerId); + if (faction == null) + { + MyVisualScriptLogicProvider.SendChatMessageColored($"Need to be in a faction to transfer grids.", Color.Red, "[FactionHangar]", packet.playerId, "Red"); + return; + } + + if (packet.hangarType == HangarType.Faction) + Session.Instance.allHangarData.TransferPrivateToFaction(faction.FactionId, packet.intValue, packet.playerId); + else + Session.Instance.allHangarData.TransferFactionToPrivate(faction.FactionId, packet.intValue, packet.playerId); + + return; + } + + // Client + if (package.Type == DataType.AddClientCooldown) + { + var packet = MyAPIGateway.Utilities.SerializeFromBinary(package.Data); + if (packet == null) return; + + TimerType type = packet.timerType; + + if (type == TimerType.StorageCooldown) + Session.Instance.storeTimer = packet.intValue; + + if (type == TimerType.RetrievalCooldown) + Session.Instance.retrievalTimer = packet.intValue; + } + + // Server + if (package.Type == DataType.AddTime) + { + var packet = MyAPIGateway.Utilities.SerializeFromBinary(package.Data); + if (packet == null) return; + + IMyFaction faction = MyAPIGateway.Session.Factions.TryGetFactionById(packet.factionId); + if (faction == null) return; + + FactionTimers.AddTimer(faction, packet.timerType, packet.intValue); + } + + // All Clients + if (package.Type == DataType.UpdateIdentities) + { + var packet = MyAPIGateway.Utilities.SerializeFromBinary(package.Data); + if (packet == null) return; + + Session.Instance.allIdentities = packet.identityObs; + } + + // Server + if (package.Type == DataType.SendChatMessage) + { + var packet = MyAPIGateway.Utilities.SerializeFromBinary(package.Data); + if (packet == null) return; + + MyVisualScriptLogicProvider.SendChatMessageColored($"{packet.message}", packet.col, "[FactionHangar]", packet.playerId, $"{packet.color}"); + return; + } + } + catch (Exception ex) + { + + } + } + + public static void ClientRequestStoreGrid(long requesterId, long playerId, List gridData, string playerName, HangarType hangarType) + { + ObjectContainer oc = new ObjectContainer() + { + requesterId = requesterId, + playerId = playerId, + gridData = gridData, + stringData = playerName, + hangarType = hangarType + }; + + CommsPackage package = new CommsPackage(DataType.StoreGrid, oc); + var sendData = MyAPIGateway.Utilities.SerializeToBinary(package); + MyAPIGateway.Multiplayer.SendMessageToServer(handler, sendData); + } + + public static void ClientRequestFactionList(long playerId, string playerName) + { + ObjectContainer oc = new ObjectContainer() + { + playerId = playerId, + stringData = playerName, + }; + + CommsPackage package = new CommsPackage(DataType.FactionList, oc); + var sendData = MyAPIGateway.Utilities.SerializeToBinary(package); + MyAPIGateway.Multiplayer.SendMessageToServer(handler, sendData); + } + + public static void ClientRequestPrivateList(long playerId, string playerName) + { + ObjectContainer oc = new ObjectContainer() + { + playerId = playerId, + stringData = playerName + }; + + CommsPackage package = new CommsPackage(DataType.PrivateList, oc); + var sendData = MyAPIGateway.Utilities.SerializeToBinary(package); + MyAPIGateway.Multiplayer.SendMessageToServer(handler, sendData); + } + + public static void ClientLoadGrid(int index, long playerId, HangarType hangarType) + { + ObjectContainer oc = new ObjectContainer() + { + intValue = index, + playerId = playerId, + hangarType = hangarType + }; + + CommsPackage package = new CommsPackage(DataType.LoadFactionGrid, oc); + var sendData = MyAPIGateway.Utilities.SerializeToBinary(package); + MyAPIGateway.Multiplayer.SendMessageToServer(handler, sendData); + } + + public static void ClientRequestGridData(int index, long playerId, HangarType hangarType, ulong steamId, bool original, bool force) + { + ObjectContainer oc = new ObjectContainer() + { + intValue = index, + playerId = playerId, + hangarType = hangarType, + steamId = steamId, + originalLocation = original, + force = force + }; + + CommsPackage package = new CommsPackage(DataType.RequestGridData, oc); + var sendData = MyAPIGateway.Utilities.SerializeToBinary(package); + MyAPIGateway.Multiplayer.SendMessageToServer(handler, sendData); + } + + public static void SendOBToClient(MyObjectBuilder_Base data, ulong steamId, int index, HangarType hangarType) + { + ObjectContainer oc = new ObjectContainer() + { + ob = data, + intValue = index, + hangarType = hangarType + }; + + CommsPackage package = new CommsPackage(DataType.SendGridData, oc); + var sendData = MyAPIGateway.Utilities.SerializeToBinary(package); + MyAPIGateway.Multiplayer.SendMessageTo(handler, sendData, steamId); + } + + public static void SendGridsToSpawn(List obs, int index, HangarType hangarType, long playerId, long cost, SpawnType spawnType) + { + ObjectContainer oc = new ObjectContainer() + { + cubeGridObs = obs, + intValue = index, + hangarType = hangarType, + playerId = playerId, + cost = cost, + spawnType = spawnType + }; + + CommsPackage package = new CommsPackage(DataType.SendObToSpawn, oc); + var sendData = MyAPIGateway.Utilities.SerializeToBinary(package); + MyAPIGateway.Multiplayer.SendMessageToServer(handler, sendData); + } + + public static void ClientRequestConfig(ulong steamId) + { + ObjectContainer oc = new ObjectContainer() + { + steamId = steamId + }; + + CommsPackage package = new CommsPackage(DataType.RequestConfig, oc); + var sendData = MyAPIGateway.Utilities.SerializeToBinary(package); + MyAPIGateway.Multiplayer.SendMessageToServer(handler, sendData); + } + + public static void ServerSendConfig(Config config, ulong steamId) + { + ObjectContainer oc = new ObjectContainer() + { + config = config + }; + + CommsPackage package = new CommsPackage(DataType.SendConfig, oc); + var sendData = MyAPIGateway.Utilities.SerializeToBinary(package); + MyAPIGateway.Multiplayer.SendMessageTo(handler, sendData, steamId); + } + + public static void ClientRequestTransfer(int index, long playerId, HangarType hangarType) + { + ObjectContainer oc = new ObjectContainer() + { + intValue = index, + playerId = playerId, + hangarType = hangarType + }; + + CommsPackage package = new CommsPackage(DataType.ClientRequestTransfer, oc); + var sendData = MyAPIGateway.Utilities.SerializeToBinary(package); + MyAPIGateway.Multiplayer.SendMessageToServer(handler, sendData); + } + + public static void AddClientCooldown(ulong steamId, bool privateStorage, TimerType type) + { + if (steamId == 0) return; + int cooldown = 0; + if (type == TimerType.StorageCooldown) + { + if (privateStorage) + cooldown = Session.Instance.config.privateHangarConfig.privateHangarCooldown; + else + cooldown = Session.Instance.config.factionHangarConfig.factionHangarCooldown; + } + + if (type == TimerType.RetrievalCooldown) + { + if (privateStorage) + cooldown = Session.Instance.config.privateHangarConfig.privateRetrievalCooldown; + else + cooldown = Session.Instance.config.factionHangarConfig.factionRetrievalCooldown; + } + + ObjectContainer oc = new ObjectContainer() + { + intValue = cooldown, + timerType = type + }; + + CommsPackage package = new CommsPackage(DataType.AddClientCooldown, oc); + var sendData = MyAPIGateway.Utilities.SerializeToBinary(package); + MyAPIGateway.Multiplayer.SendMessageTo(handler, sendData, steamId); + } + + public static void SendIdentitiesToClients(List list) + { + if (list == null) + return; + + ObjectContainer oc = new ObjectContainer() + { + identityObs = new List(list) + }; + + CommsPackage package = new CommsPackage(DataType.UpdateIdentities, oc); + var sendData = MyAPIGateway.Utilities.SerializeToBinary(package); + MyAPIGateway.Multiplayer.SendMessageToOthers(handler, sendData); + } + + public static void RequestGridRemoval(int index, long playerId, HangarType hangarType) + { + ObjectContainer oc = new ObjectContainer() + { + intValue = index, + playerId = playerId, + hangarType = hangarType + }; + + CommsPackage package = new CommsPackage(DataType.RequestGridRemoval, oc); + var sendData = MyAPIGateway.Utilities.SerializeToBinary(package); + MyAPIGateway.Multiplayer.SendMessageToServer(handler, sendData); + } + + public static void RequestTransferFactionToPrivate(long playerId, int index) + { + ObjectContainer oc = new ObjectContainer() + { + intValue = index, + playerId = playerId + }; + + CommsPackage package = new CommsPackage(DataType.FactionToPrivateTransfer, oc); + var sendData = MyAPIGateway.Utilities.SerializeToBinary(package); + MyAPIGateway.Multiplayer.SendMessageToServer(handler, sendData); + } + + public static void RequestTransferPrivateToFaction(long playerId, int index) + { + ObjectContainer oc = new ObjectContainer() + { + intValue = index, + playerId = playerId + }; + + CommsPackage package = new CommsPackage(DataType.PrivateToFactionTransfer, oc); + var sendData = MyAPIGateway.Utilities.SerializeToBinary(package); + MyAPIGateway.Multiplayer.SendMessageToServer(handler, sendData); + } + + public static void SendChatMessage(string message, string color, long playerId, Color col) + { + ChatMessage cm = new ChatMessage() + { + message = message, + color = color, + playerId = playerId, + col = col + }; + + CommsPackage package = new CommsPackage(DataType.SendChatMessage, cm); + var sendData = MyAPIGateway.Utilities.SerializeToBinary(package); + MyAPIGateway.Multiplayer.SendMessageToServer(handler, sendData); + } + + public static void AddTimer(long factionId, TimerType timerType, int timeAmt) + { + ObjectContainer oc = new ObjectContainer() + { + factionId = factionId, + timerType = timerType, + intValue = timeAmt + }; + + CommsPackage package = new CommsPackage(DataType.AddTime, oc); + var sendData = MyAPIGateway.Utilities.SerializeToBinary(package); + MyAPIGateway.Multiplayer.SendMessageToServer(handler, sendData); + } + } +} diff --git a/TSTSSESHangar/Data/Scripts/FactionHangar/Session.cs b/TSTSSESHangar/Data/Scripts/FactionHangar/Session.cs new file mode 100644 index 00000000..1a240f5a --- /dev/null +++ b/TSTSSESHangar/Data/Scripts/FactionHangar/Session.cs @@ -0,0 +1,2404 @@ +using Sandbox.ModAPI; +using VRage.Game.Components; +using VRageMath; +using Sandbox.Game.Entities; +using VRage.Game.Entity; +using VRage.Game.ModAPI; +using Sandbox.Game; +using VRage.Game; +using VRage.ModAPI; +using VRage.ObjectBuilders; +using VRage.Utils; +using VRage; +using System; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using VRage.Input; +using System.Runtime.CompilerServices; +using Sandbox.Definitions; +using VRage.GameServices; +using System.Net; +using System.Linq; +using Sandbox.Game.Weapons.Guns; +using System.Collections.Concurrent; +using VRage.Game.ModAPI.Ingame.Utilities; +using System.Text; +using VRageRender; +using Sandbox.Game.Entities.Cube; +using Sandbox.Game.Entities.Character; +using System.Net.Sockets; + +namespace CustomHangar +{ + [MySessionComponentDescriptor(MyUpdateOrder.BeforeSimulation)] + public class Session : MySessionComponentBase + { + public bool isServer; + public bool isDedicated; + public ConcurrentDictionary> factionGrids = new ConcurrentDictionary>(); + public ConcurrentDictionary> playerGrids = new ConcurrentDictionary>(); + public static Session Instance; + public readonly ushort NetworkHandle = 2355; + + public Dictionary factionSlotTotals = new Dictionary(); + public Dictionary privateSlotTotals = new Dictionary(); + public Config config; + public List allIdentities = new List(); + public const string path = "{0}.xml"; + public List hangarDelay = new List(); + public int ticks; + public List npcs = new List(); + + public AllHangarData allHangarData = new AllHangarData(); + public CacheGridsForStorage gridsToStore = new CacheGridsForStorage(); + public List enemyBlockCheckList = new List(); + public Dictionary cooldownTimers = new Dictionary(); + public List cacheGridPaths = new List(); + + //ClientSide Vars + public List previewGrids = new List(); + private bool enableInput; + private bool RotateX; + private bool RotateY; + private bool RotateZ; + private bool nRotateX; + private bool nRotateY; + private bool nRotateZ; + private float RotationSpeed = 0.01f; + private int previewDistance = 50; + private bool allowSpawn; + private int spawnIndex = -1; + private HangarType hangarType = HangarType.Faction; + public Vector3D original = new Vector3D(); + public float previewMass; + public SpawnType spawnType = SpawnType.None; + public bool useInverseSpawnArea; + public IMyPlayer playerCache = null; + private Vector3D startCoordsCache = new Vector3D(); + private Vector3D endCoordCache= new Vector3D(); + public List clientSpawnLocations = new List(); + private bool init; + private IMyHudNotification hudNotify; + private long spawnCost; + private SpawnError spawnError = SpawnError.None; + public long playerWallet; + public long factionWallet; + private bool drawClientSphereDebug = true; + public bool spawnClientGPS = true; + + // Client timers + public int retrievalTimer; + public int storeTimer; + + + + // TODO + // Complete spawn areas inverse + // Complete enemy checks by block type + // Check spawn for players/grids intersection before pasteing + // Remove funds from faction/player wallets + + // Add check for small grids voxel intersection if config is set to false + + // Add change ownership of grid if leader spawns it and the owner is no longer apart of the faction + // Add spawn config limits + // Add private hangar load/transfer/list + // Add potiental grids that can be stored nearby command + // Remove items from hands when projecting grid clientside + // Adding items to hand after projection will clear projection + + + // Add an exclusion list to omit grids from being hangared by autohangar + // ent.Components.Get() + // Add enemy checks for storing for faction/private hangars + + // Add exclusions to autohangar + // Add Cost to spawn other options + // Add bypass cost to spawn for autohangar on alls spawning options + + // Add velocity check when storing grids + // Add limits check when using autohangar + + // *Fix check enemies by block type not working + // *Add more logging/nofications + // *Run spawning grids per physical connection in offset ticks + // *Add grid below surface to autohangar + // *Fix connectors not staying connected when spawning grid from autohangar(physical connections) + // *Add nofication to first player that logins when their stuff has been autohangared + // *Add damage resets/stops timer to delay grid storage + // *Add plugin for admin commands via console + // *Add velocity check when storing grids + // *Add save file for client commands + // *Check for SC cost for all spawning options + // *Fix allPlayers not syncing in mp + // *Fix FSZ crashing when checking smallgrids static/subgrids because autohangar is deleting grids, need to check all grids grid.MarkedForClose() + // *Adjust spawn areas to be free for spawning autohangared grids but doesn't exist otherwise + // *Clamp min cost for dynamic spawning with config + // *Remove mechanical connections from potencial grids to store + + public override void BeforeStart() + { + Instance = this; + isServer = MyAPIGateway.Session.IsServer; + isDedicated = MyAPIGateway.Utilities.IsDedicated; + MyAPIGateway.Multiplayer.RegisterMessageHandler(NetworkHandle, Comms.MessageHandler); + MyAPIGateway.Utilities.MessageEntered += ChatHandler; + + if (isServer) + { + config = Config.LoadConfig(); + foreach (var area in config.spawnAreas) + { + if (area.inverseArea) + { + useInverseSpawnArea = true; + break; + } + } + + allHangarData = AllHangarData.LoadHangarData(); + + if (isDedicated) + { + if (config.enemyCheckConfig.enableBlockCheck) + { + //MyAPIGateway.Entities.OnEntityAdd += OnBlockAdded; + //MyAPIGateway.Entities.OnEntityAdd += OnBlockRemoved; + MyEntities.OnEntityCreate += OnBlockAdded; + MyEntities.OnEntityRemove += OnBlockRemoved; + } + } + } + + if (!isDedicated) + MyVisualScriptLogicProvider.ToolEquipped += ToolEquipped; + } + + public void UpdateIdentities() + { + var save = MyAPIGateway.Session.GetCheckpoint(MyAPIGateway.Session.Name); + if (save == null) return; + + allIdentities = save.Identities; + if (allIdentities == null) + return; + + Comms.SendIdentitiesToClients(allIdentities); + } + + private void CheckLastLogOff() + { + UpdateIdentities(); + if (!config.autoHangarConfig.enableAutoHangar) return; + + Dictionary factionsToHangar = new Dictionary(); + List expiredFactions = new List(); + List expiredPlayers = new List(); + + foreach(var identity in allIdentities) + { + IMyFaction faction = MyAPIGateway.Session.Factions.TryGetPlayerFaction(identity.IdentityId); + + if (faction != null) + { + if (faction.Tag.Length > 3 || faction.IsEveryoneNpc()) continue; + + bool excludeFaction = false; + foreach(var excludedTag in config.autoHangarConfig.exclusions.excludedFactions.excludedFaction) + { + if (faction.Tag != excludedTag) continue; + excludeFaction = true; + break; + } + if (excludeFaction) continue; + + if (!factionsToHangar.ContainsKey(faction)) + factionsToHangar.Add(faction, true); + } + + MyLog.Default.WriteLineAndConsole($"[FactionHangar] Player = {identity.DisplayName} Last Login: {DateTime.Now - identity.LastLogoutTime} / Config: {TimeSpan.FromDays(config.autoHangarConfig.daysFactionLogin)}"); + + if (DateTime.Now - identity.LastLogoutTime >= TimeSpan.FromDays(config.autoHangarConfig.daysFactionLogin)) + { + MyLog.Default.WriteLineAndConsole($"[FactionHangar] Player {identity.DisplayName} hasn't logged in within {config.autoHangarConfig.daysFactionLogin} days."); + + if (faction != null) + { + if (!factionsToHangar.ContainsKey(faction)) continue; + if (!factionsToHangar[faction]) continue; + } + else + { + if (expiredPlayers.Contains(identity.IdentityId)) + continue; + else + expiredPlayers.Add(identity.IdentityId); + } + } + else + { + if (faction != null) + { + if (!factionsToHangar.ContainsKey(faction)) continue; + factionsToHangar[faction] = false; + } + } + } + + foreach(var faction in factionsToHangar.Keys) + { + if (factionsToHangar[faction]) + expiredFactions.Add(faction); + } + + if (expiredFactions.Count > 0 || expiredPlayers.Count > 0) + { + HashSet ents = new HashSet(); + List physicalGroup = new List(); + List processedGrids = new List(); + MyAPIGateway.Entities.GetEntities(ents); + + factionGrids.Clear(); + playerGrids.Clear(); + + foreach(var ent in ents) + { + IMyCubeGrid grid = ent as IMyCubeGrid; + if (grid == null) continue; + + if (processedGrids.Contains(grid)) continue; + long owner = grid.BigOwners.FirstOrDefault(); + IMyFaction faction = MyAPIGateway.Session.Factions.TryGetPlayerFaction(owner); + GetGroupByType(grid, physicalGroup, GridLinkTypeEnum.Physical); + if (faction != null) + { + if (factionGrids.ContainsKey(faction)) + { + if (factionGrids[faction].Contains(grid)) continue; + + factionGrids[faction].Enqueue(grid); + processedGrids.Add(grid); + foreach(var connectedGrid in physicalGroup) + { + if (grid == connectedGrid) continue; + factionGrids[faction].Enqueue(grid); + processedGrids.Add(grid); + } + } + else + { + ConcurrentQueue temp = new ConcurrentQueue(); + temp.Enqueue(grid); + processedGrids.Add(grid); + foreach (var connectedGrid in physicalGroup) + { + if (grid == connectedGrid) continue; + temp.Enqueue(grid); + processedGrids.Add(grid); + } + factionGrids.TryAdd(faction, temp); + } + + } + else + { + if (playerGrids.ContainsKey(owner)) + { + playerGrids[owner].Enqueue(grid); + processedGrids.Add(grid); + foreach (var connectedGrid in physicalGroup) + { + if (grid == connectedGrid) continue; + playerGrids[owner].Enqueue(grid); + processedGrids.Add(grid); + } + } + else + { + ConcurrentQueue temp = new ConcurrentQueue(); + temp.Enqueue(grid); + processedGrids.Add(grid); + foreach (var connectedGrid in physicalGroup) + { + if (grid == connectedGrid) continue; + temp.Enqueue(grid); + processedGrids.Add(grid); + } + playerGrids.TryAdd(owner, temp); + } + + } + } + } + + if (expiredFactions.Count > 0) + { + foreach (var faction in expiredFactions) + AutoHangar(faction, 0); + + } + + if (expiredPlayers.Count > 0) + { + foreach (var playerId in expiredPlayers) + AutoHangar(null, playerId); + } + + } + + private void AutoHangar(IMyFaction faction, long playerId) + { + if (faction != null) + { + ConcurrentQueue grids = new ConcurrentQueue(); + IMyCubeGrid grid = null; + factionGrids.TryGetValue(faction, out grids); + List foundGridsList = new List(); + + if (grids == null) + return; + + while (grids.Count > 0) + { + grid = null; + if (grids.TryDequeue(out grid)) + { + if (grid == null) continue; + + if (foundGridsList.Contains(grid)) continue; + + List connectedGrids = new List(); + GetGroupByType(grid, connectedGrids, GridLinkTypeEnum.Physical); + MyCubeGrid cubeGrid = grid as MyCubeGrid; + MyCubeGrid biggestGrid = cubeGrid.GetBiggestGridInGroup(); + if (biggestGrid == null) + return; + + bool excludeGrid = false; + foundGridsList.Add(grid); + if (Utils.CheckForExcludedBlock(grid as MyCubeGrid)) + excludeGrid = true; + + foreach (var connectedGrid in connectedGrids) + { + if (connectedGrid == grid) continue; + foundGridsList.Add(connectedGrid); + if (!excludeGrid) + if (Utils.CheckForExcludedBlock(connectedGrid as MyCubeGrid)) + excludeGrid = true; + } + if (excludeGrid) continue; + + long owner = biggestGrid.BigOwners.FirstOrDefault(); + string playerName = GetPlayerName(owner); + RequestingGridStorage(owner, owner, biggestGrid.EntityId, playerName, false, true); + } + } + } + + if (playerId != 0) + { + ConcurrentQueue grids = new ConcurrentQueue(); + IMyCubeGrid grid = null; + playerGrids.TryGetValue(playerId, out grids); + List foundGridsList = new List(); + + if (grids == null) + return; + + while (grids.Count > 0) + { + grid = null; + if (grids.TryDequeue(out grid)) + { + if (grid == null) continue; + if (foundGridsList.Contains(grid)) continue; + + List connectedGrids = new List(); + GetGroupByType(grid, connectedGrids, GridLinkTypeEnum.Physical); + MyCubeGrid cubeGrid = grid as MyCubeGrid; + MyCubeGrid biggestGrid = cubeGrid.GetBiggestGridInGroup(); + + foundGridsList.Add(grid); + foreach (var connectedGrid in connectedGrids) + { + if (connectedGrid == grid) continue; + foundGridsList.Add(connectedGrid); + } + + long owner = biggestGrid.BigOwners.FirstOrDefault(); + string playerName = GetPlayerName(owner); + RequestingGridStorage(owner, owner, biggestGrid.EntityId, playerName, true, true); + } + } + } + } + + public new void HandleInput() + { + if (isServer && isDedicated) return; + if (!enableInput) return; + + if (playerCache.Character == null || playerCache.Character.IsDead) + return; + + UpdatePosition(); + DetectSpawnType(); + //spawnCost = CalculateCost(); + //UpdateHudMessage(); + + if (MyAPIGateway.Input.IsKeyPress(MyKeys.Home)) + RotateX = true; + else + RotateX = false; + + if (MyAPIGateway.Input.IsKeyPress(MyKeys.End)) + nRotateX = true; + else + nRotateX = false; + + if (MyAPIGateway.Input.IsKeyPress(MyKeys.Delete)) + RotateY = true; + else + RotateY = false; + + if (MyAPIGateway.Input.IsKeyPress(MyKeys.PageDown)) + nRotateY = true; + else + nRotateY = false; + + if (MyAPIGateway.Input.IsKeyPress(MyKeys.Insert)) + RotateZ = true; + else + RotateZ = false; + + if (MyAPIGateway.Input.IsKeyPress(MyKeys.PageUp)) + nRotateZ = true; + else + nRotateZ = false; + + if (MyAPIGateway.Input.IsKeyPress(MyKeys.D0)) + RemovePreviewGrids(); + + if (MyAPIGateway.Input.IsNewLeftMousePressed()) + TrySpawnPlacement(); + + if (MyAPIGateway.Input.IsKeyPress(MyKeys.LeftAlt)) + { + var rotateSpeed = MyAPIGateway.Input.DeltaMouseScrollWheelValue(); + if (rotateSpeed > 0) + RotationSpeed += .001f; + else if (rotateSpeed < 0) + RotationSpeed -= .001f; + + RotationSpeed = MathHelper.Clamp(RotationSpeed, .01f, .2f); + return; + } + + var dScroll = MyAPIGateway.Input.DeltaMouseScrollWheelValue(); + + if (dScroll > 0) + previewDistance++; + else if (dScroll < 0) + previewDistance--; + + previewDistance = MathHelper.Clamp(previewDistance, 10, 70); + } + + private void UpdatePosition() + { + //startCoordsCache = playerCache.Character.GetPosition(); + //endCoordCache = playerCache.Character.WorldMatrix.Forward * previewDistance + startCoordsCache; + startCoordsCache = MyAPIGateway.Session.Camera.Position; + endCoordCache = MyAPIGateway.Session.Camera.WorldMatrix.Forward * previewDistance + startCoordsCache; + } + + private void UpdateHudMessage() + { + if (allowSpawn) + spawnError = SpawnError.None; + + if (hudNotify != null) + { + hudNotify.Hide(); + hudNotify.Text = $"[Valid Spawn] = {allowSpawn} | [Cost To Spawn] = {spawnCost} SC | [SpawnOption] = {spawnType} | [SpawningError] = {spawnError}"; + hudNotify.Show(); + } + } + + private void DetectSpawnType(bool force = false) + { + if (!force) + if (ticks % 10 != 0) return; + + if (previewGrids == null || previewGrids.Count == 0) return; + spawnError = SpawnError.None; + + + + double distance = Vector3D.Distance(endCoordCache, original); + + if (config.spawnNearbyConfig.allowSpawnNearby) + { + if (distance <= config.spawnNearbyConfig.nearbyRadius) + { + spawnType = SpawnType.Nearby; + bool result = IsEnemyNear(); + if (result) + spawnError = SpawnError.EnemyNearby; + + spawnCost = config.spawnNearbyConfig.nearbySpawnCost; + bool canAfford = spawnCost <= factionWallet ? true : spawnCost <= playerWallet; + if (!canAfford) + spawnError = SpawnError.InsuffientFunds; + + bool intersecting = Utils.IsGridIntersecting(previewGrids); + if (intersecting) + spawnError = SpawnError.EntityBlockingPlacement; + + allowSpawn = !result && canAfford && !intersecting; + UpdateHudMessage(); + return; + } + } + + foreach (var area in config.spawnAreas) + { + if (!area.enableSpawnArea) continue; + if (useInverseSpawnArea) + { + if (Vector3D.Distance(endCoordCache, area.areaCenter) <= area.areaRadius) continue; + spawnType = SpawnType.SpawnArea; + spawnCost = area.spawnAreaCost; + bool result = IsEnemyNear(area); + if (result) + spawnError = SpawnError.EnemyNearby; + + bool canAfford = spawnCost <= factionWallet ? true : spawnCost <= playerWallet; + if (!canAfford) + spawnError = SpawnError.InsuffientFunds; + + bool intersecting = Utils.IsGridIntersecting(previewGrids); + if (intersecting) + spawnError = SpawnError.EntityBlockingPlacement; + + allowSpawn = !result && canAfford && !intersecting; + UpdateHudMessage(); + return; + } + else + { + if (Vector3D.Distance(endCoordCache, area.areaCenter) > area.areaRadius) continue; + spawnType = SpawnType.SpawnArea; + spawnCost = area.spawnAreaCost; + bool result2 = IsEnemyNear(area); + if (result2) + spawnError = SpawnError.EnemyNearby; + + bool canAfford2 = spawnCost <= factionWallet ? true : spawnCost <= playerWallet; + if (!canAfford2) + spawnError = SpawnError.InsuffientFunds; + + bool intersecting2 = Utils.IsGridIntersecting(previewGrids); + if (intersecting2) + spawnError = SpawnError.EntityBlockingPlacement; + + allowSpawn = !result2 && canAfford2 && !intersecting2; + UpdateHudMessage(); + return; + } + } + + if (config.dynamicSpawningConfig.enableDynamicSpawning) + { + spawnCost = CalculateCost(); + if (!useInverseSpawnArea) + { + spawnType = SpawnType.Dynamic; + bool result = IsEnemyNear(); + if (result) + spawnError = SpawnError.EnemyNearby; + + bool canAfford = spawnCost <= factionWallet ? true : spawnCost <= playerWallet; + if (!canAfford) + spawnError = SpawnError.InsuffientFunds; + + bool intersecting = Utils.IsGridIntersecting(previewGrids); + if (intersecting) + spawnError = SpawnError.EntityBlockingPlacement; + + allowSpawn = !result && canAfford && !intersecting; + UpdateHudMessage(); + return; + } + } + + allowSpawn = false; + spawnError = SpawnError.InvalidSpawningLocation; + UpdateHudMessage(); + } + + public bool IsEnemyNear() + { + if (previewGrids == null || previewGrids.Count == 0) return false; + long spawnOwner = isDedicated && isServer ? previewGrids[0].BigOwners.FirstOrDefault() : playerCache.IdentityId; + List ents = new List(); + if (!config.enemyCheckConfig.enableBlockCheck) + { + if (spawnType == SpawnType.Nearby && config.spawnNearbyConfig.nearbyEnemyCheck.checkEnemiesNearby) + { + GetEntitiesInSphere(ents, endCoordCache, config.spawnNearbyConfig.nearbyEnemyCheck.enemyDistanceCheck); + return IsGridEnemy(ents, spawnOwner, config.spawnNearbyConfig.nearbyEnemyCheck.alliesFriendly, config.spawnNearbyConfig.nearbyEnemyCheck.omitNPCs); + } + + if (spawnType == SpawnType.Dynamic && config.dynamicSpawningConfig.dynamicEnemyCheck.checkEnemiesNearby) + { + GetEntitiesInSphere(ents, endCoordCache, config.dynamicSpawningConfig.dynamicEnemyCheck.enemyDistanceCheck); + return IsGridEnemy(ents, spawnOwner, config.dynamicSpawningConfig.dynamicEnemyCheck.alliesFriendly, config.dynamicSpawningConfig.dynamicEnemyCheck.omitNPCs); + } + } + else + { + if (spawnType == SpawnType.Nearby && config.spawnNearbyConfig.nearbyEnemyCheck.checkEnemiesNearby) + { + foreach (var block in enemyBlockCheckList) + { + if (Vector3D.Distance(endCoordCache, block.GetPosition()) > config.spawnNearbyConfig.nearbyEnemyCheck.enemyDistanceCheck) continue; + bool result = IsBlockEnemy(block, spawnOwner, config.spawnNearbyConfig.nearbyEnemyCheck.alliesFriendly, config.spawnNearbyConfig.nearbyEnemyCheck.omitNPCs); + + if (result) + return true; + } + } + + if (spawnType == SpawnType.Dynamic && config.dynamicSpawningConfig.dynamicEnemyCheck.checkEnemiesNearby) + { + foreach (var block in enemyBlockCheckList) + { + if (Vector3D.Distance(endCoordCache, block.GetPosition()) > config.dynamicSpawningConfig.dynamicEnemyCheck.enemyDistanceCheck) continue; + bool result = IsBlockEnemy(block, spawnOwner, config.dynamicSpawningConfig.dynamicEnemyCheck.alliesFriendly, config.dynamicSpawningConfig.dynamicEnemyCheck.omitNPCs); + + if (result) + return true; + } + } + } + + return false; + } + + public bool IsEnemyNear(MyObjectBuilder_CubeGrid gridOb, long gridOwner) + { + gridOwner = isServer && isDedicated ? gridOwner : playerCache.IdentityId; + Vector3D pos = gridOb.PositionAndOrientation.Value.Position; + List ents = new List(); + + if (!config.enemyCheckConfig.enableBlockCheck) + { + if (spawnType == SpawnType.Original && config.spawnOriginalConfig.originalEnemyCheck.checkEnemiesNearby) + { + GetEntitiesInSphere(ents, pos, config.spawnOriginalConfig.originalEnemyCheck.enemyDistanceCheck); + return IsGridEnemy(ents, gridOwner, config.spawnOriginalConfig.originalEnemyCheck.alliesFriendly, config.spawnOriginalConfig.originalEnemyCheck.omitNPCs); + } + } + else + { + if (spawnType == SpawnType.Original && config.spawnOriginalConfig.originalEnemyCheck.checkEnemiesNearby) + { + foreach (var block in enemyBlockCheckList) + { + if (Vector3D.Distance(pos, block.GetPosition()) > config.spawnOriginalConfig.originalEnemyCheck.enemyDistanceCheck) continue; + bool result = IsBlockEnemy(block, gridOwner, config.spawnOriginalConfig.originalEnemyCheck.alliesFriendly, config.spawnOriginalConfig.originalEnemyCheck.omitNPCs); + + if (result) + return true; + } + } + } + + return false; + } + + private bool IsEnemyNear(SpawnAreas area) + { + if (previewGrids == null || previewGrids.Count == 0) return false; + long spawnOwner = isServer && isDedicated ? previewGrids[0].BigOwners.FirstOrDefault() : playerCache.IdentityId; + List ents = new List(); + + if (!config.enemyCheckConfig.enableBlockCheck) + { + if (area.spawnAreasEnemyCheck.checkEnemiesNearby) + { + GetEntitiesInSphere(ents, endCoordCache, area.spawnAreasEnemyCheck.enemyDistanceCheck); + return IsGridEnemy(ents, spawnOwner, area.spawnAreasEnemyCheck.alliesFriendly, area.spawnAreasEnemyCheck.omitNPCs); + } + } + else + { + if (area.spawnAreasEnemyCheck.checkEnemiesNearby) + { + foreach (var block in enemyBlockCheckList) + { + if (Vector3D.Distance(block.GetPosition(), endCoordCache) > area.spawnAreasEnemyCheck.enemyDistanceCheck) continue; + bool result = IsBlockEnemy(block, spawnOwner, area.spawnAreasEnemyCheck.alliesFriendly, area.spawnAreasEnemyCheck.omitNPCs); + + if (result) + return true; + } + } + } + + return false; + } + + private bool IsEnemyNearStoring(IMyCubeGrid grid, HangarType hangarType) + { + if (grid == null) return false; + long owner = isServer && isDedicated ? grid.BigOwners.FirstOrDefault() : playerCache.IdentityId; + List ents = new List(); + + if (!config.enemyCheckConfig.enableBlockCheck) + { + if (hangarType == HangarType.Faction) + { + if (config.factionHangarConfig.factionHangarEnemyCheck.checkEnemiesNearby) + { + GetEntitiesInSphere(ents, grid.GetPosition(), config.factionHangarConfig.factionHangarEnemyCheck.enemyDistanceCheck); + return IsGridEnemy(ents, owner, config.factionHangarConfig.factionHangarEnemyCheck.alliesFriendly, config.factionHangarConfig.factionHangarEnemyCheck.omitNPCs); + } + } + + if (hangarType == HangarType.Private) + { + if (config.privateHangarConfig.privateHangarEnemyCheck.checkEnemiesNearby) + { + GetEntitiesInSphere(ents, grid.GetPosition(), config.privateHangarConfig.privateHangarEnemyCheck.enemyDistanceCheck); + return IsGridEnemy(ents, owner, config.privateHangarConfig.privateHangarEnemyCheck.alliesFriendly, config.privateHangarConfig.privateHangarEnemyCheck.omitNPCs); + } + } + } + else + { + if (hangarType == HangarType.Faction) + { + if (config.factionHangarConfig.factionHangarEnemyCheck.checkEnemiesNearby) + { + foreach (var block in enemyBlockCheckList) + { + if (Vector3D.Distance(grid.GetPosition(), block.GetPosition()) > config.factionHangarConfig.factionHangarEnemyCheck.enemyDistanceCheck) continue; + bool result = IsBlockEnemy(block, owner, config.factionHangarConfig.factionHangarEnemyCheck.alliesFriendly, config.privateHangarConfig.privateHangarEnemyCheck.omitNPCs); + + if (result) + return true; + } + } + + if (config.privateHangarConfig.privateHangarEnemyCheck.checkEnemiesNearby) + { + foreach (var block in enemyBlockCheckList) + { + if (Vector3D.Distance(grid.GetPosition(), block.GetPosition()) > config.privateHangarConfig.privateHangarEnemyCheck.enemyDistanceCheck) continue; + bool result = IsBlockEnemy(block, owner, config.privateHangarConfig.privateHangarEnemyCheck.alliesFriendly, config.privateHangarConfig.privateHangarEnemyCheck.omitNPCs); + + if (result) + return true; + } + } + } + } + + return false; + } + + private bool IsGridEnemy(List ents, long spawnOwner, bool alliesFriendly, bool omitNPC) + { + IMyFaction myFaction = MyAPIGateway.Session.Factions.TryGetPlayerFaction(spawnOwner); + foreach (var ent in ents) + { + if (ent.MarkedForClose) continue; + IMyCubeGrid grid = ent as IMyCubeGrid; + if (grid == null) continue; + if (grid.Physics == null) continue; + //if (grid == previewGrids[0] || grid.IsSameConstructAs(previewGrids[0])) continue; + + long owner = grid.BigOwners.FirstOrDefault(); + if (owner == spawnOwner || owner == 0) continue; + IMyFaction otherFaction = MyAPIGateway.Session.Factions.TryGetPlayerFaction(owner); + if (otherFaction != null && omitNPC) + if (otherFaction.IsEveryoneNpc() || otherFaction.Tag.Length > 3) return false; + + bool result = AreFactionsEnemies(myFaction, otherFaction, alliesFriendly); + + if (result) return true; + } + + return false; + } + + private bool IsBlockEnemy(IMyCubeBlock block, long spawnOwner, bool alliesFriendly, bool omitNPC) + { + IMyFaction myFaction = MyAPIGateway.Session.Factions.TryGetPlayerFaction(spawnOwner); + + + long owner = block.OwnerId; + if (owner == spawnOwner || owner == 0) return false; + IMyFaction otherFaction = MyAPIGateway.Session.Factions.TryGetPlayerFaction(owner); + if (otherFaction != null && omitNPC) + if (otherFaction.IsEveryoneNpc() || otherFaction.Tag.Length > 3) return false; + + bool result = AreFactionsEnemies(myFaction, otherFaction, alliesFriendly); + if (result) return true; + + return false; + } + + private bool AreFactionsEnemies(IMyFaction faction1, IMyFaction faction2, bool alliesFriendly) + { + if (faction1 == null || faction2 == null) return true; + if (faction1 == faction2) return false; + + var relation = MyAPIGateway.Session.Factions.GetRelationBetweenFactions(faction1.FactionId, faction2.FactionId); + if (relation == MyRelationsBetweenFactions.Enemies) return true; + if (relation == MyRelationsBetweenFactions.Friends) + if (!alliesFriendly) return true; + + return false; + } + + public long CalculateCost() + { + float cost = 0; + double distance = Vector3D.Distance(endCoordCache, original); + + if (spawnType == SpawnType.Dynamic) + { + cost = (previewMass * (float)distance) * config.dynamicSpawningConfig.costMultiplier; + return (long)cost; + } + + return 0; + } + + private void DrawBoundingBox() + { + List entities = new List(); + GetEntitiesInSphere(entities, playerCache.GetPosition(), 200); + + Color otherCol = Color.White; + foreach (var ent in entities) + { + IMyCubeGrid grid = ent as IMyCubeGrid; + if (grid == null) continue; + + if (previewGrids.Contains(grid)) continue; + var myPosition = playerCache.GetPosition(); + var vectorToAste = grid.GetPosition() - myPosition; + var relativeVector = Vector3D.TransformNormal(vectorToAste, MatrixD.Transpose(playerCache.Character.WorldMatrix)); + if (relativeVector.Z > 0) // behind us + continue; + + BoundingBoxD boundingBoxD = grid.PositionComp.LocalAABB; + MatrixD matrixD = grid.PositionComp.WorldMatrixRef; + MySimpleObjectDraw.DrawTransparentBox(ref matrixD, ref boundingBoxD, ref otherCol, MySimpleObjectRasterizer.Wireframe, 1, 0.04f, null, MyStringId.GetOrCompute("WeaponLaser"), false, -1, MyBillboard.BlendTypeEnum.Standard, 1f, null); + } + + Color color = allowSpawn ? Color.LightGreen : Color.Red; + foreach (var grid in previewGrids) + { + BoundingBoxD boundingBoxD = grid.PositionComp.LocalAABB; + MatrixD matrixD = grid.PositionComp.WorldMatrixRef; + MySimpleObjectDraw.DrawTransparentBox(ref matrixD, ref boundingBoxD, ref color, MySimpleObjectRasterizer.Wireframe, 1, 0.04f, null, MyStringId.GetOrCompute("WeaponLaser"), false, -1, MyBillboard.BlendTypeEnum.Standard, 1f, null); + } + } + + public override void Draw() + { + if (isServer && isDedicated) return; + if (previewGrids != null && previewGrids.Count != 0 && previewMass != 0) + { + if (playerCache.Character == null || playerCache.Character.IsDead) + { + RemovePreviewGrids(); + return; + } + + DrawSpawnAreas(); + DrawBoundingBox(); + enableInput = true; + + IMyEntity ent = previewGrids[0] as IMyEntity; + var center = ent.WorldAABB.Center; + var matrix = ent.WorldMatrix; + var entPos = ent.GetPosition(); + var diff = entPos - center; + + //Vector3D startCoords = playerCache.Character.GetPosition(); + //Vector3D endCoords = playerCache.Character.WorldMatrix.Forward * previewDistance + startCoords; + Vector3D startCoords = MyAPIGateway.Session.Camera.Position; + Vector3D endCoords = MyAPIGateway.Session.Camera.WorldMatrix.Forward * previewDistance + startCoords; + //MatrixD endCoordsMatrix = MatrixD.CreateWorld(endCoords); + + ent.PositionComp.SetPosition(endCoords + diff); + + for (int i = 0; i < previewGrids.Count; i++) + { + if (i == 0) continue; + IMyEntity subEnt = previewGrids[i] as IMyEntity; + var subDiff = subEnt.GetPosition() - entPos; + subEnt.PositionComp.SetPosition(endCoords + subDiff + diff); + } + + if (RotateX || RotateY || RotateZ || nRotateX || nRotateY || nRotateZ) + { + center = ent.WorldAABB.Center; + matrix = ent.WorldMatrix; + var OffsetVector3 = center; + MatrixD rotationMatrix = MatrixD.Zero; + var up = matrix.Up; + var left = matrix.Left; + var forward = matrix.Forward; + up = Vector3D.Normalize(up); + left = Vector3D.Normalize(left); + forward = Vector3D.Normalize(forward); + + if (RotateX) rotationMatrix = MatrixD.CreateFromAxisAngle(left, RotationSpeed); + if (nRotateX) rotationMatrix = MatrixD.CreateFromAxisAngle(-left, RotationSpeed); + + if (RotateY) rotationMatrix = MatrixD.CreateFromAxisAngle(up, RotationSpeed); + if (nRotateY) rotationMatrix = MatrixD.CreateFromAxisAngle(-up, RotationSpeed); + + if (RotateZ) rotationMatrix = MatrixD.CreateFromAxisAngle(forward, RotationSpeed); + if (nRotateZ) rotationMatrix = MatrixD.CreateFromAxisAngle(-forward, RotationSpeed); + + /*if (RotateY) + { + if (RotateX) rotationMatrix *= MatrixD.CreateFromAxisAngle(up, RotationSpeed); + else rotationMatrix = MatrixD.CreateFromAxisAngle(up, RotationSpeed); + } + + if (RotateZ) + { + if (RotateY || RotateX) rotationMatrix *= MatrixD.CreateFromAxisAngle(forward, RotationSpeed); + else rotationMatrix = MatrixD.CreateFromAxisAngle(forward, RotationSpeed); + }*/ + + rotationMatrix = MatrixD.CreateTranslation(-OffsetVector3) * rotationMatrix * MatrixD.CreateTranslation(OffsetVector3); + + matrix *= rotationMatrix; + ent.SetWorldMatrix(matrix); + UpdateSubgrids(rotationMatrix); + } + + } + else + enableInput = false; + } + + public void UpdateSubgrids(MatrixD rotationMat) + { + for (int i = 0; i < previewGrids.Count; i++) + { + if (i == 0) continue; + + MatrixD matrix = previewGrids[i].WorldMatrix; + matrix *= rotationMat; + previewGrids[i].PositionComp.SetWorldMatrix(ref matrix); + } + } + + private void DrawSpawnAreas() + { + if (!drawClientSphereDebug) return; + foreach(var area in config.spawnAreas) + { + if (!area.enableSpawnArea) continue; + + MatrixD mat = MatrixD.CreateWorld(area.areaCenter); + Color color = Color.LightBlue; + MySimpleObjectDraw.DrawTransparentSphere(ref mat, area.areaRadius, ref color, MySimpleObjectRasterizer.Wireframe, 70, null, MyStringId.GetOrCompute("WeaponLaser"), 1f, -1, null, VRageRender.MyBillboard.BlendTypeEnum.Standard, 10f); + } + + if (config.spawnNearbyConfig.allowSpawnNearby) + { + MatrixD mat = MatrixD.CreateWorld(original); + Color color = Color.LightGreen; + MySimpleObjectDraw.DrawTransparentSphere(ref mat, config.spawnNearbyConfig.nearbyRadius, ref color, MySimpleObjectRasterizer.Wireframe, 70, null, MyStringId.GetOrCompute("WeaponLaser"), .09f, -1, null, VRageRender.MyBillboard.BlendTypeEnum.Standard, 10f); + } + } + + public override void UpdateBeforeSimulation() + { + Init(); + HandleInput(); + + ticks++; + + RunClientTimers(); + + // Server Only + if (!isServer) return; + + + // Runs every 60 ticks (1 sec) + RunDelayTimers(); + } + + private void Init() + { + if (isServer && isDedicated) + { + if (init) return; + + if (config.autoHangarConfig.enableAutoHangar) + CheckLastLogOff(); + else + UpdateIdentities(); + + init = true; + return; + } + + if (init) return; + + if (playerCache == null) + playerCache = MyAPIGateway.Session.LocalHumanPlayer; + + if (playerCache != null) + { + if (config == null) + { + Comms.ClientRequestConfig(playerCache.SteamUserId); + return; + } + + if (config.enemyCheckConfig.enableBlockCheck) + { + //MyAPIGateway.Entities.OnEntityAdd += OnBlockAdded; + //MyAPIGateway.Entities.OnEntityRemove += OnBlockRemoved; + MyEntities.OnEntityCreate += OnBlockAdded; + MyEntities.OnEntityRemove += OnBlockRemoved; + ClientGetBlocks(); + } + + if (isServer) + { + if (config.autoHangarConfig.enableAutoHangar) + CheckLastLogOff(); + else + UpdateIdentities(); + } + + init = true; + } + + } + + public bool TrySpawnPlacement() + { + if (!allowSpawn) return false; + + long playerId = MyAPIGateway.Session.LocalHumanPlayer.IdentityId; + List obs = new List(); + GetObFromPreview(obs); + Comms.SendGridsToSpawn(obs, spawnIndex, hangarType, playerId, spawnCost, spawnType); + + RemovePreviewGrids(); + + return true; + } + + public void RemovePreviewGrids() + { + foreach (var grid in previewGrids) + grid.Close(); + + previewGrids.Clear(); + ResetClientValues(); + + } + + private void ResetClientValues() + { + previewDistance = 50; + allowSpawn = false; + spawnIndex = -1; + hangarType = HangarType.Faction; + original = new Vector3D(); + previewMass = 0; + useInverseSpawnArea = false; + spawnType = SpawnType.None; + spawnCost = 0; + hudNotify.Hide(); + hudNotify = null; + spawnError = SpawnError.None; + playerWallet = 0; + factionWallet = 0; + enableInput = false; + Utils.RemoveSpawnLocationsClientGPS(); + } + + public void GetObFromPreview(List list) + { + list.Clear(); + foreach(var grid in previewGrids) + { + MyObjectBuilder_CubeGrid ob = grid.GetObjectBuilder() as MyObjectBuilder_CubeGrid; + list.Add(ob); + } + } + + // Server + public void SpawnGridsFromOb(List obs, int index, HangarType sentHangarType, long playerId, long cost, SpawnType spawnType, bool checkForIntersections) + { + IMyPlayer player = GetPlayerfromID(playerId); + IMyFaction faction = MyAPIGateway.Session.Factions.TryGetPlayerFaction(playerId); + MyAPIGateway.Entities.RemapObjectBuilderCollection(obs); + IMyCubeGrid mainGrid = null; + List gridsToSpawn = new List(); + Utils.CheckGridSpawnLimitsInOB(obs, faction, sentHangarType, index, spawnType, playerId); + + for (int i = 0; i < obs.Count; i++) + { + MyObjectBuilder_CubeGrid cloneOb = obs[i].Clone() as MyObjectBuilder_CubeGrid; + if (cloneOb == null) continue; + + cloneOb.CreatePhysics = true; + IMyEntity ent = MyAPIGateway.Entities.CreateFromObjectBuilder(cloneOb); + var cubeGrid = ent as MyCubeGrid; + var grid = ent as IMyCubeGrid; + if (cubeGrid == null || grid == null) return; + + cubeGrid.Save = true; + cubeGrid.SyncFlag = true; + cubeGrid.IsPreview = false; + + if (i == 0) + { + if (cubeGrid.GridSizeEnum == MyCubeSize.Small) + { + if (config.spawnSGStatic) + grid.IsStatic = true; + }else + grid.IsStatic = true; + + mainGrid = cubeGrid; + } + + if (sentHangarType == HangarType.Faction) + Utils.CheckOwnerValidFaction(faction, cubeGrid, playerId); + + gridsToSpawn.Add(cubeGrid); + } + + if (checkForIntersections) + { + if (Utils.IsGridIntersecting(gridsToSpawn)) + { + MyVisualScriptLogicProvider.SendChatMessageColored($"Failed to spawn grid from hangar, something is blocking placement.", Color.Red, "[FactionHangar]", playerId, "Red"); + return; + } + } + + foreach(var grid in gridsToSpawn) + MyAPIGateway.Entities.AddEntity(grid, true); + + IMyEntity foundEnt; + if (mainGrid == null) + { + MyVisualScriptLogicProvider.SendChatMessageColored($"Failed to spawn grid from hangar.", Color.Red, "[FactionHangar]", playerId, "Red"); + return; + } + + MyAPIGateway.Entities.TryGetEntityById(mainGrid.EntityId, out foundEnt); + if (foundEnt == null) + { + MyVisualScriptLogicProvider.SendChatMessageColored($"Failed to spawn grid from hangar.", Color.Red, "[FactionHangar]", playerId, "Red"); + return; + } + + if (sentHangarType == HangarType.Faction) + { + if (faction != null) + { + Utils.CheckGridSpawnLimits(mainGrid, faction, sentHangarType, index, spawnType, playerId); + Utils.UpdateBalance(playerId, cost, index, sentHangarType); + FactionTimers.AddTimer(faction, TimerType.RetrievalCooldown, config.factionHangarConfig.factionHangarCooldown); + allHangarData.RemoveFactionData(faction.FactionId, index, true); + } + + if (player != null) + Comms.AddClientCooldown(player.SteamUserId, false, TimerType.RetrievalCooldown); + } + + if (sentHangarType == HangarType.Private) + { + Utils.CheckGridSpawnLimits(mainGrid, null, sentHangarType, index, spawnType, playerId); + Utils.UpdateBalance(playerId, cost, index, sentHangarType); + allHangarData.RemovePrivateData(playerId, index, true); + if (player != null) + Comms.AddClientCooldown(player.SteamUserId, true, TimerType.RetrievalCooldown); + } + + if (player != null) + { + IMyCubeGrid grid = gridsToSpawn[0] as IMyCubeGrid; + if (grid == null) return; + MyVisualScriptLogicProvider.SendChatMessageColored($"Successfully spawned in grid '{grid.CustomName}'.", Color.Green, "[FactionHangar]", playerId, "Green"); + } + } + + private void RunClientTimers() + { + if (isServer && isDedicated) return; + if (ticks % 60 != 0) return; + + if (retrievalTimer > 0) + retrievalTimer--; + + if (storeTimer > 0) + storeTimer--; + } + + private void RunDelayTimers() + { + if (ticks % 60 != 0) return; + + if (cooldownTimers.Count > 0) + { + List keys = cooldownTimers.Keys.ToList(); + foreach (var faction in keys) + { + for (int i = cooldownTimers[faction].timers.Count - 1; i >= 0; i--) + { + if (cooldownTimers[faction].timers[i].time > 0) + cooldownTimers[faction].timers[i].time--; + else + cooldownTimers[faction].timers.RemoveAt(i); + + if (cooldownTimers[faction].timers.Count == 0) + cooldownTimers.Remove(faction); + } + } + } + + if (hangarDelay.Count == 0) return; + for (int i = hangarDelay.Count - 1; i >= 0; i--) + { + if (hangarDelay[i].hangarType == HangarType.Faction) + { + if (hangarDelay[i].timer >= config.factionHangarConfig.factionStoreDelay) + { + foreach (var grid in hangarDelay[i].gridData) + RequestingGridStorage(hangarDelay[i].requesterId, hangarDelay[i].playerId, grid.gridId, hangarDelay[i].playerName); + + hangarDelay.RemoveAtFast(i); + continue; + } + } + + if (hangarDelay[i].hangarType == HangarType.Private) + { + if (hangarDelay[i].timer >= config.privateHangarConfig.privateStoreDelay) + { + foreach (var grid in hangarDelay[i].gridData) + RequestingGridStorage(hangarDelay[i].requesterId, hangarDelay[i].playerId, grid.gridId, hangarDelay[i].playerName, true); + + hangarDelay.RemoveAtFast(i); + continue; + } + } + /*else + { + foreach (var grid in hangarDelay[i].gridData) + RequestingGridStorage(hangarDelay[i].playerId, grid.gridId, hangarDelay[i].playerName); + + hangarDelay.RemoveAtFast(i); + continue; + }*/ + + hangarDelay[i].timer++; + + if (hangarDelay[i].hangarType == HangarType.Faction) + { + if (config.factionHangarConfig.factionStoreDelay - hangarDelay[i].timer == 10) + foreach (var grid in hangarDelay[i].gridData) + MyVisualScriptLogicProvider.SendChatMessageColored($"Storing Grid {grid.gridName} in 10 seconds", Color.Green, "[FactionHangar]", hangarDelay[i].playerId, "Green"); + } + else + { + if (config.privateHangarConfig.privateStoreDelay - hangarDelay[i].timer == 10) + foreach (var grid in hangarDelay[i].gridData) + MyVisualScriptLogicProvider.SendChatMessageColored($"Storing Grid {grid.gridName} in 10 seconds", Color.Green, "[FactionHangar]", hangarDelay[i].playerId, "Green"); + } + } + } + + public void ChatHandler(string messageText, ref bool sendToOthers) + { + if (isDedicated) return; + IMyPlayer client = MyAPIGateway.Session.LocalHumanPlayer; + IMyFaction faction = MyAPIGateway.Session.Factions.TryGetPlayerFaction(client.IdentityId); + bool isLeader = false; + + if (faction != null) + isLeader = faction.IsLeader(client.IdentityId); + + if (messageText.Equals("/fh list") || messageText.Equals("/factionhangar list")) + { + sendToOthers = false; + Comms.ClientRequestFactionList(client.IdentityId, client.DisplayName); + + return; + } + + if (messageText.StartsWith("/fh store") || messageText.StartsWith("/factionhangar store")) + { + List entities = new List(); + sendToOthers = false; + + if (faction == null) + { + Comms.SendChatMessage("Need to be in a faction to store a grid in faction hangar.", "Red", client.IdentityId, Color.Red); + //MyVisualScriptLogicProvider.SendChatMessageColored($"Need to be in a faction to store a grid in faction hangar.", Color.Red, "[FactionHangar]", 0, "Red"); + return; + } + + if (storeTimer > 0) + { + Comms.SendChatMessage($"Must wait {storeTimer} seconds before you can store another grid.", "Red", client.IdentityId, Color.Red); + //MyVisualScriptLogicProvider.SendChatMessageColored($"Must wait {storeTimer} seconds before you can store another grid.", Color.Red, "[FactionHangar]", 0, "Red"); + return; + } + + var split = messageText.Split(' '); + string gridName = ""; + IMyCubeGrid choosenGrid = null; + if (split.Length == 1) + { + GetEntitiesInSphere(entities, playerCache.GetPosition(), 500); + if (string.IsNullOrEmpty(gridName)) + { + string list = Utils.GetGridsToStore(entities, HangarType.Faction, client.IdentityId); + Comms.SendChatMessage($"{list}", "Green", client.IdentityId, Color.Green); + //MyVisualScriptLogicProvider.SendChatMessageColored($"{list}", Color.Green, "[FactionHangar]", 0, "Green"); + + return; + } + } + + if (split.Length > 1) + { + for (int i = 2; i < split.Length; i++) + { + if (i == 2) + { + gridName = split[i]; + continue; + } + + gridName += $" {split[i]}"; + } + + GetEntitiesInSphere(entities, playerCache.GetPosition(), 500); + if (string.IsNullOrEmpty(gridName)) + { + string list = Utils.GetGridsToStore(entities, HangarType.Faction, client.IdentityId); + Comms.SendChatMessage($"{list}", "Green", client.IdentityId, Color.Green); + //MyVisualScriptLogicProvider.SendChatMessageColored($"{list}", Color.Green, "[FactionHangar]", 0, "Green"); + + return; + } + + foreach (var ent in entities) + { + + IMyCubeGrid grid = ent as IMyCubeGrid; + if (grid == null) continue; + if (gridName == grid.CustomName) + { + choosenGrid = grid; + break; + } + } + + if (choosenGrid == null) + { + Comms.SendChatMessage($"{gridName} is NOT a valid grid.", "Red", client.IdentityId, Color.Red); + //MyVisualScriptLogicProvider.SendChatMessageColored($"{gridName} is NOT a valid grid", Color.Red, "[FactionHangar]", 0, "Red"); + string list = Utils.GetGridsToStore(entities, HangarType.Faction, client.IdentityId); + Comms.SendChatMessage($"{list}", "Green", client.IdentityId, Color.Green); + //MyVisualScriptLogicProvider.SendChatMessageColored($"{list}", Color.Green, "[FactionHangar]", 0, "Green"); + + return; + } + + long gridOwner = choosenGrid.BigOwners.FirstOrDefault(); + + if (faction != null) + { + if (!DoesFactionOwnGrid(choosenGrid, faction)) + { + Comms.SendChatMessage($"Grid {choosenGrid.CustomName} is not owned by you or your faction", "Red", client.IdentityId, Color.Red); + //MyVisualScriptLogicProvider.SendChatMessageColored($"Grid {choosenGrid.CustomName} is not owned by you or your faction", Color.Red, "[FactionHangar]", 0, "Red"); + return; + } + else + { + if (!isLeader) + { + if (!DoesPlayerOwnGrid(choosenGrid, client.IdentityId)) + { + Comms.SendChatMessage($"Grid {choosenGrid.CustomName} is not owned by you, must be a faction leader to store grids that you don't own", "Red", client.IdentityId, Color.Red); + //MyVisualScriptLogicProvider.SendChatMessageColored($"Grid {choosenGrid.CustomName} is not owned by you, must be a faction leader to store grids that you don't own", Color.Red, "[FactionHangar]", 0, "Red"); + return; + } + } + } + } + + if (IsEnemyNearStoring(choosenGrid, HangarType.Faction)) + { + Comms.SendChatMessage($"Cannot store when enemy is nearby...", "Red", client.IdentityId, Color.Red); + //MyVisualScriptLogicProvider.SendChatMessageColored($"Cannot store when enemy is nearby...", Color.Red, "[FactionHangar]", 0, "Red"); + return; + } + + gridsToStore = new CacheGridsForStorage(); + List connectedGrids = new List(); + GetConnectedGrids(choosenGrid, connectedGrids); + + + if (connectedGrids.Count > 0) + { + gridsToStore.ownerId = gridOwner; + gridsToStore.requesterId = client.IdentityId; + gridsToStore.grids = new List() { choosenGrid }; + + //gridsToStore.Add(choosenGrid); + string message = "The following grids are connected and will count as slots in the faction hangar:\n\n"; + foreach (var grid in connectedGrids) + { + gridsToStore.grids.Add(grid); + //gridsToStore.Add(grid); + message += $"{grid.CustomName}\n"; + } + + message += "\nPress 'Process' to proceed or cancel with the X on the top corner"; + + hangarType = HangarType.Faction; + MyAPIGateway.Utilities.ShowMissionScreen("Connected Grids Detected!", "", null, message, ConnectedGridsResult, "Process"); + return; + } + + List gridDatas = new List(); + GridData gridData = new GridData() + { + gridId = choosenGrid.EntityId, + gridName = choosenGrid.CustomName + }; + + string ownerName = GetPlayerName(gridOwner); + gridDatas.Add(gridData); + //storeTimer = config.factionHangarConfig.factionHangarCooldown; + //Comms.AddTimer(faction.FactionId, TimerType.StorageCooldown, config.factionHangarConfig.factionHangarCooldown); + Comms.ClientRequestStoreGrid(client.IdentityId, gridOwner, gridDatas, ownerName, HangarType.Faction); + } + } + + if (messageText.StartsWith("/fh load") || messageText.StartsWith("/factionhangar load")) + { + sendToOthers = false; + if (faction == null) + { + Comms.SendChatMessage($"Need to be in a faction to load a grid in faction hangar.", "Red", client.IdentityId, Color.Red); + //MyVisualScriptLogicProvider.SendChatMessageColored($"Need to be in a faction to load a grid in faction hangar.", Color.Red, "[FactionHangar]", client.IdentityId, "Red"); + return; + } + + if (retrievalTimer > 0) + { + Comms.SendChatMessage($"Must wait {retrievalTimer} seconds before you can load another grid.", "Red", client.IdentityId, Color.Red); + //MyVisualScriptLogicProvider.SendChatMessageColored($"Must wait {retrievalTimer} seconds before you can load another grid.", Color.Red, "[FactionHangar]", client.IdentityId, "Red"); + return; + } + + var split = messageText.Split(' '); + bool originalLocation = false; + bool force = false; + string gridIndex = ""; + int index = -1; + + if (split.Length <= 2) + { + Comms.SendChatMessage("Invalid index.", "Red", client.IdentityId, Color.Red); + //MyVisualScriptLogicProvider.SendChatMessageColored($"Invalid index.", Color.Red, "[FactionHangar]", client.IdentityId, "Red"); + return; + } + + gridIndex = split[2]; + + if (!int.TryParse(gridIndex, out index)) + { + var splitBool = split[2].Split('.'); + if (splitBool.Length > 1) + bool.TryParse(splitBool[1], out originalLocation); + + if (splitBool.Length > 2) + if (splitBool[2].Equals("force", StringComparison.OrdinalIgnoreCase)) + { + if (originalLocation) + force = true; + else + { + Comms.SendChatMessage("Force command is only allowed when spawning to original location.", "Red", client.IdentityId, Color.Red); + return; + } + } + + if (!int.TryParse(splitBool[0], out index)) + { + Comms.SendChatMessage("Invalid index.", "Red", client.IdentityId, Color.Red); + return; + } + } + + if (index < 0) + { + Comms.SendChatMessage("Invalid index.", "Red", client.IdentityId, Color.Red); + //MyVisualScriptLogicProvider.SendChatMessageColored($"Invalid index.", Color.Red, "[FactionHangar]", client.IdentityId, "Red"); + return; + } + + + + + Comms.ClientRequestGridData(index, client.IdentityId, HangarType.Faction, client.SteamUserId, originalLocation, force); + } + + if (messageText.StartsWith("/fh transfer") || messageText.StartsWith("/factionhangar transfer")) + { + sendToOthers = false; + if (faction == null) + { + Comms.SendChatMessage("Need to be in a faction to transfer a grid in to private hangar.", "Red", client.IdentityId, Color.Red); + //MyVisualScriptLogicProvider.SendChatMessageColored($"Need to be in a faction to transfer a grid in to private hangar.", Color.Red, "[FactionHangar]", client.IdentityId, "Red"); + return; + } + + var split = messageText.Split(' '); + + bool originalLocation = false; + string gridIndex = ""; + int index = -1; + + if (split.Length <= 1) + { + Comms.SendChatMessage("Invalid index.", "Red", client.IdentityId, Color.Red); + //MyVisualScriptLogicProvider.SendChatMessageColored($"Invalid index.", Color.Red, "[FactionHangar]", client.IdentityId, "Red"); + return; + } + + gridIndex = split[2]; + int.TryParse(gridIndex, out index); + if (index < 0) + { + Comms.SendChatMessage("Invalid index.", "Red", client.IdentityId, Color.Red); + //MyVisualScriptLogicProvider.SendChatMessageColored($"Invalid index.", Color.Red, "[FactionHangar]", client.IdentityId, "Red"); + return; + } + + Comms.RequestTransferFactionToPrivate(client.IdentityId, index); + //allHangarData.TransferFactionToPrivate(faction.FactionId, index, client.IdentityId); + } + + if (messageText.StartsWith("/fh remove") || messageText.StartsWith("/factionhangar remove")) + { + sendToOthers = false; + if (faction == null) + { + Comms.SendChatMessage("Need to be in a faction to remove grids from hangar.", "Red", client.IdentityId, Color.Red); + //MyVisualScriptLogicProvider.SendChatMessageColored($"Need to be in a faction to remove grids from hangar.", Color.Red, "[FactionHangar]", client.IdentityId, "Red"); + return; + } + + var split = messageText.Split(' '); + + string gridIndex = ""; + int index = -1; + + if (split.Length <= 1) + { + Comms.SendChatMessage("Invalid index.", "Red", client.IdentityId, Color.Red); + //MyVisualScriptLogicProvider.SendChatMessageColored($"Invalid index.", Color.Red, "[FactionHangar]", client.IdentityId, "Red"); + return; + } + + gridIndex = split[2]; + int.TryParse(gridIndex, out index); + if (index < 0) + { + Comms.SendChatMessage("Invalid index.", "Red", client.IdentityId, Color.Red); + //MyVisualScriptLogicProvider.SendChatMessageColored($"Invalid index.", Color.Red, "[FactionHangar]", client.IdentityId, "Red"); + return; + } + + Comms.RequestGridRemoval(index, client.IdentityId, HangarType.Faction); + } + + if (messageText.StartsWith("/ph store") || messageText.StartsWith("/privatehangar store")) + { + List entities = new List(); + sendToOthers = false; + if (storeTimer > 0) + { + Comms.SendChatMessage($"Must wait {storeTimer} seconds before you can store another grid.", "Red", client.IdentityId, Color.Red); + //MyVisualScriptLogicProvider.SendChatMessageColored($"Must wait {storeTimer} seconds before you can store another grid.", Color.Red, "[FactionHangar]", client.IdentityId, "Red"); + return; + } + + var split = messageText.Split(' '); + string gridName = ""; + IMyCubeGrid choosenGrid = null; + if (split.Length == 1) + { + GetEntitiesInSphere(entities, playerCache.GetPosition(), 500); + if (string.IsNullOrEmpty(gridName)) + { + string list = Utils.GetGridsToStore(entities, HangarType.Private, client.IdentityId); + Comms.SendChatMessage($"{list}", "Green", client.IdentityId, Color.Green); + //MyVisualScriptLogicProvider.SendChatMessageColored($"{list}", Color.Green, "[FactionHangar]", client.IdentityId, "Green"); + + return; + } + } + + if (split.Length > 1) + { + for (int i = 2; i < split.Length; i++) + { + if (i == 2) + { + gridName = split[i]; + continue; + } + + gridName += $" {split[i]}"; + } + + GetEntitiesInSphere(entities, playerCache.GetPosition(), 500); + if (string.IsNullOrEmpty(gridName)) + { + string list = Utils.GetGridsToStore(entities, HangarType.Private, client.IdentityId); + Comms.SendChatMessage($"{list}", "Green", client.IdentityId, Color.Green); + //MyVisualScriptLogicProvider.SendChatMessageColored($"{list}", Color.Green, "[FactionHangar]", client.IdentityId, "Green"); + + return; + } + + foreach (var ent in entities) + { + IMyCubeGrid grid = ent as IMyCubeGrid; + if (grid == null) continue; + if (gridName == grid.CustomName) + { + choosenGrid = grid; + break; + } + } + + if (choosenGrid == null) + { + Comms.SendChatMessage($"{gridName} is NOT a valid grid.", "Red", client.IdentityId, Color.Red); + //MyVisualScriptLogicProvider.SendChatMessageColored($"{gridName} is NOT a valid grid", Color.Red, "[FactionHangar]", client.IdentityId, "Red"); + string list = Utils.GetGridsToStore(entities, HangarType.Private, client.IdentityId); + Comms.SendChatMessage($"{list}", "Green", client.IdentityId, Color.Green); + //MyVisualScriptLogicProvider.SendChatMessageColored($"{list}", Color.Green, "[FactionHangar]", client.IdentityId, "Green"); + + return; + } + + if (!DoesPlayerOwnGrid(choosenGrid, client.IdentityId)) + { + Comms.SendChatMessage($"Grid {choosenGrid.CustomName} is not owned by you.", "Red", client.IdentityId, Color.Red); + //MyVisualScriptLogicProvider.SendChatMessageColored($"Grid {choosenGrid.CustomName} is not owned by you.", Color.Red, "[FactionHangar]", client.IdentityId, "Red"); + return; + } + + if (IsEnemyNearStoring(choosenGrid, HangarType.Private)) + { + Comms.SendChatMessage($"Cannot store when enemy is nearby.", "Red", client.IdentityId, Color.Red); + //MyVisualScriptLogicProvider.SendChatMessageColored($"Cannot store when enemy is nearby...", Color.Red, "[FactionHangar]", client.IdentityId, "Red"); + return; + } + + gridsToStore = new CacheGridsForStorage(); + List connectedGrids = new List(); + GetConnectedGrids(choosenGrid, connectedGrids); + + + if (connectedGrids.Count > 0) + { + gridsToStore.ownerId = client.IdentityId; + gridsToStore.requesterId = client.IdentityId; + gridsToStore.grids = new List() { choosenGrid }; + + //gridsToStore.Add(choosenGrid); + string message = "The following grids are connected and will count as slots in the private hangar:\n\n"; + foreach (var grid in connectedGrids) + { + gridsToStore.grids.Add(grid); + //gridsToStore.Add(grid); + message += $"{grid.CustomName}\n"; + } + + message += "\nPress 'Process' to proceed or cancel with the X on the top corner"; + + hangarType = HangarType.Private; + MyAPIGateway.Utilities.ShowMissionScreen("Connected Grids Detected!", "", null, message, ConnectedGridsResult, "Process"); + return; + } + + List gridDatas = new List(); + GridData gridData = new GridData() + { + gridId = choosenGrid.EntityId, + gridName = choosenGrid.CustomName + }; + + gridDatas.Add(gridData); + //storeTimer = config.privateHangarConfig.privateHangarCooldown; + Comms.ClientRequestStoreGrid(client.IdentityId, client.IdentityId, gridDatas, client.DisplayName, HangarType.Private); + } + } + + if (messageText.StartsWith("/ph load") || messageText.StartsWith("/privatehangar load")) + { + sendToOthers = false; + + if (retrievalTimer > 0) + { + Comms.SendChatMessage($"Must wait {retrievalTimer} seconds before you can load another grid.", "Red", client.IdentityId, Color.Red); + //MyVisualScriptLogicProvider.SendChatMessageColored($"Must wait {retrievalTimer} seconds before you can load another grid.", Color.Red, "[FactionHangar]", client.IdentityId, "Red"); + return; + } + + var split = messageText.Split(' '); + + bool originalLocation = false; + bool force = false; + string gridIndex = ""; + int index = -1; + + if (split.Length <= 2) + { + Comms.SendChatMessage("Invalid index.", "Red", client.IdentityId, Color.Red); + return; + } + + gridIndex = split[2]; + if (!int.TryParse(gridIndex, out index)) + { + var splitBool = split[2].Split('.'); + if (splitBool.Length > 1) + bool.TryParse(splitBool[1], out originalLocation); + + if (splitBool.Length > 2) + if (splitBool[2].Equals("force", StringComparison.OrdinalIgnoreCase)) + { + if (originalLocation) + force = true; + else + { + Comms.SendChatMessage("Force command is only allowed when spawning to original location.", "Red", client.IdentityId, Color.Red); + return; + } + } + + if (!int.TryParse(splitBool[0], out index)) + { + Comms.SendChatMessage("Invalid index.", "Red", client.IdentityId, Color.Red); + return; + } + } + + if (index < 0) + { + Comms.SendChatMessage("Invalid index.", "Red", client.IdentityId, Color.Red); + return; + } + + Comms.ClientRequestGridData(index, client.IdentityId, HangarType.Private, client.SteamUserId, originalLocation, force); + } + + if (messageText.StartsWith("/ph transfer") || messageText.StartsWith("/privatehangar transfer")) + { + sendToOthers = false; + if (faction == null) + { + Comms.SendChatMessage("Need to be in a faction to transfer a grid in to faction hangar.", "Red", client.IdentityId, Color.Red); + //MyVisualScriptLogicProvider.SendChatMessageColored($"Need to be in a faction to transfer a grid in to faction hangar.", Color.Red, "[FactionHangar]", client.IdentityId, "Red"); + return; + } + + var split = messageText.Split(' '); + + bool originalLocation = false; + string gridIndex = ""; + int index = -1; + + if (split.Length <= 1) + { + Comms.SendChatMessage("Invalid index.", "Red", client.IdentityId, Color.Red); + //MyVisualScriptLogicProvider.SendChatMessageColored($"Invalid index.", Color.Red, "[FactionHangar]", client.IdentityId, "Red"); + return; + } + + gridIndex = split[2]; + int.TryParse(gridIndex, out index); + if (index < 0) + { + Comms.SendChatMessage("Invalid index.", "Red", client.IdentityId, Color.Red); + //MyVisualScriptLogicProvider.SendChatMessageColored($"Invalid index.", Color.Red, "[FactionHangar]", client.IdentityId, "Red"); + return; + } + + Comms.RequestTransferPrivateToFaction(client.IdentityId, index); + //allHangarData.TransferPrivateToFaction(faction.FactionId, index, client.IdentityId); + } + + if (messageText.Equals("/ph list") || messageText.Equals("/privatehangar list")) + { + sendToOthers = false; + Comms.ClientRequestPrivateList(client.IdentityId, client.DisplayName); + + return; + } + + if (messageText.StartsWith("/ph remove") || messageText.StartsWith("/privatehangar remove")) + { + sendToOthers = false; + + var split = messageText.Split(' '); + + string gridIndex = ""; + int index = -1; + + if (split.Length <= 1) + { + Comms.SendChatMessage("Invalid index.", "Red", client.IdentityId, Color.Red); + //MyVisualScriptLogicProvider.SendChatMessageColored($"Invalid index.", Color.Red, "[FactionHangar]", client.IdentityId, "Red"); + return; + } + + gridIndex = split[2]; + int.TryParse(gridIndex, out index); + if (index < 0) + { + Comms.SendChatMessage("Invalid index.", "Red", client.IdentityId, Color.Red); + //MyVisualScriptLogicProvider.SendChatMessageColored($"Invalid index.", Color.Red, "[FactionHangar]", client.IdentityId, "Red"); + return; + } + + Comms.RequestGridRemoval(index, client.IdentityId, HangarType.Private); + //allHangarData.RemovePrivateData(client.IdentityId, index, true); + } + + if (messageText.Equals("/fh togglesphere")) + { + sendToOthers = false; + drawClientSphereDebug = !drawClientSphereDebug; + Comms.SendChatMessage($"Client spawn spheres are now set to '{drawClientSphereDebug}'", "Green", client.IdentityId, Color.Green); + //MyVisualScriptLogicProvider.SendChatMessageColored($"Client spawn spheres are now set to '{drawClientSphereDebug}'", Color.Green, "[FactionHangar]", client.IdentityId, "Green"); + } + + if (messageText.Equals("/fh togglegps")) + { + sendToOthers = false; + spawnClientGPS = !spawnClientGPS; + Comms.SendChatMessage($"Client spawn gps locations are now set to '{spawnClientGPS}'", "Green", client.IdentityId, Color.Green); + //MyVisualScriptLogicProvider.SendChatMessageColored($"Client spawn gps locations are now set to '{spawnClientGPS}'", Color.Green, "[FactionHangar]", client.IdentityId, "Green"); + + } + + if (messageText.StartsWith("/fh help")) + { + sendToOthers = false; + Utils.LoadHelpPopup(); + } + } + + private void ConnectedGridsResult(ResultEnum result) + { + if (result == ResultEnum.OK) + { + IMyPlayer client = MyAPIGateway.Session.LocalHumanPlayer; + List gridDatas= new List(); + foreach (var grid in gridsToStore.grids) + { + GridData gridData = new GridData() + { + gridId = grid.EntityId, + gridName = grid.CustomName + }; + + gridDatas.Add(gridData); + } + + string ownerName = GetPlayerName(gridsToStore.ownerId); + //storeTimer = hangarType == HangarType.Faction ? config.factionHangarConfig.factionHangarCooldown : config.privateHangarConfig.privateHangarCooldown; + + /*if (hangarType == HangarType.Faction) + { + IMyFaction faction = MyAPIGateway.Session.Factions.TryGetPlayerFaction(client.IdentityId); + if (faction != null) + Comms.AddTimer(faction.FactionId, TimerType.StorageCooldown, storeTimer); + }*/ + + Comms.ClientRequestStoreGrid(client.IdentityId, gridsToStore.ownerId, gridDatas, ownerName, hangarType); + } + } + + public void GetConnectedGrids(IMyCubeGrid targetGrid, List connectedGrids) + { + List physicalGroup = new List(); + MyAPIGateway.GridGroups.GetGroup(targetGrid, GridLinkTypeEnum.Physical, physicalGroup); + foreach (var grid in physicalGroup) + { + if (!targetGrid.IsSameConstructAs(grid)) + connectedGrids.Add(grid); + } + + for (int i = connectedGrids.Count - 1; i >= 0; i--) + { + var blocks = connectedGrids[i].GetFatBlocks(); + bool attached = false; + foreach(var top in blocks) + { + if (top.IsAttached) + { + attached = true; + break; + } + } + + if (attached) + connectedGrids.RemoveAt(i); + } + } + + public bool DoesPlayerOwnGrid(IMyCubeGrid grid, long playerId) + { + if (grid == null) return false; + long owner = 0; + if (grid.BigOwners.Count != 0) + owner = grid.BigOwners[0]; + + if (owner != 0 && owner == playerId) return true; + + return false; + } + + public bool DoesFactionOwnGrid(IMyCubeGrid grid, IMyFaction faction) + { + if (grid == null) return false; + long owner = 0; + if (grid.BigOwners.Count != 0) + owner = grid.BigOwners[0]; + + IMyFaction gridFaction = MyAPIGateway.Session.Factions.TryGetPlayerFaction(owner); + if (gridFaction != null && gridFaction == faction) return true; + + return false; + } + + public void RequestingGridStorage(long requesterId, long ownerId, long gridId, string playerName, bool privateStorage = false, bool autoHangar = false) + { + IMyPlayer player = GetPlayerfromID(requesterId); + IMyPlayer gridOwner = GetPlayerfromID(ownerId); + /*if (player == null) + { + MyLog.Default.WriteLineAndConsole($"[FactionHangar] - Invalid Player"); + return; + }*/ + + IMyEntity entity = null; + MyAPIGateway.Entities.TryGetEntityById(gridId, out entity); + if (entity == null) + { + if (player != null) + MyVisualScriptLogicProvider.SendChatMessageColored($"Failed to store grid", Color.Red, "[FactionHangar]", requesterId, "Red"); + + MyLog.Default.WriteLineAndConsole($"[FactionHangar] - Unable to get grid by Id {gridId}"); + return; + } + + IMyCubeGrid grid = entity as IMyCubeGrid; + IMyFaction faction = MyAPIGateway.Session.Factions.TryGetPlayerFaction(ownerId); + + playerName = RemoveSpecialCharacters(playerName); + string gridName = RemoveSpecialCharacters(grid.CustomName); + + string path = ""; + path = Path.Combine(MyAPIGateway.Utilities.GamePaths.UserDataPath, $"FactionHangarSaves", $"{playerName}", $"{gridName}_{grid.EntityId}", "bp.sbc"); + //path = Path.Combine("C:\\", $"FactionHangarSaves", $"{playerName}", $"{gridName}_{grid.EntityId}", "bp.sbc"); + + /*if (faction != null) + { + if (privateStorage) + path = Path.Combine(MyAPIGateway.Utilities.GamePaths.ModsPath, $"FactionHangarSaves", $"PrivateHangars", $"{playerName}", $"{grid.CustomName}_{grid.EntityId}","bp.sbc"); + //path = Path.Combine(MyAPIGateway.Utilities.GamePaths.ModsPath, $"{faction.Name}_{grid.CustomName}_{grid.EntityId}.sbc"); + + else + path = Path.Combine(MyAPIGateway.Utilities.GamePaths.ModsPath, $"FactionHangarSaves", $"FactionHangars", $"{faction.Name}", $"{grid.CustomName}_{grid.EntityId}", "bp.sbc"); + //path = Path.Combine(MyAPIGateway.Utilities.GamePaths.ModsPath, $"{faction.Name}_{grid.CustomName}_{grid.EntityId}.sbc"); + + } + else + path = Path.Combine(MyAPIGateway.Utilities.GamePaths.ModsPath, $"FactionHangarSaves", $"PrivateHangars", $"{playerName}", $"{grid.CustomName}_{grid.EntityId}", "bp.sbc"); + //path = Path.Combine(MyAPIGateway.Utilities.GamePaths.ModsPath, $"{playerName}_{grid.CustomName}_{grid.EntityId}.sbc");*/ + + + if (path != "") + { + Utils.RemovePlayersFromSeats(grid as MyCubeGrid); + + if (CreateShipBlueprint(grid as MyCubeGrid, grid.CustomName, path, autoHangar ? GridLinkTypeEnum.Physical : GridLinkTypeEnum.Mechanical)) + { + if (player != null && !autoHangar) + { + //Comms.AddClientCooldown(player.SteamUserId, privateStorage, TimerType.StorageCooldown); + MyVisualScriptLogicProvider.SendChatMessageColored($"Successfully stored grid {grid.CustomName}", Color.Green, "[FactionHangar]", requesterId, "Green"); + MyLog.Default.WriteLineAndConsole($"[FactionHangar] - Player {playerName} successfully stored grid {grid.CustomName}"); + } + + //if (faction != null && !autoHangar) + //FactionTimers.AddTimer(faction, TimerType.StorageCooldown, config.factionHangarConfig.factionHangarCooldown); + + if (autoHangar) + MyLog.Default.WriteLineAndConsole($"[FactionHangar] - AutoHangar successfully stored grid {grid.CustomName}"); + + if (!privateStorage) + allHangarData.AddFactionData(faction.FactionId, grid.CustomName, grid.EntityId, ownerId, path, playerName, autoHangar); + else + allHangarData.AddPrivateData(grid.CustomName, grid.EntityId, ownerId, path, playerName, autoHangar); + + CloseGridGroup(grid, autoHangar ? GridLinkTypeEnum.Physical : GridLinkTypeEnum.Mechanical); + return; + } + } + + + if (autoHangar) + MyLog.Default.WriteLineAndConsole($"[FactionHangar] - AutoHangar failed to store grid {grid.CustomName}"); + else + MyLog.Default.WriteLineAndConsole($"[FactionHangar] - Player {playerName} failed to store grid {grid.CustomName}"); + + if (player != null) + MyVisualScriptLogicProvider.SendChatMessageColored($"Failed to store grid {grid.CustomName}", Color.Red, "[FactionHangar]", requesterId, "Red"); + } + + public string RemoveSpecialCharacters(string str) + { + StringBuilder sb = new StringBuilder(); + foreach (char c in str) + { + if ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || c == '.' || c == '_') + { + sb.Append(c); + } + } + return sb.ToString(); + } + + private void CloseGridGroup(IMyCubeGrid grid, GridLinkTypeEnum groupType) + { + List myCubeGrids= new List(); + GetGroupByType(grid, myCubeGrids, groupType); + foreach(var cubeGrid in myCubeGrids) + { + if (!cubeGrid.MarkedForClose) + cubeGrid.Close(); + } + } + + public bool CreateShipBlueprint(MyCubeGrid myCubeGrid, string blueprintName, string path, GridLinkTypeEnum groupType) + { + List list = GetGridGroupObs(myCubeGrid, groupType); + MyObjectBuilder_ShipBlueprintDefinition myObjectBuilder_ShipBlueprintDefinition = MyObjectBuilderSerializer.CreateNewObject(); + myObjectBuilder_ShipBlueprintDefinition.Id = new MyDefinitionId(new MyObjectBuilderType(typeof(MyObjectBuilder_ShipBlueprintDefinition)), MyUtils.StripInvalidChars(blueprintName)); + myObjectBuilder_ShipBlueprintDefinition.CubeGrids = list.ToArray(); + myObjectBuilder_ShipBlueprintDefinition.RespawnShip = false; + myObjectBuilder_ShipBlueprintDefinition.DisplayName = blueprintName; + myObjectBuilder_ShipBlueprintDefinition.CubeGrids[0].DisplayName = blueprintName; + MyObjectBuilder_Definitions myObjectBuilder_Definitions = MyObjectBuilderSerializer.CreateNewObject(); + myObjectBuilder_Definitions.ShipBlueprints = new MyObjectBuilder_ShipBlueprintDefinition[1]; + myObjectBuilder_Definitions.ShipBlueprints[0] = myObjectBuilder_ShipBlueprintDefinition; + MyObjectBuilderSerializer.SerializeXML(path, false, myObjectBuilder_Definitions); + return true; + } + + public List GetGridGroupObs(MyCubeGrid cubeGrid, GridLinkTypeEnum groupType) + { + List tmp = new List(); + List groupList = new List(); + MyAPIGateway.GridGroups.GetGroup(cubeGrid, groupType, groupList); + tmp.Add(cubeGrid.GetObjectBuilder() as MyObjectBuilder_CubeGrid); + + foreach (var grid in groupList) + { + if (grid == cubeGrid) continue; + tmp.Add(grid.GetObjectBuilder() as MyObjectBuilder_CubeGrid); + } + + return tmp; + } + + public void GetGroupByType(IMyCubeGrid grid, List gridList, GridLinkTypeEnum type) + { + gridList.Clear(); + MyAPIGateway.GridGroups.GetGroup(grid, type, gridList); + } + + public MyObjectBuilder_CubeGrid[] GetGridFromGridData(MyObjectBuilder_Base data, int index, HangarType sentHangarType) + { + spawnIndex = index; + hangarType = sentHangarType; + if (data == null) return null; + MyObjectBuilder_Definitions def = data as MyObjectBuilder_Definitions; + if (def == null) return null; + + if (def.ShipBlueprints == null) return null; + if (def.ShipBlueprints.Length == 0) return null; + + MyObjectBuilder_ShipBlueprintDefinition bpDef = def.ShipBlueprints[0]; + if (bpDef == null) return null; + + if (bpDef.CubeGrids == null) return null; + MyObjectBuilder_CubeGrid[] cubeGridObs = bpDef.CubeGrids; + if (cubeGridObs.Length == 0) return null; + + return cubeGridObs; + } + + public void SpawnClientSideProjectedGrid(MyObjectBuilder_CubeGrid[] cubeGridObs) + { + if (cubeGridObs == null || cubeGridObs.Length == 0) return; + + RotationSpeed = 0.01f; + previewDistance = 50; + original = cubeGridObs[0].PositionAndOrientation.Value.Position; + hudNotify = MyAPIGateway.Utilities.CreateNotification($"[Valid Spawn] = {allowSpawn} | Cost To Spawn = {spawnCost} SC", int.MaxValue, "White"); + hudNotify.Show(); + hudNotify.ResetAliveTime(); + UpdatePosition(); + DetectSpawnType(true); + Utils.AddSpawnLocationsClientGPS(); + + MyAPIGateway.Entities.RemapObjectBuilderCollection(cubeGridObs); + MatrixD baseMat = new MatrixD(); + if (cubeGridObs[0].PositionAndOrientation.HasValue) + baseMat = cubeGridObs[0].PositionAndOrientation.Value.GetMatrix(); + + if (baseMat == MatrixD.Zero) return; + + if (cubeGridObs.Length > 1) + AssignSubgridSpawnLocation(cubeGridObs, endCoordCache, baseMat); + + cubeGridObs[0].PositionAndOrientation = new MyPositionAndOrientation(endCoordCache, baseMat.Forward, baseMat.Up); + List tempGrids = new List(); + for (int i = 0; i < cubeGridObs.Length; i++) + { + MyObjectBuilder_CubeGrid cloneOb = cubeGridObs[i].Clone() as MyObjectBuilder_CubeGrid; + if (cloneOb == null) continue; + + cloneOb.CreatePhysics = false; + + IMyEntity ent = MyAPIGateway.Entities.CreateFromObjectBuilder(cloneOb); + var cubeGrid = ent as MyCubeGrid; + if (cubeGrid == null) return; + + cubeGrid.Save = false; + cubeGrid.SyncFlag = false; + cubeGrid.IsPreview = true; + tempGrids.Add(cubeGrid); + } + + var massGatherWorkData = new MassGathererWorkData(); + massGatherWorkData.grids = tempGrids; + massGatherWorkData.faction = MyAPIGateway.Session.Factions.TryGetPlayerFaction(playerCache.IdentityId); + var massGatherTask = MyAPIGateway.Parallel.Start(massGatherWorkData.ScanGridMassAction, massGatherWorkData.ScanGridMassCallback, massGatherWorkData); + } + + public void AssignSubgridSpawnLocation(MyObjectBuilder_CubeGrid[] cubeGridObs, Vector3D spawnLoc, MatrixD baseMat) + { + if (baseMat == MatrixD.Zero) return; + + for (int i = 1; i < cubeGridObs.Length; i++) + { + MatrixD subMat = cubeGridObs[i].PositionAndOrientation.Value.GetMatrix(); + MatrixD newMat = MatrixD.CreateWorld(subMat.Translation - baseMat.Translation, subMat.Forward, subMat.Up); + cubeGridObs[i].PositionAndOrientation = new MyPositionAndOrientation(spawnLoc + newMat.Translation, subMat.Forward, subMat.Up); + } + } + + public void GetEntitiesInSphere(List ents, Vector3D center, double radius) + { + ents.Clear(); + //Vector3D center = MyAPIGateway.Session.LocalHumanPlayer.GetPosition(); + BoundingSphereD sphere = new BoundingSphereD(center, radius); + MyGamePruningStructure.GetAllTopMostEntitiesInSphere(ref sphere, ents); + } + + public IMyPlayer GetPlayerfromID(long playerId) + { + List players = new List(); + MyAPIGateway.Players.GetPlayers(players); + foreach(var player in players) + if (player.IdentityId == playerId) return player; + + return null; + } + + public string GetPlayerName(long playerId) + { + foreach(var identity in allIdentities) + { + if (identity.IdentityId == playerId) + return identity.DisplayName; + } + + return string.Empty; + } + + private void OnBlockAdded(IMyEntity entity) + { + IMyCubeBlock block = entity as IMyCubeBlock; + if (block == null) return; + + MyDefinitionId blockDef = block.BlockDefinition; + foreach(var data in config.enemyCheckConfig.blockTypes) + { + foreach(var subtype in data.blockSubtypes.subtype) + { + MyDefinitionId id; + if (string.IsNullOrEmpty(subtype)) + MyDefinitionId.TryParse(data.blockType, out id); + else + MyDefinitionId.TryParse(data.blockType, subtype, out id); + + if (id == null) continue; + if (blockDef == id) + { + if (!enemyBlockCheckList.Contains(block)) + enemyBlockCheckList.Add(block); + } + } + } + } + + private void ClientGetBlocks() + { + HashSet entities = new HashSet(); + MyAPIGateway.Entities.GetEntities(entities); + foreach (var entity in entities) + { + IMyCubeGrid grid = entity as IMyCubeGrid; + if (grid == null) continue; + + var blocks = grid.GetFatBlocks(); + foreach(var block in blocks) + OnBlockAdded(block); + } + } + + private void OnBlockRemoved(IMyEntity entity) + { + IMyCubeBlock block = entity as IMyCubeBlock; + if (block == null) return; + + if (enemyBlockCheckList.Contains(block)) + enemyBlockCheckList.Remove(block); + } + + public void ToolEquipped(long playerId, string typeId, string subTypeId) + { + if (isDedicated) return; + if (previewGrids.Count == 0) return; + if (!enableInput) + { + if (playerCache.Character.EquippedTool == null) return; + MyAPIGateway.Parallel.StartBackground(() => + { + var controlEnt = playerCache.Character as Sandbox.Game.Entities.IMyControllableEntity; + MyAPIGateway.Utilities.InvokeOnGameThread(() => controlEnt?.SwitchToWeapon(null)); + }); + } + else + RemovePreviewGrids(); + + } + + protected override void UnloadData() { + try { + if (config != null) { + if (config.enemyCheckConfig.enableBlockCheck) { + if (MyAPIGateway.Entities != null) { + MyAPIGateway.Entities.OnEntityAdd -= OnBlockAdded; + MyAPIGateway.Entities.OnEntityRemove -= OnBlockRemoved; + } + } + } + + if (MyAPIGateway.Utilities != null) { + MyAPIGateway.Utilities.MessageEntered -= ChatHandler; + } + + if (MyAPIGateway.Multiplayer != null) { + MyAPIGateway.Multiplayer.UnregisterMessageHandler(NetworkHandle, Comms.MessageHandler); + } + + if (!isDedicated) { + Sandbox.ModAPI.MyAPIGateway.Utilities.ShowMessage("FactionHangar", "Mod Unloaded"); + } + + Instance = null; + } + catch (Exception ex) { + MyLog.Default.WriteLineAndConsole($"FactionHangar: Error in UnloadData() - {ex.ToString()}"); + } + } + + public override void SaveData() + { + try + { + UpdateIdentities(); + using (var writer = MyAPIGateway.Utilities.WriteFileInWorldStorage("FactionHangarStorage.xml", typeof(AllHangarData))) + { + writer.Write(MyAPIGateway.Utilities.SerializeToXML(allHangarData)); + writer.Close(); + } + + foreach(var path in cacheGridPaths) + Utils.CreateNullShipBlueprint(path); + + cacheGridPaths.Clear(); + } + catch (Exception ex) + { + VRage.Utils.MyLog.Default.WriteLineAndConsole($"FactionHangar: Error trying to save hangar data!\n {ex.ToString()}"); + } + } + } + + public enum SpawnError + { + None, + EnemyNearby, + InsuffientFunds, + EntityBlockingPlacement, + InvalidPlacementInVoxel, + InvalidSpawningLocation + } +} \ No newline at end of file diff --git a/TSTSSESHangar/Data/Scripts/FactionHangar/Timers.cs b/TSTSSESHangar/Data/Scripts/FactionHangar/Timers.cs new file mode 100644 index 00000000..71c67c6c --- /dev/null +++ b/TSTSSESHangar/Data/Scripts/FactionHangar/Timers.cs @@ -0,0 +1,45 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using VRage.Game.ModAPI; + +namespace CustomHangar +{ + public enum TimerType + { + RetrievalCooldown, + StorageCooldown + } + + public class FactionTimers + { + public List timers; + + public static void AddTimer(IMyFaction faction, TimerType type, int timeAmt) + { + TimerTypes timer = new TimerTypes() + { + type = type, + time = timeAmt + }; + + FactionTimers timers = new FactionTimers() + { + timers = new List { timer } + }; + + if (Session.Instance.cooldownTimers.ContainsKey(faction)) + Session.Instance.cooldownTimers[faction].timers.Add(timer); + else + Session.Instance.cooldownTimers.Add(faction, timers); + } + } + + public class TimerTypes + { + public TimerType type; + public int time; + } +} diff --git a/TSTSSESHangar/Data/Scripts/FactionHangar/Utils.cs b/TSTSSESHangar/Data/Scripts/FactionHangar/Utils.cs new file mode 100644 index 00000000..11c399f6 --- /dev/null +++ b/TSTSSESHangar/Data/Scripts/FactionHangar/Utils.cs @@ -0,0 +1,640 @@ +using EmptyKeys.UserInterface.Generated.StoreBlockView_Bindings; +using Sandbox.Common.ObjectBuilders; +using Sandbox.Game; +using Sandbox.Game.Entities; +using Sandbox.Game.EntityComponents; +using Sandbox.Game.Weapons; +using Sandbox.ModAPI; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using VRage; +using VRage.Game; +using VRage.Game.Entity; +using VRage.Game.ModAPI; +using VRage.Game.ObjectBuilders.Definitions; +using VRage.ObjectBuilders; +using VRage.Utils; +using VRageMath; +using VRage.Game.ModAPI.Ingame; +using Sandbox.Engine.Utils; +using System.Reflection.Metadata.Ecma335; +using VRage.Compiler; +using VRage.Game.ObjectBuilders.Definitions.SessionComponents; +using ProtoBuf.Meta; +using EmptyKeys.UserInterface.Generated; +using VRage.Scripting; + +namespace CustomHangar +{ + public static class Utils + { + public static string GetGridsToStore(List entities, HangarType hangarType, long playerId) + { + IMyFaction faction = MyAPIGateway.Session.Factions.TryGetPlayerFaction(playerId); + bool isLeader = false; + if (faction != null) + isLeader = faction.IsLeader(playerId); + + string gridNames = "Potential Grids To Store:\n"; + foreach(var entity in entities) + { + VRage.Game.ModAPI.IMyCubeGrid grid = entity as VRage.Game.ModAPI.IMyCubeGrid; + if (grid == null) continue; + + if (faction != null) + { + if (Session.Instance.DoesFactionOwnGrid(grid, faction)) + { + if (!isLeader) + { + if (Session.Instance.DoesPlayerOwnGrid(grid, playerId)) + gridNames += $"{grid.CustomName},\n"; + } + else + gridNames += $"{grid.CustomName},\n"; + } + } + else + if (Session.Instance.DoesPlayerOwnGrid(grid, playerId)) + gridNames += $"{grid.CustomName},\n"; + } + + return gridNames; + } + + public static void CheckOwnerValidFaction(IMyFaction faction, MyCubeGrid grid, long playerId) + { + if (faction == null) return; + if (faction.IsMember(playerId)) return; + + grid.ChangeGridOwner(playerId, MyOwnershipShareModeEnum.Faction); + } + + public static bool IsGridIntersecting(List grids) + { + if (grids == null || grids.Count == 0) return false; + /*List ents = new List(); + var bb = grid.PositionComp.WorldVolume.GetBoundingBox(); + MyGamePruningStructure.GetAllEntitiesInBox(ref bb, ents); + return ents.Count != 0;*/ + + /*var aabb = grid.PositionComp.WorldAABB; + bool result = grid.GetIntersectionWithAABB(ref aabb); + return result;*/ + var settings = new MyGridPlacementSettings(); + settings.VoxelPlacement = new VoxelPlacementSettings() + { + PlacementMode = VoxelPlacementMode.OutsideVoxel + }; + + foreach (var grid in grids) + { + bool isStatic = grid.GridSizeEnum == MyCubeSize.Large ? true : Session.Instance.config.spawnSGStatic; + var canPlace = MyCubeGrid.TestPlacementArea(grid, isStatic, ref settings, grid.PositionComp.LocalAABB, false, null, !isStatic, true); + if (canPlace) continue; + return true; + } + + return false; + } + + public static bool CheckForExcludedBlock(MyCubeGrid grid) + { + var blocks = grid.GetFatBlocks(); + foreach(var block in blocks) + { + VRage.Game.ModAPI.IMyCubeBlock cubeBlock = block as VRage.Game.ModAPI.IMyCubeBlock; + long owner = block.OwnerId; + if (owner == 0) continue; + + MyDefinitionId blockDef = cubeBlock.BlockDefinition; + foreach(var def in Session.Instance.config.autoHangarConfig.exclusions.excludedBlockTypes) + { + foreach(var subtype in def.blockSubtypes.subtype) + { + MyDefinitionId id; + MyDefinitionId.TryParse(def.blockType, subtype, out id); + if (id != null && id == blockDef) return true; + } + } + } + + return false; + } + + public static void LoadHelpPopup() + { + StringBuilder sb = new StringBuilder(); + sb.Append("*** Faction leaders can execute commands on any faction grid while members can only execute commands on their own grids in the faction hangar. ***\n\n"); + sb.Append("/fh list - Displays a list of grids and their index currently in your faction hangar.\n"); + sb.Append("/fh store - Displays a list of possible grids you can store to your faction hangar in range.\n"); + sb.Append("/fh store GRIDNAME - Attempts to store the desired grid to your faction hangar.\n"); + sb.Append("/fh load [index#] - Attempts to load the desired grid at index from faction hangar.\n"); + sb.Append("/fh load [index#].true - Attempts to load the desired grid at index to its original location.\n"); + sb.Append("/fh load [index#].true.force - Attempts to load the desired grid at index but forces spawning at original location (no collision checks).\n"); + sb.Append("/fh transfer [index#] - Transfers the desired grid at index over to your private hangar.\n"); + sb.Append("/fh remove [index#] - Attempts to delete the desired grid at index from faction hangar.\n"); + sb.Append("/fh togglesphere - Toggles the visble debugging sphere that shows the 'spawnable' areas.\n"); + sb.Append("/fh togglegps - Toggles the GPS markers for the 'spawnable' areas.\n"); + sb.Append("/ph list - Displays a list of grids and their index currently in your private hangar.\n"); + sb.Append("/ph store - Displays a list of possible grids you can store to private hangar in range.\n"); + sb.Append("/ph store GRIDNAME - Attempts to store the desired grid to your private hangar.\n"); + sb.Append("/ph load [index#] - Attempts to load the desired grid at index from private hangar.\n"); + sb.Append("/ph load [index#].true - Attempts to load the desired grid at index to its original location.\n"); + sb.Append("/ph load [index#].true.force - Attempts to load the desired grid at index but forces spawning at original location (no collision checks).\n"); + sb.Append("/ph transfer [index#] - Transfers the desired grid at index over to your faction hangar.\n"); + sb.Append("/ph remove [index#] - Attempts to delete the desired grid at index from private hangar.\n"); + + MyAPIGateway.Utilities.ShowMissionScreen("Faction Hangar Command List", "", null, sb.ToString(), null, "Ok"); + + } + + public static void Storegrid(ObjectContainer packet) + { + IMyFaction faction = MyAPIGateway.Session.Factions.TryGetPlayerFaction(packet.playerId); + if (packet.hangarType == HangarType.Faction) + { + if (faction == null) return; + if (Session.Instance.cooldownTimers.ContainsKey(faction)) + { + foreach (var timer in Session.Instance.cooldownTimers[faction].timers) + { + if (timer.type == TimerType.StorageCooldown) + { + MyVisualScriptLogicProvider.SendChatMessageColored($"Must wait {timer.time} seconds before your faction can store.", Color.Red, "[FactionHangar]", packet.playerId, "Red"); + return; + } + } + } + + int slots = Session.Instance.allHangarData.GetFactionSlots(faction.FactionId); + if (slots >= Session.Instance.config.factionHangarConfig.maxFactionSlots) + { + MyVisualScriptLogicProvider.SendChatMessageColored($"Your faction has exceeded the amount of stored grids.", Color.Red, "[FactionHangar]", packet.playerId, "Red"); + return; + } + + if (packet.gridData.Count > 1) + { + if (slots + packet.gridData.Count > Session.Instance.config.factionHangarConfig.maxFactionSlots) + { + MyVisualScriptLogicProvider.SendChatMessageColored($"Storing {packet.gridData.Count} connected grids will exceed your faction slots. Please remove connected grids.", Color.Red, "[FactionHangar]", packet.playerId, "Red"); + return; + } + } + } + + if (packet.hangarType == HangarType.Private) + { + int unusedSlots = Session.Instance.allHangarData.GetPrivateSlots(packet.playerId); + if (unusedSlots >= Session.Instance.config.privateHangarConfig.maxPrivateSlots) + { + MyVisualScriptLogicProvider.SendChatMessageColored($"You have exceeded the {Session.Instance.config.privateHangarConfig.maxPrivateSlots} max amount of stored grids in private hangar.", Color.Red, "[FactionHangar]", packet.playerId, "Red"); + return; + } + + if (packet.gridData.Count > 1) + { + if (unusedSlots + packet.gridData.Count > Session.Instance.config.privateHangarConfig.maxPrivateSlots) + { + MyVisualScriptLogicProvider.SendChatMessageColored($"Storing {packet.gridData.Count} connected grids will exceed your private slots of {Session.Instance.config.privateHangarConfig.maxPrivateSlots}. Please remove connected grids.", Color.Red, "[FactionHangar]", packet.playerId, "Red"); + return; + } + } + } + + int delaySeconds = packet.hangarType == HangarType.Faction ? Session.Instance.config.factionHangarConfig.factionStoreDelay : Session.Instance.config.privateHangarConfig.privateStoreDelay; + HangarDelayData hangarDelayData = new HangarDelayData() + { + playerId = packet.playerId, + gridData = packet.gridData, + playerName = packet.stringData, + hangarType = packet.hangarType, + requesterId = packet.requesterId + }; + + Session.Instance.hangarDelay.Add(hangarDelayData); + foreach (var grid in packet.gridData) + MyVisualScriptLogicProvider.SendChatMessageColored($"Storing Grid {grid.gridName} in {delaySeconds} seconds", Color.Green, "[FactionHangar]", packet.playerId, "Green"); + + if (faction != null) + FactionTimers.AddTimer(faction, TimerType.StorageCooldown, Session.Instance.config.factionHangarConfig.factionHangarCooldown); + + IMyPlayer player = Session.Instance.GetPlayerfromID(packet.requesterId); + bool privateStorage = packet.hangarType == HangarType.Private ? true : false; + if (player != null) + Comms.AddClientCooldown(player.SteamUserId, privateStorage, TimerType.StorageCooldown); + + } + + public static void GetFactionList(ObjectContainer packet) + { + IMyFaction faction = MyAPIGateway.Session.Factions.TryGetPlayerFaction(packet.playerId); + if (faction != null) + { + bool isLeader = faction.IsLeader(packet.playerId); + string gridNames = Session.Instance.allHangarData.GetFactionsGridNames(faction.FactionId, packet.playerId, isLeader); + if (string.IsNullOrEmpty(gridNames)) + { + MyVisualScriptLogicProvider.SendChatMessageColored($"Your faction does not have any stored grids.", Color.Red, "[FactionHangar]", packet.playerId, "Red"); + return; + } + + if (!isLeader) + MyVisualScriptLogicProvider.SendChatMessageColored($"You are not a faction leader and can ONLY access grids owned by you.", Color.Orange, "[FactionHangar]", packet.playerId, "Green"); + + MyVisualScriptLogicProvider.SendChatMessageColored($"{gridNames}", Color.Green, "[FactionHangar]", packet.playerId, "Green"); + return; + } + } + + public static void GetPrivateList(ObjectContainer packet) + { + string gridNames = Session.Instance.allHangarData.GetPrivateGridNames(packet.playerId); + if (string.IsNullOrEmpty(gridNames)) + { + MyVisualScriptLogicProvider.SendChatMessageColored($"Your private hangar does not have any stored grids.", Color.Red, "[FactionHangar]", packet.playerId, "Red"); + return; + } + + MyVisualScriptLogicProvider.SendChatMessageColored($"{gridNames}", Color.Green, "[FactionHangar]", packet.playerId, "Green"); + return; + } + + public static bool TryHangarGridRemoval(ObjectContainer packet) + { + if (packet.hangarType == HangarType.Faction) + { + IMyFaction faction = MyAPIGateway.Session.Factions.TryGetPlayerFaction(packet.playerId); + if (faction != null) + { + bool isLeader = faction.IsLeader(packet.playerId); + var gridData = Session.Instance.allHangarData.GetFactionGridData(faction.FactionId, packet.intValue); + if (gridData == null) + { + MyVisualScriptLogicProvider.SendChatMessageColored($"Grid index {packet.intValue} is invalid", Color.Red, "[FactionHangar]", packet.playerId, "Red"); + return false; + } + + if (!isLeader) + { + if (gridData.owner != packet.playerId) + { + MyVisualScriptLogicProvider.SendChatMessageColored($"You are not a faction leader and can ONLY remove grids owned by you.", Color.Red, "[FactionHangar]", packet.playerId, "Red"); + return false; + } + } + + Session.Instance.allHangarData.RemoveFactionData(faction.FactionId, packet.intValue, true); + return true; + } + } + + if (packet.hangarType == HangarType.Private) + { + Session.Instance.allHangarData.RemovePrivateData(packet.playerId, packet.intValue, true); + return true; + } + + return false; + } + + public static void GetGridData(ObjectContainer packet) + { + GridData gridData = null; + MyObjectBuilder_Definitions ob = null; + if (packet.hangarType == HangarType.Faction) + { + IMyFaction faction = MyAPIGateway.Session.Factions.TryGetPlayerFaction(packet.playerId); + if (faction == null) return; + + if (Session.Instance.cooldownTimers.ContainsKey(faction)) + { + foreach (var timer in Session.Instance.cooldownTimers[faction].timers) + { + if (timer.type == TimerType.RetrievalCooldown) + { + MyVisualScriptLogicProvider.SendChatMessageColored($"Must wait {timer.time} seconds before your faction can load another grid.", Color.Red, "[FactionHangar]", packet.playerId, "Red"); + return; + } + } + } + + bool isLeader = faction.IsLeader(packet.playerId); + + gridData = Session.Instance.allHangarData.GetFactionGridData(faction.FactionId, packet.intValue); + if (gridData == null) + { + MyVisualScriptLogicProvider.SendChatMessageColored($"Grid index {packet.intValue} is invalid", Color.Red, "[FactionHangar]", packet.playerId, "Red"); + return; + } + + if (!isLeader) + { + if (gridData.owner != packet.playerId) + { + MyVisualScriptLogicProvider.SendChatMessageColored($"You are not a faction leader and can ONLY access grids owned by you.", Color.Red, "[FactionHangar]", packet.playerId, "Red"); + return; + } + } + + MyObjectBuilderSerializer.DeserializeXML(gridData.gridPath, out ob); + if (ob == null) + return; + } + + if (packet.hangarType == HangarType.Private) + { + gridData = Session.Instance.allHangarData.GetPrivateGridData(packet.playerId, packet.intValue); + if (gridData == null) + { + MyVisualScriptLogicProvider.SendChatMessageColored($"Grid index {packet.intValue} is invalid", Color.Red, "[FactionHangar]", packet.playerId, "Red"); + return; + } + + MyObjectBuilderSerializer.DeserializeXML(gridData.gridPath, out ob); + if (ob == null) + return; + } + + if (packet.originalLocation) + { + MyObjectBuilder_CubeGrid[] cubeGridObs = Session.Instance.GetGridFromGridData(ob, packet.intValue, packet.hangarType); + if (cubeGridObs == null) return; + + + Session.Instance.spawnType = SpawnType.Original; + if (Session.Instance.IsEnemyNear(cubeGridObs[0], packet.playerId)) + { + MyVisualScriptLogicProvider.SendChatMessageColored($"Enemy nearby, failed to spawn from hangar.", Color.Red, "[FactionHangar]", packet.playerId, "Red"); + return; + } + + Session.Instance.SpawnGridsFromOb(cubeGridObs.ToList(), packet.intValue, packet.hangarType, packet.playerId, 0, SpawnType.Original, !packet.force); + Session.Instance.spawnType = SpawnType.None; + return; + } + + Comms.SendOBToClient(ob, packet.steamId, packet.intValue, packet.hangarType); + } + + public static void CreateNullShipBlueprint(string path) + { + //List list = GetGridGroupObs(myCubeGrid, groupType); + MyObjectBuilder_ShipBlueprintDefinition myObjectBuilder_ShipBlueprintDefinition = MyObjectBuilderSerializer.CreateNewObject(); + //myObjectBuilder_ShipBlueprintDefinition.Id = new MyDefinitionId(new MyObjectBuilderType(typeof(MyObjectBuilder_ShipBlueprintDefinition)), MyUtils.StripInvalidChars(blueprintName)); + //myObjectBuilder_ShipBlueprintDefinition.CubeGrids = list.ToArray(); + //myObjectBuilder_ShipBlueprintDefinition.RespawnShip = false; + //myObjectBuilder_ShipBlueprintDefinition.DisplayName = blueprintName; + //myObjectBuilder_ShipBlueprintDefinition.CubeGrids[0].DisplayName = blueprintName; + MyObjectBuilder_Definitions myObjectBuilder_Definitions = MyObjectBuilderSerializer.CreateNewObject(); + myObjectBuilder_Definitions.ShipBlueprints = new MyObjectBuilder_ShipBlueprintDefinition[1]; + myObjectBuilder_Definitions.ShipBlueprints[0] = myObjectBuilder_ShipBlueprintDefinition; + MyObjectBuilderSerializer.SerializeXML(path, false, myObjectBuilder_Definitions); + } + + public static void UpdateBalance(long playerId, long amount, int index, HangarType hangarType) + { + if (!Session.Instance.isServer) return; + + IMyFaction faction = MyAPIGateway.Session.Factions.TryGetPlayerFaction(playerId); + long current = 0; + if (faction != null) + { + if (hangarType == HangarType.Faction) + { + GridData data = Session.Instance.allHangarData.GetFactionGridData(faction.FactionId, index); + if (data != null) + if (data.autoHangared && Session.Instance.config.autoHangarConfig.autoBypassSpawnCost) + return; + } + else + { + GridData data = Session.Instance.allHangarData.GetPrivateGridData(playerId, index); + if (data != null) + if (data.autoHangared && Session.Instance.config.autoHangarConfig.autoBypassSpawnCost) + return; + } + + faction.TryGetBalanceInfo(out current); + if (amount <= current) + { + faction.RequestChangeBalance(-amount); + return; + } + } + + IMyPlayer player = Session.Instance.GetPlayerfromID(playerId); + if (player == null) return; + + if (hangarType == HangarType.Private) + { + GridData data = Session.Instance.allHangarData.GetPrivateGridData(playerId, index); + if (data != null) + if (data.autoHangared && Session.Instance.config.autoHangarConfig.autoBypassSpawnCost) + return; + } + + player.TryGetBalanceInfo(out current); + if (amount <= current) + player.RequestChangeBalance(-amount); + } + + public static void AddSpawnLocationsClientGPS() + { + if (!Session.Instance.spawnClientGPS) return; + foreach (var area in Session.Instance.config.spawnAreas) + { + if (!area.enableSpawnArea) continue; + if (Session.Instance.useInverseSpawnArea) + { + IMyGps gps = MyAPIGateway.Session.GPS.Create($"Non-{SpawnType.SpawnArea} - {area.areaRadius}m", "", area.areaCenter, true); + gps.GPSColor = Color.SeaGreen; + MyAPIGateway.Session.GPS.AddLocalGps(gps); + Session.Instance.clientSpawnLocations.Add(gps); + } + else + { + IMyGps gps = MyAPIGateway.Session.GPS.Create($"{SpawnType.SpawnArea} - {area.areaRadius}m", "", area.areaCenter, true); + gps.GPSColor = Color.SeaGreen; + MyAPIGateway.Session.GPS.AddLocalGps(gps); + Session.Instance.clientSpawnLocations.Add(gps); + } + } + + if (Session.Instance.config.spawnNearbyConfig.allowSpawnNearby) + { + IMyGps gps = MyAPIGateway.Session.GPS.Create($"{SpawnType.Nearby} - {Session.Instance.config.spawnNearbyConfig.nearbyRadius}m", "", Session.Instance.original, true); + gps.GPSColor = Color.Orange; + MyAPIGateway.Session.GPS.AddLocalGps(gps); + Session.Instance.clientSpawnLocations.Add(gps); + } + } + + public static void RemoveSpawnLocationsClientGPS() + { + foreach(var gps in Session.Instance.clientSpawnLocations) + MyAPIGateway.Session.GPS.RemoveLocalGps(gps); + + Session.Instance.clientSpawnLocations.Clear(); + } + + public static void CheckGridSpawnLimits(VRage.Game.ModAPI.IMyCubeGrid grid, IMyFaction faction, HangarType hangarType, int index, SpawnType spawnType, long playerId) + { + if (hangarType == HangarType.Faction) + { + if (faction != null) + { + if (Session.Instance.allHangarData.IsFactionGridAutoHangared(faction.FactionId, index)) + if (Session.Instance.config.autoHangarConfig.autoBypassSpawnLimits) return; + + if (BypassLimits(spawnType, grid.GetPosition())) return; + } + } + + if (hangarType == HangarType.Private) + { + if (Session.Instance.allHangarData.IsPrivateGridAutoHangared(playerId, index)) + if (Session.Instance.config.autoHangarConfig.autoBypassSpawnLimits) return; + + if (BypassLimits(spawnType, grid.GetPosition())) return; + } + + List connectedGrids = new List(); + Session.Instance.GetGroupByType(grid, connectedGrids, GridLinkTypeEnum.Physical); + + bool removeAmmo = Session.Instance.config.spawnConfig.removeAmmo; + bool removeUranium = Session.Instance.config.spawnConfig.removeUranium; + bool removeIce = Session.Instance.config.spawnConfig.removeIce; + + foreach(var connectedGrid in connectedGrids) + { + var blocks = connectedGrid.GetFatBlocks(); + foreach(var block in blocks) + { + if (!block.HasInventory) continue; + if (removeAmmo || removeUranium || removeIce) + { + var invList = new List(); + VRage.Game.ModAPI.IMyInventory blockInv = block.GetInventory(); + blockInv.GetItems(invList); + + foreach (var item in invList) + { + bool removeItem = false; + if (item.Type.GetItemInfo().IsAmmo && removeAmmo) + removeItem = true; + if (item.Type.SubtypeId.Contains("Ice") && removeIce) + removeItem = true; + if(item.Type.SubtypeId.Contains("Uranium") && removeUranium) + removeItem = true; + + if (!removeItem) continue; + MyFixedPoint amount = item.Amount; + uint itemId = item.ItemId; + + blockInv.RemoveItems(itemId, amount); + } + } + } + } + } + + public static bool BypassLimits(SpawnType spawntype, Vector3D pos) + { + if (spawntype == SpawnType.Dynamic) + return Session.Instance.config.dynamicSpawningConfig.dynamicSpawnBypass; + + if (spawntype == SpawnType.SpawnArea) + { + foreach(var area in Session.Instance.config.spawnAreas) + { + if (!area.enableSpawnArea) continue; + if (Vector3D.Distance(pos, area.areaCenter) > area.areaRadius) continue; + return area.spawnAreaBypass; + } + + return true; + } + + if (spawntype == SpawnType.Nearby) + return Session.Instance.config.spawnNearbyConfig.nearbySpawnBypass; + + if (spawntype == SpawnType.Original) + return Session.Instance.config.spawnOriginalConfig.originalSpawnBypass; + + return true; + } + + public static void CheckGridSpawnLimitsInOB(List obs, IMyFaction faction, HangarType hangarType, int index, SpawnType spawnType, long playerId) + { + if (hangarType == HangarType.Faction) + { + if (faction != null) + { + if (Session.Instance.allHangarData.IsFactionGridAutoHangared(faction.FactionId, index)) + if (Session.Instance.config.autoHangarConfig.autoBypassSpawnLimits) return; + + if (BypassLimits(spawnType, obs[0].PositionAndOrientation.Value.Position)) return; + } + } + + if (hangarType == HangarType.Private) + { + if (Session.Instance.allHangarData.IsPrivateGridAutoHangared(playerId, index)) + if (Session.Instance.config.autoHangarConfig.autoBypassSpawnLimits) return; + + if (BypassLimits(spawnType, obs[0].PositionAndOrientation.Value.Position)) return; + } + + foreach (var grid in obs) + { + foreach(var block in grid.CubeBlocks) + { + if (block.TypeId == typeof(MyObjectBuilder_BatteryBlock)) + { + var baseBlock = block as MyObjectBuilder_Base; + if (baseBlock == null) continue; + + var battery = baseBlock as MyObjectBuilder_BatteryBlock; + if (battery == null) continue; + + float remain = battery.CurrentStoredPower; + MyVisualScriptLogicProvider.ShowNotification($"Battery = {remain}", 20000); + battery.CurrentStoredPower = Session.Instance.config.spawnConfig.batteryPercentage / 100; + + continue; + } + + if (block.TypeId == typeof(MyObjectBuilder_GasTank)) + { + var baseBlock = block as MyObjectBuilder_Base; + if (baseBlock == null) continue; + + var tank = baseBlock as MyObjectBuilder_GasTank; + if (tank == null) continue; + + float remain = tank.FilledRatio; + MyVisualScriptLogicProvider.ShowNotification($"Gas = {remain}", 20000); + tank.FilledRatio = Session.Instance.config.spawnConfig.h2Percentage / 100; + } + } + } + } + + public static void RemovePlayersFromSeats(MyCubeGrid grid) + { + List Blocks = new List(); + MyAPIGateway.TerminalActionsHelper.GetTerminalSystemForGrid(grid).GetBlocksOfType(Blocks, x => x.IsFunctional); + + foreach(var block in Blocks) + { + if (block.IsOccupied) + block.RemovePilot(); + } + } + } +} diff --git a/TSTSSESHangar/Data/Scripts/concatrecursivelyandminify.bat b/TSTSSESHangar/Data/Scripts/concatrecursivelyandminify.bat new file mode 100644 index 00000000..9bbffa34 --- /dev/null +++ b/TSTSSESHangar/Data/Scripts/concatrecursivelyandminify.bat @@ -0,0 +1,60 @@ +@echo off +setlocal enabledelayedexpansion +chcp 65001 +REM ^^ this is to change the encoding to UTF-8, apparently + +echo Starting operation... + +set TEMP_OUTPUT=temp_concatenated.txt +set FINAL_OUTPUT=minified_output.txt +set /a COUNT=0 +set /a ERRORS=0 + +if exist "%TEMP_OUTPUT%" ( + echo Existing temporary file found. Deleting... + del "%TEMP_OUTPUT%" +) + +if exist "%FINAL_OUTPUT%" ( + echo Existing output file found. Deleting... + del "%FINAL_OUTPUT%" +) + +for /r %%i in (*.cs) do ( + echo Processing: "%%i" + type "%%i" >> "%TEMP_OUTPUT%" + if errorlevel 1 ( + echo Error processing "%%i". + set /a ERRORS+=1 + ) else ( + set /a COUNT+=1 + ) +) + +echo Concatenation completed. +echo Total files processed: %COUNT% +if %ERRORS% gtr 0 ( + echo There were %ERRORS% errors during the concatenation. +) else ( + echo No errors encountered during concatenation. +) + +echo Minifying concatenated file... +csmin < "%TEMP_OUTPUT%" > "%FINAL_OUTPUT%" +if errorlevel 1 ( + echo Error occurred during minification. + set /a ERRORS+=1 +) else ( + echo Minification completed successfully. +) + +echo Cleaning up temporary file... +del "%TEMP_OUTPUT%" + +echo Operation completed. +if %ERRORS% gtr 0 ( + echo There were %ERRORS% errors during the entire operation. +) else ( + echo No errors encountered during the entire operation. +) +pause \ No newline at end of file diff --git a/TSTSSESHangar/metadata.mod b/TSTSSESHangar/metadata.mod new file mode 100644 index 00000000..0a020fdf --- /dev/null +++ b/TSTSSESHangar/metadata.mod @@ -0,0 +1,4 @@ + + + 1.0 + \ No newline at end of file diff --git a/TSTSSESHangar/modinfo.sbmi b/TSTSSESHangar/modinfo.sbmi new file mode 100644 index 00000000..0e739626 --- /dev/null +++ b/TSTSSESHangar/modinfo.sbmi @@ -0,0 +1,11 @@ + + + 76561198071098415 + 0 + + + 3355214579 + Steam + + + \ No newline at end of file diff --git a/TSTSSESLinkUtility/upload thyself.txt b/TSTSSESLinkUtility/upload thyself.txt new file mode 100644 index 00000000..e69de29b