http-commands

This commit is contained in:
2023-04-13 20:42:05 +04:00
parent 24c9aa2043
commit e1a9ad476c
31 changed files with 428 additions and 104 deletions
@@ -0,0 +1,6 @@
namespace Ragon.Relay;
public class KickPlayerCommand
{
public string Id;
}
+1 -1
View File
@@ -6,7 +6,7 @@ using Ragon.Server.Room;
namespace Ragon.Relay; namespace Ragon.Relay;
public class RelayRoomPlugin: IRoomPlugin public class RelayRoomPlugin: BaseRoomPlugin
{ {
public void Tick(float dt) public void Tick(float dt)
{ {
+13 -30
View File
@@ -1,41 +1,24 @@
using System.Net.Http; using System;
using Ragon.Server; using Newtonsoft.Json;
using Ragon.Server.Lobby;
using Ragon.Server.Plugin; using Ragon.Server.Plugin;
using Ragon.Server.Room;
namespace Ragon.Relay; namespace Ragon.Relay;
public class RelayServerPlugin: IServerPlugin public class RelayServerPlugin: BaseServerPlugin
{ {
private HttpClient httpClient; public override bool OnCommand(string command, string payload)
public IRoomPlugin CreateRoomPlugin(RoomInformation information)
{ {
return new RelayRoomPlugin(); Console.WriteLine(command);
if (command == "kick-player")
{
var commandPayload = JsonConvert.DeserializeObject<KickPlayerCommand>(payload);
var player = GetPlayerById(commandPayload.Id);
if (player != null)
player.Connection.Close();
else
Console.WriteLine($"Player not found with Id {commandPayload.Id}");
} }
public RelayServerPlugin()
{
httpClient = new HttpClient();
}
public bool OnRoomCreate(RagonLobbyPlayer player, RagonRoom room)
{
return true;
}
public bool OnRoomRemove(RagonLobbyPlayer player, RagonRoom room)
{
return true;
}
public bool OnRoomLeave(RagonRoomPlayer player, RagonRoom room)
{
return true;
}
public bool OnRoomJoin(RagonRoomPlayer player, RagonRoom room)
{
return true; return true;
} }
} }
+2
View File
@@ -4,6 +4,8 @@
"serverTickRate": 30, "serverTickRate": 30,
"gameProtocol": "1.0.0", "gameProtocol": "1.0.0",
"port": 5000, "port": 5000,
"httpPort": 5001,
"httpKey": "defaultkey",
"limitConnections": 4095, "limitConnections": 4095,
"limitPlayersPerRoom": 20, "limitPlayersPerRoom": 20,
"limitRooms": 200, "limitRooms": 200,
@@ -26,17 +26,19 @@ namespace Ragon.Server.Handler;
public sealed class AuthorizationOperation: IRagonOperation public sealed class AuthorizationOperation: IRagonOperation
{ {
private Logger _logger = LogManager.GetCurrentClassLogger(); private Logger _logger = LogManager.GetCurrentClassLogger();
private readonly WebHookPlugin _webHook; private readonly RagonWebHookPlugin _ragonWebHook;
private readonly RagonContextObserver _contextObserver;
private readonly Configuration _configuration; private readonly Configuration _configuration;
private readonly RagonBuffer _writer; private readonly RagonBuffer _writer;
public AuthorizationOperation( public AuthorizationOperation(RagonWebHookPlugin ragonWebHook,
WebHookPlugin webHook, RagonContextObserver contextObserver,
RagonBuffer writer, RagonBuffer writer,
Configuration configuration) Configuration configuration)
{ {
_webHook = webHook; _ragonWebHook = ragonWebHook;
_configuration = configuration; _configuration = configuration;
_contextObserver = contextObserver;
_writer = writer; _writer = writer;
} }
@@ -60,10 +62,10 @@ public sealed class AuthorizationOperation: IRagonOperation
if (key == _configuration.ServerKey) if (key == _configuration.ServerKey)
{ {
if (_webHook.RequestAuthorization(context, name, payload)) if (_ragonWebHook.RequestAuthorization(context, name, payload))
return; return;
var lobbyPlayer = new RagonLobbyPlayer(Guid.NewGuid().ToString(), name, payload); var lobbyPlayer = new RagonLobbyPlayer(context.Connection, Guid.NewGuid().ToString(), name, payload);
context.SetPlayer(lobbyPlayer); context.SetPlayer(lobbyPlayer);
Approve(context); Approve(context);
@@ -78,6 +80,8 @@ public sealed class AuthorizationOperation: IRagonOperation
{ {
context.ConnectionStatus = ConnectionStatus.Authorized; context.ConnectionStatus = ConnectionStatus.Authorized;
_contextObserver.OnAuthorized(context);
var playerId = context.LobbyPlayer.Id; var playerId = context.LobbyPlayer.Id;
var playerName = context.LobbyPlayer.Name; var playerName = context.LobbyPlayer.Name;
var playerPayload = context.LobbyPlayer.Payload; var playerPayload = context.LobbyPlayer.Payload;
@@ -28,12 +28,12 @@ public sealed class RoomCreateOperation: IRagonOperation
private readonly RagonRoomParameters _roomParameters = new(); private readonly RagonRoomParameters _roomParameters = new();
private readonly Logger _logger = LogManager.GetCurrentClassLogger(); private readonly Logger _logger = LogManager.GetCurrentClassLogger();
private readonly IServerPlugin _serverPlugin; private readonly IServerPlugin _serverPlugin;
private readonly WebHookPlugin _webHookPlugin; private readonly RagonWebHookPlugin _ragonWebHookPlugin;
public RoomCreateOperation(IServerPlugin serverPlugin, WebHookPlugin webHook) public RoomCreateOperation(IServerPlugin serverPlugin, RagonWebHookPlugin ragonWebHook)
{ {
_serverPlugin = serverPlugin; _serverPlugin = serverPlugin;
_webHookPlugin = webHook; _ragonWebHookPlugin = ragonWebHook;
} }
public void Handle(RagonContext context, RagonBuffer reader, RagonBuffer writer) public void Handle(RagonContext context, RagonBuffer reader, RagonBuffer writer)
@@ -79,11 +79,13 @@ public sealed class RoomCreateOperation: IRagonOperation
var roomPlugin = _serverPlugin.CreateRoomPlugin(information); var roomPlugin = _serverPlugin.CreateRoomPlugin(information);
var room = new RagonRoom(roomId, information, roomPlugin); var room = new RagonRoom(roomId, information, roomPlugin);
roomPlayer.OnAttached(room);
context.Scheduler.Run(room); context.Scheduler.Run(room);
context.Lobby.Persist(room); context.Lobby.Persist(room);
context.SetRoom(room, roomPlayer); context.SetRoom(room, roomPlayer);
_webHookPlugin.RoomCreated(context, room); _ragonWebHookPlugin.RoomCreated(context, room, roomPlayer);
_logger.Trace($"Player {context.Connection.Id}|{context.LobbyPlayer.Name} create room {room.Id} with map {information.Map}"); _logger.Trace($"Player {context.Connection.Id}|{context.LobbyPlayer.Name} create room {room.Id} with map {information.Map}");
@@ -26,12 +26,12 @@ public sealed class RoomJoinOperation : IRagonOperation
{ {
private readonly Logger _logger = LogManager.GetCurrentClassLogger(); private readonly Logger _logger = LogManager.GetCurrentClassLogger();
private readonly IServerPlugin _serverPlugin; private readonly IServerPlugin _serverPlugin;
private readonly WebHookPlugin _webHookPlugin; private readonly RagonWebHookPlugin _ragonWebHookPlugin;
public RoomJoinOperation(IServerPlugin serverPlugin, WebHookPlugin plugin) public RoomJoinOperation(IServerPlugin serverPlugin, RagonWebHookPlugin plugin)
{ {
_serverPlugin = serverPlugin; _serverPlugin = serverPlugin;
_webHookPlugin = plugin; _ragonWebHookPlugin = plugin;
} }
public void Handle(RagonContext context, RagonBuffer reader, RagonBuffer writer) public void Handle(RagonContext context, RagonBuffer reader, RagonBuffer writer)
@@ -53,7 +53,7 @@ public sealed class RoomJoinOperation : IRagonOperation
if (!_serverPlugin.OnRoomJoin(player, existsRoom)) if (!_serverPlugin.OnRoomJoin(player, existsRoom))
return; return;
_webHookPlugin.RoomJoined(context, existsRoom, player); _ragonWebHookPlugin.RoomJoined(context, existsRoom, player);
JoinSuccess(context, existsRoom, writer); JoinSuccess(context, existsRoom, writer);
@@ -28,12 +28,12 @@ public sealed class RoomJoinOrCreateOperation : IRagonOperation
private readonly RagonRoomParameters _roomParameters = new(); private readonly RagonRoomParameters _roomParameters = new();
private readonly Logger _logger = LogManager.GetCurrentClassLogger(); private readonly Logger _logger = LogManager.GetCurrentClassLogger();
private readonly IServerPlugin _serverPlugin; private readonly IServerPlugin _serverPlugin;
private readonly WebHookPlugin _webHookPlugin; private readonly RagonWebHookPlugin _ragonWebHookPlugin;
public RoomJoinOrCreateOperation(IServerPlugin serverPlugin, WebHookPlugin plugin) public RoomJoinOrCreateOperation(IServerPlugin serverPlugin, RagonWebHookPlugin plugin)
{ {
_serverPlugin = serverPlugin; _serverPlugin = serverPlugin;
_webHookPlugin = plugin; _ragonWebHookPlugin = plugin;
} }
public void Handle(RagonContext context, RagonBuffer reader, RagonBuffer writer) public void Handle(RagonContext context, RagonBuffer reader, RagonBuffer writer)
@@ -54,7 +54,7 @@ public sealed class RoomJoinOrCreateOperation : IRagonOperation
var player = new RagonRoomPlayer(context.Connection, lobbyPlayer.Id, lobbyPlayer.Name); var player = new RagonRoomPlayer(context.Connection, lobbyPlayer.Id, lobbyPlayer.Name);
context.SetRoom(existsRoom, player); context.SetRoom(existsRoom, player);
_webHookPlugin.RoomJoined(context, existsRoom, player); _ragonWebHookPlugin.RoomJoined(context, existsRoom, player);
JoinSuccess(player, existsRoom, writer); JoinSuccess(player, existsRoom, writer);
} }
@@ -71,7 +71,7 @@ public sealed class RoomJoinOrCreateOperation : IRagonOperation
var roomPlugin = _serverPlugin.CreateRoomPlugin(information); var roomPlugin = _serverPlugin.CreateRoomPlugin(information);
var room = new RagonRoom(roomId, information, roomPlugin); var room = new RagonRoom(roomId, information, roomPlugin);
_webHookPlugin.RoomCreated(context, room); _ragonWebHookPlugin.RoomCreated(context, room, roomPlayer);
context.Lobby.Persist(room); context.Lobby.Persist(room);
context.Scheduler.Run(room); context.Scheduler.Run(room);
@@ -25,11 +25,11 @@ public sealed class RoomLeaveOperation: IRagonOperation
{ {
private readonly Logger _logger = LogManager.GetCurrentClassLogger(); private readonly Logger _logger = LogManager.GetCurrentClassLogger();
private readonly IServerPlugin _serverPlugin; private readonly IServerPlugin _serverPlugin;
private readonly WebHookPlugin _webHookPlugin; private readonly RagonWebHookPlugin _ragonWebHookPlugin;
public RoomLeaveOperation(IServerPlugin serverPlugin, WebHookPlugin plugin) public RoomLeaveOperation(IServerPlugin serverPlugin, RagonWebHookPlugin plugin)
{ {
_serverPlugin = serverPlugin; _serverPlugin = serverPlugin;
_webHookPlugin = plugin; _ragonWebHookPlugin = plugin;
} }
public void Handle(RagonContext context, RagonBuffer reader, RagonBuffer writer) public void Handle(RagonContext context, RagonBuffer reader, RagonBuffer writer)
@@ -40,7 +40,7 @@ public sealed class RoomLeaveOperation: IRagonOperation
if (room != null) if (room != null)
{ {
_serverPlugin.OnRoomLeave(roomPlayer, room); _serverPlugin.OnRoomLeave(roomPlayer, room);
_webHookPlugin.RoomLeaved(context, room, roomPlayer); _ragonWebHookPlugin.RoomLeaved(context, room, roomPlayer);
context.Room?.DetachPlayer(roomPlayer); context.Room?.DetachPlayer(roomPlayer);
_logger.Trace($"Player {context.Connection.Id}|{context.LobbyPlayer.Name} leaved from {room.Id}"); _logger.Trace($"Player {context.Connection.Id}|{context.LobbyPlayer.Name} leaved from {room.Id}");
} }
@@ -0,0 +1,97 @@
using NLog;
using System.Net;
using System.Text.Json;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Ragon.Server.IO;
using Ragon.Server.Plugin;
namespace Ragon.Server.Http;
public class RagonHttpServer
{
private readonly ILogger _logger = LogManager.GetCurrentClassLogger();
private readonly IExecutor _executor;
private readonly IServerPlugin _serverPlugin;
private HttpListener _httpListener;
private CancellationTokenSource _cancellationTokenSource;
public RagonHttpServer(IExecutor executor, IServerPlugin serverPlugin)
{
_serverPlugin = serverPlugin;
_executor = executor;
}
public async void StartAccept(CancellationToken cancellationToken)
{
while (!cancellationToken.IsCancellationRequested)
{
var context = await _httpListener.GetContextAsync();
if (context.Request.HttpMethod != "POST")
{
context.Response.StatusCode = 404;
context.Response.ContentLength64 = 0;
context.Response.Close();
}
var request = context.Request;
var reader = new StreamReader(request.InputStream, request.ContentEncoding);
var rawJson = await reader.ReadToEndAsync();
var httpCommand = JsonDocument.Parse(rawJson);
if (httpCommand != null)
{
try
{
var command = httpCommand.RootElement.GetProperty("command");
var payload = httpCommand.RootElement.GetProperty("payload");
if (_serverPlugin.OnCommand(command.GetString() ?? "none", payload.GetRawText()))
{
context.Response.StatusCode = 200;
context.Response.ContentLength64 = 0;
context.Response.Close();
}
else
{
context.Response.StatusCode = 403;
context.Response.ContentLength64 = 0;
context.Response.Close();
}
}
catch (Exception ex)
{
_logger.Error(ex);
context.Response.StatusCode = 505;
context.Response.ContentLength64 = 0;
context.Response.Close();
}
continue;
}
context.Response.StatusCode = 403;
context.Response.ContentLength64 = 0;
context.Response.Close();
}
}
public void Start(Configuration configuration)
{
_cancellationTokenSource = new CancellationTokenSource();
_logger.Info($"Listen at http://0.0.0.0:{configuration.HttpPort}/");
_httpListener = new HttpListener();
_httpListener.Prefixes.Add($"http://127.0.0.1:{configuration.HttpPort}/");
_httpListener.Start();
_executor.Run(() => StartAccept(_cancellationTokenSource.Token), TaskCreationOptions.LongRunning);
}
public void Stop()
{
_cancellationTokenSource.Cancel();
_httpListener.Stop();
}
}
+12 -7
View File
@@ -20,19 +20,24 @@ namespace Ragon.Server.IO;
public class Executor : TaskScheduler, IExecutor public class Executor : TaskScheduler, IExecutor
{ {
private ChannelReader<Task> _reader; private readonly ChannelReader<Task> _reader;
private ChannelWriter<Task> _writer; private readonly ChannelWriter<Task> _writer;
private Queue<Task> _pendingTasks; private readonly Queue<Task> _pendingTasks;
private TaskFactory _taskFactory; private readonly TaskFactory _taskFactory;
public Task Run(Action action) public Task Run(Action action, TaskCreationOptions task = TaskCreationOptions.None)
{ {
return _taskFactory.StartNew(action); return _taskFactory.StartNew(action, task);
} }
public Executor() public Executor()
{ {
var channel = Channel.CreateUnbounded<Task>(); var channel = Channel.CreateUnbounded<Task>(new UnboundedChannelOptions()
{
SingleReader = true,
SingleWriter = true,
});
_reader = channel.Reader; _reader = channel.Reader;
_writer = channel.Writer; _writer = channel.Writer;
+1 -1
View File
@@ -18,5 +18,5 @@ namespace Ragon.Server.IO;
public interface IExecutor public interface IExecutor
{ {
public Task Run(Action action); public Task Run(Action action, TaskCreationOptions task = TaskCreationOptions.None);
} }
@@ -0,0 +1,15 @@
namespace Ragon.Server;
public class RagonContextObserver
{
private Dictionary<string, RagonContext> _contexts;
public RagonContextObserver(Dictionary<string, RagonContext> contexts)
{
_contexts = contexts;
}
public void OnAuthorized(RagonContext context)
{
_contexts.Add(context.LobbyPlayer.Id, context);
}
}
+9
View File
@@ -0,0 +1,9 @@
using Ragon.Server.IO;
namespace Ragon.Server;
public interface IRagonServer
{
RagonContext? ResolveContext(INetworkConnection connection);
RagonContext? ResolveContext(string id);
}
@@ -14,6 +14,8 @@
* limitations under the License. * limitations under the License.
*/ */
using Ragon.Server.IO;
namespace Ragon.Server.Lobby; namespace Ragon.Server.Lobby;
public enum ConnectionStatus public enum ConnectionStatus
@@ -25,14 +27,16 @@ public enum ConnectionStatus
public class RagonLobbyPlayer public class RagonLobbyPlayer
{ {
public INetworkConnection Connection { get; }
public string Id { get; private set; } public string Id { get; private set; }
public string Name { get; private set; } public string Name { get; private set; }
public string Payload { get; private set; } public string Payload { get; private set; }
public RagonLobbyPlayer(string id, string name, string payload) public RagonLobbyPlayer(INetworkConnection connection, string id, string name, string payload)
{ {
Id = id; Id = id;
Name = name; Name = name;
Payload = payload; Payload = payload;
Connection = connection;
} }
} }
@@ -0,0 +1,53 @@
using Ragon.Server.Entity;
using Ragon.Server.IO;
using Ragon.Server.Lobby;
using Ragon.Server.Room;
using Ragon.Server.Time;
namespace Ragon.Server.Plugin;
public class BaseRoomPlugin: IRoomPlugin
{
private IRagonRoom _ragonRoom;
public RagonRoomPlayer GetPlayerById(string id)
{
var player = _ragonRoom.GetPlayerById(id);
return player;
}
public RagonRoomPlayer GetPlayerByConnection(INetworkConnection connection)
{
var player = _ragonRoom.GetPlayerByConnection(connection);
return player;
}
public virtual void OnAttached(IRagonRoom room)
{
_ragonRoom = room;
}
public virtual void OnDetached()
{
}
#region VIRTUAL
public virtual void Tick(float dt)
{
}
public virtual bool OnEntityCreate(RagonRoomPlayer creator, RagonEntity entity)
{
return true;
}
public virtual bool OnEntityRemove(RagonRoomPlayer remover, RagonEntity entity)
{
return true;
}
#endregion
}
@@ -0,0 +1,62 @@
using Ragon.Server.IO;
using Ragon.Server.Lobby;
using Ragon.Server.Room;
namespace Ragon.Server.Plugin;
public class BaseServerPlugin: IServerPlugin
{
private IRagonServer _ragonServer;
public RagonLobbyPlayer? GetPlayerById(string id)
{
var context = _ragonServer.ResolveContext(id);
return context?.LobbyPlayer;
}
public RagonLobbyPlayer? GetPlayerByConnection(INetworkConnection connection)
{
var context = _ragonServer.ResolveContext(connection);
return context?.LobbyPlayer;
}
public void OnAttached(IRagonServer server)
{
_ragonServer = server;
}
public void OnDetached()
{
}
public virtual bool OnRoomCreate(RagonLobbyPlayer player, RagonRoom room)
{
return true;
}
public virtual bool OnRoomRemove(RagonLobbyPlayer player, RagonRoom room)
{
return true;
}
public virtual bool OnRoomLeave(RagonRoomPlayer player, RagonRoom room)
{
return true;
}
public virtual bool OnRoomJoin(RagonRoomPlayer player, RagonRoom room)
{
return true;
}
public virtual bool OnCommand(string command, string payload)
{
return true;
}
public IRoomPlugin CreateRoomPlugin(RoomInformation information)
{
return new BaseRoomPlugin();
}
}
+1 -1
View File
@@ -22,7 +22,7 @@ namespace Ragon.Server.Plugin;
public interface IRoomPlugin public interface IRoomPlugin
{ {
void Tick(float dt); void Tick(float dt);
void OnAttached(); void OnAttached(IRagonRoom room);
void OnDetached(); void OnDetached();
bool OnEntityCreate(RagonRoomPlayer creator, RagonEntity entity); bool OnEntityCreate(RagonRoomPlayer creator, RagonEntity entity);
bool OnEntityRemove(RagonRoomPlayer remover, RagonEntity entity); bool OnEntityRemove(RagonRoomPlayer remover, RagonEntity entity);
+4 -1
View File
@@ -14,6 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
using Ragon.Server.Http;
using Ragon.Server.Lobby; using Ragon.Server.Lobby;
using Ragon.Server.Room; using Ragon.Server.Room;
@@ -21,10 +22,12 @@ namespace Ragon.Server.Plugin;
public interface IServerPlugin public interface IServerPlugin
{ {
void OnAttached(IRagonServer server);
void OnDetached();
bool OnRoomCreate(RagonLobbyPlayer player, RagonRoom room); bool OnRoomCreate(RagonLobbyPlayer player, RagonRoom room);
bool OnRoomRemove(RagonLobbyPlayer player, RagonRoom room); bool OnRoomRemove(RagonLobbyPlayer player, RagonRoom room);
bool OnRoomLeave(RagonRoomPlayer player, RagonRoom room); bool OnRoomLeave(RagonRoomPlayer player, RagonRoom room);
bool OnRoomJoin(RagonRoomPlayer player, RagonRoom room); bool OnRoomJoin(RagonRoomPlayer player, RagonRoom room);
bool OnCommand(string command, string payload);
IRoomPlugin CreateRoomPlugin(RoomInformation information); IRoomPlugin CreateRoomPlugin(RoomInformation information);
} }
@@ -0,0 +1,16 @@
using Ragon.Server.Room;
namespace Ragon.Server.Plugin.Web;
[Serializable]
public class PlayerDto
{
public string Id { get; set;}
public string Name { get; set; }
public PlayerDto(RagonRoomPlayer ragonRoomPlayer)
{
Id = ragonRoomPlayer.Id;
Name = ragonRoomPlayer.Name;
}
}
@@ -0,0 +1,23 @@
using Ragon.Server.Room;
namespace Ragon.Server.Plugin.Web;
[Serializable]
public class RoomDto
{
public string Id { get; set;}
public int PlayerMin { get; set; }
public int PlayerMax { get; set; }
public int PlayerCount { get; set; }
public PlayerDto[] Players { get; set; }
public RoomDto(RagonRoom room)
{
Id = room.Id;
PlayerMin = room.PlayerMin;
PlayerMax = room.PlayerMax;
PlayerCount = room.PlayerCount;
Players = room.PlayerList.Select(p => new PlayerDto(p)).ToArray();
}
}
@@ -8,14 +8,14 @@ using Ragon.Server.Room;
namespace Ragon.Server.Plugin.Web; namespace Ragon.Server.Plugin.Web;
public class WebHookPlugin public class RagonWebHookPlugin
{ {
private Dictionary<string, string> _webHooks; private Dictionary<string, string> _webHooks;
private RagonServer _server; private RagonServer _server;
private HttpClient _httpClient; private HttpClient _httpClient;
public WebHookPlugin(RagonServer server, Configuration configuration) public RagonWebHookPlugin(RagonServer server, Configuration configuration)
{ {
_webHooks = new Dictionary<string, string>(configuration.WebHooks); _webHooks = new Dictionary<string, string>(configuration.WebHooks);
_httpClient = new HttpClient(); _httpClient = new HttpClient();
@@ -30,7 +30,7 @@ public class WebHookPlugin
var executor = context.Executor; var executor = context.Executor;
executor.Run(async () => executor.Run(async () =>
{ {
var authorizationOperation = (AuthorizationOperation) _server.Resolve(RagonOperation.AUTHORIZE); var authorizationOperation = (AuthorizationOperation) _server.ResolveOperation(RagonOperation.AUTHORIZE);
var response = await _httpClient.PostAsync(new Uri(value), httpContent); var response = await _httpClient.PostAsync(new Uri(value), httpContent);
if (response.StatusCode != HttpStatusCode.OK) if (response.StatusCode != HttpStatusCode.OK)
{ {
@@ -42,7 +42,7 @@ public class WebHookPlugin
var authorizationResponse = JsonConvert.DeserializeObject<AuthorizationResponse>(content); var authorizationResponse = JsonConvert.DeserializeObject<AuthorizationResponse>(content);
if (authorizationResponse != null) if (authorizationResponse != null)
{ {
var lobbyPlayer = new RagonLobbyPlayer(authorizationResponse.Id, authorizationResponse.Name, authorizationResponse.Payload); var lobbyPlayer = new RagonLobbyPlayer(context.Connection, authorizationResponse.Id, authorizationResponse.Name, authorizationResponse.Payload);
context.SetPlayer(lobbyPlayer); context.SetPlayer(lobbyPlayer);
authorizationOperation.Approve(context); authorizationOperation.Approve(context);
@@ -58,12 +58,14 @@ public class WebHookPlugin
return false; return false;
} }
public void RoomCreated(RagonContext context, RagonRoom room) public void RoomCreated(RagonContext context, RagonRoom room, RagonRoomPlayer player)
{ {
if (_webHooks.TryGetValue("room-created", out var value) && !string.IsNullOrEmpty(value)) if (_webHooks.TryGetValue("room-created", out var value) && !string.IsNullOrEmpty(value))
{ {
var request = new RoomCreatedRequest() var request = new RoomCreatedRequest()
{ {
Room = new RoomDto(room),
Player = new PlayerDto(player)
}; };
var content = JsonContent.Create(request); var content = JsonContent.Create(request);
var executor = context.Executor; var executor = context.Executor;
@@ -75,8 +77,9 @@ public class WebHookPlugin
{ {
if (_webHooks.TryGetValue("room-removed", out var value) && !string.IsNullOrEmpty(value)) if (_webHooks.TryGetValue("room-removed", out var value) && !string.IsNullOrEmpty(value))
{ {
var request = new RoomCreatedRequest() var request = new RoomRemovedRequest()
{ {
Room = new RoomDto(ragonRoom)
}; };
var content = JsonContent.Create(request); var content = JsonContent.Create(request);
var executor = context.Executor; var executor = context.Executor;
@@ -88,8 +91,10 @@ public class WebHookPlugin
{ {
if (_webHooks.TryGetValue("room-joined", out var value) && !string.IsNullOrEmpty(value)) if (_webHooks.TryGetValue("room-joined", out var value) && !string.IsNullOrEmpty(value))
{ {
var request = new RoomCreatedRequest() var request = new RoomJoinedRequest()
{ {
Room = new RoomDto(existsRoom),
Player = new PlayerDto(player)
}; };
var content = JsonContent.Create(request); var content = JsonContent.Create(request);
var executor = context.Executor; var executor = context.Executor;
@@ -101,8 +106,10 @@ public class WebHookPlugin
{ {
if (_webHooks.TryGetValue("room-leaved", out var value) && !string.IsNullOrEmpty(value)) if (_webHooks.TryGetValue("room-leaved", out var value) && !string.IsNullOrEmpty(value))
{ {
var request = new RoomCreatedRequest() var request = new RoomLeavedRequest()
{ {
Room = new RoomDto(room),
Player = new PlayerDto(roomPlayer)
}; };
var content = JsonContent.Create(request); var content = JsonContent.Create(request);
var executor = context.Executor; var executor = context.Executor;
@@ -1,7 +1,9 @@
namespace Ragon.Server.Plugin.Web; namespace Ragon.Server.Plugin.Web;
[Serializable] [Serializable]
public class RoomCreatedRequest public class RoomCreatedRequest
{ {
public RoomDto Room { get; set; }
public PlayerDto Player { get; set; }
} }
@@ -2,5 +2,6 @@ namespace Ragon.Server.Plugin.Web;
public class RoomJoinedRequest public class RoomJoinedRequest
{ {
public RoomDto Room { get; set; }
public PlayerDto Player { get; set; }
} }
@@ -3,5 +3,6 @@ namespace Ragon.Server.Plugin.Web;
[Serializable] [Serializable]
public class RoomLeavedRequest public class RoomLeavedRequest
{ {
public RoomDto Room { get; set; }
public PlayerDto Player { get; set; }
} }
@@ -1,7 +1,9 @@
using Ragon.Server.Plugin.Web;
namespace Ragon.Server.Plugin.Web; namespace Ragon.Server.Plugin.Web;
[Serializable] [Serializable]
public class RoomRemovedRequest public class RoomRemovedRequest
{ {
public RoomDto Room { get; set; }
} }
+1 -2
View File
@@ -23,9 +23,8 @@ namespace Ragon.Server;
public class RagonContext public class RagonContext
{ {
public INetworkConnection Connection { get; }
public ConnectionStatus ConnectionStatus { get; set; } public ConnectionStatus ConnectionStatus { get; set; }
public INetworkConnection Connection { get; }
public IExecutor Executor { get; private set; } public IExecutor Executor { get; private set; }
public IRagonLobby Lobby { get; private set; } public IRagonLobby Lobby { get; private set; }
+29 -16
View File
@@ -18,6 +18,7 @@ using System.Diagnostics;
using NLog; using NLog;
using Ragon.Protocol; using Ragon.Protocol;
using Ragon.Server.Handler; using Ragon.Server.Handler;
using Ragon.Server.Http;
using Ragon.Server.IO; using Ragon.Server.IO;
using Ragon.Server.Lobby; using Ragon.Server.Lobby;
using Ragon.Server.Plugin; using Ragon.Server.Plugin;
@@ -26,20 +27,23 @@ using Ragon.Server.Time;
namespace Ragon.Server; namespace Ragon.Server;
public class RagonServer : INetworkListener public class RagonServer : IRagonServer, INetworkListener
{ {
private readonly Logger _logger = LogManager.GetCurrentClassLogger(); private readonly Logger _logger = LogManager.GetCurrentClassLogger();
private readonly INetworkServer _server; private readonly INetworkServer _server;
private readonly IRagonOperation[] _handlers;
private readonly IRagonLobby _lobby;
private readonly IServerPlugin _serverPlugin;
private readonly Thread _dedicatedThread; private readonly Thread _dedicatedThread;
private readonly Executor _executor; private readonly Executor _executor;
private readonly WebHookPlugin _webhooks;
private readonly Configuration _configuration; private readonly Configuration _configuration;
private readonly IRagonOperation[] _handlers; private readonly RagonWebHookPlugin _webhooks;
private readonly RagonHttpServer _httpServer;
private readonly RagonBuffer _reader; private readonly RagonBuffer _reader;
private readonly RagonBuffer _writer; private readonly RagonBuffer _writer;
private readonly IRagonLobby _lobby;
private readonly RagonScheduler _scheduler; private readonly RagonScheduler _scheduler;
private readonly Dictionary<ushort, RagonContext> _contexts; private readonly Dictionary<ushort, RagonContext> _contextsByConnection;
private readonly Dictionary<string, RagonContext> _contextsByPlayerId;
private readonly Stopwatch _timer; private readonly Stopwatch _timer;
private readonly long _tickRate = 0; private readonly long _tickRate = 0;
@@ -51,20 +55,26 @@ public class RagonServer : INetworkListener
_server = server; _server = server;
_executor = _server.Executor; _executor = _server.Executor;
_configuration = configuration; _configuration = configuration;
_contexts = new Dictionary<ushort, RagonContext>(); _serverPlugin = plugin;
_contextsByConnection = new Dictionary<ushort, RagonContext>();
_contextsByPlayerId = new Dictionary<string, RagonContext>();
_lobby = new LobbyInMemory(); _lobby = new LobbyInMemory();
_scheduler = new RagonScheduler(); _scheduler = new RagonScheduler();
_webhooks = new WebHookPlugin(this, configuration); _webhooks = new RagonWebHookPlugin(this, configuration);
_dedicatedThread = new Thread(Execute); _dedicatedThread = new Thread(Execute);
_dedicatedThread.IsBackground = true; _dedicatedThread.IsBackground = true;
_httpServer = new RagonHttpServer(_executor, plugin);
_reader = new RagonBuffer(); _reader = new RagonBuffer();
_writer = new RagonBuffer(); _writer = new RagonBuffer();
_tickRate = 1000 / _configuration.ServerTickRate; _tickRate = 1000 / _configuration.ServerTickRate;
_timer = new Stopwatch(); _timer = new Stopwatch();
var contextObserver = new RagonContextObserver(_contextsByPlayerId);
_serverPlugin.OnAttached(this);
_handlers = new IRagonOperation[byte.MaxValue]; _handlers = new IRagonOperation[byte.MaxValue];
_handlers[(byte) RagonOperation.AUTHORIZE] = new AuthorizationOperation(_webhooks, _writer, configuration); _handlers[(byte) RagonOperation.AUTHORIZE] = new AuthorizationOperation(_webhooks, contextObserver, _writer, configuration);
_handlers[(byte) RagonOperation.JOIN_OR_CREATE_ROOM] = new RoomJoinOrCreateOperation(plugin, _webhooks); _handlers[(byte) RagonOperation.JOIN_OR_CREATE_ROOM] = new RoomJoinOrCreateOperation(plugin, _webhooks);
_handlers[(byte) RagonOperation.CREATE_ROOM] = new RoomCreateOperation(plugin, _webhooks); _handlers[(byte) RagonOperation.CREATE_ROOM] = new RoomCreateOperation(plugin, _webhooks);
_handlers[(byte) RagonOperation.JOIN_ROOM] = new RoomJoinOperation(plugin, _webhooks); _handlers[(byte) RagonOperation.JOIN_ROOM] = new RoomJoinOperation(plugin, _webhooks);
@@ -79,8 +89,6 @@ public class RagonServer : INetworkListener
_logger.Trace($"Server Tick Rate: {_configuration.ServerTickRate}"); _logger.Trace($"Server Tick Rate: {_configuration.ServerTickRate}");
} }
public IRagonOperation Resolve(RagonOperation operation) => _handlers[(byte)operation];
public void Execute() public void Execute()
{ {
_timer.Start(); _timer.Start();
@@ -88,11 +96,11 @@ public class RagonServer : INetworkListener
{ {
if (_timer.ElapsedMilliseconds > _tickRate) if (_timer.ElapsedMilliseconds > _tickRate)
{ {
_executor.Update();
_scheduler.Update(_timer.ElapsedMilliseconds / 1000.0f); _scheduler.Update(_timer.ElapsedMilliseconds / 1000.0f);
_timer.Restart(); _timer.Restart();
} }
_executor.Update();
_server.Update(); _server.Update();
Thread.Sleep(1); Thread.Sleep(1);
} }
@@ -108,6 +116,7 @@ public class RagonServer : INetworkListener
Port = _configuration.Port, Port = _configuration.Port,
}; };
_httpServer.Start(_configuration);
_server.Start(this, networkConfiguration); _server.Start(this, networkConfiguration);
if (executeInDedicatedThread) if (executeInDedicatedThread)
@@ -118,6 +127,7 @@ public class RagonServer : INetworkListener
public void Dispose() public void Dispose()
{ {
_serverPlugin.OnDetached();
_server.Stop(); _server.Stop();
_dedicatedThread.Interrupt(); _dedicatedThread.Interrupt();
} }
@@ -127,12 +137,12 @@ public class RagonServer : INetworkListener
var context = new RagonContext(connection, _executor, _lobby, _scheduler); var context = new RagonContext(connection, _executor, _lobby, _scheduler);
_logger.Trace($"Connected: {connection.Id}"); _logger.Trace($"Connected: {connection.Id}");
_contexts.Add(connection.Id, context); _contextsByConnection.Add(connection.Id, context);
} }
public void OnDisconnected(INetworkConnection connection) public void OnDisconnected(INetworkConnection connection)
{ {
if (_contexts.Remove(connection.Id, out var context)) if (_contextsByConnection.Remove(connection.Id, out var context))
{ {
var room = context.Room; var room = context.Room;
if (room != null) if (room != null)
@@ -152,7 +162,7 @@ public class RagonServer : INetworkListener
public void OnTimeout(INetworkConnection connection) public void OnTimeout(INetworkConnection connection)
{ {
if (_contexts.Remove(connection.Id, out var context)) if (_contextsByConnection.Remove(connection.Id, out var context))
{ {
var room = context.Room; var room = context.Room;
if (room != null) if (room != null)
@@ -173,7 +183,7 @@ public class RagonServer : INetworkListener
{ {
try try
{ {
if (_contexts.TryGetValue(connection.Id, out var context)) if (_contextsByConnection.TryGetValue(connection.Id, out var context))
{ {
_writer.Clear(); _writer.Clear();
_reader.Clear(); _reader.Clear();
@@ -188,4 +198,7 @@ public class RagonServer : INetworkListener
_logger.Error(ex); _logger.Error(ex);
} }
} }
public IRagonOperation ResolveOperation(RagonOperation operation) => _handlers[(byte)operation];
public RagonContext? ResolveContext(INetworkConnection connection) => _contextsByConnection.TryGetValue(connection.Id, out var context) ? context : null;
public RagonContext? ResolveContext(string playerId) => _contextsByPlayerId.TryGetValue(playerId, out var context) ? context : null;
} }
@@ -38,6 +38,8 @@ public struct Configuration
public ushort ServerTickRate; public ushort ServerTickRate;
public string GameProtocol; public string GameProtocol;
public ushort Port; public ushort Port;
public ushort HttpPort;
public string HttpKey;
public int LimitConnections; public int LimitConnections;
public int LimitPlayersPerRoom; public int LimitPlayersPerRoom;
public int LimitRooms; public int LimitRooms;
+9
View File
@@ -0,0 +1,9 @@
using Ragon.Server.IO;
namespace Ragon.Server.Room;
public interface IRagonRoom
{
RagonRoomPlayer GetPlayerByConnection(INetworkConnection connection);
RagonRoomPlayer GetPlayerById(string id);
}
+5 -1
View File
@@ -16,12 +16,13 @@
using Ragon.Protocol; using Ragon.Protocol;
using Ragon.Server.Entity; using Ragon.Server.Entity;
using Ragon.Server.IO;
using Ragon.Server.Plugin; using Ragon.Server.Plugin;
using Ragon.Server.Time; using Ragon.Server.Time;
namespace Ragon.Server.Room; namespace Ragon.Server.Room;
public class RagonRoom : IRagonAction public class RagonRoom : IRagonRoom, IRagonAction
{ {
public string Id { get; private set; } public string Id { get; private set; }
public string Map { get; private set; } public string Map { get; private set; }
@@ -204,4 +205,7 @@ public class RagonRoom : IRagonAction
foreach (var readyPlayer in ReadyPlayersList) foreach (var readyPlayer in ReadyPlayersList)
readyPlayer.Connection.Reliable.Send(data); readyPlayer.Connection.Reliable.Send(data);
} }
public RagonRoomPlayer GetPlayerByConnection(INetworkConnection connection) => Players[connection.Id];
public RagonRoomPlayer GetPlayerById(string id) => PlayerList.First(p => p.Id == id);
} }