Compare commits

..

15 Commits

Author SHA1 Message Date
edmand46 530c6109ea fixed: serializer resize 2022-05-29 16:36:25 +04:00
edmand46 3efd73d8cb chore: update server version 2022-05-29 16:18:55 +04:00
edmand46 a85ac99a3c fixed: event replication 2022-05-29 16:15:26 +04:00
edmand46 e295e9f7db fixed: serializer 2022-05-28 12:11:35 +04:00
edmand46 06dd23ee8d chore: remove logs 2022-05-28 11:58:54 +04:00
edmand46 62d3f7acdd fixed: incorrected snapshot on reconnecting, added resizble serializer 2022-05-28 11:53:42 +04:00
edmand46 e2d07eb396 fixed: snapshot 2022-05-28 10:33:06 +04:00
edmand46 4f00c36cd9 feat: reworked room with new serializer, reduce header of packet, added snapshot, added player join, left, ownership changed events events, added dispatch of states
fixed: missed authority bug
2022-05-26 21:09:53 +04:00
edmand46 8c1945e352 feat: added RagonSerializer, removed RagonHeader, reduced boilerplate code 2022-05-26 21:06:26 +04:00
edmand46 2ef1da5c90 feat: added player id for identify user in external services 2022-05-26 21:05:54 +04:00
edmand46 ec65b9f305 feat: added spawn payload in snapshot, reduce allocations in entity state 2022-05-26 21:05:05 +04:00
edmand46 35ca016520 chore: move to thread application logic, updated logo 2022-05-18 22:17:25 +04:00
edmand46 8481cb89ad Merge pull request #2 from OlegDzhuraev/fixes
Recursion fix and room bytes count corrected
2022-05-18 21:39:45 +04:00
Oleg Dzhuraev bcec99cff1 Recursion fix and room bytes count corrected 2022-05-17 13:59:46 +03:00
edmand46 bb7cccb61a chore: update logo 2022-05-15 13:05:39 +04:00
16 changed files with 571 additions and 340 deletions
BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.0 KiB

