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.

140 lines
5.7KB

  1. using System;
  2. using System.Reflection;
  3. using DataLoader;
  4. using HarmonyLib;
  5. using RobocraftX.Blocks;
  6. using RobocraftX.Blocks.Scaling;
  7. using RobocraftX.Character;
  8. using RobocraftX.Common;
  9. using RobocraftX.CR.MachineEditing;
  10. using Svelto.ECS;
  11. using Svelto.ECS.EntityStructs;
  12. using Unity.Mathematics;
  13. using UnityEngine;
  14. using GamecraftModdingAPI.Utility;
  15. using GamecraftModdingAPI.Engines;
  16. using GamecraftModdingAPI.Players;
  17. using RobocraftX.Rendering.GPUI;
  18. namespace GamecraftModdingAPI.Blocks
  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. public EGID PlaceBlock(BlockIDs block, BlockColors color, byte darkness, float3 position, int uscale,
  37. float3 scale, Player player, float3 rotation, out EntityInitializer initializer)
  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. if (darkness > 9)
  40. throw new Exception("That is too dark. Make sure to use 0-9 as darkness. (0 is default.)");
  41. initializer = BuildBlock((ushort) block, (byte) (color + darkness * 10), position, uscale, scale, rotation,
  42. (player ?? new Player(PlayerType.Local)).Id);
  43. return initializer.EGID;
  44. }
  45. private EntityInitializer BuildBlock(ushort block, byte color, float3 position, int uscale, float3 scale, float3 rot, uint playerId)
  46. {
  47. if (_blockEntityFactory == null)
  48. throw new BlockException("The factory is null.");
  49. if (uscale < 1)
  50. throw new BlockException("Scale needs to be at least 1");
  51. if (scale.x < 4e-5) scale.x = uscale;
  52. if (scale.y < 4e-5) scale.y = uscale;
  53. if (scale.z < 4e-5) scale.z = uscale;
  54. uint resourceId = (uint) PrefabsID.GenerateResourceID(0, block);
  55. if (!PrefabsID.PrefabIDByResourceIDMap.ContainsKey(resourceId))
  56. throw new BlockException("Block with ID " + block + " not found!");
  57. //RobocraftX.CR.MachineEditing.PlaceSingleBlockEngine
  58. ScalingEntityStruct scaling = new ScalingEntityStruct {scale = scale};
  59. Quaternion rotQ = Quaternion.Euler(rot);
  60. RotationEntityStruct rotation = new RotationEntityStruct {rotation = rotQ};
  61. GridRotationStruct gridRotation = new GridRotationStruct
  62. {position = position, rotation = rotQ};
  63. DBEntityStruct dbEntity = new DBEntityStruct {DBID = block};
  64. BlockPlacementScaleEntityStruct placementScale = new BlockPlacementScaleEntityStruct
  65. {
  66. blockPlacementHeight = uscale, blockPlacementWidth = uscale, desiredScaleFactor = uscale
  67. };
  68. EntityInitializer structInitializer = _blockEntityFactory.Build(CommonExclusiveGroups.nextBlockEntityID, block); //The ghost block index is only used for triggers
  69. if (color != byte.MaxValue)
  70. structInitializer.Init(new ColourParameterEntityStruct
  71. {
  72. indexInPalette = color,
  73. hasNetworkChange = true
  74. });
  75. structInitializer.Init(new CubeMaterialStruct
  76. {
  77. materialId = 0, //TODO
  78. cosmeticallyPaintedOnly = true //TODO
  79. });
  80. uint prefabId = PrefabsID.GetOrCreatePrefabID(block, 0, 0, false); //TODO
  81. structInitializer.Init(new GFXPrefabEntityStructGPUI(prefabId));
  82. structInitializer.Init(new PhysicsPrefabEntityStruct(prefabId));
  83. structInitializer.Init(dbEntity);
  84. structInitializer.Init(new PositionEntityStruct {position = position});
  85. structInitializer.Init(rotation);
  86. structInitializer.Init(scaling);
  87. structInitializer.Init(gridRotation);
  88. structInitializer.Init(new UniformBlockScaleEntityStruct
  89. {
  90. scaleFactor = placementScale.desiredScaleFactor
  91. });
  92. structInitializer.Init(new BlockPlacementInfoStruct()
  93. {
  94. loadedFromDisk = false,
  95. placedBy = playerId,
  96. triggerAutoWiring = false //TODO
  97. });
  98. /*structInitializer.Init(new CollisionFilterOverride
  99. {
  100. belongsTo = 32U,
  101. collidesWith = 239532U
  102. });*/
  103. EGID playerEGID = new EGID(playerId, CharacterExclusiveGroups.OnFootGroup);
  104. ref PickedBlockExtraDataStruct pickedBlock = ref entitiesDB.QueryEntity<PickedBlockExtraDataStruct>(playerEGID);
  105. pickedBlock.placedBlockEntityID = structInitializer.EGID;
  106. pickedBlock.placedBlockWasAPickedBlock = false;
  107. return structInitializer;
  108. }
  109. public string Name { get; } = "GamecraftModdingAPIPlacementGameEngine";
  110. public bool isRemovable => false;
  111. [HarmonyPatch]
  112. public class FactoryObtainerPatch
  113. {
  114. static void Postfix(BlockEntityFactory blockEntityFactory)
  115. {
  116. _blockEntityFactory = blockEntityFactory;
  117. Logging.MetaDebugLog("Block entity factory injected.");
  118. }
  119. static MethodBase TargetMethod(Harmony instance)
  120. {
  121. return AccessTools.TypeByName("RobocraftX.CR.MachineEditing.PlaceSingleBlockEngine").GetConstructors()[0];
  122. }
  123. }
  124. }
  125. }