diff --git a/Ragon.Protocol/Sources/RagonBuffer.cs b/Ragon.Protocol/Sources/RagonBuffer.cs index f8cb693..3630255 100644 --- a/Ragon.Protocol/Sources/RagonBuffer.cs +++ b/Ragon.Protocol/Sources/RagonBuffer.cs @@ -425,6 +425,32 @@ namespace Ragon.Protocol return data; } + + public void ToArray(byte[] outData) + { + Debug.Assert(outData.Length >= Length); + + var bucketsCount = (_write >> 5) + 1; + var length = Length; + + for (int i = 0; i < bucketsCount; i++) + { + var dataIdx = i * 4; + var bucket = _buckets[i]; + + if (dataIdx < length) + outData[dataIdx] = (byte)bucket; + + if (dataIdx + 1 < length) + outData[dataIdx + 1] = (byte)(bucket >> 8); + + if (dataIdx + 2 < length) + outData[dataIdx + 2] = (byte)(bucket >> 16); + + if (dataIdx + 3 < length) + outData[dataIdx + 3] = (byte)(bucket >> 24); + } + } private void Resize(int capacity) { diff --git a/Ragon.Protocol/Sources/RagonOperation.cs b/Ragon.Protocol/Sources/RagonOperation.cs index 32cecf2..2c43def 100644 --- a/Ragon.Protocol/Sources/RagonOperation.cs +++ b/Ragon.Protocol/Sources/RagonOperation.cs @@ -19,29 +19,30 @@ namespace Ragon.Protocol { public enum RagonOperation: byte { - AUTHORIZE, - AUTHORIZED_SUCCESS, - AUTHORIZED_FAILED, - JOIN_OR_CREATE_ROOM, - CREATE_ROOM, - JOIN_ROOM, - LEAVE_ROOM, - OWNERSHIP_ENTITY_CHANGED, - OWNERSHIP_ROOM_CHANGED, - JOIN_SUCCESS, - JOIN_FAILED, - LOAD_SCENE, - SCENE_LOADED, - PLAYER_JOINED, - PLAYER_LEAVED, - CREATE_ENTITY, - REMOVE_ENTITY, - SNAPSHOT, - REPLICATE_ENTITY_STATE, - REPLICATE_ENTITY_EVENT, - TRANSFER_ROOM_OWNERSHIP, - TRANSFER_ENTITY_OWNERSHIP, - REPLICATE_RAW_DATA, - TIMESTAMP_SYNCHRONIZATION, + AUTHORIZE = 1, + AUTHORIZED_SUCCESS = 2, + AUTHORIZED_FAILED = 3, + JOIN_OR_CREATE_ROOM = 4, + CREATE_ROOM = 5, + JOIN_ROOM = 6, + LEAVE_ROOM = 7, + OWNERSHIP_ENTITY_CHANGED = 8, + OWNERSHIP_ROOM_CHANGED= 9, + JOIN_SUCCESS = 10, + JOIN_FAILED = 11, + LOAD_SCENE = 12, + SCENE_LOADED = 13, + PLAYER_JOINED = 14, + PLAYER_LEAVED = 15, + CREATE_ENTITY = 16, + REMOVE_ENTITY = 17, + SNAPSHOT = 18, + REPLICATE_ENTITY_STATE = 19, + REPLICATE_ENTITY_EVENT = 20, + REPLICATE_RAW_DATA = 21, + REPLICATE_ROOM_EVENT = 22, + TRANSFER_ROOM_OWNERSHIP = 23, + TRANSFER_ENTITY_OWNERSHIP = 24, + TIMESTAMP_SYNCHRONIZATION = 25, } } \ No newline at end of file diff --git a/Ragon.Server.ENet/Sources/ENetConnection.cs b/Ragon.Server.ENet/Sources/ENetConnection.cs index 20b7aba..5169d9a 100644 --- a/Ragon.Server.ENet/Sources/ENetConnection.cs +++ b/Ragon.Server.ENet/Sources/ENetConnection.cs @@ -31,8 +31,8 @@ public sealed class ENetConnection: INetworkConnection _peer = peer; Id = (ushort) peer.ID; - Reliable = new ENetReliableChannel(peer, 0); - Unreliable = new ENetUnreliableChannel(peer, 1); + Reliable = new ENetReliableChannel(peer, NetworkChannel.RELIABLE); + Unreliable = new ENetUnreliableChannel(peer, NetworkChannel.UNRELIABLE); } public void Close() diff --git a/Ragon.Server.ENet/Sources/ENetReliableChannel.cs b/Ragon.Server.ENet/Sources/ENetReliableChannel.cs index 762ae3e..9828edd 100644 --- a/Ragon.Server.ENet/Sources/ENetReliableChannel.cs +++ b/Ragon.Server.ENet/Sources/ENetReliableChannel.cs @@ -14,7 +14,9 @@ * limitations under the License. */ +using System.Net; using ENet; +using Ragon.Protocol; using Ragon.Server.IO; namespace Ragon.Server.ENet; @@ -23,11 +25,13 @@ public sealed class ENetReliableChannel: INetworkChannel { private Peer _peer; private byte _channelId; + private byte[] _data; - public ENetReliableChannel(Peer peer, int channelId) + public ENetReliableChannel(Peer peer, NetworkChannel channel) { _peer = peer; - _channelId = (byte) channelId; + _data = new byte[1500]; + _channelId = (byte) channel; } public void Send(byte[] data) @@ -37,4 +41,14 @@ public sealed class ENetReliableChannel: INetworkChannel _peer.Send(_channelId, ref newPacket); } + + public void Send(RagonBuffer buffer) + { + buffer.ToArray(_data); + + var newPacket = new Packet(); + newPacket.Create(_data, buffer.Length, PacketFlags.Reliable); + + _peer.Send(_channelId, ref newPacket); + } } \ No newline at end of file diff --git a/Ragon.Server.ENet/Sources/ENetServer.cs b/Ragon.Server.ENet/Sources/ENetServer.cs index 1eacbc8..6bb1e01 100644 --- a/Ragon.Server.ENet/Sources/ENetServer.cs +++ b/Ragon.Server.ENet/Sources/ENetServer.cs @@ -118,7 +118,7 @@ namespace Ragon.Server.ENet _event.Packet.CopyTo(dataRaw); _event.Packet.Dispose(); - _listener.OnData(connection, dataRaw); + _listener.OnData(connection, (NetworkChannel) _event.ChannelID, dataRaw); break; } } diff --git a/Ragon.Server.ENet/Sources/ENetUnreliableChannel.cs b/Ragon.Server.ENet/Sources/ENetUnreliableChannel.cs index 268128e..9d3a50b 100644 --- a/Ragon.Server.ENet/Sources/ENetUnreliableChannel.cs +++ b/Ragon.Server.ENet/Sources/ENetUnreliableChannel.cs @@ -15,6 +15,7 @@ */ using ENet; +using Ragon.Protocol; using Ragon.Server.IO; namespace Ragon.Server.ENet; @@ -23,11 +24,12 @@ public sealed class ENetUnreliableChannel: INetworkChannel { private Peer _peer; private byte _channelId; + private byte[] _data; - public ENetUnreliableChannel(Peer peer, int channelId) + public ENetUnreliableChannel(Peer peer, NetworkChannel channel) { _peer = peer; - _channelId = (byte) channelId; + _channelId = (byte) channel; } public void Send(byte[] data) @@ -37,4 +39,14 @@ public sealed class ENetUnreliableChannel: INetworkChannel _peer.Send(_channelId, ref newPacket); } + + public void Send(RagonBuffer buffer) + { + buffer.ToArray(_data); + + var newPacket = new Packet(); + newPacket.Create(_data, buffer.Length, PacketFlags.None); + + _peer.Send(_channelId, ref newPacket); + } } \ No newline at end of file diff --git a/Ragon.Server.WebSocketServer/Sources/WebSocketReliableChannel.cs b/Ragon.Server.WebSocketServer/Sources/WebSocketReliableChannel.cs index c00c528..a3dfd61 100644 --- a/Ragon.Server.WebSocketServer/Sources/WebSocketReliableChannel.cs +++ b/Ragon.Server.WebSocketServer/Sources/WebSocketReliableChannel.cs @@ -15,6 +15,7 @@ */ using System.Net.WebSockets; +using Ragon.Protocol; using Ragon.Server.IO; namespace Ragon.Server.WebSocketServer; @@ -35,9 +36,17 @@ public class WebSocketReliableChannel : INetworkChannel _queue.Enqueue(data); } + public void Send(RagonBuffer buffer) + { + var sendData = buffer.ToArray(); + _queue.Enqueue(sendData); + } + public async Task Flush() { while (_queue.TryDequeue(out var sendData) && _socket.State == WebSocketState.Open) + { await _socket.SendAsync(sendData, WebSocketMessageType.Binary, WebSocketMessageFlags.EndOfMessage, CancellationToken.None); + } } } \ No newline at end of file diff --git a/Ragon.Server.WebSocketServer/Sources/WebSocketServer.cs b/Ragon.Server.WebSocketServer/Sources/WebSocketServer.cs index eed20db..5c5933a 100644 --- a/Ragon.Server.WebSocketServer/Sources/WebSocketServer.cs +++ b/Ragon.Server.WebSocketServer/Sources/WebSocketServer.cs @@ -82,9 +82,12 @@ public class WebSocketServer : INetworkServer try { var result = await webSocket.ReceiveAsync(buffer, cancellationToken); - var dataRaw = buffer.Slice(0, result.Count); - if (dataRaw.Length > 0) - _networkListener.OnData(connection, dataRaw.ToArray()); + if (result.Count > 0) + { + var channel = (RagonOperation) bytes[0] == RagonOperation.REPLICATE_RAW_DATA ? NetworkChannel.RAW : NetworkChannel.RELIABLE; + var payload = buffer.Slice(0, buffer.Length); + _networkListener.OnData(connection, channel , payload.ToArray()); + } } catch (Exception ex) { diff --git a/Ragon.Server/Sources/Handler/AuthorizationOperation.cs b/Ragon.Server/Sources/Handler/AuthorizationOperation.cs index 5d00c57..5e50626 100644 --- a/Ragon.Server/Sources/Handler/AuthorizationOperation.cs +++ b/Ragon.Server/Sources/Handler/AuthorizationOperation.cs @@ -22,24 +22,25 @@ using Ragon.Server.Plugin.Web; namespace Ragon.Server.Handler; -public sealed class AuthorizationOperation: IRagonOperation +public sealed class AuthorizationOperation: BaseOperation { private Logger _logger = LogManager.GetCurrentClassLogger(); - private readonly RagonWebHookPlugin _ragonWebHook; - private readonly RagonContextObserver _contextObserver; + private readonly RagonWebHookPlugin _webhook; + private readonly RagonContextObserver _observer; private readonly RagonBuffer _writer; public AuthorizationOperation( - RagonWebHookPlugin ragonWebHook, - RagonContextObserver contextObserver, - RagonBuffer writer) + RagonBuffer reader, + RagonBuffer writer, + RagonWebHookPlugin webhook, + RagonContextObserver observer): base(reader, writer) { - _ragonWebHook = ragonWebHook; - _contextObserver = contextObserver; + _webhook = webhook; + _observer = observer; _writer = writer; } - public void Handle(RagonContext context, RagonBuffer reader, RagonBuffer writer) + public override void Handle(RagonContext context, byte[] data) { if (context.ConnectionStatus == ConnectionStatus.Authorized) { @@ -54,13 +55,13 @@ public sealed class AuthorizationOperation: IRagonOperation } var configuration = context.Configuration; - var key = reader.ReadString(); - var name = reader.ReadString(); - var payload = reader.ReadString(); + var key = Reader.ReadString(); + var name = Reader.ReadString(); + var payload = Reader.ReadString(); if (key == configuration.ServerKey) { - if (_ragonWebHook.RequestAuthorization(context, name, payload)) + if (_webhook.RequestAuthorization(context, name, payload)) return; var lobbyPlayer = new RagonLobbyPlayer(context.Connection, Guid.NewGuid().ToString(), name, payload); @@ -78,7 +79,7 @@ public sealed class AuthorizationOperation: IRagonOperation { context.ConnectionStatus = ConnectionStatus.Authorized; - _contextObserver.OnAuthorized(context); + _observer.OnAuthorized(context); var playerId = context.LobbyPlayer.Id; var playerName = context.LobbyPlayer.Name; @@ -108,4 +109,6 @@ public sealed class AuthorizationOperation: IRagonOperation _logger.Trace($"Connection {context.Connection.Id}"); } + + } \ No newline at end of file diff --git a/Ragon.Server/Sources/Handler/IRagonOperation.cs b/Ragon.Server/Sources/Handler/BaseOperation.cs similarity index 69% rename from Ragon.Server/Sources/Handler/IRagonOperation.cs rename to Ragon.Server/Sources/Handler/BaseOperation.cs index 3db5c0a..de50cc6 100644 --- a/Ragon.Server/Sources/Handler/IRagonOperation.cs +++ b/Ragon.Server/Sources/Handler/BaseOperation.cs @@ -18,7 +18,16 @@ using Ragon.Protocol; namespace Ragon.Server.Handler; -public interface IRagonOperation +public abstract class BaseOperation { - public void Handle(RagonContext context, RagonBuffer reader, RagonBuffer writer); + protected readonly RagonBuffer Reader; + protected readonly RagonBuffer Writer; + + public BaseOperation(RagonBuffer reader, RagonBuffer writer) + { + Reader = reader; + Writer = writer; + } + + public abstract void Handle(RagonContext context, byte[] data); } \ No newline at end of file diff --git a/Ragon.Server/Sources/Handler/EntityCreateOperation.cs b/Ragon.Server/Sources/Handler/EntityCreateOperation.cs index c419d8c..b0b9a97 100644 --- a/Ragon.Server/Sources/Handler/EntityCreateOperation.cs +++ b/Ragon.Server/Sources/Handler/EntityCreateOperation.cs @@ -20,18 +20,22 @@ using Ragon.Server.Entity; namespace Ragon.Server.Handler; -public sealed class EntityCreateOperation : IRagonOperation +public sealed class EntityCreateOperation : BaseOperation { private readonly Logger _logger = LogManager.GetCurrentClassLogger(); - public void Handle(RagonContext context, RagonBuffer reader, RagonBuffer writer) + public EntityCreateOperation(RagonBuffer reader, RagonBuffer writer) : base(reader, writer) + { + } + + public override void Handle(RagonContext context, byte[] data) { var player = context.RoomPlayer; var room = context.Room; - var attachId = reader.ReadUShort(); - var entityType = reader.ReadUShort(); - var eventAuthority = (RagonAuthority) reader.ReadByte(); - var propertiesCount = reader.ReadUShort(); + var attachId = Reader.ReadUShort(); + var entityType = Reader.ReadUShort(); + var eventAuthority = (RagonAuthority) Reader.ReadByte(); + var propertiesCount = Reader.ReadUShort(); var entityParameters = new RagonEntityParameters() { @@ -45,14 +49,14 @@ public sealed class EntityCreateOperation : IRagonOperation var entity = new RagonEntity(entityParameters); for (var i = 0; i < propertiesCount; i++) { - var propertyType = reader.ReadBool(); - var propertySize = reader.ReadUShort(); + var propertyType = Reader.ReadBool(); + var propertySize = Reader.ReadUShort(); entity.AddProperty(new RagonProperty(propertySize, propertyType)); } - if (reader.Capacity > 0) - entity.Payload.Read(reader); + if (Reader.Capacity > 0) + entity.Payload.Read(Reader); var plugin = room.Plugin; if (!plugin.OnEntityCreate(player, entity)) @@ -66,4 +70,6 @@ public sealed class EntityCreateOperation : IRagonOperation _logger.Trace($"Player {context.Connection.Id}|{context.LobbyPlayer.Name} created entity {entity.Id}:{entity.Type}"); } + + } \ No newline at end of file diff --git a/Ragon.Server/Sources/Handler/EntityEventOperation.cs b/Ragon.Server/Sources/Handler/EntityEventOperation.cs index 63c51a8..c73f662 100644 --- a/Ragon.Server/Sources/Handler/EntityEventOperation.cs +++ b/Ragon.Server/Sources/Handler/EntityEventOperation.cs @@ -20,15 +20,19 @@ using Ragon.Server.Event; namespace Ragon.Server.Handler; -public sealed class EntityEventOperation : IRagonOperation +public sealed class EntityEventOperation : BaseOperation { private readonly Logger _logger = LogManager.GetCurrentClassLogger(); + + public EntityEventOperation(RagonBuffer reader, RagonBuffer writer) : base(reader, writer) + { + } - public void Handle(RagonContext context, RagonBuffer reader, RagonBuffer writer) + public override void Handle(RagonContext context, byte[] data) { var player = context.RoomPlayer; var room = context.Room; - var entityId = reader.ReadUShort(); + var entityId = Reader.ReadUShort(); if (!room.Entities.TryGetValue(entityId, out var ent)) { @@ -36,16 +40,16 @@ public sealed class EntityEventOperation : IRagonOperation return; } - var eventId = reader.ReadUShort(); - var eventMode = (RagonReplicationMode)reader.ReadByte(); - var targetMode = (RagonTarget)reader.ReadByte(); + var eventId = Reader.ReadUShort(); + var eventMode = (RagonReplicationMode)Reader.ReadByte(); + var targetMode = (RagonTarget)Reader.ReadByte(); var targetPlayerPeerId = (ushort)0; if (targetMode == RagonTarget.Player) - targetPlayerPeerId = reader.ReadUShort(); + targetPlayerPeerId = Reader.ReadUShort(); var @event = new RagonEvent(player, eventId); - @event.Read(reader); + @event.Read(Reader); if (targetMode == RagonTarget.Player && room.Players.TryGetValue(targetPlayerPeerId, out var targetPlayer)) { diff --git a/Ragon.Server/Sources/Handler/EntityOwnershipOperation.cs b/Ragon.Server/Sources/Handler/EntityOwnershipOperation.cs index 7deb29d..4b20eb0 100644 --- a/Ragon.Server/Sources/Handler/EntityOwnershipOperation.cs +++ b/Ragon.Server/Sources/Handler/EntityOwnershipOperation.cs @@ -3,17 +3,21 @@ using Ragon.Protocol; namespace Ragon.Server.Handler; -public sealed class EntityOwnershipOperation : IRagonOperation +public sealed class EntityOwnershipOperation : BaseOperation { private readonly Logger _logger = LogManager.GetCurrentClassLogger(); + + public EntityOwnershipOperation(RagonBuffer reader, RagonBuffer writer) : base(reader, writer) + { + } - public void Handle(RagonContext context, RagonBuffer reader, RagonBuffer writer) + public override void Handle(RagonContext context, byte[] data) { var currentOwner = context.RoomPlayer; var room = context.Room; - var entityId = reader.ReadUShort(); - var playerPeerId = reader.ReadUShort(); + var entityId = Reader.ReadUShort(); + var playerPeerId = Reader.ReadUShort(); if (!room.Entities.TryGetValue(entityId, out var entity)) { @@ -40,13 +44,13 @@ public sealed class EntityOwnershipOperation : IRagonOperation _logger.Trace($"Entity {entity.Id} next owner {nextOwner.Connection.Id}"); - writer.Clear(); - writer.WriteOperation(RagonOperation.OWNERSHIP_ENTITY_CHANGED); - writer.WriteUShort(playerPeerId); - writer.WriteUShort(1); - writer.WriteUShort(entity.Id); + Writer.Clear(); + Writer.WriteOperation(RagonOperation.OWNERSHIP_ENTITY_CHANGED); + Writer.WriteUShort(playerPeerId); + Writer.WriteUShort(1); + Writer.WriteUShort(entity.Id); - var sendData = writer.ToArray(); + var sendData = Writer.ToArray(); foreach (var player in room.PlayerList) player.Connection.Reliable.Send(sendData); } diff --git a/Ragon.Server/Sources/Handler/EntityRemoveOperation.cs b/Ragon.Server/Sources/Handler/EntityRemoveOperation.cs index e3ec76a..d799ff6 100644 --- a/Ragon.Server/Sources/Handler/EntityRemoveOperation.cs +++ b/Ragon.Server/Sources/Handler/EntityRemoveOperation.cs @@ -20,20 +20,24 @@ using Ragon.Server.Entity; namespace Ragon.Server.Handler; -public sealed class EntityDestroyOperation: IRagonOperation +public sealed class EntityDestroyOperation: BaseOperation { private readonly Logger _logger = LogManager.GetCurrentClassLogger(); - public void Handle(RagonContext context, RagonBuffer reader, RagonBuffer writer) + public EntityDestroyOperation(RagonBuffer reader, RagonBuffer writer) : base(reader, writer) + { + } + + public override void Handle(RagonContext context, byte[] data) { var player = context.RoomPlayer; var room = context.Room; - var entityId = reader.ReadUShort(); + var entityId = Reader.ReadUShort(); if (room.Entities.TryGetValue(entityId, out var entity)) { var payload = new RagonPayload(); - payload.Read(reader); + payload.Read(Reader); room.DetachEntity(entity); player.DetachEntity(entity); diff --git a/Ragon.Server/Sources/Handler/EntityStateOperation.cs b/Ragon.Server/Sources/Handler/EntityStateOperation.cs index 639ebde..47776ef 100644 --- a/Ragon.Server/Sources/Handler/EntityStateOperation.cs +++ b/Ragon.Server/Sources/Handler/EntityStateOperation.cs @@ -19,20 +19,24 @@ using Ragon.Protocol; namespace Ragon.Server.Handler; -public sealed class EntityStateOperation: IRagonOperation +public sealed class EntityStateOperation: BaseOperation { private readonly ILogger _logger = LogManager.GetCurrentClassLogger(); - - public void Handle(RagonContext context, RagonBuffer reader, RagonBuffer writer) + + public EntityStateOperation(RagonBuffer reader, RagonBuffer writer) : base(reader, writer) + { + } + + public override void Handle(RagonContext context, byte[] data) { var room = context.Room; var player = context.RoomPlayer; - var entitiesCount = reader.ReadUShort(); + var entitiesCount = Reader.ReadUShort(); for (var entityIndex = 0; entityIndex < entitiesCount; entityIndex++) { - var entityId = reader.ReadUShort(); - if (room.Entities.TryGetValue(entityId, out var entity) && entity.TryReadState(player, reader)) + var entityId = Reader.ReadUShort(); + if (room.Entities.TryGetValue(entityId, out var entity) && entity.TryReadState(player, Reader)) { room.Track(entity); } diff --git a/Ragon.Server/Sources/Handler/RoomCreateOperation.cs b/Ragon.Server/Sources/Handler/RoomCreateOperation.cs index c36c18b..6c028e1 100644 --- a/Ragon.Server/Sources/Handler/RoomCreateOperation.cs +++ b/Ragon.Server/Sources/Handler/RoomCreateOperation.cs @@ -23,20 +23,20 @@ using Ragon.Server.Room; namespace Ragon.Server.Handler; -public sealed class RoomCreateOperation: IRagonOperation +public sealed class RoomCreateOperation : BaseOperation { private readonly RagonRoomParameters _roomParameters = new(); private readonly Logger _logger = LogManager.GetCurrentClassLogger(); private readonly IServerPlugin _serverPlugin; private readonly RagonWebHookPlugin _ragonWebHookPlugin; - - public RoomCreateOperation(IServerPlugin serverPlugin, RagonWebHookPlugin ragonWebHook) + + public RoomCreateOperation(RagonBuffer reader, RagonBuffer writer, IServerPlugin serverPlugin, RagonWebHookPlugin ragonWebHook) : base(reader, writer) { _serverPlugin = serverPlugin; _ragonWebHookPlugin = ragonWebHook; } - public void Handle(RagonContext context, RagonBuffer reader, RagonBuffer writer) + public override void Handle(RagonContext context, byte[] data) { if (context.ConnectionStatus == ConnectionStatus.Unauthorized) { @@ -44,56 +44,56 @@ public sealed class RoomCreateOperation: IRagonOperation return; } - var custom = reader.ReadBool(); + var custom = Reader.ReadBool(); var roomId = Guid.NewGuid().ToString(); - + if (custom) { - roomId = reader.ReadString(); + roomId = Reader.ReadString(); if (context.Lobby.FindRoomById(roomId, out _)) - { - writer.Clear(); - writer.WriteOperation(RagonOperation.JOIN_FAILED); - writer.WriteString($"Room with id {roomId} already exists"); - - var sendData = writer.ToArray(); + { + Writer.Clear(); + Writer.WriteOperation(RagonOperation.JOIN_FAILED); + Writer.WriteString($"Room with id {roomId} already exists"); + + var sendData = Writer.ToArray(); context.Connection.Reliable.Send(sendData); - + _logger.Trace($"Player {context.Connection.Id}|{context.LobbyPlayer.Name} join failed to room {roomId}, room already exist"); - return; + return; } } - - _roomParameters.Deserialize(reader); - + + _roomParameters.Deserialize(Reader); + var information = new RoomInformation() { - Scene = _roomParameters.Scene, - Max = _roomParameters.Max, - Min = _roomParameters.Min, + Scene = _roomParameters.Scene, + Max = _roomParameters.Max, + Min = _roomParameters.Min, }; var lobbyPlayer = context.LobbyPlayer; var roomPlayer = new RagonRoomPlayer(context.Connection, lobbyPlayer.Id, lobbyPlayer.Name); - + var roomPlugin = _serverPlugin.CreateRoomPlugin(information); var room = new RagonRoom(roomId, information, roomPlugin); - + roomPlayer.OnAttached(room); - + context.Scheduler.Run(room); context.Lobby.Persist(room); context.SetRoom(room, roomPlayer); - + _ragonWebHookPlugin.RoomCreated(context, room, roomPlayer); - + _logger.Trace($"Player {context.Connection.Id}|{context.LobbyPlayer.Name} create room {room.Id} with scene {information.Scene}"); - - JoinSuccess(roomPlayer, room, writer); - + + JoinSuccess(roomPlayer, room, Writer); + _logger.Trace($"Player {context.Connection.Id}|{context.LobbyPlayer.Name} joined to room {room.Id}"); } - + private void JoinSuccess(RagonRoomPlayer player, RagonRoom room, RagonBuffer writer) { writer.Clear(); @@ -101,8 +101,8 @@ public sealed class RoomCreateOperation: IRagonOperation writer.WriteString(room.Id); writer.WriteString(player.Id); writer.WriteString(room.Owner.Id); - writer.WriteUShort((ushort) room.PlayerMin); - writer.WriteUShort((ushort) room.PlayerMax); + writer.WriteUShort((ushort)room.PlayerMin); + writer.WriteUShort((ushort)room.PlayerMax); writer.WriteString(room.Scene); var sendData = writer.ToArray(); diff --git a/Ragon.Server/Sources/Handler/RoomDataOperation.cs b/Ragon.Server/Sources/Handler/RoomDataOperation.cs new file mode 100644 index 0000000..395b294 --- /dev/null +++ b/Ragon.Server/Sources/Handler/RoomDataOperation.cs @@ -0,0 +1,47 @@ +/* + * 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 NLog; +using Ragon.Protocol; + +namespace Ragon.Server.Handler; + +public sealed class RoomDataOperation : BaseOperation +{ + public RoomDataOperation(RagonBuffer reader, RagonBuffer writer) : base(reader, writer) + { + } + + public override void Handle(RagonContext context, byte[] data) + { + var player = context.RoomPlayer; + var room = context.Room; + + Writer.Clear(); + Writer.WriteOperation(RagonOperation.REPLICATE_RAW_DATA); + Writer.WriteUShort(player.Connection.Id); + + var playerData = Writer.ToArray(); + var payloadData = data; + var size = playerData.Length + payloadData.Length; + var sendData = new byte[size]; + + Array.Copy(playerData, 0, sendData, 0, playerData.Length); + Array.Copy(payloadData, 0, sendData, playerData.Length, payloadData.Length); + + room.Broadcast(sendData); + } +} \ No newline at end of file diff --git a/Ragon.Server/Sources/Handler/RoomEventOperation.cs b/Ragon.Server/Sources/Handler/RoomEventOperation.cs new file mode 100644 index 0000000..df7c7d6 --- /dev/null +++ b/Ragon.Server/Sources/Handler/RoomEventOperation.cs @@ -0,0 +1,44 @@ +using Ragon.Protocol; +using Ragon.Server.Event; + +namespace Ragon.Server.Handler; + +public class RoomEventOperation : BaseOperation +{ + public RoomEventOperation(RagonBuffer reader, RagonBuffer writer) : base(reader, writer) + { + } + + public override void Handle(RagonContext context, byte[] data) + { + var room = context.Room; + var player = context.RoomPlayer; + + var eventId = Reader.ReadUShort(); + var replicationMode = (RagonReplicationMode)Reader.ReadByte(); + var targetMode = (RagonTarget)Reader.ReadByte(); + var targetPlayerPeerId = (ushort)0; + + if (targetMode == RagonTarget.Player) + targetPlayerPeerId = Reader.ReadUShort(); + + var @event = new RagonEvent(player, eventId); + @event.Read(Reader); + + Writer.Clear(); + Writer.WriteUShort(eventId); + Writer.WriteUShort(player.Connection.Id); + Writer.WriteUShort((ushort) replicationMode); + + var sendData = Writer.ToArray(); + + if (targetMode == RagonTarget.Player && room.Players.TryGetValue(targetPlayerPeerId, out var targetPlayer)) + { + targetPlayer.Connection.Reliable.Send(sendData); + return; + } + + foreach (var roomPlayer in room.ReadyPlayersList) + roomPlayer.Connection.Reliable.Send(sendData); + } +} \ No newline at end of file diff --git a/Ragon.Server/Sources/Handler/RoomJoinOperation.cs b/Ragon.Server/Sources/Handler/RoomJoinOperation.cs index dc1e1ec..6e47f79 100644 --- a/Ragon.Server/Sources/Handler/RoomJoinOperation.cs +++ b/Ragon.Server/Sources/Handler/RoomJoinOperation.cs @@ -22,40 +22,40 @@ using Ragon.Server.Room; namespace Ragon.Server.Handler; -public sealed class RoomJoinOperation : IRagonOperation +public sealed class RoomJoinOperation : BaseOperation { private readonly Logger _logger = LogManager.GetCurrentClassLogger(); - private readonly RagonWebHookPlugin _webHook; - - public RoomJoinOperation(RagonWebHookPlugin plugin) + + public RoomJoinOperation(RagonBuffer reader, RagonBuffer writer, RagonWebHookPlugin plugin) : base(reader, writer) { _webHook = plugin; } - public void Handle(RagonContext context, RagonBuffer reader, RagonBuffer writer) + + public override void Handle(RagonContext context, byte[] data) { - var roomId = reader.ReadString(); + var roomId = Reader.ReadString(); var lobbyPlayer = context.LobbyPlayer; if (!context.Lobby.FindRoomById(roomId, out var existsRoom)) { - JoinFailed(context, writer); - + JoinFailed(context, Writer); + _logger.Trace($"Player {context.Connection.Id}|{context.LobbyPlayer.Name} failed to join room {roomId}"); return; } var player = new RagonRoomPlayer(context.Connection, lobbyPlayer.Id, lobbyPlayer.Name); context.SetRoom(existsRoom, player); - + if (!existsRoom.Plugin.OnPlayerJoined(player)) return; - + _webHook.RoomJoined(context, existsRoom, player); - - JoinSuccess(context, existsRoom, writer); - + + JoinSuccess(context, existsRoom, Writer); + _logger.Trace($"Player {context.Connection.Id}|{context.LobbyPlayer.Name} joined to {existsRoom.Id}"); } @@ -66,8 +66,8 @@ public sealed class RoomJoinOperation : IRagonOperation writer.WriteString(room.Id); writer.WriteString(context.RoomPlayer.Id); writer.WriteString(room.Owner.Id); - writer.WriteUShort((ushort) room.PlayerMin); - writer.WriteUShort((ushort) room.PlayerMax); + writer.WriteUShort((ushort)room.PlayerMin); + writer.WriteUShort((ushort)room.PlayerMax); writer.WriteString(room.Scene); var sendData = writer.ToArray(); diff --git a/Ragon.Server/Sources/Handler/RoomJoinOrCreateOperation.cs b/Ragon.Server/Sources/Handler/RoomJoinOrCreateOperation.cs index 95226aa..3670e86 100644 --- a/Ragon.Server/Sources/Handler/RoomJoinOrCreateOperation.cs +++ b/Ragon.Server/Sources/Handler/RoomJoinOrCreateOperation.cs @@ -23,20 +23,20 @@ using Ragon.Server.Room; namespace Ragon.Server.Handler; -public sealed class RoomJoinOrCreateOperation : IRagonOperation +public sealed class RoomJoinOrCreateOperation : BaseOperation { private readonly RagonRoomParameters _roomParameters = new(); private readonly Logger _logger = LogManager.GetCurrentClassLogger(); private readonly IServerPlugin _serverPlugin; private readonly RagonWebHookPlugin _ragonWebHookPlugin; - public RoomJoinOrCreateOperation(IServerPlugin serverPlugin, RagonWebHookPlugin plugin) + public RoomJoinOrCreateOperation(RagonBuffer reader, RagonBuffer writer, IServerPlugin serverPlugin, RagonWebHookPlugin plugin): base(reader, writer) { _serverPlugin = serverPlugin; _ragonWebHookPlugin = plugin; } - - public void Handle(RagonContext context, RagonBuffer reader, RagonBuffer writer) + + public override void Handle(RagonContext context, byte[] data) { if (context.ConnectionStatus == ConnectionStatus.Unauthorized) { @@ -47,7 +47,7 @@ public sealed class RoomJoinOrCreateOperation : IRagonOperation var roomId = Guid.NewGuid().ToString(); var lobbyPlayer = context.LobbyPlayer; - _roomParameters.Deserialize(reader); + _roomParameters.Deserialize(Reader); if (context.Lobby.FindRoomByScene(_roomParameters.Scene, out var existsRoom)) { @@ -56,7 +56,7 @@ public sealed class RoomJoinOrCreateOperation : IRagonOperation _ragonWebHookPlugin.RoomJoined(context, existsRoom, player); - JoinSuccess(player, existsRoom, writer); + JoinSuccess(player, existsRoom, Writer); } else { @@ -79,7 +79,7 @@ public sealed class RoomJoinOrCreateOperation : IRagonOperation _logger.Trace($"Player {context.Connection.Id}|{context.LobbyPlayer.Name} create room {room.Id} with scene {information.Scene}"); - JoinSuccess(roomPlayer, room, writer); + JoinSuccess(roomPlayer, room, Writer); } } diff --git a/Ragon.Server/Sources/Handler/RoomLeaveOperation.cs b/Ragon.Server/Sources/Handler/RoomLeaveOperation.cs index 0acb494..bda8b5d 100644 --- a/Ragon.Server/Sources/Handler/RoomLeaveOperation.cs +++ b/Ragon.Server/Sources/Handler/RoomLeaveOperation.cs @@ -21,16 +21,17 @@ using Ragon.Server.Plugin.Web; namespace Ragon.Server.Handler; -public sealed class RoomLeaveOperation: IRagonOperation +public sealed class RoomLeaveOperation: BaseOperation { private readonly Logger _logger = LogManager.GetCurrentClassLogger(); private readonly RagonWebHookPlugin _webHook; - public RoomLeaveOperation(RagonWebHookPlugin plugin) + + public RoomLeaveOperation(RagonBuffer reader, RagonBuffer writer, RagonWebHookPlugin plugin): base(reader, writer) { _webHook = plugin; } - public void Handle(RagonContext context, RagonBuffer reader, RagonBuffer writer) + public override void Handle(RagonContext context, byte[] data) { var room = context.Room; var roomPlayer = context.RoomPlayer; diff --git a/Ragon.Server/Sources/Handler/RoomOwnershipOperation.cs b/Ragon.Server/Sources/Handler/RoomOwnershipOperation.cs index 5ef9fa2..859a4ef 100644 --- a/Ragon.Server/Sources/Handler/RoomOwnershipOperation.cs +++ b/Ragon.Server/Sources/Handler/RoomOwnershipOperation.cs @@ -4,11 +4,16 @@ using Ragon.Server.Entity; namespace Ragon.Server.Handler; -public sealed class RoomOwnershipOperation : IRagonOperation +public sealed class RoomOwnershipOperation : BaseOperation { private readonly Logger _logger = LogManager.GetCurrentClassLogger(); - public void Handle(RagonContext context, RagonBuffer reader, RagonBuffer writer) + + public RoomOwnershipOperation(RagonBuffer reader, RagonBuffer writer) : base(reader, writer) { - + } + + public override void Handle(RagonContext context, byte[] data) + { + } } \ No newline at end of file diff --git a/Ragon.Server/Sources/Handler/SceneLoadOperation.cs b/Ragon.Server/Sources/Handler/SceneLoadOperation.cs index 5fee7e6..4d74a77 100644 --- a/Ragon.Server/Sources/Handler/SceneLoadOperation.cs +++ b/Ragon.Server/Sources/Handler/SceneLoadOperation.cs @@ -20,16 +20,18 @@ using Ragon.Protocol; namespace Ragon.Server.Handler; -public class SceneLoadOperation: IRagonOperation +public class SceneLoadOperation: BaseOperation { private readonly Logger _logger = LogManager.GetCurrentClassLogger(); - - public void Handle(RagonContext context, RagonBuffer reader, RagonBuffer writer) + + public SceneLoadOperation(RagonBuffer reader, RagonBuffer writer) : base(reader, writer) {} + + public override void Handle(RagonContext context, byte[] data) { var roomOwner = context.Room.Owner; var currentPlayer = context.RoomPlayer; var room = context.Room; - var sceneName = reader.ReadString(); + var sceneName = Reader.ReadString(); if (roomOwner.Connection.Id != currentPlayer.Connection.Id) { @@ -39,11 +41,11 @@ public class SceneLoadOperation: IRagonOperation room.UpdateMap(sceneName); - writer.Clear(); - writer.WriteOperation(RagonOperation.LOAD_SCENE); - writer.WriteString(sceneName); + Writer.Clear(); + Writer.WriteOperation(RagonOperation.LOAD_SCENE); + Writer.WriteString(sceneName); - var sendData = writer.ToArray(); + var sendData = Writer.ToArray(); foreach (var player in room.PlayerList) player.Connection.Reliable.Send(sendData); } diff --git a/Ragon.Server/Sources/Handler/SceneLoadedOperation.cs b/Ragon.Server/Sources/Handler/SceneLoadedOperation.cs index 865f6bc..377d192 100644 --- a/Ragon.Server/Sources/Handler/SceneLoadedOperation.cs +++ b/Ragon.Server/Sources/Handler/SceneLoadedOperation.cs @@ -22,16 +22,16 @@ using Ragon.Server.Room; namespace Ragon.Server.Handler; -public sealed class SceneLoadedOperation : IRagonOperation +public sealed class SceneLoadedOperation : BaseOperation { private readonly Logger _logger = LogManager.GetCurrentClassLogger(); - public SceneLoadedOperation() + public SceneLoadedOperation(RagonBuffer reader, RagonBuffer writer): base(reader, writer) { } - - public void Handle(RagonContext context, RagonBuffer reader, RagonBuffer writer) + + public override void Handle(RagonContext context, byte[] data) { if (context.ConnectionStatus == ConnectionStatus.Unauthorized) return; @@ -42,13 +42,13 @@ public sealed class SceneLoadedOperation : IRagonOperation if (player == owner) { - var statics = reader.ReadUShort(); + var statics = Reader.ReadUShort(); for (var staticIndex = 0; staticIndex < statics; staticIndex++) { - var entityType = reader.ReadUShort(); - var eventAuthority = (RagonAuthority)reader.ReadByte(); - var staticId = reader.ReadUShort(); - var propertiesCount = reader.ReadUShort(); + var entityType = Reader.ReadUShort(); + var eventAuthority = (RagonAuthority)Reader.ReadByte(); + var staticId = Reader.ReadUShort(); + var propertiesCount = Reader.ReadUShort(); var entityParameters = new RagonEntityParameters() { @@ -62,8 +62,8 @@ public sealed class SceneLoadedOperation : IRagonOperation var entity = new RagonEntity(entityParameters); for (var propertyIndex = 0; propertyIndex < propertiesCount; propertyIndex++) { - var propertyType = reader.ReadBool(); - var propertySize = reader.ReadUShort(); + var propertyType = Reader.ReadBool(); + var propertySize = Reader.ReadUShort(); entity.AddProperty(new RagonProperty(propertySize, propertyType)); } @@ -86,14 +86,14 @@ public sealed class SceneLoadedOperation : IRagonOperation foreach (var roomPlayer in room.WaitPlayersList) { - DispatchPlayerJoinExcludePlayer(room, roomPlayer, writer); + DispatchPlayerJoinExcludePlayer(room, roomPlayer, Writer); roomPlayer.SetReady(); } room.UpdateReadyPlayerList(); - DispatchSnapshot(room, room.WaitPlayersList, writer); + DispatchSnapshot(room, room.WaitPlayersList, Writer); room.WaitPlayersList.Clear(); } @@ -101,14 +101,14 @@ public sealed class SceneLoadedOperation : IRagonOperation { player.SetReady(); - DispatchPlayerJoinExcludePlayer(room, player, writer); + DispatchPlayerJoinExcludePlayer(room, player, Writer); room.UpdateReadyPlayerList(); - DispatchSnapshot(room, new List() { player }, writer); + DispatchSnapshot(room, new List() { player }, Writer); foreach (var entity in room.EntityList) - entity.RestoreBufferedEvents(player, writer); + entity.RestoreBufferedEvents(player, Writer); } else { diff --git a/Ragon.Server/Sources/Handler/TimestampSyncOperation.cs b/Ragon.Server/Sources/Handler/TimestampSyncOperation.cs index 4989f37..5ca9ba7 100644 --- a/Ragon.Server/Sources/Handler/TimestampSyncOperation.cs +++ b/Ragon.Server/Sources/Handler/TimestampSyncOperation.cs @@ -2,12 +2,16 @@ using Ragon.Protocol; namespace Ragon.Server.Handler; -public class TimestampSyncOperation: IRagonOperation +public class TimestampSyncOperation: BaseOperation { - public void Handle(RagonContext context, RagonBuffer reader, RagonBuffer writer) + public TimestampSyncOperation(RagonBuffer reader, RagonBuffer writer) : base(reader, writer) { - var timestamp0 = reader.Read(32); - var timestamp1 = reader.Read(32); + } + + public override void Handle(RagonContext context, byte[] data) + { + var timestamp0 = Reader.Read(32); + var timestamp1 = Reader.Read(32); var value = new DoubleToUInt() { Int0 = timestamp0, Int1 = timestamp1 }; context.RoomPlayer?.SetTimestamp(value.Double); diff --git a/Ragon.Server/Sources/IO/INetworkChannel.cs b/Ragon.Server/Sources/IO/INetworkChannel.cs index d18b1ca..67b0c2c 100644 --- a/Ragon.Server/Sources/IO/INetworkChannel.cs +++ b/Ragon.Server/Sources/IO/INetworkChannel.cs @@ -21,4 +21,5 @@ namespace Ragon.Server.IO; public interface INetworkChannel { void Send(byte[] data); + void Send(RagonBuffer buffer); } \ No newline at end of file diff --git a/Ragon.Server/Sources/IO/INetworkListener.cs b/Ragon.Server/Sources/IO/INetworkListener.cs index ff47db9..a498567 100644 --- a/Ragon.Server/Sources/IO/INetworkListener.cs +++ b/Ragon.Server/Sources/IO/INetworkListener.cs @@ -21,5 +21,5 @@ public interface INetworkListener void OnConnected(INetworkConnection connection); void OnDisconnected(INetworkConnection connection); void OnTimeout(INetworkConnection connection); - void OnData(INetworkConnection connection, byte[] data); + void OnData(INetworkConnection connection, NetworkChannel channel, byte[] data); } \ No newline at end of file diff --git a/Ragon.Server/Sources/IO/NetworkChannel.cs b/Ragon.Server/Sources/IO/NetworkChannel.cs new file mode 100644 index 0000000..241bffd --- /dev/null +++ b/Ragon.Server/Sources/IO/NetworkChannel.cs @@ -0,0 +1,8 @@ +namespace Ragon.Server.IO; + +public enum NetworkChannel +{ + RELIABLE = 1, + UNRELIABLE = 2, + RAW = 3, +} \ No newline at end of file diff --git a/Ragon.Server/Sources/RagonServer.cs b/Ragon.Server/Sources/RagonServer.cs index d306e03..a6198bc 100644 --- a/Ragon.Server/Sources/RagonServer.cs +++ b/Ragon.Server/Sources/RagonServer.cs @@ -31,7 +31,7 @@ public class RagonServer : IRagonServer, INetworkListener { private readonly Logger _logger = LogManager.GetCurrentClassLogger(); private readonly INetworkServer _server; - private readonly IRagonOperation[] _handlers; + private readonly BaseOperation[] _handlers; private readonly IRagonLobby _lobby; private readonly IServerPlugin _serverPlugin; private readonly Thread _dedicatedThread; @@ -46,7 +46,7 @@ public class RagonServer : IRagonServer, INetworkListener private readonly Dictionary _contextsByPlayerId; private readonly Stopwatch _timer; private readonly long _tickRate = 0; - + public RagonServer( INetworkServer server, IServerPlugin plugin, @@ -68,28 +68,29 @@ public class RagonServer : IRagonServer, INetworkListener _writer = new RagonBuffer(); _tickRate = 1000 / _configuration.ServerTickRate; _timer = new Stopwatch(); - + var contextObserver = new RagonContextObserver(_contextsByPlayerId); - + _serverPlugin.OnAttached(this); - - _handlers = new IRagonOperation[byte.MaxValue]; - _handlers[(byte) RagonOperation.AUTHORIZE] = new AuthorizationOperation(_webhooks, contextObserver, _writer); - _handlers[(byte) RagonOperation.JOIN_OR_CREATE_ROOM] = new RoomJoinOrCreateOperation(plugin, _webhooks); - _handlers[(byte) RagonOperation.CREATE_ROOM] = new RoomCreateOperation(plugin, _webhooks); - _handlers[(byte) RagonOperation.JOIN_ROOM] = new RoomJoinOperation(_webhooks); - _handlers[(byte) RagonOperation.LEAVE_ROOM] = new RoomLeaveOperation(_webhooks); - _handlers[(byte) RagonOperation.LOAD_SCENE] = new SceneLoadOperation(); - _handlers[(byte) RagonOperation.SCENE_LOADED] = new SceneLoadedOperation(); - _handlers[(byte) RagonOperation.CREATE_ENTITY] = new EntityCreateOperation(); - _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(); - _handlers[(byte)RagonOperation.REPLICATE_RAW_DATA] = new RoomDataOperation(); - _handlers[(byte)RagonOperation.TIMESTAMP_SYNCHRONIZATION] = new TimestampSyncOperation(); - + + _handlers = new BaseOperation[byte.MaxValue]; + _handlers[(byte)RagonOperation.AUTHORIZE] = new AuthorizationOperation(_reader, _writer, _webhooks, contextObserver); + _handlers[(byte)RagonOperation.JOIN_OR_CREATE_ROOM] = new RoomJoinOrCreateOperation(_reader, _writer, plugin, _webhooks); + _handlers[(byte)RagonOperation.CREATE_ROOM] = new RoomCreateOperation(_reader, _writer, plugin, _webhooks); + _handlers[(byte)RagonOperation.JOIN_ROOM] = new RoomJoinOperation(_reader, _writer, _webhooks); + _handlers[(byte)RagonOperation.LEAVE_ROOM] = new RoomLeaveOperation(_reader, _writer, _webhooks); + _handlers[(byte)RagonOperation.LOAD_SCENE] = new SceneLoadOperation(_reader, _writer); + _handlers[(byte)RagonOperation.SCENE_LOADED] = new SceneLoadedOperation(_reader, _writer); + _handlers[(byte)RagonOperation.CREATE_ENTITY] = new EntityCreateOperation(_reader, _writer); + _handlers[(byte)RagonOperation.REMOVE_ENTITY] = new EntityDestroyOperation(_reader, _writer); + _handlers[(byte)RagonOperation.REPLICATE_ENTITY_EVENT] = new EntityEventOperation(_reader, _writer); + _handlers[(byte)RagonOperation.REPLICATE_ENTITY_STATE] = new EntityStateOperation(_reader, _writer); + _handlers[(byte)RagonOperation.TRANSFER_ROOM_OWNERSHIP] = new EntityOwnershipOperation(_reader, _writer); + _handlers[(byte)RagonOperation.TRANSFER_ENTITY_OWNERSHIP] = new EntityOwnershipOperation(_reader, _writer); + _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); + _logger.Trace($"Server Tick Rate: {_configuration.ServerTickRate}"); } @@ -102,10 +103,10 @@ public class RagonServer : IRagonServer, INetworkListener { _timer.Restart(); _scheduler.Update(_timer.ElapsedMilliseconds / 1000.0f); - + SendTimestamp(); } - + _executor.Update(); _server.Update(); Thread.Sleep(1); @@ -121,13 +122,13 @@ public class RagonServer : IRagonServer, INetworkListener Address = "0.0.0.0", Port = _configuration.Port, }; - + _httpServer.Start(_configuration); _server.Start(this, networkConfiguration); if (executeInDedicatedThread) _dedicatedThread.Start(); - else + else Execute(); } @@ -141,7 +142,7 @@ public class RagonServer : IRagonServer, INetworkListener public void OnConnected(INetworkConnection connection) { var context = new RagonContext(connection, _configuration, _executor, _lobby, _scheduler); - + _logger.Trace($"Connected: {connection.Id}"); _contextsByConnection.Add(connection.Id, context); } @@ -154,10 +155,10 @@ public class RagonServer : IRagonServer, INetworkListener if (room != null) { room.DetachPlayer(context.RoomPlayer); - if (_lobby.RemoveIfEmpty(room)) + if (_lobby.RemoveIfEmpty(room)) _webhooks.RoomRemoved(context, room); } - + _logger.Trace($"Disconnected: {connection.Id}"); } else @@ -176,7 +177,7 @@ public class RagonServer : IRagonServer, INetworkListener room.DetachPlayer(context.RoomPlayer); _lobby.RemoveIfEmpty(room); } - + _logger.Trace($"Timeout: {connection.Id}|{context.LobbyPlayer.Name}|{context.LobbyPlayer.Id}"); } else @@ -185,7 +186,7 @@ public class RagonServer : IRagonServer, INetworkListener } } - public void OnData(INetworkConnection connection, byte[] data) + public void OnData(INetworkConnection connection, NetworkChannel channel, byte[] data) { try { @@ -193,10 +194,17 @@ public class RagonServer : IRagonServer, INetworkListener { _writer.Clear(); _reader.Clear(); - _reader.FromArray(data); + if (channel == NetworkChannel.RAW) + { + _handlers[(byte)RagonOperation.REPLICATE_RAW_DATA].Handle(context, data); + return; + } + + _reader.FromArray(data); + var operation = _reader.ReadByte(); - _handlers[operation].Handle(context, _reader, _writer); + _handlers[operation].Handle(context, data); } } catch (Exception ex) @@ -212,7 +220,7 @@ public class RagonServer : IRagonServer, INetworkListener { Double = timestamp, }; - + _writer.Clear(); _writer.WriteOperation(RagonOperation.TIMESTAMP_SYNCHRONIZATION); _writer.Write(value.Int0, 32); @@ -221,23 +229,19 @@ public class RagonServer : IRagonServer, INetworkListener var sendData = _writer.ToArray(); _server.BroadcastUnreliable(sendData); } - - public IRagonOperation ResolveOperation(RagonOperation operation) + + public BaseOperation ResolveOperation(RagonOperation operation) { return _handlers[(byte)operation]; } public RagonLobbyPlayer? GetPlayerByConnection(INetworkConnection connection) { - return _contextsByConnection.TryGetValue(connection.Id, out var context) ? - context.LobbyPlayer : - null; + return _contextsByConnection.TryGetValue(connection.Id, out var context) ? context.LobbyPlayer : null; } public RagonLobbyPlayer? GetPlayerById(string playerId) { - return _contextsByPlayerId.TryGetValue(playerId, out var context) ? - context.LobbyPlayer : - null; + return _contextsByPlayerId.TryGetValue(playerId, out var context) ? context.LobbyPlayer : null; } } \ No newline at end of file