public void OnGamePlayerPreJoinEvent(IGamePlayerJoiningEvent e) { var client = e.Player.Client; var host = e.Game.Host; if (host != null) { var hostMods = host.Client.GetReactor()?.Mods; var clientMods = client.GetReactor()?.Mods; var clientMissing = hostMods != null ? hostMods.Where(mod => mod.Side == PluginSide.Both && (clientMods == null || !clientMods.Contains(mod))).ToArray() : Array.Empty <Mod>(); var hostMissing = clientMods != null ? clientMods.Where(mod => mod.Side == PluginSide.Both && (hostMods == null || !hostMods.Contains(mod))).ToArray() : Array.Empty <Mod>(); if (clientMissing.Any() || hostMissing.Any()) { var message = new StringBuilder(); if (clientMissing.Any()) { message.Append("You are missing: "); message.AppendJoin(", ", clientMissing.Select(x => $"{x.Id} ({x.Version})")); message.AppendLine(); } if (hostMissing.Any()) { message.Append("Host is missing: "); message.AppendJoin(", ", hostMissing.Select(x => $"{x.Id} ({x.Version})")); message.AppendLine(); } e.JoinResult = GameJoinResult.CreateCustomError(message.ToString()); } } }
public async ValueTask <GameJoinResult> AddClientAsync(ClientBase client) { var hasLock = false; try { hasLock = await _clientAddLock.WaitAsync(TimeSpan.FromMinutes(1)); if (hasLock) { return(await AddClientSafeAsync(client)); } } finally { if (hasLock) { _clientAddLock.Release(); } } return(GameJoinResult.FromError(GameJoinError.InvalidClient)); }
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 }
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)); }