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.

447 lines
12KB

  1. using System;
  2. using Gamecraft.GUI.Blueprints;
  3. using Unity.Mathematics;
  4. using RobocraftX.Common;
  5. using RobocraftX.Common.Players;
  6. using Svelto.ECS;
  7. using GamecraftModdingAPI.Players;
  8. using GamecraftModdingAPI.Blocks;
  9. namespace GamecraftModdingAPI
  10. {
  11. /// <summary>
  12. /// An in-game player character. Any Leo you see is a player.
  13. /// </summary>
  14. public class Player : IEquatable<Player>, IEquatable<EGID>
  15. {
  16. // static functionality
  17. private static PlayerEngine playerEngine = new PlayerEngine();
  18. private static Player localPlayer;
  19. /// <summary>
  20. /// Checks if the specified player exists.
  21. /// </summary>
  22. /// <returns>Whether the player exists.</returns>
  23. /// <param name="player">Player type.</param>
  24. public static bool Exists(PlayerType player)
  25. {
  26. switch (player)
  27. {
  28. case PlayerType.Remote:
  29. return playerEngine.GetRemotePlayer() != uint.MaxValue;
  30. case PlayerType.Local:
  31. return playerEngine.GetLocalPlayer() != uint.MaxValue;
  32. }
  33. return false;
  34. }
  35. /// <summary>
  36. /// Checks if the specified player exists.
  37. /// </summary>
  38. /// <returns>Whether the player exists.</returns>
  39. /// <param name="player">The player's unique identifier.</param>
  40. public static bool Exists(uint player)
  41. {
  42. return playerEngine.ExistsById(player);
  43. }
  44. /// <summary>
  45. /// The amount of Players in the current game.
  46. /// </summary>
  47. /// <returns>The count.</returns>
  48. public static uint Count()
  49. {
  50. return (uint) playerEngine.GetAllPlayerCount();
  51. }
  52. /// <summary>
  53. /// Returns the current player belonging to this client.
  54. /// </summary>
  55. public static Player LocalPlayer
  56. {
  57. get
  58. {
  59. if (localPlayer == null || localPlayer.Id != playerEngine.GetLocalPlayer())
  60. localPlayer = new Player(PlayerType.Local);
  61. return localPlayer;
  62. }
  63. }
  64. /// <summary>
  65. /// Initializes a new instance of the <see cref="T:GamecraftModdingAPI.Player"/> class.
  66. /// </summary>
  67. /// <param name="id">The player's unique identifier.</param>
  68. public Player(uint id)
  69. {
  70. this.Id = id;
  71. if (!Exists(id))
  72. {
  73. throw new PlayerNotFoundException($"No player with id {id} exists");
  74. }
  75. this.Type = playerEngine.GetLocalPlayer() == id ? PlayerType.Local : PlayerType.Remote;
  76. }
  77. /// <summary>
  78. /// Initializes a new instance of the <see cref="T:GamecraftModdingAPI.Player"/> class.
  79. /// </summary>
  80. /// <param name="player">The player type. Chooses the first available player matching the criteria.</param>
  81. public Player(PlayerType player)
  82. {
  83. switch (player)
  84. {
  85. case PlayerType.Local:
  86. this.Id = playerEngine.GetLocalPlayer();
  87. break;
  88. case PlayerType.Remote:
  89. this.Id = playerEngine.GetRemotePlayer();
  90. break;
  91. }
  92. if (this.Id == uint.MaxValue)
  93. {
  94. throw new PlayerNotFoundException($"No player of {player} type exists");
  95. }
  96. this.Type = player;
  97. }
  98. // object fields & properties
  99. /// <summary>
  100. /// The player's type.
  101. /// The player type is always relative to the current client, not the game host.
  102. /// </summary>
  103. /// <value>The enumerated player type.</value>
  104. public PlayerType Type { get; }
  105. /// <summary>
  106. /// The player's unique identifier.
  107. /// </summary>
  108. /// <value>The identifier.</value>
  109. public uint Id { get; }
  110. /// <summary>
  111. /// The player's current position.
  112. /// </summary>
  113. /// <value>The position.</value>
  114. public float3 Position
  115. {
  116. get
  117. {
  118. return playerEngine.GetLocation(Id);
  119. }
  120. set
  121. {
  122. playerEngine.SetLocation(Id, value, false);
  123. }
  124. }
  125. /// <summary>
  126. /// The player's current rotation.
  127. /// </summary>
  128. /// <value>The rotation.</value>
  129. public float3 Rotation
  130. {
  131. get
  132. {
  133. return playerEngine.GetRotation(Id);
  134. }
  135. set
  136. {
  137. playerEngine.SetRotation(Id, value);
  138. }
  139. }
  140. /// <summary>
  141. /// The player's current velocity.
  142. /// </summary>
  143. /// <value>The velocity.</value>
  144. public float3 Velocity
  145. {
  146. get
  147. {
  148. return playerEngine.GetLinearVelocity(Id);
  149. }
  150. set
  151. {
  152. playerEngine.SetLinearVelocity(Id, value);
  153. }
  154. }
  155. /// <summary>
  156. /// The player's current angular velocity.
  157. /// </summary>
  158. /// <value>The angular velocity.</value>
  159. public float3 AngularVelocity
  160. {
  161. get
  162. {
  163. return playerEngine.GetAngularVelocity(Id);
  164. }
  165. set
  166. {
  167. playerEngine.SetAngularVelocity(Id, value);
  168. }
  169. }
  170. /// <summary>
  171. /// The player's mass.
  172. /// </summary>
  173. /// <value>The mass.</value>
  174. public float Mass
  175. {
  176. get
  177. {
  178. return 1f / playerEngine.GetMass(Id).InverseMass;
  179. }
  180. // FIXME: Setting mass doesn't do anything
  181. /*set
  182. {
  183. playerEngine.SetInverseMass(Id, 1f / value);
  184. }*/
  185. }
  186. private float _ping = -1f;
  187. /// <summary>
  188. /// The player's latest network ping time.
  189. /// </summary>
  190. /// <value>The ping (s).</value>
  191. public float Ping
  192. {
  193. get
  194. {
  195. float? temp = playerEngine.GetLastPingTime(Id, Type);
  196. if (temp.HasValue)
  197. {
  198. _ping = temp.Value;
  199. }
  200. return _ping;
  201. }
  202. }
  203. /// <summary>
  204. /// The player's initial health when entering Simulation (aka Time Running) mode.
  205. /// </summary>
  206. /// <value>The initial health.</value>
  207. public float InitialHealth
  208. {
  209. get => playerEngine.GetInitialHealth(Id);
  210. set
  211. {
  212. playerEngine.SetInitialHealth(Id, value);
  213. }
  214. }
  215. /// <summary>
  216. /// The player's current health in Simulation (aka Time Running) mode.
  217. /// </summary>
  218. /// <value>The current health.</value>
  219. public float CurrentHealth
  220. {
  221. get => playerEngine.GetCurrentHealth(Id);
  222. set
  223. {
  224. playerEngine.DamagePlayer(Id, CurrentHealth - value);
  225. }
  226. }
  227. /// <summary>
  228. /// Whether this <see cref="T:GamecraftModdingAPI.Player"/> is damageable.
  229. /// </summary>
  230. /// <value><c>true</c> if damageable; otherwise, <c>false</c>.</value>
  231. public bool Damageable
  232. {
  233. get => playerEngine.GetDamageable(Id);
  234. set
  235. {
  236. playerEngine.SetDamageable(Id, value);
  237. }
  238. }
  239. /// <summary>
  240. /// The player's lives when initially entering Simulation (aka Time Running) mode.
  241. /// </summary>
  242. /// <value>The initial lives.</value>
  243. public uint InitialLives
  244. {
  245. get => playerEngine.GetInitialLives(Id);
  246. set => playerEngine.SetInitialLives(Id, value);
  247. }
  248. /// <summary>
  249. /// The player's current lives in Simulation (aka Time Running) mode.
  250. /// </summary>
  251. /// <value>The current lives.</value>
  252. public uint CurrentLives
  253. {
  254. get => playerEngine.GetCurrentLives(Id);
  255. set => playerEngine.SetCurrentLives(Id, value);
  256. }
  257. /// <summary>
  258. /// Whether the Game Over screen is displayed for the player.
  259. /// </summary>
  260. /// <value><c>true</c> if game over; otherwise, <c>false</c>.</value>
  261. public bool GameOver
  262. {
  263. get => playerEngine.GetGameOverScreen(Id);
  264. }
  265. /// <summary>
  266. /// Whether the player is dead.
  267. /// If <c>true</c>, hopefully it was quick.
  268. /// </summary>
  269. /// <value><c>true</c> if dead; otherwise, <c>false</c>.</value>
  270. public bool Dead
  271. {
  272. get => playerEngine.IsDead(Id);
  273. }
  274. /// <summary>
  275. /// The player's selected block ID in their hand.
  276. /// </summary>
  277. /// <value>The selected block.</value>
  278. public BlockIDs SelectedBlock
  279. {
  280. get
  281. {
  282. return (BlockIDs)playerEngine.GetSelectedBlock(Id);
  283. }
  284. }
  285. /// <summary>
  286. /// The player's selected block color in their hand.
  287. /// </summary>
  288. /// <value>The selected block's color.</value>
  289. public BlockColor SelectedColor
  290. {
  291. get
  292. {
  293. return new BlockColor(playerEngine.GetSelectedColor(Id));
  294. }
  295. }
  296. /// <summary>
  297. /// The player's selected block colour in their hand.
  298. /// </summary>
  299. /// <value>The selected block's colour.</value>
  300. public BlockColor SelectedColour
  301. {
  302. get
  303. {
  304. return new BlockColor(playerEngine.GetSelectedColor(Id));
  305. }
  306. }
  307. /// <summary>
  308. /// The player's selected blueprint in their hand. Set to null to clear. Dispose after usage.
  309. /// </summary>
  310. public Blueprint SelectedBlueprint
  311. {
  312. get => playerEngine.GetPlayerStruct(Id, out BlueprintInventoryItemEntityStruct biies)
  313. ? new Blueprint(biies.blueprintResourceId)
  314. : null;
  315. set => BlockGroup._engine.SelectBlueprint(value?.Id ?? uint.MaxValue);
  316. }
  317. // object methods
  318. /// <summary>
  319. /// Teleport the player to the specified coordinates.
  320. /// </summary>
  321. /// <param name="x">The x coordinate.</param>
  322. /// <param name="y">The y coordinate.</param>
  323. /// <param name="z">The z coordinate.</param>
  324. /// <param name="relative">If set to <c>true</c> teleport relative to the player's current position.</param>
  325. /// <param name="exitSeat">If set to <c>true</c> exit any seat the player is in.</param>
  326. public void Teleport(float x, float y, float z, bool relative = true, bool exitSeat = true)
  327. {
  328. float3 location = new float3(x, y, z);
  329. if (relative)
  330. {
  331. location += playerEngine.GetLocation(Id);
  332. }
  333. playerEngine.SetLocation(Id, location, exitSeat: exitSeat);
  334. }
  335. /// <summary>
  336. /// Returns the block the player is currently looking at in build mode.
  337. /// </summary>
  338. /// <param name="maxDistance">The maximum distance from the player (default is the player's building reach)</param>
  339. /// <returns>The block or null if not found</returns>
  340. public Block GetBlockLookedAt(float maxDistance = -1f)
  341. {
  342. var egid = playerEngine.GetThingLookedAt(Id, maxDistance);
  343. return egid.HasValue && egid.Value.groupID != CommonExclusiveGroups.SIMULATION_BODIES_GROUP
  344. ? new Block(egid.Value)
  345. : null;
  346. }
  347. /// <summary>
  348. /// Returns the rigid body the player is currently looking at during simulation.
  349. /// </summary>
  350. /// <param name="maxDistance">The maximum distance from the player (default is the player's building reach)</param>
  351. /// <returns>The block or null if not found</returns>
  352. public SimBody GetSimBodyLookedAt(float maxDistance = -1f)
  353. {
  354. var egid = playerEngine.GetThingLookedAt(Id, maxDistance);
  355. return egid.HasValue && egid.Value.groupID == CommonExclusiveGroups.SIMULATION_BODIES_GROUP
  356. ? new SimBody(egid.Value)
  357. : null;
  358. }
  359. /// <summary>
  360. /// Returns the blocks that are in the player's current selection.
  361. /// </summary>
  362. /// <returns>An array of blocks or an empty array</returns>
  363. public Block[] GetSelectedBlocks()
  364. {
  365. return playerEngine.GetSelectedBlocks(Id);
  366. }
  367. public bool Equals(Player other)
  368. {
  369. if (ReferenceEquals(null, other)) return false;
  370. if (ReferenceEquals(this, other)) return true;
  371. return Id == other.Id;
  372. }
  373. public bool Equals(EGID other)
  374. {
  375. return Id == other.entityID && other.groupID == (Type == PlayerType.Local
  376. ? PlayersExclusiveGroups.LocalPlayers
  377. : PlayersExclusiveGroups.RemotePlayers);
  378. }
  379. public override bool Equals(object obj)
  380. {
  381. if (ReferenceEquals(null, obj)) return false;
  382. if (ReferenceEquals(this, obj)) return true;
  383. if (obj.GetType() != this.GetType()) return false;
  384. return Equals((Player) obj);
  385. }
  386. public override int GetHashCode()
  387. {
  388. return (int) Id;
  389. }
  390. // internal methods
  391. internal static void Init()
  392. {
  393. Utility.GameEngineManager.AddGameEngine(playerEngine);
  394. }
  395. }
  396. }