protected override void OnMessageReceived(string userNickName, string userColorCode, string text)
    {
        if (text.EqualsAny("!notes1", "!notes2", "!notes3", "!notes4"))
        {
            int index = "1234".IndexOf(text.Substring(6, 1), StringComparison.Ordinal);
            _ircConnection.SendMessage(TwitchPlaySettings.data.Notes, index + 1, _notes[index]);
            return;
        }

        if (text.StartsWith("!notes1 ", StringComparison.InvariantCultureIgnoreCase) || text.StartsWith("!notes2 ", StringComparison.InvariantCultureIgnoreCase) ||
            text.StartsWith("!notes3 ", StringComparison.InvariantCultureIgnoreCase) || text.StartsWith("!notes4 ", StringComparison.InvariantCultureIgnoreCase))
        {
            if (!IsAuthorizedDefuser(userNickName))
            {
                return;
            }
            int    index = "1234".IndexOf(text.Substring(6, 1), StringComparison.Ordinal);
            string notes = text.Substring(8);
            if (notes == "")
            {
                return;
            }

            _ircConnection.SendMessage(TwitchPlaySettings.data.NotesTaken, index + 1, notes);

            _notes[index] = notes;
            moduleCameras?.SetNotes(index, notes);
            return;
        }

        if (text.StartsWith("!appendnotes1 ", StringComparison.InvariantCultureIgnoreCase) || text.StartsWith("!appendnotes2 ", StringComparison.InvariantCultureIgnoreCase) ||
            text.StartsWith("!appendnotes3 ", StringComparison.InvariantCultureIgnoreCase) || text.StartsWith("!appendnotes4 ", StringComparison.InvariantCultureIgnoreCase))
        {
            text = text.Substring(0, 1) + text.Substring(7, 6) + text.Substring(1, 6) + text.Substring(13);
        }

        if (text.StartsWith("!notes1append ", StringComparison.InvariantCultureIgnoreCase) || text.StartsWith("!notes2append ", StringComparison.InvariantCultureIgnoreCase) ||
            text.StartsWith("!notes3append ", StringComparison.InvariantCultureIgnoreCase) || text.StartsWith("!notes4append ", StringComparison.InvariantCultureIgnoreCase))
        {
            if (!IsAuthorizedDefuser(userNickName))
            {
                return;
            }
            int    index = "1234".IndexOf(text.Substring(6, 1), StringComparison.Ordinal);
            string notes = text.Substring(14);
            if (notes == "")
            {
                return;
            }

            _ircConnection.SendMessage(TwitchPlaySettings.data.NotesAppended, index + 1, notes);

            _notes[index] += " " + notes;
            moduleCameras?.AppendNotes(index, notes);
            return;
        }

        if (text.EqualsAny("!clearnotes1", "!clearnotes2", "!clearnotes3", "!clearnotes4"))
        {
            text = text.Substring(0, 1) + text.Substring(6, 6) + text.Substring(1, 5);
        }

        if (text.EqualsAny("!notes1clear", "!notes2clear", "!notes3clear", "!notes4clear"))
        {
            if (!IsAuthorizedDefuser(userNickName))
            {
                return;
            }
            int index = "1234".IndexOf(text.Substring(6, 1), StringComparison.Ordinal);
            _notes[index] = TwitchPlaySettings.data.NotesSpaceFree;
            _ircConnection.SendMessage(TwitchPlaySettings.data.NoteSlotCleared, index + 1);

            moduleCameras?.SetNotes(index, TwitchPlaySettings.data.NotesSpaceFree);
            return;
        }

        if (text.Equals("!snooze", StringComparison.InvariantCultureIgnoreCase))
        {
            if (!IsAuthorizedDefuser(userNickName))
            {
                return;
            }
            if (TwitchPlaySettings.data.AllowSnoozeOnly)
            {
                alarmClock.TurnOff();
            }
            else
            {
                alarmClock.ButtonDown(0);
            }
            return;
        }

        if (text.Equals("!stop", StringComparison.InvariantCultureIgnoreCase))
        {
            if (!IsAuthorizedDefuser(userNickName, true))
            {
                return;
            }
            _currentBomb = _coroutineQueue.CurrentBombID;
            return;
        }

        if (text.Equals("!modules", StringComparison.InvariantCultureIgnoreCase))
        {
            if (!IsAuthorizedDefuser(userNickName))
            {
                return;
            }
            moduleCameras?.AttachToModules(_componentHandles);
            return;
        }

        if (text.StartsWith("!claims ", StringComparison.InvariantCultureIgnoreCase))
        {
            if (!IsAuthorizedDefuser(userNickName))
            {
                return;
            }
            userNickName = text.Substring(8);
            text         = "!claims";
            if (userNickName == "")
            {
                return;
            }
        }

        if (text.Equals("!claims", StringComparison.InvariantCultureIgnoreCase))
        {
            if (!IsAuthorizedDefuser(userNickName))
            {
                return;
            }
            List <string> claimed = (from handle in _componentHandles where handle.PlayerName != null && handle.PlayerName.Equals(userNickName, StringComparison.InvariantCultureIgnoreCase) && !handle.Solved select string.Format(TwitchPlaySettings.data.OwnedModule, handle.idText.text.Replace("!", ""), handle.headerText.text)).ToList();
            if (claimed.Count > 0)
            {
                string message = string.Format(TwitchPlaySettings.data.OwnedModuleList, userNickName, string.Join(", ", claimed.ToArray(), 0, Math.Min(claimed.Count, 5)));
                if (claimed.Count > 5)
                {
                    message += "...";
                }
                _ircConnection.SendMessage(message);
            }
            else
            {
                _ircConnection.SendMessage(TwitchPlaySettings.data.NoOwnedModules, userNickName);
            }
            return;
        }

        if (text.StartsWith("!claim ", StringComparison.InvariantCultureIgnoreCase))
        {
            var split = text.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
            foreach (var claim in split.Skip(1))
            {
                TwitchComponentHandle handle = _componentHandles.FirstOrDefault(x => x.Code.Equals(claim));
                if (handle == null || !GameRoom.Instance.IsCurrentBomb(handle.bombID))
                {
                    continue;
                }
                handle.OnMessageReceived(userNickName, userColorCode, string.Format("!{0} claim", claim));
            }
            return;
        }

        if (text.EqualsAny("!unclaim all", "!release all", "!unclaimall", "!releaseall"))
        {
            string[] moduleIDs = _componentHandles.Where(x => x.PlayerName != null && x.PlayerName.Equals(userNickName, StringComparison.InvariantCultureIgnoreCase))
                                 .Select(x => x.Code).ToArray();
            text = string.Format("!unclaim {0}", string.Join(" ", moduleIDs));
        }

        if (text.StartsWith("!unclaim ", StringComparison.InvariantCultureIgnoreCase) || text.StartsWith("!release ", StringComparison.InvariantCultureIgnoreCase))
        {
            var split = text.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
            foreach (var claim in split.Skip(1))
            {
                TwitchComponentHandle handle = _componentHandles.FirstOrDefault(x => x.Code.Equals(claim));
                if (handle == null || !GameRoom.Instance.IsCurrentBomb(handle.bombID))
                {
                    continue;
                }
                handle.OnMessageReceived(userNickName, userColorCode, string.Format("!{0} unclaim", claim));
            }
            return;
        }



        if (text.Equals("!unclaimed", StringComparison.InvariantCultureIgnoreCase))
        {
            if (!IsAuthorizedDefuser(userNickName))
            {
                return;
            }

            IEnumerable <string> unclaimed = _componentHandles.Where(handle => !handle.claimed && !handle.Solved && GameRoom.Instance.IsCurrentBomb(handle.bombID)).Shuffle().Take(3)
                                             .Select(handle => string.Format("{0} ({1})", handle.headerText.text, handle.Code)).ToList();

            if (unclaimed.Any())
            {
                _ircConnection.SendMessage("Unclaimed Modules: {0}", unclaimed.Join(", "));
            }
            else
            {
                _ircConnection.SendMessage("There are no more unclaimed modules.");
            }

            return;
        }

        if (text.StartsWith("!find ", StringComparison.InvariantCultureIgnoreCase) || text.StartsWith("!search ", StringComparison.InvariantCultureIgnoreCase))
        {
            if (!IsAuthorizedDefuser(userNickName))
            {
                return;
            }

            var    split = text.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
            string query = split.Skip(1).Join(" ");
            IEnumerable <string> modules = _componentHandles.Where(handle => handle.headerText.text.ContainsIgnoreCase(query) && GameRoom.Instance.IsCurrentBomb(handle.bombID))
                                           .OrderByDescending(handle => handle.headerText.text.EqualsIgnoreCase(query)).ThenBy(handle => handle.Solved).ThenBy(handle => handle.PlayerName != null).Take(3)
                                           .Select(handle => string.Format("{0} ({1}) - {2}", handle.headerText.text, handle.Code,
                                                                           handle.Solved ? "Solved" : (handle.PlayerName == null ? "Unclaimed" : "Claimed by " + handle.PlayerName)
                                                                           )).ToList();

            if (modules.Any())
            {
                _ircConnection.SendMessage("Modules: {0}", modules.Join(", "));
            }
            else
            {
                _ircConnection.SendMessage("Couldn't find any modules containing \"{0}\".", query);
            }

            return;
        }

        if (text.Equals("!filledgework", StringComparison.InvariantCultureIgnoreCase) && UserAccess.HasAccess(userNickName, AccessLevel.Mod, true))
        {
            foreach (var commander in _bombCommanders)
            {
                commander.FillEdgework(_currentBomb != commander.twitchBombHandle.bombID);
            }
            return;
        }

        if (text.StartsWith("!setmultiplier", StringComparison.InvariantCultureIgnoreCase) && UserAccess.HasAccess(userNickName, AccessLevel.SuperUser, true))
        {
            float tempNumber = float.Parse(text.Substring(15));
            OtherModes.setMultiplier(tempNumber);
        }

        if (text.Equals("!solvebomb", StringComparison.InvariantCultureIgnoreCase) && UserAccess.HasAccess(userNickName, AccessLevel.SuperUser, true))
        {
            foreach (var handle in _componentHandles.Where(x => GameRoom.Instance.IsCurrentBomb(x.bombID)))
            {
                if (!handle.Solved)
                {
                    handle.SolveSilently();
                }
            }
            return;
        }

        GameRoom.Instance.RefreshBombID(ref _currentBomb);

        if (_currentBomb > -1)
        {
            //Check for !bomb messages, and pass them off to the currently held bomb.
            Match match = Regex.Match(text, "^!bomb (.+)", RegexOptions.IgnoreCase);
            if (match.Success)
            {
                string internalCommand = match.Groups[1].Value;
                text = string.Format("!bomb{0} {1}", _currentBomb + 1, internalCommand);
            }

            match = Regex.Match(text, "^!edgework$");
            if (match.Success)
            {
                text = string.Format("!edgework{0}", _currentBomb + 1);
            }
            else
            {
                match = Regex.Match(text, "^!edgework (.+)");
                if (match.Success)
                {
                    string internalCommand = match.Groups[1].Value;
                    text = string.Format("!edgework{0} {1}", _currentBomb + 1, internalCommand);
                }
            }
        }

        foreach (TwitchBombHandle handle in _bombHandles)
        {
            if (handle == null)
            {
                continue;
            }
            IEnumerator onMessageReceived = handle.OnMessageReceived(userNickName, userColorCode, text);
            if (onMessageReceived == null)
            {
                continue;
            }

            if (_currentBomb != handle.bombID)
            {
                if (!GameRoom.Instance.IsCurrentBomb(handle.bombID))
                {
                    continue;
                }

                _coroutineQueue.AddToQueue(_bombHandles[_currentBomb].HideMainUIWindow(), handle.bombID);
                _coroutineQueue.AddToQueue(handle.ShowMainUIWindow(), handle.bombID);
                _coroutineQueue.AddToQueue(_bombCommanders[_currentBomb].LetGoBomb(), handle.bombID);

                _currentBomb = handle.bombID;
            }
            _coroutineQueue.AddToQueue(onMessageReceived, handle.bombID);
        }

        foreach (TwitchComponentHandle componentHandle in _componentHandles)
        {
            if (!GameRoom.Instance.IsCurrentBomb(componentHandle.bombID))
            {
                continue;
            }
            IEnumerator onMessageReceived = componentHandle.OnMessageReceived(userNickName, userColorCode, text);
            if (onMessageReceived == null)
            {
                continue;
            }

            if (_currentBomb != componentHandle.bombID)
            {
                _coroutineQueue.AddToQueue(_bombHandles[_currentBomb].HideMainUIWindow(), componentHandle.bombID);
                _coroutineQueue.AddToQueue(_bombHandles[componentHandle.bombID].ShowMainUIWindow(), componentHandle.bombID);
                _coroutineQueue.AddToQueue(_bombCommanders[_currentBomb].LetGoBomb(), componentHandle.bombID);
                _currentBomb = componentHandle.bombID;
            }
            _coroutineQueue.AddToQueue(onMessageReceived, componentHandle.bombID);
        }
    }