Ejemplo n.º 1
0
    public void StopQueue()
    {
        if (_activeCoroutine != null)
        {
            StopCoroutine(_activeCoroutine);
            _activeCoroutine = null;
        }

        _processing = false;

        coroutineCanceller.ResetCancel();
    }
Ejemplo n.º 2
0
    private IEnumerator ProcessQueueCoroutine()
    {
        CoroutineCanceller.ResetCancel();

        while (_coroutineQueue.Count > 0)
        {
            IEnumerator coroutine = _coroutineQueue.Dequeue();
            if (_bombIDProcessed.Count > 0)
            {
                CurrentBombID = _bombIDProcessed.Dequeue();
            }
            bool result = true;
            while (result)
            {
                try
                {
                    result = coroutine.MoveNext();
                }
                catch
                {
                    result = false;
                }
                if (result)
                {
                    yield return(coroutine.Current);
                }
            }
        }

        _processing      = false;
        _activeCoroutine = null;

        CoroutineCanceller.ResetCancel();
    }
    protected internal override IEnumerator RespondToCommandInternal(string inputCommand)
    {
        inputCommand = inputCommand.Trim();
        if (!inputCommand.StartsWith("press ", StringComparison.InvariantCultureIgnoreCase))
        {
            yield break;
        }
        inputCommand = inputCommand.Substring(6);

        string sequence = "pressing ";

        foreach (Match move in Regex.Matches(inputCommand, @"(\b(red|blue|green|yellow)\b|[rbgy])", RegexOptions.IgnoreCase))
        {
            SimonButton button = _buttons[buttonIndex[move.Value.Substring(0, 1).ToLowerInvariant()]];

            if (button != null)
            {
                yield return(move.Value);

                sequence += move.Value + " ";

                if (CoroutineCanceller.ShouldCancel)
                {
                    CoroutineCanceller.ResetCancel();
                    yield break;
                }

                yield return(DoInteractionClick(button, sequence));
            }
        }
    }
Ejemplo n.º 4
0
    private IEnumerator ProcessQueueCoroutine()
    {
        CoroutineCanceller.ResetCancel();

        while (_coroutineQueue.Count > 0)
        {
            IEnumerator coroutine = _coroutineQueue.Dequeue();
            if (_bombIDProcessed.Count > 0)
            {
                CurrentBombID = _bombIDProcessed.Dequeue();
            }
            bool result = true;
            while (result)
            {
                try
                {
                    result = coroutine.MoveNext();
                }
                catch (Exception e)
                {
                    DebugHelper.LogException(e, "An exception occurred while executing a queued coroutine:");
                    result = false;
                }
                if (result)
                {
                    yield return(coroutine.Current);
                }
            }
        }

        _processing      = false;
        _activeCoroutine = null;

        CoroutineCanceller.ResetCancel();
    }
Ejemplo n.º 5
0
    public static IEnumerator DefaultCommand(TwitchModule module, string user, string cmd)
    {
        if (cmd.RegexMatch(out Match match, @"(?<zoom>zoom *(?<time>\d*\.?\d+)?)? *(?<tilt>tilt *(?<direction>[uptobmdwnlefrigh]+|-?\d+)?)? *(?:send *to *module)? *(?<command>.+)?"))
        {
            var groups  = match.Groups;
            var timed   = groups["time"].Success;
            var zoom    = groups["zoom"].Success;
            var tilt    = groups["tilt"].Success;
            var command = groups["command"].Success;

            // Both a time and a command can't be entered. And either a zoom or tilt needs to take place otherwise, we should let the command run normally.
            if ((!timed || !command) && (zoom || tilt))
            {
                MusicPlayer musicPlayer = null;
                int         delay       = 2;
                if (timed)
                {
                    delay = groups["time"].Value.TryParseInt() ?? 2;
                    delay = Math.Max(2, delay);
                    if (delay >= 15)
                    {
                        musicPlayer = MusicPlayer.StartRandomMusic();
                    }
                }

                object toYield = command ? (object)RunModuleCommand(module, user, groups["command"].Value) : delay;

                IEnumerator routine = null;
                if (tilt)
                {
                    routine = Tilt(module, toYield, groups["direction"].Value);
                }

                if (zoom)
                {
                    routine = Zoom(module, user, routine ?? toYield);
                }

                yield return(routine);

                if (CoroutineCanceller.ShouldCancel)
                {
                    CoroutineCanceller.ResetCancel();
                    IRCConnection.SendMessage($"Sorry @{user}, your request to hold up the bomb for {delay} seconds has been cut short.");
                }

                if (musicPlayer != null)
                {
                    musicPlayer.StopMusic();
                }

                yield break;
            }
        }

        yield return(RunModuleCommand(module, user, cmd));
    }
