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.

131 lines
5.7KB

  1. using System.Reflection;
  2. using DataLoader;
  3. using Gamecraft.Blocks.BlockGroups;
  4. using Gamecraft.Wires;
  5. using HarmonyLib;
  6. using RobocraftX.Blocks;
  7. using RobocraftX.Character;
  8. using RobocraftX.Common;
  9. using RobocraftX.CR.MachineEditing.BoxSelect;
  10. using RobocraftX.Rendering;
  11. using RobocraftX.Rendering.GPUI;
  12. using Svelto.ECS;
  13. using Svelto.ECS.EntityStructs;
  14. using Unity.Mathematics;
  15. using TechbloxModdingAPI.Engines;
  16. using TechbloxModdingAPI.Utility;
  17. using TechbloxModdingAPI.Utility.ECS;
  18. namespace TechbloxModdingAPI.Blocks.Engines
  19. {
  20. /// <summary>
  21. /// Engine which executes block placement actions
  22. /// </summary>
  23. public class PlacementEngine : IApiEngine
  24. {
  25. public bool IsInGame;
  26. public void Dispose()
  27. {
  28. IsInGame = false;
  29. }
  30. public void Ready()
  31. {
  32. IsInGame = true;
  33. }
  34. public EntitiesDB entitiesDB { get; set; }
  35. private static BlockEntityFactory _blockEntityFactory; //Injected from PlaceSingleBlockEngine
  36. private static IEntityFactory _entityFactory;
  37. public EntityInitializer PlaceBlock(BlockIDs block, float3 position, Player player, bool autoWire)
  38. { //It appears that only the non-uniform scale has any visible effect, but if that's not given here it will be set to the uniform one
  39. return BuildBlock((ushort) block, position, autoWire, (player ?? Player.LocalPlayer).Id);
  40. }
  41. private EntityInitializer BuildBlock(ushort block, float3 position, bool autoWire, uint playerId)
  42. {
  43. if (_blockEntityFactory == null)
  44. throw new BlockException("The factory is null.");
  45. if(!FullGameFields._dataDb.ContainsKey<CubeListData>(block))
  46. throw new BlockException("Block with ID " + block + " not found!");
  47. //RobocraftX.CR.MachineEditing.PlaceSingleBlockEngine
  48. DBEntityStruct dbEntity = new DBEntityStruct {DBID = block};
  49. EntityInitializer structInitializer = _blockEntityFactory.Build(CommonExclusiveGroups.blockIDGeneratorClient.Next(), block); //The ghost block index is only used for triggers
  50. uint prefabAssetID = structInitializer.Has<PrefabAssetIDComponent>()
  51. ? structInitializer.Get<PrefabAssetIDComponent>().prefabAssetID
  52. : throw new BlockException("Prefab asset ID not found!"); //Set by the game
  53. uint prefabId = PrefabsID.GetOrAddPrefabID((ushort) prefabAssetID, (byte) BlockMaterial.SteelBodywork, 1, false);
  54. structInitializer.Init(new GFXPrefabEntityStructGPUI(prefabId));
  55. structInitializer.Init(dbEntity);
  56. structInitializer.Init(new PositionEntityStruct {position = position});
  57. structInitializer.Init(new RotationEntityStruct {rotation = quaternion.identity});
  58. structInitializer.Init(new ScalingEntityStruct {scale = new float3(1, 1, 1)});
  59. structInitializer.Init(new GridRotationStruct
  60. {
  61. position = position,
  62. rotation = quaternion.identity
  63. });
  64. structInitializer.Init(new UniformBlockScaleEntityStruct {scaleFactor = 1});
  65. structInitializer.Get<CubeMaterialStruct>().materialId = (byte) BlockMaterial.SteelBodywork;
  66. var bssesopt = entitiesDB.QueryEntityOptional<BoxSelectStateEntityStruct>(new EGID(playerId,
  67. BoxSelectExclusiveGroups.BoxSelectVolumeExclusiveGroup));
  68. if (!bssesopt)
  69. throw new BlockException("Invalid player ID specified for block placement");
  70. structInitializer.Init(new BlockPlacementInfoStruct
  71. {
  72. loadedFromDisk = false,
  73. placedByBuildingDrone = bssesopt.Get().buildingDroneReference,
  74. triggerAutoWiring = autoWire && structInitializer.Has<BlockPortsStruct>()
  75. });
  76. int nextFilterId = BlockGroupUtility.NextFilterId;
  77. structInitializer.Init(new BlockGroupEntityComponent
  78. {
  79. currentBlockGroup = nextFilterId
  80. });
  81. _entityFactory.BuildEntity<BlockGroupEntityDescriptor>((uint) nextFilterId,
  82. BlockGroupExclusiveGroups.BlockGroupEntityGroup)
  83. .Init(new BlockGroupTransformEntityComponent
  84. {
  85. blockGroupGridRotation = quaternion.identity,
  86. blockGroupGridPosition = position
  87. });
  88. foreach (var group in CharacterExclusiveGroups.AllCharacters)
  89. {
  90. EGID playerEGID = new EGID(playerId, group);
  91. if (!entitiesDB.TryQueryEntitiesAndIndex<PickedBlockExtraDataStruct>(playerEGID, out uint index,
  92. out var array)) continue;
  93. ref PickedBlockExtraDataStruct pickedBlock = ref array[index];
  94. pickedBlock.placedBlockEntityID = structInitializer.EGID;
  95. pickedBlock.placedBlockWasAPickedBlock = false;
  96. }
  97. return structInitializer;
  98. }
  99. public string Name => "TechbloxModdingAPIPlacementGameEngine";
  100. public bool isRemovable => false;
  101. [HarmonyPatch]
  102. class FactoryObtainerPatch
  103. {
  104. static void Postfix(BlockEntityFactory blockEntityFactory, IEntityFactory entityFactory)
  105. {
  106. _blockEntityFactory = blockEntityFactory;
  107. _entityFactory = entityFactory;
  108. Logging.MetaDebugLog("Block entity factory injected.");
  109. }
  110. static MethodBase TargetMethod(Harmony instance)
  111. {
  112. return AccessTools.TypeByName("RobocraftX.CR.MachineEditing.PlaceSingleBlockEngine").GetConstructors()[0];
  113. }
  114. }
  115. }
  116. }