diff --git a/Ragon.Common/Protocol/RagonOperation.cs b/Ragon.Common/Protocol/RagonOperation.cs
index 7e7a720..567533a 100644
--- a/Ragon.Common/Protocol/RagonOperation.cs
+++ b/Ragon.Common/Protocol/RagonOperation.cs
@@ -1,13 +1,17 @@
namespace Ragon.Common
{
- public enum RagonOperation: ushort
+ public enum RagonOperation: byte
{
AUTHORIZE,
AUTHORIZED_SUCCESS,
AUTHORIZED_FAILED,
+ JOIN_OR_CREATE_ROOM,
JOIN_ROOM,
LEAVE_ROOM,
+ OWNERSHIP_CHANGED,
+ JOIN_SUCCESS,
+ JOIN_FAILED,
LOAD_SCENE,
SCENE_IS_LOADED,
@@ -18,9 +22,7 @@ namespace Ragon.Common
CREATE_ENTITY,
DESTROY_ENTITY,
- RESTORE_BEGIN,
- RESTORE_END,
- RESTORED,
+ SNAPSHOT,
REPLICATE_ENTITY_STATE,
REPLICATE_ENTITY_EVENT,
diff --git a/Ragon/Ragon.csproj b/Ragon/Ragon.csproj
index 79a3555..82932d4 100755
--- a/Ragon/Ragon.csproj
+++ b/Ragon/Ragon.csproj
@@ -26,4 +26,8 @@
+
+
+
+
diff --git a/Ragon/Sources/Configuration/ConfigurationLoader.cs b/Ragon/Sources/Configuration/ConfigurationLoader.cs
index f2ee380..1ddb919 100755
--- a/Ragon/Sources/Configuration/ConfigurationLoader.cs
+++ b/Ragon/Sources/Configuration/ConfigurationLoader.cs
@@ -9,7 +9,7 @@ namespace Ragon.Core
public static class ConfigurationLoader
{
private static readonly Logger _logger = LogManager.GetCurrentClassLogger();
- private static readonly string _serverVersion = "1.0.0-rc";
+ private static readonly string _serverVersion = "1.0.3-rc";
private static void CopyrightInfo()
{
diff --git a/Ragon/Sources/Plugin/PluginBase.cs b/Ragon/Sources/Plugin/PluginBase.cs
index 7dfe213..a1b2e39 100755
--- a/Ragon/Sources/Plugin/PluginBase.cs
+++ b/Ragon/Sources/Plugin/PluginBase.cs
@@ -7,33 +7,36 @@ using Ragon.Common;
namespace Ragon.Core
{
- public class PluginBase: IDisposable
+ public class PluginBase : IDisposable
{
private delegate void SubscribeDelegate(Player player, ref ReadOnlySpan data);
+
private delegate void SubscribeEntityDelegate(Player player, Entity entity, ref ReadOnlySpan data);
private Dictionary _globalEvents = new();
private Dictionary> _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 ILogger _logger;
-
+
public void Attach(Room room)
{
_logger = LogManager.GetLogger($"Plugin<{GetType().Name}>");
-
+
Room = room;
-
+
_globalEvents.Clear();
_entityEvents.Clear();
}
+
public void Dispose()
{
_globalEvents.Clear();
_entityEvents.Clear();
}
-
+
public void Subscribe(ushort evntCode, Action action) where T : IRagonSerializable, new()
{
if (_globalEvents.ContainsKey(evntCode))
@@ -41,7 +44,7 @@ namespace Ragon.Core
_logger.Warn($"Event subscriber already added {evntCode}");
return;
}
-
+
var data = new T();
_globalEvents.Add(evntCode, (Player player, ref ReadOnlySpan raw) =>
{
@@ -50,14 +53,14 @@ namespace Ragon.Core
_logger.Warn($"Payload is empty for event {evntCode}");
return;
}
-
+
_buffer.Clear();
_buffer.FromSpan(ref raw, raw.Length);
data.Deserialize(_buffer);
action.Invoke(player, data);
});
}
-
+
public void Subscribe(ushort evntCode, Action action)
{
if (_globalEvents.ContainsKey(evntCode))
@@ -65,11 +68,8 @@ namespace Ragon.Core
_logger.Warn($"Event subscriber already added {evntCode}");
return;
}
-
- _globalEvents.Add(evntCode, (Player player, ref ReadOnlySpan raw) =>
- {
- action.Invoke(player);
- });
+
+ _globalEvents.Add(evntCode, (Player player, ref ReadOnlySpan raw) => { action.Invoke(player); });
}
public void Subscribe(Entity entity, ushort evntCode, Action action) where T : IRagonSerializable, new()
@@ -80,8 +80,8 @@ namespace Ragon.Core
{
_logger.Warn($"Event subscriber already added {evntCode} for {entity.EntityId}");
return;
- }
-
+ }
+
var data = new T();
_entityEvents[entity.EntityId].Add(evntCode, (Player player, Entity ent, ref ReadOnlySpan raw) =>
{
@@ -90,13 +90,13 @@ namespace Ragon.Core
_logger.Warn($"Payload is empty for entity {ent.EntityId} event {evntCode}");
return;
}
-
+
_buffer.Clear();
_buffer.FromSpan(ref raw, raw.Length);
data.Deserialize(_buffer);
action.Invoke(player, ent, data);
});
-
+
return;
}
@@ -110,6 +110,7 @@ namespace Ragon.Core
_logger.Warn($"Payload is empty for entity {ent.EntityId} event {evntCode}");
return;
}
+
_buffer.Clear();
_buffer.FromSpan(ref raw, raw.Length);
data.Deserialize(_buffer);
@@ -126,24 +127,18 @@ namespace Ragon.Core
{
_logger.Warn($"Event subscriber already added {evntCode} for {entity.EntityId}");
return;
- }
-
- _entityEvents[entity.EntityId].Add(evntCode, (Player player, Entity ent, ref ReadOnlySpan raw) =>
- {
- action.Invoke(player, ent);
- });
+ }
+
+ _entityEvents[entity.EntityId].Add(evntCode, (Player player, Entity ent, ref ReadOnlySpan raw) => { action.Invoke(player, ent); });
return;
}
{
_entityEvents.Add(entity.EntityId, new Dictionary());
- _entityEvents[entity.EntityId].Add(evntCode, (Player player, Entity ent, ref ReadOnlySpan raw) =>
- {
- action.Invoke(player, ent);
- });
+ _entityEvents[entity.EntityId].Add(evntCode, (Player player, Entity ent, ref ReadOnlySpan raw) => { action.Invoke(player, ent); });
}
}
-
+
public void UnsubscribeAll()
{
_globalEvents.Clear();
@@ -157,7 +152,7 @@ namespace Ragon.Core
if (!_entityEvents[entityId].ContainsKey(evntCode))
return false;
-
+
var player = Room.GetPlayerById(peerId);
var entity = Room.GetEntityById(entityId);
_entityEvents[entityId][evntCode].Invoke(player, entity, ref payload);
@@ -179,75 +174,67 @@ namespace Ragon.Core
public void SendEvent(Player player, uint eventCode, IRagonSerializable payload)
{
+ _serializer.Clear();
+ _serializer.WriteOperation(RagonOperation.REPLICATE_EVENT);
+
_buffer.Clear();
payload.Serialize(_buffer);
-
- var sendData = new byte[_buffer.Length + 4];
- Span data = sendData.AsSpan();
- Span operationData = data.Slice(0, 2);
- Span eventCodeData = data.Slice(2, 2);
- Span payloadData = data.Slice(4, data.Length - 4);
-
+
+ var payloadData = _serializer.GetWritableData(_buffer.Length);
_buffer.ToSpan(ref payloadData);
-
- RagonHeader.WriteUShort((ushort) RagonOperation.REPLICATE_EVENT, ref operationData);
- RagonHeader.WriteUShort((ushort) eventCode, ref eventCodeData);
-
+
+ var sendData = _serializer.ToArray();
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();
payload.Serialize(_buffer);
-
- var sendData = new byte[_buffer.Length + 4];
- Span data = sendData.AsSpan();
- Span operationData = data.Slice(0, 2);
- Span eventCodeData = data.Slice(2, 2);
- Span payloadData = data.Slice(4, _buffer.Length);
- RagonHeader.WriteUShort((ushort) RagonOperation.REPLICATE_EVENT,ref operationData);
- RagonHeader.WriteUShort( eventCode, ref eventCodeData);
-
+ var payloadData = _serializer.GetWritableData(_buffer.Length);
_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)
{
+ _serializer.Clear();
+ _serializer.WriteOperation(RagonOperation.REPLICATE_ENTITY_EVENT);
+ _serializer.WriteInt(entity.EntityId);
+
_buffer.Clear();
payload.Serialize(_buffer);
+
+ var payloadData = _serializer.GetWritableData(_buffer.Length);
+ _buffer.ToSpan(ref payloadData);
- var sendData = new byte[_buffer.Length + 6];
- Span data = sendData.AsSpan();
- Span operationData = data.Slice(0, 2);
- Span entityData = data.Slice(2, 4);
-
- RagonHeader.WriteUShort((ushort) RagonOperation.REPLICATE_EVENT, ref operationData);
- RagonHeader.WriteInt(entity.EntityId, ref entityData);
-
- Room.Send(player.PeerId, sendData);
+ var sendData = _serializer.ToArray();
+ Room.Send(player.PeerId, sendData, DeliveryType.Reliable);
}
-
- 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();
payload.Serialize(_buffer);
+
+ var payloadData = _serializer.GetWritableData(_buffer.Length);
+ _buffer.ToSpan(ref payloadData);
- var sendData = new byte[_buffer.Length + 6];
- Span data = sendData.AsSpan();
- Span operationData = data.Slice(0, 2);
- Span 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);
}
-
+
#region VIRTUAL
public virtual void OnPlayerJoined(Player player)
@@ -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 OnEntityDestroyed(Player destoyer, Entity entity)
{
-
}
public virtual void OnStart()
diff --git a/Ragon/Sources/Rooms/Room.cs b/Ragon/Sources/Rooms/Room.cs
index 8f19568..9ab93cd 100755
--- a/Ragon/Sources/Rooms/Room.cs
+++ b/Ragon/Sources/Rooms/Room.cs
@@ -1,10 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
-using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
-using System.Text;
-using NetStack.Serialization;
using NLog;
using Ragon.Common;
@@ -26,12 +22,17 @@ namespace Ragon.Core
private readonly PluginBase _plugin;
private readonly RoomThread _roomThread;
+ private readonly RagonSerializer _serializer = new(2048);
// Cache
private uint[] _readyPlayers = Array.Empty();
private uint[] _allPlayers = Array.Empty();
private Entity[] _entitiesAll = Array.Empty();
+ 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)
{
_roomThread = roomThread;
@@ -55,51 +56,47 @@ namespace Ragon.Core
var player = new Player()
{
+ Id = Guid.NewGuid().ToString(),
PlayerName = "Player " + peerId,
PeerId = peerId,
IsLoaded = false,
Entities = new List(),
EntitiesIds = new List(),
};
+
+ {
+ _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(sendData, DeliveryType.Reliable);
+ }
+
_players.Add(peerId, player);
_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 data = sendData.AsSpan();
-
- Span operationData = data.Slice(0, 2);
- Span peerData = data.Slice(2, 4);
- Span ownerData = data.Slice(4, 4);
- Span minData = data.Slice(10, 4);
- Span maxData = data.Slice(14, 4);
- Span 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 sendData = _serializer.ToArray();
+ Send(peerId, sendData, DeliveryType.Reliable);
}
{
- var sceneRawData = Encoding.UTF8.GetBytes(Map).AsSpan();
- var sendData = new byte[sceneRawData.Length + 2];
- var data = sendData.AsSpan();
-
- Span operationData = data.Slice(0, 2);
- Span sceneData = data.Slice(2, sceneRawData.Length);
-
- RagonHeader.WriteUShort((ushort) RagonOperation.LOAD_SCENE, ref operationData);
- sceneRawData.CopyTo(sceneData);
+ _serializer.Clear();
+ _serializer.WriteOperation(RagonOperation.LOAD_SCENE);
+ _serializer.WriteString(Map);
+ var sendData = _serializer.ToArray();
Send(peerId, sendData, DeliveryType.Reliable);
}
}
@@ -109,55 +106,69 @@ namespace Ragon.Core
if (_players.Remove(peerId, out var player))
{
_allPlayers = _players.Select(p => p.Key).ToArray();
+ var isOwnershipChange = player.PeerId == _owner;
- _plugin.OnPlayerLeaved(player);
-
- foreach (var entityId in player.EntitiesIds)
{
- var sendData = new byte[6];
- var entityData = sendData.AsSpan();
- var operationData = entityData.Slice(0, 2);
+ _plugin.OnPlayerLeaved(player);
- RagonHeader.WriteUShort((ushort) RagonOperation.DESTROY_ENTITY, ref operationData);
- RagonHeader.WriteInt(entityId, ref entityData);
+ _serializer.Clear();
+ _serializer.WriteOperation(RagonOperation.PLAYER_LEAVED);
+ _serializer.WriteString(player.Id);
+ _serializer.WriteUShort((ushort) player.EntitiesIds.Count);
+ foreach (var entityId in player.EntitiesIds)
+ {
+ _serializer.WriteInt(entityId);
+ _entities.Remove(entityId);
+ }
+
+ var sendData = _serializer.ToArray();
Broadcast(_allPlayers, sendData);
+ }
- _entities.Remove(entityId);
+ 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(_allPlayers, sendData);
+ }
}
}
}
public void ProcessEvent(RagonOperation operation, uint peerId, ReadOnlySpan rawData)
{
+ _serializer.Clear();
+ _serializer.FromSpan(ref rawData);
+
switch (operation)
{
case RagonOperation.REPLICATE_ENTITY_STATE:
{
- var entityData = rawData.Slice(2, 4);
- var entityId = RagonHeader.ReadInt(ref entityData);
+ var entityId = _serializer.ReadInt();
if (_entities.TryGetValue(entityId, out var ent))
{
if (ent.State.Authority == RagonAuthority.OWNER_ONLY && ent.OwnerId != peerId)
return;
- ent.State.Data = rawData.Slice(6, rawData.Length - 6).ToArray();
-
- var data = new byte[rawData.Length];
-
- rawData.CopyTo(data);
-
- Broadcast(_readyPlayers, data);
+ var entityStateData = _serializer.ReadData(_serializer.Size);
+ ent.State.Write(ref entityStateData);
}
-
break;
}
case RagonOperation.REPLICATE_ENTITY_EVENT:
{
- var evntCodeData = rawData.Slice(2, 2);
- var entityIdData = rawData.Slice(4, 4);
- var evntId = RagonHeader.ReadUShort(ref evntCodeData);
- var entityId = RagonHeader.ReadInt(ref entityIdData);
+ var evntId = _serializer.ReadUShort();
+ var entityId = _serializer.ReadInt();
if (!_entities.TryGetValue(entityId, out var ent))
return;
@@ -165,86 +176,79 @@ namespace Ragon.Core
if (ent.Authority == RagonAuthority.OWNER_ONLY && ent.OwnerId != peerId)
return;
- var payload = rawData.Slice(8, rawData.Length - 8);
+ var payload = _serializer.ReadData(_serializer.Size);
if (_plugin.InternalHandle(peerId, entityId, evntId, ref payload))
return;
var data = new byte[rawData.Length];
-
rawData.CopyTo(data);
-
Broadcast(_readyPlayers, data, DeliveryType.Reliable);
break;
}
case RagonOperation.REPLICATE_EVENT:
{
- var evntCodeData = rawData.Slice(2, 2);
- var evntId = RagonHeader.ReadUShort(ref evntCodeData);
-
- var payload = rawData.Slice(4, rawData.Length - 4);
+ var evntId = _serializer.ReadUShort();
+ var payload = _serializer.ReadData(_serializer.Size);
if (_plugin.InternalHandle(peerId, evntId, ref payload))
return;
- var data = new byte[rawData.Length];
-
- rawData.CopyTo(data);
-
- Broadcast(_readyPlayers, data, DeliveryType.Reliable);
+ _serializer.Clear();
+ _serializer.WriteOperation(RagonOperation.REPLICATE_EVENT);
+ _serializer.WriteUShort(evntId);
+ var sendData = _serializer.ToArray();
+ Broadcast(_readyPlayers, sendData, DeliveryType.Reliable);
break;
}
case RagonOperation.CREATE_ENTITY:
{
- var typeData = rawData.Slice(2, 2);
- var authorityData = rawData.Slice(2, 2);
- var entityPayloadData = rawData.Slice(4, rawData.Length - 4);
-
- var entityType = RagonHeader.ReadUShort(ref typeData);
- var stateAuthority = (RagonAuthority) authorityData[0];
- var eventAuthority = (RagonAuthority) authorityData[1];
+ var entityType = _serializer.ReadUShort();
+ var stateAuthority = (RagonAuthority) _serializer.ReadByte();
+ var eventAuthority = (RagonAuthority) _serializer.ReadByte();
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];
player.Entities.Add(entity);
player.EntitiesIds.Add(entity.EntityId);
+ var ownerId = (ushort) peerId;
+
_entities.Add(entity.EntityId, entity);
_entitiesAll = _entities.Values.ToArray();
_plugin.OnEntityCreated(player, entity);
- var data = new byte[entityPayloadData.Length + 14];
- var sendData = data.AsSpan();
- var operationData = sendData.Slice(0, 2);
- var entityTypeData = sendData.Slice(2, 2);
- var authority = sendData.Slice(4, 2);
- var entityIdData = sendData.Slice(6, 4);
- var peerData = sendData.Slice(10, 4);
- var payload = sendData.Slice(14, entityPayloadData.Length);
-
- entityPayloadData.CopyTo(payload);
-
- authority[0] = authorityData[0];
- authority[1] = authorityData[1];
-
- 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);
+ _serializer.Clear();
+ _serializer.WriteOperation(RagonOperation.CREATE_ENTITY);
+ _serializer.WriteUShort(entityType);
+ _serializer.WriteByte((byte) stateAuthority);
+ _serializer.WriteByte((byte) eventAuthority);
+ _serializer.WriteInt(entity.EntityId);
+ _serializer.WriteUShort(ownerId);
+
+ {
+ var entityPayload = entity.Payload.Read();
+ _serializer.WriteData(ref entityPayload);
+ }
+
+ var sendData = _serializer.ToArray();
+ Broadcast(_allPlayers, sendData, DeliveryType.Reliable);
break;
}
case RagonOperation.DESTROY_ENTITY:
{
- var entityData = rawData.Slice(2, 4);
- var entityId = RagonHeader.ReadInt(ref entityData);
+ var entityId = _serializer.ReadInt();
if (_entities.TryGetValue(entityId, out var entity))
{
if (entity.Authority == RagonAuthority.OWNER_ONLY && entity.OwnerId != peerId)
return;
-
+
var player = _players[peerId];
+ var destroyPayload = _serializer.ReadData(_serializer.Size);
player.Entities.Remove(entity);
player.EntitiesIds.Remove(entity.EntityId);
@@ -254,49 +258,53 @@ namespace Ragon.Core
_plugin.OnEntityDestroyed(player, entity);
- var data = new byte[rawData.Length];
- Span sendData = data.AsSpan();
- rawData.CopyTo(sendData);
+ _serializer.Clear();
+ _serializer.WriteOperation(RagonOperation.DESTROY_ENTITY);
+ _serializer.WriteInt(entityId);
+ _serializer.WriteData(ref destroyPayload);
- Broadcast(_readyPlayers, data, DeliveryType.Reliable);
+ var sendData = _serializer.ToArray();
+ Broadcast(_readyPlayers, sendData, DeliveryType.Reliable);
}
break;
}
case RagonOperation.SCENE_IS_LOADED:
{
- Send(peerId, RagonOperation.RESTORE_BEGIN, DeliveryType.Reliable);
- foreach (var entity in _entities.Values)
+ _serializer.Clear();
+ _serializer.WriteOperation(RagonOperation.SNAPSHOT);
+
+ _serializer.WriteInt(_readyPlayers.Length + 1);
+ foreach (var playerPeerId in _readyPlayers)
{
- var entityState = entity.State.Data.AsSpan();
- var data = new byte[entity.State.Data.Length + 14];
+ _serializer.WriteString(_players[playerPeerId].Id);
+ _serializer.WriteUShort((ushort) playerPeerId);
+ _serializer.WriteString(_players[playerPeerId].PlayerName);
+ }
+
+ _serializer.WriteString(_players[peerId].Id);
+ _serializer.WriteUShort((ushort) peerId);
+ _serializer.WriteString(_players[peerId].PlayerName);
- Span sendData = data.AsSpan();
- Span operationData = sendData.Slice(0, 2);
- Span entityTypeData = sendData.Slice(2, 2);
- Span authorityData = sendData.Slice(4, 2);
- Span entityData = sendData.Slice(6, 4);
- Span ownerData = sendData.Slice(10, 4);
- Span 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);
+ _serializer.WriteInt(_entitiesAll.Length);
+ foreach (var entity in _entitiesAll)
+ {
+ _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);
}
- Send(peerId, RagonOperation.RESTORE_END, DeliveryType.Reliable);
- break;
- }
- case RagonOperation.RESTORED:
- {
+ var sendData = _serializer.ToArray();
+ Send(peerId, sendData, DeliveryType.Reliable);
+
_players[peerId].IsLoaded = true;
_readyPlayers = _players.Where(p => p.Value.IsLoaded).Select(p => p.Key).ToArray();
@@ -310,6 +318,24 @@ namespace Ragon.Core
{
_ticks++;
_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()
@@ -331,26 +357,6 @@ namespace Ragon.Core
_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(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)
{
_roomThread.WriteOutEvent(new Event()
diff --git a/Ragon/Sources/Rooms/RoomManager.cs b/Ragon/Sources/Rooms/RoomManager.cs
index 3d5cd3b..77a7ef5 100644
--- a/Ragon/Sources/Rooms/RoomManager.cs
+++ b/Ragon/Sources/Rooms/RoomManager.cs
@@ -14,7 +14,7 @@ namespace Ragon.Core
private PluginFactory _factory;
private AuthorizationManager _manager;
private RoomThread _roomThread;
-
+ private RagonSerializer _serializer;
public Action<(uint, Room)> OnJoined;
public Action<(uint, Room)> OnLeaved;
@@ -23,6 +23,7 @@ namespace Ragon.Core
_roomThread = roomThread;
_factory = factory;
+ _serializer = new RagonSerializer();
_manager = _factory.CreateManager(roomThread.Configuration);
_rooms = new List();
_peersByRoom = new Dictionary();
@@ -37,9 +38,40 @@ namespace Ragon.Core
OnAuthorize(peerId, payload);
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:
{
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));
break;
}
@@ -56,25 +88,18 @@ namespace Ragon.Core
{
if (_manager.OnAuthorize(peerId, ref payload))
{
- var sendData = new byte[2];
- Span data = sendData.AsSpan();
-
- RagonHeader.WriteUShort((ushort) RagonOperation.AUTHORIZED_SUCCESS, ref data);
-
- _roomThread.WriteOutEvent(new Event()
- {
- Delivery = DeliveryType.Reliable,
- Type = EventType.DATA,
- Data = sendData,
- PeerId = peerId,
- });
- }
- else
- {
- var sendData = new byte[2];
- var data = sendData.AsSpan();
- RagonHeader.WriteUShort((ushort) RagonOperation.AUTHORIZED_FAILED, ref data);
-
+ var sendData = new[] {(byte) RagonOperation.AUTHORIZED_SUCCESS};
+ _roomThread.WriteOutEvent(new Event()
+ {
+ Delivery = DeliveryType.Reliable,
+ Type = EventType.DATA,
+ Data = sendData,
+ PeerId = peerId,
+ });
+ }
+ else
+ {
+ var sendData = new[] {(byte) RagonOperation.AUTHORIZED_FAILED};
_roomThread.WriteOutEvent(new Event()
{
Delivery = DeliveryType.Reliable,
@@ -82,7 +107,6 @@ namespace Ragon.Core
Data = sendData,
PeerId = peerId,
});
-
_roomThread.WriteOutEvent(new Event()
{
Delivery = DeliveryType.Reliable,
@@ -93,15 +117,36 @@ namespace Ragon.Core
}
}
- public Room Join(uint peerId, ReadOnlySpan payload)
+ public Room? Join(uint peerId, ReadOnlySpan payload)
{
- var minData = payload.Slice(0, 2);
- var maxData = payload.Slice(2, 2);
- var mapData = payload.Slice(4, payload.Length - 4);
+ var roomId = Encoding.UTF8.GetString(payload);
- var map = Encoding.UTF8.GetString(mapData);
- var min = RagonHeader.ReadUShort(ref minData);
- var max = RagonHeader.ReadUShort(ref maxData);
+ if (_rooms.Count > 0)
+ {
+ 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 payload)
+ {
+ _serializer.Clear();
+ _serializer.FromSpan(ref payload);
+
+ var min = _serializer.ReadUShort();
+ var max = _serializer.ReadUShort();
+ var map = _serializer.ReadString();
Room room = null;
if (_rooms.Count > 0)
@@ -112,11 +157,11 @@ namespace Ragon.Core
{
room = existRoom;
room.Joined(peerId, payload);
-
+
_peersByRoom.Add(peerId, room);
-
- return room;
- }
+
+ return room;
+ }
}
}
@@ -127,7 +172,7 @@ namespace Ragon.Core
room = new Room(_roomThread, plugin, map, min, max);
room.Joined(peerId, payload);
room.Start();
-
+
_peersByRoom.Add(peerId, room);
_rooms.Add(room);
@@ -136,8 +181,8 @@ namespace Ragon.Core
public Room Left(uint peerId, ReadOnlySpan payload)
{
- _peersByRoom.Remove(peerId, out var room);
-
+ _peersByRoom.Remove(peerId, out var room);
+
return room;
}
@@ -147,10 +192,10 @@ namespace Ragon.Core
if (room != null)
{
room.Leave(peerId);
- if (room.PlayersCount <= 0)
+ if (room.PlayersCount <= 0 && room.PlayersMin > 0)
{
_rooms.Remove(room);
-
+
room.Stop();
room.Dispose();
}
diff --git a/Ragon/Sources/Rooms/RoomThread.cs b/Ragon/Sources/Rooms/RoomThread.cs
index a326c4d..089c3b5 100755
--- a/Ragon/Sources/Rooms/RoomThread.cs
+++ b/Ragon/Sources/Rooms/RoomThread.cs
@@ -16,8 +16,8 @@ namespace Ragon.Core
private readonly Stopwatch _timer;
private readonly ILogger _logger = LogManager.GetCurrentClassLogger();
private readonly float _deltaTime = 0.0f;
- private RingBuffer _receiveBuffer = new RingBuffer(8192 + 8192);
- private RingBuffer _sendBuffer = new RingBuffer(8192 + 8192);
+ private readonly RingBuffer _receiveBuffer = new(2048);
+ private readonly RingBuffer _sendBuffer = new(2048);
public Configuration Configuration { get; private set; }
public bool ReadOutEvent(out Event evnt) => _sendBuffer.TryDequeue(out evnt);
@@ -70,13 +70,14 @@ namespace Ragon.Core
if (evnt.Type == EventType.DATA)
{
var data = new ReadOnlySpan(evnt.Data);
- var operationData = data.Slice(0, 2);
- var operation = (RagonOperation) RagonHeader.ReadUShort(ref operationData);
+ var operation = (RagonOperation) data[0];
+ var payload = data.Slice(1, data.Length - 1);
+
if (_socketByRooms.TryGetValue(evnt.PeerId, out var room))
{
try
{
- room.ProcessEvent(operation, evnt.PeerId, data);
+ room.ProcessEvent(operation, evnt.PeerId, payload);
}
catch (Exception exception)
{
@@ -85,7 +86,6 @@ namespace Ragon.Core
}
else
{
- var payload = data.Slice(2, data.Length - 2);
_roomManager.ProcessEvent(operation, evnt.PeerId, payload);
}
}