Example #1
0
        public override async ValueTask HandleMessageAsync(IMessageReader reader, MessageType messageType)
        {
            byte flag = reader.Tag;

            _logger.LogTrace("[{0}] Server got {1}.", Id, flag);

            switch (flag)
            {
            case MessageFlags.HostGame:
            {
                // Read game settings.
                GameOptionsData gameInfo = Message00HostGameC2S.Deserialize(reader, out _);

                // Create game.
                IGame?game = await _gameManager.CreateAsync(this, gameInfo);

                if (game == null)
                {
                    await DisconnectAsync(DisconnectReason.GameMissing);

                    return;
                }

                // Code in the packet below will be used in JoinGame.
                using (var writer = MessageWriter.Get(MessageType.Reliable))
                {
                    Message00HostGameS2C.Serialize(writer, game.Code);
                    await Connection.SendAsync(writer);
                }

                break;
            }

            case MessageFlags.JoinGame:
            {
                Message01JoinGameC2S.Deserialize(reader, out GameCode gameCode);

                Game?game = _gameManager.Find(gameCode);
                if (game == null)
                {
                    await DisconnectAsync(DisconnectReason.GameMissing);

                    return;
                }

                GameJoinResult result = await game.AddClientAsync(this);

                switch (result.Error)
                {
                case GameJoinError.None:
                    break;

                case GameJoinError.InvalidClient:
                    await DisconnectAsync(DisconnectReason.Custom, "Client is in an invalid state.");

                    break;

                case GameJoinError.Banned:
                    await DisconnectAsync(DisconnectReason.Banned);

                    break;

                case GameJoinError.GameFull:
                    await DisconnectAsync(DisconnectReason.GameFull);

                    break;

                case GameJoinError.InvalidLimbo:
                    await DisconnectAsync(DisconnectReason.Custom, "Invalid limbo state while joining.");

                    break;

                case GameJoinError.GameStarted:
                    await DisconnectAsync(DisconnectReason.GameStarted);

                    break;

                case GameJoinError.GameDestroyed:
                    await DisconnectAsync(DisconnectReason.Custom, DisconnectMessages.Destroyed);

                    break;

                case GameJoinError.Custom:
                    await DisconnectAsync(DisconnectReason.Custom, result.Message);

                    break;

                default:
                    await DisconnectAsync(DisconnectReason.Custom, "Unknown error.");

                    break;
                }

                break;
            }

            case MessageFlags.StartGame:
            {
                if (!IsPacketAllowed(reader, true))
                {
                    return;
                }

                await Player !.Game.HandleStartGame(reader);
                break;
            }

            // No idea how this flag is triggered.
            case MessageFlags.RemoveGame:
                break;

            case MessageFlags.RemovePlayer:
            {
                if (!IsPacketAllowed(reader, true))
                {
                    return;
                }

                Message04RemovePlayerC2S.Deserialize(
                    reader,
                    out int playerId,
                    out byte reason);

                await Player !.Game.HandleRemovePlayer(playerId, (DisconnectReason)reason);
                break;
            }

            case MessageFlags.GameData:
            case MessageFlags.GameDataTo:
            {
                if (!IsPacketAllowed(reader, false))
                {
                    return;
                }

                bool toPlayer = flag == MessageFlags.GameDataTo;

                int  position = reader.Position;
                bool verified = await Player !.Game.HandleGameDataAsync(reader, Player, toPlayer);
                reader.Seek(position);

                if (verified && Player != null)
                {
                    // Broadcast packet to all other players.
                    using (var writer = MessageWriter.Get(messageType))
                    {
                        if (toPlayer)
                        {
                            int target = reader.ReadPackedInt32();
                            reader.CopyTo(writer);
                            await Player.Game.SendToAsync(writer, target);
                        }
                        else
                        {
                            reader.CopyTo(writer);
                            await Player.Game.SendToAllExceptAsync(writer, Id);
                        }
                    }
                }

                break;
            }

            case MessageFlags.EndGame:
            {
                if (!IsPacketAllowed(reader, true))
                {
                    return;
                }

                Message08EndGameC2S.Deserialize(
                    reader,
                    out GameOverReason gameOverReason);

                await Player !.Game.HandleEndGame(reader, gameOverReason);
                break;
            }

            case MessageFlags.AlterGame:
            {
                if (!IsPacketAllowed(reader, true))
                {
                    return;
                }

                Message10AlterGameC2S.Deserialize(
                    reader,
                    out AlterGameTags gameTag,
                    out bool value);

                if (gameTag != AlterGameTags.ChangePrivacy)
                {
                    return;
                }

                await Player !.Game.HandleAlterGame(reader, Player, value);
                break;
            }

            case MessageFlags.KickPlayer:
            {
                if (!IsPacketAllowed(reader, true))
                {
                    return;
                }

                Message11KickPlayerC2S.Deserialize(
                    reader,
                    out int playerId,
                    out bool isBan);

                await Player !.Game.HandleKickPlayer(playerId, isBan);
                break;
            }

            case MessageFlags.GetGameListV2:
            {
                Message16GetGameListC2S.Deserialize(reader, out var options, out _);
                await OnRequestGameListAsync(options);

                break;
            }

            default:
                if (_customMessageManager.TryGet(flag, out var customRootMessage))
                {
                    await customRootMessage.HandleMessageAsync(this, reader, messageType);

                    break;
                }

                _logger.LogWarning("Server received unknown flag {0}.", flag);
                break;
            }

#if DEBUG
            if (flag != MessageFlags.GameData &&
                flag != MessageFlags.GameDataTo &&
                flag != MessageFlags.EndGame &&
                reader.Position < reader.Length)
            {
                _logger.LogWarning(
                    "Server did not consume all bytes from {0} ({1} < {2}).",
                    flag,
                    reader.Position,
                    reader.Length);
            }
#endif
        }
