From d3ae5a4465b0be1580c693f2fc9a5bf43ca2e778 Mon Sep 17 00:00:00 2001 From: edmand46 Date: Thu, 9 May 2024 10:50:59 +0300 Subject: [PATCH] feat: player propeties --- .../Sources/Handler/PlayerUserDataHandler.cs | 22 +++++- .../Sources/Handler/RoomUserDataHandler.cs | 24 +++++-- Ragon.Client/Sources/IUserData.cs | 27 +++++++ Ragon.Client/Sources/RagonClient.cs | 71 +++++++++++++------ Ragon.Client/Sources/RagonListenerList.cs | 32 ++++++--- Ragon.Client/Sources/RagonPlayer.cs | 8 +-- Ragon.Client/Sources/RagonPlayerCache.cs | 2 +- Ragon.Client/Sources/RagonRoom.cs | 4 +- Ragon.Client/Sources/RagonUserData.cs | 24 +++++-- Ragon.Client/Sources/RagonUserDataReadOnly.cs | 65 +++++++++++++++++ Ragon.Protocol/Sources/RagonOperation.cs | 4 +- Ragon.Relay/relay.config.json | 1 + .../Handler/PlayerPropertiesOperation.cs | 28 -------- .../Handler/PlayerUserDataOperation.cs | 40 +++++++++++ ...sOperation.cs => RoomUserDataOperation.cs} | 23 ++++-- Ragon.Server/Sources/RagonServer.cs | 16 ++--- .../Sources/RagonServerConfiguration.cs | 1 + 17 files changed, 300 insertions(+), 92 deletions(-) create mode 100644 Ragon.Client/Sources/IUserData.cs create mode 100644 Ragon.Client/Sources/RagonUserDataReadOnly.cs delete mode 100644 Ragon.Server/Sources/Handler/PlayerPropertiesOperation.cs create mode 100644 Ragon.Server/Sources/Handler/PlayerUserDataOperation.cs rename Ragon.Server/Sources/Handler/{RoomPropertiesOperation.cs => RoomUserDataOperation.cs} (70%) diff --git a/Ragon.Client/Sources/Handler/PlayerUserDataHandler.cs b/Ragon.Client/Sources/Handler/PlayerUserDataHandler.cs index 4d96a20..2fdb8c4 100644 --- a/Ragon.Client/Sources/Handler/PlayerUserDataHandler.cs +++ b/Ragon.Client/Sources/Handler/PlayerUserDataHandler.cs @@ -1,3 +1,19 @@ +/* + * Copyright 2024 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 @@ -25,8 +41,12 @@ namespace Ragon.Client { player.UserData.Read(reader); - _listenerList.OnPlayerUserData(); + _listenerList.OnPlayerUserData(player); + + return; } + + RagonLog.Warn("Received user data for unknown player."); } } } \ No newline at end of file diff --git a/Ragon.Client/Sources/Handler/RoomUserDataHandler.cs b/Ragon.Client/Sources/Handler/RoomUserDataHandler.cs index 7ae89eb..8a8b7dc 100644 --- a/Ragon.Client/Sources/Handler/RoomUserDataHandler.cs +++ b/Ragon.Client/Sources/Handler/RoomUserDataHandler.cs @@ -1,21 +1,37 @@ +/* + * Copyright 2024 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 RoomUserDataHandler: IHandler + internal class RoomUserDataHandler : IHandler { private readonly RagonClient _client; private readonly RagonListenerList _listenerList; + public RoomUserDataHandler(RagonClient client, RagonListenerList listenerList) { _client = client; _listenerList = listenerList; } - + public void Handle(RagonBuffer reader) { - _client.Room?.HandleProperties(reader); - + _client.Room?.HandleUserData(reader); _listenerList.OnRoomUserData(); } } diff --git a/Ragon.Client/Sources/IUserData.cs b/Ragon.Client/Sources/IUserData.cs new file mode 100644 index 0000000..184532e --- /dev/null +++ b/Ragon.Client/Sources/IUserData.cs @@ -0,0 +1,27 @@ +/* + * Copyright 2024 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; + +public interface IUserData +{ + public byte[] this[string key] { get; set; } + bool Dirty { get; } + void Read(RagonBuffer buffer); + void Write(RagonBuffer buffer); +} \ No newline at end of file diff --git a/Ragon.Client/Sources/RagonClient.cs b/Ragon.Client/Sources/RagonClient.cs index 248d416..a48962d 100644 --- a/Ragon.Client/Sources/RagonClient.cs +++ b/Ragon.Client/Sources/RagonClient.cs @@ -1,5 +1,5 @@ /* - * Copyright 2023 Eduard Kargin + * Copyright 2023-2024 Eduard Kargin * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -47,7 +47,7 @@ namespace Ragon.Client public RagonEntityCache Entity => _entityCache; public NetworkStatistics Statistics => _stats; public RagonRoom Room => _room; - + internal RagonBuffer Buffer => _writeBuffer; internal INetworkChannel Reliable => _connection.Reliable; internal INetworkChannel Unreliable => _connection.Unreliable; @@ -57,12 +57,12 @@ namespace Ragon.Client public RagonClient(INetworkConnection connection, int rate) { _listeners = new RagonListenerList(this); - + _connection = connection; _connection.OnData += OnData; _connection.OnConnected += OnConnected; _connection.OnDisconnected += OnDisconnected; - + _replicationRate = (1000.0f / rate) / 1000.0f; _replicationTime = 0; @@ -98,33 +98,38 @@ namespace Ragon.Client _writeBuffer = new RagonBuffer(); _readBuffer = new RagonBuffer(); - _session = new RagonSession(this, _writeBuffer); - _playerCache = new RagonPlayerCache(); + _session = new RagonSession(this, _writeBuffer); _entityCache = new RagonEntityCache(this, _playerCache, _sceneCollector); _handlers = new IHandler[byte.MaxValue]; _handlers[(byte)RagonOperation.AUTHORIZED_SUCCESS] = new AuthorizeSuccessHandler(this, _listeners); _handlers[(byte)RagonOperation.AUTHORIZED_FAILED] = new AuthorizeFailedHandler(_listeners); - _handlers[(byte)RagonOperation.JOIN_SUCCESS] = new JoinSuccessHandler(this, _listeners, _playerCache, _entityCache); + _handlers[(byte)RagonOperation.JOIN_SUCCESS] = + new JoinSuccessHandler(this, _listeners, _playerCache, _entityCache); _handlers[(byte)RagonOperation.JOIN_FAILED] = new JoinFailedHandler(_listeners); _handlers[(byte)RagonOperation.LEAVE_ROOM] = new LeaveRoomHandler(this, _listeners, _entityCache); - _handlers[(byte)RagonOperation.OWNERSHIP_ROOM_CHANGED] = new OwnershipRoomHandler(_listeners, _playerCache, _entityCache); - _handlers[(byte)RagonOperation.OWNERSHIP_ENTITY_CHANGED] = new EntityOwnershipHandler(_listeners, _playerCache, _entityCache); + _handlers[(byte)RagonOperation.OWNERSHIP_ROOM_CHANGED] = + new OwnershipRoomHandler(_listeners, _playerCache, _entityCache); + _handlers[(byte)RagonOperation.OWNERSHIP_ENTITY_CHANGED] = + new EntityOwnershipHandler(_listeners, _playerCache, _entityCache); _handlers[(byte)RagonOperation.PLAYER_JOINED] = new PlayerJoinHandler(_playerCache, _listeners); _handlers[(byte)RagonOperation.PLAYER_LEAVED] = new PlayerLeftHandler(_entityCache, _playerCache, _listeners); _handlers[(byte)RagonOperation.LOAD_SCENE] = new SceneLoadHandler(this, _listeners); - _handlers[(byte)RagonOperation.CREATE_ENTITY] = new EntityCreateHandler(this, _playerCache, _entityCache, _entityListener); + _handlers[(byte)RagonOperation.CREATE_ENTITY] = + new EntityCreateHandler(this, _playerCache, _entityCache, _entityListener); _handlers[(byte)RagonOperation.REMOVE_ENTITY] = new EntityRemoveHandler(_entityCache); _handlers[(byte)RagonOperation.REPLICATE_ENTITY_STATE] = new StateEntityHandler(_entityCache); _handlers[(byte)RagonOperation.REPLICATE_ENTITY_EVENT] = new EntityEventHandler(_playerCache, _entityCache); _handlers[(byte)RagonOperation.REPLICATE_ROOM_EVENT] = new RoomEventHandler(this, _playerCache); - _handlers[(byte)RagonOperation.SNAPSHOT] = new SnapshotHandler(this, _listeners, _entityCache, _playerCache, _entityListener); + _handlers[(byte)RagonOperation.SNAPSHOT] = + new SnapshotHandler(this, _listeners, _entityCache, _playerCache, _entityListener); _handlers[(byte)RagonOperation.TIMESTAMP_SYNCHRONIZATION] = new TimestampHandler(this); _handlers[(byte)RagonOperation.REPLICATE_RAW_DATA] = new RoomDataHandler(_playerCache, _listeners); _handlers[(byte)RagonOperation.ROOM_LIST_UPDATED] = new RoomListHandler(_session, _listeners); - _handlers[(byte)RagonOperation.ROOM_PROPERTIES_UPDATED] = new RoomUserDataHandler(this, _listeners); - + _handlers[(byte)RagonOperation.ROOM_DATA_UPDATED] = new RoomUserDataHandler(this, _listeners); + _handlers[(byte)RagonOperation.PLAYER_DATA_UPDATED] = new PlayerUserDataHandler(_playerCache, _listeners); + var protocolRaw = RagonVersion.Parse(protocol); _connection.Connect(address, port, protocolRaw); } @@ -149,7 +154,8 @@ namespace Ragon.Client _entityCache.WriteState(_writeBuffer); SendTimestamp(); - SendProperties(); + SendRoomUserData(); + SendPlayerUserData(); } _stats.Update(_connection.BytesSent, _connection.BytesReceived, _connection.Ping, dt); @@ -166,6 +172,7 @@ namespace Ragon.Client _status = RagonStatus.DISCONNECTED; _connection.Disconnect(); } + _connection.Dispose(); } @@ -182,6 +189,8 @@ namespace Ragon.Client public void AddListener(IRagonSceneRequestListener listener) => _listeners.Add(listener); public void AddListener(IRagonDataListener listener) => _listeners.Add(listener); public void AddListener(IRagonRoomListListener listener) => _listeners.Add(listener); + public void AddListener(IRagonPlayerUserDataListener listener) => _listeners.Add(listener); + public void AddListener(IRagonRoomUserDataListener listener) => _listeners.Add(listener); public void RemoveListener(IRagonListener listener) => _listeners.Remove(listener); public void RemoveListener(IRagonAuthorizationListener listener) => _listeners.Remove(listener); public void RemoveListener(IRagonConnectionListener listener) => _listeners.Remove(listener); @@ -195,6 +204,8 @@ namespace Ragon.Client public void RemoveListener(IRagonSceneRequestListener listener) => _listeners.Remove(listener); public void RemoveListener(IRagonDataListener listener) => _listeners.Remove(listener); public void RemoveListener(IRagonRoomListListener listener) => _listeners.Remove(listener); + public void RemoveListener(IRagonRoomUserDataListener listener) => _listeners.Remove(listener); + public void RemoveListener(IRagonPlayerUserDataListener listener) => _listeners.Remove(listener); #endregion @@ -233,18 +244,34 @@ namespace Ragon.Client _writeBuffer.Write(value.Int0, 32); _writeBuffer.Write(value.Int1, 32); } - - private void SendProperties() + + private void SendRoomUserData() { if (_room == null) return; - + var props = _room.UserData; - if (!props.Dirty) return; - + if (!props.Dirty) return; + _writeBuffer.Clear(); - _writeBuffer.WriteOperation(RagonOperation.ROOM_PROPERTIES_UPDATED); - - _room.UserData.Write(_writeBuffer); + _writeBuffer.WriteOperation(RagonOperation.ROOM_DATA_UPDATED); + + props.Write(_writeBuffer); + + var sendData = _writeBuffer.ToArray(); + _connection.Reliable.Send(sendData); + } + + private void SendPlayerUserData() + { + if (_playerCache.Local == null) return; + + var props = _playerCache.Local.UserData; + if (!props.Dirty) return; + + _writeBuffer.Clear(); + _writeBuffer.WriteOperation(RagonOperation.PLAYER_DATA_UPDATED); + + props.Write(_writeBuffer); var sendData = _writeBuffer.ToArray(); _connection.Reliable.Send(sendData); diff --git a/Ragon.Client/Sources/RagonListenerList.cs b/Ragon.Client/Sources/RagonListenerList.cs index 8bfe7b3..83e87b1 100644 --- a/Ragon.Client/Sources/RagonListenerList.cs +++ b/Ragon.Client/Sources/RagonListenerList.cs @@ -1,5 +1,5 @@ /* - * Copyright 2023 Eduard Kargin + * Copyright 2023-2024 Eduard Kargin * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -34,6 +34,7 @@ namespace Ragon.Client private readonly List _dataListeners = new(); private readonly List _roomListListeners = new(); private readonly List _roomUserDataListeners = new(); + private readonly List _playerUserDataListeners = new(); private readonly List _delayedActions = new(); public RagonListenerList(RagonClient client) @@ -53,6 +54,7 @@ namespace Ragon.Client _playerJoinListeners.Add(listener); _playerLeftListeners.Add(listener); _roomUserDataListeners.Add(listener); + _playerUserDataListeners.Add(listener); } public void Remove(IRagonListener listener) @@ -69,6 +71,7 @@ namespace Ragon.Client _playerJoinListeners.Remove(listener); _playerLeftListeners.Remove(listener); _roomUserDataListeners.Remove(listener); + _playerUserDataListeners.Remove(listener); }); } @@ -84,7 +87,7 @@ namespace Ragon.Client { _dataListeners.Add(dataListener); } - + public void Add(IRagonAuthorizationListener listener) { _authorizationListeners.Add(listener); @@ -134,22 +137,27 @@ namespace Ragon.Client { _playerLeftListeners.Add(listener); } - + public void Add(IRagonRoomListListener listener) { _roomListListeners.Add(listener); } - + public void Add(IRagonRoomUserDataListener listener) { _roomUserDataListeners.Add(listener); } + public void Add(IRagonPlayerUserDataListener listener) + { + _playerUserDataListeners.Add(listener); + } + public void Remove(IRagonDataListener listener) { _delayedActions.Add(() => _dataListeners.Remove(listener)); } - + public void Remove(IRagonSceneRequestListener listener) { _delayedActions.Add(() => _sceneRequestListeners.Remove(listener)); @@ -199,7 +207,7 @@ namespace Ragon.Client { _delayedActions.Add(() => _playerLeftListeners.Remove(listener)); } - + public void Remove(IRagonRoomListListener listener) { _delayedActions.Add(() => _roomListListeners.Remove(listener)); @@ -210,6 +218,11 @@ namespace Ragon.Client _delayedActions.Add(() => _roomUserDataListeners.Remove(listener)); } + public void Remove(IRagonPlayerUserDataListener listener) + { + _delayedActions.Add(() => _playerUserDataListeners.Remove(listener)); + } + public void OnAuthorizationSuccess(string playerId, string playerName, string payload) { foreach (var listener in _authorizationListeners) @@ -293,16 +306,17 @@ namespace Ragon.Client foreach (var listListener in _roomListListeners) listListener.OnRoomListUpdate(roomInfos); } - + public void OnRoomUserData() { foreach (var userDataListener in _roomUserDataListeners) userDataListener.OnUserDataUpdated(_client); } - public void OnPlayerUserData() + public void OnPlayerUserData(RagonPlayer player) { - + foreach(var playerUserDataListener in _playerUserDataListeners) + playerUserDataListener.OnPlayerUserDataUpdated(_client, player); } } } \ No newline at end of file diff --git a/Ragon.Client/Sources/RagonPlayer.cs b/Ragon.Client/Sources/RagonPlayer.cs index f1cf3da..3bfa375 100644 --- a/Ragon.Client/Sources/RagonPlayer.cs +++ b/Ragon.Client/Sources/RagonPlayer.cs @@ -1,5 +1,5 @@ /* - * Copyright 2023 Eduard Kargin + * Copyright 2023-2024 Eduard Kargin * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,8 +14,6 @@ * limitations under the License. */ -using Ragon.Protocol; - namespace Ragon.Client { [Serializable] @@ -26,7 +24,7 @@ namespace Ragon.Client public ushort PeerId { get; set; } public bool IsRoomOwner { get; set; } public bool IsLocal { get; set; } - public RagonUserData UserData { get; private set; } + public IUserData UserData { get; private set; } public RagonPlayer(ushort peerId, string playerId, string name, bool isRoomOwner, bool isLocal) { @@ -35,7 +33,7 @@ namespace Ragon.Client IsLocal = isLocal; Name = name; Id = playerId; - UserData = new RagonUserData(); + UserData = isLocal ? new RagonUserData() : new RagonUserDataReadOnly(); } } } \ No newline at end of file diff --git a/Ragon.Client/Sources/RagonPlayerCache.cs b/Ragon.Client/Sources/RagonPlayerCache.cs index d1cdcbd..c3d3f8a 100644 --- a/Ragon.Client/Sources/RagonPlayerCache.cs +++ b/Ragon.Client/Sources/RagonPlayerCache.cs @@ -1,5 +1,5 @@ /* - * Copyright 2023 Eduard Kargin + * Copyright 2023-2024 Eduard Kargin * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Ragon.Client/Sources/RagonRoom.cs b/Ragon.Client/Sources/RagonRoom.cs index 1a5a0ac..43ca668 100644 --- a/Ragon.Client/Sources/RagonRoom.cs +++ b/Ragon.Client/Sources/RagonRoom.cs @@ -1,5 +1,5 @@ /* - * Copyright 2023 Eduard Kargin + * Copyright 2023-2024 Eduard Kargin * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -107,7 +107,7 @@ namespace Ragon.Client RagonLog.Warn($"Handler event on entity {Id} with eventCode {eventCode} not defined"); } - internal void HandleProperties(RagonBuffer buffer) + internal void HandleUserData(RagonBuffer buffer) { _userData.Read(buffer); } diff --git a/Ragon.Client/Sources/RagonUserData.cs b/Ragon.Client/Sources/RagonUserData.cs index 44ca2d6..d51ae49 100644 --- a/Ragon.Client/Sources/RagonUserData.cs +++ b/Ragon.Client/Sources/RagonUserData.cs @@ -1,8 +1,24 @@ +/* + * Copyright 2024 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 { - public class RagonUserData + public class RagonUserData: IUserData { public byte[] this[string key] { @@ -22,8 +38,8 @@ namespace Ragon.Client public RagonUserData() { } - - internal void Read(RagonBuffer buffer) + + public void Read(RagonBuffer buffer) { _properties.Clear(); @@ -38,7 +54,7 @@ namespace Ragon.Client } } - internal void Write(RagonBuffer buffer) + public void Write(RagonBuffer buffer) { buffer.WriteUShort((ushort)_properties.Count); foreach (var property in _properties) diff --git a/Ragon.Client/Sources/RagonUserDataReadOnly.cs b/Ragon.Client/Sources/RagonUserDataReadOnly.cs new file mode 100644 index 0000000..110aa64 --- /dev/null +++ b/Ragon.Client/Sources/RagonUserDataReadOnly.cs @@ -0,0 +1,65 @@ +/* + * Copyright 2024 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; + +public class RagonUserDataReadOnly : IUserData +{ + public byte[] this[string key] + { + get => _properties[key]; + set { } + } + + public bool Dirty => _dirty; + + private bool _dirty = false; + private readonly Dictionary _properties = new(); + + public RagonUserDataReadOnly() + { + } + + public void Write(RagonBuffer buffer) + { + buffer.WriteUShort((ushort)_properties.Count); + foreach (var property in _properties) + { + buffer.WriteString(property.Key); + buffer.WriteUShort((ushort)property.Value.Length); + buffer.WriteBytes(property.Value); + } + + _dirty = false; + } + + public void Read(RagonBuffer buffer) + { + _properties.Clear(); + + var len = buffer.ReadUShort(); + for (int i = 0; i < len; i++) + { + var key = buffer.ReadString(); + var valueSize = buffer.ReadUShort(); + var value = buffer.ReadBytes(valueSize); + + _properties[key] = value; + } + } +} \ No newline at end of file diff --git a/Ragon.Protocol/Sources/RagonOperation.cs b/Ragon.Protocol/Sources/RagonOperation.cs index 2efbeae..f5a9960 100644 --- a/Ragon.Protocol/Sources/RagonOperation.cs +++ b/Ragon.Protocol/Sources/RagonOperation.cs @@ -45,7 +45,7 @@ namespace Ragon.Protocol TRANSFER_ENTITY_OWNERSHIP = 24, TIMESTAMP_SYNCHRONIZATION = 25, ROOM_LIST_UPDATED = 26, - PLAYER_PROPERTIES_UPDATED = 27, - ROOM_PROPERTIES_UPDATED = 28, + PLAYER_DATA_UPDATED = 27, + ROOM_DATA_UPDATED = 28, } } \ No newline at end of file diff --git a/Ragon.Relay/relay.config.json b/Ragon.Relay/relay.config.json index 25fbb5a..55c4b5e 100644 --- a/Ragon.Relay/relay.config.json +++ b/Ragon.Relay/relay.config.json @@ -10,6 +10,7 @@ "limitPlayersPerRoom": 20, "limitRooms": 200, "limitBufferedEvents": 50, + "limitUserData": 1024, "webHooks": { "room-created": "http://127.0.0.1:3000/service/create-room", diff --git a/Ragon.Server/Sources/Handler/PlayerPropertiesOperation.cs b/Ragon.Server/Sources/Handler/PlayerPropertiesOperation.cs deleted file mode 100644 index 32b055b..0000000 --- a/Ragon.Server/Sources/Handler/PlayerPropertiesOperation.cs +++ /dev/null @@ -1,28 +0,0 @@ -using NLog; -using Ragon.Protocol; -using Ragon.Server.IO; -using Ragon.Server.Lobby; - -namespace Ragon.Server.Handler -{ - public class PlayerPropertiesOperation : BaseOperation - { - private readonly ILogger _logger = LogManager.GetCurrentClassLogger(); - - public PlayerPropertiesOperation(RagonBuffer reader, RagonBuffer writer) : base(reader, writer) - { - } - - public override void Handle(RagonContext context, NetworkChannel channel) - { - if (context.ConnectionStatus == ConnectionStatus.Unauthorized) - { - _logger.Warn($"Player {context.Connection.Id} not authorized for this request"); - return; - } - - var playerData = Reader.ReadBytes(Reader.Capacity); - context.UserData.Data = playerData; - } - } -} \ No newline at end of file diff --git a/Ragon.Server/Sources/Handler/PlayerUserDataOperation.cs b/Ragon.Server/Sources/Handler/PlayerUserDataOperation.cs new file mode 100644 index 0000000..cc05955 --- /dev/null +++ b/Ragon.Server/Sources/Handler/PlayerUserDataOperation.cs @@ -0,0 +1,40 @@ +using NLog; +using Ragon.Protocol; +using Ragon.Server.IO; +using Ragon.Server.Lobby; + +namespace Ragon.Server.Handler +{ + public class PlayerUserDataOperation : BaseOperation + { + private readonly ILogger _logger = LogManager.GetCurrentClassLogger(); + private readonly int _userDataLimit; + + public PlayerUserDataOperation( + RagonBuffer reader, + RagonBuffer writer, + int userDataLimit + ) : base(reader, writer) + { + _userDataLimit = userDataLimit; + } + + public override void Handle(RagonContext context, NetworkChannel channel) + { + if (context.ConnectionStatus == ConnectionStatus.Unauthorized) + { + _logger.Warn($"Player {context.Connection.Id} not authorized for this request"); + return; + } + + var playerUserData = Reader.ReadBytes(Reader.Capacity); + if (playerUserData.Length > _userDataLimit) + { + _logger.Warn($"Player {context.Connection.Id} exceeded user data limit"); + return; + } + + context.UserData.Data = playerUserData; + } + } +} \ No newline at end of file diff --git a/Ragon.Server/Sources/Handler/RoomPropertiesOperation.cs b/Ragon.Server/Sources/Handler/RoomUserDataOperation.cs similarity index 70% rename from Ragon.Server/Sources/Handler/RoomPropertiesOperation.cs rename to Ragon.Server/Sources/Handler/RoomUserDataOperation.cs index c1b3119..ccffd20 100644 --- a/Ragon.Server/Sources/Handler/RoomPropertiesOperation.cs +++ b/Ragon.Server/Sources/Handler/RoomUserDataOperation.cs @@ -21,12 +21,18 @@ using Ragon.Server.Lobby; namespace Ragon.Server.Handler; -public sealed class RoomPropertiesOperation : BaseOperation +public sealed class RoomUserDataOperation : BaseOperation { private readonly ILogger _logger = LogManager.GetCurrentClassLogger(); - - public RoomPropertiesOperation(RagonBuffer reader, RagonBuffer writer) : base(reader, writer) + private readonly int _userDataLimit; + + public RoomUserDataOperation( + RagonBuffer reader, + RagonBuffer writer, + int userDataLimit + ) : base(reader, writer) { + _userDataLimit = userDataLimit; } public override void Handle(RagonContext context, NetworkChannel channel) @@ -36,11 +42,16 @@ public sealed class RoomPropertiesOperation : BaseOperation _logger.Warn($"Player {context.Connection.Id} not authorized for this request"); return; } - - var roomData = Reader.ReadBytes(Reader.Capacity); + var roomUserData = Reader.ReadBytes(Reader.Capacity); + if (roomUserData.Length > _userDataLimit) + { + _logger.Warn("Room user data is too big"); + return; + } + var room = context.Room; if (room != null) - room.UserData.Data = roomData; + room.UserData.Data = roomUserData; } } \ No newline at end of file diff --git a/Ragon.Server/Sources/RagonServer.cs b/Ragon.Server/Sources/RagonServer.cs index 68f877f..aaeda90 100644 --- a/Ragon.Server/Sources/RagonServer.cs +++ b/Ragon.Server/Sources/RagonServer.cs @@ -74,8 +74,8 @@ public class RagonServer : IRagonServer, INetworkListener var contextObserver = new RagonContextObserver(_contextsByPlayerId); _scheduler.Run(new RagonActionTimer(SendRoomList, 1.0f)); - _scheduler.Run(new RagonActionTimer(SendPlayerProperties, 1.0f)); - _scheduler.Run(new RagonActionTimer(SendRoomProperties, 1.0f)); + _scheduler.Run(new RagonActionTimer(SendPlayerUserData, 0.2f)); + _scheduler.Run(new RagonActionTimer(SendRoomUserData, 0.2f)); _serverPlugin.OnAttached(this); @@ -96,8 +96,8 @@ public class RagonServer : IRagonServer, INetworkListener _handlers[(byte)RagonOperation.TIMESTAMP_SYNCHRONIZATION] = new TimestampSyncOperation(_reader, _writer); _handlers[(byte)RagonOperation.REPLICATE_ROOM_EVENT] = new RoomEventOperation(_reader, _writer); _handlers[(byte)RagonOperation.REPLICATE_RAW_DATA] = new RoomDataOperation(_reader, _writer); - _handlers[(byte)RagonOperation.ROOM_PROPERTIES_UPDATED] = new RoomPropertiesOperation(_reader, _writer); - _handlers[(byte)RagonOperation.PLAYER_PROPERTIES_UPDATED] = new PlayerPropertiesOperation(_reader, _writer); + _handlers[(byte)RagonOperation.ROOM_DATA_UPDATED] = new RoomUserDataOperation(_reader, _writer, _configuration.LimitUserData); + _handlers[(byte)RagonOperation.PLAYER_DATA_UPDATED] = new PlayerUserDataOperation(_reader, _writer, _configuration.LimitUserData); _logger.Trace($"Server Tick Rate: {_configuration.ServerTickRate}"); } @@ -248,14 +248,14 @@ public class RagonServer : IRagonServer, INetworkListener } } - public void SendPlayerProperties() + public void SendPlayerUserData() { foreach (var (_, value) in _contextsByPlayerId) { if (value.UserData.IsDirty) { _writer.Clear(); - _writer.WriteOperation(RagonOperation.PLAYER_PROPERTIES_UPDATED); + _writer.WriteOperation(RagonOperation.PLAYER_DATA_UPDATED); _writer.WriteUShort(value.Connection.Id); _writer.WriteBytes(value.UserData.Data); @@ -267,14 +267,14 @@ public class RagonServer : IRagonServer, INetworkListener } } - public void SendRoomProperties() + public void SendRoomUserData() { foreach (var room in _lobby.Rooms) { if (room.UserData.IsDirty) { _writer.Clear(); - _writer.WriteOperation(RagonOperation.ROOM_PROPERTIES_UPDATED); + _writer.WriteOperation(RagonOperation.ROOM_DATA_UPDATED); _writer.WriteBytes(room.UserData.Data); var sendData = _writer.ToArray(); diff --git a/Ragon.Server/Sources/RagonServerConfiguration.cs b/Ragon.Server/Sources/RagonServerConfiguration.cs index 4cd3dda..3e1e3d2 100644 --- a/Ragon.Server/Sources/RagonServerConfiguration.cs +++ b/Ragon.Server/Sources/RagonServerConfiguration.cs @@ -39,6 +39,7 @@ public struct RagonServerConfiguration public int LimitPlayersPerRoom; public int LimitRooms; public int LimitBufferedEvents; + public int LimitUserData; public Dictionary WebHooks; private static readonly Logger Logger = LogManager.GetCurrentClassLogger();