Skip to content

Instantly share code, notes, and snippets.

@Programmer86
Created August 6, 2020 09:29
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Programmer86/c150cc645e596c898bc03df1b0f5e9b6 to your computer and use it in GitHub Desktop.
Save Programmer86/c150cc645e596c898bc03df1b0f5e9b6 to your computer and use it in GitHub Desktop.
public class Startup
{
// This method gets called by the runtime. Use this method to add services to the container.
// For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton<BattlesController>();
services.AddSingleton<GamesManager>();
services.AddSignalR();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseWebSockets();
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapHub<GamesControlHub>("/hubs/GamesControlHub", options => {
options.Transports = Microsoft.AspNetCore.Http.Connections.HttpTransportType.WebSockets;
});
endpoints.MapGet("/", async context =>
{
await context.Response.WriteAsync("Hello World!");
});
});
}
}
// ---------------------------------------------------------------------------------------------------------
// SignalR Core hub on server side
public class GamesControlHub : Hub<IGameControlClient>, IGameControlServer
{
private GamesManager gameManager;
private BattlesController battlesController;
public GamesControlHub(GamesManager manager, BattlesController controller)
{
gameManager = manager;
battlesController = controller;
}
public override async Task OnConnectedAsync()
{
gameManager.ConnectPlayer(Context.ConnectionId);
await base.OnConnectedAsync();
}
public override async Task OnDisconnectedAsync(Exception exception)
{
gameManager.DisconnectPlayer(Context.ConnectionId);
await base.OnDisconnectedAsync(exception);
}
public Task SendBattleCancelSearchRequestMessageToServer(BattleCancelSearchRequestMessage message)
{
gameManager.LeaveSearchQueue(Context.ConnectionId);
return Task.CompletedTask;
}
public Task SendBattleSearchRequestMessageToServer(BattleSearchRequestMessage message)
{
gameManager.JoinSearchQueue(Context.ConnectionId);
return Task.CompletedTask;
}
public async Task SendPingRequestMessageToServer(PingRequestMessage message) =>
await Clients.Caller.SendPingReplyMessageToClient(new PingReplyMessage(message));
public async Task SendPlayerMoveRequestMessageToServer(PlayerMoveRequestMessage message) =>
await battlesController.PlayerMove(Context.ConnectionId, message);
}
// ---------------------------------------------------------------------------------------------------------
// SignalR Core hub on client side (placed in Share project)
class GameControlHub : IGameControlServer
{
public bool Connected
{
get => connection.State == HubConnectionState.Connected;
}
public string ConnectionId
{
get => connection.ConnectionId;
}
private const string HUB_ROUTE = "hubs/GamesControlHub";
private HubConnection connection;
public GameControlHub(string baseAddress)
{
connection = new HubConnectionBuilder()
.WithUrl(baseAddress + HUB_ROUTE, HttpTransportType.WebSockets)
.Build();
connection.Closed += ReconnectToHub;
var interfacesMethods = typeof(IGameControlClient).GetMethods();
foreach (var method in interfacesMethods)
{
var paramType = method.GetParameters()[0].ParameterType;
connection.On(method.Name, new[] { paramType }, ReceiveMessageAsync);
}
}
public async Task ConnectAsync() =>
await connection.StartAsync();
private async Task ReconnectToHub(Exception error)
{
await Task.Delay(new Random().Next(0, 5) * 1000);
await connection.StartAsync();
}
private async Task<bool> SendMessageAsync(BaseMessage message)
{
if (Connected == false)
return false;
var messageTypeName = message.GetType().Name;
await connection.InvokeAsync($"Send{messageTypeName}ToServer", message);
return true;
}
private async Task ReceiveMessageAsync(object[] inputs)
{
var message = inputs[0] as BaseMessage;
var messageTypeName = message.GetType().Name;
var messageMethod = this.GetType().GetMethod($"Receive{messageTypeName}");
var calledMethod = messageMethod.Invoke(this, new object[] { message }) as Task;
await calledMethod;
}
public async Task SendPingRequestMessageToServer(PingRequestMessage message) =>
await SendMessageAsync(message);
public event Func<PingReplyMessage, Task> OnReceivePingReplyMessage;
public async Task ReceivePingReplyMessage(PingReplyMessage message)
{
if (OnReceivePingReplyMessage == null)
return;
await OnReceivePingReplyMessage.Invoke(message);
}
public async Task SendBattleSearchRequestMessageToServer(BattleSearchRequestMessage message) =>
await SendMessageAsync(message);
public event Func<BattleFoundReplyMessage, Task> OnReceiveBattleFoundReplyMessage;
public async Task ReceiveBattleFoundReplyMessage(BattleFoundReplyMessage message)
{
if (OnReceiveBattleFoundReplyMessage == null)
return;
await OnReceiveBattleFoundReplyMessage.Invoke(message);
}
public async Task SendPlayerMoveRequestMessageToServer(PlayerMoveRequestMessage message) =>
await SendMessageAsync(message);
public event Func<PlayerMoveReplyMessage, Task> OnReceivePlayerMoveReplyMessage;
public async Task ReceivePlayerMoveReplyMessage(PlayerMoveReplyMessage message)
{
if (OnReceiveBattleFoundReplyMessage == null)
return;
await OnReceivePlayerMoveReplyMessage.Invoke(message);
}
public async Task SendBattleCancelSearchRequestMessageToServer(BattleCancelSearchRequestMessage message) =>
await SendMessageAsync(message);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment