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 }
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 }