/.vscode
-/build
\ No newline at end of file
+/build
+/.vs
+/src/Impostor.Plugins.Debugger/Properties/launchSettings.json
--- /dev/null
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Net;
+using System.Text;
+using System.Threading.Tasks;
+
+using Impostor.Server.Net.Redirector;
+
+namespace Impostor.Server.Extensions
+{
+ public static class NodeLocatorExtensions
+ {
+ public static async ValueTask<bool> ExistsAsync(this INodeLocator nodeLocator, string gameCode)
+ {
+ return await nodeLocator.FindAsync(gameCode) != null;
+ }
+ }
+}
\ No newline at end of file
using System.Linq;
using System.Net;
using System.Threading.Tasks;
+
using Impostor.Api;
using Impostor.Api.Events;
using Impostor.Api.Events.Managers;
using Impostor.Api.Innersloth;
using Impostor.Api.Innersloth.Data;
using Impostor.Server.Data;
+using Impostor.Server.Extensions;
using Impostor.Server.Net.Redirector;
using Impostor.Server.Net.State;
+
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
public async ValueTask<Game> CreateAsync(GameOptionsData options)
{
// TODO: Prevent duplicates when using server redirector using INodeProvider.
+ var (success, game) = await TryCreateAsync(options);
+
+ for (int i = 0; i < 10 && !success; i++)
+ {
+ (success, game) = await TryCreateAsync(options);
+ }
+
+ if (!success)
+ {
+ throw new ImpostorException("Could not create new game"); // TODO: Fix generic exception.
+ }
+
+ return game;
+ }
+
+ public async ValueTask<(bool success, Game game)> TryCreateAsync(GameOptionsData options)
+ {
var gameCode = GameCode.Create();
var gameCodeStr = gameCode.Code;
var game = ActivatorUtilities.CreateInstance<Game>(_serviceProvider, _publicIp, gameCode, options);
- if (_nodeLocator.Find(gameCodeStr) != null || !_games.TryAdd(gameCode, game))
+ if (await _nodeLocator.ExistsAsync(gameCodeStr) || !_games.TryAdd(gameCode, game))
{
- throw new ImpostorException("Could not create new game"); // TODO: Fix generic exception.
+ return (false, null);
}
- _nodeLocator.Save(gameCodeStr, _publicIp);
+ await _nodeLocator.SaveAsync(gameCodeStr, _publicIp);
_logger.LogDebug("Created game with code {0}.", game.Code);
await _eventManager.CallAsync(new GameCreatedEvent(game));
- return game;
+ return (true, game);
}
public Game Find(GameCode code)
}
_logger.LogDebug("Remove game with code {0} ({1}).", GameCodeParser.IntToGameName(gameCode), gameCode);
- _nodeLocator.Remove(GameCodeParser.IntToGameName(gameCode));
+ await _nodeLocator.RemoveAsync(GameCodeParser.IntToGameName(gameCode));
await _eventManager.CallAsync(new GameDestroyedEvent(game));
}
out _);
using var packet = MessageWriter.Get(MessageType.Reliable);
- var endpoint = _nodeLocator.Find(GameCodeParser.IntToGameName(gameCode));
+ var endpoint = await _nodeLocator.FindAsync(GameCodeParser.IntToGameName(gameCode));
if (endpoint == null)
{
Message01JoinGameS2C.SerializeError(packet, false, DisconnectReason.GameMissing);
using System.Net;
+using System.Threading.Tasks;
namespace Impostor.Server.Net.Redirector
{
public interface INodeLocator
{
- IPEndPoint Find(string gameCode);
+ ValueTask<IPEndPoint> FindAsync(string gameCode);
- void Save(string gameCode, IPEndPoint endPoint);
+ ValueTask SaveAsync(string gameCode, IPEndPoint endPoint);
- void Remove(string gameCode);
+ ValueTask RemoveAsync(string gameCode);
}
}
\ No newline at end of file
using System.Net;
+using System.Threading.Tasks;
namespace Impostor.Server.Net.Redirector
{
public class NodeLocatorNoOp : INodeLocator
{
- public IPEndPoint Find(string gameCode)
- {
- // Do nothing.
- return null;
- }
+ public ValueTask<IPEndPoint> FindAsync(string gameCode) => ValueTask.FromResult(default(IPEndPoint));
- public void Save(string gameCode, IPEndPoint endPoint)
- {
- // Do nothing.
- }
+ public ValueTask SaveAsync(string gameCode, IPEndPoint endPoint) => ValueTask.CompletedTask;
- public void Remove(string gameCode)
- {
- // Do nothing.
- }
+ public ValueTask RemoveAsync(string gameCode) => ValueTask.CompletedTask;
}
}
\ No newline at end of file
using System;
using System.Net;
+using System.Threading.Tasks;
+
using Microsoft.Extensions.Caching.Distributed;
using Microsoft.Extensions.Logging;
_cache = cache;
}
- public IPEndPoint Find(string gameCode)
+ public async ValueTask<IPEndPoint> FindAsync(string gameCode)
{
- var entry = _cache.GetString(gameCode);
+ var entry = await _cache.GetStringAsync(gameCode);
if (entry == null)
{
return null;
return IPEndPoint.Parse(entry);
}
- public void Save(string gameCode, IPEndPoint endPoint)
+ public async ValueTask SaveAsync(string gameCode, IPEndPoint endPoint)
{
- _cache.SetString(gameCode, endPoint.ToString(), new DistributedCacheEntryOptions
+ await _cache.SetStringAsync(gameCode, endPoint.ToString(), new DistributedCacheEntryOptions
{
SlidingExpiration = TimeSpan.FromHours(1),
});
}
- public void Remove(string gameCode)
+ public async ValueTask RemoveAsync(string gameCode)
{
- _cache.Remove(gameCode);
+ await _cache.RemoveAsync(gameCode);
}
}
}
\ No newline at end of file
using System.Net;
using System.Net.Sockets;
using System.Text;
+using System.Threading.Tasks;
using Impostor.Server.Data;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
}
}
- public IPEndPoint Find(string gameCode)
+ public ValueTask<IPEndPoint> FindAsync(string gameCode)
{
if (!_isMaster)
{
- return null;
+ return ValueTask.FromResult(default(IPEndPoint));
}
if (_availableNodes.TryGetValue(gameCode, out var node))
if (node.Expired)
{
_availableNodes.TryRemove(gameCode, out _);
- return null;
+ return ValueTask.FromResult(default(IPEndPoint));
}
- return node.Endpoint;
+ return ValueTask.FromResult(node.Endpoint);
}
- return null;
+ return ValueTask.FromResult(default(IPEndPoint));
}
- public void Remove(string gameCode)
+ public ValueTask RemoveAsync(string gameCode)
{
if (!_isMaster)
{
- return;
+ return ValueTask.CompletedTask;
}
_availableNodes.TryRemove(gameCode, out _);
+ return ValueTask.CompletedTask;
}
- public void Save(string gameCode, IPEndPoint endPoint)
+ public ValueTask SaveAsync(string gameCode, IPEndPoint endPoint)
{
var data = Encoding.UTF8.GetBytes($"{gameCode},{endPoint}");
_client.Send(data, data.Length, _server);
+ return ValueTask.CompletedTask;
}
public void Dispose()