From e3b3fd5ef4ad4d29d50cb1c2c93e89914885f527 Mon Sep 17 00:00:00 2001 From: "NGnius (Graham)" Date: Mon, 11 May 2020 20:30:16 -0400 Subject: [PATCH] Implement Player OOP class --- GamecraftModdingAPI/Main.cs | 2 + GamecraftModdingAPI/Player.cs | 166 ++++++++++++++ GamecraftModdingAPI/Players/PlayerEngine.cs | 238 ++++++++++++++++++++ GamecraftModdingAPI/Players/PlayerType.cs | 9 + 4 files changed, 415 insertions(+) create mode 100644 GamecraftModdingAPI/Player.cs create mode 100644 GamecraftModdingAPI/Players/PlayerEngine.cs create mode 100644 GamecraftModdingAPI/Players/PlayerType.cs diff --git a/GamecraftModdingAPI/Main.cs b/GamecraftModdingAPI/Main.cs index 1258435..4dced5e 100644 --- a/GamecraftModdingAPI/Main.cs +++ b/GamecraftModdingAPI/Main.cs @@ -71,6 +71,8 @@ namespace GamecraftModdingAPI Inventory.Hotbar.Init(); // init input Input.FakeInput.Init(); + // init object-oriented classes + Player.Init(); Logging.MetaLog($"{currentAssembly.GetName().Name} v{currentAssembly.GetName().Version} initialized"); } diff --git a/GamecraftModdingAPI/Player.cs b/GamecraftModdingAPI/Player.cs new file mode 100644 index 0000000..6bd05c5 --- /dev/null +++ b/GamecraftModdingAPI/Player.cs @@ -0,0 +1,166 @@ +using System; + +using Unity.Mathematics; + +using GamecraftModdingAPI.Players; +using GamecraftModdingAPI.Utility; + +namespace GamecraftModdingAPI +{ + public class Player + { + // static functionality + private static PlayerEngine playerEngine = new PlayerEngine(); + + 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; + } + + public static bool Exists(uint player) + { + return playerEngine.ExistsById(player); + } + + public Player(uint id) + { + this.Id = id; + if (!Exists(id)) + { + throw new InvalidOperationException($"No player with id {id} exists"); + } + this.Type = playerEngine.GetLocalPlayer() == id ? PlayerType.Local : PlayerType.Remote; + } + + public Player(PlayerType player) + { + uint localId = playerEngine.GetLocalPlayer(); + 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 InvalidOperationException($"No player of {player} type exists"); + } + this.Type = player; + } + + // object fields & properties + + public PlayerType Type { get; } + + public uint Id { get; private set; } + + public float3 Position + { + get + { + return playerEngine.GetLocation(Id); + } + + set + { + playerEngine.SetLocation(Id, value, false); + } + } + + public quaternion Rotation + { + get + { + return playerEngine.GetRotation(Id); + } + + set + { + playerEngine.SetRotation(Id, value); + } + } + + public float3 Velocity + { + get + { + return playerEngine.GetLinearVelocity(Id); + } + + set + { + playerEngine.SetLinearVelocity(Id, value); + } + } + + public float3 AngularVelocity + { + get + { + return playerEngine.GetAngularVelocity(Id); + } + + set + { + playerEngine.SetAngularVelocity(Id, value); + } + } + + public float Mass + { + get + { + return 1f / playerEngine.GetMass(Id).InverseMass; + } + + set + { + playerEngine.SetInverseMass(Id, 1f / value); + } + } + + private float _ping = -1f; + + public float Ping + { + get + { + float? temp = playerEngine.GetLastPingTime(Id, Type); + if (temp.HasValue) + { + _ping = temp.Value; + } + return _ping; + } + } + + // object methods + + 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); + } + + // internal methods + + public static void Init() + { + Utility.GameEngineManager.AddGameEngine(playerEngine); + } + } +} diff --git a/GamecraftModdingAPI/Players/PlayerEngine.cs b/GamecraftModdingAPI/Players/PlayerEngine.cs new file mode 100644 index 0000000..beef48a --- /dev/null +++ b/GamecraftModdingAPI/Players/PlayerEngine.cs @@ -0,0 +1,238 @@ +using System; +using System.Runtime.CompilerServices; + +using RobocraftX.Character; +using RobocraftX.Character.Movement; +using RobocraftX.Common.Players; +using RobocraftX.Common.Input; +using RobocraftX.Physics; +using Svelto.ECS; +using Unity.Mathematics; +using Unity.Physics; + +using GamecraftModdingAPI.Engines; + +namespace GamecraftModdingAPI.Players +{ + internal class PlayerEngine : IApiEngine + { + public string Name { get; } = "GamecraftModdingAPIPlayerGameEngine"; + + public EntitiesDB entitiesDB { set; private get; } + + public bool isRemovable => false; + + private bool isReady = false; + + public void Dispose() + { + isReady = false; + } + + public void Ready() + { + isReady = true; + } + + public uint GetLocalPlayer() + { + if (!isReady) return uint.MaxValue; + PlayerIDStruct[] localPlayers = entitiesDB.QueryEntities(PlayersExclusiveGroups.LocalPlayers).ToFastAccess(out uint count); + if (count > 0) + { + return localPlayers[0].ID.entityID; + } + return uint.MaxValue; + } + + public uint GetRemotePlayer() + { + if (!isReady) return uint.MaxValue; + PlayerIDStruct[] localPlayers = entitiesDB.QueryEntities(PlayersExclusiveGroups.RemotePlayers).ToFastAccess(out uint count); + if (count > 0) + { + return localPlayers[0].ID.entityID; + } + return uint.MaxValue; + } + + public bool ExistsById(uint playerId) + { + PlayerIDStruct[] players = entitiesDB.QueryEntities(PlayersExclusiveGroups.LocalPlayers).ToFastAccess(out uint count); + for (int i = 0; i < count; i++) + { + if (players[i].ID.entityID == playerId) + { + return true; + } + } + players = entitiesDB.QueryEntities(PlayersExclusiveGroups.RemotePlayers).ToFastAccess(out count); + for (int i = 0; i < count; i++) + { + if (players[i].ID.entityID == playerId) + { + return true; + } + } + return false; + } + + public float3 GetLocation(uint playerId) + { + if (GetCharacterStruct(playerId, out RigidBodyEntityStruct rbes)) + { + return rbes.position; + } + return float3.zero; + } + + public bool SetLocation(uint playerId, float3 location, bool exitSeat = true) + { + ExclusiveGroup[] characterGroups = CharacterExclusiveGroups.AllCharacters; + for (int i = 0; i < characterGroups.Length; i++) + { + EGID egid = new EGID(playerId, characterGroups[i]); + if (entitiesDB.Exists(egid)) + { + ref RigidBodyEntityStruct rbes = ref entitiesDB.QueryEntity(egid); + if (characterGroups[i] == CharacterExclusiveGroups.InPilotSeatGroup && exitSeat) + { + entitiesDB.QueryEntity(egid).instantExit = true; + entitiesDB.PublishEntityChange(egid); + } + rbes.position = location; + return true; + } + } + return false; + } + + public quaternion GetRotation(uint playerId) + { + if (GetCharacterStruct(playerId, out RigidBodyEntityStruct rbes)) + { + return rbes.rotation; + } + return quaternion.identity; + } + + public bool SetRotation(uint playerId, quaternion value) + { + if (GetCharacterStruct(playerId, out RigidBodyEntityStruct rbes)) + { + rbes.rotation = value; + return true; + } + return false; + } + + public float3 GetLinearVelocity(uint playerId) + { + if (GetCharacterStruct(playerId, out RigidBodyEntityStruct rbes)) + { + return rbes.velocity; + } + return float3.zero; + } + + public bool SetLinearVelocity(uint playerId, float3 value) + { + if (GetCharacterStruct(playerId, out RigidBodyEntityStruct rbes)) + { + rbes.velocity = value; + return true; + } + return false; + } + + public float3 GetAngularVelocity(uint playerId) + { + if (GetCharacterStruct(playerId, out RigidBodyEntityStruct rbes)) + { + return rbes.angularVelocity; + } + return float3.zero; + } + + public bool SetAngularVelocity(uint playerId, float3 value) + { + if (GetCharacterStruct(playerId, out RigidBodyEntityStruct rbes)) + { + rbes.angularVelocity = value; + return true; + } + return false; + } + + public PhysicsMass GetMass(uint playerId) + { + if (GetCharacterStruct(playerId, out RigidBodyEntityStruct rbes)) + { + return rbes.physicsMass; + } + return default; + } + + public bool SetInverseMass(uint playerId, float inverseMass) + { + if (GetCharacterStruct(playerId, out RigidBodyEntityStruct rbes)) + { + rbes.physicsMass.InverseInertia = inverseMass; + return true; + } + return false; + } + + public float? GetLastPingTime(uint playerId, PlayerType type) + { + EGID egid = new EGID(playerId, GroupFromEnum(type)); + if (entitiesDB.Exists(egid)) + { + return entitiesDB.QueryEntity(egid).lastPingTimeSinceLevelLoad; + } + return null; + } + + // reusable methods + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private ExclusiveGroup GroupFromEnum(PlayerType type) + { + return type == PlayerType.Local ? PlayersExclusiveGroups.LocalPlayers : PlayersExclusiveGroups.RemotePlayers; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool GetCharacterStruct(uint playerId, out T s) where T : unmanaged, IEntityComponent + { + ExclusiveGroup[] characterGroups = CharacterExclusiveGroups.AllCharacters; + for (int i = 0; i < characterGroups.Length; i++) + { + EGID egid = new EGID(playerId, characterGroups[i]); + if (entitiesDB.Exists(egid)) + { + s = entitiesDB.QueryEntity(egid); + return true; + } + } + s = default; + return false; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool GetPlayerStruct(uint playerId, out T s) where T : unmanaged, IEntityComponent + { + ExclusiveGroup[] playerGroups = PlayersExclusiveGroups.AllPlayers; + for (int i = 0; i < playerGroups.Length; i++) + { + EGID egid = new EGID(playerId, playerGroups[i]); + if (entitiesDB.Exists(egid)) + { + s = entitiesDB.QueryEntity(egid); + return true; + } + } + s = default; + return false; + } + } +} diff --git a/GamecraftModdingAPI/Players/PlayerType.cs b/GamecraftModdingAPI/Players/PlayerType.cs new file mode 100644 index 0000000..0b4966c --- /dev/null +++ b/GamecraftModdingAPI/Players/PlayerType.cs @@ -0,0 +1,9 @@ +using System; +namespace GamecraftModdingAPI.Players +{ + public enum PlayerType + { + Local, + Remote + } +}