A stable modding interface between Techblox and mods https://mod.exmods.org/
您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

243 行
7.0KB

  1. using System.Collections.Generic;
  2. using System.Linq;
  3. using Gamecraft.ColourPalette;
  4. using Gamecraft.TimeRunning;
  5. using Gamecraft.Wires;
  6. using RobocraftX.Blocks;
  7. using RobocraftX.Common;
  8. using RobocraftX.Physics;
  9. using RobocraftX.Rendering;
  10. using RobocraftX.Rendering.GPUI;
  11. using Svelto.DataStructures;
  12. using Svelto.ECS;
  13. using Svelto.ECS.EntityStructs;
  14. using Svelto.ECS.Hybrid;
  15. using Unity.Mathematics;
  16. using TechbloxModdingAPI.Engines;
  17. using TechbloxModdingAPI.Utility;
  18. namespace TechbloxModdingAPI.Blocks.Engines
  19. {
  20. /// <summary>
  21. /// Engine for executing general block actions
  22. /// </summary>
  23. public partial class BlockEngine : IApiEngine
  24. {
  25. public string Name { get; } = "TechbloxModdingAPIBlockGameEngine";
  26. public EntitiesDB entitiesDB { set; private get; }
  27. public bool isRemovable => false;
  28. public void Dispose()
  29. {
  30. }
  31. public void Ready()
  32. {
  33. }
  34. public Block[] GetConnectedBlocks(EGID blockID)
  35. {
  36. if (!BlockExists(blockID)) return new Block[0];
  37. Stack<EGID> cubeStack = new Stack<EGID>();
  38. FasterList<EGID> cubes = new FasterList<EGID>(10);
  39. var coll = entitiesDB.QueryEntities<GridConnectionsEntityStruct>();
  40. foreach (var (ecoll, _) in coll)
  41. {
  42. var ecollB = ecoll.ToBuffer();
  43. for(int i = 0; i < ecoll.count; i++)
  44. {
  45. ref var conn = ref ecollB.buffer[i];
  46. conn.isProcessed = false;
  47. }
  48. }
  49. ConnectedCubesUtility.TreeTraversal.GetConnectedCubes(entitiesDB, blockID, cubeStack, cubes,
  50. (in GridConnectionsEntityStruct g) => { return false; });
  51. var ret = new Block[cubes.count];
  52. for (int i = 0; i < cubes.count; i++)
  53. ret[i] = Block.New(cubes[i]);
  54. return ret;
  55. }
  56. public float4 ConvertBlockColor(byte index) => index == byte.MaxValue
  57. ? new float4(-1f, -1f, -1f, -1f)
  58. : entitiesDB.QueryEntity<PaletteEntryEntityStruct>(index,
  59. CommonExclusiveGroups.COLOUR_PALETTE_GROUP).Colour;
  60. public OptionalRef<T> GetBlockInfoOptional<T>(Block block) where T : unmanaged, IEntityComponent
  61. {
  62. return entitiesDB.QueryEntityOptional<T>(block);
  63. }
  64. public ref T GetBlockInfo<T>(Block block) where T : unmanaged, IEntityComponent
  65. {
  66. return ref entitiesDB.QueryEntityOrDefault<T>(block);
  67. }
  68. internal ref T GetBlockInfo<T>(EcsObjectBase obj) where T : unmanaged, IEntityComponent
  69. {
  70. return ref entitiesDB.QueryEntityOrDefault<T>(obj);
  71. }
  72. public ref T GetBlockInfoViewComponent<T>(Block block) where T : struct, IEntityViewComponent
  73. {
  74. return ref entitiesDB.QueryEntityOrDefault<T>(block);
  75. }
  76. public void UpdateDisplayedBlock(EGID id)
  77. {
  78. if (!BlockExists(id)) return;
  79. var pos = entitiesDB.QueryEntity<PositionEntityStruct>(id);
  80. var rot = entitiesDB.QueryEntity<RotationEntityStruct>(id);
  81. var scale = entitiesDB.QueryEntity<ScalingEntityStruct>(id);
  82. entitiesDB.QueryEntity<RenderingDataStruct>(id).matrix = float4x4.TRS(pos.position, rot.rotation, scale.scale);
  83. }
  84. internal void UpdatePrefab(Block block, byte material, bool flipped)
  85. {
  86. var prefabAssetIDOpt = entitiesDB.QueryEntityOptional<PrefabAssetIDComponent>(block);
  87. uint prefabAssetID = prefabAssetIDOpt
  88. ? prefabAssetIDOpt.Get().prefabAssetID
  89. : uint.MaxValue;
  90. if (prefabAssetID == uint.MaxValue)
  91. {
  92. if (entitiesDB.QueryEntityOptional<DBEntityStruct>(block)) //The block exists
  93. throw new BlockException("Prefab asset ID not found for block " + block); //Set by the game
  94. return;
  95. }
  96. uint prefabId =
  97. PrefabsID.GetOrCreatePrefabID((ushort) prefabAssetID, material, 1, flipped);
  98. entitiesDB.QueryEntityOrDefault<GFXPrefabEntityStructGPUI>(block).prefabID = prefabId;
  99. if (block.Exists)
  100. entitiesDB.PublishEntityChange<GFXPrefabEntityStructGPUI>(block.Id);
  101. //Phyiscs prefab: prefabAssetID, set on block creation from the CubeListData
  102. }
  103. public bool BlockExists(EGID blockID)
  104. {
  105. return entitiesDB.Exists<DBEntityStruct>(blockID);
  106. }
  107. public SimBody[] GetSimBodiesFromID(byte id)
  108. {
  109. var ret = new FasterList<SimBody>(4);
  110. var oide = entitiesDB.QueryEntities<ObjectIdEntityStruct>();
  111. EGIDMapper<GridConnectionsEntityStruct>? connections = null;
  112. foreach (var ((oids, count), _) in oide)
  113. {
  114. for (int i = 0; i < count; i++)
  115. {
  116. ref ObjectIdEntityStruct oid = ref oids[i];
  117. if (oid.objectId != id) continue;
  118. if (!connections.HasValue) //Would need reflection to get the group from the build group otherwise
  119. connections = entitiesDB.QueryMappedEntities<GridConnectionsEntityStruct>(oid.ID.groupID);
  120. var rid = connections.Value.Entity(oid.ID.entityID).machineRigidBodyId;
  121. foreach (var rb in ret)
  122. {
  123. if (rb.Id.entityID == rid)
  124. goto DUPLICATE; //Multiple Object Identifiers on one rigid body
  125. }
  126. ret.Add(new SimBody(rid));
  127. DUPLICATE: ;
  128. }
  129. }
  130. return ret.ToArray();
  131. }
  132. public SimBody[] GetConnectedSimBodies(uint id)
  133. {
  134. var joints = entitiesDB.QueryEntities<JointEntityStruct>(MachineSimulationGroups.JOINTS_GROUP).ToBuffer();
  135. var list = new FasterList<SimBody>(4);
  136. for (int i = 0; i < joints.count; i++)
  137. {
  138. ref var joint = ref joints.buffer[i];
  139. if (joint.isBroken) continue;
  140. if (joint.connectedEntityA == id) list.Add(new SimBody(joint.connectedEntityB));
  141. else if (joint.connectedEntityB == id) list.Add(new SimBody(joint.connectedEntityA));
  142. }
  143. return list.ToArray();
  144. }
  145. public SimBody[] GetClusterBodies(uint cid)
  146. {
  147. var groups = entitiesDB.QueryEntities<GridConnectionsEntityStruct>();
  148. var bodies = new HashSet<uint>();
  149. foreach (var (coll, _) in groups)
  150. {
  151. var array = coll.ToBuffer().buffer;
  152. for (var index = 0; index < array.capacity; index++)
  153. {
  154. var conn = array[index];
  155. if (conn.clusterId == cid)
  156. bodies.Add(conn.machineRigidBodyId);
  157. }
  158. }
  159. return bodies.Select(id => new SimBody(id, cid)).ToArray();
  160. }
  161. public EGID? FindBlockEGID(uint id)
  162. {
  163. var groups = entitiesDB.FindGroups<DBEntityStruct>();
  164. foreach (ExclusiveGroupStruct group in groups)
  165. {
  166. if (entitiesDB.Exists<DBEntityStruct>(id, group))
  167. return new EGID(id, group);
  168. }
  169. return null;
  170. }
  171. public Cluster GetCluster(uint sbid)
  172. {
  173. var groups = entitiesDB.QueryEntities<GridConnectionsEntityStruct>();
  174. foreach (var (coll, _) in groups)
  175. {
  176. var array = coll.ToBuffer().buffer;
  177. for (var index = 0; index < array.capacity; index++)
  178. {
  179. var conn = array[index];
  180. //Static blocks don't have a cluster ID but the cluster destruction manager should have one
  181. if (conn.machineRigidBodyId == sbid && conn.clusterId != uint.MaxValue)
  182. return new Cluster(conn.clusterId);
  183. }
  184. }
  185. return null;
  186. }
  187. public Block[] GetBodyBlocks(uint sbid)
  188. {
  189. var groups = entitiesDB.QueryEntities<GridConnectionsEntityStruct>();
  190. var set = new HashSet<Block>();
  191. foreach (var (coll, _) in groups)
  192. {
  193. var array = coll.ToBuffer().buffer;
  194. for (var index = 0; index < array.capacity; index++)
  195. {
  196. var conn = array[index];
  197. if (conn.machineRigidBodyId == sbid)
  198. set.Add(Block.New(conn.ID));
  199. }
  200. }
  201. return set.ToArray();
  202. }
  203. #if DEBUG
  204. public EntitiesDB GetEntitiesDB()
  205. {
  206. return entitiesDB;
  207. }
  208. #endif
  209. }
  210. }