A stable modding interface between Techblox and mods https://mod.exmods.org/
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

301 lines
8.8KB

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using Gamecraft.ColourPalette;
  5. using Gamecraft.TimeRunning;
  6. using Gamecraft.Wires;
  7. using RobocraftX.Blocks;
  8. using RobocraftX.Common;
  9. using RobocraftX.Physics;
  10. using RobocraftX.Rendering;
  11. using Svelto.ECS.EntityStructs;
  12. using Svelto.DataStructures;
  13. using Svelto.ECS;
  14. using Svelto.ECS.Hybrid;
  15. using Unity.Mathematics;
  16. using GamecraftModdingAPI.Engines;
  17. namespace GamecraftModdingAPI.Blocks
  18. {
  19. /// <summary>
  20. /// Engine for executing general block actions
  21. /// </summary>
  22. public partial class BlockEngine : IApiEngine
  23. {
  24. public string Name { get; } = "GamecraftModdingAPIBlockGameEngine";
  25. public EntitiesDB entitiesDB { set; private get; }
  26. public bool isRemovable => false;
  27. public void Dispose()
  28. {
  29. }
  30. public void Ready()
  31. {
  32. }
  33. public Block[] GetConnectedBlocks(EGID blockID)
  34. {
  35. if (!BlockExists(blockID)) return new Block[0];
  36. Stack<EGID> cubeStack = new Stack<EGID>();
  37. FasterList<EGID> cubes = new FasterList<EGID>(10);
  38. var coll = entitiesDB.QueryEntities<GridConnectionsEntityStruct>();
  39. foreach (var (ecoll, _) in coll)
  40. {
  41. var ecollB = ecoll.ToBuffer();
  42. for(int i = 0; i < ecoll.count; i++)
  43. {
  44. ref var conn = ref ecollB.buffer[i];
  45. conn.isProcessed = false;
  46. }
  47. }
  48. ConnectedCubesUtility.TreeTraversal.GetConnectedCubes(entitiesDB, blockID, cubeStack, cubes,
  49. (in GridConnectionsEntityStruct g) => { return false; });
  50. var ret = new Block[cubes.count];
  51. for (int i = 0; i < cubes.count; i++)
  52. ret[i] = new Block(cubes[i]);
  53. return ret;
  54. }
  55. public float4 ConvertBlockColor(byte index) => index == byte.MaxValue
  56. ? new float4(-1f, -1f, -1f, -1f)
  57. : entitiesDB.QueryEntity<PaletteEntryEntityStruct>(index,
  58. CommonExclusiveGroups.COLOUR_PALETTE_GROUP).Colour;
  59. public ref T GetBlockInfo<T>(EGID blockID) where T : unmanaged, IEntityComponent
  60. {
  61. if (entitiesDB.Exists<T>(blockID))
  62. return ref entitiesDB.QueryEntity<T>(blockID);
  63. T[] structHolder = new T[1]; //Create something that can be referenced
  64. return ref structHolder[0]; //Gets a default value automatically
  65. }
  66. public ref T GetBlockInfoViewStruct<T>(EGID blockID) where T : struct, INeedEGID, IEntityViewComponent
  67. {
  68. if (entitiesDB.Exists<T>(blockID))
  69. return ref entitiesDB.QueryEntity<T>(blockID);
  70. T[] structHolder = new T[1]; //Create something that can be referenced
  71. return ref structHolder[0]; //Gets a default value automatically
  72. }
  73. public U GetBlockInfo<T, U>(Block block, Func<T, U> getter,
  74. U def = default) where T : unmanaged, IEntityComponent
  75. {
  76. if (entitiesDB.Exists<T>(block.Id))
  77. return getter(entitiesDB.QueryEntity<T>(block.Id));
  78. return GetBlockInitInfo(block, getter, def);
  79. }
  80. public U GetBlockInfoViewStruct<T, U>(Block block, Func<T, U> getter,
  81. U def = default) where T : struct, IEntityViewComponent
  82. {
  83. if (entitiesDB.Exists<T>(block.Id))
  84. return getter(entitiesDB.QueryEntity<T>(block.Id));
  85. return GetBlockInitInfo(block, getter, def);
  86. }
  87. private U GetBlockInitInfo<T, U>(Block block, Func<T, U> getter, U def) where T : struct, IEntityComponent
  88. {
  89. if (block.InitData.Group == null) return def;
  90. var initializer = new EntityInitializer(block.Id, block.InitData.Group);
  91. if (initializer.Has<T>())
  92. return getter(initializer.Get<T>());
  93. return def;
  94. }
  95. public delegate void Setter<T, U>(ref T component, U value) where T : struct, IEntityComponent;
  96. public void SetBlockInfoViewStruct<T, U>(Block block, Setter<T, U> setter, U value) where T : struct, IEntityViewComponent
  97. {
  98. if (entitiesDB.Exists<T>(block.Id))
  99. setter(ref entitiesDB.QueryEntity<T>(block.Id), value);
  100. else
  101. SetBlockInitInfo(block, setter, value);
  102. }
  103. public void SetBlockInfo<T, U>(Block block, Setter<T, U> setter, U value) where T : unmanaged, IEntityComponent
  104. {
  105. if (entitiesDB.Exists<T>(block.Id))
  106. setter(ref entitiesDB.QueryEntity<T>(block.Id), value);
  107. else
  108. SetBlockInitInfo(block, setter, value);
  109. }
  110. private void SetBlockInitInfo<T, U>(Block block, Setter<T, U> setter, U value)
  111. where T : struct, IEntityComponent
  112. {
  113. if (block.InitData.Group != null)
  114. {
  115. var initializer = new EntityInitializer(block.Id, block.InitData.Group);
  116. T component = initializer.Has<T>() ? initializer.Get<T>() : default;
  117. ref T structRef = ref component;
  118. setter(ref structRef, value);
  119. initializer.Init(structRef);
  120. }
  121. }
  122. public void UpdateDisplayedBlock(EGID id)
  123. {
  124. if (!BlockExists(id)) return;
  125. var pos = entitiesDB.QueryEntity<PositionEntityStruct>(id);
  126. var rot = entitiesDB.QueryEntity<RotationEntityStruct>(id);
  127. var scale = entitiesDB.QueryEntity<ScalingEntityStruct>(id);
  128. entitiesDB.QueryEntity<RenderingDataStruct>(id).matrix = float4x4.TRS(pos.position, rot.rotation, scale.scale);
  129. }
  130. public bool BlockExists(EGID blockID)
  131. {
  132. return entitiesDB.Exists<DBEntityStruct>(blockID);
  133. }
  134. public bool GetBlockInfoExists<T>(Block block) where T : struct, IEntityComponent
  135. {
  136. if (entitiesDB.Exists<T>(block.Id))
  137. return true;
  138. if (block.InitData.Group == null)
  139. return false;
  140. var init = new EntityInitializer(block.Id, block.InitData.Group);
  141. return init.Has<T>();
  142. }
  143. public SimBody[] GetSimBodiesFromID(byte id)
  144. {
  145. var ret = new FasterList<SimBody>(4);
  146. var oide = entitiesDB.QueryEntities<ObjectIdEntityStruct>();
  147. EGIDMapper<GridConnectionsEntityStruct>? connections = null;
  148. foreach (var ((oids, count), _) in oide)
  149. {
  150. for (int i = 0; i < count; i++)
  151. {
  152. ref ObjectIdEntityStruct oid = ref oids[i];
  153. if (oid.objectId != id) continue;
  154. if (!connections.HasValue) //Would need reflection to get the group from the build group otherwise
  155. connections = entitiesDB.QueryMappedEntities<GridConnectionsEntityStruct>(oid.ID.groupID);
  156. var rid = connections.Value.Entity(oid.ID.entityID).machineRigidBodyId;
  157. foreach (var rb in ret)
  158. {
  159. if (rb.Id.entityID == rid)
  160. goto DUPLICATE; //Multiple Object Identifiers on one rigid body
  161. }
  162. ret.Add(new SimBody(rid));
  163. DUPLICATE: ;
  164. }
  165. }
  166. return ret.ToArray();
  167. }
  168. public ObjectIdentifier[] GetObjectIDsFromID(byte id, bool sim)
  169. {
  170. var ret = new FasterList<ObjectIdentifier>(4);
  171. var oide = entitiesDB.QueryEntities<ObjectIdEntityStruct>();
  172. foreach (var ((oids, count), _) in oide)
  173. {
  174. for (int i = 0; i < count; i++)
  175. {
  176. ref ObjectIdEntityStruct oid = ref oids[i];
  177. if (sim ? oid.simObjectId == id : oid.objectId == id)
  178. ret.Add(new ObjectIdentifier(oid.ID));
  179. }
  180. }
  181. return ret.ToArray();
  182. }
  183. public SimBody[] GetConnectedSimBodies(uint id)
  184. {
  185. var joints = entitiesDB.QueryEntities<JointEntityStruct>(MachineSimulationGroups.JOINTS_GROUP).ToBuffer();
  186. var list = new FasterList<SimBody>(4);
  187. for (int i = 0; i < joints.count; i++)
  188. {
  189. ref var joint = ref joints.buffer[i];
  190. if (joint.isBroken) continue;
  191. if (joint.connectedEntityA == id) list.Add(new SimBody(joint.connectedEntityB));
  192. else if (joint.connectedEntityB == id) list.Add(new SimBody(joint.connectedEntityA));
  193. }
  194. return list.ToArray();
  195. }
  196. public SimBody[] GetClusterBodies(uint cid)
  197. {
  198. var groups = entitiesDB.QueryEntities<GridConnectionsEntityStruct>();
  199. var bodies = new HashSet<uint>();
  200. foreach (var (coll, _) in groups)
  201. {
  202. var array = coll.ToBuffer().buffer;
  203. for (var index = 0; index < array.capacity; index++)
  204. {
  205. var conn = array[index];
  206. if (conn.clusterId == cid)
  207. bodies.Add(conn.machineRigidBodyId);
  208. }
  209. }
  210. return bodies.Select(id => new SimBody(id, cid)).ToArray();
  211. }
  212. public EGID? FindBlockEGID(uint id)
  213. {
  214. var groups = entitiesDB.FindGroups<DBEntityStruct>();
  215. foreach (ExclusiveGroupStruct group in groups)
  216. {
  217. if (entitiesDB.Exists<DBEntityStruct>(id, group))
  218. return new EGID(id, group);
  219. }
  220. return null;
  221. }
  222. public Cluster GetCluster(uint sbid)
  223. {
  224. var groups = entitiesDB.QueryEntities<GridConnectionsEntityStruct>();
  225. foreach (var (coll, _) in groups)
  226. {
  227. var array = coll.ToBuffer().buffer;
  228. for (var index = 0; index < array.capacity; index++)
  229. {
  230. var conn = array[index];
  231. //Static blocks don't have a cluster ID but the cluster destruction manager should have one
  232. if (conn.machineRigidBodyId == sbid && conn.clusterId != uint.MaxValue)
  233. return new Cluster(conn.clusterId);
  234. }
  235. }
  236. return null;
  237. }
  238. public Block[] GetBodyBlocks(uint sbid)
  239. {
  240. var groups = entitiesDB.QueryEntities<GridConnectionsEntityStruct>();
  241. var set = new HashSet<Block>();
  242. foreach (var (coll, _) in groups)
  243. {
  244. var array = coll.ToBuffer().buffer;
  245. for (var index = 0; index < array.capacity; index++)
  246. {
  247. var conn = array[index];
  248. if (conn.machineRigidBodyId == sbid)
  249. set.Add(new Block(conn.ID));
  250. }
  251. }
  252. return set.ToArray();
  253. }
  254. #if DEBUG
  255. public EntitiesDB GetEntitiesDB()
  256. {
  257. return entitiesDB;
  258. }
  259. #endif
  260. }
  261. }