This commit is contained in:
2022-04-24 09:05:15 +04:00
commit b26e7c1402
60 changed files with 3887 additions and 0 deletions
+19
View File
@@ -0,0 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<LangVersion>10</LangVersion>
<Nullable>enable</Nullable>
<TargetFrameworks>net6.0;netstandard2.1</TargetFrameworks>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="ENet-CSharp" Version="2.4.8" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
<PackageReference Include="NLog" Version="5.0.0-rc2" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Ragon.Common\Ragon.Common.csproj" />
</ItemGroup>
</Project>
+2
View File
@@ -0,0 +1,2 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=sources/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
+83
View File
@@ -0,0 +1,83 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using DisruptorUnity3d;
using NetStack.Serialization;
using NLog;
using Ragon.Common.Protocol;
namespace Ragon.Core
{
public class Application : IDisposable
{
private readonly Logger _logger = LogManager.GetCurrentClassLogger();
private readonly List<RoomThread> _roomThreads = new();
private readonly Dictionary<uint, RoomThread> _socketByRoomThreads = new();
private readonly Dictionary<RoomThread, int> _roomThreadCounter = new();
private readonly ENetServer _socketServer;
public Application(PluginFactory factory, Configuration configuration, int threadsCount)
{
_socketServer = new ENetServer();
for (var i = 0; i < threadsCount; i++)
{
var roomThread = new RoomThread(factory);
_roomThreadCounter.Add(roomThread, 0);
_roomThreads.Add(roomThread);
}
}
public void Start()
{
_socketServer.Start(5000);
foreach (var roomThread in _roomThreads)
roomThread.Start();
while (true)
{
foreach (var roomThread in _roomThreads)
while (roomThread.ReadOutEvent(out var evnt))
_socketServer.WriteEvent(evnt);
while (_socketServer.ReadEvent(out var evnt))
{
if (evnt.Type == EventType.CONNECTED)
{
var roomThread = _roomThreads.First();
_roomThreadCounter[roomThread] += 1;
_socketByRoomThreads.Add(evnt.PeerId, roomThread);
}
if (_socketByRoomThreads.TryGetValue(evnt.PeerId, out var existsRoomThread))
existsRoomThread.WriteInEvent(evnt);
if (evnt.Type == EventType.DISCONNECTED)
{
_socketByRoomThreads.Remove(evnt.PeerId, out var roomThread);
_roomThreadCounter[roomThread] =- 1;
}
if (evnt.Type == EventType.TIMEOUT)
{
_socketByRoomThreads.Remove(evnt.PeerId, out var roomThread);
_roomThreadCounter[roomThread] =- 1;
}
}
Thread.Sleep(1);
}
}
public void Dispose()
{
foreach (var roomThread in _roomThreads)
roomThread.Dispose();
_roomThreads.Clear();
}
}
}
+17
View File
@@ -0,0 +1,17 @@
using NLog;
namespace Ragon.Core
{
public class Bootstrap
{
private ILogger _logger = LogManager.GetCurrentClassLogger();
public void Configure(PluginFactory factory)
{
_logger.Info("Configure application...");
var configuration = ConfigurationLoader.Load("config.json");
var app = new Application(factory, configuration, 2);
app.Start();
}
}
}
+7
View File
@@ -0,0 +1,7 @@
namespace Ragon.Core
{
public class Configuration
{
public string[] blacklist;
}
}
+38
View File
@@ -0,0 +1,38 @@
using System;
using System.IO;
using Newtonsoft.Json;
using NLog;
using Logger = NLog.Logger;
namespace Ragon.Core
{
public static class ConfigurationLoader
{
private static readonly Logger _logger = LogManager.GetCurrentClassLogger();
private static readonly string _serverVersion = "2.0.0-preview";
private static void CopyrightInfo()
{
_logger.Info($"Server Version: {_serverVersion}");
_logger.Info($"Machine Name: {Environment.MachineName}");
_logger.Info($"OS: {Environment.OSVersion}");
_logger.Info($"Processors: {Environment.ProcessorCount}");
_logger.Info($"Runtime Version: {Environment.Version}");
_logger.Info("==================================");
_logger.Info("= =");
_logger.Info($"={"Yohoho Server".PadBoth(32)}=");
_logger.Info("= =");
_logger.Info("==================================");
}
public static Configuration Load(string filePath)
{
CopyrightInfo();
var data = File.ReadAllText(filePath);
var configuration = JsonConvert.DeserializeObject<Configuration>(data);
return configuration;
}
}
}
+142
View File
@@ -0,0 +1,142 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading;
using DisruptorUnity3d;
using ENet;
using NLog;
using NLog.LayoutRenderers.Wrappers;
namespace Ragon.Core
{
public enum Status
{
Stopped,
Listening,
Disconnecting,
Connecting,
Assigning,
Connected
}
public enum DeliveryType
{
UnreliableUnsequenced,
UnreliableSequenced,
UnreliableFragmented,
ReliableSequenced
}
public class ENetServer : IDisposable
{
public Status Status { get; private set; }
private ILogger _logger = LogManager.GetCurrentClassLogger();
private Thread _thread;
private Host _host;
private Address _address;
private ENet.Event _netEvent;
private Peer[] _peers;
private RingBuffer<Event> _receiveBuffer;
private RingBuffer<Event> _sendBuffer;
public void WriteEvent(Event evnt) => _sendBuffer.Enqueue(evnt);
public bool ReadEvent(out Event evnt) => _receiveBuffer.TryDequeue(out evnt);
public void Start(ushort port)
{
Library.Initialize();
_address = default;
_address.Port = port;
_host = new Host();
_host.Create(_address, 4095, 2, 0, 0, 1024 * 1024);
_peers = new Peer[4095];
_sendBuffer = new RingBuffer<Event>(8192 + 8192);
_receiveBuffer = new RingBuffer<Event>(8192 + 8192);
Status = Status.Listening;
_thread = new Thread(Execute);
_thread.Name = "NetworkThread";
_thread.Start();
_logger.Info($"Socket Server Started at port {port}");
}
private void Execute()
{
while (true)
{
while (_sendBuffer.TryDequeue(out var data))
{
var newPacket = new Packet();
newPacket.Create(data.Data, data.Data.Length, PacketFlags.Reliable);
_peers[data.PeerId].Send(0, ref newPacket);
}
bool polled = false;
while (!polled)
{
if (_host.CheckEvents(out _netEvent) <= 0)
{
if (_host.Service(16, out _netEvent) <= 0)
break;
polled = true;
}
switch (_netEvent.Type)
{
case ENet.EventType.None:
Console.WriteLine("None event");
break;
case ENet.EventType.Connect:
{
var @event = new Event {PeerId = _netEvent.Peer.ID, Type = EventType.CONNECTED};
// Console.WriteLine("Client connected - ID: " + _netEvent.Peer.ID + ", IP: " + _netEvent.Peer.IP);
_peers[_netEvent.Peer.ID] = _netEvent.Peer;
_receiveBuffer.Enqueue(@event);
break;
}
case ENet.EventType.Disconnect:
{
var @event = new Event {PeerId = _netEvent.Peer.ID, Type = EventType.DISCONNECTED};
// Console.WriteLine("Client disconnected - ID: " + _netEvent.Peer.ID + ", IP: " + _netEvent.Peer.IP);
_receiveBuffer.Enqueue(@event);
break;
}
case ENet.EventType.Timeout:
{
// Console.WriteLine("Client timeout - ID: " + _netEvent.Peer.ID + ", IP: " + _netEvent.Peer.IP);
var @event = new Event {PeerId = _netEvent.Peer.ID, Type = EventType.TIMEOUT};
// Console.WriteLine("Client disconnected - ID: " + _netEvent.Peer.ID + ", IP: " + _netEvent.Peer.IP);
_receiveBuffer.Enqueue(@event);
break;
}
case ENet.EventType.Receive:
{
// Console.WriteLine("Packet received from - ID: " + _netEvent.Peer.ID + ", IP: " + _netEvent.Peer.IP + ", Channel ID: " + _netEvent.ChannelID + ", Data length: " + _netEvent.Packet.Length);
var data = new byte[_netEvent.Packet.Length];
_netEvent.Packet.CopyTo(data);
_netEvent.Packet.Dispose();
var @event = new Event {PeerId = _netEvent.Peer.ID, Type = EventType.DATA, Data = data};
_receiveBuffer.Enqueue(@event);
break;
}
}
}
}
}
public void Dispose()
{
Library.Deinitialize();
_host?.Dispose();
}
}
}
+18
View File
@@ -0,0 +1,18 @@
using System.Collections.Generic;
namespace Ragon.Core;
public class Entity
{
private static int _idGenerator = 0;
public int EntityId { get; private set; }
public uint OwnerId { get; private set; }
public byte[] State { get; set; }
public Dictionary<int, byte[]> Properties { get; set; }
public Entity(uint ownerId)
{
OwnerId = ownerId;
EntityId = _idGenerator++;
}
}
+9
View File
@@ -0,0 +1,9 @@
namespace Ragon.Core
{
public struct Event
{
public EventType Type;
public uint PeerId;
public byte[] Data;
}
}
+10
View File
@@ -0,0 +1,10 @@
namespace Ragon.Core
{
public enum EventType
{
CONNECTED,
DISCONNECTED,
TIMEOUT,
DATA,
}
}
+14
View File
@@ -0,0 +1,14 @@
using System;
namespace Ragon.Core
{
public static class StringExtensions
{
public static string PadBoth(this string str, int length)
{
int spaces = length - str.Length;
int padLeft = spaces / 2 + str.Length;
return str.PadLeft(padLeft).PadRight(length);
}
}
}
+14
View File
@@ -0,0 +1,14 @@
using System;
namespace Ragon.Core
{
public static class ValueExtensions
{
public static T Clamp<T>(this T val, T min, T max) where T : IComparable<T>
{
if (val.CompareTo(min) < 0) return min;
else if (val.CompareTo(max) > 0) return max;
else return val;
}
}
}
+15
View File
@@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
namespace Ragon.Core
{
public class Player
{
public uint PeerId { get; set; }
public string PlayerName { get; set; }
public bool IsLoaded { get; set; }
public List<Entity> Entities;
public List<int> EntitiesIds;
}
}
+36
View File
@@ -0,0 +1,36 @@
using System;
using System.Collections.Generic;
namespace Ragon.Core
{
public class PluginBase
{
static class Storage<T>
{
public static Dictionary<Room, Dictionary<ushort, Action<T>>> Subscribes = new();
}
protected Room _room;
// protected Dictionary<ushort, > _subscribes = new Dictionary<ushort,???>();
public void Attach(Room room) => _room = room;
public void Subscribe<T>(ushort evntCode, Action<T> val)
{
Storage<T>.Subscribes.Add(_room, val);
}
public virtual void OnStart()
{
}
public virtual void OnStop()
{
}
public virtual void OnTick(ulong ticks, float deltaTime)
{
}
}
}
+7
View File
@@ -0,0 +1,7 @@
namespace Ragon.Core
{
public interface PluginFactory
{
public PluginBase CreatePlugin(string map);
}
}
+344
View File
@@ -0,0 +1,344 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NetStack.Serialization;
using NLog;
using Ragon.Common.Protocol;
namespace Ragon.Core
{
public class Room : IDisposable
{
private ILogger _logger = LogManager.GetCurrentClassLogger();
private Dictionary<uint, Player> _players = new();
private Dictionary<int, Entity> _entities = new();
private uint Owner;
private BitBuffer _buffer = new BitBuffer(8192);
private byte[] _bytes = new byte[8192];
private readonly PluginBase _plugin;
private readonly RoomThread _roomThread;
private readonly string _map;
private ulong _ticks = 0;
// Cache
private uint[] _readyPlayers = Array.Empty<uint>();
public int Players => _players.Count;
public int MaxPlayers { get; } = 0;
public Room(RoomThread roomThread, PluginBase pluginBase, string map)
{
_roomThread = roomThread;
_plugin = pluginBase;
_map = map;
_plugin.Attach(this);
}
public void Joined(uint peerId, byte[] payload)
{
if (_players.Count == 0)
{
Owner = peerId;
}
var player = new Player()
{
PlayerName = "Player " + peerId,
PeerId = peerId,
IsLoaded = false,
Entities = new List<Entity>(),
EntitiesIds = new List<int>(),
};
_players.Add(peerId, player);
_plugin.OnPlayerConnected(player);
var data = new byte[8];
ProtocolHeader.WriteEntity((int) peerId, data, 0);
ProtocolHeader.WriteEntity((int) Owner, data, 4);
Send(peerId, RagonOperation.JOIN_ROOM, data);
var sceneRawData = Encoding.UTF8.GetBytes(_map);
Send(peerId, RagonOperation.LOAD_SCENE, sceneRawData);
}
public void Leave(uint peerId)
{
if (_players.Remove(peerId, out var player))
{
_plugin.OnPlayerDisconnected(player);
foreach (var entityId in player.EntitiesIds)
{
var entityData = new byte[4];
ProtocolHeader.WriteEntity(entityId, entityData, 0);
Broadcast(_readyPlayers, RagonOperation.DESTROY_ENTITY, entityData);
_entities.Remove(entityId);
}
}
}
public void ProcessEvent(RagonOperation operation, uint peerId, byte[] rawData)
{
switch (operation)
{
case RagonOperation.REPLICATE_ENTITY_STATE:
{
var entityId = ProtocolHeader.ReadEntity(rawData, 2);
if (_entities.TryGetValue(entityId, out var ent))
{
var data = new byte[rawData.Length - 6]; // opcode(ushort)(2) + entity(int)(4)
Array.Copy(rawData, 6, data, 0, rawData.Length - 6);
_entities[entityId].State = data;
Broadcast(_readyPlayers, rawData);
}
break;
}
case RagonOperation.REPLICATE_ENTITY_PROPERTY:
{
var entityId = ProtocolHeader.ReadEntity(rawData, 2);
if (_entities.TryGetValue(entityId, out var ent))
{
var propertyId = ProtocolHeader.ReadProperty(rawData, 6);
var data = new byte[rawData.Length - 10]; // opcode(ushort)(2) + entity(int)(4) + propertyId(int)(4)
Array.Copy(rawData, 10, data, 0, rawData.Length - 10);
var props = _entities[entityId].Properties;
if (props.ContainsKey(propertyId))
{
props[propertyId] = data;
}
else
{
props.Add(propertyId, data);
}
Broadcast(_readyPlayers, RagonOperation.REPLICATE_ENTITY_PROPERTY, rawData);
}
break;
}
case RagonOperation.REPLICATE_EVENT:
{
Broadcast(_readyPlayers, rawData);
break;
}
case RagonOperation.CREATE_ENTITY:
{
var entity = new Entity(peerId);
var data = new byte[rawData.Length - 2]; // opcode(ushort)(2)
Array.Copy(rawData, 2, data, 0, rawData.Length - 2);
entity.State = data;
entity.Properties = new Dictionary<int, byte[]>();
var player = _players[peerId];
player.Entities.Add(entity);
player.EntitiesIds.Add(entity.EntityId);
_entities.Add(entity.EntityId, entity);
var entityData = new byte[entity.State.Length + 8];
ProtocolHeader.WriteEntity(entity.EntityId, entityData, 0);
ProtocolHeader.WriteEntity((int) peerId, entityData, 4);
Array.Copy(entity.State, 0, entityData, 8, entity.State.Length);
_logger.Trace("Create entity Owner:" + peerId + " Id: " + entity.EntityId);
Broadcast(_readyPlayers, RagonOperation.CREATE_ENTITY, entityData);
break;
}
case RagonOperation.DESTROY_ENTITY:
{
var entityId = ProtocolHeader.ReadEntity(rawData);
if (_entities.TryGetValue(entityId, out var entity))
{
if (entity.OwnerId == peerId)
{
var player = _players[peerId];
player.Entities.Remove(entity);
player.EntitiesIds.Remove(entity.EntityId);
_entities.Remove(entityId);
Broadcast(_readyPlayers, rawData);
}
}
break;
}
case RagonOperation.SCENE_IS_LOADED:
{
Send(peerId, RagonOperation.RESTORE_BEGIN, Array.Empty<byte>());
foreach (var entity in _entities.Values)
{
var entityData = new byte[entity.State.Length + 8];
ProtocolHeader.WriteEntity(entity.EntityId, entityData, 0);
ProtocolHeader.WriteEntity((int) entity.OwnerId, entityData, 4);
Array.Copy(entity.State, 0, entityData, 8, entity.State.Length);
Send(peerId, RagonOperation.CREATE_ENTITY, entityData);
}
Send(peerId, RagonOperation.RESTORE_END, Array.Empty<byte>());
break;
}
case RagonOperation.RESTORED:
{
_players[peerId].IsLoaded = true;
_readyPlayers = _players.Where(p => p.Value.IsLoaded).Select(p => p.Key).ToArray();
break;
}
}
}
public void Tick(float deltaTime)
{
_ticks++;
_plugin.OnTick(_ticks, deltaTime);
}
public void Start()
{
_plugin.OnStart();
}
public void Stop()
{
_plugin.OnStop();
}
public void Dispose()
{
}
public void Send(uint peerId, RagonOperation operation, byte[] payload)
{
if (payload.Length > 0)
{
var data = new byte[payload.Length + 2];
Array.Copy(payload, 0, data, 2, payload.Length);
ProtocolHeader.WriteOperation((ushort) operation, data);
_roomThread.WriteOutEvent(new Event()
{
PeerId = peerId,
Data = data,
Type = EventType.DATA,
});
}
else
{
var data = new byte[2];
ProtocolHeader.WriteOperation((ushort) operation, data);
_roomThread.WriteOutEvent(new Event()
{
PeerId = peerId,
Data = data,
Type = EventType.DATA,
});
}
}
public void Send(uint peerId, RagonOperation operation, IData payload)
{
_buffer.Clear();
payload.Serialize(_buffer);
_buffer.ToArray(_bytes);
var data = new byte[_buffer.Length + 2];
Array.Copy(_bytes, 0, data, 2, _buffer.Length);
ProtocolHeader.WriteOperation((ushort) operation, data);
_roomThread.WriteOutEvent(new Event()
{
PeerId = peerId,
Data = data,
Type = EventType.DATA,
});
}
public void Broadcast(uint[] peersIds, RagonOperation operation, IData payload)
{
_buffer.Clear();
payload.Serialize(_buffer);
_buffer.ToArray(_bytes);
var data = new byte[_buffer.Length + 2];
Array.Copy(_bytes, 0, data, 2, _buffer.Length);
ProtocolHeader.WriteOperation((ushort) operation, data);
foreach (var peer in peersIds)
{
_roomThread.WriteOutEvent(new Event()
{
PeerId = peer,
Data = data,
Type = EventType.DATA,
});
}
}
public void Broadcast(uint[] peersIds, RagonOperation operation, byte[] payload)
{
var data = new byte[payload.Length + 2];
Array.Copy(payload, 0, data, 2, payload.Length);
ProtocolHeader.WriteOperation((ushort) operation, data);
foreach (var peer in peersIds)
{
_roomThread.WriteOutEvent(new Event()
{
PeerId = peer,
Data = data,
Type = EventType.DATA,
});
}
}
public void Broadcast(uint[] peersIds, byte[] rawData)
{
foreach (var peer in peersIds)
{
_roomThread.WriteOutEvent(new Event()
{
PeerId = peer,
Data = rawData,
Type = EventType.DATA,
});
}
}
public void Broadcast(byte[] rawData)
{
foreach (var player in _players.Values.ToArray())
{
_roomThread.WriteOutEvent(new Event()
{
PeerId = player.PeerId,
Data = rawData,
Type = EventType.DATA,
});
}
}
}
}
+117
View File
@@ -0,0 +1,117 @@
using System;
using System.Collections.Generic;
using System.Text;
using NetStack.Serialization;
using NLog;
using Ragon.Common.Protocol;
namespace Ragon.Core
{
public class RoomManager
{
private readonly Logger _logger = LogManager.GetCurrentClassLogger();
private List<Room> _rooms;
private Dictionary<uint, Room> _peersByRoom;
private PluginFactory _factory;
private RoomThread _roomThread;
private BitBuffer _bitBuffer;
public Action<(uint, Room)> OnJoined;
public Action<(uint, Room)> OnLeaved;
public RoomManager(RoomThread roomThread, PluginFactory factory)
{
_roomThread = roomThread;
_factory = factory;
_rooms = new List<Room>();
_peersByRoom = new Dictionary<uint, Room>();
_bitBuffer = new BitBuffer(1024);
}
public void ProccessEvent(RagonOperation operation, uint peerId, byte[] payload)
{
switch (operation)
{
case RagonOperation.AUTHORIZE:
{
OnAuthorize(peerId, payload);
break;
}
case RagonOperation.JOIN_ROOM:
{
var room = Join(peerId, payload);
OnJoined?.Invoke((peerId, room));
break;
}
case RagonOperation.LEAVE_ROOM:
{
var room = Left(peerId, payload);
OnLeaved((peerId, room));
break;
}
}
}
public void OnAuthorize(uint peerId, byte[] payload)
{
_bitBuffer.Clear();
// _bitBuffer.FromArray(payload, payload.Length);
// var authorizePacket = new AuthorationData();
// authorizePacket.Deserialize(_bitBuffer);
var data = new byte[2];
ProtocolHeader.WriteOperation((ushort) RagonOperation.AUTHORIZED_SUCCESS, data);
_roomThread.WriteOutEvent(new Event()
{
Type = EventType.DATA,
Data = data,
PeerId = peerId,
});
}
public Room Join(uint peerId, byte[] payload)
{
var map = Encoding.UTF8.GetString(payload);
if (_rooms.Count > 0)
{
var existsRoom = _rooms[0];
existsRoom.Joined(peerId, payload);
_peersByRoom.Add(peerId, existsRoom);
return existsRoom;
}
var plugin = _factory.CreatePlugin(map);
if (plugin == null)
throw new NullReferenceException($"Plugin for map {map} is null");
_logger.Info("Room created");
var room = new Room(_roomThread, plugin, map);
room.Joined(peerId, payload);
_peersByRoom.Add(peerId, room);
_rooms.Add(room);
return room;
}
public Room Left(uint peerId, byte[] payload)
{
_peersByRoom.Remove(peerId, out var room);
room?.Leave(peerId);
return room;
}
public void Tick(float deltaTime)
{
foreach (Room room in _rooms)
room.Tick(deltaTime);
}
}
}
+103
View File
@@ -0,0 +1,103 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading;
using DisruptorUnity3d;
using ENet;
using NetStack.Serialization;
using Ragon.Common.Protocol;
namespace Ragon.Core
{
public class RoomThread : IDisposable
{
private readonly RoomManager _roomManager;
private readonly Dictionary<uint, Room> _socketByRooms;
private readonly Thread _thread;
private readonly Stopwatch _timer;
private RingBuffer<Event> _receiveBuffer = new RingBuffer<Event>(8192 + 8192);
private RingBuffer<Event> _sendBuffer = new RingBuffer<Event>(8192 + 8192);
public bool ReadOutEvent(out Event evnt) => _sendBuffer.TryDequeue(out evnt);
public void WriteOutEvent(Event evnt) => _sendBuffer.Enqueue(evnt);
public bool ReadIntEvent(out Event evnt) => _receiveBuffer.TryDequeue(out evnt);
public void WriteInEvent(Event evnt) => _receiveBuffer.Enqueue(evnt);
public RoomThread(PluginFactory factory)
{
_thread = new Thread(Execute);
_thread.IsBackground = true;
_timer = new Stopwatch();
_socketByRooms = new Dictionary<uint, Room>();
_roomManager = new RoomManager(this, factory);
_roomManager.OnJoined += (tuple) => _socketByRooms.Add(tuple.Item1, tuple.Item2);
_roomManager.OnLeaved += (tuple) => _socketByRooms.Remove(tuple.Item1);
}
public void Start()
{
_timer.Start();
_thread.Start();
}
public void Stop()
{
_thread.Interrupt();
}
private void Execute()
{
while (true)
{
var deltaTime = _timer.ElapsedMilliseconds;
if (deltaTime > 1000 / 60)
{
while (_receiveBuffer.TryDequeue(out var evnt))
{
if (evnt.Type == EventType.DISCONNECTED || evnt.Type == EventType.TIMEOUT)
{
if (_socketByRooms.ContainsKey(evnt.PeerId))
{
_roomManager.Left(evnt.PeerId, Array.Empty<byte>());
_socketByRooms.Remove(evnt.PeerId);
}
}
if (evnt.Type == EventType.DATA)
{
var operation = (RagonOperation) ProtocolHeader.ReadOperation(evnt.Data, 0);
if (_socketByRooms.TryGetValue(evnt.PeerId, out var room))
{
room.ProcessEvent(operation, evnt.PeerId, evnt.Data);
}
else
{
var payload = new byte[evnt.Data.Length - 2];
Array.Copy(evnt.Data, 2, payload, 0, evnt.Data.Length - 2);
_roomManager.ProccessEvent(operation, evnt.PeerId, payload);
}
}
}
_roomManager.Tick(deltaTime / 1000.0f);
_timer.Restart();
}
else
{
Thread.Sleep(1);
}
}
}
public void Dispose()
{
}
}
}
+9
View File
@@ -0,0 +1,9 @@
namespace Ragon.Core
{
public struct RoomThreadInfo
{
public int PlayersCount;
public int PlayersMax;
public bool Available;
}
}
+6
View File
@@ -0,0 +1,6 @@
namespace Ragon.Core;
public class WebsocketServer
{
}
+2
View File
@@ -0,0 +1,2 @@
- Send states only on scene loaded
- Add events global and by entity