Ejemplo n.º 6
0
    public static IEnumerator Zoom(TwitchModule module, string user, [Group(1)] float?duration)
    {
        MusicPlayer musicPlayer = null;
        var         delay       = duration ?? 2;

        delay = Math.Max(2, delay);
        module.Solver._zoom = true;
        if (delay >= 15)
        {
            musicPlayer = MusicPlayer.StartRandomMusic();
        }

        var zoomCoroutine = TwitchGame.ModuleCameras?.ZoomCamera(module, 1);

        if (zoomCoroutine != null)
        {
            while (zoomCoroutine.MoveNext())
            {
                yield return(zoomCoroutine.Current);
            }
        }

        yield return(new WaitForSecondsWithCancel(delay, false, module.Solver));

        if (CoroutineCanceller.ShouldCancel)
        {
            CoroutineCanceller.ResetCancel();
            IRCConnection.SendMessage($"Sorry @{user}, your request to hold up the bomb for {delay} seconds has been cut short.");
        }

        if (musicPlayer != null)
        {
            musicPlayer.StopMusic();
        }

        var unzoomCoroutine = TwitchGame.ModuleCameras?.UnzoomCamera(module, 1);

        if (unzoomCoroutine != null)
        {
            while (unzoomCoroutine.MoveNext())
            {
                yield return(unzoomCoroutine.Current);
            }
        }
    }
    private IEnumerator ProcessQueueCoroutine()
    {
        while (_coroutineQueue.Count > 0)
        {
            CoroutineCanceller.ResetCancel();

            IEnumerator coroutine = _coroutineQueue.First.Value;
            if (_bombIDProcessed.Count > 0)
            {
                CurrentBombID = _bombIDProcessed.Dequeue();
            }

            yield return(ProcessCoroutine(coroutine));

            _coroutineQueue.RemoveFirst();
        }

        _processing      = false;
        _activeCoroutine = null;

        CoroutineCanceller.ResetCancel();
    }
