private async ValueTask <GameJoinResult> AddClientSafeAsync(ClientBase client)
        {
            // Check if the IP of the player is banned.
            if (client.Connection != null && _bannedIps.Contains(client.Connection.EndPoint.Address))
            {
                return(GameJoinResult.FromError(GameJoinError.Banned));
            }

            var player = client.Player;

            // Check if;
            // - The player is already in this game.
            // - The game is full.
            if (player?.Game != this && _players.Count >= Options.MaxPlayers)
            {
                return(GameJoinResult.FromError(GameJoinError.GameFull));
            }

            if (GameState == GameStates.Starting || GameState == GameStates.Started)
            {
                return(GameJoinResult.FromError(GameJoinError.GameStarted));
            }

            if (GameState == GameStates.Destroyed)
            {
                return(GameJoinResult.FromError(GameJoinError.GameDestroyed));
            }

            if (Host != null)
            {
                foreach (var hostMod in Host.Client.Mods)
                {
                    if (hostMod.Side == PluginSide.Both && client.Mods.All(clientMod => hostMod.Id != clientMod.Id))
                    {
                        return(GameJoinResult.CreateCustomError($"You are missing {hostMod.Id} - {hostMod.Version}"));
                    }
                }

                foreach (var clientMod in client.Mods)
                {
                    if (clientMod.Side == PluginSide.Both && Host.Client.Mods.All(hostMod => clientMod.Id != hostMod.Id))
                    {
                        return(GameJoinResult.CreateCustomError($"Host of this game is missing {clientMod.Id} - {clientMod.Version}"));
                    }
                }
            }

            var isNew = false;

            if (player == null || player.Game != this)
            {
                var clientPlayer = new ClientPlayer(_serviceProvider.GetRequiredService <ILogger <ClientPlayer> >(), client, this);

                if (!_clientManager.Validate(client))
                {
                    return(GameJoinResult.FromError(GameJoinError.InvalidClient));
                }

                isNew         = true;
                player        = clientPlayer;
                client.Player = clientPlayer;
            }

            // Check current player state.
            if (player.Limbo == LimboStates.NotLimbo)
            {
                return(GameJoinResult.FromError(GameJoinError.InvalidLimbo));
            }

            if (GameState == GameStates.Ended)
            {
                await HandleJoinGameNext(player, isNew);

                return(GameJoinResult.CreateSuccess(player));
            }

            await HandleJoinGameNew(player, isNew);

            return(GameJoinResult.CreateSuccess(player));
        }
        private async ValueTask <GameJoinResult> AddClientSafeAsync(ClientBase client)
        {
            // Check if the IP of the player is banned.
            if (_bannedIps.Contains(client.Connection.EndPoint.Address))
            {
                return(GameJoinResult.FromError(GameJoinError.Banned));
            }

            ClientPlayer?player = client.Player;

            // Check if;
            // - The player is already in this game.
            // - The game is full.
            if (player?.Game != this && _players.Count >= Options.MaxPlayers)
            {
                return(GameJoinResult.FromError(GameJoinError.GameFull));
            }

            if (GameState == GameStates.Starting || GameState == GameStates.Started)
            {
                return(GameJoinResult.FromError(GameJoinError.GameStarted));
            }

            if (GameState == GameStates.Destroyed)
            {
                return(GameJoinResult.FromError(GameJoinError.GameDestroyed));
            }

            bool isNew = false;

            if (player == null || player.Game != this)
            {
                var clientPlayer = new ClientPlayer(_serviceProvider.GetRequiredService <ILogger <ClientPlayer> >(), client, this);

                if (!_clientManager.Validate(client))
                {
                    return(GameJoinResult.FromError(GameJoinError.InvalidClient));
                }

                isNew         = true;
                player        = clientPlayer;
                client.Player = clientPlayer;
            }

            // Check current player state.
            if (player.Limbo == LimboStates.NotLimbo)
            {
                return(GameJoinResult.FromError(GameJoinError.InvalidLimbo));
            }

            if (GameState == GameStates.Ended)
            {
                await HandleJoinGameNext(player, isNew);

                return(GameJoinResult.CreateSuccess(player));
            }

            var @event = new GamePlayerJoiningEvent(this, player);
            await _eventManager.CallAsync(@event);

            if (@event.JoinResult != null && [email protected])
            {
                return(@event.JoinResult.Value);
            }

            await HandleJoinGameNew(player, isNew);

            return(GameJoinResult.CreateSuccess(player));
        }