public bool HandleTextMessage(NotifyTextMessageEvent evt, Action <string> messageCallback)
        {
            if (!Settings.ChatCommandsEnabled || string.IsNullOrEmpty(evt.Message) || !evt.Message.StartsWith(Settings.ChatCommandPrefix))
            {
                return(false);
            }

            Parent.LogMessage($"{evt.InvokerName} requested command: \"{evt.Message}\"");

            //Copy event as to not mess up other event handlers
            NotifyTextMessageEvent tempEvt = new NotifyTextMessageEvent();

            evt.CopyProperties(tempEvt);
            evt = tempEvt;

            evt.Message = evt.Message.Substring(Settings.ChatCommandPrefix.Length);

            bool hasAdmin = Settings.AdminUniqueIds.Contains(evt.InvokerUniqueId);

            if (Parent.RateLimiter.CheckRateLimit("chat_command", evt.InvokerUniqueId, hasAdmin) == false)
            {
                messageCallback.Invoke(ColorCoder.ErrorBright("Slow down a little, you are sending too many commands!"));
                return(true);
            }

            string[]      messageSplit = evt.Message.Split(new string[] { " " }, StringSplitOptions.RemoveEmptyEntries);
            string        command      = messageSplit[0].ToLower();
            List <string> parameters   = messageSplit.Skip(1).ToList();

            parameters = ParseParameterEscapes(parameters);

            ChatCommand commandToExecute = null;

            //Handle exceptions that occur during the parsing of the parameters
            try {
                commandToExecute = GetCommandForMessage(command, parameters, evt.InvokerUniqueId);
            } catch (ChatCommandNotFoundException) {
                messageCallback.Invoke(ColorCoder.ErrorBright("Command was not found"));
                return(true);
            } catch (ChatCommandInvalidSyntaxException ex) {
                messageCallback.Invoke(ColorCoder.ErrorBright($"Invalid syntax. Usage of command:\n{Settings.ChatCommandPrefix}{ex.Message}"));
                return(true);
            } catch (NoPermissionException) {
                messageCallback.Invoke(ColorCoder.ErrorBright($"You don't have access to this command, {ColorCoder.Username(evt.InvokerName)}"));
                return(true);
            } catch (CommandParameterInvalidFormatException ex) {
                messageCallback.Invoke(ColorCoder.ErrorBright($"The {ex.GetParameterPosition()} parameter's format was invalid ({ex.ParameterName} = '{ex.ParameterValue}'). It has to be {ColorCoder.Bold(ex.GetNeededType())}!\nUsage: {Settings.ChatCommandPrefix}{ex.UsageHelp}"));
                return(true);
            } catch (TimeStringParseException ex) {
                messageCallback.Invoke(ColorCoder.ErrorBright($"The provided time value '{ex.Input}' had invalid syntax: {ex.Message}"));
                return(true);
            }


            //Handle exceptions that occur during execution of the command
            try {
                commandToExecute.HandleCommand(evt, command, parameters, messageCallback);
            } catch (MultipleTargetsFoundException ex) {
                string joined = string.Join(", ", ex.AllFoundTargets.Select(client => ColorCoder.Bold($"'{client.Nickname}'")));
                messageCallback.Invoke(ColorCoder.ErrorBright($"Too many targets were found with {ColorCoder.Bold($"'{ex.Message}'")} in their name ({joined})"));
            } catch (CooldownNotExpiredException ex) {
                messageCallback.Invoke(ColorCoder.ErrorBright($"That command is still on cooldown. ({ColorCoder.Bold($"{CooldownManager.FormatCooldownTime(ex.Duration)}")} cooldown)"));
            } catch (NoTargetsFoundException ex) {
                messageCallback.Invoke(ColorCoder.ErrorBright($"No targets were found with {ColorCoder.Bold($"'{ex.Message}'")} in their name..."));
            } catch (Exception ex) {
                Parent.LogMessage($"Encountered exception in command '{commandToExecute.GetType().Name}': {ex}");
            }

            return(true);
        }