From 555edd18f94426475f2a2858612b005d33f93188 Mon Sep 17 00:00:00 2001 From: BB_pezsgo Date: Sun, 5 Jan 2025 08:51:59 +0100 Subject: [PATCH] sessions --- Assets/Components/Player.cs | 4 + Assets/RPC/SessionLoginRequestRpc.cs | 10 + Assets/RPC/SessionRegisterRequestRpc.cs | 6 + Assets/RPC/SessionResponseRpc.cs | 17 ++ Assets/Scenes/GameScene.unity | 10 +- Assets/Systems/Client/EntityInfoUISystem.cs | 4 + Assets/Systems/Client/PlayerSystemClient.cs | 117 +++++++++++ Assets/Systems/Server/PlayerSystemServer.cs | 216 ++++++++++++++++++++ Assets/Systems/Server/ServerSystem.cs | 111 ---------- Assets/Utils/Marshal.cs | 18 ++ 10 files changed, 397 insertions(+), 116 deletions(-) create mode 100644 Assets/RPC/SessionLoginRequestRpc.cs create mode 100644 Assets/RPC/SessionRegisterRequestRpc.cs create mode 100644 Assets/RPC/SessionResponseRpc.cs create mode 100644 Assets/Systems/Client/PlayerSystemClient.cs create mode 100644 Assets/Systems/Server/PlayerSystemServer.cs delete mode 100644 Assets/Systems/Server/ServerSystem.cs create mode 100644 Assets/Utils/Marshal.cs diff --git a/Assets/Components/Player.cs b/Assets/Components/Player.cs index b09e959..85cb56a 100644 --- a/Assets/Components/Player.cs +++ b/Assets/Components/Player.cs @@ -1,3 +1,5 @@ +using System; +using Unity.Burst; using Unity.Entities; using Unity.NetCode; @@ -8,6 +10,7 @@ public enum PlayerConnectionState : byte Disconnected, } +[BurstCompile] public struct Player : IComponentData { [GhostField] public int ConnectionId; @@ -15,4 +18,5 @@ public struct Player : IComponentData [GhostField] public int Team; [GhostField] public float Resources; public bool IsCoreComputerSpawned; + public Guid Guid; } diff --git a/Assets/RPC/SessionLoginRequestRpc.cs b/Assets/RPC/SessionLoginRequestRpc.cs new file mode 100644 index 0000000..cc345a4 --- /dev/null +++ b/Assets/RPC/SessionLoginRequestRpc.cs @@ -0,0 +1,10 @@ +using System; +using Unity.Burst; +using Unity.Collections; +using Unity.NetCode; + +[BurstCompile] +public struct SessionLoginRequestRpc : IRpcCommand +{ + public required FixedBytes16 Guid; +} diff --git a/Assets/RPC/SessionRegisterRequestRpc.cs b/Assets/RPC/SessionRegisterRequestRpc.cs new file mode 100644 index 0000000..d926903 --- /dev/null +++ b/Assets/RPC/SessionRegisterRequestRpc.cs @@ -0,0 +1,6 @@ +using Unity.NetCode; + +public struct SessionRegisterRequestRpc : IRpcCommand +{ + +} diff --git a/Assets/RPC/SessionResponseRpc.cs b/Assets/RPC/SessionResponseRpc.cs new file mode 100644 index 0000000..a635ccf --- /dev/null +++ b/Assets/RPC/SessionResponseRpc.cs @@ -0,0 +1,17 @@ +using Unity.Burst; +using Unity.Collections; +using Unity.NetCode; + +public enum SessionStatusCode : byte +{ + OK, + AlreadyLoggedIn, + InvalidGuid, +} + +[BurstCompile] +public struct SessionResponseRpc : IRpcCommand +{ + public required SessionStatusCode StatusCode; + public required FixedBytes16 Guid; +} diff --git a/Assets/Scenes/GameScene.unity b/Assets/Scenes/GameScene.unity index 7f04492..3c3e8df 100644 --- a/Assets/Scenes/GameScene.unity +++ b/Assets/Scenes/GameScene.unity @@ -1331,26 +1331,26 @@ MonoBehaviour: x: 4 y: 6 Script: builder.bbc - Team: 2 + Team: 1 - Prefab: {fileID: 2099412289264216910, guid: 2433642d39f17be6aa8ad8c596976581, type: 3} Spawn: x: 2 y: 6 Script: builder.bbc - Team: 2 + Team: 1 - Prefab: {fileID: 1994654560244389388, guid: 8cc3337a89423ebee8b83eac4f208105, type: 3} Spawn: x: 0 y: 6 Script: extractor.bbc - Team: 2 + Team: 1 - Prefab: {fileID: 8196213229133260831, guid: b9ee901bbacbf08859e49b904b381b95, type: 3} Spawn: x: -2 y: 6 Script: transporter.bbc - Team: 2 - Team: 2 + Team: 1 + Team: 1 GeneratedScript: unit-4.bbc GeneratedCount: 0 Start: {x: -20, y: -20} diff --git a/Assets/Systems/Client/EntityInfoUISystem.cs b/Assets/Systems/Client/EntityInfoUISystem.cs index b8200b1..22138ba 100644 --- a/Assets/Systems/Client/EntityInfoUISystem.cs +++ b/Assets/Systems/Client/EntityInfoUISystem.cs @@ -21,7 +21,9 @@ void ISystem.OnUpdate(ref SystemState state) .WithAll() .WithEntityAccess()) { +#if UNITY_EDITOR && ENABLE_PROFILER using Unity.Profiling.ProfilerMarker.AutoScope _ = __instantiateUI.Auto(); +#endif GameObject uiPrefab = SystemAPI.ManagedAPI.GetSingleton().EntityInfo; Unity.Mathematics.float3 spawnPosition = transform.ValueRO.Position; @@ -77,7 +79,9 @@ void ISystem.OnUpdate(ref SystemState state) .WithNone() .WithEntityAccess()) { +#if UNITY_EDITOR && ENABLE_PROFILER using Unity.Profiling.ProfilerMarker.AutoScope _ = __destroyUI.Auto(); +#endif Object.Destroy(uiRef.Value.gameObject); commandBuffer.RemoveComponent(entity); diff --git a/Assets/Systems/Client/PlayerSystemClient.cs b/Assets/Systems/Client/PlayerSystemClient.cs new file mode 100644 index 0000000..734ab16 --- /dev/null +++ b/Assets/Systems/Client/PlayerSystemClient.cs @@ -0,0 +1,117 @@ +using System; +using Unity.Burst; +using Unity.Collections; +using Unity.Entities; +using Unity.NetCode; + +[BurstCompile] +[WorldSystemFilter(WorldSystemFilterFlags.ClientSimulation | WorldSystemFilterFlags.ThinClientSimulation)] +public partial struct PlayerSystemClient : ISystem +{ + bool _requestSent; + SessionStatusCode _sessionStatus; + Guid _guid; + + void ISystem.OnCreate(ref SystemState state) + { + _requestSent = false; + _guid = default; + state.RequireForUpdate(); + } + + void ISystem.OnUpdate(ref SystemState state) + { + EntityCommandBuffer commandBuffer = SystemAPI.GetSingleton().CreateCommandBuffer(state.WorldUnmanaged); + + NetworkStreamConnection connection = SystemAPI.GetSingleton(); + + foreach (var (request, command, entity) in + SystemAPI.Query, RefRO>() + .WithEntityAccess()) + { + commandBuffer.DestroyEntity(entity); + + _sessionStatus = command.ValueRO.StatusCode; + _guid = Marshal.As(command.ValueRO.Guid); + + Debug.Log(string.Format("[Client] Session status: {0}\n guid: {1}", _sessionStatus, _guid)); + } + + if (connection.CurrentState != ConnectionState.State.Connected) return; + + if (!TryGetLocalPlayer(ref state, out Player player)) + { + if (!_requestSent) + { + Entity response = commandBuffer.CreateEntity(); + commandBuffer.AddComponent(response); + if (_guid == default) + { + Debug.Log(string.Format("[Client] No player found, registering")); + + commandBuffer.AddComponent(response, new() + { + + }); + } + else + { + Debug.Log(string.Format("[Client] No player found, logging in with {0}", _guid)); + + commandBuffer.AddComponent(response, new() + { + Guid = Marshal.As(_guid) + }); + } + + _requestSent = true; + } + } + else + { + _requestSent = false; + } + } + + public bool TryGetLocalPlayer(ref SystemState state, out Player player) + { + if (!SystemAPI.TryGetSingleton(out NetworkId networkId)) + { + player = default; + return false; + } + + foreach (var _player in + SystemAPI.Query>()) + { + if (_player.ValueRO.ConnectionId != networkId.Value) continue; + player = _player.ValueRO; + return true; + } + + player = default; + return false; + } + + public static bool TryGetLocalPlayer(out Player player) + { + using EntityQuery playersQ = ConnectionManager.ClientOrDefaultWorld.EntityManager.CreateEntityQuery(typeof(Player)); + using EntityQuery connectionsQ = ConnectionManager.ClientOrDefaultWorld.EntityManager.CreateEntityQuery(typeof(NetworkId)); + if (!connectionsQ.TryGetSingleton(out NetworkId networkId)) + { + player = default; + return false; + } + + using NativeArray players = playersQ.ToComponentDataArray(Allocator.Temp); + for (int i = 0; i < players.Length; i++) + { + if (players[i].ConnectionId != networkId.Value) continue; + player = players[i]; + return true; + } + + player = default; + return false; + } +} diff --git a/Assets/Systems/Server/PlayerSystemServer.cs b/Assets/Systems/Server/PlayerSystemServer.cs new file mode 100644 index 0000000..b92f141 --- /dev/null +++ b/Assets/Systems/Server/PlayerSystemServer.cs @@ -0,0 +1,216 @@ +using System; +using Unity.Burst; +using Unity.Collections; +using Unity.Entities; +using Unity.NetCode; +using Unity.Transforms; + +[BurstCompile] +[WorldSystemFilter(WorldSystemFilterFlags.ServerSimulation)] +public partial struct PlayerSystemServer : ISystem +{ + int _teamCounter; + + [BurstCompile] + void ISystem.OnCreate(ref SystemState state) + { + state.RequireForUpdate(); + _teamCounter = 0; + } + + [BurstCompile] + void ISystem.OnUpdate(ref SystemState state) + { + EntityCommandBuffer commandBuffer = SystemAPI.GetSingleton().CreateCommandBuffer(state.WorldUnmanaged); + + PrefabDatabase prefabs = SystemAPI.GetSingleton(); + var spawns = SystemAPI.GetSingletonBuffer(false); + + foreach (var (id, entity) in + SystemAPI.Query>() + .WithNone() + .WithEntityAccess()) + { + Debug.Log(string.Format("[Server] Client {0} initialized", id.ValueRO.Value)); + commandBuffer.AddComponent(entity); + } + + foreach (var (request, command, entity) in + SystemAPI.Query, RefRO>() + .WithEntityAccess()) + { + var source = SystemAPI.GetComponentRO(request.ValueRO.SourceConnection); + commandBuffer.DestroyEntity(entity); + + Debug.Log(string.Format("[Server] Received register request from client {0}", source.ValueRO.Value)); + + bool exists = false; + foreach (var player in + SystemAPI.Query>()) + { + if (player.ValueRO.ConnectionId == source.ValueRO.Value) + { + exists = true; + } + } + + if (exists) + { + Entity response = commandBuffer.CreateEntity(); + commandBuffer.AddComponent(response, new() + { + TargetConnection = request.ValueRO.SourceConnection, + }); + commandBuffer.AddComponent(response, new() + { + StatusCode = SessionStatusCode.AlreadyLoggedIn, + Guid = default, + }); + } + else + { + Guid guid = Guid.NewGuid(); + + Entity newPlayer = commandBuffer.Instantiate(prefabs.Player); + commandBuffer.SetComponent(newPlayer, new() + { + ConnectionId = source.ValueRO.Value, + ConnectionState = PlayerConnectionState.Connected, + Team = -1, + IsCoreComputerSpawned = false, + Resources = 5, + Guid = guid, + }); + + Entity response = commandBuffer.CreateEntity(); + commandBuffer.AddComponent(response, new() + { + TargetConnection = request.ValueRO.SourceConnection, + }); + commandBuffer.AddComponent(response, new() + { + StatusCode = SessionStatusCode.OK, + Guid = Marshal.As(ref guid), + }); + } + } + + foreach (var (request, command, entity) in + SystemAPI.Query, RefRO>() + .WithEntityAccess()) + { + var source = SystemAPI.GetComponentRO(request.ValueRO.SourceConnection); + commandBuffer.DestroyEntity(entity); + + FixedBytes16 guid = command.ValueRO.Guid; + + Debug.Log(string.Format("[Server] Received login request from client {0} with guid {1}", source.ValueRO.Value, Marshal.As(guid))); + + bool exists = false; + foreach (var player in + SystemAPI.Query>()) + { + if (player.ValueRO.Guid != Marshal.As(guid)) continue; + + exists = true; + bool loggedIn = player.ValueRO.ConnectionId != -1; + if (!loggedIn) + { + player.ValueRW.ConnectionId = source.ValueRO.Value; + player.ValueRW.ConnectionState = PlayerConnectionState.Connected; + } + + Entity response = commandBuffer.CreateEntity(); + commandBuffer.AddComponent(response, new() + { + TargetConnection = request.ValueRO.SourceConnection, + }); + commandBuffer.AddComponent(response, new() + { + StatusCode = loggedIn ? SessionStatusCode.AlreadyLoggedIn : SessionStatusCode.OK, + Guid = guid, + }); + break; + } + + if (!exists) + { + Entity response = commandBuffer.CreateEntity(); + commandBuffer.AddComponent(response, new() + { + TargetConnection = request.ValueRO.SourceConnection, + }); + commandBuffer.AddComponent(response, new() + { + StatusCode = SessionStatusCode.InvalidGuid, + Guid = guid, + }); + } + } + + foreach (var player in + SystemAPI.Query>()) + { + if (player.ValueRO.Team == -1) + { + player.ValueRW.Team = _teamCounter++; + } + + if (player.ValueRO.ConnectionState != PlayerConnectionState.Connected) continue; + + bool found = false; + foreach (var id in + SystemAPI.Query>() + .WithAll()) + { + if (id.ValueRO.Value == player.ValueRO.ConnectionId) + { + found = true; + break; + } + } + + if (!found) + { + player.ValueRW.ConnectionId = -1; + player.ValueRW.ConnectionState = PlayerConnectionState.Disconnected; + } + else + { + if (!player.ValueRO.IsCoreComputerSpawned) + { + for (int i = 0; i < spawns.Length; i++) + { + if (spawns[i].IsOccupied) continue; + spawns[i] = spawns[i] with { IsOccupied = true }; + + Entity coreComputer = commandBuffer.Instantiate(prefabs.CoreComputer); + commandBuffer.SetComponent(coreComputer, new() + { + Team = player.ValueRO.Team + }); + commandBuffer.SetComponent(coreComputer, LocalTransform.FromPosition(spawns[i].Position)); + commandBuffer.SetComponent(coreComputer, new() + { + NetworkId = player.ValueRO.ConnectionId, + }); + + Entity builder = commandBuffer.Instantiate(prefabs.Builder); + commandBuffer.SetComponent(builder, new() + { + Team = player.ValueRO.Team + }); + commandBuffer.SetComponent(builder, LocalTransform.FromPosition(spawns[i].Position + new Unity.Mathematics.float3(2f, 0.5f, 2f))); + commandBuffer.SetComponent(builder, new() + { + NetworkId = player.ValueRO.ConnectionId, + }); + + break; + } + player.ValueRW.IsCoreComputerSpawned = true; + } + } + } + } +} diff --git a/Assets/Systems/Server/ServerSystem.cs b/Assets/Systems/Server/ServerSystem.cs deleted file mode 100644 index fb3b150..0000000 --- a/Assets/Systems/Server/ServerSystem.cs +++ /dev/null @@ -1,111 +0,0 @@ -using System; -using Unity.Burst; -using Unity.Entities; -using Unity.NetCode; -using Unity.Transforms; - -[BurstCompile] -[WorldSystemFilter(WorldSystemFilterFlags.ServerSimulation)] -public partial struct ServerSystem : ISystem -{ - int _teamCounter; - - [BurstCompile] - void ISystem.OnCreate(ref SystemState state) - { - _teamCounter = 1; - state.RequireForUpdate(); - } - - [BurstCompile] - void ISystem.OnUpdate(ref SystemState state) - { - EntityCommandBuffer commandBuffer = SystemAPI.GetSingleton().CreateCommandBuffer(state.WorldUnmanaged); - - PrefabDatabase prefabs = SystemAPI.GetSingleton(); - var spawns = SystemAPI.GetSingletonBuffer(false); - - foreach (var (id, entity) in - SystemAPI.Query>() - .WithNone() - .WithEntityAccess()) - { - commandBuffer.AddComponent(entity); - - Entity newPlayer = commandBuffer.Instantiate(prefabs.Player); - commandBuffer.SetComponent(newPlayer, new() - { - ConnectionId = id.ValueRO.Value, - ConnectionState = PlayerConnectionState.Connected, - Team = -1, - IsCoreComputerSpawned = false, - Resources = 5, - }); - } - - foreach (var item in - SystemAPI.Query>()) - { - if (item.ValueRO.Team == -1) - { - item.ValueRW.Team = _teamCounter++; - } - - if (item.ValueRO.ConnectionState != PlayerConnectionState.Connected) continue; - - bool found = false; - foreach (var (id, _, entity) in - SystemAPI.Query, RefRO>() - .WithEntityAccess()) - { - if (id.ValueRO.Value == item.ValueRO.ConnectionId) - { - found = true; - break; - } - } - - if (!found) - { - item.ValueRW.ConnectionId = -1; - item.ValueRW.ConnectionState = PlayerConnectionState.Disconnected; - } - else - { - if (!item.ValueRO.IsCoreComputerSpawned) - { - for (int i = 0; i < spawns.Length; i++) - { - if (spawns[i].IsOccupied) continue; - spawns[i] = spawns[i] with { IsOccupied = true }; - - Entity coreComputer = commandBuffer.Instantiate(prefabs.CoreComputer); - commandBuffer.SetComponent(coreComputer, new() - { - Team = item.ValueRO.Team - }); - commandBuffer.SetComponent(coreComputer, LocalTransform.FromPosition(spawns[i].Position)); - commandBuffer.SetComponent(coreComputer, new() - { - NetworkId = item.ValueRO.ConnectionId, - }); - - Entity builder = commandBuffer.Instantiate(prefabs.Builder); - commandBuffer.SetComponent(builder, new() - { - Team = item.ValueRO.Team - }); - commandBuffer.SetComponent(builder, LocalTransform.FromPosition(spawns[i].Position + new Unity.Mathematics.float3(2f, 0.5f, 2f))); - commandBuffer.SetComponent(builder, new() - { - NetworkId = item.ValueRO.ConnectionId, - }); - - break; - } - item.ValueRW.IsCoreComputerSpawned = true; - } - } - } - } -} diff --git a/Assets/Utils/Marshal.cs b/Assets/Utils/Marshal.cs new file mode 100644 index 0000000..222cbf1 --- /dev/null +++ b/Assets/Utils/Marshal.cs @@ -0,0 +1,18 @@ +using System.Runtime.CompilerServices; +using Unity.Burst; + +[BurstCompile] +public static class Marshal +{ + [BurstCompile] + public static unsafe TTo As(this TFrom from) + where TFrom : unmanaged + where TTo : unmanaged + => *(TTo*)&from; + + [BurstCompile] + public static unsafe TTo As(ref this TFrom from) + where TFrom : unmanaged + where TTo : unmanaged + => *(TTo*)Unsafe.AsPointer(ref from); +}