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.