Esempio n. 1
0
        private static async Task Main(string[] args)
        {
            Log.Logger = new LoggerConfiguration()
                         .WriteTo.Console()
                         .CreateLogger();

            var writeHandshake = MessageWriter.Get(MessageType.Reliable);

            writeHandshake.Write(50516550);
            writeHandshake.Write("AeonLucid");

            var writeGameCreate = MessageWriter.Get(MessageType.Reliable);

            Message00HostGameC2S.Serialize(writeGameCreate, new GameOptionsData
            {
                MaxPlayers   = 4,
                NumImpostors = 2
            });

            // TODO: ObjectPool for MessageReaders
            using (var connection = new UdpClientConnection(new IPEndPoint(IPAddress.Parse("127.0.0.1"), 22023), null))
            {
                var e = new ManualResetEvent(false);

                // Register events.
                connection.DataReceived = DataReceived;
                connection.Disconnected = Disconnected;

                // Connect and send handshake.
                await connection.ConnectAsync(writeHandshake.ToByteArray(false));

                Log.Information("Connected.");

                // Create a game.
                await connection.SendAsync(writeGameCreate);

                Log.Information("Requested game creation.");

                // Recycle.
                writeHandshake.Recycle();
                writeGameCreate.Recycle();

                e.WaitOne();
            }
        }
Esempio n. 2
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
        }
Esempio n. 3
0
        private static async Task ParsePacket(BinaryReader reader)
        {
            var dataType = (RecordedPacketType)reader.ReadByte();

            // Read client id.
            var clientId = reader.ReadInt32();

            switch (dataType)
            {
            case RecordedPacketType.Connect:
                // Read data.
                var addressLength = reader.ReadByte();
                var addressBytes  = reader.ReadBytes(addressLength);
                var addressPort   = reader.ReadUInt16();
                var address       = new IPEndPoint(new IPAddress(addressBytes), addressPort);
                var name          = reader.ReadString();

                // Create and register connection.
                var connection = new MockHazelConnection(address);

                await _clientManager.RegisterConnectionAsync(connection, name, 50516550, null);

                // Store reference for ourselfs.
                Connections.Add(clientId, connection);
                break;

            case RecordedPacketType.Disconnect:
                string reason = null;

                if (reader.BaseStream.Position < reader.BaseStream.Length)
                {
                    reason = reader.ReadString();
                }

                await Connections[clientId].Client !.HandleDisconnectAsync(reason);
                Connections.Remove(clientId);
                break;

            case RecordedPacketType.Message:
            {
                var messageType = (MessageType)reader.ReadByte();
                var tag         = reader.ReadByte();
                var length      = reader.ReadInt32();
                var buffer      = reader.ReadBytes(length);
                using var message = _readerPool.Get();

                message.Update(buffer, tag: tag);

                if (tag == MessageFlags.HostGame)
                {
                    GameOptions.Add(clientId, Message00HostGameC2S.Deserialize(message));
                }
                else if (Connections.TryGetValue(clientId, out var client))
                {
                    await client.Client !.HandleMessageAsync(message, messageType);
                }

                break;
            }

            case RecordedPacketType.GameCreated:
                _gameCodeFactory.Result = GameCode.From(reader.ReadString());

                await _gameManager.CreateAsync(GameOptions[clientId]);

                GameOptions.Remove(clientId);
                break;

            default:
                throw new ArgumentOutOfRangeException();
            }
        }
Esempio n. 4
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
        }