private void OnMessageReceived(object sender, OnMessageReceivedArgs e)
        {
            User userData = GetOrAddUser(e.ChatMessage.Username, false);

            userData.TotalMessages++;

            string possibleMeme = e.ChatMessage.Message.ToLower();

            if (BotProgram.BotData.Memes.TryGetValue(possibleMeme, out string meme) == true)
            {
                BotProgram.QueueMessage(meme);
            }
            else
            {
                //Ignore commands as inputs
                if (possibleMeme.StartsWith(Globals.CommandIdentifier) == true)
                {
                    return;
                }

                (bool valid, List <List <Parser.Input> > inputList, bool containsStartInput, int durationCounter)
                parsedData = default;

                try
                {
                    string parse_message = Parser.Expandify(Parser.PopulateMacros(e.ChatMessage.Message));

                    parsedData = Parser.Parse(parse_message);
                }
                catch
                {
                    //Kimimaru: Sanitize parsing exceptions for now
                    //Most of these are currently caused by differences in how C# and Python handle slicing strings (Substring() vs string[:])
                    //One example that throws this that shouldn't is "#mash(w234"
                    //BotProgram.QueueMessage($"ERROR: {exception.Message}");
                    parsedData.valid = false;
                }

                if (parsedData.valid == false)
                {
                    //Kimimaru: Currently this also shows this for any message - keep commented until we find a better way to differentiate them
                    //Parser.Input input = parsedData.inputList[0][0];
                    //if (string.IsNullOrEmpty(input.error) == false)
                    //    BotProgram.QueueMessage($"Invalid input: {input.error}");
                }
                else
                {
                    //Ignore if user is silenced
                    if (userData.Silenced == true)
                    {
                        return;
                    }

                    if (InputGlobals.IsValidPauseInputDuration(parsedData.inputList, "start", BotData.MaxPauseHoldDuration) == false)
                    {
                        BotProgram.QueueMessage($"Invalid input: Pause button held for longer than the max duration of {BotData.MaxPauseHoldDuration} milliseconds!");
                        return;
                    }

                    if (InputHandler.StopRunningInputs == false)
                    {
                        //Mark this as a valid input
                        userData.ValidInputs++;

                        bool shouldPerformInput = true;

                        //Check the team the user is on for the controller they should be using
                        //Validate that the controller is acquired and exists
                        int controllerNum = userData.Team;

                        if (controllerNum < 0 || controllerNum >= VJoyController.Joysticks.Length)
                        {
                            BotProgram.QueueMessage($"ERROR: Invalid joystick number {controllerNum + 1}. # of joysticks: {VJoyController.Joysticks.Length}. Please change your controller port to a valid number to perform inputs.");
                            shouldPerformInput = false;
                        }
                        //Now verify that the controller has been acquired by vJoy
                        else if (VJoyController.Joysticks[controllerNum].IsAcquired == false)
                        {
                            BotProgram.QueueMessage($"ERROR: Joystick number {controllerNum + 1} with controller ID of {VJoyController.Joysticks[controllerNum].ControllerID} has not been acquired by the vJoy driver! Ensure you (the streamer) have a vJoy device set up at this ID.");
                            shouldPerformInput = false;
                        }

                        //We're okay to perform the input
                        if (shouldPerformInput == true)
                        {
                            InputHandler.CarryOutInput(parsedData.inputList, controllerNum);

                            //If auto whitelist is enabled, the user reached the whitelist message threshold,
                            //the user isn't whitelisted, and the user hasn't ever been whitelisted, whitelist them
                            if (BotSettings.AutoWhitelistEnabled == true && userData.Level < (int)AccessLevels.Levels.Whitelisted &&
                                userData.AutoWhitelisted == false && userData.ValidInputs >= BotSettings.AutoWhitelistInputCount)
                            {
                                userData.Level           = (int)AccessLevels.Levels.Whitelisted;
                                userData.AutoWhitelisted = true;

                                if (string.IsNullOrEmpty(BotSettings.AutoWhitelistMsg) == false)
                                {
                                    //Replace the user's name with the message
                                    string msg = BotSettings.AutoWhitelistMsg.Replace("{0}", e.ChatMessage.Username);
                                    QueueMessage(msg);
                                }
                            }
                        }
                    }
                    else
                    {
                        QueueMessage("New inputs cannot be processed until all other inputs have stopped.");
                    }

                    //Debug info
                    //BotProgram.QueueMessage("Valid input!");
                    //string thing = "Valid input(s): ";
                    //
                    //for (int i = 0; i < parsedData.inputList.Count; i++)
                    //{
                    //    for (int j = 0; j < parsedData.inputList[i].Count; j++)
                    //    {
                    //        Parser.Input thing2 = parsedData.inputList[i][j];
                    //
                    //        thing += thing2.ToString() + "\n";
                    //    }
                    //}
                    //Console.WriteLine(thing);
                }
            }

            //Kimimaru: For testing this will work, but we shouldn't save after each message
            SaveBotData();
        }