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.

244 lines
7.6KB

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