Esempio n. 1
0
        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));
            }

            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 void WriteWaitForHostMessage(MessageWriter message, bool clear, ClientPlayer player)
 {
     Message12WaitForHost.Serialize(message, clear, Code, player.Client.Id);
 }
Esempio n. 3
0
        public async ValueTask <bool> HandleGameDataAsync(IMessageReader parent, ClientPlayer sender, bool toPlayer)
        {
            // Find target player.
            ClientPlayer target = null;

            if (toPlayer)
            {
                var targetId = parent.ReadPackedInt32();
                if (targetId == FakeClientId && !_gamedataFakeReceived && sender.IsHost)
                {
                    _gamedataFakeReceived = true;

                    // Remove the fake client, we received the data.
                    using (var message = MessageWriter.Get(MessageType.Reliable))
                    {
                        WriteRemovePlayerMessage(message, false, FakeClientId, (byte)DisconnectReason.ExitGame);

                        await sender.Client.Connection.SendAsync(message);
                    }
                }
                else if (!TryGetPlayer(targetId, out target))
                {
                    _logger.LogWarning("Player {0} tried to send GameData to unknown player {1}.", sender.Client.Id, targetId);
                    return(false);
                }

                _logger.LogTrace("Received GameData for target {0}.", targetId);
            }

            // Parse GameData messages.
            while (parent.Position < parent.Length)
            {
                using var reader = parent.ReadMessage();

                switch (reader.Tag)
                {
                case GameDataTag.DataFlag:
                {
                    var netId = reader.ReadPackedUInt32();
                    if (_allObjectsFast.TryGetValue(netId, out var obj))
                    {
                        await obj.DeserializeAsync(sender, target, reader, false);
                    }
                    else
                    {
                        _logger.LogWarning("Received DataFlag for unregistered NetId {0}.", netId);
                    }

                    break;
                }

                case GameDataTag.RpcFlag:
                {
                    var netId = reader.ReadPackedUInt32();
                    if (_allObjectsFast.TryGetValue(netId, out var obj))
                    {
                        if (!await obj.HandleRpc(sender, target, (RpcCalls)reader.ReadByte(), reader))
                        {
                            return(false);
                        }
                    }
                    else
                    {
                        _logger.LogWarning("Received RpcFlag for unregistered NetId {0}.", netId);
                    }

                    break;
                }

                case GameDataTag.SpawnFlag:
                {
                    // Only the host is allowed to despawn objects.
                    if (!sender.IsHost)
                    {
                        if (await sender.Client.ReportCheatAsync(new CheatContext(nameof(GameDataTag.SpawnFlag)), "Tried to send SpawnFlag as non-host."))
                        {
                            return(false);
                        }
                    }

                    var objectId = reader.ReadPackedUInt32();
                    if (objectId < SpawnableObjects.Length)
                    {
                        var innerNetObject = (InnerNetObject)ActivatorUtilities.CreateInstance(_serviceProvider, SpawnableObjects[objectId], this);
                        var ownerClientId  = reader.ReadPackedInt32();

                        // Prevent fake client from being broadcasted.
                        // TODO: Remove message from stream properly.
                        if (ownerClientId == FakeClientId)
                        {
                            return(false);
                        }

                        innerNetObject.SpawnFlags = (SpawnFlags)reader.ReadByte();

                        var components      = innerNetObject.GetComponentsInChildren <InnerNetObject>();
                        var componentsCount = reader.ReadPackedInt32();

                        if (componentsCount != components.Count)
                        {
                            _logger.LogError(
                                "Children didn't match for spawnable {0}, name {1} ({2} != {3})",
                                objectId,
                                innerNetObject.GetType().Name,
                                componentsCount,
                                components.Count);
                            continue;
                        }

                        _logger.LogDebug(
                            "Spawning {0} components, SpawnFlags {1}",
                            innerNetObject.GetType().Name,
                            innerNetObject.SpawnFlags);

                        for (var i = 0; i < componentsCount; i++)
                        {
                            var obj = components[i];

                            obj.NetId   = reader.ReadPackedUInt32();
                            obj.OwnerId = ownerClientId;

                            _logger.LogDebug(
                                "- {0}, NetId {1}, OwnerId {2}",
                                obj.GetType().Name,
                                obj.NetId,
                                obj.OwnerId);

                            if (!AddNetObject(obj))
                            {
                                _logger.LogTrace("Failed to AddNetObject, it already exists.");

                                obj.NetId = uint.MaxValue;
                                break;
                            }

                            using var readerSub = reader.ReadMessage();
                            if (readerSub.Length > 0)
                            {
                                await obj.DeserializeAsync(sender, target, readerSub, true);
                            }

                            await OnSpawnAsync(obj);
                        }

                        continue;
                    }

                    _logger.LogError("Couldn't find spawnable object {0}.", objectId);
                    break;
                }

                // Only the host is allowed to despawn objects.
                case GameDataTag.DespawnFlag:
                {
                    var netId = reader.ReadPackedUInt32();
                    if (_allObjectsFast.TryGetValue(netId, out var obj))
                    {
                        if (sender.Client.Id != obj.OwnerId && !sender.IsHost)
                        {
                            _logger.LogWarning(
                                "Player {0} ({1}) tried to send DespawnFlag for {2} but was denied.",
                                sender.Client.Name,
                                sender.Client.Id,
                                netId);
                            return(false);
                        }

                        RemoveNetObject(obj);
                        await OnDestroyAsync(obj);

                        _logger.LogDebug("Destroyed InnerNetObject {0} ({1}), OwnerId {2}", obj.GetType().Name, netId, obj.OwnerId);
                    }
                    else
                    {
                        _logger.LogDebug(
                            "Player {0} ({1}) sent DespawnFlag for unregistered NetId {2}.",
                            sender.Client.Name,
                            sender.Client.Id,
                            netId);
                    }

                    break;
                }

                case GameDataTag.SceneChangeFlag:
                {
                    // Sender is only allowed to change his own scene.
                    var clientId = reader.ReadPackedInt32();
                    if (clientId != sender.Client.Id)
                    {
                        _logger.LogWarning(
                            "Player {0} ({1}) tried to send SceneChangeFlag for another player.",
                            sender.Client.Name,
                            sender.Client.Id);
                        return(false);
                    }

                    sender.Scene = reader.ReadString();

                    _logger.LogTrace("> Scene {0} to {1}", clientId, sender.Scene);
                    break;
                }

                case GameDataTag.ReadyFlag:
                {
                    var clientId = reader.ReadPackedInt32();
                    _logger.LogTrace("> IsReady {0}", clientId);
                    break;
                }

                default:
                {
                    _logger.LogTrace("Bad GameData tag {0}", reader.Tag);
                    break;
                }
                }

                if (sender.Client.Player == null)
                {
                    // Disconnect handler was probably invoked, cancel the rest.
                    return(false);
                }
            }

            return(true);
        }
Esempio n. 4
0
        private ValueTask BroadcastJoinMessage(IMessageWriter message, bool clear, ClientPlayer player)
        {
            Message01JoinGameS2C.SerializeJoin(message, clear, Code, player.Client.Id, HostId);

            return(SendToAllExceptAsync(message, player.Client.Id));
        }
Esempio n. 5
0
        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));
            }

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