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.

274 lines
8.2KB

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