Ejemplo n.º 8
0
    public static IEnumerator DefaultCommand(TwitchModule module, string user, string cmd)
    {
        if ((Votes.Active && Votes.CurrentVoteType == VoteTypes.Solve && Votes.voteModule == module) || module.Votesolving)
        {
            IRCConnection.SendMessage($"Sorry @{user}, the module you are trying to interact with is being votesolved.");
            yield break;
        }
        if (cmd.RegexMatch(out Match match, @"(?:(?<zoom>zoom *(?<time>\d*\.?\d+)?)|(?<superzoom>superzoom *(?<factor>\d*\.?\d+) *(?<x>\d*\.?\d+)? *(?<y>\d*\.?\d+)? *(?<stime>\d*\.?\d+)?))? *(?:(?<tilt>tilt *(?<direction>[uptobmdwnlefrigh]+|-?\d+)?)|(?<show>show)?)? *(?:send *to *module)? *(?<command>.+)?"))
        {
            var groups  = match.Groups;
            var timed   = groups["time"].Success || groups["stime"].Success;
            var zooming = groups["zoom"].Success || groups["superzoom"].Success;
            var tilt    = groups["tilt"].Success;
            var show    = groups["show"].Success;
            var command = groups["command"].Success;

            if (!timed && !zooming && !command && show)
            {
                yield return(Show(module, 0.5));

                yield break;
            }
            // Both a time and a command can't be entered. And either a zoom, show or tilt needs to take place otherwise, we should let the command run normally.
            if ((!timed || !command) && (zooming || tilt || show))
            {
                MusicPlayer musicPlayer = null;
                float       delay       = 2;
                if (timed)
                {
                    delay = groups["time"].Value.TryParseInt() ?? groups["stime"].Value.TryParseInt() ?? 2;
                    delay = Math.Max(2, delay);
                }

                object toYield = command ? (object)RunModuleCommand(module, user, groups["command"].Value) : delay;

                IEnumerator routine = null;
                if (show)
                {
                    routine = Show(module, toYield);
                }
                if (tilt)
                {
                    routine = Tilt(module, toYield, groups["direction"].Value.ToLowerInvariant());
                }

                if (zooming)
                {
                    var zoomData = new SuperZoomData(
                        groups["factor"].Value.TryParseFloat() ?? 1,
                        groups["x"].Value.TryParseFloat() ?? 0.5f,
                        groups["y"].Value.TryParseFloat() ?? 0.5f
                        );
                    routine = Zoom(module, zoomData, routine ?? toYield);
                }

                if (delay >= 15)
                {
                    musicPlayer = MusicPlayer.StartRandomMusic();
                }

                yield return(routine);

                if (CoroutineCanceller.ShouldCancel)
                {
                    CoroutineCanceller.ResetCancel();
                    IRCConnection.SendMessage($"Sorry @{user}, your request to hold up the bomb for {delay} seconds has been cut short.");
                }

                if (musicPlayer != null)
                {
                    musicPlayer.StopMusic();
                }

                yield break;
            }
        }

        yield return(RunModuleCommand(module, user, cmd));
    }
