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();
///
/// 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);
}
///
/// 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.OWNED_BLOCKS_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;
}
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
public static void Init()
{
Utility.GameEngineManager.AddGameEngine(playerEngine);
}
}
}