feat: websocket

This commit is contained in:
2022-10-22 21:34:35 +04:00
parent b9e79af9d8
commit b7e8327ca8
27 changed files with 312 additions and 181 deletions
+1
View File
@@ -1,4 +1,5 @@
using System; using System;
using System.Threading;
using Game.Source; using Game.Source;
using Ragon.Core; using Ragon.Core;
@@ -4,10 +4,10 @@ using Ragon.Core;
namespace Game.Source; namespace Game.Source;
public class AuthorizationProviderByKey: IAuthorizationProvider public class ApplicationHandlerByKey: IApplicationHandler
{ {
private Configuration _configuration; private Configuration _configuration;
public AuthorizationProviderByKey(Configuration configuration) public ApplicationHandlerByKey(Configuration configuration)
{ {
_configuration = configuration; _configuration = configuration;
} }
@@ -26,4 +26,19 @@ public class AuthorizationProviderByKey: IAuthorizationProvider
reject(0); reject(0);
} }
} }
public void OnCustomEvent(ushort peerId, ReadOnlySpan<byte> payload)
{
}
public void OnJoin(ushort peerId)
{
}
public void OnLeave(ushort peerId)
{
}
} }
@@ -10,9 +10,9 @@ namespace Game.Source
return new SimplePlugin(); return new SimplePlugin();
} }
public IAuthorizationProvider CreateAuthorizationProvider(Configuration configuration) public IApplicationHandler CreateAuthorizationProvider(Configuration configuration)
{ {
return new AuthorizationProviderByKey(configuration); return new ApplicationHandlerByKey(configuration);
} }
} }
} }
+42 -34
View File
@@ -6,21 +6,20 @@ using NLog;
namespace Ragon.Core namespace Ragon.Core
{ {
public class Application : IHandler public class Application : IEventHandler
{ {
private readonly RoomManager _roomManager; private readonly RoomManager _roomManager;
private readonly Thread _thread; private readonly Thread _thread;
private readonly Lobby _lobby; private readonly Lobby _lobby;
private readonly ISocketServer _socketServer; private readonly ISocketServer _socketServer;
private readonly IDispatcherInternal _dispatcherInternal; private readonly Dispatcher _dispatcher;
private readonly IDispatcher _dispatcher;
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 readonly Configuration _configuration; private readonly Configuration _configuration;
private readonly RagonSerializer _serializer; private readonly RagonSerializer _serializer;
public ISocketServer SocketServer => _socketServer; public ISocketServer SocketServer => _socketServer;
public IDispatcher Dispatcher => _dispatcher; public Dispatcher Dispatcher => _dispatcher;
public Application(PluginFactory factory, Configuration configuration) public Application(PluginFactory factory, Configuration configuration)
{ {
@@ -30,10 +29,9 @@ namespace Ragon.Core
_serializer = new RagonSerializer(); _serializer = new RagonSerializer();
var dispatcher = new Dispatcher(); var dispatcher = new Dispatcher();
_dispatcherInternal = dispatcher;
_dispatcher = dispatcher; _dispatcher = dispatcher;
_socketServer = new ENetServer(this); _socketServer = new WebSocketServer(this);
_deltaTime = 1000.0f / configuration.SendRate; _deltaTime = 1000.0f / configuration.SendRate;
_roomManager = new RoomManager(factory, this); _roomManager = new RoomManager(factory, this);
@@ -81,45 +79,55 @@ namespace Ragon.Core
while (true) while (true)
{ {
_socketServer.Process(); _socketServer.Process();
_dispatcherInternal.Process(); _dispatcher.Process();
_roomManager.Tick(_deltaTime); _roomManager.Tick(_deltaTime);
//
Thread.Sleep((int) _deltaTime); Thread.Sleep((int) _deltaTime);
} }
} }
public void OnConnected(ushort peerId)
public void OnEvent(Event evnt)
{ {
if (evnt.Type == EventType.Timeout || evnt.Type == EventType.Disconnect) _logger.Trace("Connected " + peerId);
}
public void OnDisconnected(ushort peerId)
{
_logger.Trace("Disconnected " + peerId);
var player = _lobby.AuthorizationManager.GetPlayer(peerId);
if (player != null)
_roomManager.Left(player, Array.Empty<byte>());
_lobby.OnDisconnected(peerId);
}
public void OnData(ushort peerId, byte[] data)
{
try
{ {
var player = _lobby.AuthorizationManager.GetPlayer((ushort) evnt.Peer.ID); _serializer.Clear();
if (player != null) _serializer.FromArray(data);
_roomManager.Left(player, Array.Empty<byte>());
_lobby.OnDisconnected((ushort) evnt.Peer.ID); var operation = _serializer.ReadOperation();
if (_roomManager.RoomsBySocket.TryGetValue(peerId, out var room))
room.ProcessEvent(peerId, operation, _serializer);
_lobby.ProcessEvent(peerId, operation, _serializer);
} }
catch (Exception exception)
if (evnt.Type == EventType.Receive)
{ {
try _logger.Error(exception);
{
var peerId = (ushort) evnt.Peer.ID;
var dataRaw = new byte[evnt.Packet.Length];
evnt.Packet.CopyTo(dataRaw);
_serializer.FromArray(dataRaw);
var operation = _serializer.ReadOperation();
if (_roomManager.RoomsBySocket.TryGetValue(peerId, out var room))
room.ProcessEvent(peerId, operation, _serializer);
_lobby.ProcessEvent(peerId, operation, _serializer);
}
catch (Exception exception)
{
_logger.Error(exception);
}
} }
} }
public void OnTimeout(ushort peerId)
{
var player = _lobby.AuthorizationManager.GetPlayer(peerId);
if (player != null)
_roomManager.Left(player, Array.Empty<byte>());
_lobby.OnDisconnected(peerId);
}
} }
} }
@@ -5,17 +5,17 @@ using Ragon.Common;
namespace Ragon.Core; namespace Ragon.Core;
public class AuthorizationManager : IAuthorizationManager public class AuthorizationManager
{ {
private Logger _logger = LogManager.GetCurrentClassLogger(); private Logger _logger = LogManager.GetCurrentClassLogger();
private IAuthorizationProvider _provider; private IApplicationHandler _provider;
private Application _gameThread; private Application _gameThread;
private Lobby _lobby; private Lobby _lobby;
private RagonSerializer _serializer; private RagonSerializer _serializer;
private readonly Dictionary<uint, Player> _playersByPeers; private readonly Dictionary<uint, Player> _playersByPeers;
private readonly Dictionary<string, Player> _playersByIds; private readonly Dictionary<string, Player> _playersByIds;
public AuthorizationManager(IAuthorizationProvider provider, Application gameThread, Lobby lobby, RagonSerializer serializer) public AuthorizationManager(IApplicationHandler provider, Application gameThread, Lobby lobby, RagonSerializer serializer)
{ {
_serializer = serializer; _serializer = serializer;
_lobby = lobby; _lobby = lobby;
@@ -29,11 +29,10 @@ namespace Ragon.Core
_logger.Info($"OS: {Environment.OSVersion}"); _logger.Info($"OS: {Environment.OSVersion}");
_logger.Info($"Processors: {Environment.ProcessorCount}"); _logger.Info($"Processors: {Environment.ProcessorCount}");
_logger.Info($"Runtime Version: {Environment.Version}"); _logger.Info($"Runtime Version: {Environment.Version}");
_logger.Info("=================================="); _logger.Info("==================================");
_logger.Info("= ="); _logger.Info("| |");
_logger.Info($"={"Ragon".PadBoth(32)}="); _logger.Info("| Ragon |");
_logger.Info("= ="); _logger.Info("| |");
_logger.Info("=================================="); _logger.Info("==================================");
} }
@@ -3,7 +3,7 @@ using System.Collections.Generic;
namespace Ragon.Core; namespace Ragon.Core;
public class Dispatcher: IDispatcher, IDispatcherInternal public class Dispatcher
{ {
public Queue<Action> _actions = new Queue<Action>(); public Queue<Action> _actions = new Queue<Action>();
+17
View File
@@ -228,4 +228,21 @@ public class Entity
} }
} }
} }
public void ProcessEvent(Player player, RagonSerializer reader)
{
var eventId = reader.ReadUShort();
var eventMode = (RagonReplicationMode) reader.ReadByte();
var targetMode = (RagonTarget) reader.ReadByte();
var payloadData = reader.ReadData(reader.Size);
Span<byte> payloadRaw = stackalloc byte[reader.Size];
ReadOnlySpan<byte> payload = payloadRaw;
payloadData.CopyTo(payloadRaw);
if (_room.Plugin.InternalHandle(player.PeerId, EntityId, eventId, ref payload))
return;
ReplicateEvent(player.PeerId, eventId, payload, eventMode, targetMode);
}
} }
@@ -1,14 +0,0 @@
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);
}
}
}
@@ -1,14 +0,0 @@
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;
}
}
}
+23 -35
View File
@@ -7,7 +7,7 @@ using Ragon.Common;
namespace Ragon.Core namespace Ragon.Core
{ {
public class GameRoom : IGameRoom public class GameRoom
{ {
public int PlayersMin { get; private set; } public int PlayersMin { get; private set; }
public int PlayersMax { get; private set; } public int PlayersMax { get; private set; }
@@ -15,14 +15,14 @@ namespace Ragon.Core
public int EntitiesCount => _entities.Count; public int EntitiesCount => _entities.Count;
public string Id { get; private set; } public string Id { get; private set; }
public string Map { get; private set; } public string Map { get; private set; }
public PluginBase Plugin => _plugin;
private ILogger _logger = LogManager.GetCurrentClassLogger(); private ILogger _logger = LogManager.GetCurrentClassLogger();
private Dictionary<ushort, Player> _players = new(); private Dictionary<ushort, Player> _players = new();
private Dictionary<int, Entity> _entities = new(); private Dictionary<int, Entity> _entities = new();
private ushort _owner; private ushort _owner;
private readonly IScheduler _scheduler;
private readonly ISocketServer _socketServer; private readonly ISocketServer _socketServer;
private readonly Scheduler _scheduler;
private readonly Application _application; private readonly Application _application;
private readonly PluginBase _plugin; private readonly PluginBase _plugin;
private readonly RagonSerializer _writer = new(512); private readonly RagonSerializer _writer = new(512);
@@ -131,7 +131,7 @@ namespace Ragon.Core
} }
player.AttachEntity(entity); player.AttachEntity(entity);
AttachEntity(entity); AttachEntity(player, entity);
} }
_entitiesAll = _entities.Values.ToArray(); _entitiesAll = _entities.Values.ToArray();
@@ -202,26 +202,15 @@ namespace Ragon.Core
} }
case RagonOperation.REPLICATE_ENTITY_EVENT: case RagonOperation.REPLICATE_ENTITY_EVENT:
{ {
var eventId = reader.ReadUShort();
var eventMode = (RagonReplicationMode) reader.ReadByte();
var targetMode = (RagonTarget) reader.ReadByte();
var entityId = reader.ReadUShort(); var entityId = reader.ReadUShort();
var payloadData = reader.ReadData(reader.Size);
Span<byte> payloadRaw = stackalloc byte[reader.Size];
ReadOnlySpan<byte> payload = payloadRaw;
payloadData.CopyTo(payloadRaw);
if (!_entities.TryGetValue(entityId, out var ent)) if (!_entities.TryGetValue(entityId, out var ent))
{ {
_logger.Warn($"Entity not found for event with Id {eventId}"); _logger.Warn($"Entity not found for event with Id {entityId}");
return; return;
} }
if (_plugin.InternalHandle(peerId, entityId, eventId, ref payload)) var player = _players[peerId];
return; ent.ProcessEvent(player, reader);
ent.ReplicateEvent(peerId, eventId, payload, eventMode, targetMode);
break; break;
} }
case RagonOperation.CREATE_ENTITY: case RagonOperation.CREATE_ENTITY:
@@ -233,7 +222,7 @@ namespace Ragon.Core
_logger.Trace($"[{peerId}] Create Entity {entityType}"); _logger.Trace($"[{peerId}] Create Entity {entityType}");
var player = _players[peerId]; var player = _players[peerId];
var entity = new Entity(this, (ushort) player.PeerId, entityType, 0, eventAuthority); var entity = new Entity(this, player.PeerId, entityType, 0, eventAuthority);
for (var i = 0; i < propertiesCount; i++) for (var i = 0; i < propertiesCount; i++)
{ {
var propertyType = reader.ReadBool(); var propertyType = reader.ReadBool();
@@ -248,7 +237,7 @@ namespace Ragon.Core
return; return;
player.AttachEntity(entity); player.AttachEntity(entity);
AttachEntity(entity); AttachEntity(player, entity);
entity.Create(); entity.Create();
break; break;
@@ -258,21 +247,10 @@ namespace Ragon.Core
var entityId = reader.ReadInt(); var entityId = reader.ReadInt();
if (_entities.TryGetValue(entityId, out var entity)) if (_entities.TryGetValue(entityId, out var entity))
{ {
if (entity.Authority == RagonAuthority.OwnerOnly && entity.OwnerId != peerId)
return;
var player = _players[peerId]; var player = _players[peerId];
var destroyPayload = reader.ReadData(reader.Size); var payload = reader.ReadData(reader.Size);
DetachEntity(player, entity, payload);
player.DetachEntity(entity);
DetachEntity(entity);
if (_plugin.OnEntityDestroyed(player, entity))
return;
entity.Destroy(destroyPayload);
} }
break; break;
} }
} }
@@ -296,16 +274,26 @@ namespace Ragon.Core
_plugin.OnStop(); _plugin.OnStop();
_plugin.Detach(); _plugin.Detach();
_scheduler.Dispose();
} }
public void AttachEntity(Entity entity) public void AttachEntity(Player player, Entity entity)
{ {
_entities.Add(entity.EntityId, entity); _entities.Add(entity.EntityId, entity);
_entitiesAll = _entities.Values.ToArray(); _entitiesAll = _entities.Values.ToArray();
} }
public void DetachEntity(Entity entity) public void DetachEntity(Player player, Entity entity, ReadOnlySpan<byte> payload)
{ {
if (entity.Authority == RagonAuthority.OwnerOnly && entity.OwnerId != player.PeerId)
return;
if (_plugin.OnEntityDestroyed(player, entity))
return;
player.DetachEntity(entity);
entity.Destroy(payload);
_entities.Remove(entity.EntityId); _entities.Remove(entity.EntityId);
_entitiesAll = _entities.Values.ToArray(); _entitiesAll = _entities.Values.ToArray();
} }
@@ -3,7 +3,10 @@ using System.Threading.Tasks;
namespace Ragon.Core; namespace Ragon.Core;
public interface IAuthorizationProvider public interface IApplicationHandler
{ {
Task OnAuthorizationRequest(string key, string playerName, byte[] additionalData, Action<string, string> Accept, Action<uint> Reject); Task OnAuthorizationRequest(string key, string playerName, byte[] additionalData, Action<string, string> Accept, Action<uint> Reject);
public void OnCustomEvent(ushort peerId, ReadOnlySpan<byte> payload);
public void OnJoin(ushort peerId);
public void OnLeave(ushort peerId);
} }
-6
View File
@@ -1,6 +0,0 @@
namespace Ragon.Core;
public interface IAuthorizationManager
{
}
-14
View File
@@ -1,14 +0,0 @@
namespace Ragon.Core;
public interface IGameRoom
{
public string Id { get; }
public string Map { get; }
public int PlayersMin { get; }
public int PlayersMax { get; }
public int PlayersCount { get; }
public Player GetPlayerById(string id);
public Player GetPlayerByPeer(ushort peerId);
public Entity GetEntityById(int entityId);
}
+1 -1
View File
@@ -15,7 +15,7 @@ public class Lobby
public AuthorizationManager AuthorizationManager => _authorizationManager; public AuthorizationManager AuthorizationManager => _authorizationManager;
public Lobby(IAuthorizationProvider provider, RoomManager manager, Application application) public Lobby(IApplicationHandler provider, RoomManager manager, Application application)
{ {
_roomManager = manager; _roomManager = manager;
_application = application; _application = application;
+1 -3
View File
@@ -3,8 +3,6 @@ namespace Ragon.Core
public interface PluginFactory public interface PluginFactory
{ {
public PluginBase CreatePlugin(string map); public PluginBase CreatePlugin(string map);
public IAuthorizationProvider CreateAuthorizationProvider(Configuration configuration); public IApplicationHandler CreateAuthorizationProvider(Configuration configuration);
} }
} }
+1 -1
View File
@@ -14,7 +14,7 @@ namespace Ragon.Core
private Dictionary<int, Dictionary<ushort, SubscribeEntityDelegate>> _entityEvents = new(); private Dictionary<int, Dictionary<ushort, SubscribeEntityDelegate>> _entityEvents = new();
private readonly RagonSerializer _serializer = new(); private readonly RagonSerializer _serializer = new();
protected IGameRoom Room { get; private set; } = null!; protected GameRoom Room { get; private set; } = null!;
protected ILogger Logger = null!; protected ILogger Logger = null!;
public void Attach(GameRoom gameRoom) public void Attach(GameRoom gameRoom)
@@ -1,10 +1,10 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.ComponentModel;
namespace Ragon.Core namespace Ragon.Core
{ {
public class Scheduler: IScheduler public class Scheduler: IDisposable
{ {
List<SchedulerTask> _scheduledTasks; List<SchedulerTask> _scheduledTasks;
+12 -7
View File
@@ -14,12 +14,12 @@ namespace Ragon.Core
private Address _address; private Address _address;
private Event _netEvent; private Event _netEvent;
private Peer[] _peers; private Peer[] _peers;
private IHandler _handler; private IEventHandler _eventHandler;
private Stopwatch _timer; private Stopwatch _timer;
public ENetServer(IHandler handler) public ENetServer(IEventHandler eventHandler)
{ {
_handler = handler; _eventHandler = eventHandler;
_timer = Stopwatch.StartNew(); _timer = Stopwatch.StartNew();
_peers = Array.Empty<Peer>(); _peers = Array.Empty<Peer>();
_host = new Host(); _host = new Host();
@@ -115,23 +115,28 @@ namespace Ragon.Core
// break; // break;
// } // }
_peers[_netEvent.Peer.ID] = _netEvent.Peer; _peers[_netEvent.Peer.ID] = _netEvent.Peer;
_handler.OnEvent(_netEvent); _eventHandler.OnConnected((ushort)_netEvent.Peer.ID);
break; break;
} }
case EventType.Disconnect: case EventType.Disconnect:
{ {
_handler.OnEvent(_netEvent); _eventHandler.OnDisconnected((ushort)_netEvent.Peer.ID);
break; break;
} }
case EventType.Timeout: case EventType.Timeout:
{ {
_handler.OnEvent(_netEvent); _eventHandler.OnTimeout((ushort)_netEvent.Peer.ID);
break; break;
} }
case EventType.Receive: case EventType.Receive:
{ {
_handler.OnEvent(_netEvent); var peerId = (ushort) _netEvent.Peer.ID;
var dataRaw = new byte[_netEvent.Packet.Length];
_netEvent.Packet.CopyTo(dataRaw);
_netEvent.Packet.Dispose(); _netEvent.Packet.Dispose();
_eventHandler.OnData(peerId, dataRaw);
break; break;
} }
} }
@@ -0,0 +1,7 @@
namespace Ragon.Core;
public class WebSocketPacket
{
public ushort PeerId;
public byte[] Data;
}
@@ -0,0 +1,115 @@
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.WebSockets;
using System.Threading;
using System.Threading.Tasks;
using NLog;
using Ragon.Common;
namespace Ragon.Core;
public class WebSocketServer : ISocketServer
{
private ushort _idSequencer = 0;
private ILogger _logger = LogManager.GetCurrentClassLogger();
private Dictionary<ushort, WebSocket> _webSockets = new Dictionary<ushort, WebSocket>();
private Queue<WebSocketPacket> _events;
private IEventHandler _eventHandler;
private WebSocketTaskScheduler _webSocketScheduler;
private TaskFactory _taskFactory;
private HttpListener _httpListener;
public WebSocketServer(IEventHandler eventHandler)
{
_eventHandler = eventHandler;
_events = new Queue<WebSocketPacket>(1024);
_webSocketScheduler = new WebSocketTaskScheduler();
_taskFactory = new TaskFactory(_webSocketScheduler);
}
async void StartAccept()
{
while (true)
{
var context = await _httpListener.GetContextAsync();
if (!context.Request.IsWebSocketRequest) continue;
var webSocketContext = await context.AcceptWebSocketAsync(null);
var webSocket = webSocketContext.WebSocket;
_idSequencer++;
_webSockets.Add(_idSequencer, webSocket);
_ = _taskFactory.StartNew(() => StartListen(webSocket, _idSequencer));
}
}
async void StartListen(WebSocket webSocket, ushort peerId)
{
_eventHandler.OnConnected(peerId);
var bytes = new byte[2048];
var buffer = new Memory<byte>(bytes);
while (webSocket.State == WebSocketState.Open)
{
var result = await webSocket.ReceiveAsync(buffer, CancellationToken.None);
var dataRaw = buffer.Slice(0, result.Count);
_eventHandler.OnData(peerId, dataRaw.ToArray());
}
_eventHandler.OnDisconnected(peerId);
}
async void ProcessQueue()
{
while (_events.TryDequeue(out var evnt))
{
if (_webSockets.TryGetValue(evnt.PeerId, out var ws) && ws.State == WebSocketState.Open)
{
await ws.SendAsync(evnt.Data, WebSocketMessageType.Binary, WebSocketMessageFlags.EndOfMessage, CancellationToken.None);
}
}
}
public void Start(ushort port, int connections, uint protocol)
{
_httpListener = new HttpListener();
_httpListener.Prefixes.Add($"http://*:{port}/");
_httpListener.Start();
_taskFactory.StartNew(StartAccept);
var protocolDecoded = (protocol >> 16 & 0xFF) + "." + (protocol >> 8 & 0xFF) + "." + (protocol & 0xFF);
_logger.Info($"Network listening on http://*:{port}/");
_logger.Info($"Protocol: {protocolDecoded}");
}
public void Process()
{
_webSocketScheduler.Process();
ProcessQueue();
}
public void Stop()
{
_httpListener.Stop();
}
public void Send(ushort peerId, byte[] data, DeliveryType type)
{
_events.Enqueue(new WebSocketPacket() {PeerId = peerId, Data = data});
}
public void Broadcast(ushort[] peersIds, byte[] data, DeliveryType type)
{
foreach (var peerId in peersIds)
_events.Enqueue(new WebSocketPacket() {PeerId = peerId, Data = data});
}
public void Disconnect(ushort peerId, uint errorCode)
{
_webSockets[peerId].CloseAsync(WebSocketCloseStatus.NormalClosure, null, CancellationToken.None);
}
}
@@ -0,0 +1,46 @@
using System;
using System.Collections.Generic;
using System.Threading.Channels;
using System.Threading.Tasks;
namespace Ragon.Core;
public class WebSocketTaskScheduler: TaskScheduler
{
private ChannelReader<Task> _reader;
private ChannelWriter<Task> _writer;
private Channel<Task> _channel;
public WebSocketTaskScheduler()
{
_channel = Channel.CreateUnbounded<Task>();
_reader = _channel.Reader;
_writer = _channel.Writer;
}
protected override IEnumerable<Task>? GetScheduledTasks()
{
throw new NotSupportedException();
}
protected override void QueueTask(Task task)
{
_writer.TryWrite(task);
}
protected override bool TryExecuteTaskInline(Task task, bool taskWasPreviouslyQueued)
{
return false;
}
public void Process()
{
while (_reader.TryRead(out var task))
{
TryExecuteTask(task);
if (task.Status != TaskStatus.RanToCompletion)
_writer.TryWrite(task);
}
}
}
+11
View File
@@ -0,0 +1,11 @@
using ENet;
namespace Ragon.Core;
public interface IEventHandler
{
public void OnConnected(ushort peerId);
public void OnDisconnected(ushort peerId);
public void OnTimeout(ushort peerId);
public void OnData(ushort peerId, byte[] data);
}
-8
View File
@@ -1,8 +0,0 @@
using ENet;
namespace Ragon.Core;
public interface IHandler
{
public void OnEvent(Event evnt);
}
-8
View File
@@ -1,8 +0,0 @@
using System;
namespace Ragon.Core;
public interface IDispatcher
{
public void Dispatch(Action action);
}
@@ -1,6 +0,0 @@
namespace Ragon.Core;
public interface IDispatcherInternal
{
public void Process();
}
-12
View File
@@ -1,12 +0,0 @@
using System;
namespace Ragon.Core;
public interface IScheduler
{
public SchedulerTask Schedule(Action<SchedulerTask> action, float interval, int count = 1);
public SchedulerTask ScheduleForever(Action<SchedulerTask> action, float interval);
public void StopSchedule(SchedulerTask schedulerTask);
public void Tick(float deltaTime);
}