diff --git a/src/Impostor.Api/Net/IClient.cs b/src/Impostor.Api/Net/IClient.cs index e4f81001..0732c0cc 100644 --- a/src/Impostor.Api/Net/IClient.cs +++ b/src/Impostor.Api/Net/IClient.cs @@ -8,7 +8,7 @@ namespace Impostor.Api.Net /// /// Represents a connected game client. /// - public interface IClient + public interface IClient : IEquatable { /// /// Gets or sets the unique ID of the client. diff --git a/src/Impostor.Server/Net/ClientBase.cs b/src/Impostor.Server/Net/ClientBase.cs index b52d5121..a8945faf 100644 --- a/src/Impostor.Server/Net/ClientBase.cs +++ b/src/Impostor.Server/Net/ClientBase.cs @@ -59,5 +59,20 @@ namespace Impostor.Server.Net { await Connection.CustomDisconnectAsync(reason, message); } + + public bool Equals(IClient? other) + { + return other != null && Id == other.Id; + } + + public override bool Equals(object? obj) + { + return Equals(obj as ClientBase); + } + + public override int GetHashCode() + { + return Id; + } } } diff --git a/src/Impostor.Server/Net/Manager/GameManager.cs b/src/Impostor.Server/Net/Manager/GameManager.cs index 4e985214..7de311a9 100644 --- a/src/Impostor.Server/Net/Manager/GameManager.cs +++ b/src/Impostor.Server/Net/Manager/GameManager.cs @@ -31,6 +31,7 @@ namespace Impostor.Server.Net.Manager private readonly IEventManager _eventManager; private readonly IGameCodeFactory _gameCodeFactory; private readonly ICompatibilityManager _compatibilityManager; + private readonly ConcurrentDictionary _gamesCreatedBy; public GameManager( ILogger logger, @@ -49,6 +50,7 @@ namespace Impostor.Server.Net.Manager _games = new ConcurrentDictionary(); _compatibilityConfig = compatibilityConfig.Value; _compatibilityManager = compatibilityManager; + _gamesCreatedBy = new ConcurrentDictionary(); } IEnumerable IGameManager.Games => _games.Select(kv => kv.Value); @@ -85,6 +87,12 @@ namespace Impostor.Server.Net.Manager public async ValueTask CreateAsync(IClient? owner, IGameOptions options, GameFilterOptions filterOptions) { + if (owner != null && !_gamesCreatedBy.TryAdd(owner, null)) + { + _logger.LogWarning("Connection {Name}({ClientId}) has tried to create a second game, blocked", owner.Name, owner.Id); + return null; + } + var @event = new GameCreationEvent(this, owner); await _eventManager.CallAsync(@event); @@ -100,6 +108,11 @@ namespace Impostor.Server.Net.Manager (success, game) = await TryCreateAsync(options, filterOptions, owner); } + if (owner != null) + { + _gamesCreatedBy[owner] = game; + } + if (!success || game == null) { throw new ImpostorException("Could not create new game"); // TODO: Fix generic exception.