diff --git a/Slipspace Engine/modinfo.sbmi b/Slipspace Engine/modinfo.sbmi
new file mode 100644
index 00000000..8b4e7c31
--- /dev/null
+++ b/Slipspace Engine/modinfo.sbmi
@@ -0,0 +1,11 @@
+
+
+ 76561198071098415
+ 0
+
+
+ 3260158135
+ Steam
+
+
+
\ No newline at end of file
diff --git a/TSTSSESCores/Data/Guids.sbc b/TSTSSESCores/Data/Guids.sbc
new file mode 100644
index 00000000..65398e06
--- /dev/null
+++ b/TSTSSESCores/Data/Guids.sbc
@@ -0,0 +1,15 @@
+
+
+
+
+
+ ModStorageComponent
+ MIG-SpecCores
+
+
+ 82f6e121-550f-4042-a2b8-185ed2a52abc
+ 82f6e121-550f-4042-a2b8-185ed2a52abd
+
+
+
+
\ No newline at end of file
diff --git a/TSTSSESCores/Data/Scripts/Scripts/.idea/.idea.Scripts/.idea/.gitignore b/TSTSSESCores/Data/Scripts/Scripts/.idea/.idea.Scripts/.idea/.gitignore
new file mode 100644
index 00000000..6972269b
--- /dev/null
+++ b/TSTSSESCores/Data/Scripts/Scripts/.idea/.idea.Scripts/.idea/.gitignore
@@ -0,0 +1,13 @@
+# Default ignored files
+/shelf/
+/workspace.xml
+# Rider ignored files
+/modules.xml
+/projectSettingsUpdater.xml
+/contentModel.xml
+/.idea.Scripts.iml
+# Datasource local storage ignored files
+/dataSources/
+/dataSources.local.xml
+# Editor-based HTTP Client requests
+/httpRequests/
diff --git a/TSTSSESCores/Data/Scripts/Scripts/.idea/.idea.Scripts/.idea/encodings.xml b/TSTSSESCores/Data/Scripts/Scripts/.idea/.idea.Scripts/.idea/encodings.xml
new file mode 100644
index 00000000..df87cf95
--- /dev/null
+++ b/TSTSSESCores/Data/Scripts/Scripts/.idea/.idea.Scripts/.idea/encodings.xml
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/TSTSSESCores/Data/Scripts/Scripts/.idea/.idea.Scripts/.idea/indexLayout.xml b/TSTSSESCores/Data/Scripts/Scripts/.idea/.idea.Scripts/.idea/indexLayout.xml
new file mode 100644
index 00000000..7b08163c
--- /dev/null
+++ b/TSTSSESCores/Data/Scripts/Scripts/.idea/.idea.Scripts/.idea/indexLayout.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/TSTSSESCores/Data/Scripts/Scripts/.idea/.idea.Scripts/.idea/vcs.xml b/TSTSSESCores/Data/Scripts/Scripts/.idea/.idea.Scripts/.idea/vcs.xml
new file mode 100644
index 00000000..c2365ab1
--- /dev/null
+++ b/TSTSSESCores/Data/Scripts/Scripts/.idea/.idea.Scripts/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/TSTSSESCores/Data/Scripts/Scripts/App.config b/TSTSSESCores/Data/Scripts/Scripts/App.config
new file mode 100644
index 00000000..bae5d6d8
--- /dev/null
+++ b/TSTSSESCores/Data/Scripts/Scripts/App.config
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/TSTSSESCores/Data/Scripts/Scripts/Shared/Action2.cs b/TSTSSESCores/Data/Scripts/Scripts/Shared/Action2.cs
new file mode 100644
index 00000000..bbc03219
--- /dev/null
+++ b/TSTSSESCores/Data/Scripts/Scripts/Shared/Action2.cs
@@ -0,0 +1,9 @@
+namespace MIG.Shared.CSharp {
+ public interface Action2 {
+ void run(T t, K k);
+ }
+
+ public interface Action1 {
+ void run(T t);
+ }
+}
diff --git a/TSTSSESCores/Data/Scripts/Scripts/Shared/BlockIdmatcher.cs b/TSTSSESCores/Data/Scripts/Scripts/Shared/BlockIdmatcher.cs
new file mode 100644
index 00000000..f49b0d92
--- /dev/null
+++ b/TSTSSESCores/Data/Scripts/Scripts/Shared/BlockIdmatcher.cs
@@ -0,0 +1,203 @@
+using System;
+using System.Collections.Generic;
+using System.Text.RegularExpressions;
+using VRage.Game;
+
+namespace SharedLib
+{
+
+ public class BlockIdMatcherWithCache : BlockIdMatcher
+ {
+ private Dictionary matches = new Dictionary();
+ public BlockIdMatcherWithCache(string s) : base(s)
+ {
+ }
+
+ public override bool Matches(MyDefinitionId Id)
+ {
+ bool result;
+ if (!matches.TryGetValue(Id, out result))
+ {
+ result = base.Matches(Id);
+ matches[Id] = result;
+ return result;
+ }
+
+ return result;
+ }
+ }
+
+ ///
+ /// Examples: */*AdminBlock* */*Admin-Block A/*Admin-Block *!Admin-Block */* a/a
+ ///
+ public class BlockIdMatcher
+ {
+ private static Regex regex = new Regex("([*\\w-_0-9]+)?(?:\\/)?([*\\w-_0-9]+)");
+ public List checks = new List();
+
+ public BlockIdMatcher(string s)
+ {
+ if (s == null) { return; }
+ var m = regex.Matches(s);
+ for (var x = 0; x < m.Count; x++)
+ {
+ var match = m[x];
+ switch (match.Groups.Count)
+ {
+ case 2:
+ {
+ var w = match.Groups[1].Value;
+ checks.Add(new TypeSubtypeMatcher(TypeSubtypeMatcher.MODE_ANY, String.Empty, GetMode(w), w.Replace("*", "")));
+ break;
+ }
+ case 3:
+ {
+ var w1 = match.Groups[1].Value;
+ var w2 = match.Groups[2].Value;
+ checks.Add(new TypeSubtypeMatcher(GetMode(w1), w1.Replace("*", ""), GetMode(w2), w2.Replace("*", "")));
+ break;
+ }
+ }
+ }
+ }
+
+ public override string ToString()
+ {
+ var s = "";
+ foreach(var x in checks)
+ {
+ s += x.ToString() + " ";
+ }
+
+ return $"BlockIdMatcher:{checks.Count} [{s}]";
+ }
+
+ private int GetMode(string w)
+ {
+ var v = !w.Contains("!");
+ if (w == "*") return TypeSubtypeMatcher.MODE_ANY;
+ if (w.StartsWith("*") && w.EndsWith("*")) return v ? TypeSubtypeMatcher.MODE_CONTAINS : TypeSubtypeMatcher.MODE_NOT_CONTAINS;
+ if (w.StartsWith("*")) return v ? TypeSubtypeMatcher.MODE_ENDS : TypeSubtypeMatcher.MODE_NOT_ENDS;
+ if (w.EndsWith("*")) return v ? TypeSubtypeMatcher.MODE_STARTS : TypeSubtypeMatcher.MODE_NOT_STARTS;
+ return TypeSubtypeMatcher.MODE_EXACT;
+ }
+
+ public virtual bool Matches(string type, string subtype)
+ {
+ foreach (var x in checks)
+ {
+ if (x.Matches(type, subtype))
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
+
+ public virtual bool Matches(MyDefinitionId Id)
+ {
+ return Matches(Id.TypeId.ToString().Replace("MyObjectBuilder_", ""), Id.SubtypeName);
+ }
+
+ public class TypeSubtypeMatcher
+ {
+ public const int MODE_EXACT = 0;
+
+ public const int MODE_STARTS = 1;
+ public const int MODE_ENDS = 2;
+ public const int MODE_CONTAINS = 3;
+
+ public const int MODE_NOT_STARTS = 4;
+ public const int MODE_NOT_ENDS = 5;
+ public const int MODE_NOT_CONTAINS = 6;
+
+ public const int MODE_ANY = 7;
+
+
+ public int modeType = 0;
+ public int modeSubType = 0;
+ public string typeString = null;
+ public string subtypeString = null;
+
+
+ public TypeSubtypeMatcher(int modeType, string typeString, int modeSubType, string subtypeString)
+ {
+ this.modeType = modeType;
+ this.typeString = typeString;
+ this.modeSubType = modeSubType;
+ this.subtypeString = subtypeString;
+ }
+
+ public bool MatchesType(string type)
+ {
+ switch (modeType)
+ {
+ case MODE_EXACT:
+ if (type != typeString) return false;
+ break;
+ case MODE_STARTS:
+ if (!type.StartsWith(typeString)) return false;
+ break;
+ case MODE_NOT_STARTS:
+ if (type.StartsWith(typeString)) return false;
+ break;
+ case MODE_ENDS:
+ if (!type.EndsWith(typeString)) return false;
+ break;
+ case MODE_NOT_ENDS:
+ if (type.EndsWith(typeString)) return false;
+ break;
+ case MODE_CONTAINS:
+ if (!type.Contains(typeString)) return false;
+ break;
+ case MODE_NOT_CONTAINS:
+ if (type.Contains(typeString)) return false;
+ break;
+ }
+
+ return true;
+ }
+
+ public bool MatchesSubtype(string subtype)
+ {
+ switch (modeSubType)
+ {
+ case MODE_EXACT:
+ if (subtype != subtypeString) return false;
+ break;
+ case MODE_STARTS:
+ if (!subtype.StartsWith(subtypeString)) return false;
+ break;
+ case MODE_NOT_STARTS:
+ if (subtype.StartsWith(subtypeString)) return false;
+ break;
+ case MODE_ENDS:
+ if (!subtype.EndsWith(subtypeString)) return false;
+ break;
+ case MODE_NOT_ENDS:
+ if (subtype.EndsWith(subtypeString)) return false;
+ break;
+ case MODE_CONTAINS:
+ if (!subtype.Contains(subtypeString)) return false;
+ break;
+ case MODE_NOT_CONTAINS:
+ if (subtype.Contains(subtypeString)) return false;
+ break;
+ }
+
+ return true;
+ }
+
+ public bool Matches(string type, string subtype)
+ {
+ return MatchesType(type) && MatchesSubtype(subtype);
+ }
+
+ public override string ToString()
+ {
+ return typeString + "/" + subtypeString + "[" + modeType + "/" + modeSubType + "]";
+ }
+ }
+ }
+}
diff --git a/TSTSSESCores/Data/Scripts/Scripts/Shared/BlueprintsHelper.cs b/TSTSSESCores/Data/Scripts/Scripts/Shared/BlueprintsHelper.cs
new file mode 100644
index 00000000..fe72792f
--- /dev/null
+++ b/TSTSSESCores/Data/Scripts/Scripts/Shared/BlueprintsHelper.cs
@@ -0,0 +1,110 @@
+using Sandbox.Definitions;
+using VRage.ObjectBuilders;
+
+namespace MIG.Shared.SE
+{
+
+ public enum BlueprintType
+ {
+ OreToIngot,
+ OresToIngots,
+ OresToOres,
+
+ IngotsToIngots,
+ IngotsToComponent,
+ IngotsToComponents,
+
+ ComponentsToComponents,
+
+ OtherToTools,
+ IngotsToTools,
+
+ Other
+ }
+
+ public static class BlueprintsHelper
+ {
+ public static readonly MyObjectBuilderType COMPONENT = MyObjectBuilderType.Parse("MyObjectBuilder_Component");
+ public static readonly MyObjectBuilderType ORE = MyObjectBuilderType.Parse("MyObjectBuilder_Ore");
+ public static readonly MyObjectBuilderType INGOT = MyObjectBuilderType.Parse("MyObjectBuilder_Ingot");
+ public static readonly MyObjectBuilderType TOOL = MyObjectBuilderType.Parse("MyObjectBuilder_PhysicalGunObject");
+ public static readonly MyObjectBuilderType TOOL2 = MyObjectBuilderType.Parse("MyObjectBuilder_OxygenContainerObject");
+
+ public static BlueprintType GetBlueprintType(this MyBlueprintDefinitionBase b)
+ {
+ var hasInputOres = false;
+ var hasInputIngots = false;
+ var hasInputComponents = false;
+ var hasInputOther = false;
+
+ var hasOutputOres = false;
+ var hasOutputIngots = false;
+ var hasOutputComponents = false;
+ var hasOutputTools = false;
+ var hasOutputOther = false;
+
+ foreach (var r in b.Prerequisites)
+ {
+ if (r.Id.TypeId == COMPONENT)
+ {
+ hasInputComponents = true;
+ continue;
+ }
+ if (r.Id.TypeId == ORE)
+ {
+ hasInputOres = true;
+ continue;
+ }
+ if (r.Id.TypeId == INGOT)
+ {
+ hasInputIngots = true;
+ continue;
+ }
+
+ hasInputOther = true;
+ }
+
+ foreach (var r in b.Results)
+ {
+ if (r.Id.TypeId == COMPONENT)
+ {
+ hasOutputComponents = true;
+ continue;
+ }
+ if (r.Id.TypeId == TOOL || r.Id.TypeId == TOOL2)
+ {
+ hasOutputTools = true;
+ continue;
+ }
+ if (r.Id.TypeId == ORE)
+ {
+ hasOutputOres = true;
+ continue;
+ }
+ if (r.Id.TypeId == INGOT)
+ {
+ hasOutputIngots = true;
+ continue;
+ }
+
+ hasOutputOther = true;
+ }
+
+ var i = (hasInputOres ? 1 : 0) + (hasInputIngots ? 1 : 0) + (hasInputComponents ? 1 : 0) + (hasInputOther ? 1 : 0);
+ var o = (hasOutputOres ? 1 : 0) + (hasOutputIngots ? 1 : 0) + (hasOutputComponents ? 1 : 0) + (hasOutputTools ? 1 : 0) + (hasOutputOther ? 1 : 0);
+
+ if (i != 1) return BlueprintType.Other;
+ if (o != 1) return BlueprintType.Other;
+
+ if (hasOutputTools) return hasInputIngots ? BlueprintType.IngotsToTools : BlueprintType.OtherToTools;
+ if (hasInputOres && hasOutputIngots) return b.Results.Length == 1 && b.Prerequisites.Length == 1 ? BlueprintType.OreToIngot : BlueprintType.OresToIngots;
+ if (hasInputIngots && hasOutputComponents) return b.Results.Length > 1 ? BlueprintType.IngotsToComponents : BlueprintType.IngotsToComponent;
+ if (hasInputOres && hasOutputOres) return BlueprintType.OresToOres;
+ if (hasInputIngots && hasOutputIngots) return BlueprintType.IngotsToIngots;
+ if (hasInputComponents && hasOutputComponents) return BlueprintType.ComponentsToComponents;
+ if (hasOutputTools) return BlueprintType.IngotsToTools;
+
+ return BlueprintType.Other;
+ }
+ }
+}
diff --git a/TSTSSESCores/Data/Scripts/Scripts/Shared/Common.cs b/TSTSSESCores/Data/Scripts/Scripts/Shared/Common.cs
new file mode 100644
index 00000000..e3cab113
--- /dev/null
+++ b/TSTSSESCores/Data/Scripts/Scripts/Shared/Common.cs
@@ -0,0 +1,132 @@
+using Sandbox.Game;
+using Sandbox.ModAPI;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using ProtoBuf;
+using VRage.Game.ModAPI;
+using VRageMath;
+
+namespace MIG.Shared.SE {
+ public static class Common {
+
+ [ProtoContract]
+ class PlayerMessage
+ {
+ [ProtoMember(1)]
+ public string message;
+
+ [ProtoMember(2)]
+ public string author;
+
+
+ [ProtoMember(4)] public string font = "Blue";
+ }
+
+ private static Connection SendMessageConnection;
+ public static void Init()
+ {
+ SendMessageConnection = new Connection(16623, RequestSendMessageHandler);
+ }
+
+
+ private static void RequestSendMessageHandler(PlayerMessage arg1, ulong arg2, bool arg3)
+ {
+ SendChatMessage(arg1.message, arg1.author, arg2.IdentityId(), arg1.font);
+ }
+
+ public static void SendChatMessage(string message, string author = "", long playerId = 0L, string font = "Blue") {
+ if (!MyAPIGateway.Session.IsServer)
+ {
+ SendMessageConnection.SendMessageToServer(new PlayerMessage()
+ {
+ message = message,
+ author = author,
+ font = font
+ });
+ }
+ else
+ {
+ MyVisualScriptLogicProvider.SendChatMessage (message, author, playerId, font);
+ }
+
+ }
+
+ public static void SendChatMessageToMe(string message, string author = "", string font = "Blue") {
+ if (MyAPIGateway.Session.Player != null) {
+ MyVisualScriptLogicProvider.SendChatMessage (message, author, MyAPIGateway.Session.Player.IdentityId, font);
+ }
+ }
+
+ public static void ShowNotification(string message, int disappearTimeMs, string font = "White", long playerId = 0L) {
+ MyVisualScriptLogicProvider.ShowNotification (message, disappearTimeMs, font, playerId);
+ }
+
+ public static void ShowNotificationForAllInRange(string message, int disappearTimeMs, Vector3D pos, float r, string font = "White") {
+ var pl = GetOnlinePlayersInRange (pos, r);
+ foreach (var x in pl) {
+ MyVisualScriptLogicProvider.ShowNotification (message, disappearTimeMs, font, x.IdentityId);
+ }
+ }
+
+
+ public static void ShowNotificationForMeInGrid(IMyCubeGrid grid, string message, int disappearTimeMs, string font = "White") {
+ if (MyAPIGateway.Session.isTorchServer()) return;
+ try {
+ var cock = MyAPIGateway.Session.Player.Controller.ControlledEntity as IMyCockpit;
+ if (cock == null) return;
+ if (cock.CubeGrid != grid) {
+ return;
+ }
+ MyVisualScriptLogicProvider.ShowNotificationLocal(message, disappearTimeMs, font);
+ } catch (Exception e) { }
+ }
+
+
+ public static List GetOnlinePlayersInRange (Vector3D pos, float r) {
+ List players = new List();
+ r = r*r;
+ MyAPIGateway.Multiplayer.Players.GetPlayers(players, (x)=>{
+ var ch = x.Character;
+ if (ch != null) {
+ return (ch.WorldMatrix.Translation - pos).LengthSquared() < r;
+ }
+ return false;
+ });
+ return players;
+ }
+
+
+
+
+
+ public static String getPlayerName (long id) {
+ var p = getPlayer (id);
+ return p ==null ? "UnknownP" : p.DisplayName;
+ }
+
+ public static IMyPlayer getPlayer (long id) {
+ var ind = new List();
+
+ MyAPIGateway.Players.GetPlayers (ind, (x) => { return x.IdentityId == id; });
+ return ind.FirstOrDefault(null) as IMyPlayer;
+ }
+ //public static bool isBot (long id) {
+ // var ind = new List();
+ // MyAPIGateway.Players.GetAllIdentites (ind, (x) => { return x.IdentityId == id; });
+ //
+ // if (ind.Count == 1) {
+ // ind[0].
+ // }
+ //}
+
+ //public static void ShowNotificationToAll(string message, int disappearTimeMs, string font = "White") {
+ // MyVisualScriptLogicProvider.ShowNotificationToAll (message, disappearTimeMs, font);
+ //}
+ //
+ //public static void ShowSystemMessage(string from, string text, long player) {
+ // //MyAPIGateway.Utilities.ShowMessage("System", "Killed by : [" +killer.DisplayName + "] Sent to him: [" + (-took)+"] credits");
+ //
+ //}
+ }
+}
diff --git a/TSTSSESCores/Data/Scripts/Scripts/Shared/EconomyHelper.cs b/TSTSSESCores/Data/Scripts/Scripts/Shared/EconomyHelper.cs
new file mode 100644
index 00000000..764c3fcb
--- /dev/null
+++ b/TSTSSESCores/Data/Scripts/Scripts/Shared/EconomyHelper.cs
@@ -0,0 +1,96 @@
+using System.Collections.Generic;
+using Sandbox.Definitions;
+using VRage.Game;
+using VRage.Game.ModAPI;
+using VRage.ObjectBuilders;
+
+namespace MIG.Shared.SE {
+ public static class EconomyHelper {
+ public static MyObjectBuilderType COMPONENT = MyObjectBuilderType.Parse("MyObjectBuilder_Component");
+ public static MyObjectBuilderType INGOT = MyObjectBuilderType.Parse("MyObjectBuilder_Ingot");
+ public static MyObjectBuilderType ORE = MyObjectBuilderType.Parse("MyObjectBuilder_Ore");
+ public static MyDefinitionId ASSEMBLER_TIME = new MyDefinitionId(ORE, "AssemblerTime");
+ public static MyDefinitionId REFINERY_TIME = new MyDefinitionId(ORE , "RefineryTime");
+ public static MyDefinitionId WORTH = new MyDefinitionId(ORE, "Money");
+ public static MyDefinitionId WORTH_OK = new MyDefinitionId(ORE, "MoneyOk");
+
+
+ public static long changeMoney (this IMyPlayer pl, double perc, long amount = 0) {
+ long bal;
+ if (pl.TryGetBalanceInfo (out bal)) {
+ var fee = (long)(bal * perc + amount);
+ var take = fee - bal > 0? bal : fee;
+ pl.RequestChangeBalance (fee);
+ return fee;
+ }
+ return 0;
+ }
+
+ public static long changeMoney (this IMyFaction pl, double perc, long amount = 0) {
+ long bal;
+ if (pl.TryGetBalanceInfo (out bal)) {
+ var fee = (long)(bal * perc + amount) ;
+ var take = fee - bal > 0? bal : fee;
+ pl.RequestChangeBalance (take);
+ return take;
+ }
+ return 0;
+ }
+
+
+
+
+ private static void FormWorth(Dictionary> dict, MyBlueprintDefinitionBase b, Dictionary mapper, bool isRef, MyBlueprintDefinitionBase.Item result)
+ {
+ var from = isRef ? b.Results: b.Results;
+ var to = isRef ? b.Prerequisites : b.Prerequisites;
+ var time = isRef ? REFINERY_TIME : ASSEMBLER_TIME;
+
+ var key = result.Id;
+ var am = result.Amount;
+ var d = new Dictionary();
+
+ if (result.Id.SubtypeName.Contains("Scrap")) return;
+
+ double w;
+ var money = 0.0;
+ var hasAllMappings = true;
+
+ foreach (var y in to)
+ {
+ if (y.Id.SubtypeName.Contains("Scrap")) return;
+ w = (double)y.Amount / (double)am;
+ d[y.Id] = w;// * assemblerMutliplier;
+
+ if (mapper.ContainsKey(y.Id))
+ {
+ money += mapper[y.Id] * w;
+ }
+ else
+ {
+ hasAllMappings = false;
+ }
+ }
+
+ w = b.BaseProductionTimeInSeconds / (double)am;
+ d[time] = w;
+
+ if (hasAllMappings && mapper.ContainsKey(time))
+ {
+ money += w * mapper[time];
+ }
+ else
+ {
+ hasAllMappings = false;
+ }
+
+ d[WORTH] = money;
+ if (hasAllMappings)
+ {
+ d[WORTH_OK] = 1;
+ }
+
+ dict[key] = d;
+ }
+ }
+}
diff --git a/TSTSSESCores/Data/Scripts/Scripts/Shared/Ext.cs b/TSTSSESCores/Data/Scripts/Scripts/Shared/Ext.cs
new file mode 100644
index 00000000..6f82b704
--- /dev/null
+++ b/TSTSSESCores/Data/Scripts/Scripts/Shared/Ext.cs
@@ -0,0 +1,113 @@
+using Sandbox.Common.ObjectBuilders;
+using Sandbox.Definitions;
+using Sandbox.Game.Entities;
+using System;
+using System.Collections.Generic;
+using MIG.SpecCores;
+using VRage.Game;
+using VRage.Game.ModAPI;
+using VRageMath;
+
+namespace MIG.Shared.SE {
+ public static class Ext {
+ public static T FindAndMove (this List list, int newPos, Func x) {
+ var ind = list.FindIndex ((y) => x.Invoke(y));
+ if (ind != -1) {
+ var tt = list[ind];
+ list.Move (ind, newPos);
+ return tt;
+ } else { return default(T); }
+ }
+
+ public static void FindAndMoveAll (this List list, int newPos, Func x) {
+ var ind = list.FindIndex ((y) => x.Invoke(y));
+ var ind2 = list.FindLastIndex((y) => x.Invoke(y));
+
+
+ if (ind != -1 && ind2 != -1) {
+ var tt = list[ind];
+
+ var pos = 0;
+ for (var i = ind; i<=ind2; i++)
+ {
+ list.Move (i, newPos+pos);
+ pos++;
+ }
+ }
+ }
+
+ public static Ship GetShip(this IMyCubeGrid grid) {
+ var x = OriginalSpecCoreSession.Instance.gridToShip;
+ if (x.ContainsKey(grid.EntityId)) return x[grid.EntityId];
+ else return null;
+ }
+
+
+ public static Dictionary GetBlockPrice (this IMySlimBlock slim, Dictionary dict = null) {
+ if (dict == null) dict = new Dictionary();
+
+ var cmps = (slim.BlockDefinition as MyCubeBlockDefinition).Components;
+
+ foreach (var xx in cmps) {
+ var id = xx.Definition.Id;
+ var c = xx.Count;
+ if (dict.ContainsKey(id)) {
+ dict[id] += c;
+ } else {
+ dict.Add (id, c);
+ }
+ }
+
+ return dict;
+ }
+
+ public static Dictionary GetBlockLeftNeededComponents (this IMySlimBlock slim, Dictionary dict = null, Dictionary temp = null) {
+ if (dict == null) dict = new Dictionary();
+
+ var cmps = (slim.BlockDefinition as MyCubeBlockDefinition).Components;
+
+ temp.Clear();
+ foreach (var xx in cmps) {
+ var id = xx.Definition.Id;
+ var c = xx.Count;
+ if (temp.ContainsKey(id)) {
+ temp[id] += c;
+ } else {
+ temp.Add (id, c);
+ }
+ }
+
+ foreach (var x in temp) {
+ var id = x.Key;
+ var has = slim.GetConstructionStockpileItemAmount (id);
+ var need = x.Value;
+ var left = need - has;
+ if (left > 0) {
+ if (dict.ContainsKey(id)) {
+ dict[id] += left;
+ } else {
+ dict.Add (id, left);
+ }
+ }
+ }
+
+ return dict;
+ }
+
+ public static Vector3D GetWorldPosition (this IMySlimBlock block) {
+ var box = new BoundingBoxD ();
+ block.GetWorldBoundingBox(out box);
+ return box.Center;
+ }
+
+ public static bool Contains (this MySafeZone __instance, Vector3 point) {
+ if (__instance.Shape == MySafeZoneShape.Sphere) {
+ BoundingSphereD boundingSphereD = new BoundingSphereD(__instance.PositionComp.GetPosition(), (double)__instance.Radius);
+ return boundingSphereD.Contains(point) == ContainmentType.Contains;
+ } else {
+ MyOrientedBoundingBoxD myOrientedBoundingBoxD = new MyOrientedBoundingBoxD(__instance.PositionComp.LocalAABB, __instance.PositionComp.WorldMatrix);
+ return myOrientedBoundingBoxD.Contains(ref point);
+ }
+ }
+ }
+}
diff --git a/TSTSSESCores/Data/Scripts/Scripts/Shared/FrameExecutor.cs b/TSTSSESCores/Data/Scripts/Scripts/Shared/FrameExecutor.cs
new file mode 100644
index 00000000..d19ddc8c
--- /dev/null
+++ b/TSTSSESCores/Data/Scripts/Scripts/Shared/FrameExecutor.cs
@@ -0,0 +1,163 @@
+using System;
+using System.Collections.Generic;
+using Digi;
+using MIG.Shared.CSharp;
+using VRage.ModAPI;
+
+namespace MIG.Shared.SE {
+ public static class FrameExecutor {
+ private static int frame = 0;
+ public static int currentFrame { get { return frame; } }
+
+ private static readonly List> onEachFrameLogic = new List>();
+ private static readonly List> addOnEachFrameLogic = new List>();
+ private static readonly List> removeOnEachFrameLogic = new List>();
+ private static bool needRemoveFrameLogic = false;
+
+ public static void Update() {
+ try {
+ foreach (var x in onEachFrameLogic) {
+ x.run(frame);
+ }
+
+ onEachFrameLogic.AddList(addOnEachFrameLogic);
+ foreach (var x in removeOnEachFrameLogic)
+ {
+ onEachFrameLogic.Remove(x);
+ }
+ addOnEachFrameLogic.Clear();
+ removeOnEachFrameLogic.Clear();
+ frame++;
+ } catch (Exception e) {
+ Log.ChatError("FrameExecutor", e);
+ }
+ }
+
+ public static void addFrameLogic(Action1 action) {
+ addOnEachFrameLogic.Add(action);
+ }
+
+ public static ActionWrapper addFrameLogic(Action action) {
+ ActionWrapper wrapper = new ActionWrapper(action);
+ addOnEachFrameLogic.Add(wrapper);
+ return wrapper;
+ }
+
+ public static BlockWrapperAction addFrameLogic(Timer timer, IMyEntity entity, Action action)
+ {
+ return addFrameLogic(timer, entity, new ActionWrapper(action));
+ }
+
+ public static BlockWrapperAction addFrameLogic(Timer timer, IMyEntity entity, Action1 action)
+ {
+ if (entity == null)
+ {
+ Log.ChatError("addFrameLogic:Entity is null");
+ return new BlockWrapperAction(entity, timer, action);
+ }
+ BlockWrapperAction wrapper = new BlockWrapperAction(entity, timer, action);
+ addOnEachFrameLogic.Add(wrapper);
+ return wrapper;
+ }
+
+ public static void removeFrameLogic(Action1 action) {
+ removeOnEachFrameLogic.Add(action);
+ }
+
+ public static void addDelayedLogic(long frames, Action1 action) {
+ addOnEachFrameLogic.Add(new DelayerAction(frames, action));
+ }
+
+ public static DelayerAction addDelayedLogic(long frames, Action action)
+ {
+ var da = new DelayerAction(frames, new ActionWrapper(action));
+ addOnEachFrameLogic.Add(da);
+ return da;
+ }
+
+ public class ActionWrapper : Action1
+ {
+ Action action;
+ public ActionWrapper (Action action)
+ {
+ this.action = action;
+ }
+
+ public void run(long t)
+ {
+ action(t);
+ }
+
+ public void Unsub()
+ {
+ FrameExecutor.removeFrameLogic(this);
+ }
+ }
+
+
+ public class BlockWrapperAction : Action1 {
+ private Timer timer;
+ private Action1 action;
+ private IMyEntity entity;
+ public BlockWrapperAction(IMyEntity entity, Timer timer, Action1 action) {
+ this.timer = timer;
+ this.action = action;
+ this.entity = entity;
+ if (entity == null)
+ {
+
+ }
+ }
+
+ public void Cancel()
+ {
+ FrameExecutor.removeFrameLogic(this);
+ }
+
+ public void RunNow()
+ {
+ action.run(-1);
+ }
+
+ public void run(long k) {
+ if (timer.tick())
+ {
+ if (entity.MarkedForClose || entity.Closed)
+ {
+ Cancel();
+ return;
+ }
+ action.run(k);
+ }
+ }
+ }
+
+
+ public class DelayerAction : Action1 {
+ private long timer;
+ private Action1 action;
+ public DelayerAction(long timer, Action1 action) {
+ this.timer = timer;
+ this.action = action;
+ }
+
+ public void Cancel()
+ {
+ FrameExecutor.removeFrameLogic(this);
+ }
+
+ public void RunNow()
+ {
+ action.run(-1);
+ }
+
+ public void run(long k) {
+ if (timer > 0) {
+ timer--; return;
+ }
+ FrameExecutor.removeFrameLogic(this);
+ action.run(k);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/TSTSSESCores/Data/Scripts/Scripts/Shared/FreezableTimerLogic.cs b/TSTSSESCores/Data/Scripts/Scripts/Shared/FreezableTimerLogic.cs
new file mode 100644
index 00000000..af57453e
--- /dev/null
+++ b/TSTSSESCores/Data/Scripts/Scripts/Shared/FreezableTimerLogic.cs
@@ -0,0 +1,73 @@
+using System;
+using MIG.Shared.CSharp;
+using ProtoBuf;
+using VRage.ModAPI;
+
+namespace MIG.Shared.SE
+{
+ public class FreezableTimerLogic
+ {
+ private Wrapper SettingsWrapper;
+ private Action TickAction;
+ private IMyEntity Entity;
+ private Guid Guid;
+ private long MinimalMsToTrigger;
+
+ private long LastRun
+ {
+ get { return SettingsWrapper.LastRun; }
+ set { SettingsWrapper.LastRun = value; }
+ }
+
+ //public T Settings {
+ // get { return SettingsWrapper.Settings; }
+ // set { SettingsWrapper.Settings = value; }
+ //}
+
+ public void Init(Guid guid, IMyEntity entity, Action tick, Func getDefaultSettings, long minimalMsToTrigger = 1000, bool stopAtStart = false)
+ {
+ Guid = guid;
+ Entity = entity;
+ TickAction = tick;
+ MinimalMsToTrigger = minimalMsToTrigger;
+ if (!Entity.TryGetStorageData(guid, out SettingsWrapper, protoBuf:true))
+ {
+ SettingsWrapper = new Wrapper();
+ //SettingsWrapper.Settings = getDefaultSettings();
+ LastRun = stopAtStart ? -1 : SharpUtils.msTimeStamp();
+ }
+
+ }
+
+ public void Tick()
+ {
+ if (LastRun < 0)
+ {
+ return;
+ }
+ var dx = (SharpUtils.msTimeStamp() - LastRun) / MinimalMsToTrigger;
+ if (dx < 0) return;
+ TickAction((int) dx);
+ LastRun += MinimalMsToTrigger * dx;
+ Save();
+ }
+
+ public void Stop() { if (LastRun != -1) { LastRun = -1; Save(); } }
+
+ public void Start(int extraTime) { LastRun = SharpUtils.msTimeStamp() - extraTime; Save(); }
+
+ public void AddTime(int time) { LastRun -= time; Save(); }
+
+ private void Save() { Entity.SetStorageData(Guid, SettingsWrapper, protoBuf:true); }
+
+ [ProtoContract]
+ private class Wrapper
+ {
+ [ProtoMember(1)]
+ public long LastRun;
+
+ [ProtoMember(2)]
+ public T Settings;
+ }
+ }
+}
\ No newline at end of file
diff --git a/TSTSSESCores/Data/Scripts/Scripts/Shared/GameLogicWithSyncAndSettings.cs b/TSTSSESCores/Data/Scripts/Scripts/Shared/GameLogicWithSyncAndSettings.cs
new file mode 100644
index 00000000..c9b21902
--- /dev/null
+++ b/TSTSSESCores/Data/Scripts/Scripts/Shared/GameLogicWithSyncAndSettings.cs
@@ -0,0 +1,286 @@
+using Sandbox.ModAPI;
+using System;
+using System.Collections.Generic;
+using VRage.Game.Components;
+using VRage.ObjectBuilders;
+using VRage.ModAPI;
+using Sandbox.Game.EntityComponents;
+using Digi;
+
+namespace MIG.Shared.SE
+{
+ /*[ProtoContract]
+ public class TestSettings
+ {
+ [ProtoMember(1)]
+ public float CurrentThrust;
+ }
+
+ public class TestBlockSettings
+ {
+ public float FlameLength;
+ public float MaxThrust;
+ }
+
+
+ public class TestGameLogic : GameLogicWithSyncAndSettings
+ {
+ private static Guid GUID = new Guid();
+ private static Sync sync;
+
+ public override TestSettings GetDefaultSettings() { return new TestSettings { CurrentThrust = 0f }; }
+ public override Guid GetGuid() { return GUID; }
+ public override Sync GetSync() { return sync; }
+ public override TestBlockSettings InitBlockSettings() {
+ return new TestBlockSettings() { FlameLength = 5f };
+ }
+
+ public static void Init ()
+ {
+ sync = new Sync(53334, (x)=>x.Settings, Handler);
+ }
+
+ protected override void OnSettingsChanged()
+ {
+
+ }
+
+ public override void ApplyDataFromClient(TestSettings arrivedSettings)
+ {
+ Settings.CurrentThrust = MathHelper.Clamp(arrivedSettings.CurrentThrust, 0, BlockSettings.MaxThrust);
+ }
+ }*/
+
+ public abstract class GameLogicWithSyncAndSettings : MyGameLogicComponent where FinalClass : GameLogicWithSyncAndSettings
+ {
+ ///
+ /// Get guid, that belongs to this type of gamelogic. Must be STATIC and UNIQ per each nested class
+ ///
+ ///
+ protected abstract Guid GetGuid();
+
+ ///
+ /// Get sync, that belongs to this type of gamelogic. Must be STATIC and UNIQ per each nested class
+ ///
+ ///
+ protected abstract Sync GetSync();
+
+ ///
+ /// Called, when data arrives on server from clients.
+ /// You must apply changes to gameLogic.Settings
+ ///
+ /// Data that arrived from client
+ protected abstract void ApplyDataFromClient (DynamicSettings arrivedSettings,ulong userSteamId, byte type);
+
+
+ ///
+ /// If new block placed, what settings it will have?
+ ///
+ ///
+ protected abstract DynamicSettings GetDefaultSettings();
+
+ ///
+ /// When block placed, we should define here static setting.
+ ///
+ ///
+ protected abstract StaticSettings InitBlockSettings();
+
+ ///
+ /// Data that is automaticly transfered between client and server. It is also stored in settings.
+ ///
+ public DynamicSettings Settings;
+
+ ///
+ /// Data that is not changed at all. It is somthing like SBC values
+ ///
+ public StaticSettings BlockSettings;
+
+ ///
+ /// Called when settings were changed
+ ///
+ protected virtual void OnSettingsChanged() { }
+
+ ///
+ /// Called when settings are loaded
+ ///
+ protected virtual void OnInitedSettings() { }
+
+ ///
+ /// Called once per blockClass. Here you init controls for your block gui
+ ///
+ protected virtual void InitControls() { }
+
+ ///
+ /// Called once in first UpdateBeforeFrame
+ ///
+ protected virtual void OnceInitBeforeFrame () { }
+
+ private static readonly HashSet InitedControls = new HashSet();
+
+ IMyEntity myEntity;
+
+ public override void Init(MyObjectBuilder_EntityBase objectBuilder)
+ {
+ base.Init(objectBuilder);
+ LoadSettings();
+ BlockSettings = InitBlockSettings();
+
+ if (!MyAPIGateway.Session.IsServer)
+ {
+ GetSync().RequestData(Entity.EntityId);
+ }
+
+ OnInitedSettings();
+
+ //Init controls once;
+ bool needInit = false;
+ lock (InitedControls)
+ {
+ needInit = InitedControls.Add(GetType());
+ }
+
+ if (needInit)
+ {
+ InitControls();
+ }
+ }
+
+ public override MyObjectBuilder_EntityBase GetObjectBuilder(bool copy = false)
+ {
+ SaveSettings(true);
+ return base.GetObjectBuilder(copy);
+ }
+
+
+ public static void Handler (FinalClass block, DynamicSettings settings, byte type,ulong userSteamId, bool isFromServer)
+ {
+ var tt = (GameLogicWithSyncAndSettings)block;
+
+ if (isFromServer && !MyAPIGateway.Session.IsServer)
+ {
+ tt.Settings = settings;
+ tt.OnSettingsChanged();
+ }
+ else
+ {
+ tt.ApplyDataFromClient(settings, userSteamId, type);
+ tt.NotifyAndSave();
+ tt.OnSettingsChanged();
+ }
+ }
+
+ #region Init Settings
+
+ ///
+ /// Must be called on client side, in Gui elements, or on Server side where data from client is arrived;
+ ///
+ protected void NotifyAndSave(byte type=255, bool forceSave = false)
+ {
+ try
+ {
+ if (MyAPIGateway.Session.IsServer)
+ {
+ //Log.ChatError($"NotifyFromServer:[{type}][{Settings}]");
+ GetSync().SendMessageToOthers(Entity.EntityId, Settings, type: type);
+ SaveSettings(forceSave);
+
+ if (!MyAPIGateway.Session.isTorchServer())
+ {
+ ApplyDataFromClient(Settings, MyAPIGateway.Session.LocalHumanPlayer.SteamUserId, type);
+ OnSettingsChanged();
+ }
+ }
+ else
+ {
+ var sync = GetSync();
+ if (sync != null)
+ {
+ //Log.ChatError($"NotifyFromClient:[{type}][{Settings}]");
+ sync.SendMessageToServer(Entity.EntityId, Settings, type: type);
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ Log.ChatError($"NotifyAndSave {type} Exception {ex} {ex.StackTrace}");
+ }
+ }
+
+ ///
+ /// Must be called on client side, in Gui elements, or on Server side where data from client is arrived;
+ ///
+ protected void Notify(DynamicSettings data, byte type = 255)
+ {
+ try
+ {
+ var sync = GetSync();
+ if (sync != null)
+ {
+ //Log.ChatError($"NotifyFromClient:[{type}][{data}]");
+ sync.SendMessageToServer(Entity.EntityId, data, type: type);
+ }
+ }
+ catch (Exception ex)
+ {
+ Log.ChatError("NotifyAndSave Exception " + ex.ToString() + ex.StackTrace);
+ }
+ }
+
+ public override void OnAddedToContainer()
+ {
+ base.OnAddedToContainer();
+ if (Entity.Storage == null)
+ {
+ Entity.Storage = new MyModStorageComponent();
+ }
+ }
+
+ private void LoadSettings()
+ {
+ if (!Entity.TryGetStorageData(GetGuid(), out Settings))
+ {
+ Settings = GetDefaultSettings();
+ SaveSettings();
+ }
+ }
+
+ private bool m_settingsDirty;
+ protected void SaveSettings(bool forceSave = false)
+ {
+ m_settingsDirty = true;
+ forceSave = true; //TODO: currently GetObjectBuilder is not called
+ if (MyAPIGateway.Session.IsServer)
+ {
+ if (forceSave)
+ {
+ if (m_settingsDirty)
+ {
+ Entity.SetStorageData(GetGuid(), Settings);
+ m_settingsDirty = false;
+ }
+ }
+ else
+ {
+ m_settingsDirty = true;
+ }
+ }
+ }
+
+
+
+ #endregion
+
+
+
+ private bool m_firstUpdate = true;
+ public override void UpdateOnceBeforeFrame()
+ {
+ base.UpdateOnceBeforeFrame();
+
+ if (m_firstUpdate) {
+ m_firstUpdate = false;
+ OnceInitBeforeFrame();
+ }
+ }
+ }
+}
diff --git a/TSTSSESCores/Data/Scripts/Scripts/Shared/Getter.cs b/TSTSSESCores/Data/Scripts/Scripts/Shared/Getter.cs
new file mode 100644
index 00000000..a12cc257
--- /dev/null
+++ b/TSTSSESCores/Data/Scripts/Scripts/Shared/Getter.cs
@@ -0,0 +1,14 @@
+namespace MIG.Shared.SE
+{
+ public interface Getter {
+ T Get();
+ }
+
+ public class FixedGetter : Getter {
+ T t;
+ public FixedGetter(T t) {
+ this.t = t;
+ }
+ public T Get() { return t; }
+ }
+}
\ No newline at end of file
diff --git a/TSTSSESCores/Data/Scripts/Scripts/Shared/Gps.cs b/TSTSSESCores/Data/Scripts/Scripts/Shared/Gps.cs
new file mode 100644
index 00000000..5f274db4
--- /dev/null
+++ b/TSTSSESCores/Data/Scripts/Scripts/Shared/Gps.cs
@@ -0,0 +1,68 @@
+using Digi;
+using Sandbox.ModAPI;
+using System;
+using System.Collections.Generic;
+using VRage.Game.ModAPI;
+using VRageMath;
+
+namespace MIG.Shared.CSharp {
+ public static class Gps {
+ public static void AddGps(string name, string description, Vector3D position) {
+ IMyGps gps = MyAPIGateway.Session.GPS.Create(name, description, position, true, true);
+ MyAPIGateway.Session.GPS.AddLocalGps(gps);
+ }
+
+ public static void AddGpsColored(string name, string description, Vector3D position, Vector3D color)
+ {
+ IMyGps gps = MyAPIGateway.Session.GPS.Create(name, description, position, true, true);
+ gps.GPSColor = new Color(color);
+ MyAPIGateway.Session.GPS.AddLocalGps(gps);
+ }
+
+ public static void RemoveWithDescription (string startsWith) {
+ if (MyAPIGateway.Session == null) return;
+ if (MyAPIGateway.Session.Player == null) return;
+
+ try {
+ List list = MyAPIGateway.Session.GPS.GetGpsList(MyAPIGateway.Session.Player.PlayerID);
+ foreach (var item in list) {
+ if (item.Description != null && item.Description.StartsWith(startsWith)) {
+ MyAPIGateway.Session.GPS.RemoveLocalGps(item);
+ }
+ }
+ } catch (Exception ex) {
+ Log.Error(ex, "RemoveSavedGPS()");
+ }
+ }
+
+ public static IMyGps RemoveWithDescription(string startsWith, long player, bool all = true)
+ {
+ IMyGps gps = null;
+ List list = MyAPIGateway.Session.GPS.GetGpsList(player);
+ foreach (var item in list)
+ {
+ if (item.Description != null && item.Description.StartsWith(startsWith))
+ {
+ gps = item;
+ MyAPIGateway.Session.GPS.RemoveGps(player, item);
+ if (!all) return gps;
+ }
+ }
+
+ return gps;
+ }
+
+ public static IMyGps GetWithDescription(string startsWith, long player)
+ {
+ List list = MyAPIGateway.Session.GPS.GetGpsList(player);
+ foreach (var item in list)
+ {
+ if (item.Description != null && item.Description.StartsWith(startsWith))
+ {
+ return item;
+ }
+ }
+ return null;
+ }
+ }
+}
diff --git a/TSTSSESCores/Data/Scripts/Scripts/Shared/GridAndBlocks.cs b/TSTSSESCores/Data/Scripts/Scripts/Shared/GridAndBlocks.cs
new file mode 100644
index 00000000..61f070cd
--- /dev/null
+++ b/TSTSSESCores/Data/Scripts/Scripts/Shared/GridAndBlocks.cs
@@ -0,0 +1,167 @@
+using System;
+using System.Collections.Generic;
+using Sandbox.ModAPI;
+using VRage.Game.ModAPI;
+using Sandbox.Definitions;
+
+namespace MIG.Shared.SE {
+ static class GridAndBlocks {
+ public static void GetRefinerySpeedAndYield(this IMyRefinery rf, out double speed, out double yield, out double power, out double ingotsPerSec) {
+ var def = (rf.SlimBlock.BlockDefinition as MyRefineryDefinition);
+ speed = (1+rf.UpgradeValues["Productivity"]) * def.RefineSpeed;
+ yield = rf.UpgradeValues["Effectiveness"] * def.MaterialEfficiency;
+ power = rf.UpgradeValues["PowerEfficiency"];
+ ingotsPerSec = speed * yield;
+ }
+
+ public static void GetAssemblerSpeedAndPower(this IMyAssembler rf, out double speed, out double power) {
+ var def = (rf.SlimBlock.BlockDefinition as MyAssemblerDefinition);
+ speed = (1+rf.UpgradeValues["Productivity"]) * def.AssemblySpeed;
+ power = rf.UpgradeValues["PowerEfficiency"];
+ }
+
+
+
+ public static bool checkSubtypeName(this IMySlimBlock x, string[] startsWith = null, string[] exactNames = null, bool onlyFunctional = false) {
+ var bd = x.BlockDefinition;
+ if (bd == null || bd.Id == null || bd.Id.SubtypeName == null) return false;
+
+ var t = bd.Id.SubtypeName;
+
+ if (onlyFunctional) {
+ if (!x.FatBlock.IsFunctional) {
+ return false;
+ }
+ }
+
+ if (startsWith != null) {
+ foreach (var y in startsWith) {
+ if (t.StartsWith(y)) return true;
+ }
+ }
+ if (exactNames != null) {
+ foreach (var z in exactNames) {
+ if (z.Equals(t)) return true;
+ }
+ }
+ return false;
+ }
+
+ public static List GetBlocksBySubtypeName(this IMyCubeGrid g, List blocks, string[] startsWith = null, string[] exactNames = null, bool onlyFunctional = false, bool inAllGrids = false) {
+ if (blocks == null) blocks = new List();
+
+ g.GetBlocks(blocks, x => checkSubtypeName(x, startsWith, exactNames, onlyFunctional));
+
+ if (inAllGrids) {
+ var connectedGrids = MyAPIGateway.GridGroups.GetGroup(g, GridLinkTypeEnum.Physical);
+ foreach (var y in connectedGrids) {
+ y.GetBlocks(blocks, x => checkSubtypeName(x, startsWith, exactNames, onlyFunctional));
+ }
+ }
+
+ return blocks;
+ }
+
+
+ public static T FindBlock(this IMyCubeGrid y) {
+ var blocks = new List();
+ y.GetBlocks(blocks);
+
+ foreach (var x in blocks) {
+ if (x.FatBlock == null) {
+ //Log.Info("Find Block failed:" + x.GetType().Name + " " + x);
+ continue;
+ }
+ if (x.FatBlock is T) {
+ return (T)(x.FatBlock);
+ } else {
+ //Log.Info("Find Block failed:" + x.GetType().Name + " " + x.FatBlock.GetType().Name);
+ }
+ }
+
+ return default(T);
+ }
+
+
+ public static ICollection FindBlocks(this IMyCubeGrid y, ICollection ret, Func filter) {
+ var blocks = new List();
+ y.GetBlocks(blocks);
+ foreach (var x in blocks) {
+ if (filter(x)) ret.Add((T)x.FatBlock);
+ }
+
+ return ret;
+ }
+
+ public static void FindBlocks (this IMyCubeGrid y, Action filter) {
+ var blocks = new List();
+ y.GetBlocks(blocks);
+ foreach (var x in blocks) {
+ filter.Invoke(x);
+ }
+ }
+
+ public static ICollection FindBlocks(this IMyCubeGrid y, ICollection ret) {
+ return y.FindBlocks(ret, x => {
+ var fat = x.FatBlock;
+ if (fat == null) return false;
+ return fat is T;
+ });
+ }
+
+ public static List FindBlocks(this IMyCubeGrid y, Func filter) {
+ var blocks = new List();
+ var ret = new List();
+ y.GetBlocks(blocks);
+ foreach (var x in blocks) {
+ if (filter(x)) ret.Add(x);
+ }
+
+ return ret;
+ }
+
+ public static List FindBlocksOfType(this IMyCubeGrid y) where T : IMyCubeBlock
+ {
+ var ret = new List();
+ var blocks = new List();
+ y.GetBlocks(blocks);
+
+ foreach (var x in blocks)
+ {
+ var fat = x.FatBlock;
+ if (fat == null) continue;
+ if (!(fat is T)) continue;
+
+ ret.Add((T)fat);
+ }
+
+ return ret;
+ }
+
+
+ public static T FindBlock(this IMyCubeGrid y, string name) where T : IMyTerminalBlock {
+ var blocks = new List();
+ y.GetBlocks(blocks);
+
+ foreach (var x in blocks) {
+ var fat = x.FatBlock;
+ if (fat == null) continue;
+ if (!(fat is T)) continue;
+ var f = (T)fat;
+ if (f.CustomName.Equals(name)) return (T)(x.FatBlock);
+ }
+
+ return default(T);
+ }
+
+ public static IMySlimBlock FindBlock(this IMyCubeGrid y, Func filter) {
+ var blocks = new List();
+ y.GetBlocks(blocks);
+ foreach (var x in blocks) {
+ if (filter(x)) return x;
+ }
+
+ return null;
+ }
+ }
+}
diff --git a/TSTSSESCores/Data/Scripts/Scripts/Shared/GuiControlDuplicateRemover.cs b/TSTSSESCores/Data/Scripts/Scripts/Shared/GuiControlDuplicateRemover.cs
new file mode 100644
index 00000000..353005d6
--- /dev/null
+++ b/TSTSSESCores/Data/Scripts/Scripts/Shared/GuiControlDuplicateRemover.cs
@@ -0,0 +1,39 @@
+using System.Collections.Generic;
+using Sandbox.ModAPI;
+using Sandbox.ModAPI.Interfaces.Terminal;
+
+namespace Scripts.Shared
+{
+ public static class GuiControlDuplicateRemover
+ {
+ private static string[] duplicates;
+ public static void Init(params string[] dups)
+ {
+ duplicates = dups;
+ MyAPIGateway.TerminalControls.CustomControlGetter += TerminalControlsOnCustomControlGetter;
+ }
+
+ private static void TerminalControlsOnCustomControlGetter(IMyTerminalBlock block, List controls)
+ {
+ HashSet exists = new HashSet();
+ for (var index = 0; index < controls.Count; index++)
+ {
+ var action = controls[index];
+ if (exists.Contains(action.Id))
+ {
+ controls.RemoveAt(index);
+ index--;
+ continue;
+ }
+
+ foreach (var dup in duplicates)
+ {
+ if (action.Id.Contains(dup))
+ {
+ exists.Add(action.Id);
+ }
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/TSTSSESCores/Data/Scripts/Scripts/Shared/GuiHelper.cs b/TSTSSESCores/Data/Scripts/Scripts/Shared/GuiHelper.cs
new file mode 100644
index 00000000..536e9c78
--- /dev/null
+++ b/TSTSSESCores/Data/Scripts/Scripts/Shared/GuiHelper.cs
@@ -0,0 +1,251 @@
+using Sandbox.ModAPI;
+using Sandbox.ModAPI.Interfaces.Terminal;
+using System;
+using System.Collections.Generic;
+using System.Text;
+using MIG.Shared.CSharp;
+using VRage.Utils;
+using VRageMath;
+
+namespace MIG.Shared.SE
+{
+ public static class GuiHelper
+ {
+
+ public static long DoubleClickTimer = 0;
+
+ public static void DoubleClick(ref long timer, Action action)
+ {
+ var now = SharpUtils.msTimeStamp();
+ if (now - timer > 500)
+ {
+ timer = now;
+ }
+ else
+ {
+ action();
+ DoubleClickTimer += 1000;
+ }
+ }
+
+ public static void DoubleClick(this IMyTerminalControlButton button)
+ {
+ var action = button.Action;
+ button.Action = (xx) =>
+ {
+ DoubleClick(ref DoubleClickTimer, () => action(xx));
+ };
+ }
+
+ public static IMyTerminalControlSlider CreateSlider (this IMyTerminalControls system, string id, string name, string tooltip, float min, float max,
+ Func getter, Action writer, Action setter, Func getterT, Func enabled= null, Func visible = null, bool update = false)
+ {
+ var XControl = system.CreateControl(typeof(T).Name+ "_" + id);
+ XControl.Title = MyStringId.GetOrCompute(name);
+ XControl.Tooltip = MyStringId.GetOrCompute(tooltip);
+ XControl.SetLimits(min, max);
+ XControl.Enabled = IsEnabled(enabled, getterT);
+ XControl.Visible = IsVisible (visible, getterT);
+
+
+ XControl.Getter = (b) => getter(getterT (b));
+ XControl.Writer = (b, t) => writer(getterT (b), t);
+ XControl.Setter = (b, v) =>
+ {
+ setter(getterT (b), v);
+ if (update) XControl.UpdateVisual();
+ };
+
+ XControl.Enabled = XControl.Enabled.TryCatch(name + " Enabled");
+ XControl.Visible = XControl.Visible.TryCatch(name + " Visible");
+ XControl.Getter = XControl.Getter.TryCatch(name + " Getter");
+ XControl.Setter = XControl.Setter.TryCatch(name + " Setter");
+ XControl.Writer = XControl.Writer.TryCatch(name + " Writer");
+
+ system.AddControl(XControl);
+
+ return XControl;
+ }
+
+ public static IMyTerminalControlLabel CreateLabel(this IMyTerminalControls system, string id, MyStringId text)
+ {
+ var control = system.CreateControl(typeof(T).Name+ "_" + id);
+ control.Label = text;
+ MyAPIGateway.TerminalControls.AddControl(control);
+ return control;
+ }
+
+
+
+ public static IMyTerminalControlButton CreateButton(this IMyTerminalControls system, string id, string name, string tooltip, Action action, Func getterT, Func enabled = null, Func visible = null)
+ {
+ var XControl = system.CreateControl(typeof(T).Name+ "_" + id);
+ XControl.Title = MyStringId.GetOrCompute(name);
+ XControl.Tooltip = MyStringId.GetOrCompute(tooltip);
+ XControl.Enabled = IsEnabled(enabled, getterT);
+ XControl.Visible = IsVisible (visible, getterT);
+ XControl.Action = (b) => action(getterT (b));
+
+ XControl.Enabled = XControl.Enabled.TryCatch(name + " Enabled");
+ XControl.Visible = XControl.Visible.TryCatch(name + " Visible");
+ XControl.Action = XControl.Action.TryCatch(name + " Action");
+
+ system.AddControl(XControl);
+ return XControl;
+ }
+
+ public static IMyTerminalControlColor CreateColorPicker(this IMyTerminalControls system, string id, string name, string tooltip, Func getter, Action setter, Func getterT, Func enabled = null, Func visible = null)
+ {
+ var XControl = system.CreateControl(typeof(T).Name+ "_" + id);
+ XControl.Title = MyStringId.GetOrCompute(name);
+ XControl.Tooltip = MyStringId.GetOrCompute(tooltip);
+ XControl.Enabled = IsEnabled(enabled, getterT);
+ XControl.Visible = IsVisible (visible, getterT);
+ XControl.Getter = (b) => getter(getterT (b));
+ XControl.Setter = (b, v) => setter(getterT (b), v);
+
+ XControl.Enabled = XControl.Enabled.TryCatch(name + " Enabled");
+ XControl.Visible = XControl.Visible.TryCatch(name + " Visible");
+ XControl.Getter = XControl.Getter.TryCatch(name + " Getter");
+ XControl.Setter = XControl.Setter.TryCatch(name + " Setter");
+
+ system.AddControl(XControl);
+
+ return XControl;
+ }
+
+ public static IMyTerminalControlCombobox CreateCombobox(this IMyTerminalControls system, string id, string name, string tooltip, Func getter, Action setter, List texts, Func getterT, Func enabled = null, Func visible=null, bool update = false)
+ {
+ var XControl = system.CreateControl(typeof(T).Name+ "_" + id);
+ XControl.Title = MyStringId.GetOrCompute(name);
+ XControl.Tooltip = MyStringId.GetOrCompute(tooltip);
+
+ XControl.Getter = (b) => getter(getterT (b));
+ XControl.Setter = (b, v) =>
+ {
+ setter(getterT (b), v);
+ if(update) XControl.UpdateVisual();
+ };
+
+ XControl.Enabled = IsEnabled(enabled, getterT);
+ XControl.Visible = IsVisible (visible, getterT);
+
+
+ XControl.ComboBoxContent = (b) =>
+ {
+ var c = 0;
+ foreach (var x in texts) {
+ var i = new VRage.ModAPI.MyTerminalControlComboBoxItem();
+ i.Key = c;
+ i.Value = x;
+ c++;
+ b.Add(i);
+ }
+ };
+ XControl.SupportsMultipleBlocks = true;
+
+ XControl.Enabled = XControl.Enabled.TryCatch(name + " Enabled");
+ XControl.Visible = XControl.Visible.TryCatch(name + " Visible");
+ XControl.Getter = XControl.Getter.TryCatch(name + " Getter");
+ XControl.Setter = XControl.Setter.TryCatch(name + " Setter");
+ XControl.ComboBoxContent = XControl.ComboBoxContent.TryCatch(name+ " ComboBoxContent");
+
+ system.AddControl(XControl);
+
+ return XControl;
+ }
+
+ public static IMyTerminalControlCheckbox CreateCheckbox(this IMyTerminalControls system, string id, string name, string tooltip,
+ Func getter, Action setter, Func getterT = null, Func enabled = null, Func visible = null, bool update = false)
+ {
+ var XControl = system.CreateControl(typeof(T).Name+ "_" + id);
+ XControl.Title = MyStringId.GetOrCompute(name);
+ XControl.Tooltip = MyStringId.GetOrCompute(tooltip);
+
+ XControl.Enabled = IsEnabled(enabled, getterT);
+ XControl.Visible = IsVisible (visible, getterT);
+ XControl.Getter = (b) => getter(getterT (b));
+ XControl.Setter = (b, v) =>
+ {
+ setter(getterT (b), v);
+ if(update) XControl.UpdateVisual();
+ };
+
+ XControl.Enabled = XControl.Enabled.TryCatch(name + " Enabled");
+ XControl.Visible = XControl.Visible.TryCatch(name + " Visible");
+ XControl.Getter = XControl.Getter.TryCatch(name + " Getter");
+ XControl.Setter = XControl.Setter.TryCatch(name + " Setter");
+ system.AddControl(XControl);
+ return XControl;
+ }
+
+ public static IMyTerminalControlOnOffSwitch CreateOnOff(this IMyTerminalControls system, string id, string name, string tooltip,
+ Func getter, Action setter, Func getterT = null, Func enabled = null, Func visible = null, bool update = false)
+ {
+ var XControl = system.CreateControl(typeof(T).Name+ "_" + id);
+ XControl.Title = MyStringId.GetOrCompute(name);
+ XControl.Tooltip = MyStringId.GetOrCompute(tooltip);
+
+ XControl.Enabled = IsEnabled(enabled, getterT);
+ XControl.Visible = IsVisible (visible, getterT);
+ XControl.Getter = (b) => getter(getterT (b));
+ XControl.Setter = (b, v) =>
+ {
+ setter(getterT (b), v);
+ if(update) XControl.UpdateVisual();
+ };
+
+ XControl.Enabled = XControl.Enabled.TryCatch(name + " Enabled");
+ XControl.Visible = XControl.Visible.TryCatch(name + " Visible");
+ XControl.Getter = XControl.Getter.TryCatch(name + " Getter");
+ XControl.Setter = XControl.Setter.TryCatch(name + " Setter");
+ system.AddControl(XControl);
+ return XControl;
+ }
+
+
+ public static IMyTerminalControlTextbox CreateTextbox(this IMyTerminalControls system, string id, string name, string tooltip,
+ Func getter, Action setter, Func getterT = null, Func enabled = null, Func visible = null, bool update = false)
+ {
+ var XControl = system.CreateControl(typeof(T).Name+ "_" + id);
+ XControl.Title = MyStringId.GetOrCompute(name);
+ XControl.Tooltip = MyStringId.GetOrCompute(tooltip);
+ XControl.Enabled = IsEnabled(enabled, getterT);
+ XControl.Visible = IsVisible(visible, getterT);
+ XControl.Getter = (b) => getter(getterT (b));
+ XControl.Setter = (b, v) =>
+ {
+ setter(getterT (b), v);
+ if (update) XControl.UpdateVisual();
+ };
+
+ XControl.Enabled = XControl.Enabled.TryCatch(name + " Enabled");
+ XControl.Visible = XControl.Visible.TryCatch(name + " Visible");
+ XControl.Getter = XControl.Getter.TryCatch(name + " Getter");
+ XControl.Setter = XControl.Setter.TryCatch(name + " Setter");
+
+ system.AddControl(XControl);
+ return XControl;
+ }
+
+ private static Func IsEnabled (Func enabled, Func getterT)
+ {
+ return (b) =>
+ {
+ var bb = getterT(b);
+ if (bb == null) return false;
+ return enabled?.Invoke(bb) ?? true;
+ };
+ }
+
+ private static Func IsVisible (Func isVisible, Func getterT)
+ {
+ return (b) =>
+ {
+ var bb = getterT(b);
+ if (bb == null) return false;
+ return isVisible?.Invoke(bb) ?? true;
+ };
+ }
+ }
+}
diff --git a/TSTSSESCores/Data/Scripts/Scripts/Shared/GuiIniter.cs b/TSTSSESCores/Data/Scripts/Scripts/Shared/GuiIniter.cs
new file mode 100644
index 00000000..0b847887
--- /dev/null
+++ b/TSTSSESCores/Data/Scripts/Scripts/Shared/GuiIniter.cs
@@ -0,0 +1,64 @@
+using System;
+using System.Collections.Generic;
+using Sandbox.ModAPI;
+using VRage.Game.ModAPI;
+
+namespace MIG.SpecCores
+{
+ public abstract class GUIIniter
+ {
+ private readonly HashSet initedGUI = new HashSet();
+ private readonly HashSet initedInterfacesGUI = new HashSet();
+ private List> possibleBlocksToInit = new List>();
+
+ private bool iMyTerminalWasInited = false;
+ protected abstract void InitControls() where T : IMyCubeBlock;
+
+ public void CreateGui(IMyCubeBlock block)
+ {
+ if (block == null) return;
+ var type = block.GetType();
+ if (initedGUI.Contains(type)) return;
+
+ lock (this)
+ {
+ if (initedGUI.Contains(type)) return;
+ initedGUI.Add(type);
+ for (int i = 0; i < possibleBlocksToInit.Count; i++)
+ {
+ var fx = possibleBlocksToInit[i];
+ var added = fx(block);
+ if (added) return;
+ }
+
+ if (!iMyTerminalWasInited)
+ {
+ iMyTerminalWasInited = true;
+ InitControls();
+ }
+ }
+ }
+
+
+ public void AddType() where T: IMyCubeBlock
+ {
+ possibleBlocksToInit.Add(Init);
+ }
+
+ private bool Init(IMyCubeBlock entity) where T : IMyCubeBlock where Z : IMyCubeBlock
+ {
+ if (entity is T)
+ {
+ var added = initedInterfacesGUI.Add(typeof(T));
+ if (added)
+ {
+ InitControls();
+ }
+
+ return true;
+ }
+
+ return false;
+ }
+ }
+}
\ No newline at end of file
diff --git a/TSTSSESCores/Data/Scripts/Scripts/Shared/InventoryUtils.cs b/TSTSSESCores/Data/Scripts/Scripts/Shared/InventoryUtils.cs
new file mode 100644
index 00000000..16bc8f6f
--- /dev/null
+++ b/TSTSSESCores/Data/Scripts/Scripts/Shared/InventoryUtils.cs
@@ -0,0 +1,416 @@
+using System;
+using System.Collections.Generic;
+using Sandbox.Definitions;
+using VRage.Game;
+using VRage;
+using MIG.Shared.SE;
+using Sandbox.ModAPI;
+using Sandbox.Game;
+using VRageMath;
+using VRage.Game.Entity;
+using Sandbox.Game.Entities;
+using VRage.Game.ModAPI;
+using static VRage.Game.ModAPI.Ingame.MyInventoryItemExtension;
+
+//using VRage.Game.ModAPI.Ingame;
+
+namespace ServerMod {
+ static class InventoryUtils {
+
+ // получает все предметы в инвентарях
+ public static void GetInventoryItems(IMyCubeBlock block, Dictionary dictionary, string type = "", string subtypeId = "", bool NamesByClient = false, bool IgnoreGarage = false) {
+ if (block == null || !block.HasInventory) return;
+ if (IgnoreGarage && block.SubtypeName().Contains("Garage")) return;
+
+ for (int i = 0; i < block.InventoryCount; i++)
+ {
+ var inventory = (MyInventory) block.GetInventory(i);
+ var items = inventory.GetItems();
+
+ foreach (var item in items)
+ {
+ var _item = MyDefinitionManager.Static.TryGetPhysicalItemDefinition(item.GetDefinitionId());
+
+ if ((string.IsNullOrWhiteSpace(type) || _item.Id.TypeId.ToString() == type) &&
+ _item.Id.SubtypeName.Contains(subtypeId))
+ {
+ double count = item.Amount.RawValue / 1000000d;
+
+ if (dictionary.ContainsKey(_item)) dictionary[_item] += count;
+ else dictionary.Add(_item, count);
+ }
+ }
+ }
+ }
+
+ public static void GetInventoryItems(IMyCubeBlock block, Dictionary dictionary, string type = "", string subtypeId = "", bool IgnoreGarage = false) {
+ if (block == null || !block.HasInventory) return;
+ if (IgnoreGarage && block.SubtypeName().Contains("Garage")) return;
+
+ for (int i = 0; i < block.InventoryCount; i++)
+ {
+ var inventory = (MyInventory) block.GetInventory(i);
+ var items = inventory.GetItems();
+
+ foreach (var item in items)
+ {
+ var _item = MyDefinitionManager.Static.TryGetPhysicalItemDefinition(item.GetDefinitionId());
+
+ if ((string.IsNullOrWhiteSpace(type) || _item.Id.TypeId.ToString() == type) &&
+ _item.Id.SubtypeName.Contains(subtypeId))
+ {
+ double count = item.Amount.RawValue / 1000000d;
+
+ if (dictionary.ContainsKey(_item)) dictionary[_item] += count;
+ else dictionary.Add(_item, count);
+ }
+ }
+ }
+ }
+
+ // получает текущее компоненты в блоках
+ public static void GetComponents(this IMySlimBlock block, IDictionary dictionary) {
+ var components = (block.BlockDefinition as MyCubeBlockDefinition).Components;
+
+ foreach (var component in components)
+ {
+ var name = component.DeconstructItem;
+ int count = component.Count;
+
+ if (dictionary.ContainsKey(name)) dictionary[name] += count;
+ else dictionary.Add(name, count);
+ }
+
+ var missingComponents = new Dictionary();
+ block.GetMissingComponentsItemsDefinitions(missingComponents);
+
+ foreach (var component in missingComponents)
+ {
+ var item = component.Key;
+ var count = component.Value;
+
+ if (dictionary.ContainsKey(item)) dictionary[item] -= count;
+ else dictionary.Add(item, count);
+ }
+ }
+ public static void GetMissingComponentsItemsDefinitions(this IMySlimBlock block, IDictionary dictionary) {
+
+ var missingComponents = new Dictionary();
+ block.GetMissingComponents(missingComponents);
+
+ foreach (var component in missingComponents) {
+ var item = MyDefinitionManager.Static.TryGetPhysicalItemDefinition(MyDefinitionId.Parse("MyObjectBuilder_Component/" + component.Key));
+ int count = component.Value;
+
+ if (dictionary.ContainsKey(item)) dictionary[item] -= count;
+ else dictionary.Add(item, count);
+ }
+ }
+
+ // получает все компоненты в блоках
+ public static void GetTotalComponents(this IMySlimBlock block, Dictionary dictionary) {
+ var components = (block.BlockDefinition as MyCubeBlockDefinition).Components;
+
+ foreach (var component in components)
+ {
+ var name = component.DeconstructItem;
+
+ int count = component.Count;
+
+ if (dictionary.ContainsKey(name)) dictionary[name] += count;
+ else dictionary.Add(name, count);
+ }
+ }
+
+ public static void GetComponentsTranslation(this IMySlimBlock block, Dictionary dictionary)
+ {
+ var components = (block.BlockDefinition as MyCubeBlockDefinition).Components;
+
+ foreach (var component in components)
+ {
+ var SubtypeName = component.Definition.Id.SubtypeName;
+ var TextName = component.Definition.DisplayNameText;
+
+ if (!dictionary.ContainsKey(SubtypeName)) dictionary.Add(SubtypeName, TextName);
+ }
+
+ }
+
+
+ // получает объем компонентов в блоках
+ public static float GetComponentsVolume(this IMySlimBlock block)
+
+ {
+ float total = 0f;
+ foreach (var component in (block.BlockDefinition as MyCubeBlockDefinition).Components)
+ {
+ total += component.Definition.Volume;
+ }
+ return total;
+ }
+
+
+
+ // получает недостающие компоненты
+ // IMySlimBlock.GetConstructionStockpileItemAmount() работает (работал) некорректно,
+ // поэтому поиск через IMySlimBlock.GetMissingComponents()
+ public static void GetMissingComponents(this IMySlimBlock block, Dictionary dictionary, bool NamesByClient = false)
+ {
+ var missingComponents = new Dictionary();
+ block.GetMissingComponents(missingComponents);
+
+ foreach (var component in missingComponents) {
+ string name = component.Key;
+ int count = component.Value;
+
+ if (dictionary.ContainsKey(name)) dictionary[name] += count;
+ else dictionary.Add(name, count);
+ }
+ }
+
+
+
+ public static void GetAllCargosInRange (ref BoundingSphereD sphere2, List cargos, string blockName, bool allowAssemblers = false, Func filter = null, Func sort = null, int maxTake = Int32.MaxValue) {
+ var data = MyEntities.GetTopMostEntitiesInSphere(ref sphere2);
+ var ships = new HashSet();
+ foreach (var x in data) {
+ var g = x as MyCubeGrid;
+ if (g != null) {
+ ships.Add(g);
+ }
+ }
+ data.Clear();
+
+ var allBlocks = new List();
+ var enters = new List();
+ var sphere3 = sphere2;
+
+ foreach (var x in ships) {
+ x?.OverFatBlocks((b) => {
+ if (!(b is IMyCargoContainer) && !(b is IMyShipConnector) && !(allowAssemblers && b is IMyAssembler)) return;
+ var term = b as IMyTerminalBlock;
+ if (!term.IsFunctional) return;
+ if (term.CustomName.Contains(blockName)) return;
+ if (!term.HasLocalPlayerAccess()) return;
+ if (sphere3.Contains(term.WorldMatrix.Translation) == ContainmentType.Contains && !IsSeparated(term)) {
+ var add = true;
+ foreach (var e in enters) {
+ if (AreConnected(e, term)) {
+ add = false;
+ break;
+ }
+ }
+ if (add) enters.Add(term);
+ }
+
+ if (filter == null || filter.Invoke(term)) {
+ allBlocks.Add(term);
+ }
+ });
+ }
+
+ if (sort != null) {
+ allBlocks.Sort((a,b)=>sort.Invoke(a, b));
+ }
+
+ foreach (var x in allBlocks) {
+ if (IsSeparated(x)) {
+ cargos.Add (x as MyEntity);
+ if (cargos.Count >= maxTake) return;
+ } else {
+ foreach (var y in enters) {
+ if (AreConnected (x, y)) {
+ cargos.Add (x as MyEntity);
+ if (cargos.Count >= maxTake) return;
+ break;
+ }
+ }
+ }
+ }
+
+ }
+
+ public static void GetAllCargosInRangeSimple(ref BoundingSphereD sphere2, List cargos, Func filter = null)
+ {
+ var data = MyEntities.GetTopMostEntitiesInSphere(ref sphere2);
+ var ships = new HashSet();
+ foreach (var x in data)
+ {
+ var g = x as MyCubeGrid;
+ if (g != null)
+ {
+ ships.Add(g);
+ }
+ }
+ data.Clear();
+
+ var allBlocks = new List();
+ var sphere3 = sphere2;
+
+ foreach (var x in ships){
+ x?.OverFatBlocks((b) => {
+ if (!(b is IMyCargoContainer) && !(b is IMyShipConnector)) return;
+ var term = b as IMyTerminalBlock;
+ if (!term.IsFunctional) return;
+ if (!term.HasLocalPlayerAccess()) return;
+ if (sphere3.Contains(term.WorldMatrix.Translation) != ContainmentType.Contains) return;
+
+ if (filter == null || filter.Invoke(term)) {
+ cargos.Add(b);
+ }
+ });
+ }
+
+ }
+
+ private static bool IsSeparated(IMyTerminalBlock a) {
+ var sn = a.SlimBlock.BlockDefinition.Id.SubtypeName;
+ if (sn.StartsWith("Freight")) return true;
+ if (sn.Equals("LargeBlockLockerRoom") || sn.Equals("LargeBlockLockerRoomCorner") || sn.Equals("LargeBlockLockers")) return true;
+ return false;
+ }
+
+ private static bool AreConnected (IMyTerminalBlock a, IMyTerminalBlock b) {
+ //if (a.CubeGrid != b.CubeGrid) return false;
+ if (a==b) return true;
+
+ for (var x=0; x < a.InventoryCount; x++) {
+ for (var y=0; y < b.InventoryCount; y++) {
+ if (a.GetInventory (x).IsConnectedTo (b.GetInventory(y))) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
+
+ public static string CustomName (this IMyInventory x) {
+ var term = (x.Owner as IMyTerminalBlock);
+ if (term == null) return x.Owner.DisplayName;
+ else return term.CustomName;
+ }
+
+ public static MyFixedPoint calculateCargoMass (this IMyCubeGrid grid) {
+ MyFixedPoint mass = 0;
+ grid.FindBlocks(x => {
+
+ var fat = x.FatBlock;
+ if (fat == null || !fat.HasInventory) return false;
+ var i = fat.GetInventory();
+ if (i == null) return false;
+
+ mass += i.CurrentMass;
+ return false;
+ });
+
+ return mass;
+ }
+
+
+
+
+ public static int GetItemIndexByID (this IMyInventory inv, uint itemId) {
+ for (var index=0; index p = null, bool alwaysAtEnd = false) {
+ for (var x=from.ItemCount-1; x>=0; x--) {
+ var t = from.GetItemAt(x);
+ MyFixedPoint? amount = p!= null ? p.Invoke(t.Value) : null;
+ if (amount == null || amount > 0) {
+ from.TransferItemTo (inventory, x, checkConnection:false, amount:amount, targetItemIndex: (alwaysAtEnd ? (int?)inventory.ItemCount : null));
+ }
+ }
+ }
+
+
+ public static void PullRequest (this IMyInventory target, List from, Dictionary what, bool alwaysAtEnd = false) {
+ foreach (var x in from) {
+ if (what.Count == 0) break;
+
+ MoveAllItemsFrom (target, x, (i) => {
+ if (what.ContainsKey (i.Type)) {
+ var need = what[i.Type];
+ var have = i.Amount;
+
+
+ if (need > have) {
+ what[i.Type] = need - have;
+ return null;
+ } else {
+ what.Remove(i.Type);
+ return need;
+ }
+ }
+ return -1;
+ }, alwaysAtEnd:alwaysAtEnd);
+ }
+ }
+
+ public static void PushRequest (this IMyInventory target, List from, Dictionary what, bool alwaysAtEnd = false) {
+ foreach (var x in from) {
+ if (what.Count == 0) break;
+
+ MoveAllItemsFrom (x, target, (i) => {
+ if (what.ContainsKey (i.Type)) {
+ var need = what[i.Type];
+ var have = i.Amount;
+
+
+ if (need > have) {
+ what[i.Type] = need - have;
+ return null;
+ } else {
+ what.Remove(i.Type);
+ return need;
+ }
+ }
+ return -1;
+ }, alwaysAtEnd:alwaysAtEnd);
+ }
+ }
+
+ public static double CanProduce (this MyBlueprintDefinitionBase bp, Dictionary items) {
+ double can_produce_times = Double.MaxValue;
+ foreach (var pre in bp.Prerequisites) {
+ var have = items.GetOr (pre.Id, MyFixedPoint.Zero);
+ var times = (double)have / (double)pre.Amount;
+ if (times < can_produce_times) {
+ can_produce_times = times;
+ if (can_produce_times == 0) { return 0; }
+ }
+ }
+
+ return can_produce_times;
+ }
+
+
+ public static bool ParseHumanDefinition (string type, string subtype, out MyDefinitionId id)
+ {
+ if (type == "i" || type == "I")
+ {
+ type = "Ingot";
+ }
+ else if (type == "o" || type == "O")
+ {
+ type = "Ore";
+ }
+ else if (type == "c" || type == "C")
+ {
+ type = "Component";
+ }
+ return MyDefinitionId.TryParse("MyObjectBuilder_" + type + "/" + subtype, out id);
+ }
+ public static string GetHumanName(MyDefinitionId id)
+ {
+ return id.TypeId.ToString().Replace("MyObjectBuilder_", "") + "/" + id.SubtypeName;
+ }
+ }
+}
diff --git a/TSTSSESCores/Data/Scripts/Scripts/Shared/Log.cs b/TSTSSESCores/Data/Scripts/Scripts/Shared/Log.cs
new file mode 100644
index 00000000..8fcbfa5a
--- /dev/null
+++ b/TSTSSESCores/Data/Scripts/Scripts/Shared/Log.cs
@@ -0,0 +1,88 @@
+using System;
+using MIG.Shared.SE;
+using Sandbox.ModAPI;
+using VRage.Game;
+using VRage.Game.ModAPI;
+using VRage.Utils;
+
+namespace Digi {
+ public static class Log // v1.4
+ {
+ public static string modName = "UNNAMED";
+ public static int MAX_LOGS = 500;
+ public static int logged = 0;
+ public static bool CanWriteToChat = false;
+
+ private static IMyHudNotification notify = null;
+
+ public static void Error(Exception e) {
+ Error(e.ToString());
+ }
+
+ public static void ServerError(Exception e) {
+ MyLog.Default.WriteLineAndConsole(e.Message + " " + e.StackTrace);
+ }
+
+ public static void Error(Exception e, string printText) {
+ Error(printText +" "+ e.ToString(), printText);
+ }
+
+ public static void Error(string msg) {
+ Error(msg, modName + " error - open %AppData%/SpaceEngineers");
+ }
+
+ public static void ChatError (String s, Exception e) {
+ ChatError (s + " " + e.ToString());
+ }
+
+ public static void ChatError (Exception e) {
+ ChatError (e.ToString());
+ }
+
+ public static void Test(String s)
+ {
+ ChatError(s);
+ }
+
+ public static void ChatError (String s)
+ {
+ s = "SpecCores:" + s;
+ Info(s);
+ //if (!CanWriteToChat) return;
+
+ if (logged >= MAX_LOGS) return;
+ logged++;
+
+ Common.SendChatMessageToMe (s, "");
+ if (logged == MAX_LOGS)
+ {
+ Common.SendChatMessageToMe("Reached limit of messages. Watch logs", "");
+ }
+ }
+
+ public static void Error(string msg, string printText) {
+ Info("ERROR: " + msg);
+ if (!CanWriteToChat) return;
+ try {
+ if (MyAPIGateway.Session != null) {
+ //MyAPIGateway.Utilities.CreateNotification(msg, 5000, MyFontEnum.Red).Show();
+ if (notify == null) {
+ notify = MyAPIGateway.Utilities.CreateNotification(msg, 5000, MyFontEnum.Red);
+ } else {
+ notify.Text = msg;
+ notify.ResetAliveTime();
+ }
+
+ notify.Show();
+ }
+ } catch (Exception e) {
+ Info("ERROR: Could not send notification to local client: " + e);
+ MyLog.Default.WriteLineAndConsole(modName + " error/exception: Could not send notification to local client: " + e);
+ }
+ }
+
+ public static void Info(string msg) {
+ MyLog.Default.WriteLineAndConsole(msg);
+ }
+ }
+}
\ No newline at end of file
diff --git a/TSTSSESCores/Data/Scripts/Scripts/Shared/ModConnection.cs b/TSTSSESCores/Data/Scripts/Scripts/Shared/ModConnection.cs
new file mode 100644
index 00000000..779f3018
--- /dev/null
+++ b/TSTSSESCores/Data/Scripts/Scripts/Shared/ModConnection.cs
@@ -0,0 +1,273 @@
+using Sandbox.ModAPI;
+using System;
+using System.Collections.Generic;
+using System.Text;
+using VRage.Game;
+using VRage.Utils;
+
+namespace MIG.Shared.SE
+{
+ public static class ModConnection
+ {
+ private static string TAG = "MOD";
+ private static int PORT1 = 6666666;
+ private static int PORT2 = 6666667;
+ private static Dictionary Data;
+ private static Dictionary>> Subscriptions = new Dictionary>>();
+ private const bool DEBUGLOG = false;
+ private static List> RegisterQueue = new List>();
+
+ private static bool IsMain = false;
+ public static bool IsInited => ModConnection.Data != null;
+
+
+ public static void Close()
+ {
+ MyAPIGateway.Utilities.UnregisterMessageHandler(PORT1, ConnectionPortHandler);
+ MyAPIGateway.Utilities.UnregisterMessageHandler(PORT2, NotifyChannelHandler);
+ }
+
+ public static void Init()
+ {
+ if (IsInited) throw new Exception("ModConnection already inited!");
+ Log("ModConnectionComponent:MOD Init");
+ MyAPIGateway.Utilities.RegisterMessageHandler(PORT1, ConnectionPortHandler);
+ MyAPIGateway.Utilities.RegisterMessageHandler(PORT2, NotifyChannelHandler);
+
+ MyAPIGateway.Utilities.SendModMessage(PORT1, null);
+
+ if (Data == null)
+ {
+ IsMain = true;
+ Data = new Dictionary();
+ foreach (var x in RegisterQueue) //We have to react on own methods too
+ {
+ SetValue(x.Key, x.Value, crashOnDuplicate: true);
+ }
+ //We dont need react, because we are subscribed on NotifyChannel
+ }
+ else
+ {
+ foreach (var x in Data)
+ {
+ Handle(x.Key, x.Value);
+ }
+ foreach (var x in RegisterQueue)
+ {
+ SetValue(x.Key, x.Value, crashOnDuplicate: true);
+ }
+ }
+ }
+
+
+ private static void ConnectionPortHandler(object data)
+ {
+ Log("ConnectionPortHandler");
+ if (data == null) //Request data
+ {
+ if (IsMain && Data != null)
+ {
+ Log("Request data !" + TAG);
+ MyAPIGateway.Utilities.SendModMessage(PORT1, Data);
+ }
+ else
+ {
+ Log("Request data Error ! " + TAG + " [" + data+"]");
+ //Ignore we are not Main, or not inited yet.
+ }
+ }
+ else
+ {
+ var fn = data as Dictionary;
+ if (fn != null)
+ {
+ Log ("Arrived data! "+ TAG);
+ Data = fn;
+ }
+ else
+ {
+ Log("Error1 ! " + TAG);
+ //possible trash;
+ }
+ }
+ }
+
+ public static void Log (string data)
+ {
+ if (DEBUGLOG)
+ {
+ MyLog.Default.Error($"MCon {TAG}: {data}");
+ }
+ }
+
+ public static void LogError (string data)
+ {
+ if (DEBUGLOG)
+ {
+ MyLog.Default.Error($"MCon {TAG}: {data}");
+ }
+ }
+
+ private static void NotifyChannelHandler(object data)
+ {
+ var pair = data as KeyValuePair?;
+ if (!pair.HasValue)
+ {
+ Log("Something wrong [Cores]");
+ return;
+ }
+ var d = pair.Value;
+
+ if (!Data.ContainsKey(d.Key))
+ {
+ Log($"Desynchronization [Cores] [{d.Key}]/[{d.Value}] -> [{d.Key}]/[null]");
+ }
+ else
+ {
+ if (Data[d.Key] != d.Value)
+ {
+ Log($"Desynchronization [Cores] [{d.Key}]/[{d.Value}] -> [{d.Key}]/[{Data[d.Key]}]");
+ }
+ }
+
+ Log($"Registered [Cores] [{d.Key}]->[{d.Value}]");
+ Handle(d.Key, d.Value);
+ }
+
+ private static string ALL = "";
+ private static void Handle(string Name, object O)
+ {
+ Log("Handle [Cores]: " + Name);
+ if (Name != ALL)
+ {
+ if (Subscriptions.ContainsKey(Name))
+ {
+ foreach (var x in Subscriptions[Name])
+ {
+ try
+ {
+ x(Name, O);
+ }
+ catch (Exception e)
+ {
+ Log($"ModConnection [Cores]: Exception for [{Name}] : {e.ToString()}");
+ }
+ }
+ }
+ }
+
+ if (Subscriptions.ContainsKey(ALL))
+ {
+ foreach (var x in Subscriptions[ALL])
+ {
+ try
+ {
+ x(Name, O);
+ }
+ catch (Exception e)
+ {
+ Log($"ModConnection [Cores]: Exception for [{Name}] : {e.ToString()}");
+ }
+ }
+ }
+ }
+
+
+
+
+
+ public static void SetValue(string Name, object Data, bool crashOnDuplicate = false, bool notify = true)
+ {
+ if (ModConnection.Data == null)
+ {
+ RegisterQueue.Add(new KeyValuePair(Name, Data));
+ }
+ else
+ {
+ if (crashOnDuplicate && ModConnection.Data.ContainsKey(Name))
+ {
+ PrintAllData();
+ throw new Exception($"Key already exists {Name} : [{ModConnection.Data[Name]}");
+ }
+
+ ModConnection.Data[Name] = Data;
+ if (notify) MyAPIGateway.Utilities.SendModMessage(PORT2, new KeyValuePair(Name, Data));
+ }
+ }
+
+ public static T Get(string Name)
+ {
+ object o;
+ if (Data.TryGetValue(Name, out o))
+ {
+ if (o is T)
+ {
+ return (T)o;
+ }
+ }
+
+ return default(T);
+ }
+
+ public static void Subscribe(string Name, Action OnDataArrivedOrChanged)
+ {
+ Action catched = (a, b) =>
+ {
+ try
+ {
+ OnDataArrivedOrChanged(a, b);
+ }
+ catch (Exception e)
+ {
+ Log($"{Name}:" + e.ToString());
+ }
+ };
+
+ Subscriptions.GetOrNew(Name).Add(catched);
+ if (Data.ContainsKey(Name))
+ {
+ try
+ {
+ catched(Name, Data[Name]);
+ }
+ catch (Exception e)
+ {
+ LogError($"ModConnection [Cores]:OnDataArrivedOrChanged {Name} {Data[Name]} error: {e}");
+ }
+
+ }
+ }
+
+ public static void Subscribe(string Name, Action OnDataArrivedOrChanged)
+ {
+ Subscribe(Name, (name, data) => OnDataArrivedOrChanged((T) data));
+ }
+
+ public static void Subscribe(string Name, T intance, Action OnDataArrivedOrChanged)
+ {
+ Subscribe(Name, (name, data) => OnDataArrivedOrChanged((T) data));
+ }
+
+ public static void SetValueAndSubscribe(string Name, T Data, Action OnDataArrivedOrChanged, bool crashOnDuplicate = true)
+ {
+ SetValue(Name, Data, crashOnDuplicate);
+ Subscribe(Name, OnDataArrivedOrChanged);
+ }
+
+ public static void SubscribeToAll(Action OnDataArrivedOrChanged)
+ {
+ Subscribe(ALL, OnDataArrivedOrChanged);
+ }
+
+ public static void PrintAllData()
+ {
+ var sb = new StringBuilder("ModConnection [Cores]:\n");
+ foreach (var x in Data)
+ {
+ sb.AppendLine($"{x.Key} -> {x.Value}");
+ }
+
+ Log(sb.ToString());
+ }
+ }
+}
\ No newline at end of file
diff --git a/TSTSSESCores/Data/Scripts/Scripts/Shared/NAPI.cs b/TSTSSESCores/Data/Scripts/Scripts/Shared/NAPI.cs
new file mode 100644
index 00000000..d06e65c3
--- /dev/null
+++ b/TSTSSESCores/Data/Scripts/Scripts/Shared/NAPI.cs
@@ -0,0 +1,1448 @@
+using Sandbox.Game.Entities;
+using Sandbox.ModAPI;
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Linq;
+using System.Text;
+using System.Text.RegularExpressions;
+using Sandbox.Game.EntityComponents;
+using VRage.Game.Components;
+using VRage.Game.ModAPI;
+using VRage.ModAPI;
+using VRageMath;
+using Sandbox.Definitions;
+using VRage;
+using VRage.Game;
+using VRage.Collections;
+using VRage.Game.Entity;
+using VRage.ObjectBuilders;
+
+namespace MIG.Shared.SE {
+
+ public static class NAPI {
+ private const int FREEZE_FLAG = 4;
+ public static bool isFrozen(this IMyEntity grid) { return ((int)grid.Flags | FREEZE_FLAG) == (int)grid.Flags; }
+ public static void setFrozen(this IMyEntity grid) { grid.Flags = grid.Flags | (EntityFlags)FREEZE_FLAG; }
+ public static void setUnFrozen(this IMyEntity e) { e.Flags &= ~(EntityFlags)FREEZE_FLAG; }
+
+
+
+ public static Vector3D GetWorldPosition (this IMySlimBlock block) {
+ var box = new BoundingBoxD ();
+ block.GetWorldBoundingBox(out box);
+ return box.Center;
+ }
+
+ [Obsolete("Use IsDedicated instead")]
+ public static bool isTorchServer (this IMySession session) {
+ return MyAPIGateway.Utilities.IsDedicated;
+ }
+
+ public static bool IsDedicated (this IMySession session) {
+ return MyAPIGateway.Utilities.IsDedicated;
+ }
+
+ public static string SubtypeName (this IMyCubeBlock block) {
+ return block.SlimBlock.BlockDefinition.Id.SubtypeName;
+ }
+
+ public static T Definition(this MyObjectBuilder_CubeBlock ob) where T : MyCubeBlockDefinition
+ {
+ return (T)MyDefinitionManager.Static.GetCubeBlockDefinition(ob);
+ }
+
+ public static MyCubeBlockDefinition Definition(this MyObjectBuilder_CubeBlock ob)
+ {
+ return MyDefinitionManager.Static.GetCubeBlockDefinition(ob);
+ }
+
+ public static string GetHumanName(this MyDefinitionId id)
+ {
+ return id.ToString().Replace("MyObjectBuilder_", "");
+ }
+
+ public static string GetHumanInfo(this Dictionary kv)
+ {
+ var sb = new StringBuilder();
+ foreach (var kv2 in kv)
+ {
+ sb.Append($" {kv2.Value}x{kv2.Key.GetHumanName()} ");
+ }
+ return sb.ToString();
+ }
+
+
+ public static long BuiltBy(this IMyCubeBlock block) {
+ return block.SlimBlock.BuiltBy;
+ }
+
+ public static bool IsSameFactionLeader(this IMyCubeBlock block)
+ {
+ var builtBy = block.BuiltBy();
+ var f = builtBy.PlayerFaction();
+ var pl = MyAPIGateway.Session.LocalHumanPlayer;
+ var my = pl.GetFaction();
+ if (f != my) return false;
+ if (my == null) return pl.IdentityId == builtBy;
+ return my.IsLeader(pl.IdentityId) || my.IsFounder(pl.IdentityId);
+ }
+
+ public static T As(this long entityId) {
+ IMyEntity entity;
+ if (!MyAPIGateway.Entities.TryGetEntityById(entityId, out entity)) return default(T);
+ if (entity is T) { return (T) entity; } else { return default(T); }
+ }
+
+ public static T GetAs (this IMyEntity entity) where T : MyGameLogicComponent {
+ var logic = entity.GameLogic;
+ var t = logic as T;
+ if (t != null) return t;
+ var cmp = logic as MyCompositeGameLogicComponent;
+ return cmp?.GetAs();
+ }
+
+ public static void FindFatBlocks(this IMyCubeGrid grid, List blocks, Func filter) {
+ var gg = grid as MyCubeGrid;
+ var ff = gg.GetFatBlocks();
+ foreach (var x in ff) {
+ var fat = (IMyCubeBlock) x;
+ if (filter(fat)) { blocks.Add((T) fat); }
+ }
+ }
+
+ public static void OverFatBlocks(this IMyCubeGrid grid, Action action) {
+ var gg = grid as MyCubeGrid;
+ var ff = gg.GetFatBlocks();
+ foreach (var x in ff) {
+ var fat = (IMyCubeBlock) x;
+ action(fat);
+ }
+ }
+
+ public static List GetConnectedGrids(this IMyCubeGrid grid, GridLinkTypeEnum with, List list = null, bool clear = false) {
+ if (list == null) list = new List();
+ if (clear) list.Clear();
+ MyAPIGateway.GridGroups.GetGroup(grid, with, list);
+ return list;
+ }
+
+ public static IMyFaction PlayerFaction(this long playerId) { return MyAPIGateway.Session.Factions.TryGetPlayerFaction(playerId); }
+
+ public static IMyPlayer GetPlayer(this IMyCharacter character) { return MyAPIGateway.Players.GetPlayerControllingEntity(character); } //CAN BE NULL IF IN COCKPIT
+ public static IMyPlayer GetPlayer(this IMyShipController cockpit) { return MyAPIGateway.Players.GetPlayerControllingEntity(cockpit); }
+ public static IMyPlayer GetPlayer(this IMyIdentity Identity) {
+ IMyPlayer player = null;
+ MyAPIGateway.Players.GetPlayers(null, (x) => {
+ if (x.IdentityId == Identity.IdentityId)
+ {
+ player = x;
+ }
+ return false;
+ });
+ return player;
+ }
+
+ public static IMyIdentity GetIdentity(this long playerId)
+ {
+ IMyIdentity ident = null;
+ MyAPIGateway.Players.GetAllIdentites(null, (x)=>
+ {
+ if (playerId == x.IdentityId)
+ {
+ ident = x;
+ }
+ return false;
+ });
+ return ident;
+ }
+
+ public static void SetPower(this IMyCubeBlock cubeBlock, float power)
+ {
+ cubeBlock?.ResourceSink?.SetMaxRequiredInputByType(MyResourceDistributorComponent.ElectricityId, power);
+ cubeBlock?.ResourceSink?.SetRequiredInputByType(MyResourceDistributorComponent.ElectricityId, power);
+ }
+
+ public static float CurrentPowerInput(this IMySlimBlock block)
+ {
+ var fat = block.FatBlock;
+ if (fat == null) return 0;
+ return fat.ResourceSink.CurrentInputByType(MyResourceDistributorComponent.ElectricityId);
+ }
+
+ public static float MaxRequiredPowerInput(this IMySlimBlock block)
+ {
+ var fat = block.FatBlock;
+ if (fat == null) return 0;
+ return fat.ResourceSink.MaxRequiredInputByType(MyResourceDistributorComponent.ElectricityId);
+ }
+
+ public static float CurrentPowerInput(this IMyCubeBlock fat)
+ {
+ if (fat == null) return 0;
+ return fat.ResourceSink.CurrentInputByType(MyResourceDistributorComponent.ElectricityId);
+ }
+
+ public static float MaxRequiredPowerInput(this IMyCubeBlock fat)
+ {
+ if (fat == null) return 0;
+ return fat.ResourceSink.MaxRequiredInputByType(MyResourceDistributorComponent.ElectricityId);
+ }
+
+ public static bool IsOnline (this IMyPlayerCollection players, long identity)
+ {
+ bool contains = false;
+ players.GetPlayers (null, (x)=>{
+ if (x.IdentityId == identity)
+ {
+ contains = true;
+ }
+ return false;
+ });
+
+ return contains;
+ }
+
+ public static bool IsControllingCockpit (this IMyShipController cockpit)
+ {
+ if (cockpit.IsMainCockpit)
+ {
+ return true;
+ }
+ else if (cockpit.ControllerInfo != null && cockpit.ControllerInfo.Controller != null && cockpit.ControllerInfo.Controller.ControlledEntity != null)
+ {
+ return true;
+ }
+
+ return false;
+ }
+
+ public static bool IsMainControlledCockpit(this IMyShipController cockpit)
+ {
+ return cockpit.ControllerInfo != null && cockpit.ControllerInfo.Controller != null && cockpit.ControllerInfo.Controller.ControlledEntity != null;
+ }
+
+ public static IMyCubeGrid GetMyControlledGrid(this IMySession session) {
+ var cock = MyAPIGateway.Session.Player.Controller.ControlledEntity as IMyCockpit;
+ if (cock == null) return null;
+ return cock.CubeGrid;
+ }
+
+ public static IMyFaction Faction(this long factionId)
+ {
+ return MyAPIGateway.Session.Factions.TryGetFactionById(factionId);
+ }
+
+ public static bool isBot (this IMyIdentity identity)
+ {
+ return MyAPIGateway.Players.TryGetSteamId(identity.IdentityId) == 0;
+ }
+
+ public static bool IsUserAdmin(this ulong SteamUserId)
+ {
+ return MyAPIGateway.Session.IsUserAdmin(SteamUserId);
+ }
+
+ public static MyPromoteLevel PromoteLevel (this ulong SteamUserId)
+ {
+ var PlayersList = new List();
+ MyAPIGateway.Players.GetPlayers(PlayersList);
+ foreach (var Player in PlayersList.Where(Player => Player.SteamUserId == SteamUserId))
+ {
+ return Player.PromoteLevel;
+ }
+ return MyPromoteLevel.None;
+ }
+
+ public static IMyIdentity Identity (this ulong SteamUserId)
+ {
+ IMyIdentity identity = null;
+ MyAPIGateway.Multiplayer.Players.GetAllIdentites(null, (x)=>
+ {
+ if (identity != null) return false;
+ var st = MyAPIGateway.Multiplayer.Players.TryGetSteamId(x.IdentityId);
+ if (st == SteamUserId)
+ {
+ identity = x;
+ }
+ return false;
+ });
+ return identity;
+ }
+
+ public static long IdentityId (this ulong SteamUserId)
+ {
+ return SteamUserId.Identity()?.IdentityId ?? 0;
+ }
+
+ public static BoundingBoxD GetAABB (this List grids)
+ {
+ var aabb1 = grids[0].PositionComp.WorldAABB;
+ BoundingBoxD aabb = new BoundingBoxD(aabb1.Min, aabb1.Max);
+ for (var x=1; x GetEntitiesInSphere (this IMyEntities entities, Vector3D pos, double radius, Func filter = null) {
+ var sphere = new BoundingSphereD(pos, radius);
+ var list = entities.GetEntitiesInSphere(ref sphere);
+ if (filter != null) { list.RemoveAll((x)=>!filter(x)); }
+ return list;
+ }
+
+
+ public static void SendMessageToOthersProto(this IMyMultiplayer multi, ushort id, object o, bool reliable = true) {
+ var bytes = MyAPIGateway.Utilities.SerializeToBinary(o);
+ multi.SendMessageToOthers(id, bytes, reliable);
+ }
+
+ // Calculates how much components are welded for block
+ public static void GetRealComponentsCost(this IMySlimBlock block, Dictionary dictionary, Dictionary temp = null)
+ {
+ if (temp == null) temp = new Dictionary();
+ var components = (block.BlockDefinition as MyCubeBlockDefinition).Components;
+ foreach (var component in components)
+ {
+ string name = component.Definition.Id.SubtypeName;
+ int count = component.Count;
+
+ if (dictionary.ContainsKey(name)) dictionary[name] += count;
+ else dictionary.Add(name, count);
+ }
+
+ temp.Clear();
+ block.GetMissingComponents(temp);
+
+ foreach (var component in temp)
+ {
+ string name = component.Key;
+ int count = component.Value;
+
+ if (dictionary.ContainsKey(name)) dictionary[name] -= count;
+ else dictionary.Add(name, count);
+ }
+ }
+
+ public static bool ParseHumanDefinition(string type, string subtype, out MyDefinitionId id)
+ {
+ if (type == "i" || type == "I")
+ {
+ type = "Ingot";
+ }
+ else if (type == "o" || type == "O")
+ {
+ type = "Ore";
+ }
+ else if (type == "c" || type == "C")
+ {
+ type = "Component";
+ }
+ return MyDefinitionId.TryParse("MyObjectBuilder_" + type + "/" + subtype, out id);
+ }
+
+ public static ListReader GetFatBlocks (this IMyCubeGrid grid)
+ {
+ return ((MyCubeGrid)grid).GetFatBlocks();
+ }
+ }
+
+ public static class RandomSugar {
+ public static Vector3 NextVector(this Random random, float x, float y, float z)
+ {
+ x = x * (float)(2*random.NextDouble()-1d);
+ y = y * (float)(2*random.NextDouble()-1d);
+ z = z * (float)(2*random.NextDouble()-1d);
+ return new Vector3(x, y, z);
+ }
+
+ public static double NextDouble(this Random random, double min, double max)
+ {
+ return min + (max - min) * random.NextDouble();
+ }
+
+ public static float NextFloat(this Random random, double min, double max)
+ {
+ return (float)(min + (max - min) * random.NextDouble());
+ }
+
+ public static T Next (this Random random, IEnumerable