Ejemplo n.º 9
0
    public IEnumerator RespondToCommand(string userNickName, string message)
    {
        DisableOnStrike      = false;
        Strike               = false;
        StrikeCount          = 0;
        _currentUserNickName = userNickName;

        FloatingHoldable.HoldStateEnum holdState = Holdable.HoldState;

        if (holdState == FloatingHoldable.HoldStateEnum.Held)
        {
        }
        else
        {
            IEnumerator holdCoroutine = HoldableCommander.Hold();
            while (holdCoroutine.MoveNext() && !Strike)
            {
                yield return(holdCoroutine.Current);
            }
        }

        IEnumerator processCommand = RespondToCommandCommon(message);

        if (processCommand == null || !processCommand.MoveNext())
        {
            DebugHelper.Log("Running RespondToCommandInternal()");
            processCommand = RespondToCommandInternal(message);
            bool cancelled  = false;
            bool parseError = false;
            bool cancelling = false;

            if (processCommand == null || !processCommand.MoveNext())
            {
                if (!Strike)
                {
                    SendToChat(null, userNickName, ref parseError);
                }
            }
            else
            {
                processIEnumerators.Push(processCommand);
                processIEnumerators.Push(FirstItem(processCommand.Current));
            }

            do
            {
                try
                {
                    bool result = false;
                    while (!result && !Strike)
                    {
                        if (processIEnumerators.Count > 0)
                        {
                            processCommand = processIEnumerators.Pop();
                            result         = processCommand.MoveNext();
                            if (result)
                            {
                                processIEnumerators.Push(processCommand);
                            }
                        }
                        else
                        {
                            break;
                        }
                    }
                    if (Strike)
                    {
                        DebugHelper.Log("A strike was caused by the command. Invocation will not continue.");
                    }
                    if (!result || Strike)
                    {
                        break;
                    }
                }
                catch (Exception ex)
                {
                    DebugHelper.LogException(ex, "Error Processing command due to an exception. Invocation will not continue.:");
                    break;
                }

                switch (processCommand.Current)
                {
                case IEnumerator iEnumerator:
                    if (iEnumerator != null)
                    {
                        processIEnumerators.Push(iEnumerator);
                    }
                    continue;

                case KMSelectable kmSelectable when kmSelectable != null:
                    if (heldSelectables.Contains(kmSelectable))
                    {
                        DoInteractionEnd(kmSelectable);
                        heldSelectables.Remove(kmSelectable);
                    }
                    else
                    {
                        DoInteractionStart(kmSelectable);
                        heldSelectables.Add(kmSelectable);
                    }
                    break;

                case KMSelectable[] kmSelectables:
                    foreach (KMSelectable selectable in kmSelectables)
                    {
                        if (selectable != null)
                        {
                            yield return(DoInteractionClick(selectable));

                            if (Strike)
                            {
                                break;
                            }
                        }
                        else
                        {
                            yield return(new WaitForSeconds(0.1f));
                        }
                    }
                    break;

                case Quaternion quaternion:
                    HoldableCommander.RotateByLocalQuaternion(quaternion);
                    break;

                case string currentString when !string.IsNullOrEmpty(currentString):
                    if (currentString.Equals("trycancel", StringComparison.InvariantCultureIgnoreCase) &&
                        CoroutineCanceller.ShouldCancel)
                    {
                        CoroutineCanceller.ResetCancel();
                        cancelled = true;
                    }
                    else if (currentString.ToLowerInvariant().EqualsAny("elevator music", "hold music", "waiting music"))
                    {
                        if (_musicPlayer == null)
                        {
                            _musicPlayer = MusicPlayer.StartRandomMusic();
                        }
                    }
                    else if (currentString.ToLowerInvariant().Equals("cancelled") && cancelling)
                    {
                        CancelBool?.SetValue(CommandComponent, false);
                        CoroutineCanceller.ResetCancel();
                        cancelled = true;
                    }
                    else if (currentString.StartsWith("strikemessage ", StringComparison.InvariantCultureIgnoreCase) &&
                             currentString.Substring(14).Trim() != string.Empty)
                    {
                        StrikeMessage = currentString.Substring(14);
                    }
                    else if (currentString.Equals("strike", StringComparison.InvariantCultureIgnoreCase))
                    {
                        _delegatedStrikeUserNickName = _currentUserNickName;
                    }
                    else if (currentString.Equals("multiple strikes", StringComparison.InvariantCultureIgnoreCase))
                    {
                        DisableOnStrike = true;
                    }
                    else if (currentString.ToLowerInvariant().EqualsAny("detonate", "explode") && BombMessageResponder.BombActive)
                    {
                        BombCommander BombCommander = BombMessageResponder.Instance.BombCommanders[0];
                        AwardStrikes(_currentUserNickName, BombCommander.StrikeLimit - BombCommander.StrikeCount);
                        BombCommander.twitchBombHandle.CauseExplosionByModuleCommand(string.Empty, HoldableCommander.ID);
                        Strike = true;
                    }
                    else if (currentString.ToLowerInvariant().Equals("show front"))
                    {
                        processIEnumerators.Push(HoldableCommander.Hold(true));
                    }
                    else if (currentString.ToLowerInvariant().Equals("show back"))
                    {
                        processIEnumerators.Push(HoldableCommander.Hold(false));
                    }
                    else
                    {
                        SendToChat(currentString, userNickName, ref parseError);
                    }
                    break;

                case string[] currentStrings:
                    if (currentStrings.Length >= 1)
                    {
                        if (currentStrings[0].ToLowerInvariant().EqualsAny("detonate", "explode") && BombMessageResponder.BombActive)
                        {
                            BombCommander BombCommander = BombMessageResponder.Instance.BombCommanders[0];
                            AwardStrikes(_currentUserNickName, BombCommander.StrikeLimit - BombCommander.StrikeCount);
                            switch (currentStrings.Length)
                            {
                            case 2:
                                BombCommander.twitchBombHandle.CauseExplosionByModuleCommand(currentStrings[1], HoldableCommander.ID);
                                break;

                            case 3:
                                BombCommander.twitchBombHandle.CauseExplosionByModuleCommand(currentStrings[1], currentStrings[2]);
                                break;

                            default:
                                BombCommander.twitchBombHandle.CauseExplosionByModuleCommand(string.Empty, HoldableCommander.ID);
                                break;
                            }
                            break;
                        }
                    }
                    break;

                case Dictionary <string, bool> permissions:
                    foreach (KeyValuePair <string, bool> pair in permissions)
                    {
                        if (TwitchPlaySettings.data.ModPermissions.ContainsKey(pair.Key))
                        {
                            continue;
                        }
                        TwitchPlaySettings.data.ModPermissions.Add(pair.Key, pair.Value);
                        TwitchPlaySettings.WriteDataToFile();
                    }
                    break;

                case KMMission mission:
                    MiscellaneousMessageResponder.Instance.RunMission(mission);
                    break;

                case object[] objects:
                    if (objects == null)
                    {
                        break;
                    }
                    switch (objects.Length)
                    {
                    case 3 when objects[0] is string objstr:
                        if (IsAskingPermission(objstr, userNickName, out bool permissionGranted))
                        {
                            if (permissionGranted)
                            {
                                switch (objects[1])
                                {
                                case Action actionTrue:
                                    actionTrue.Invoke();
                                    break;

                                case IEnumerator iEnumerator when iEnumerator != null:
                                    processIEnumerators.Push(iEnumerator);
                                    yield return(null);

                                    continue;
                                }
                            }
                            else
                            {
                                switch (objects[2])
                                {
                                case Action actionFalse:
                                    actionFalse.Invoke();
                                    break;

                                case string objStr2 when !string.IsNullOrEmpty(objStr2):
                                    SendToChat(objStr2, userNickName, ref parseError);
                                    break;

                                case IEnumerator iEnumerator when iEnumerator != null:
                                    processIEnumerators.Push(iEnumerator);
                                    yield return(null);

                                    continue;
                                }
                            }
                        }
                        break;
                    }
                    break;
Ejemplo n.º 10
0
    public IEnumerator RespondToCommand(string userNickName, string message)
    {
        TryCancel  = false;
        _responded = false;
        _zoom      = false;
        _processingTwitchCommand = true;
        if (Solved)
        {
            _processingTwitchCommand = false;
            yield break;
        }

        _currentUserNickName = userNickName;

        int beforeStrikeCount = StrikeCount;

        IEnumerator subcoroutine = null;

        if (message.StartsWith("send to module ", StringComparison.InvariantCultureIgnoreCase))
        {
            message = message.Substring(15);
        }
        else
        {
            subcoroutine = RespondToCommandCommon(message, userNickName);
        }

        if (subcoroutine == null || !subcoroutine.MoveNext())
        {
            if (_responded)
            {
                yield break;
            }

            if (_zoom)
            {
                message = message.Substring(4).Trim();
            }

            try
            {
                subcoroutine = RespondToCommandInternal(message);
            }
            catch (Exception e)
            {
                HandleModuleException(e);
                yield break;
            }

            bool moved = false;
            if (subcoroutine != null)
            {
                try
                {
                    moved = subcoroutine.MoveNext();
                    if (moved && modInfo.DoesTheRightThing)
                    {
                        //Handle No-focus API commands. In order to focus the module, the first thing yielded cannot be one of the things handled here, as the solver will yield break if
                        //it is one of these API commands returned.
                        switch (subcoroutine.Current)
                        {
                        case string currentString:
                            if (SendToTwitchChat(currentString, userNickName) && !currentString.StartsWith("strikemessage", StringComparison.InvariantCultureIgnoreCase))
                            {
                                yield break;
                            }
                            break;
                        }
                        _responded = true;
                    }
                }
                catch (Exception e)
                {
                    HandleModuleException(e);
                    yield break;
                }
            }

            if (subcoroutine == null || !moved || Solved || beforeStrikeCount != StrikeCount)
            {
                if (Solved || beforeStrikeCount != StrikeCount)
                {
                    IRCConnection.Instance.SendMessage("Please submit an issue at https://github.com/samfun123/KtaneTwitchPlays/issues regarding module !{0} ({1}) attempting to solve prematurely.", ComponentHandle.Code, ComponentHandle.HeaderText);
                    if (modInfo != null)
                    {
                        modInfo.DoesTheRightThing = false;
                        ModuleData.DataHasChanged = true;
                        ModuleData.WriteDataToFile();
                    }

                    IEnumerator focusDefocus = BombCommander.Focus(Selectable, FocusDistance, FrontFace);
                    while (focusDefocus.MoveNext())
                    {
                        yield return(focusDefocus.Current);
                    }
                    yield return(new WaitForSeconds(0.5f));

                    focusDefocus = BombCommander.Defocus(Selectable, FrontFace);
                    while (focusDefocus.MoveNext())
                    {
                        yield return(focusDefocus.Current);
                    }
                    yield return(new WaitForSeconds(0.5f));
                }
                else if (!_responded)
                {
                    ComponentHandle.CommandInvalid(userNickName);
                }

                _currentUserNickName     = null;
                _processingTwitchCommand = false;
                yield break;
            }
        }

        IEnumerator focusCoroutine = BombCommander.Focus(Selectable, FocusDistance, FrontFace);

        while (focusCoroutine.MoveNext())
        {
            yield return(focusCoroutine.Current);
        }

        yield return(new WaitForSeconds(0.5f));

        IEnumerator unzoom = null;

        if (_zoom)
        {
            IEnumerator zoom = BombMessageResponder.moduleCameras?.ZoomCamera(BombComponent, 1);
            unzoom = BombMessageResponder.moduleCameras?.UnzoomCamera(BombComponent, 1);
            if (zoom == null || unzoom == null)
            {
                _zoom = false;
            }
            else
            {
                while (zoom.MoveNext())
                {
                    yield return(zoom.Current);
                }
            }
        }

        int  previousStrikeCount = StrikeCount;
        bool parseError          = false;
        bool needQuaternionReset = false;
        bool hideCamera          = false;
        bool exceptionThrown     = false;
        bool trycancelsequence   = false;

        while ((previousStrikeCount == StrikeCount && !Solved) || DisableOnStrike)
        {
            try
            {
                if (!subcoroutine.MoveNext())
                {
                    break;
                }
                else
                {
                    _responded = true;
                }
            }
            catch (Exception e)
            {
                exceptionThrown = true;
                HandleModuleException(e);
                break;
            }

            object currentValue = subcoroutine.Current;
            if (currentValue is string currentString)
            {
                if (currentString.Equals("strike", StringComparison.InvariantCultureIgnoreCase))
                {
                    _delegatedStrikeUserNickName = userNickName;
                }
                else if (currentString.Equals("solve", StringComparison.InvariantCultureIgnoreCase))
                {
                    _delegatedSolveUserNickName = userNickName;
                }
                else if (currentString.Equals("unsubmittablepenalty", StringComparison.InvariantCultureIgnoreCase))
                {
                    if (TwitchPlaySettings.data.UnsubmittablePenaltyPercent <= 0)
                    {
                        continue;
                    }

                    int penalty = Math.Max((int)(modInfo.moduleScore * TwitchPlaySettings.data.UnsubmittablePenaltyPercent), 1);
                    Leaderboard.Instance.AddScore(_currentUserNickName, -penalty);
                    IRCConnection.Instance.SendMessage(TwitchPlaySettings.data.UnsubmittableAnswerPenalty, _currentUserNickName, Code, modInfo.moduleDisplayName, penalty, penalty > 1 ? "s" : "");
                }
                else if (currentString.Equals("parseerror", StringComparison.InvariantCultureIgnoreCase))
                {
                    parseError = true;
                    break;
                }
                else if (currentString.RegexMatch(out Match match, "^trycancel((?: (?:.|\\n)+)?)$"))
                {
                    if (CoroutineCanceller.ShouldCancel)
                    {
                        CoroutineCanceller.ResetCancel();
                        if (!string.IsNullOrEmpty(match.Groups[1].Value))
                        {
                            IRCConnection.Instance.SendMessage($"Sorry @{userNickName}, {match.Groups[1].Value.Trim()}");
                        }
                        break;
                    }
                }
                else if (currentString.RegexMatch(out match, "^trycancelsequence((?: (?:.|\\n)+)?)$"))
                {
                    trycancelsequence = true;
                    yield return(currentValue);

                    continue;
                }
                else if (currentString.RegexMatch(out match, "^trywaitcancel ([0-9]+(?:\\.[0-9])?)((?: (?:.|\\n)+)?)$") && float.TryParse(match.Groups[1].Value, out float waitCancelTime))
                {
                    yield return(new WaitForSecondsWithCancel(waitCancelTime, false));

                    if (CoroutineCanceller.ShouldCancel)
                    {
                        CoroutineCanceller.ResetCancel();
                        if (!string.IsNullOrEmpty(match.Groups[2].Value))
                        {
                            IRCConnection.Instance.SendMessage($"Sorry @{userNickName}, {match.Groups[2].Value.Trim()}");
                        }
                        break;
                    }
                }
                // Commands that allow messages to be sent to the chat.
                else if (SendToTwitchChat(currentString, userNickName))
                {
                    //handled
                }
                else if (currentString.StartsWith("add strike", StringComparison.InvariantCultureIgnoreCase))
                {
                    OnStrike(null);
                }
                else if (currentString.Equals("multiple strikes", StringComparison.InvariantCultureIgnoreCase))
                {
                    DisableOnStrike = true;
                }
                else if (currentString.Equals("end multiple strikes", StringComparison.InvariantCultureIgnoreCase))
                {
                    if (previousStrikeCount == StrikeCount)
                    {
                        DisableOnStrike = false;
                        if (Solved)
                        {
                            OnPass(null);
                        }
                    }
                    else
                    {
                        break;
                    }
                }
                else if (currentString.StartsWith("autosolve", StringComparison.InvariantCultureIgnoreCase))
                {
                    HandleModuleException(new Exception(currentString));
                    break;
                }
                else if (currentString.ToLowerInvariant().EqualsAny("detonate", "explode"))
                {
                    AwardStrikes(_currentUserNickName, BombCommander.StrikeLimit - BombCommander.StrikeCount);
                    BombCommander.twitchBombHandle.CauseExplosionByModuleCommand(string.Empty, modInfo.moduleDisplayName);
                    break;
                }
                else if (currentString.RegexMatch(out match, "^(end |toggle )?(?:elevator|hold|waiting) music$"))
                {
                    if (match.Groups.Count > 1 && _musicPlayer != null)
                    {
                        _musicPlayer.StopMusic();
                        _musicPlayer = null;
                    }
                    else if (!currentString.StartsWith("end ", StringComparison.InvariantCultureIgnoreCase) && _musicPlayer == null)
                    {
                        _musicPlayer = MusicPlayer.StartRandomMusic();
                    }
                }
                else if (currentString.ToLowerInvariant().Equals("hide camera"))
                {
                    if (!hideCamera)
                    {
                        BombMessageResponder.moduleCameras?.Hide();
                        BombMessageResponder.moduleCameras?.HideHUD();
                        IEnumerator hideUI = BombCommander.twitchBombHandle.HideMainUIWindow();
                        while (hideUI.MoveNext())
                        {
                            yield return(hideUI.Current);
                        }
                    }
                    hideCamera = true;
                }
                else if (currentString.Equals("cancelled", StringComparison.InvariantCultureIgnoreCase) && CoroutineCanceller.ShouldCancel)
                {
                    CoroutineCanceller.ResetCancel();
                    TryCancel = false;
                    break;
                }
                else
                {
                    if (TwitchPlaySettings.data.EnableDebuggingCommands)
                    {
                        DebugHelper.Log($"Unprocessed string: {currentString}");
                    }
                }
            }
            else if (currentValue is KMSelectable selectable1)
            {
                if (HeldSelectables.Contains(selectable1))
                {
                    DoInteractionEnd(selectable1);
                    HeldSelectables.Remove(selectable1);
                }
                else
                {
                    DoInteractionStart(selectable1);
                    HeldSelectables.Add(selectable1);
                }
            }
            else if (currentValue is IList <KMSelectable> selectables)
            {
                foreach (KMSelectable selectable in selectables)
                {
                    yield return(DoInteractionClick(selectable));

                    if ((previousStrikeCount != StrikeCount && !DisableOnStrike) || Solved || (trycancelsequence && CoroutineCanceller.ShouldCancel))
                    {
                        break;
                    }
                }
                if (trycancelsequence && CoroutineCanceller.ShouldCancel)
                {
                    CoroutineCanceller.ResetCancel();
                    break;
                }
            }
            else if (currentValue is Quaternion localQuaternion)
            {
                BombCommander.RotateByLocalQuaternion(localQuaternion);
                //Whitelist perspective pegs as it only returns Quaternion.Euler(x, 0, 0), which is compatible with the RotateCamaraByQuaternion.
                if (BombComponent.GetComponent <KMBombModule>()?.ModuleType.Equals("spwizPerspectivePegs") ?? false)
                {
                    BombCommander.RotateCameraByLocalQuaternion(BombComponent, localQuaternion);
                }
                needQuaternionReset = true;
            }
            else if (currentValue is Quaternion[] localQuaternions)
            {
                if (localQuaternions.Length == 2)
                {
                    BombCommander.RotateByLocalQuaternion(localQuaternions[0]);
                    BombCommander.RotateCameraByLocalQuaternion(BombComponent, localQuaternions[1]);
                    needQuaternionReset = true;
                }
            }
            else if (currentValue is string[] currentStrings)
            {
                if (currentStrings.Length >= 1)
                {
                    if (currentStrings[0].ToLowerInvariant().EqualsAny("detonate", "explode"))
                    {
                        AwardStrikes(_currentUserNickName, BombCommander.StrikeLimit - BombCommander.StrikeCount);
                        switch (currentStrings.Length)
                        {
                        case 2:
                            BombCommander.twitchBombHandle.CauseExplosionByModuleCommand(currentStrings[1], modInfo.moduleDisplayName);
                            break;

                        case 3:
                            BombCommander.twitchBombHandle.CauseExplosionByModuleCommand(currentStrings[1], currentStrings[2]);
                            break;

                        default:
                            BombCommander.twitchBombHandle.CauseExplosionByModuleCommand(string.Empty, modInfo.moduleDisplayName);
                            break;
                        }
                        break;
                    }
                }
            }
            yield return(currentValue);

            if (CoroutineCanceller.ShouldCancel)
            {
                TryCancel = true;
            }

            trycancelsequence = false;
        }

        if (!_responded && !exceptionThrown)
        {
            ComponentHandle.CommandInvalid(userNickName);
        }

        if (needQuaternionReset)
        {
            BombCommander.RotateByLocalQuaternion(Quaternion.identity);
            BombCommander.RotateCameraByLocalQuaternion(BombComponent, Quaternion.identity);
        }

        if (hideCamera)
        {
            BombMessageResponder.moduleCameras?.Show();
            BombMessageResponder.moduleCameras?.ShowHUD();
            IEnumerator showUI = BombCommander.twitchBombHandle.ShowMainUIWindow();
            while (showUI.MoveNext())
            {
                yield return(showUI.Current);
            }
        }

        if (_musicPlayer != null)
        {
            _musicPlayer.StopMusic();
            _musicPlayer = null;
        }

        if (DisableOnStrike)
        {
            DisableOnStrike = false;
            BombMessageResponder.moduleCameras?.UpdateStrikes(true);
            if (Solved)
            {
                OnPass(null);
            }
            AwardStrikes(_currentUserNickName, StrikeCount - previousStrikeCount);
        }

        if (!parseError)
        {
            yield return(new WaitForSeconds(0.5f));
        }

        if (_zoom)
        {
            while (unzoom?.MoveNext() ?? false)
            {
                yield return(unzoom.Current);
            }
        }

        IEnumerator defocusCoroutine = BombCommander.Defocus(Selectable, FrontFace);

        while (defocusCoroutine.MoveNext())
        {
            yield return(defocusCoroutine.Current);
        }

        yield return(new WaitForSeconds(0.5f));

        _currentUserNickName     = null;
        _processingTwitchCommand = false;
    }