using System; using Unity.Mathematics; using RobocraftX.Common; using RobocraftX.Common.Players; using Svelto.ECS; using GamecraftModdingAPI.Players; using GamecraftModdingAPI.Blocks; namespace GamecraftModdingAPI { /// /// An in-game player character. Any Leo you see is a player. /// public class Player : IEquatable, IEquatable { // static functionality private static PlayerEngine playerEngine = new PlayerEngine(); private static Player localPlayer; /// /// Checks if the specified player exists. /// /// Whether the player exists. /// Player type. public static bool Exists(PlayerType player) { switch (player) { case PlayerType.Remote: return playerEngine.GetRemotePlayer() != uint.MaxValue; case PlayerType.Local: return playerEngine.GetLocalPlayer() != uint.MaxValue; } return false; } /// /// Checks if the specified player exists. /// /// Whether the player exists. /// The player's unique identifier. public static bool Exists(uint player) { return playerEngine.ExistsById(player); } /// /// The amount of Players in the current game. /// /// The count. public static uint Count() { return (uint) playerEngine.GetAllPlayerCount(); } /// /// Returns the current player belonging to this client. /// public static Player LocalPlayer { get { if (localPlayer == null || localPlayer.Id != playerEngine.GetLocalPlayer()) localPlayer = new Player(PlayerType.Local); return localPlayer; } } /// /// Initializes a new instance of the class. /// /// The player's unique identifier. public Player(uint id) { this.Id = id; if (!Exists(id)) { throw new PlayerNotFoundException($"No player with id {id} exists"); } this.Type = playerEngine.GetLocalPlayer() == id ? PlayerType.Local : PlayerType.Remote; } /// /// Initializes a new instance of the class. /// /// The player type. Chooses the first available player matching the criteria. public Player(PlayerType player) { switch (player) { case PlayerType.Local: this.Id = playerEngine.GetLocalPlayer(); break; case PlayerType.Remote: this.Id = playerEngine.GetRemotePlayer(); break; } if (this.Id == uint.MaxValue) { throw new PlayerNotFoundException($"No player of {player} type exists"); } this.Type = player; } // object fields & properties /// /// The player's type. /// The player type is always relative to the current client, not the game host. /// /// The enumerated player type. public PlayerType Type { get; } /// /// The player's unique identifier. /// /// The identifier. public uint Id { get; } /// /// The player's current position. /// /// The position. public float3 Position { get { return playerEngine.GetLocation(Id); } set { playerEngine.SetLocation(Id, value, false); } } /// /// The player's current rotation. /// /// The rotation. public float3 Rotation { get { return playerEngine.GetRotation(Id); } set { playerEngine.SetRotation(Id, value); } } /// /// The player's current velocity. /// /// The velocity. public float3 Velocity { get { return playerEngine.GetLinearVelocity(Id); } set { playerEngine.SetLinearVelocity(Id, value); } } /// /// The player's current angular velocity. /// /// The angular velocity. public float3 AngularVelocity { get { return playerEngine.GetAngularVelocity(Id); } set { playerEngine.SetAngularVelocity(Id, value); } } /// /// The player's mass. /// /// The mass. public float Mass { get { return 1f / playerEngine.GetMass(Id).InverseMass; } // FIXME: Setting mass doesn't do anything /*set { playerEngine.SetInverseMass(Id, 1f / value); }*/ } private float _ping = -1f; /// /// The player's latest network ping time. /// /// The ping (s). public float Ping { get { float? temp = playerEngine.GetLastPingTime(Id, Type); if (temp.HasValue) { _ping = temp.Value; } return _ping; } } /// /// The player's initial health when entering Simulation (aka Time Running) mode. /// /// The initial health. public float InitialHealth { get => playerEngine.GetInitialHealth(Id); set { playerEngine.SetInitialHealth(Id, value); } } /// /// The player's current health in Simulation (aka Time Running) mode. /// /// The current health. public float CurrentHealth { get => playerEngine.GetCurrentHealth(Id); set { playerEngine.DamagePlayer(Id, CurrentHealth - value); } } /// /// Whether this is damageable. /// /// true if damageable; otherwise, false. public bool Damageable { get => playerEngine.GetDamageable(Id); set { playerEngine.SetDamageable(Id, value); } } /// /// The player's lives when initially entering Simulation (aka Time Running) mode. /// /// The initial lives. public uint InitialLives { get => playerEngine.GetInitialLives(Id); set => playerEngine.SetInitialLives(Id, value); } /// /// The player's current lives in Simulation (aka Time Running) mode. /// /// The current lives. public uint CurrentLives { get => playerEngine.GetCurrentLives(Id); set => playerEngine.SetCurrentLives(Id, value); } /// /// Whether the Game Over screen is displayed for the player. /// /// true if game over; otherwise, false. public bool GameOver { get => playerEngine.GetGameOverScreen(Id); } /// /// Whether the player is dead. /// If true, hopefully it was quick. /// /// true if dead; otherwise, false. public bool Dead { get => playerEngine.IsDead(Id); } /// /// The player's selected block ID in their hand. /// /// The selected block. public BlockIDs SelectedBlock { get { return (BlockIDs)playerEngine.GetSelectedBlock(Id); } } /// /// The player's selected block color in their hand. /// /// The selected block's color. public BlockColor SelectedColor { get { return new BlockColor(playerEngine.GetSelectedColor(Id)); } } /// /// The player's selected block colour in their hand. /// /// The selected block's colour. public BlockColor SelectedColour { get { return new BlockColor(playerEngine.GetSelectedColor(Id)); } } // object methods /// /// Teleport the player to the specified coordinates. /// /// The x coordinate. /// The y coordinate. /// The z coordinate. /// If set to true teleport relative to the player's current position. /// If set to true exit any seat the player is in. public void Teleport(float x, float y, float z, bool relative = true, bool exitSeat = true) { float3 location = new float3(x, y, z); if (relative) { location += playerEngine.GetLocation(Id); } playerEngine.SetLocation(Id, location, exitSeat: exitSeat); } /// /// Returns the block the player is currently looking at in build mode. /// /// The maximum distance from the player (default is the player's building reach) /// The block or null if not found public Block GetBlockLookedAt(float maxDistance = -1f) { var egid = playerEngine.GetThingLookedAt(Id, maxDistance); return egid.HasValue && egid.Value.groupID != CommonExclusiveGroups.SIMULATION_BODIES_GROUP ? new Block(egid.Value) : null; } /// /// Returns the rigid body the player is currently looking at during simulation. /// /// The maximum distance from the player (default is the player's building reach) /// The block or null if not found public SimBody GetSimBodyLookedAt(float maxDistance = -1f) { var egid = playerEngine.GetThingLookedAt(Id, maxDistance); return egid.HasValue && egid.Value.groupID == CommonExclusiveGroups.SIMULATION_BODIES_GROUP ? new SimBody(egid.Value) : null; } /// /// Returns the blocks that are in the player's current selection. /// /// An array of blocks or an empty array public Block[] GetSelectedBlocks() { return playerEngine.GetSelectedBlocks(Id); } public bool Equals(Player other) { if (ReferenceEquals(null, other)) return false; if (ReferenceEquals(this, other)) return true; return Id == other.Id; } public bool Equals(EGID other) { return Id == other.entityID && other.groupID == (Type == PlayerType.Local ? PlayersExclusiveGroups.LocalPlayers : PlayersExclusiveGroups.RemotePlayers); } public override bool Equals(object obj) { if (ReferenceEquals(null, obj)) return false; if (ReferenceEquals(this, obj)) return true; if (obj.GetType() != this.GetType()) return false; return Equals((Player) obj); } public override int GetHashCode() { return (int) Id; } // internal methods internal static void Init() { Utility.GameEngineManager.AddGameEngine(playerEngine); } } }