A stable modding interface between Techblox and mods https://mod.exmods.org/
選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

BlueprintEngine.cs 19KB

Merge branch 'master' into preview # Conflicts: # Automation/gen_csproj.py # GamecraftModdingAPI/App/AppEngine.cs # GamecraftModdingAPI/App/GameGameEngine.cs # GamecraftModdingAPI/App/GameMenuEngine.cs # GamecraftModdingAPI/Block.cs # GamecraftModdingAPI/Blocks/BlockEngine.cs # GamecraftModdingAPI/Blocks/BlockEngineInit.cs # GamecraftModdingAPI/Blocks/BlockEventsEngine.cs # GamecraftModdingAPI/Blocks/BlockIDs.cs # GamecraftModdingAPI/Blocks/ConsoleBlock.cs # GamecraftModdingAPI/Blocks/DampedSpring.cs # GamecraftModdingAPI/Blocks/LogicGate.cs # GamecraftModdingAPI/Blocks/Motor.cs # GamecraftModdingAPI/Blocks/MusicBlock.cs # GamecraftModdingAPI/Blocks/ObjectIdentifier.cs # GamecraftModdingAPI/Blocks/Piston.cs # GamecraftModdingAPI/Blocks/PlacementEngine.cs # GamecraftModdingAPI/Blocks/Servo.cs # GamecraftModdingAPI/Blocks/SfxBlock.cs # GamecraftModdingAPI/Blocks/SpawnPoint.cs # GamecraftModdingAPI/Blocks/TextBlock.cs # GamecraftModdingAPI/Blocks/Timer.cs # GamecraftModdingAPI/GamecraftModdingAPI.csproj # GamecraftModdingAPI/Inventory/HotbarEngine.cs # GamecraftModdingAPI/Inventory/HotbarSlotSelectionHandlerEnginePatch.cs # GamecraftModdingAPI/Main.cs # GamecraftModdingAPI/Player.cs # GamecraftModdingAPI/Players/PlayerEngine.cs # GamecraftModdingAPI/Tests/GamecraftModdingAPIPluginTest.cs # TechbloxModdingAPI/BlockGroup.cs # TechbloxModdingAPI/Blocks/Engines/BlueprintEngine.cs # TechbloxModdingAPI/Blocks/Engines/RemovalEngine.cs # TechbloxModdingAPI/Blocks/Engines/SignalEngine.cs # TechbloxModdingAPI/Blueprint.cs # TechbloxModdingAPI/Input/FakeInput.cs
2年前
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Reflection;
  4. using Gamecraft.Blocks.BlockGroups;
  5. using Gamecraft.GUI.Blueprints;
  6. using HarmonyLib;
  7. using RobocraftX.Blocks;
  8. using RobocraftX.Blocks.Ghost;
  9. using RobocraftX.Common;
  10. using RobocraftX.CR.MachineEditing.BoxSelect;
  11. using RobocraftX.CR.MachineEditing.BoxSelect.ClipboardOperations;
  12. using RobocraftX.Physics;
  13. using RobocraftX.Rendering;
  14. using RobocraftX.Rendering.GPUI;
  15. using Svelto.DataStructures;
  16. using Svelto.ECS;
  17. using Svelto.ECS.DataStructures;
  18. using Svelto.ECS.EntityStructs;
  19. using Svelto.ECS.Native;
  20. using Svelto.ECS.Serialization;
  21. using Techblox.Blocks;
  22. using TechbloxModdingAPI.Engines;
  23. using TechbloxModdingAPI.Utility;
  24. using Unity.Collections;
  25. using Unity.Mathematics;
  26. using UnityEngine;
  27. using Allocator = Svelto.Common.Allocator;
  28. namespace TechbloxModdingAPI.Blocks.Engines
  29. {
  30. public class BlueprintEngine : IFactoryEngine
  31. {
  32. private readonly MethodInfo getBlocksFromGroup =
  33. AccessTools.Method("RobocraftX.CR.MachineEditing.PlaceBlockUtility:GetBlocksSharingBlockgroup");
  34. private NativeDynamicArray selectedBlocksInGroup;
  35. private NativeHashSet<ulong> removedConnections = new NativeHashSet<ulong>();
  36. private int addingToBlockGroup = -1;
  37. private static readonly Type PlaceBlueprintUtilityType =
  38. AccessTools.TypeByName("RobocraftX.CR.MachineEditing.PlaceBlueprintUtility");
  39. private static readonly FieldInfo LocalBlockMap =
  40. AccessTools.DeclaredField(PlaceBlueprintUtilityType, "_localBlockMap");
  41. private static readonly MethodInfo BuildBlock = AccessTools.Method(PlaceBlueprintUtilityType, "BuildBlock");
  42. private static readonly MethodInfo BuildWires = AccessTools.Method(PlaceBlueprintUtilityType, "BuildWires");
  43. private static readonly Type SerializeGhostBlueprintType =
  44. AccessTools.TypeByName("RobocraftX.CR.MachineEditing.BoxSelect.SerializeGhostChildrenOnAddEngine");
  45. private static readonly MethodInfo SerializeGhostBlueprint =
  46. AccessTools.Method(SerializeGhostBlueprintType, "SerializeClipboardGhostEntities");
  47. private static NativeEntityRemove nativeRemove;
  48. private static MachineGraphConnectionEntityFactory connectionFactory;
  49. private static IEntityFunctions entityFunctions;
  50. private static ClipboardSerializationDataResourceManager clipboardManager;
  51. private static IEntitySerialization entitySerialization;
  52. private static IEntityFactory entityFactory;
  53. private static FasterList<EGID> globalBlockMap;
  54. private static object SerializeGhostBlueprintInstance;
  55. private static GhostChildEntityFactory BuildGhostBlueprintFactory;
  56. public void Ready()
  57. {
  58. selectedBlocksInGroup = NativeDynamicArray.Alloc<EGID>(Allocator.Persistent);
  59. }
  60. public EntitiesDB entitiesDB { get; set; }
  61. public void Dispose()
  62. {
  63. selectedBlocksInGroup.Dispose();
  64. }
  65. public Block[] GetBlocksFromGroup(EGID blockID, out float3 pos, out quaternion rot)
  66. {
  67. var blockPos = default(float3);
  68. var blockRot = default(quaternion);
  69. var parameters = new object[] {blockID, selectedBlocksInGroup, entitiesDB, blockPos, blockRot};
  70. getBlocksFromGroup.Invoke(null, parameters);
  71. pos = (float3) parameters[3];
  72. rot = (quaternion) parameters[4];
  73. int count = selectedBlocksInGroup.Count<EGID>();
  74. var ret = new Block[count];
  75. for (uint i = 0; i < count; i++)
  76. ret[i] = Block.New(selectedBlocksInGroup.Get<EGID>(i));
  77. selectedBlocksInGroup.FastClear();
  78. return ret;
  79. }
  80. public void RemoveBlockGroup(int id)
  81. {
  82. BlockGroupUtility.RemoveAllBlocksInBlockGroup(id, entitiesDB, removedConnections, nativeRemove,
  83. connectionFactory, default).Complete();
  84. }
  85. public int CreateBlockGroup(float3 position, quaternion rotation)
  86. {
  87. int nextFilterId = BlockGroupUtility.NextFilterId;
  88. Factory.BuildEntity<BlockGroupEntityDescriptor>((uint) nextFilterId,
  89. BlockGroupExclusiveGroups.BlockGroupEntityGroup).Init(new BlockGroupTransformEntityComponent
  90. {
  91. blockGroupGridRotation = rotation,
  92. blockGroupGridPosition = position
  93. });
  94. return nextFilterId;
  95. }
  96. public void AddBlockToGroup(EGID blockID, int groupID)
  97. {
  98. if (globalBlockMap == null)
  99. globalBlockMap = FullGameFields._deserialisedBlockMap;
  100. if (groupID != addingToBlockGroup)
  101. {
  102. Logging.MetaDebugLog("Changing current block group from " + addingToBlockGroup + " to " + groupID);
  103. addingToBlockGroup = groupID;
  104. globalBlockMap.Clear();
  105. }
  106. globalBlockMap.Add(blockID);
  107. }
  108. public void SelectBlueprint(uint resourceID)
  109. {
  110. if (resourceID == uint.MaxValue)
  111. BlueprintUtil.UnselectBlueprint(entitiesDB);
  112. else
  113. BlueprintUtil.SelectBlueprint(entitiesDB, resourceID, false, -1);
  114. }
  115. public uint CreateBlueprint()
  116. {
  117. uint index = clipboardManager.AllocateSerializationData();
  118. return index;
  119. }
  120. public void ReplaceBlueprint(uint playerID, uint blueprintID, ICollection<Block> selected, float3 pos, quaternion rot)
  121. {
  122. var blockIDs = new EGID[selected.Count];
  123. using (var enumerator = selected.GetEnumerator())
  124. {
  125. for (var i = 0; enumerator.MoveNext(); i++)
  126. {
  127. var block = enumerator.Current;
  128. blockIDs[i] = block.Id;
  129. }
  130. }
  131. var serializationData = clipboardManager.GetSerializationData(blueprintID);
  132. SelectionSerializationUtility.ClearClipboard(playerID, entitiesDB, entityFunctions, serializationData.blueprintData, -1);
  133. if (selected.Count == 0)
  134. return;
  135. //ref BlockGroupTransformEntityComponent groupTransform = ref EntityNativeDBExtensions.QueryEntity<BlockGroupTransformEntityComponent>(entitiesDb, (uint) local1.currentBlockGroup, BlockGroupExclusiveGroups.BlockGroupEntityGroup);
  136. //ref ColliderAabb collider = ref EntityNativeDBExtensions.QueryEntity<ColliderAabb>(entitiesDB, (uint) groupID, BlockGroupExclusiveGroups.BlockGroupEntityGroup);
  137. //float3 bottomOffset = PlaceBlockUtility.GetBottomOffset(collider);
  138. //var rootPosition = math.mul(groupTransform.blockGroupGridRotation, bottomOffset) + groupTransform.blockGroupGridPosition;
  139. //var rootRotation = groupTransform.blockGroupGridRotation;
  140. clipboardManager.SetGhostSerialized(blueprintID, false);
  141. SelectionSerializationUtility.CopySelectionToClipboard(playerID, entitiesDB,
  142. serializationData.blueprintData, entitySerialization, entityFactory, blockIDs,
  143. (uint) blockIDs.Length, pos, rot, -1);
  144. BuildGhostBlueprint(selected, pos, rot, playerID);
  145. SerializeGhostBlueprint.Invoke(SerializeGhostBlueprintInstance, new object[] {playerID, blueprintID});
  146. }
  147. private void BuildGhostBlueprint(ICollection<Block> blocks, float3 pos, quaternion rot, uint playerID)
  148. {
  149. GhostChildUtility.ClearGhostChildren(playerID, entitiesDB, entityFunctions);
  150. var bssesopt = entitiesDB.QueryEntityOptional<BoxSelectStateEntityStruct>(new EGID(playerID,
  151. BoxSelectExclusiveGroups.BoxSelectVolumeExclusiveGroup));
  152. if (!bssesopt)
  153. return;
  154. foreach (var block in blocks)
  155. {
  156. GhostChildUtility.BuildGhostChild(in playerID, block.Id, in pos, in rot, entitiesDB,
  157. BuildGhostBlueprintFactory, false, bssesopt.Get().buildingDroneReference,
  158. FullGameFields._managers.blockLabelResourceManager);
  159. }
  160. }
  161. public Block[] PlaceBlueprintBlocks(uint blueprintID, uint playerID, float3 pos, float3 rot)
  162. { //RobocraftX.CR.MachineEditing.PlaceBlueprintUtility.PlaceBlocksFromSerialisedData
  163. var serializationData = clipboardManager.GetSerializationData(blueprintID);
  164. var blueprintData = serializationData.blueprintData;
  165. blueprintData.dataPos = 0U;
  166. uint selectionSize;
  167. PositionEntityStruct selectionPosition;
  168. RotationEntityStruct selectionRotation;
  169. uint version;
  170. BoxSelectSerializationUtilities.ReadClipboardHeader(blueprintData, out selectionSize, out selectionPosition, out selectionRotation, out version);
  171. ((FasterList<EGID>) LocalBlockMap.GetValue(null)).Clear();
  172. if (version <= 1U)
  173. {
  174. uint groupsCount;
  175. BoxSelectSerializationUtilities.ReadBlockGroupData(blueprintData, out groupsCount);
  176. for (int index = 0; (long) index < (long) groupsCount; ++index)
  177. {
  178. int nextFilterId = BlockGroupUtility.NextFilterId;
  179. entitySerialization.DeserializeNewEntity(new EGID((uint) nextFilterId, BlockGroupExclusiveGroups.BlockGroupEntityGroup), blueprintData, 1);
  180. }
  181. }
  182. int nextFilterId1 = BlockGroupUtility.NextFilterId;
  183. entityFactory.BuildEntity<BlockGroupEntityDescriptor>(new EGID((uint) nextFilterId1,
  184. BlockGroupExclusiveGroups.BlockGroupEntityGroup)).Init(new BlockGroupTransformEntityComponent
  185. {
  186. blockGroupGridPosition = selectionPosition.position,
  187. blockGroupGridRotation = selectionRotation.rotation
  188. });
  189. var frot = Quaternion.Euler(rot);
  190. var grid = new GridRotationStruct {position = pos, rotation = frot};
  191. var poss = new PositionEntityStruct {position = pos};
  192. var rots = new RotationEntityStruct {rotation = frot};
  193. for (int index = 0; (long) index < (long) selectionSize; ++index)
  194. BuildBlock.Invoke(null,
  195. new object[]
  196. {
  197. playerID, grid, poss, rots, selectionPosition, selectionRotation, blueprintData,
  198. entitySerialization, nextFilterId1
  199. });
  200. /*
  201. uint playerId, in GridRotationStruct ghostParentGrid,
  202. in PositionEntityStruct ghostParentPosition, in RotationEntityStruct ghostParentRotation,
  203. in PositionEntityStruct selectionPosition, in RotationEntityStruct selectionRotation,
  204. ISerializationData serializationData, EntitiesDB entitiesDb,
  205. IEntitySerialization entitySerialization, int blockGroupId
  206. */
  207. if (globalBlockMap == null)
  208. globalBlockMap = FullGameFields._deserialisedBlockMap;
  209. var placedBlocks = (FasterList<EGID>) LocalBlockMap.GetValue(null);
  210. globalBlockMap.Clear();
  211. globalBlockMap.AddRange(placedBlocks);
  212. BuildWires.Invoke(null,
  213. new object[] {playerID, blueprintData, entitySerialization, entitiesDB, entityFactory});
  214. var blocks = new Block[placedBlocks.count];
  215. for (int i = 0; i < blocks.Length; i++)
  216. blocks[i] = Block.New(placedBlocks[i]);
  217. return blocks;
  218. }
  219. public void GetBlueprintInfo(uint blueprintID, out float3 pos, out quaternion rot, out uint selectionSize)
  220. {
  221. var serializationData = clipboardManager.GetSerializationData(blueprintID);
  222. var blueprintData = serializationData.blueprintData;
  223. blueprintData.dataPos = 0U;
  224. BoxSelectSerializationUtilities.ReadClipboardHeader(blueprintData, out selectionSize, out var posst,
  225. out var rotst, out _);
  226. blueprintData.dataPos = 0U; //Just to be sure, it gets reset when it's read anyway
  227. pos = posst.position;
  228. rot = rotst.rotation;
  229. }
  230. public void InitBlueprint(uint blueprintID)
  231. {
  232. clipboardManager.IncrementRefCount(blueprintID);
  233. }
  234. public void DisposeBlueprint(uint blueprintID)
  235. {
  236. clipboardManager.DecrementRefCount(blueprintID);
  237. }
  238. //GhostChildUtility.BuildGhostChild
  239. public Block BuildGhostChild()
  240. {
  241. var sourceId = new EGID(Player.LocalPlayer.Id, GHOST_BLOCKS_ENABLED.Group);
  242. var positionEntityStruct = entitiesDB.QueryEntity<PositionEntityStruct>(sourceId);
  243. var rotationEntityStruct = entitiesDB.QueryEntity<RotationEntityStruct>(sourceId);
  244. var scalingEntityStruct = entitiesDB.QueryEntity<ScalingEntityStruct>(sourceId);
  245. var dbStruct = entitiesDB.QueryEntity<DBEntityStruct>(sourceId);
  246. var colliderStruct = entitiesDB.QueryEntity<ColliderAabb>(sourceId);
  247. var colorStruct = entitiesDB.QueryEntity<ColourParameterEntityStruct>(sourceId);
  248. uint ghostChildBlockId = CommonExclusiveGroups.GetNewGhostChildBlockID();
  249. var ghostEntityReference = GhostBlockUtils.GetGhostEntityReference(sourceId.entityID, entitiesDB);
  250. var entityInitializer = BuildGhostBlueprintFactory.Build(
  251. new EGID(ghostChildBlockId, BoxSelectExclusiveGroups.GhostChildEntitiesExclusiveGroup), /*dbStruct.DBID*/ (uint)BlockIDs.Cube,
  252. FullGameFields._managers.blockLabelResourceManager);
  253. entityInitializer.Init(dbStruct);
  254. entityInitializer.Init(new GFXPrefabEntityStructGPUI(
  255. PrefabsID.GetOrCreatePrefabID((ushort)entityInitializer.Get<PrefabAssetIDComponent>().prefabAssetID,
  256. entitiesDB.QueryEntity<CubeMaterialStruct>(sourceId).materialId, 7,
  257. FlippedBlockUtils.IsFlipped(in scalingEntityStruct.scale)), true));
  258. entityInitializer.Init(entitiesDB.QueryEntity<CubeMaterialStruct>(sourceId));
  259. entityInitializer.Init(new GhostParentEntityStruct
  260. {
  261. ghostBlockParentEntityReference = ghostEntityReference,
  262. ownerMustSerializeOnAdd = false
  263. });
  264. entityInitializer.Init(colorStruct);
  265. entityInitializer.Init(colliderStruct);
  266. entityInitializer.Init(new RigidBodyEntityStruct
  267. {
  268. position = positionEntityStruct.position,
  269. rotation = rotationEntityStruct.rotation
  270. });
  271. entityInitializer.Init(new ScalingEntityStruct
  272. {
  273. scale = scalingEntityStruct.scale
  274. });
  275. entityInitializer.Init(new LocalTransformEntityStruct
  276. {
  277. position = positionEntityStruct.position,
  278. rotation = rotationEntityStruct.rotation
  279. });
  280. entityInitializer.Init(new RotationEntityStruct
  281. {
  282. rotation = rotationEntityStruct.rotation
  283. });
  284. entityInitializer.Init(new PositionEntityStruct
  285. {
  286. position = positionEntityStruct.position
  287. });
  288. entityInitializer.Init(new SkewComponent
  289. {
  290. skewMatrix = entitiesDB.QueryEntity<SkewComponent>(sourceId).skewMatrix
  291. });
  292. entityInitializer.Init(new BlockPlacementInfoStruct
  293. {
  294. placedByBuildingDrone = entitiesDB
  295. .QueryEntityOptional<BoxSelectStateEntityStruct>(new EGID(Player.LocalPlayer.Id,
  296. BoxSelectExclusiveGroups.BoxSelectVolumeExclusiveGroup)).Get().buildingDroneReference
  297. });
  298. entityInitializer.Init(new GridRotationStruct
  299. {
  300. position = float3.zero,
  301. rotation = quaternion.identity
  302. });
  303. var block = Block.New(entityInitializer.EGID);
  304. block.InitData = entityInitializer;
  305. return block;
  306. }
  307. public string Name { get; } = "TechbloxModdingAPIBlueprintGameEngine";
  308. public bool isRemovable { get; } = false;
  309. [HarmonyPatch]
  310. private static class RemoveEnginePatch
  311. {
  312. public static void Prefix(IEntityFunctions entityFunctions,
  313. MachineGraphConnectionEntityFactory machineGraphConnectionEntityFactory)
  314. {
  315. nativeRemove = entityFunctions.ToNativeRemove<BlockEntityDescriptor>("GCAPI" + nameof(BlueprintEngine));
  316. connectionFactory = machineGraphConnectionEntityFactory;
  317. BlueprintEngine.entityFunctions = entityFunctions;
  318. }
  319. public static MethodBase TargetMethod()
  320. {
  321. return AccessTools.GetDeclaredConstructors(AccessTools.TypeByName("RobocraftX.CR.MachineEditing.RemoveBlockEngine"))[0];
  322. }
  323. }
  324. [HarmonyPatch]
  325. private static class SelectEnginePatch
  326. {
  327. public static void Prefix(ClipboardSerializationDataResourceManager clipboardSerializationDataResourceManager,
  328. IEntitySerialization entitySerialization,
  329. IEntityFactory entityFactory)
  330. {
  331. clipboardManager = clipboardSerializationDataResourceManager;
  332. BlueprintEngine.entitySerialization = entitySerialization;
  333. BlueprintEngine.entityFactory = entityFactory;
  334. }
  335. public static MethodBase TargetMethod()
  336. {
  337. return AccessTools.GetDeclaredConstructors(AccessTools.TypeByName("RobocraftX.CR.MachineEditing.SelectBlockEngine"))[0];
  338. }
  339. }
  340. [HarmonyPatch]
  341. private static class SerializeGhostBlueprintPatch
  342. {
  343. public static void Postfix(object __instance)
  344. {
  345. SerializeGhostBlueprintInstance = __instance;
  346. }
  347. public static MethodBase TargetMethod()
  348. {
  349. return AccessTools.GetDeclaredConstructors(SerializeGhostBlueprintType)[0];
  350. }
  351. }
  352. [HarmonyPatch]
  353. private static class BuildGhostBlueprintPatch
  354. {
  355. public static void Postfix(GhostChildEntityFactory ghostChildEntityFactory)
  356. {
  357. BuildGhostBlueprintFactory = ghostChildEntityFactory;
  358. }
  359. public static MethodBase TargetMethod()
  360. {
  361. return AccessTools.GetDeclaredConstructors(AccessTools.TypeByName("RobocraftX.CR.MachineEditing.BuildGhostChildForMultiblockPickEngine"))[0];
  362. }
  363. }
  364. public IEntityFactory Factory { get; set; }
  365. }
  366. }