public override async ValueTask <bool> HandleRpc(ClientPlayer sender, ClientPlayer?target, RpcCalls call, IMessageReader reader)
        {
            if (!await TestRpc(sender, target, call, Rpcs))
            {
                return(false);
            }

            if (!_playerControl.PlayerInfo.IsImpostor)
            {
                if (await sender.Client.ReportCheatAsync(RpcCalls.EnterVent, $"Client sent {call} as crewmate"))
                {
                    return(false);
                }
            }

            int ventId;

            switch (call)
            {
            case RpcCalls.EnterVent:
                Rpc19EnterVent.Deserialize(reader, out ventId);
                break;

            case RpcCalls.ExitVent:
                Rpc19EnterVent.Deserialize(reader, out ventId);
                break;

            default:
                return(false);
            }

            await _eventManager.CallAsync(new PlayerVentEvent(_game, sender, _playerControl, (VentLocation)ventId, call == RpcCalls.EnterVent));

            return(true);
        }
        public override async ValueTask <bool> HandleRpcAsync(ClientPlayer sender, ClientPlayer?target, RpcCalls call, IMessageReader reader)
        {
            if (!await ValidateOwnership(call, sender) || !await ValidateImpostor(RpcCalls.MurderPlayer, sender, _playerControl.PlayerInfo))
            {
                return(false);
            }

            int ventId;

            switch (call)
            {
            case RpcCalls.EnterVent:
                Rpc19EnterVent.Deserialize(reader, out ventId);
                break;

            case RpcCalls.ExitVent:
                Rpc19EnterVent.Deserialize(reader, out ventId);
                break;

            case RpcCalls.CustomRpc:
                return(await HandleCustomRpc(reader, _game));

            default:
                return(await UnregisteredCall(call, sender));
            }

            await _eventManager.CallAsync(new PlayerVentEvent(_game, sender, _playerControl, (VentLocation)ventId, call == RpcCalls.EnterVent));

            return(true);
        }
        public override async ValueTask <bool> HandleRpcAsync(ClientPlayer sender, ClientPlayer?target, RpcCalls call, IMessageReader reader)
        {
            if (!await ValidateOwnership(call, sender))
            {
                return(false);
            }

            switch (call)
            {
            case RpcCalls.EnterVent:
            case RpcCalls.ExitVent:
                if (!await ValidateImpostor(call, sender, _playerControl.PlayerInfo))
                {
                    return(false);
                }

                int ventId;

                switch (call)
                {
                case RpcCalls.EnterVent:
                    Rpc19EnterVent.Deserialize(reader, out ventId);
                    break;

                case RpcCalls.ExitVent:
                    Rpc20ExitVent.Deserialize(reader, out ventId);
                    break;

                default:
                    throw new ArgumentOutOfRangeException(nameof(call), call, null);
                }

                var vent = Game.GameNet.ShipStatus !.Data.Vents[ventId];

                switch (call)
                {
                case RpcCalls.EnterVent:
                    await _eventManager.CallAsync(new PlayerEnterVentEvent(Game, sender, _playerControl, vent));

                    break;

                case RpcCalls.ExitVent:
                    await _eventManager.CallAsync(new PlayerExitVentEvent(Game, sender, _playerControl, vent));

                    break;
                }

                break;

            case RpcCalls.ClimbLadder:
                Rpc31ClimbLadder.Deserialize(reader, out var ladderId, out var lastClimbLadderSid);
                break;

            default:
                return(await UnregisteredCall(call, sender));
            }

            return(true);
        }