Example #2
0
        public override async ValueTask HandleMessageAsync(IMessageReader reader, MessageType messageType)
        {
            var flag = reader.Tag;

            _logger.LogTrace("[{0}] Server got {1}.", Id, flag);

            switch (flag)
            {
            case MessageFlags.HostGame:
            {
                // Read game settings.
                var gameInfo = Message00HostGameC2S.Deserialize(reader);

                // Create game.
                var game = await _gameManager.CreateAsync(gameInfo);

                // Code in the packet below will be used in JoinGame.
                using (var writer = MessageWriter.Get(MessageType.Reliable))
                {
                    Message00HostGameS2C.Serialize(writer, game.Code);
                    await Connection.SendAsync(writer);
                }

                break;
            }

            case MessageFlags.JoinGame:
            {
                Message01JoinGameC2S.Deserialize(
                    reader,
                    out var gameCode,
                    out _);

                var game = _gameManager.Find(gameCode);
                if (game == null)
                {
                    await DisconnectAsync(DisconnectReason.GameMissing);

                    return;
                }

                var result = await game.AddClientAsync(this);

                switch (result.Error)
                {
                case GameJoinError.None:
                    break;

                case GameJoinError.InvalidClient:
                    await DisconnectAsync(DisconnectReason.Custom, "Client is in an invalid state.");

                    break;

                case GameJoinError.Banned:
                    await DisconnectAsync(DisconnectReason.Banned);

                    break;

                case GameJoinError.GameFull:
                    await DisconnectAsync(DisconnectReason.GameFull);

                    break;

                case GameJoinError.InvalidLimbo:
                    await DisconnectAsync(DisconnectReason.Custom, "Invalid limbo state while joining.");

                    break;

                case GameJoinError.GameStarted:
                    await DisconnectAsync(DisconnectReason.GameStarted);

                    break;

                case GameJoinError.GameDestroyed:
                    await DisconnectAsync(DisconnectReason.Custom, DisconnectMessages.Destroyed);

                    break;

                case GameJoinError.Custom:
                    await DisconnectAsync(DisconnectReason.Custom, result.Message);

                    break;

                default:
                    await DisconnectAsync(DisconnectReason.Custom, "Unknown error.");

                    break;
                }

                break;
            }

            case MessageFlags.StartGame:
            {
                if (!IsPacketAllowed(reader, true))
                {
                    return;
                }

                await Player.Game.HandleStartGame(reader);

                break;
            }

            // No idea how this flag is triggered.
            case MessageFlags.RemoveGame:
                break;

            case MessageFlags.RemovePlayer:
            {
                if (!IsPacketAllowed(reader, true))
                {
                    return;
                }

                Message04RemovePlayerC2S.Deserialize(
                    reader,
                    out var playerId,
                    out var reason);

                await Player.Game.HandleRemovePlayer(playerId, (DisconnectReason)reason);

                break;
            }

            case MessageFlags.GameData:
            case MessageFlags.GameDataTo:
            {
                if (!IsPacketAllowed(reader, false))
                {
                    return;
                }

                var toPlayer = flag == MessageFlags.GameDataTo;

                // Handle packet.
                using var readerCopy = reader.Copy();

                // TODO: Return value, either a bool (to cancel) or a writer (to cancel (null) or modify/overwrite).
                try
                {
                    var verified = await Player.Game.HandleGameDataAsync(readerCopy, Player, toPlayer);

                    if (verified)
                    {
                        // Broadcast packet to all other players.
                        using (var writer = MessageWriter.Get(messageType))
                        {
                            if (toPlayer)
                            {
                                var target = reader.ReadPackedInt32();
                                reader.CopyTo(writer);
                                await Player.Game.SendToAsync(writer, target);
                            }
                            else
                            {
                                reader.CopyTo(writer);
                                await Player.Game.SendToAllExceptAsync(writer, Id);
                            }
                        }
                    }
                }
                catch (ImpostorCheatException e)
                {
                    if (_antiCheatConfig.BanIpFromGame)
                    {
                        Player.Game.BanIp(Connection.EndPoint.Address);
                    }

                    await DisconnectAsync(DisconnectReason.Hacking, e.Message);
                }

                break;
            }

            case MessageFlags.EndGame:
            {
                if (!IsPacketAllowed(reader, true))
                {
                    return;
                }

                Message08EndGameC2S.Deserialize(
                    reader,
                    out var gameOverReason);

                await Player.Game.HandleEndGame(reader, gameOverReason);

                break;
            }

            case MessageFlags.AlterGame:
            {
                if (!IsPacketAllowed(reader, true))
                {
                    return;
                }

                Message10AlterGameC2S.Deserialize(
                    reader,
                    out var gameTag,
                    out var value);

                if (gameTag != AlterGameTags.ChangePrivacy)
                {
                    return;
                }

                await Player.Game.HandleAlterGame(reader, Player, value);

                break;
            }

            case MessageFlags.KickPlayer:
            {
                if (!IsPacketAllowed(reader, true))
                {
                    return;
                }

                Message11KickPlayerC2S.Deserialize(
                    reader,
                    out var playerId,
                    out var isBan);

                await Player.Game.HandleKickPlayer(playerId, isBan);

                break;
            }

            case MessageFlags.GetGameListV2:
            {
                Message16GetGameListC2S.Deserialize(reader, out var options);
                await OnRequestGameListAsync(options);

                break;
            }

            default:
                _logger.LogWarning("Server received unknown flag {0}.", flag);
                break;
            }

#if DEBUG
            if (flag != MessageFlags.GameData &&
                flag != MessageFlags.GameDataTo &&
                flag != MessageFlags.EndGame &&
                reader.Position < reader.Length)
            {
                _logger.LogWarning(
                    "Server did not consume all bytes from {0} ({1} < {2}).",
                    flag,
                    reader.Position,
                    reader.Length);
            }
#endif
        }