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.

413 lines
11KB

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