-35
View File
@@ -1,35 +0,0 @@
using System;
using System.Runtime.CompilerServices;
using NetStack.Buffers;
namespace Ragon.Common
{
public static class RagonHeader
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void WriteUShort(ushort id, ref Span<byte> data) {
data[0] = (byte)(id & 0x00FF);
data[1] = (byte)((id & 0xFF00) >> 8);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ushort ReadUShort(ref ReadOnlySpan<byte> data)
{
return (ushort)(data[0] + (data[1] << 8));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void WriteInt(int id, ref Span<byte> data) {
data[0] = (byte)(id & 0x00FF);
data[1] = (byte)((id & 0xFF00) >> 8);
data[2] = (byte)((id & 0xFF00) >> 16);
data[3] = (byte)((id & 0xFF00) >> 24);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int ReadInt(ref ReadOnlySpan<byte> data)
{
return (ushort)(data[0] + (data[1] << 8) + (data[2] << 16) + (data[3] << 24));
}
}
}
+6 -4
View File
@@ -1,13 +1,17 @@
namespace Ragon.Common namespace Ragon.Common
{ {
public enum RagonOperation: ushort public enum RagonOperation: byte
{ {
AUTHORIZE, AUTHORIZE,
AUTHORIZED_SUCCESS, AUTHORIZED_SUCCESS,
AUTHORIZED_FAILED, AUTHORIZED_FAILED,
JOIN_OR_CREATE_ROOM,
JOIN_ROOM, JOIN_ROOM,
LEAVE_ROOM, LEAVE_ROOM,
OWNERSHIP_CHANGED,
JOIN_SUCCESS,
JOIN_FAILED,
LOAD_SCENE, LOAD_SCENE,
SCENE_IS_LOADED, SCENE_IS_LOADED,
@@ -18,9 +22,7 @@ namespace Ragon.Common
CREATE_ENTITY, CREATE_ENTITY,
DESTROY_ENTITY, DESTROY_ENTITY,
RESTORE_BEGIN, SNAPSHOT,
RESTORE_END,
RESTORED,
REPLICATE_ENTITY_STATE, REPLICATE_ENTITY_STATE,
REPLICATE_ENTITY_EVENT, REPLICATE_ENTITY_EVENT,
+191
View File
@@ -0,0 +1,191 @@
using System;
using System.Runtime.CompilerServices;
using System.Text;
namespace Ragon.Common
{
public class RagonSerializer
{
private byte[] _data;
private int _offset;
private int _size;
public int Lenght => _offset;
public int Size => _size - _offset;
public RagonSerializer(int capacity = 2048)
{
_data = new byte[capacity];
_offset = 0;
_size = 0;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void WriteByte(byte value)
{
ResizeIfNeed(1);
_data[_offset] = value;
_offset += 1;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public int ReadByte()
{
var value = _data[_offset];
_offset += 1;
return value;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void WriteInt(int value)
{
ResizeIfNeed(4);
_data[_offset] = (byte) (value & 0x00FF);
_data[_offset + 1] = (byte) ((value & 0xFF00) >> 8);
_data[_offset + 2] = (byte) ((value & 0xFF00) >> 16);
_data[_offset + 3] = (byte) ((value & 0xFF00) >> 24);
_offset += 4;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public int ReadInt()
{
var value = _data[_offset] + (_data[_offset + 1] << 8) + (_data[_offset + 2] << 16) + (_data[_offset + 3] << 24);
_offset += 4;
return value;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void WriteString(string value)
{
var stringRaw = Encoding.UTF8.GetBytes(value).AsSpan();
ResizeIfNeed(2 + stringRaw.Length);
WriteUShort((ushort) stringRaw.Length);
var data = _data.AsSpan().Slice(_offset, stringRaw.Length);
stringRaw.CopyTo(data);
_offset += stringRaw.Length;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public string ReadString()
{
var lenght = ReadUShort();
var stringRaw = _data.AsSpan().Slice(_offset, lenght);
var str = Encoding.UTF8.GetString(stringRaw);
_offset += lenght;
return str;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ReadOnlySpan<byte> ReadData(int lenght)
{
var data = _data.AsSpan();
var payloadData = data.Slice(_offset, lenght);
_offset += payloadData.Length;
return payloadData;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void WriteData(ref ReadOnlySpan<byte> payload)
{
ResizeIfNeed(payload.Length);
var data = _data.AsSpan();
var payloadData = data.Slice(_offset, payload.Length);
payload.CopyTo(payloadData);
_offset += payload.Length;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Span<byte> GetWritableData(int lenght)
{
ResizeIfNeed(lenght);
var data = _data.AsSpan();
var payloadData = data.Slice(_offset, lenght);
_offset += lenght;
return payloadData;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void WriteOperation(RagonOperation ragonOperation)
{
ResizeIfNeed(1);
_data[_offset] = (byte) ragonOperation;
_offset += 1;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public RagonOperation ReadOperation()
{
var op = (RagonOperation) _data[_offset];
_offset += 1;
return op;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void WriteUShort(ushort value)
{
ResizeIfNeed(2);
_data[_offset] = (byte) (value & 0x00FF);
_data[_offset + 1] = (byte) ((value & 0xFF00) >> 8);
_offset += 2;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ushort ReadUShort()
{
var value = (ushort) (_data[_offset] + (_data[_offset + 1] << 8));
_offset += 2;
return value;
}
public void Clear()
{
_offset = 0;
_size = 0;
}
public void ToSpan(ref Span<byte> data)
{
var span = _data.AsSpan();
var dataSpan = span.Slice(0, _offset);
dataSpan.CopyTo(data);
}
public void FromSpan(ref ReadOnlySpan<byte> data)
{
Clear();
ResizeIfNeed(data.Length);
var dataSpan = _data.AsSpan();
data.CopyTo(dataSpan);
_size = data.Length;
}
public byte[] ToArray()
{
var bytes = new byte[_offset];
Buffer.BlockCopy(_data, 0, bytes, 0, _offset);
return bytes;
}
private void ResizeIfNeed(int lenght)
{
if (_offset + lenght < _data.Length)
return;
var newData = new byte[_data.Length * 2 + lenght];
Buffer.BlockCopy(_data, 0, newData, 0, _data.Length);
_data = newData;
}
}
}
+14 -6
View File
@@ -16,6 +16,8 @@ namespace Ragon.Core
private readonly ENetServer _socketServer; private readonly ENetServer _socketServer;
private int _roomThreadBalancer = 0; private int _roomThreadBalancer = 0;
private Thread _thread;
public Application(PluginFactory factory, Configuration configuration, int threadsCount) public Application(PluginFactory factory, Configuration configuration, int threadsCount)
{ {
_socketServer = new ENetServer(); _socketServer = new ENetServer();
@@ -29,13 +31,8 @@ namespace Ragon.Core
} }
} }
public void Start() private void Loop()
{ {
_socketServer.Start(_configuration.Server.Port);
foreach (var roomThread in _roomThreads)
roomThread.Start();
while (true) while (true)
{ {
foreach (var roomThread in _roomThreads) foreach (var roomThread in _roomThreads)
@@ -79,6 +76,17 @@ namespace Ragon.Core
} }
} }
public void Start()
{
_socketServer.Start(_configuration.Server.Port);
foreach (var roomThread in _roomThreads)
roomThread.Start();
_thread = new Thread(Loop);
_thread.Start();
}
public void Dispose() public void Dispose()
{ {
foreach (var roomThread in _roomThreads) foreach (var roomThread in _roomThreads)
+5 -2
View File
@@ -1,4 +1,6 @@
using NLog; using System;
using System.IO;
using NLog;
namespace Ragon.Core namespace Ragon.Core
{ {
@@ -9,7 +11,8 @@ namespace Ragon.Core
public void Configure(PluginFactory factory) public void Configure(PluginFactory factory)
{ {
_logger.Info("Configure application..."); _logger.Info("Configure application...");
var configuration = ConfigurationLoader.Load("config.json"); var filePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "config.json");
var configuration = ConfigurationLoader.Load(filePath);
var app = new Application(factory, configuration, 2); var app = new Application(factory, configuration, 2);
app.Start(); app.Start();
} }
@@ -9,7 +9,7 @@ namespace Ragon.Core
public static class ConfigurationLoader public static class ConfigurationLoader
{ {
private static readonly Logger _logger = LogManager.GetCurrentClassLogger(); private static readonly Logger _logger = LogManager.GetCurrentClassLogger();
private static readonly string _serverVersion = "1.0.0-rc"; private static readonly string _serverVersion = "1.0.4-rc";
private static void CopyrightInfo() private static void CopyrightInfo()
{ {
+2
View File
@@ -10,6 +10,7 @@ public class Entity
public ushort EntityType { get; private set; } public ushort EntityType { get; private set; }
public RagonAuthority Authority { get; private set; } public RagonAuthority Authority { get; private set; }
public EntityState State { get; private set; } public EntityState State { get; private set; }
public EntityState Payload { get; private set; }
public Entity(uint ownerId, ushort entityType, RagonAuthority stateAuthority, RagonAuthority eventAuthority) public Entity(uint ownerId, ushort entityType, RagonAuthority stateAuthority, RagonAuthority eventAuthority)
{ {
@@ -17,6 +18,7 @@ public class Entity
EntityType = entityType; EntityType = entityType;
EntityId = _idGenerator++; EntityId = _idGenerator++;
State = new EntityState(stateAuthority); State = new EntityState(stateAuthority);
Payload = new EntityState(stateAuthority);
Authority = eventAuthority; Authority = eventAuthority;
} }
} }
+16 -10
View File
@@ -8,25 +8,31 @@ public class EntityState
{ {
public bool isDirty { get; private set; } public bool isDirty { get; private set; }
public RagonAuthority Authority { get; private set; } public RagonAuthority Authority { get; private set; }
public int Size => _size;
public byte[] Data private int _size = 0;
{ private byte[] _data = new byte[2048];
get => Data;
set
{
Data = value;
isDirty = true;
}
}
public EntityState(RagonAuthority ragonAuthority) public EntityState(RagonAuthority ragonAuthority)
{ {
Authority = ragonAuthority; Authority = ragonAuthority;
isDirty = false;
}
public ReadOnlySpan<byte> Read()
{
return _data.AsSpan().Slice(0, _size);
}
public void Write(ref ReadOnlySpan<byte> src)
{
src.CopyTo(_data);
_size = src.Length;
isDirty = true; isDirty = true;
} }
public void Clear() public void Clear()
{ {
isDirty = true; isDirty = false;
} }
} }
+1
View File
@@ -5,6 +5,7 @@ namespace Ragon.Core
{ {
public class Player public class Player
{ {
public string Id { get; set; }
public uint PeerId { get; set; } public uint PeerId { get; set; }
public string PlayerName { get; set; } public string PlayerName { get; set; }
public bool IsLoaded { get; set; } public bool IsLoaded { get; set; }
+39 -54
View File
@@ -7,14 +7,16 @@ using Ragon.Common;
namespace Ragon.Core namespace Ragon.Core
{ {
public class PluginBase: IDisposable public class PluginBase : IDisposable
{ {
private delegate void SubscribeDelegate(Player player, ref ReadOnlySpan<byte> data); private delegate void SubscribeDelegate(Player player, ref ReadOnlySpan<byte> data);
private delegate void SubscribeEntityDelegate(Player player, Entity entity, ref ReadOnlySpan<byte> data); private delegate void SubscribeEntityDelegate(Player player, Entity entity, ref ReadOnlySpan<byte> data);
private Dictionary<ushort, SubscribeDelegate> _globalEvents = new(); private Dictionary<ushort, SubscribeDelegate> _globalEvents = new();
private Dictionary<int, Dictionary<ushort, SubscribeEntityDelegate>> _entityEvents = new(); private Dictionary<int, Dictionary<ushort, SubscribeEntityDelegate>> _entityEvents = new();
private BitBuffer _buffer = new BitBuffer(8192); private readonly BitBuffer _buffer = new();
private readonly RagonSerializer _serializer = new();
protected Room Room { get; private set; } protected Room Room { get; private set; }
protected ILogger _logger; protected ILogger _logger;
@@ -28,6 +30,7 @@ namespace Ragon.Core
_globalEvents.Clear(); _globalEvents.Clear();
_entityEvents.Clear(); _entityEvents.Clear();
} }
public void Dispose() public void Dispose()
{ {
_globalEvents.Clear(); _globalEvents.Clear();
@@ -66,10 +69,7 @@ namespace Ragon.Core
return; return;
} }
_globalEvents.Add(evntCode, (Player player, ref ReadOnlySpan<byte> raw) => _globalEvents.Add(evntCode, (Player player, ref ReadOnlySpan<byte> raw) => { action.Invoke(player); });
{
action.Invoke(player);
});
} }
public void Subscribe<T>(Entity entity, ushort evntCode, Action<Player, Entity, T> action) where T : IRagonSerializable, new() public void Subscribe<T>(Entity entity, ushort evntCode, Action<Player, Entity, T> action) where T : IRagonSerializable, new()
@@ -110,6 +110,7 @@ namespace Ragon.Core
_logger.Warn($"Payload is empty for entity {ent.EntityId} event {evntCode}"); _logger.Warn($"Payload is empty for entity {ent.EntityId} event {evntCode}");
return; return;
} }
_buffer.Clear(); _buffer.Clear();
_buffer.FromSpan(ref raw, raw.Length); _buffer.FromSpan(ref raw, raw.Length);
data.Deserialize(_buffer); data.Deserialize(_buffer);
@@ -128,19 +129,13 @@ namespace Ragon.Core
return; return;
} }
_entityEvents[entity.EntityId].Add(evntCode, (Player player, Entity ent, ref ReadOnlySpan<byte> raw) => _entityEvents[entity.EntityId].Add(evntCode, (Player player, Entity ent, ref ReadOnlySpan<byte> raw) => { action.Invoke(player, ent); });
{
action.Invoke(player, ent);
});
return; return;
} }
{ {
_entityEvents.Add(entity.EntityId, new Dictionary<ushort, SubscribeEntityDelegate>()); _entityEvents.Add(entity.EntityId, new Dictionary<ushort, SubscribeEntityDelegate>());
_entityEvents[entity.EntityId].Add(evntCode, (Player player, Entity ent, ref ReadOnlySpan<byte> raw) => _entityEvents[entity.EntityId].Add(evntCode, (Player player, Entity ent, ref ReadOnlySpan<byte> raw) => { action.Invoke(player, ent); });
{
action.Invoke(player, ent);
});
} }
} }
@@ -179,71 +174,63 @@ namespace Ragon.Core
public void SendEvent(Player player, uint eventCode, IRagonSerializable payload) public void SendEvent(Player player, uint eventCode, IRagonSerializable payload)
{ {
_serializer.Clear();
_serializer.WriteOperation(RagonOperation.REPLICATE_EVENT);
_buffer.Clear(); _buffer.Clear();
payload.Serialize(_buffer); payload.Serialize(_buffer);
var sendData = new byte[_buffer.Length + 4]; var payloadData = _serializer.GetWritableData(_buffer.Length);
Span<byte> data = sendData.AsSpan();
Span<byte> operationData = data.Slice(0, 2);
Span<byte> eventCodeData = data.Slice(2, 2);
Span<byte> payloadData = data.Slice(4, data.Length - 4);
_buffer.ToSpan(ref payloadData); _buffer.ToSpan(ref payloadData);
RagonHeader.WriteUShort((ushort) RagonOperation.REPLICATE_EVENT, ref operationData); var sendData = _serializer.ToArray();
RagonHeader.WriteUShort((ushort) eventCode, ref eventCodeData);
Room.Send(player.PeerId, sendData); Room.Send(player.PeerId, sendData);
} }
public void SendEvent(ushort eventCode, IRagonSerializable payload) public void BroadcastEvent(ushort eventCode, IRagonSerializable payload)
{ {
_serializer.Clear();
_serializer.WriteOperation(RagonOperation.REPLICATE_EVENT);
_buffer.Clear(); _buffer.Clear();
payload.Serialize(_buffer); payload.Serialize(_buffer);
var sendData = new byte[_buffer.Length + 4]; var payloadData = _serializer.GetWritableData(_buffer.Length);
Span<byte> data = sendData.AsSpan();
Span<byte> operationData = data.Slice(0, 2);
Span<byte> eventCodeData = data.Slice(2, 2);
Span<byte> payloadData = data.Slice(4, _buffer.Length);
RagonHeader.WriteUShort((ushort) RagonOperation.REPLICATE_EVENT,ref operationData);
RagonHeader.WriteUShort( eventCode, ref eventCodeData);
_buffer.ToSpan(ref payloadData); _buffer.ToSpan(ref payloadData);
Room.Broadcast(sendData); var sendData = _serializer.ToArray();
Room.Broadcast(sendData, DeliveryType.Reliable);
} }
public void SendEntityEvent(Player player, Entity entity, IRagonSerializable payload) public void SendEntityEvent(Player player, Entity entity, IRagonSerializable payload)
{ {
_serializer.Clear();
_serializer.WriteOperation(RagonOperation.REPLICATE_ENTITY_EVENT);
_serializer.WriteInt(entity.EntityId);
_buffer.Clear(); _buffer.Clear();
payload.Serialize(_buffer); payload.Serialize(_buffer);
var sendData = new byte[_buffer.Length + 6]; var payloadData = _serializer.GetWritableData(_buffer.Length);
Span<byte> data = sendData.AsSpan(); _buffer.ToSpan(ref payloadData);
Span<byte> operationData = data.Slice(0, 2);
Span<byte> entityData = data.Slice(2, 4);
RagonHeader.WriteUShort((ushort) RagonOperation.REPLICATE_EVENT, ref operationData); var sendData = _serializer.ToArray();
RagonHeader.WriteInt(entity.EntityId, ref entityData); Room.Send(player.PeerId, sendData, DeliveryType.Reliable);
Room.Send(player.PeerId, sendData);
} }
public void SendEntityEvent(Entity entity, IRagonSerializable payload) public void BroadcastEntityEvent(Entity entity, IRagonSerializable payload)
{ {
_serializer.Clear();
_serializer.WriteOperation(RagonOperation.REPLICATE_ENTITY_EVENT);
_serializer.WriteInt(entity.EntityId);
_buffer.Clear(); _buffer.Clear();
payload.Serialize(_buffer); payload.Serialize(_buffer);
var sendData = new byte[_buffer.Length + 6]; var payloadData = _serializer.GetWritableData(_buffer.Length);
Span<byte> data = sendData.AsSpan(); _buffer.ToSpan(ref payloadData);
Span<byte> operationData = data.Slice(0, 2);
Span<byte> entityData = data.Slice(2, 4);
RagonHeader.WriteUShort((ushort) RagonOperation.REPLICATE_EVENT, ref operationData);
RagonHeader.WriteInt(entity.EntityId, ref entityData);
var sendData = _serializer.ToArray();
Room.Broadcast(sendData); Room.Broadcast(sendData);
} }
@@ -258,18 +245,16 @@ namespace Ragon.Core
{ {
} }
public virtual void OnOwnerChanged(Player player) public virtual void OnOwnershipChanged(Player player)
{ {
} }
public virtual void OnEntityCreated(Player creator, Entity entity) public virtual void OnEntityCreated(Player creator, Entity entity)
{ {
} }
public virtual void OnEntityDestroyed(Player destoyer, Entity entity) public virtual void OnEntityDestroyed(Player destoyer, Entity entity)
{ {
} }
public virtual void OnStart() public virtual void OnStart()
+169 -148
View File
@@ -1,10 +1,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics;
using System.Linq; using System.Linq;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Text;
using NetStack.Serialization;
using NLog; using NLog;
using Ragon.Common; using Ragon.Common;
@@ -26,12 +23,17 @@ namespace Ragon.Core
private readonly PluginBase _plugin; private readonly PluginBase _plugin;
private readonly RoomThread _roomThread; private readonly RoomThread _roomThread;
private readonly RagonSerializer _serializer = new(512);
// Cache // Cache
private uint[] _readyPlayers = Array.Empty<uint>(); private uint[] _readyPlayers = Array.Empty<uint>();
private uint[] _allPlayers = Array.Empty<uint>(); private uint[] _allPlayers = Array.Empty<uint>();
private Entity[] _entitiesAll = Array.Empty<Entity>(); private Entity[] _entitiesAll = Array.Empty<Entity>();
public Player GetPlayerById(uint peerId) => _players[peerId];
public Entity GetEntityById(int entityId) => _entities[entityId];
public Player GetOwner() => _players[_owner];
public Room(RoomThread roomThread, PluginBase pluginBase, string map, int min, int max) public Room(RoomThread roomThread, PluginBase pluginBase, string map, int min, int max)
{ {
_roomThread = roomThread; _roomThread = roomThread;
@@ -55,6 +57,7 @@ namespace Ragon.Core
var player = new Player() var player = new Player()
{ {
Id = Guid.NewGuid().ToString(),
PlayerName = "Player " + peerId, PlayerName = "Player " + peerId,
PeerId = peerId, PeerId = peerId,
IsLoaded = false, IsLoaded = false,
@@ -62,44 +65,39 @@ namespace Ragon.Core
EntitiesIds = new List<int>(), EntitiesIds = new List<int>(),
}; };
{
_serializer.Clear();
_serializer.WriteOperation(RagonOperation.PLAYER_JOINED);
_serializer.WriteUShort((ushort) player.PeerId);
_serializer.WriteString(player.Id);
_serializer.WriteString(player.PlayerName);
var sendData = _serializer.ToArray();
Broadcast(_readyPlayers, sendData, DeliveryType.Reliable);
}
_players.Add(peerId, player); _players.Add(peerId, player);
_allPlayers = _players.Select(p => p.Key).ToArray(); _allPlayers = _players.Select(p => p.Key).ToArray();
{ {
var idRaw = Encoding.UTF8.GetBytes(Id).AsSpan(); _serializer.Clear();
_serializer.WriteOperation(RagonOperation.JOIN_SUCCESS);
_serializer.WriteString(Id);
_serializer.WriteString(player.Id);
_serializer.WriteString(GetOwner().Id);
_serializer.WriteUShort((ushort) PlayersMin);
_serializer.WriteUShort((ushort) PlayersMax);
var sendData = new byte[idRaw.Length + 18]; var sendData = _serializer.ToArray();
var data = sendData.AsSpan(); Send(peerId, sendData, DeliveryType.Reliable);
Span<byte> operationData = data.Slice(0, 2);
Span<byte> peerData = data.Slice(2, 4);
Span<byte> ownerData = data.Slice(4, 4);
Span<byte> minData = data.Slice(10, 4);
Span<byte> maxData = data.Slice(14, 4);
Span<byte> idData = data.Slice(18, idRaw.Length);
RagonHeader.WriteUShort((ushort) RagonOperation.JOIN_ROOM, ref operationData);
RagonHeader.WriteInt((int) peerId, ref peerData);
RagonHeader.WriteInt((int) _owner, ref ownerData);
RagonHeader.WriteInt(PlayersMin, ref minData);
RagonHeader.WriteInt(PlayersMax, ref maxData);
idRaw.CopyTo(idData);
Send(peerId, sendData);
} }
{ {
var sceneRawData = Encoding.UTF8.GetBytes(Map).AsSpan(); _serializer.Clear();
var sendData = new byte[sceneRawData.Length + 2]; _serializer.WriteOperation(RagonOperation.LOAD_SCENE);
var data = sendData.AsSpan(); _serializer.WriteString(Map);
Span<byte> operationData = data.Slice(0, 2);
Span<byte> sceneData = data.Slice(2, sceneRawData.Length);
RagonHeader.WriteUShort((ushort) RagonOperation.LOAD_SCENE, ref operationData);
sceneRawData.CopyTo(sceneData);
var sendData = _serializer.ToArray();
Send(peerId, sendData, DeliveryType.Reliable); Send(peerId, sendData, DeliveryType.Reliable);
} }
} }
@@ -109,55 +107,71 @@ namespace Ragon.Core
if (_players.Remove(peerId, out var player)) if (_players.Remove(peerId, out var player))
{ {
_allPlayers = _players.Select(p => p.Key).ToArray(); _allPlayers = _players.Select(p => p.Key).ToArray();
_readyPlayers = _players.Where(p => p.Value.IsLoaded).Select(p => p.Key).ToArray();
var isOwnershipChange = player.PeerId == _owner;
{
_plugin.OnPlayerLeaved(player); _plugin.OnPlayerLeaved(player);
_serializer.Clear();
_serializer.WriteOperation(RagonOperation.PLAYER_LEAVED);
_serializer.WriteString(player.Id);
_serializer.WriteUShort((ushort) player.EntitiesIds.Count);
foreach (var entityId in player.EntitiesIds) foreach (var entityId in player.EntitiesIds)
{ {
var sendData = new byte[6]; _serializer.WriteInt(entityId);
var entityData = sendData.AsSpan();
var operationData = entityData.Slice(0, 2);
RagonHeader.WriteUShort((ushort) RagonOperation.DESTROY_ENTITY, ref operationData);
RagonHeader.WriteInt(entityId, ref entityData);
Broadcast(_allPlayers, sendData);
_entities.Remove(entityId); _entities.Remove(entityId);
} }
var sendData = _serializer.ToArray();
Broadcast(_readyPlayers, sendData);
}
if (_allPlayers.Length > 0 && isOwnershipChange)
{
var newRoomOwnerId = _allPlayers[0];
var newRoomOwner = _players[newRoomOwnerId];
{
_plugin.OnOwnershipChanged(newRoomOwner);
_serializer.Clear();
_serializer.WriteOperation(RagonOperation.OWNERSHIP_CHANGED);
_serializer.WriteString(newRoomOwner.Id);
var sendData = _serializer.ToArray();
Broadcast(_readyPlayers, sendData);
}
}
} }
} }
public void ProcessEvent(RagonOperation operation, uint peerId, ReadOnlySpan<byte> rawData) public void ProcessEvent(RagonOperation operation, uint peerId, ReadOnlySpan<byte> rawData)
{ {
_serializer.Clear();
_serializer.FromSpan(ref rawData);
switch (operation) switch (operation)
{ {
case RagonOperation.REPLICATE_ENTITY_STATE: case RagonOperation.REPLICATE_ENTITY_STATE:
{ {
var entityData = rawData.Slice(2, 4); var entityId = _serializer.ReadInt();
var entityId = RagonHeader.ReadInt(ref entityData);
if (_entities.TryGetValue(entityId, out var ent)) if (_entities.TryGetValue(entityId, out var ent))
{ {
if (ent.State.Authority == RagonAuthority.OWNER_ONLY && ent.OwnerId != peerId) if (ent.State.Authority == RagonAuthority.OWNER_ONLY && ent.OwnerId != peerId)
return; return;
ent.State.Data = rawData.Slice(6, rawData.Length - 6).ToArray(); var entityStateData = _serializer.ReadData(_serializer.Size);
ent.State.Write(ref entityStateData);
var data = new byte[rawData.Length];
rawData.CopyTo(data);
Broadcast(_readyPlayers, data);
} }
break; break;
} }
case RagonOperation.REPLICATE_ENTITY_EVENT: case RagonOperation.REPLICATE_ENTITY_EVENT:
{ {
var evntCodeData = rawData.Slice(2, 2); var evntId = _serializer.ReadUShort();
var entityIdData = rawData.Slice(4, 4); var entityId = _serializer.ReadInt();
var evntId = RagonHeader.ReadUShort(ref evntCodeData);
var entityId = RagonHeader.ReadInt(ref entityIdData);
if (!_entities.TryGetValue(entityId, out var ent)) if (!_entities.TryGetValue(entityId, out var ent))
return; return;
@@ -165,86 +179,95 @@ namespace Ragon.Core
if (ent.Authority == RagonAuthority.OWNER_ONLY && ent.OwnerId != peerId) if (ent.Authority == RagonAuthority.OWNER_ONLY && ent.OwnerId != peerId)
return; return;
var payload = rawData.Slice(8, rawData.Length - 8); Span<byte> payloadRaw = stackalloc byte[_serializer.Size];
var payloadData = _serializer.ReadData(_serializer.Size);
payloadData.CopyTo(payloadRaw);
ReadOnlySpan<byte> payload = payloadRaw;
if (_plugin.InternalHandle(peerId, entityId, evntId, ref payload)) if (_plugin.InternalHandle(peerId, entityId, evntId, ref payload))
return; return;
var data = new byte[rawData.Length]; _serializer.Clear();
_serializer.WriteOperation(RagonOperation.REPLICATE_ENTITY_EVENT);
_serializer.WriteUShort(evntId);
_serializer.WriteInt(entityId);
_serializer.WriteData(ref payload);
var sendData = _serializer.ToArray();
rawData.CopyTo(data); Broadcast(_readyPlayers, sendData, DeliveryType.Reliable);
Broadcast(_readyPlayers, data, DeliveryType.Reliable);
break; break;
} }
case RagonOperation.REPLICATE_EVENT: case RagonOperation.REPLICATE_EVENT:
{ {
var evntCodeData = rawData.Slice(2, 2); var evntId = _serializer.ReadUShort();
var evntId = RagonHeader.ReadUShort(ref evntCodeData);
var payload = rawData.Slice(4, rawData.Length - 4); Span<byte> payloadRaw = stackalloc byte[_serializer.Size];
var payloadData = _serializer.ReadData(_serializer.Size);
payloadData.CopyTo(payloadRaw);
ReadOnlySpan<byte> payload = payloadRaw;
if (_plugin.InternalHandle(peerId, evntId, ref payload)) if (_plugin.InternalHandle(peerId, evntId, ref payload))
return; return;
var data = new byte[rawData.Length]; _serializer.Clear();
_serializer.WriteOperation(RagonOperation.REPLICATE_EVENT);
_serializer.WriteUShort(evntId);
_serializer.WriteData(ref payload);
rawData.CopyTo(data); var sendData = _serializer.ToArray();
Broadcast(_readyPlayers, sendData, DeliveryType.Reliable);
Broadcast(_readyPlayers, data, DeliveryType.Reliable);
break; break;
} }
case RagonOperation.CREATE_ENTITY: case RagonOperation.CREATE_ENTITY:
{ {
var typeData = rawData.Slice(2, 2); var entityType = _serializer.ReadUShort();
var authorityData = rawData.Slice(2, 2); var stateAuthority = (RagonAuthority) _serializer.ReadByte();
var entityPayloadData = rawData.Slice(4, rawData.Length - 4); var eventAuthority = (RagonAuthority) _serializer.ReadByte();
var entityType = RagonHeader.ReadUShort(ref typeData);
var stateAuthority = (RagonAuthority) authorityData[0];
var eventAuthority = (RagonAuthority) authorityData[1];
var entity = new Entity(peerId, entityType, stateAuthority, eventAuthority); var entity = new Entity(peerId, entityType, stateAuthority, eventAuthority);
entity.State.Data = entityPayloadData.ToArray();
{
var entityPayload = _serializer.ReadData(_serializer.Size);
entity.Payload.Write(ref entityPayload);
}
var player = _players[peerId]; var player = _players[peerId];
player.Entities.Add(entity); player.Entities.Add(entity);
player.EntitiesIds.Add(entity.EntityId); player.EntitiesIds.Add(entity.EntityId);
var ownerId = (ushort) peerId;
_entities.Add(entity.EntityId, entity); _entities.Add(entity.EntityId, entity);
_entitiesAll = _entities.Values.ToArray(); _entitiesAll = _entities.Values.ToArray();
_plugin.OnEntityCreated(player, entity); _plugin.OnEntityCreated(player, entity);
var data = new byte[entityPayloadData.Length + 14]; _serializer.Clear();
var sendData = data.AsSpan(); _serializer.WriteOperation(RagonOperation.CREATE_ENTITY);
var operationData = sendData.Slice(0, 2); _serializer.WriteUShort(entityType);
var entityTypeData = sendData.Slice(2, 2); _serializer.WriteByte((byte) stateAuthority);
var authority = sendData.Slice(4, 2); _serializer.WriteByte((byte) eventAuthority);
var entityIdData = sendData.Slice(6, 4); _serializer.WriteInt(entity.EntityId);
var peerData = sendData.Slice(10, 4); _serializer.WriteUShort(ownerId);
var payload = sendData.Slice(14, entityPayloadData.Length);
entityPayloadData.CopyTo(payload); {
var entityPayload = entity.Payload.Read();
_serializer.WriteData(ref entityPayload);
}
authority[0] = authorityData[0]; var sendData = _serializer.ToArray();
authority[1] = authorityData[1]; Broadcast(_readyPlayers, sendData, DeliveryType.Reliable);
RagonHeader.WriteUShort((ushort) RagonOperation.CREATE_ENTITY, ref operationData);
RagonHeader.WriteUShort(entityType, ref entityTypeData);
RagonHeader.WriteInt(entity.EntityId, ref entityIdData);
RagonHeader.WriteInt((int) peerId, ref peerData);
Broadcast(_allPlayers, data, DeliveryType.Reliable);
break; break;
} }
case RagonOperation.DESTROY_ENTITY: case RagonOperation.DESTROY_ENTITY:
{ {
var entityData = rawData.Slice(2, 4); var entityId = _serializer.ReadInt();
var entityId = RagonHeader.ReadInt(ref entityData);
if (_entities.TryGetValue(entityId, out var entity)) if (_entities.TryGetValue(entityId, out var entity))
{ {
if (entity.Authority == RagonAuthority.OWNER_ONLY && entity.OwnerId != peerId) if (entity.Authority == RagonAuthority.OWNER_ONLY && entity.OwnerId != peerId)
return; return;
var player = _players[peerId]; var player = _players[peerId];
var destroyPayload = _serializer.ReadData(_serializer.Size);
player.Entities.Remove(entity); player.Entities.Remove(entity);
player.EntitiesIds.Remove(entity.EntityId); player.EntitiesIds.Remove(entity.EntityId);
@@ -254,49 +277,49 @@ namespace Ragon.Core
_plugin.OnEntityDestroyed(player, entity); _plugin.OnEntityDestroyed(player, entity);
var data = new byte[rawData.Length]; _serializer.Clear();
Span<byte> sendData = data.AsSpan(); _serializer.WriteOperation(RagonOperation.DESTROY_ENTITY);
rawData.CopyTo(sendData); _serializer.WriteInt(entityId);
_serializer.WriteData(ref destroyPayload);
Broadcast(_readyPlayers, data, DeliveryType.Reliable); var sendData = _serializer.ToArray();
Broadcast(_readyPlayers, sendData, DeliveryType.Reliable);
} }
break; break;
} }
case RagonOperation.SCENE_IS_LOADED: case RagonOperation.SCENE_IS_LOADED:
{ {
Send(peerId, RagonOperation.RESTORE_BEGIN, DeliveryType.Reliable); _serializer.Clear();
foreach (var entity in _entities.Values) _serializer.WriteOperation(RagonOperation.SNAPSHOT);
_serializer.WriteInt(_allPlayers.Length);
foreach (var playerPeerId in _allPlayers)
{ {
var entityState = entity.State.Data.AsSpan(); _serializer.WriteString(_players[playerPeerId].Id);
var data = new byte[entity.State.Data.Length + 12]; _serializer.WriteUShort((ushort) playerPeerId);
_serializer.WriteString(_players[playerPeerId].PlayerName);
Span<byte> sendData = data.AsSpan();
Span<byte> operationData = sendData.Slice(0, 2);
Span<byte> entityTypeData = sendData.Slice(2, 2);
Span<byte> authorityData = sendData.Slice(4, 2);
Span<byte> entityData = sendData.Slice(6, 4);
Span<byte> ownerData = sendData.Slice(10, 4);
Span<byte> entityStateData = sendData.Slice(14, entity.State.Data.Length);
RagonHeader.WriteUShort((ushort) RagonOperation.CREATE_ENTITY, ref operationData);
RagonHeader.WriteUShort(entity.EntityType, ref entityTypeData);
RagonHeader.WriteInt(entity.EntityId, ref entityData);
RagonHeader.WriteInt((int) entity.OwnerId, ref ownerData);
authorityData[0] = (byte) entity.State.Authority;
authorityData[1] = (byte) entity.Authority;
entityState.CopyTo(entityStateData);
Send(peerId, data, DeliveryType.Reliable);
} }
Send(peerId, RagonOperation.RESTORE_END, DeliveryType.Reliable); _serializer.WriteInt(_entitiesAll.Length);
break; foreach (var entity in _entitiesAll)
}
case RagonOperation.RESTORED:
{ {
_serializer.WriteInt(entity.EntityId);
_serializer.WriteByte((byte) entity.State.Authority);
_serializer.WriteByte((byte) entity.Authority);
_serializer.WriteUShort(entity.EntityType);
_serializer.WriteUShort((ushort) entity.OwnerId);
var payload = entity.Payload.Read();
_serializer.WriteUShort((ushort) payload.Length);
_serializer.WriteData(ref payload);
var state = entity.State.Read();
_serializer.WriteUShort((ushort) state.Length);
_serializer.WriteData(ref state);
}
var sendData = _serializer.ToArray();
Send(peerId, sendData, DeliveryType.Reliable);
_players[peerId].IsLoaded = true; _players[peerId].IsLoaded = true;
_readyPlayers = _players.Where(p => p.Value.IsLoaded).Select(p => p.Key).ToArray(); _readyPlayers = _players.Where(p => p.Value.IsLoaded).Select(p => p.Key).ToArray();
@@ -310,6 +333,24 @@ namespace Ragon.Core
{ {
_ticks++; _ticks++;
_plugin.OnTick(_ticks, deltaTime); _plugin.OnTick(_ticks, deltaTime);
foreach (var entity in _entitiesAll)
{
if (entity.State.isDirty)
{
var state = entity.State.Read();
_serializer.Clear();
_serializer.WriteOperation(RagonOperation.REPLICATE_ENTITY_STATE);
_serializer.WriteInt(entity.EntityId);
_serializer.WriteData(ref state);
var sendData = _serializer.ToArray();
Broadcast(_readyPlayers, sendData, DeliveryType.Unreliable);
entity.State.Clear();
}
}
} }
public void Start() public void Start()
@@ -331,26 +372,6 @@ namespace Ragon.Core
_plugin.Dispose(); _plugin.Dispose();
} }
public Player GetPlayerById(uint peerId) => _players[peerId];
public Entity GetEntityById(int entityId) => _entities[entityId];
public Player GetOwner() => _players[_owner];
public void Send(uint peerId, RagonOperation operation, DeliveryType deliveryType = DeliveryType.Unreliable)
{
var rawData = new byte[2];
var rawDataSpan = new Span<byte>(rawData);
RagonHeader.WriteUShort((ushort) operation, ref rawDataSpan);
_roomThread.WriteOutEvent(new Event()
{
PeerId = peerId,
Data = rawData,
Type = EventType.DATA,
Delivery = deliveryType,
});
}
public void Send(uint peerId, byte[] rawData, DeliveryType deliveryType = DeliveryType.Unreliable) public void Send(uint peerId, byte[] rawData, DeliveryType deliveryType = DeliveryType.Unreliable)
{ {
_roomThread.WriteOutEvent(new Event() _roomThread.WriteOutEvent(new Event()
+64 -19
View File
@@ -14,7 +14,7 @@ namespace Ragon.Core
private PluginFactory _factory; private PluginFactory _factory;
private AuthorizationManager _manager; private AuthorizationManager _manager;
private RoomThread _roomThread; private RoomThread _roomThread;
private RagonSerializer _serializer;
public Action<(uint, Room)> OnJoined; public Action<(uint, Room)> OnJoined;
public Action<(uint, Room)> OnLeaved; public Action<(uint, Room)> OnLeaved;
@@ -23,6 +23,7 @@ namespace Ragon.Core
_roomThread = roomThread; _roomThread = roomThread;
_factory = factory; _factory = factory;
_serializer = new RagonSerializer();
_manager = _factory.CreateManager(roomThread.Configuration); _manager = _factory.CreateManager(roomThread.Configuration);
_rooms = new List<Room>(); _rooms = new List<Room>();
_peersByRoom = new Dictionary<uint, Room>(); _peersByRoom = new Dictionary<uint, Room>();
@@ -37,9 +38,40 @@ namespace Ragon.Core
OnAuthorize(peerId, payload); OnAuthorize(peerId, payload);
break; break;
} }
case RagonOperation.JOIN_OR_CREATE_ROOM:
{
var room = JoinOrCreate(peerId, payload);
if (room == null)
{
var sendData = new[] {(byte) RagonOperation.JOIN_FAILED};
_roomThread.WriteOutEvent(new Event()
{
Delivery = DeliveryType.Reliable,
Type = EventType.DATA,
Data = sendData,
PeerId = peerId,
});
return;
}
OnJoined?.Invoke((peerId, room));
break;
}
case RagonOperation.JOIN_ROOM: case RagonOperation.JOIN_ROOM:
{ {
var room = Join(peerId, payload); var room = Join(peerId, payload);
if (room == null)
{
var sendData = new[] {(byte) RagonOperation.JOIN_FAILED};
_roomThread.WriteOutEvent(new Event()
{
Delivery = DeliveryType.Reliable,
Type = EventType.DATA,
Data = sendData,
PeerId = peerId,
});
return;
}
OnJoined?.Invoke((peerId, room)); OnJoined?.Invoke((peerId, room));
break; break;
} }
@@ -56,11 +88,7 @@ namespace Ragon.Core
{ {
if (_manager.OnAuthorize(peerId, ref payload)) if (_manager.OnAuthorize(peerId, ref payload))
{ {
var sendData = new byte[2]; var sendData = new[] {(byte) RagonOperation.AUTHORIZED_SUCCESS};
Span<byte> data = sendData.AsSpan();
RagonHeader.WriteUShort((ushort) RagonOperation.AUTHORIZED_SUCCESS, ref data);
_roomThread.WriteOutEvent(new Event() _roomThread.WriteOutEvent(new Event()
{ {
Delivery = DeliveryType.Reliable, Delivery = DeliveryType.Reliable,
@@ -71,10 +99,7 @@ namespace Ragon.Core
} }
else else
{ {
var sendData = new byte[2]; var sendData = new[] {(byte) RagonOperation.AUTHORIZED_FAILED};
var data = sendData.AsSpan();
RagonHeader.WriteUShort((ushort) RagonOperation.AUTHORIZED_FAILED, ref data);
_roomThread.WriteOutEvent(new Event() _roomThread.WriteOutEvent(new Event()
{ {
Delivery = DeliveryType.Reliable, Delivery = DeliveryType.Reliable,
@@ -82,7 +107,6 @@ namespace Ragon.Core
Data = sendData, Data = sendData,
PeerId = peerId, PeerId = peerId,
}); });
_roomThread.WriteOutEvent(new Event() _roomThread.WriteOutEvent(new Event()
{ {
Delivery = DeliveryType.Reliable, Delivery = DeliveryType.Reliable,
@@ -93,15 +117,36 @@ namespace Ragon.Core
} }
} }
public Room Join(uint peerId, ReadOnlySpan<byte> payload) public Room? Join(uint peerId, ReadOnlySpan<byte> payload)
{ {
var minData = payload.Slice(0, 2); var roomId = Encoding.UTF8.GetString(payload);
var maxData = payload.Slice(2, 2);
var mapData = payload.Slice(4, payload.Length - 4);
var map = Encoding.UTF8.GetString(mapData); if (_rooms.Count > 0)
var min = RagonHeader.ReadUShort(ref minData); {
var max = RagonHeader.ReadUShort(ref maxData); foreach (var existRoom in _rooms)
{
if (existRoom.Id == roomId && existRoom.PlayersCount < existRoom.PlayersMax)
{
existRoom.Joined(peerId, payload);
_peersByRoom.Add(peerId, existRoom);
return existRoom;
}
}
}
return null;
}
public Room? JoinOrCreate(uint peerId, ReadOnlySpan<byte> payload)
{
_serializer.Clear();
_serializer.FromSpan(ref payload);
var min = _serializer.ReadUShort();
var max = _serializer.ReadUShort();
var map = _serializer.ReadString();
Room room = null; Room room = null;
if (_rooms.Count > 0) if (_rooms.Count > 0)
@@ -147,7 +192,7 @@ namespace Ragon.Core
if (room != null) if (room != null)
{ {
room.Leave(peerId); room.Leave(peerId);
if (room.PlayersCount <= 0) if (room.PlayersCount <= 0 && room.PlayersMin > 0)
{ {
_rooms.Remove(room); _rooms.Remove(room);
+6 -6
View File
@@ -16,8 +16,8 @@ namespace Ragon.Core
private readonly Stopwatch _timer; private readonly Stopwatch _timer;
private readonly ILogger _logger = LogManager.GetCurrentClassLogger(); private readonly ILogger _logger = LogManager.GetCurrentClassLogger();
private readonly float _deltaTime = 0.0f; private readonly float _deltaTime = 0.0f;
private RingBuffer<Event> _receiveBuffer = new RingBuffer<Event>(8192 + 8192); private readonly RingBuffer<Event> _receiveBuffer = new(2048);
private RingBuffer<Event> _sendBuffer = new RingBuffer<Event>(8192 + 8192); private readonly RingBuffer<Event> _sendBuffer = new(2048);
public Configuration Configuration { get; private set; } public Configuration Configuration { get; private set; }
public bool ReadOutEvent(out Event evnt) => _sendBuffer.TryDequeue(out evnt); public bool ReadOutEvent(out Event evnt) => _sendBuffer.TryDequeue(out evnt);
@@ -70,13 +70,14 @@ namespace Ragon.Core
if (evnt.Type == EventType.DATA) if (evnt.Type == EventType.DATA)
{ {
var data = new ReadOnlySpan<byte>(evnt.Data); var data = new ReadOnlySpan<byte>(evnt.Data);
var operationData = data.Slice(0, 2); var operation = (RagonOperation) data[0];
var operation = (RagonOperation) RagonHeader.ReadUShort(ref operationData); var payload = data.Slice(1, data.Length - 1);
if (_socketByRooms.TryGetValue(evnt.PeerId, out var room)) if (_socketByRooms.TryGetValue(evnt.PeerId, out var room))
{ {
try try
{ {
room.ProcessEvent(operation, evnt.PeerId, data); room.ProcessEvent(operation, evnt.PeerId, payload);
} }
catch (Exception exception) catch (Exception exception)
{ {
@@ -85,7 +86,6 @@ namespace Ragon.Core
} }
else else
{ {
var payload = data.Slice(2, data.Length - 2);
_roomManager.ProcessEvent(operation, evnt.PeerId, payload); _roomManager.ProcessEvent(operation, evnt.PeerId, payload);
} }
} }
+3 -1
View File
@@ -1,5 +1,5 @@
<p align="center"> <p align="center">
<img src="Images/logo.png" width="200" > <img src="Images/ragon-logo.png" width="200" >
</p> </p>
## Ragon Server ## Ragon Server
@@ -27,6 +27,7 @@ Ragon is fully free high perfomance room based game server with plugin based arc
### Roadmap: ### Roadmap:
- Allow customize matchmaking - Allow customize matchmaking
- Refactoring some moments(a lot duplications of code, etc...)
- Use native memory - Use native memory
- Reduce allocations - Reduce allocations
- Dashboard for monitoring entities and players in realtime - Dashboard for monitoring entities and players in realtime
@@ -37,6 +38,7 @@ Ragon is fully free high perfomance room based game server with plugin based arc
### Requirements ### Requirements
- OSX, Windows, Linux(Ubuntu, Debian) - OSX, Windows, Linux(Ubuntu, Debian)
- .NET 6.0 - .NET 6.0
### Dependencies ### Dependencies
* ENet-Sharp v2.4.8 * ENet-Sharp v2.4.8
* NetStack latest * NetStack latest