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.

311 lines
9.1KB

  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. {
  70. // TODO: optimize by using EntitiesDB internal calls instead of iterating over everything
  71. BT<MB<T>> entities = entitiesDB.QueryEntities<T>(blockID.groupID).ToBuffer();
  72. for (int i = 0; i < entities.count; i++)
  73. {
  74. if (entities.buffer[i].ID == blockID)
  75. {
  76. return ref entities.buffer[i];
  77. }
  78. }
  79. }
  80. T[] structHolder = new T[1]; //Create something that can be referenced
  81. return ref structHolder[0]; //Gets a default value automatically
  82. }
  83. public U GetBlockInfo<T, U>(Block block, Func<T, U> getter,
  84. U def = default) where T : unmanaged, IEntityComponent
  85. {
  86. if (entitiesDB.Exists<T>(block.Id))
  87. return getter(entitiesDB.QueryEntity<T>(block.Id));
  88. return GetBlockInitInfo(block, getter, def);
  89. }
  90. public U GetBlockInfoViewStruct<T, U>(Block block, Func<T, U> getter,
  91. U def = default) where T : struct, IEntityViewComponent
  92. {
  93. if (entitiesDB.Exists<T>(block.Id))
  94. return getter(entitiesDB.QueryEntity<T>(block.Id));
  95. return GetBlockInitInfo(block, getter, def);
  96. }
  97. private U GetBlockInitInfo<T, U>(Block block, Func<T, U> getter, U def) where T : struct, IEntityComponent
  98. {
  99. if (block.InitData.Group == null) return def;
  100. var initializer = new EntityComponentInitializer(block.Id, block.InitData.Group);
  101. if (initializer.Has<T>())
  102. return getter(initializer.Get<T>());
  103. return def;
  104. }
  105. public delegate void Setter<T, U>(ref T component, U value) where T : struct, IEntityComponent;
  106. public void SetBlockInfoViewStruct<T, U>(Block block, Setter<T, U> setter, U value) where T : struct, IEntityViewComponent
  107. {
  108. if (entitiesDB.Exists<T>(block.Id))
  109. setter(ref entitiesDB.QueryEntity<T>(block.Id), value);
  110. else
  111. SetBlockInitInfo(block, setter, value);
  112. }
  113. public void SetBlockInfo<T, U>(Block block, Setter<T, U> setter, U value) where T : unmanaged, IEntityComponent
  114. {
  115. if (entitiesDB.Exists<T>(block.Id))
  116. setter(ref entitiesDB.QueryEntity<T>(block.Id), value);
  117. else
  118. SetBlockInitInfo(block, setter, value);
  119. }
  120. private void SetBlockInitInfo<T, U>(Block block, Setter<T, U> setter, U value)
  121. where T : struct, IEntityComponent
  122. {
  123. if (block.InitData.Group != null)
  124. {
  125. var initializer = new EntityComponentInitializer(block.Id, block.InitData.Group);
  126. T component = initializer.Has<T>() ? initializer.Get<T>() : default;
  127. ref T structRef = ref component;
  128. setter(ref structRef, value);
  129. initializer.Init(structRef);
  130. }
  131. }
  132. public void UpdateDisplayedBlock(EGID id)
  133. {
  134. if (!BlockExists(id)) return;
  135. var pos = entitiesDB.QueryEntity<PositionEntityStruct>(id);
  136. var rot = entitiesDB.QueryEntity<RotationEntityStruct>(id);
  137. var scale = entitiesDB.QueryEntity<ScalingEntityStruct>(id);
  138. entitiesDB.QueryEntity<RenderingDataStruct>(id).matrix = float4x4.TRS(pos.position, rot.rotation, scale.scale);
  139. }
  140. public bool BlockExists(EGID blockID)
  141. {
  142. return entitiesDB.Exists<DBEntityStruct>(blockID);
  143. }
  144. public bool GetBlockInfoExists<T>(Block block) where T : struct, IEntityComponent
  145. {
  146. if (entitiesDB.Exists<T>(block.Id))
  147. return true;
  148. if (block.InitData.Group == null)
  149. return false;
  150. var init = new EntityComponentInitializer(block.Id, block.InitData.Group);
  151. return init.Has<T>();
  152. }
  153. public SimBody[] GetSimBodiesFromID(byte id)
  154. {
  155. var ret = new FasterList<SimBody>(4);
  156. var oide = entitiesDB.QueryEntities<ObjectIdEntityStruct>();
  157. EGIDMapper<GridConnectionsEntityStruct>? connections = null;
  158. foreach (var ((oids, count), _) in oide)
  159. {
  160. for (int i = 0; i < count; i++)
  161. {
  162. ref ObjectIdEntityStruct oid = ref oids[i];
  163. if (oid.objectId != id) continue;
  164. if (!connections.HasValue) //Would need reflection to get the group from the build group otherwise
  165. connections = entitiesDB.QueryMappedEntities<GridConnectionsEntityStruct>(oid.ID.groupID);
  166. var rid = connections.Value.Entity(oid.ID.entityID).machineRigidBodyId;
  167. foreach (var rb in ret)
  168. {
  169. if (rb.Id.entityID == rid)
  170. goto DUPLICATE; //Multiple Object Identifiers on one rigid body
  171. }
  172. ret.Add(new SimBody(rid));
  173. DUPLICATE: ;
  174. }
  175. }
  176. return ret.ToArray();
  177. }
  178. public ObjectIdentifier[] GetObjectIDsFromID(byte id, bool sim)
  179. {
  180. var ret = new FasterList<ObjectIdentifier>(4);
  181. var oide = entitiesDB.QueryEntities<ObjectIdEntityStruct>();
  182. foreach (var ((oids, count), _) in oide)
  183. {
  184. for (int i = 0; i < count; i++)
  185. {
  186. ref ObjectIdEntityStruct oid = ref oids[i];
  187. if (sim ? oid.simObjectId == id : oid.objectId == id)
  188. ret.Add(new ObjectIdentifier(oid.ID));
  189. }
  190. }
  191. return ret.ToArray();
  192. }
  193. public SimBody[] GetConnectedSimBodies(uint id)
  194. {
  195. var joints = entitiesDB.QueryEntities<JointEntityStruct>(MachineSimulationGroups.JOINTS_GROUP).ToBuffer();
  196. var list = new FasterList<SimBody>(4);
  197. for (int i = 0; i < joints.count; i++)
  198. {
  199. ref var joint = ref joints.buffer[i];
  200. if (joint.isBroken) continue;
  201. if (joint.connectedEntityA == id) list.Add(new SimBody(joint.connectedEntityB));
  202. else if (joint.connectedEntityB == id) list.Add(new SimBody(joint.connectedEntityA));
  203. }
  204. return list.ToArray();
  205. }
  206. public SimBody[] GetClusterBodies(uint cid)
  207. {
  208. var groups = entitiesDB.QueryEntities<GridConnectionsEntityStruct>();
  209. var bodies = new HashSet<uint>();
  210. foreach (var (coll, _) in groups)
  211. {
  212. var array = coll.ToBuffer().buffer;
  213. for (var index = 0; index < array.capacity; index++)
  214. {
  215. var conn = array[index];
  216. if (conn.clusterId == cid)
  217. bodies.Add(conn.machineRigidBodyId);
  218. }
  219. }
  220. return bodies.Select(id => new SimBody(id, cid)).ToArray();
  221. }
  222. public EGID? FindBlockEGID(uint id)
  223. {
  224. var groups = entitiesDB.FindGroups<DBEntityStruct>();
  225. foreach (ExclusiveGroupStruct group in groups)
  226. {
  227. if (entitiesDB.Exists<DBEntityStruct>(id, group))
  228. return new EGID(id, group);
  229. }
  230. return null;
  231. }
  232. public Cluster GetCluster(uint sbid)
  233. {
  234. var groups = entitiesDB.QueryEntities<GridConnectionsEntityStruct>();
  235. foreach (var (coll, _) in groups)
  236. {
  237. var array = coll.ToBuffer().buffer;
  238. for (var index = 0; index < array.capacity; index++)
  239. {
  240. var conn = array[index];
  241. //Static blocks don't have a cluster ID but the cluster destruction manager should have one
  242. if (conn.machineRigidBodyId == sbid && conn.clusterId != uint.MaxValue)
  243. return new Cluster(conn.clusterId);
  244. }
  245. }
  246. return null;
  247. }
  248. public Block[] GetBodyBlocks(uint sbid)
  249. {
  250. var groups = entitiesDB.QueryEntities<GridConnectionsEntityStruct>();
  251. var set = new HashSet<Block>();
  252. foreach (var (coll, _) in groups)
  253. {
  254. var array = coll.ToBuffer().buffer;
  255. for (var index = 0; index < array.capacity; index++)
  256. {
  257. var conn = array[index];
  258. if (conn.machineRigidBodyId == sbid)
  259. set.Add(new Block(conn.ID));
  260. }
  261. }
  262. return set.ToArray();
  263. }
  264. #if DEBUG
  265. public EntitiesDB GetEntitiesDB()
  266. {
  267. return entitiesDB;
  268. }
  269. #endif
  270. }
  271. }