Merge pull request #3 from edmand46/dev

Replication level
This commit is contained in:
2022-07-31 09:37:35 +04:00
committed by GitHub
7 changed files with 199 additions and 67 deletions
+1
View File
@@ -7,6 +7,7 @@ namespace Ragon.Common
AUTHORIZED_FAILED, AUTHORIZED_FAILED,
JOIN_OR_CREATE_ROOM, JOIN_OR_CREATE_ROOM,
CREATE_ROOM,
JOIN_ROOM, JOIN_ROOM,
LEAVE_ROOM, LEAVE_ROOM,
OWNERSHIP_CHANGED, OWNERSHIP_CHANGED,
@@ -0,0 +1,25 @@
using NetStack.Serialization;
namespace Ragon.Common
{
public class RagonRoomParameters: IRagonSerializable
{
public string Map { get; set; }
public int Min { get; set; }
public int Max { get; set; }
public void Serialize(BitBuffer buffer)
{
buffer.AddString(Map);
buffer.AddInt(Min);
buffer.AddInt(Max);
}
public void Deserialize(BitBuffer buffer)
{
Map = buffer.ReadString();
Min = buffer.ReadInt();
Max = buffer.ReadInt();
}
}
}
+18
View File
@@ -38,6 +38,24 @@ namespace Ragon.Common
return value; return value;
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void WriteBool(bool value)
{
ResizeIfNeed(1);
_data[_offset] = value ? (byte) 1 : (byte) 0;
_offset += 1;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool ReadBool()
{
var value = _data[_offset];
_offset += 1;
return value == 1;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void WriteInt(int value) public void WriteInt(int value)
{ {
+18 -27
View File
@@ -29,7 +29,7 @@ namespace Ragon.Core
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 GameRoom(IGameThread gameThread, PluginBase pluginBase, string map, int min, int max) public GameRoom(IGameThread gameThread, PluginBase pluginBase, string roomId, string map, int min, int max)
{ {
_gameThread = gameThread; _gameThread = gameThread;
_plugin = pluginBase; _plugin = pluginBase;
@@ -38,7 +38,7 @@ namespace Ragon.Core
Map = map; Map = map;
PlayersMin = min; PlayersMin = min;
PlayersMax = max; PlayersMax = max;
Id = Guid.NewGuid().ToString(); Id = roomId;
_plugin.Attach(this); _plugin.Attach(this);
} }
@@ -94,8 +94,6 @@ namespace Ragon.Core
_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(); _readyPlayers = _players.Where(p => p.Value.IsLoaded).Select(p => p.Key).ToArray();
var isOwnershipChange = player.PeerId == _owner;
{ {
_plugin.OnPlayerLeaved(player); _plugin.OnPlayerLeaved(player);
@@ -114,34 +112,12 @@ namespace Ragon.Core
Broadcast(_readyPlayers, sendData); Broadcast(_readyPlayers, sendData);
} }
if (_allPlayers.Length > 0 && isOwnershipChange)
{
var newRoomOwnerId = _allPlayers[0];
var newRoomOwner = _players[newRoomOwnerId];
_owner = newRoomOwnerId;
{
_plugin.OnOwnershipChanged(newRoomOwner);
_serializer.Clear();
_serializer.WriteOperation(RagonOperation.OWNERSHIP_CHANGED);
_serializer.WriteString(newRoomOwner.Id);
var sendData = _serializer.ToArray();
Broadcast(_readyPlayers, sendData);
}
}
_entitiesAll = _entities.Values.ToArray(); _entitiesAll = _entities.Values.ToArray();
} }
} }
public void ProcessEvent(uint peerId, ReadOnlySpan<byte> rawData) public void ProcessEvent(uint peerId, RagonOperation operation, ReadOnlySpan<byte> payloadRawData)
{ {
var operation = (RagonOperation) rawData[0];
var payloadRawData = rawData.Slice(1, rawData.Length - 1);
_serializer.Clear(); _serializer.Clear();
_serializer.FromSpan(ref payloadRawData); _serializer.FromSpan(ref payloadRawData);
@@ -193,6 +169,21 @@ namespace Ragon.Core
Broadcast(_readyPlayers, sendData, DeliveryType.Reliable); Broadcast(_readyPlayers, sendData, DeliveryType.Reliable);
break; break;
} }
case RagonOperation.LOAD_SCENE:
{
var sceneName = _serializer.ReadString();
_readyPlayers = Array.Empty<uint>();
_entitiesAll = Array.Empty<Entity>();
_entities.Clear();
_serializer.Clear();
_serializer.WriteOperation(RagonOperation.LOAD_SCENE);
_serializer.WriteString(sceneName);
var sendData = _serializer.ToArray();
Broadcast(_allPlayers, sendData, DeliveryType.Reliable);
break;
}
case RagonOperation.REPLICATE_EVENT: case RagonOperation.REPLICATE_EVENT:
{ {
var evntId = _serializer.ReadUShort(); var evntId = _serializer.ReadUShort();
+7 -8
View File
@@ -1,7 +1,7 @@
using System; using System;
using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Threading; using System.Threading;
using Ragon.Common;
using ENet; using ENet;
using NLog; using NLog;
@@ -109,14 +109,13 @@ namespace Ragon.Core
evnt.Packet.CopyTo(dataRaw); evnt.Packet.CopyTo(dataRaw);
var data = new ReadOnlySpan<byte>(dataRaw); var data = new ReadOnlySpan<byte>(dataRaw);
var operation = (RagonOperation) data[0];
var payload = data.Slice(1, data.Length - 1);
if (_roomManager.RoomsBySocket.TryGetValue(peerId, out var room)) if (_roomManager.RoomsBySocket.TryGetValue(peerId, out var room))
{ room.ProcessEvent(peerId, operation, payload);
room.ProcessEvent(peerId, data);
} _lobby.ProcessEvent(peerId, operation, payload);
else
{
_lobby.ProcessEvent(peerId, data);
}
} }
catch (Exception exception) catch (Exception exception)
{ {
+82 -18
View File
@@ -1,64 +1,128 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using NetStack.Serialization;
using NLog;
using Ragon.Common; using Ragon.Common;
namespace Ragon.Core; namespace Ragon.Core;
public class Lobby : ILobby public class Lobby : ILobby
{ {
private readonly ILogger _logger = LogManager.GetCurrentClassLogger();
private readonly RagonSerializer _serializer; private readonly RagonSerializer _serializer;
private readonly BitBuffer _buffer;
private readonly RoomManager _roomManager; private readonly RoomManager _roomManager;
private readonly AuthorizationManager _authorizationManager; private readonly AuthorizationManager _authorizationManager;
private readonly IGameThread _gameThread;
public AuthorizationManager AuthorizationManager => _authorizationManager; public AuthorizationManager AuthorizationManager => _authorizationManager;
public Lobby(IAuthorizationProvider provider, RoomManager manager, IGameThread gameThread) public Lobby(IAuthorizationProvider provider, RoomManager manager, IGameThread gameThread)
{ {
_roomManager = manager; _roomManager = manager;
_gameThread = gameThread;
_buffer = new BitBuffer();
_serializer = new RagonSerializer(); _serializer = new RagonSerializer();
_authorizationManager = new AuthorizationManager(provider, gameThread, this, _serializer); _authorizationManager = new AuthorizationManager(provider, gameThread, this, _serializer);
} }
public void ProcessEvent(uint peerId, ReadOnlySpan<byte> data) public void ProcessEvent(uint peerId, RagonOperation op, ReadOnlySpan<byte> payload)
{ {
var op = (RagonOperation) data[0];
var payload = data.Slice(1, data.Length - 1);
_serializer.Clear(); _serializer.Clear();
_serializer.FromSpan(ref payload); _serializer.FromSpan(ref payload);
switch (op) if (op == RagonOperation.AUTHORIZE)
{
case RagonOperation.AUTHORIZE:
{ {
var key = _serializer.ReadString(); var key = _serializer.ReadString();
var playerName = _serializer.ReadString(); var playerName = _serializer.ReadString();
var protocol = _serializer.ReadByte(); var protocol = _serializer.ReadByte();
_authorizationManager.OnAuthorization(peerId, key, playerName, protocol); _authorizationManager.OnAuthorization(peerId, key, playerName, protocol);
break; return;
} }
var player = _authorizationManager.GetPlayer(peerId);
if (player == null)
{
_logger.Warn($"Peer not authorized {peerId} trying to {op}");
return;
}
switch (op)
{
case RagonOperation.JOIN_ROOM: case RagonOperation.JOIN_ROOM:
{ {
var roomId = _serializer.ReadString(); var roomId = _serializer.ReadString();
var player = _authorizationManager.GetPlayer(peerId); roomId = _serializer.ReadString();
if (player != null) var exists = _roomManager.Rooms.Any(r => r.Id == roomId);
if (!exists)
{
_serializer.Clear();
_serializer.WriteOperation(RagonOperation.JOIN_FAILED);
_serializer.WriteString($"Room with id {roomId} not exists");
var sendData = _serializer.ToArray();
_gameThread.Server.Send(peerId, sendData, DeliveryType.Reliable);
return;
}
if (_roomManager.RoomsBySocket.ContainsKey(peerId))
_roomManager.Left(player, Array.Empty<byte>());
_roomManager.Join(player, roomId, Array.Empty<byte>()); _roomManager.Join(player, roomId, Array.Empty<byte>());
break; break;
} }
case RagonOperation.CREATE_ROOM:
{
var roomId = Guid.NewGuid().ToString();
var custom = _serializer.ReadBool();
if (custom)
{
roomId = _serializer.ReadString();
var exists = _roomManager.Rooms.Any(r => r.Id == roomId);
if (exists)
{
_serializer.Clear();
_serializer.WriteOperation(RagonOperation.JOIN_FAILED);
_serializer.WriteString($"Room with id {roomId} already exists");
var sendData = _serializer.ToArray();
_gameThread.Server.Send(peerId, sendData, DeliveryType.Reliable);
return;
}
}
var propertiesPayload = _serializer.ReadData(_serializer.Size);
_buffer.Clear();
_buffer.FromSpan(ref propertiesPayload, propertiesPayload.Length);
var roomProperties = new RagonRoomParameters();
roomProperties.Deserialize(_buffer);
if (_roomManager.RoomsBySocket.ContainsKey(peerId))
_roomManager.Left(player, Array.Empty<byte>());
_roomManager.Create(player, roomId, roomProperties, Array.Empty<byte>());
break;
}
case RagonOperation.JOIN_OR_CREATE_ROOM: case RagonOperation.JOIN_OR_CREATE_ROOM:
{ {
var min = _serializer.ReadUShort(); var roomId = Guid.NewGuid().ToString();
var max = _serializer.ReadUShort(); var roomProperties = new RagonRoomParameters();
var map = _serializer.ReadString(); var propertiesPayload = _serializer.ReadData(_serializer.Size);
var player = _authorizationManager.GetPlayer(peerId);
if (player != null) _buffer.Clear();
_roomManager.JoinOrCreate(player, map, min, max, Array.Empty<byte>()); _buffer.FromSpan(ref propertiesPayload, propertiesPayload.Length);
roomProperties.Deserialize(_buffer);
if (_roomManager.RoomsBySocket.ContainsKey(peerId))
_roomManager.Left(player, Array.Empty<byte>());
_roomManager.JoinOrCreate(player, roomId, roomProperties, Array.Empty<byte>());
break; break;
} }
case RagonOperation.LEAVE_ROOM: case RagonOperation.LEAVE_ROOM:
{ {
var player = _authorizationManager.GetPlayer(peerId);
if (player != null)
_roomManager.Left(player, Array.Empty<byte>()); _roomManager.Left(player, Array.Empty<byte>());
break; break;
} }
+38 -4
View File
@@ -11,7 +11,7 @@ public class RoomManager
private readonly IGameThread _gameThread; private readonly IGameThread _gameThread;
private readonly PluginFactory _factory; private readonly PluginFactory _factory;
private readonly Logger _logger = LogManager.GetCurrentClassLogger(); private readonly Logger _logger = LogManager.GetCurrentClassLogger();
private readonly List<GameRoom> _rooms = new List<GameRoom>(); private readonly List<GameRoom> _rooms = new();
private readonly Dictionary<uint, GameRoom> _roomsBySocket; private readonly Dictionary<uint, GameRoom> _roomsBySocket;
public IReadOnlyDictionary<uint, GameRoom> RoomsBySocket => _roomsBySocket; public IReadOnlyDictionary<uint, GameRoom> RoomsBySocket => _roomsBySocket;
@@ -26,6 +26,8 @@ public class RoomManager
public void Join(Player player, string roomId, byte[] payload) public void Join(Player player, string roomId, byte[] payload)
{ {
_logger.Trace($"Player ({player.PlayerName}|{player.Id}) joined to room with Id {roomId}");
if (_rooms.Count > 0) if (_rooms.Count > 0)
{ {
foreach (var existRoom in _rooms) foreach (var existRoom in _rooms)
@@ -34,20 +36,46 @@ public class RoomManager
{ {
existRoom.Joined(player, payload); existRoom.Joined(player, payload);
_roomsBySocket.Add(player.PeerId, existRoom); _roomsBySocket.Add(player.PeerId, existRoom);
break; return;
} }
} }
} }
} }
public void JoinOrCreate(Player player, string map, int min, int max, byte[] payload) public void Create(Player creator, string roomId, RagonRoomParameters parameters, byte[] payload)
{ {
var map = parameters.Map;
var min = parameters.Min;
var max = parameters.Max;
_logger.Trace($"Player ({creator.PlayerName}|{creator.Id}) create room with Id {roomId} and params ({map}|{min}|{max})");
var plugin = _factory.CreatePlugin(map);
if (plugin == null)
throw new NullReferenceException($"Plugin for map {map} is null");
var room = new GameRoom(_gameThread, plugin, roomId, map, min, max);
room.Joined(creator, payload);
room.Start();
_roomsBySocket.Add(creator.PeerId, room);
_rooms.Add(room);
}
public void JoinOrCreate(Player player, string roomId, RagonRoomParameters parameters, byte[] payload)
{
var map = parameters.Map;
var min = parameters.Min;
var max = parameters.Max;
if (_rooms.Count > 0) if (_rooms.Count > 0)
{ {
foreach (var existRoom in _rooms) foreach (var existRoom in _rooms)
{ {
if (existRoom.Map == map && existRoom.PlayersCount < existRoom.PlayersMax) if (existRoom.Map == map && existRoom.PlayersCount < existRoom.PlayersMax)
{ {
_logger.Trace($"Player ({player.PlayerName}|{player.Id}) joined to room with Id {roomId}");
existRoom.Joined(player, payload); existRoom.Joined(player, payload);
_roomsBySocket.Add(player.PeerId, existRoom); _roomsBySocket.Add(player.PeerId, existRoom);
return; return;
@@ -55,11 +83,13 @@ public class RoomManager
} }
} }
_logger.Trace($"Room not found for Player ({player.PlayerName}|{player.Id}), create room with Id {roomId} and params ({map}|{min}|{max})");
var plugin = _factory.CreatePlugin(map); var plugin = _factory.CreatePlugin(map);
if (plugin == null) if (plugin == null)
throw new NullReferenceException($"Plugin for map {map} is null"); throw new NullReferenceException($"Plugin for map {map} is null");
var room = new GameRoom(_gameThread, plugin, map, min, max); var room = new GameRoom(_gameThread, plugin, roomId, map, min, max);
room.Joined(player, payload); room.Joined(player, payload);
room.Start(); room.Start();
@@ -71,12 +101,16 @@ public class RoomManager
{ {
if (_roomsBySocket.Remove(player.PeerId, out var room)) if (_roomsBySocket.Remove(player.PeerId, out var room))
{ {
_logger.Trace($"Player ({player.PlayerName}|{player.Id}) left room with Id {room.Id}");
room.Leave(player.PeerId); room.Leave(player.PeerId);
if (room.PlayersCount < room.PlayersMin) if (room.PlayersCount < room.PlayersMin)
{ {
_logger.Trace($"Room with Id {room.Id} destroyed");
room.Stop(); room.Stop();
_rooms.Remove(room); _rooms.Remove(room);
} }
_gameThread.Server.Send(player.PeerId, new byte[] {(byte) RagonOperation.LEAVE_ROOM}, DeliveryType.Reliable);
} }
} }