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.

208 lines
6.9KB

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