From 20662ae24d59830b73b18bb0ee2a077fae34cf7c Mon Sep 17 00:00:00 2001 From: edmand45 Date: Tue, 27 Jun 2023 23:41:30 +0300 Subject: [PATCH] wip --- Ragon.Client/Sources/Entity/RagonProperty.cs | 43 ++++++---------- .../Sources/Handler/EntityCreateHandler.cs | 2 +- ...ipHandler.cs => OwnershipEntityHandler.cs} | 8 +-- .../Sources/Handler/OwnershipRoomHandler.cs | 46 +++++++++++++++++ .../Sources/Handler/SnapshotHandler.cs | 5 +- Ragon.Client/Sources/RagonClient.cs | 3 +- Ragon.Client/Sources/RagonEntityCache.cs | 16 +++++- Ragon.Client/Sources/RagonPlayerCache.cs | 11 +++-- Ragon.Client/Sources/RagonRoom.cs | 6 ++- Ragon.Protocol/Sources/RagonOperation.cs | 5 +- .../Handler/EntityOwnershipOperation.cs | 49 +++++++++++++++++++ .../Sources/Handler/RoomOwnershipOperation.cs | 14 ++++++ Ragon.Server/Sources/RagonServer.cs | 2 + Ragon.Server/Sources/Room/RagonRoom.cs | 2 +- 14 files changed, 163 insertions(+), 49 deletions(-) rename Ragon.Client/Sources/Handler/{OwnershipHandler.cs => OwnershipEntityHandler.cs} (89%) create mode 100644 Ragon.Client/Sources/Handler/OwnershipRoomHandler.cs create mode 100644 Ragon.Server/Sources/Handler/EntityOwnershipOperation.cs create mode 100644 Ragon.Server/Sources/Handler/RoomOwnershipOperation.cs diff --git a/Ragon.Client/Sources/Entity/RagonProperty.cs b/Ragon.Client/Sources/Entity/RagonProperty.cs index 8669482..b629a40 100644 --- a/Ragon.Client/Sources/Entity/RagonProperty.cs +++ b/Ragon.Client/Sources/Entity/RagonProperty.cs @@ -29,15 +29,14 @@ namespace Ragon.Client public bool IsFixed => _fixed; public int Size => _size; - private RagonEntity _entity; - private RagonBuffer _propertyBuffer; + private RagonEntity _entity; private bool _dirty; private int _size; private int _ticks; private int _priority; private bool _fixed; private string _name; - + protected bool InvokeLocal; protected RagonProperty(int priority, bool invokeLocal) @@ -45,7 +44,6 @@ namespace Ragon.Client _size = 0; _priority = priority; _fixed = false; - _propertyBuffer = new RagonBuffer(); InvokeLocal = invokeLocal; } @@ -94,44 +92,31 @@ namespace Ragon.Client internal void AssignEntity(RagonEntity ent) { _entity = ent; - + Changed?.Invoke(); } internal void Write(RagonBuffer buffer) { - _propertyBuffer.Clear(); - if (_fixed) { - Serialize(_propertyBuffer); - - buffer.FromBuffer(_propertyBuffer, _size); + Serialize(buffer); + return; } - else - { - Serialize(_propertyBuffer); - var propSize = _propertyBuffer.WriteOffset; - buffer.WriteUShort((ushort) propSize); - buffer.FromBuffer(_propertyBuffer, propSize); - } + var sizeOffset = buffer.WriteOffset; + buffer.Write(0, 16); + var propOffset = buffer.WriteOffset; + + Serialize(buffer); + + var propSize = (uint)(buffer.WriteOffset - propOffset); + buffer.Write(propSize, 16, sizeOffset); } internal void Read(RagonBuffer buffer) { - _propertyBuffer.Clear(); - - if (_fixed) - { - buffer.ToBuffer(_propertyBuffer, _size); - Deserialize(_propertyBuffer); - return; - } - - var propSize = buffer.ReadUShort(); - buffer.ToBuffer(_propertyBuffer, propSize); - Deserialize(_propertyBuffer); + Deserialize(buffer); } public virtual void Serialize(RagonBuffer buffer) diff --git a/Ragon.Client/Sources/Handler/EntityCreateHandler.cs b/Ragon.Client/Sources/Handler/EntityCreateHandler.cs index fef3f34..e784ac1 100644 --- a/Ragon.Client/Sources/Handler/EntityCreateHandler.cs +++ b/Ragon.Client/Sources/Handler/EntityCreateHandler.cs @@ -51,7 +51,7 @@ internal class EntityCreateHandler : Handler return; } - var hasAuthority = _playerCache.LocalPlayer.Id == player.Id; + var hasAuthority = _playerCache.Local.Id == player.Id; var entity = _entityCache.OnCreate(attachId, entityType, 0, entityId, hasAuthority); entity.Attach(_client, entityId, entityType, hasAuthority, player, payload); } diff --git a/Ragon.Client/Sources/Handler/OwnershipHandler.cs b/Ragon.Client/Sources/Handler/OwnershipEntityHandler.cs similarity index 89% rename from Ragon.Client/Sources/Handler/OwnershipHandler.cs rename to Ragon.Client/Sources/Handler/OwnershipEntityHandler.cs index 2fb75c6..5edb74a 100644 --- a/Ragon.Client/Sources/Handler/OwnershipHandler.cs +++ b/Ragon.Client/Sources/Handler/OwnershipEntityHandler.cs @@ -19,13 +19,13 @@ using Ragon.Protocol; namespace Ragon.Client; -internal class OwnershipHandler: Handler +internal class OwnershipEntityHandler: Handler { private readonly RagonListenerList _listenerList; private readonly RagonPlayerCache _playerCache; private readonly RagonEntityCache _entityCache; - public OwnershipHandler( + public OwnershipEntityHandler( RagonListenerList listenerList, RagonPlayerCache playerCache, RagonEntityCache entityCache) @@ -39,10 +39,6 @@ internal class OwnershipHandler: Handler { var newOwnerId = buffer.ReadString(); var player = _playerCache.GetPlayerById(newOwnerId); - - _playerCache.OnOwnershipChanged(newOwnerId); - _listenerList.OnOwnershipChanged(player); - var entities = buffer.ReadUShort(); for (var i = 0; i < entities; i++) { diff --git a/Ragon.Client/Sources/Handler/OwnershipRoomHandler.cs b/Ragon.Client/Sources/Handler/OwnershipRoomHandler.cs new file mode 100644 index 0000000..49aca9e --- /dev/null +++ b/Ragon.Client/Sources/Handler/OwnershipRoomHandler.cs @@ -0,0 +1,46 @@ +/* + * Copyright 2023 Eduard Kargin + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +using Ragon.Protocol; + +namespace Ragon.Client; + +internal class OwnershipRoomHandler: Handler +{ + private readonly RagonListenerList _listenerList; + private readonly RagonPlayerCache _playerCache; + private readonly RagonEntityCache _entityCache; + + public OwnershipRoomHandler( + RagonListenerList listenerList, + RagonPlayerCache playerCache, + RagonEntityCache entityCache) + { + _listenerList = listenerList; + _playerCache = playerCache; + _entityCache = entityCache; + } + + public void Handle(RagonBuffer buffer) + { + var newOwnerId = buffer.ReadString(); + var player = _playerCache.GetPlayerById(newOwnerId); + + _playerCache.OnOwnershipChanged(newOwnerId); + _listenerList.OnOwnershipChanged(player); + } +} \ No newline at end of file diff --git a/Ragon.Client/Sources/Handler/SnapshotHandler.cs b/Ragon.Client/Sources/Handler/SnapshotHandler.cs index 5cdde43..a163ac5 100644 --- a/Ragon.Client/Sources/Handler/SnapshotHandler.cs +++ b/Ragon.Client/Sources/Handler/SnapshotHandler.cs @@ -15,6 +15,7 @@ */ +using System.Diagnostics; using Ragon.Protocol; namespace Ragon.Client; @@ -64,7 +65,7 @@ internal class SnapshotHandler : Handler var payload = new RagonPayload(payloadSize); payload.Read(buffer); - var hasAuthority = _playerCache.LocalPlayer.Id == player.Id; + var hasAuthority = _playerCache.Local.Id == player.Id; var entity = _entityCache.OnCreate(0, entityType, 0, entityId, hasAuthority); entity.Read(buffer); @@ -85,7 +86,7 @@ internal class SnapshotHandler : Handler var payload = new RagonPayload(payloadSize); payload.Read(buffer); - var hasAuthority = _playerCache.LocalPlayer.Id == player.Id; + var hasAuthority = _playerCache.Local.Id == player.Id; var entity = _entityCache.OnCreate(0, entityType, staticId, entityId, hasAuthority); entity.Read(buffer); diff --git a/Ragon.Client/Sources/RagonClient.cs b/Ragon.Client/Sources/RagonClient.cs index bcb1058..63722fe 100644 --- a/Ragon.Client/Sources/RagonClient.cs +++ b/Ragon.Client/Sources/RagonClient.cs @@ -90,7 +90,8 @@ namespace Ragon.Client _handlers[(byte)RagonOperation.JOIN_SUCCESS] = new JoinSuccessHandler(this, _readBuffer, _listenerList, _playerCache, _entityCache); _handlers[(byte)RagonOperation.JOIN_FAILED] = new JoinFailedHandler(_listenerList); _handlers[(byte)RagonOperation.LEAVE_ROOM] = new LeaveRoomHandler(this, _listenerList, _entityCache); - _handlers[(byte)RagonOperation.OWNERSHIP_CHANGED] = new OwnershipHandler(_listenerList, _playerCache, _entityCache); + _handlers[(byte)RagonOperation.OWNERSHIP_ROOM_CHANGED] = new OwnershipRoomHandler(_listenerList, _playerCache, _entityCache); + _handlers[(byte)RagonOperation.OWNERSHIP_ENTITY_CHANGED] = new OwnershipEntityHandler(_listenerList, _playerCache, _entityCache); _handlers[(byte)RagonOperation.PLAYER_JOINED] = new PlayerJoinHandler(_playerCache, _listenerList); _handlers[(byte)RagonOperation.PLAYER_LEAVED] = new PlayerLeftHandler(_entityCache, _playerCache, _listenerList); _handlers[(byte)RagonOperation.LOAD_SCENE] = new SceneLoadHandler(this, _listenerList); diff --git a/Ragon.Client/Sources/RagonEntityCache.cs b/Ragon.Client/Sources/RagonEntityCache.cs index eabc6eb..4ed30a9 100644 --- a/Ragon.Client/Sources/RagonEntityCache.cs +++ b/Ragon.Client/Sources/RagonEntityCache.cs @@ -52,7 +52,7 @@ public sealed class RagonEntityCache public void Create(RagonEntity entity, IRagonPayload? spawnPayload) { - var attachId = (ushort) (_playerCache.LocalPlayer.PeerId + _localEntitiesCounter++) ; + var attachId = (ushort) (_playerCache.Local.PeerId + _localEntitiesCounter++) ; var buffer = _client.Buffer; buffer.Clear(); @@ -71,6 +71,19 @@ public sealed class RagonEntityCache _client.Reliable.Send(sendData); } + public void Transfer(RagonEntity entity, RagonPlayer player) + { + var buffer = _client.Buffer; + + buffer.Clear(); + buffer.WriteOperation(RagonOperation.TRANSFER_ENTITY_OWNERSHIP); + buffer.WriteUShort(entity.Id); + buffer.WriteUShort(player.PeerId); + + var sendData = buffer.ToArray(); + _client.Reliable.Send(sendData); + } + public void Destroy(RagonEntity entity, IRagonPayload? destroyPayload) { if (!entity.IsAttached) @@ -78,6 +91,7 @@ public sealed class RagonEntityCache RagonLog.Warn("Can't destroy object, he is not created"); return; } + var buffer = _client.Buffer; buffer.Clear(); diff --git a/Ragon.Client/Sources/RagonPlayerCache.cs b/Ragon.Client/Sources/RagonPlayerCache.cs index fca23cc..2625fc0 100644 --- a/Ragon.Client/Sources/RagonPlayerCache.cs +++ b/Ragon.Client/Sources/RagonPlayerCache.cs @@ -18,12 +18,13 @@ namespace Ragon.Client; public sealed class RagonPlayerCache { - private List _players = new List(); - private Dictionary _playersById = new(); - private Dictionary _playersByConnection = new(); + private readonly List _players = new(); + private readonly Dictionary _playersById = new(); + private readonly Dictionary _playersByConnection = new(); + public IReadOnlyList Players => _players; public RagonPlayer Owner { get; private set; } - public RagonPlayer LocalPlayer { get; private set; } + public RagonPlayer Local { get; private set; } public bool IsRoomOwner => _ownerId == _localId; public RagonPlayer? GetPlayerById(string playerId) => _playersById[playerId]; @@ -51,7 +52,7 @@ public sealed class RagonPlayerCache var player = new RagonPlayer(peerId, playerId, playerName, isOwner, isLocal); if (player.IsLocal) - LocalPlayer = player; + Local = player; if (player.IsRoomOwner) Owner = player; diff --git a/Ragon.Client/Sources/RagonRoom.cs b/Ragon.Client/Sources/RagonRoom.cs index b6bdaab..3a1a5ba 100644 --- a/Ragon.Client/Sources/RagonRoom.cs +++ b/Ragon.Client/Sources/RagonRoom.cs @@ -28,9 +28,10 @@ namespace Ragon.Client public int MinPlayers => _information.Min; public int MaxPlayers => _information.Max; - public RagonPlayer Local => _playerCache.LocalPlayer; + public IReadOnlyList Players => _playerCache.Players; + public RagonPlayer Local => _playerCache.Local; public RagonPlayer Owner => _playerCache.Owner; - + public RagonRoom(RagonClient client, RagonEntityCache entityCache, RagonPlayerCache playerCache, @@ -55,6 +56,7 @@ namespace Ragon.Client public void CreateEntity(RagonEntity entity) => CreateEntity(entity, null); public void CreateEntity(RagonEntity entity, IRagonPayload? payload) => _entityCache.Create(entity, payload); + public void TransferEntity(RagonEntity entity, RagonPlayer player) => _entityCache.Transfer(entity, player); public void DestroyEntity(RagonEntity entityId) => DestroyEntity(entityId, null); public void DestroyEntity(RagonEntity entityId, IRagonPayload? payload) => _entityCache.Destroy(entityId, payload); diff --git a/Ragon.Protocol/Sources/RagonOperation.cs b/Ragon.Protocol/Sources/RagonOperation.cs index c492b68..a152d1e 100644 --- a/Ragon.Protocol/Sources/RagonOperation.cs +++ b/Ragon.Protocol/Sources/RagonOperation.cs @@ -26,7 +26,8 @@ namespace Ragon.Protocol CREATE_ROOM, JOIN_ROOM, LEAVE_ROOM, - OWNERSHIP_CHANGED, + OWNERSHIP_ENTITY_CHANGED, + OWNERSHIP_ROOM_CHANGED, JOIN_SUCCESS, JOIN_FAILED, LOAD_SCENE, @@ -38,5 +39,7 @@ namespace Ragon.Protocol SNAPSHOT, REPLICATE_ENTITY_STATE, REPLICATE_ENTITY_EVENT, + TRANSFER_ROOM_OWNERSHIP, + TRANSFER_ENTITY_OWNERSHIP, } } \ No newline at end of file diff --git a/Ragon.Server/Sources/Handler/EntityOwnershipOperation.cs b/Ragon.Server/Sources/Handler/EntityOwnershipOperation.cs new file mode 100644 index 0000000..8873e6d --- /dev/null +++ b/Ragon.Server/Sources/Handler/EntityOwnershipOperation.cs @@ -0,0 +1,49 @@ +using NLog; +using Ragon.Protocol; + +namespace Ragon.Server.Handler; + +public sealed class EntityOwnershipOperation : IRagonOperation +{ + private readonly Logger _logger = LogManager.GetCurrentClassLogger(); + + public void Handle(RagonContext context, RagonBuffer reader, RagonBuffer writer) + { + var player = context.RoomPlayer; + var room = context.Room; + + var entityId = reader.ReadUShort(); + var playerId = reader.ReadUShort(); + + if (!room.Entities.TryGetValue(entityId, out var entity)) + { + _logger.Error($"Entity not found with id {entityId}"); + return; + } + + if (entity.Owner.Connection.Id != player.Connection.Id) + { + _logger.Error($"Player not owner of entity with id {entityId}"); + return; + } + + if (!room.Players.TryGetValue(playerId, out var nextOwner)) + { + _logger.Error($"Player not found with id {entityId}"); + return; + } + + writer.Clear(); + writer.WriteOperation(RagonOperation.OWNERSHIP_ENTITY_CHANGED); + writer.WriteUShort(nextOwner.Connection.Id); + writer.WriteUShort(1); + writer.WriteUShort(entity.Id); + + player.Entities.Remove(entity); + nextOwner.Entities.Add(entity); + + entity.Attach(nextOwner); + + _logger.Trace($"Entity {entity.Id} next owner {nextOwner.Connection.Id}"); + } +} \ No newline at end of file diff --git a/Ragon.Server/Sources/Handler/RoomOwnershipOperation.cs b/Ragon.Server/Sources/Handler/RoomOwnershipOperation.cs new file mode 100644 index 0000000..5ef9fa2 --- /dev/null +++ b/Ragon.Server/Sources/Handler/RoomOwnershipOperation.cs @@ -0,0 +1,14 @@ +using NLog; +using Ragon.Protocol; +using Ragon.Server.Entity; + +namespace Ragon.Server.Handler; + +public sealed class RoomOwnershipOperation : IRagonOperation +{ + private readonly Logger _logger = LogManager.GetCurrentClassLogger(); + public void Handle(RagonContext context, RagonBuffer reader, RagonBuffer writer) + { + + } +} \ No newline at end of file diff --git a/Ragon.Server/Sources/RagonServer.cs b/Ragon.Server/Sources/RagonServer.cs index 8dba18f..62682be 100644 --- a/Ragon.Server/Sources/RagonServer.cs +++ b/Ragon.Server/Sources/RagonServer.cs @@ -85,6 +85,8 @@ public class RagonServer : IRagonServer, INetworkListener _handlers[(byte) RagonOperation.REMOVE_ENTITY] = new EntityDestroyOperation(); _handlers[(byte) RagonOperation.REPLICATE_ENTITY_EVENT] = new EntityEventOperation(); _handlers[(byte) RagonOperation.REPLICATE_ENTITY_STATE] = new EntityStateOperation(); + _handlers[(byte) RagonOperation.TRANSFER_ROOM_OWNERSHIP] = new EntityOwnershipOperation(); + _handlers[(byte) RagonOperation.TRANSFER_ENTITY_OWNERSHIP] = new EntityOwnershipOperation(); _logger.Trace($"Server Tick Rate: {_configuration.ServerTickRate}"); } diff --git a/Ragon.Server/Sources/Room/RagonRoom.cs b/Ragon.Server/Sources/Room/RagonRoom.cs index 07a7755..f90c513 100644 --- a/Ragon.Server/Sources/Room/RagonRoom.cs +++ b/Ragon.Server/Sources/Room/RagonRoom.cs @@ -153,7 +153,7 @@ public class RagonRoom : IRagonRoom, IRagonAction var entitiesToUpdate = roomPlayer.Entities.StaticList; Writer.Clear(); - Writer.WriteOperation(RagonOperation.OWNERSHIP_CHANGED); + Writer.WriteOperation(RagonOperation.OWNERSHIP_ENTITY_CHANGED); Writer.WriteString(Owner.Id); Writer.WriteUShort((ushort)entitiesToUpdate.Count);