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.

204 lines
6.7KB

  1. using System.Runtime.CompilerServices;
  2. using RobocraftX.Character;
  3. using RobocraftX.Character.Movement;
  4. using RobocraftX.Common.Players;
  5. using RobocraftX.Common.Input;
  6. using RobocraftX.CR.MachineEditing.BoxSelect;
  7. using RobocraftX.Physics;
  8. using RobocraftX.Blocks.Ghost;
  9. using Gamecraft.GUI.HUDFeedbackBlocks;
  10. using Svelto.ECS;
  11. using Techblox.Camera;
  12. using Unity.Mathematics;
  13. using Svelto.ECS.DataStructures;
  14. using Techblox.BuildingDrone;
  15. using TechbloxModdingAPI.Engines;
  16. using TechbloxModdingAPI.Utility;
  17. namespace TechbloxModdingAPI.Players
  18. {
  19. internal class PlayerEngine : IApiEngine, IFactoryEngine
  20. {
  21. public string Name { get; } = "TechbloxModdingAPIPlayerGameEngine";
  22. public EntitiesDB entitiesDB { set; private get; }
  23. public bool isRemovable => false;
  24. public IEntityFactory Factory { set; private get; }
  25. private bool isReady = false;
  26. public void Dispose()
  27. {
  28. isReady = false;
  29. }
  30. public void Ready()
  31. {
  32. isReady = true;
  33. }
  34. public uint GetLocalPlayer()
  35. {
  36. if (!isReady) return uint.MaxValue;
  37. var localPlayers = entitiesDB.QueryEntities<PlayerIDStruct>(PlayersExclusiveGroups.LocalPlayers).ToBuffer();
  38. if (localPlayers.count > 0)
  39. {
  40. return localPlayers.buffer[0].ID.entityID;
  41. }
  42. return uint.MaxValue;
  43. }
  44. public uint GetRemotePlayer()
  45. {
  46. if (!isReady) return uint.MaxValue;
  47. var localPlayers = entitiesDB.QueryEntities<PlayerIDStruct>(PlayersExclusiveGroups.RemotePlayers).ToBuffer();
  48. if (localPlayers.count > 0)
  49. {
  50. return localPlayers.buffer[0].ID.entityID;
  51. }
  52. return uint.MaxValue;
  53. }
  54. public long GetAllPlayerCount()
  55. {
  56. if (entitiesDB == null) return 0;
  57. long count = 0;
  58. foreach (ExclusiveGroupStruct eg in PlayersExclusiveGroups.AllPlayers)
  59. {
  60. count += entitiesDB.Count<PlayerIDStruct>(eg);
  61. }
  62. return count;
  63. }
  64. public long GetLocalPlayerCount()
  65. {
  66. if (entitiesDB == null) return 0;
  67. return entitiesDB.Count<PlayerIDStruct>(PlayersExclusiveGroups.LocalPlayers);
  68. }
  69. public long GetRemotePlayerCount()
  70. {
  71. if (entitiesDB == null) return 0;
  72. return entitiesDB.Count<PlayerIDStruct>(PlayersExclusiveGroups.RemotePlayers);
  73. }
  74. public bool ExistsById(uint playerId)
  75. {
  76. if (entitiesDB == null) return false;
  77. return entitiesDB.Exists<PlayerIDStruct>(playerId, PlayersExclusiveGroups.LocalPlayers)
  78. || entitiesDB.Exists<PlayerIDStruct>(playerId, PlayersExclusiveGroups.RemotePlayers);
  79. }
  80. public bool SetLocation(uint playerId, float3 location, bool exitSeat = true)
  81. {
  82. if (entitiesDB == null) return false;
  83. var rbesOpt = GetCharacterStruct<RigidBodyEntityStruct>(playerId, out var group);
  84. if (!rbesOpt)
  85. return false;
  86. if (group == CharacterExclusiveGroups.InPilotSeatGroup && exitSeat)
  87. {
  88. EGID egid = new EGID(playerId, group);
  89. entitiesDB.QueryEntity<CharacterPilotSeatEntityStruct>(egid).instantExit = true;
  90. entitiesDB.PublishEntityChange<CharacterPilotSeatEntityStruct>(egid);
  91. }
  92. rbesOpt.Get().position = location;
  93. return true;
  94. }
  95. public bool GetGameOverScreen(uint playerId)
  96. {
  97. if (entitiesDB == null) return false;
  98. ref HudActivatedBlocksEntityStruct habes = ref entitiesDB.QueryEntity<HudActivatedBlocksEntityStruct>(HUDFeedbackBlocksGUIExclusiveGroups.GameOverHudEgid);
  99. NativeDynamicArrayCast<EGID> nativeDynamicArrayCast = new NativeDynamicArrayCast<EGID>(habes.activatedBlocksOrdered);
  100. return nativeDynamicArrayCast.count > 0;
  101. }
  102. public bool IsDead(uint playerId)
  103. {
  104. if (entitiesDB == null) return true;
  105. return entitiesDB.Exists<RigidBodyEntityStruct>(playerId, CharacterExclusiveGroups.DeadCharacters);
  106. }
  107. // reusable methods
  108. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  109. public OptionalRef<T> GetCharacterStruct<T>(uint playerId) where T : unmanaged, IEntityComponent =>
  110. GetCharacterStruct<T>(playerId, out _);
  111. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  112. public OptionalRef<T> GetCharacterStruct<T>(uint playerId, out ExclusiveGroupStruct group) where T : unmanaged, IEntityComponent
  113. {
  114. group = default;
  115. if (GameState.IsBuildMode())
  116. return entitiesDB.QueryEntityOptional<T>(new EGID(playerId, LocalBuildingDrone.BuildGroup));
  117. var characterGroups = CharacterExclusiveGroups.AllCharacters;
  118. for (int i = 0; i < characterGroups.count; i++)
  119. {
  120. EGID egid = new EGID(playerId, characterGroups[i]);
  121. var opt = entitiesDB.QueryEntityOptional<T>(egid);
  122. if (opt.Exists)
  123. {
  124. group = characterGroups[i];
  125. return opt;
  126. }
  127. }
  128. return new OptionalRef<T>();
  129. }
  130. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  131. public OptionalRef<T> GetPlayerStruct<T>(uint playerId, PlayerType type) where T : unmanaged, IEntityComponent
  132. {
  133. var playerGroup = type == PlayerType.Local ? PlayersExclusiveGroups.LocalPlayers : PlayersExclusiveGroups.RemotePlayers;
  134. EGID egid = new EGID(playerId, playerGroup);
  135. return entitiesDB.QueryEntityOptional<T>(egid);
  136. }
  137. public OptionalRef<T> GetCameraStruct<T>(uint playerId) where T : unmanaged, IEntityComponent
  138. {
  139. return entitiesDB.QueryEntityOptional<T>(new EGID(playerId, CameraExclusiveGroups.PhysicCameraGroup));
  140. }
  141. public EGID GetThingLookedAt(uint playerId, float maxDistance = -1f)
  142. {
  143. var opt = GetCameraStruct<PhysicCameraRayCastEntityStruct>(playerId);
  144. if (!opt) return default;
  145. PhysicCameraRayCastEntityStruct rayCast = opt;
  146. float distance = maxDistance < 0
  147. ? GhostBlockUtils.GetBuildInteractionDistance(entitiesDB, rayCast,
  148. GhostBlockUtils.GhostCastMethod.GhostCastProportionalToBlockSize)
  149. : maxDistance;
  150. if (rayCast.hit && rayCast.distance <= distance)
  151. return rayCast.hitEgid; //May be EGID.Empty (default)
  152. return default;
  153. }
  154. public unsafe Block[] GetSelectedBlocks(uint playerid)
  155. {
  156. if (!entitiesDB.Exists<BoxSelectStateEntityStruct>(playerid,
  157. BoxSelectExclusiveGroups.BoxSelectVolumeExclusiveGroup))
  158. return new Block[0];
  159. var state = entitiesDB.QueryEntity<BoxSelectStateEntityStruct>(playerid,
  160. BoxSelectExclusiveGroups.BoxSelectVolumeExclusiveGroup);
  161. var blocks = entitiesDB.QueryEntity<SelectedBlocksStruct>(playerid,
  162. BoxSelectExclusiveGroups.BoxSelectVolumeExclusiveGroup);
  163. if (!state.active) return new Block[0];
  164. var pointer = (EGID*) blocks.selectedBlocks.ToPointer();
  165. var ret = new Block[blocks.count];
  166. for (int j = 0; j < blocks.count; j++)
  167. {
  168. var egid = pointer[j];
  169. ret[j] = Block.New(egid);
  170. }
  171. return ret;
  172. }
  173. }
  174. }