예제 #1
0
        public override void ExecuteCommand(EvtChatCommandArgs e)
        {
            string msg = e.Command.ArgumentsAsString;

            if (msg == null)
            {
                msg = string.Empty;
            }

            BotProgram.BotData.GameMessage = msg;

            //Always save the message to a file so it updates on OBS

            /*For reading from this file on OBS:
             * 1. Create Text (GDI+)
             * 2. Check the box labeled "Read from file"
             * 3. Browse and select the file
             */
            if (Globals.SaveToTextFile(Globals.GameMessageFilename, BotProgram.BotData.GameMessage) == false)
            {
                BotProgram.MsgHandler.QueueMessage($"Unable to save message to file");
            }

            BotProgram.SaveBotData();
        }
        public override void ExecuteCommand(object sender, OnChatCommandReceivedArgs e)
        {
            string logMessage = e.Command.ArgumentsAsString;

            if (string.IsNullOrEmpty(logMessage) == true)
            {
                BotProgram.QueueMessage("Please enter a message for the log.");
                return;
            }

            DateTime curTime = DateTime.UtcNow;

            //Add a new log
            GameLog newLog = new GameLog();

            newLog.LogMessage = logMessage;
            newLog.User       = e.Command.ChatMessage.Username;

            string date = curTime.ToShortDateString();
            string time = curTime.ToLongTimeString();

            newLog.DateTimeString = $"{date} at {time}";

            BotProgram.BotData.Logs.Add(newLog);
            BotProgram.SaveBotData();

            BotProgram.QueueMessage("Successfully logged message!");
        }
예제 #3
0
        public override void ExecuteCommand(EvtChatCommandArgs e)
        {
            List <string> args = e.Command.ArgumentsAsList;

            if (args.Count != 1)
            {
                BotProgram.MsgHandler.QueueMessage($"{Globals.CommandIdentifier}removemacro usage: \"#macroname\"");
                return;
            }

            string macroName = args[0].ToLowerInvariant();

            if (BotProgram.BotData.Macros.ContainsKey(macroName) == true)
            {
                char macroFirstChar = macroName[1];

                //Remove from the parser macro list
                List <string> parserMacroList = BotProgram.BotData.ParserMacroLookup[macroFirstChar];
                parserMacroList.Remove(macroName);
                if (parserMacroList.Count == 0)
                {
                    BotProgram.BotData.ParserMacroLookup.Remove(macroFirstChar);
                }

                BotProgram.BotData.Macros.TryRemove(macroName, out string removedMacro);
                BotProgram.SaveBotData();

                BotProgram.MsgHandler.QueueMessage($"Removed macro {macroName}.");
            }
            else
            {
                BotProgram.MsgHandler.QueueMessage($"Macro \"{macroName}\" could not be found.");
            }
        }
예제 #4
0
        public override void ExecuteCommand(EvtChatCommandArgs e)
        {
            string name        = e.Command.ChatMessage.DisplayName;
            string nameToLower = name.ToLower();

            User user = BotProgram.GetOrAddUser(nameToLower);

            if (user == null)
            {
                return;
            }

            if (user.OptedOut == false)
            {
                user.SetOptOut(true);

                BotProgram.SaveBotData();
                BotProgram.MsgHandler.QueueMessage("Opted out of bot stats!");
                return;
            }
            else if (user.OptedOut == true)
            {
                user.SetOptOut(false);

                BotProgram.SaveBotData();
                BotProgram.MsgHandler.QueueMessage("Opted back into bot stats!");
                return;
            }
        }
예제 #5
0
        public override void ExecuteCommand(EvtChatCommandArgs e)
        {
            List <string> args = e.Command.ArgumentsAsList;

            if (args.Count < 2)
            {
                BotProgram.MsgHandler.QueueMessage($"{Globals.CommandIdentifier}addmeme usage: memename memevalue");
                return;
            }

            if (args[0].ElementAt(0) == '/' || args[1].ElementAt(0) == '/')
            {
                BotProgram.MsgHandler.QueueMessage("Memes cannot start with Twitch chat commands!");
                return;
            }

            if (args[0].ElementAt(0) == Globals.CommandIdentifier)
            {
                BotProgram.MsgHandler.QueueMessage($"Memes cannot start with \'{Globals.CommandIdentifier}\'");
                return;
            }

            if (args[0].ElementAt(0) == Globals.MacroIdentifier)
            {
                BotProgram.MsgHandler.QueueMessage($"Memes cannot start with \'{Globals.MacroIdentifier}\'");
                return;
            }

            if (args[0].Length > MAX_MEME_LENGTH)
            {
                BotProgram.MsgHandler.QueueMessage($"The max meme length is {MAX_MEME_LENGTH} characters!");
                return;
            }

            string memeToLower     = args[0].ToLower();
            bool   sendOverwritten = false;

            if (BotProgram.BotData.Memes.ContainsKey(memeToLower) == true)
            {
                BotProgram.BotData.Memes.TryRemove(memeToLower, out string meme);
                sendOverwritten = true;
            }

            string actualMeme = e.Command.ArgumentsAsString.Remove(0, args[0].Length + 1);

            BotProgram.BotData.Memes.TryAdd(memeToLower, actualMeme);

            BotProgram.SaveBotData();

            if (sendOverwritten == true)
            {
                BotProgram.MsgHandler.QueueMessage("Meme overwritten!");
            }
            else
            {
                MemesCommand.CacheMemesString();
            }
        }
예제 #6
0
        public override void ExecuteCommand(object sender, OnChatCommandReceivedArgs e)
        {
            List <string> amount = e.Command.ArgumentsAsList;

            if (amount.Count != 1)
            {
                BotProgram.QueueMessage($"Sorry, please enter a valid bet amount!");
                return;
            }

            if (long.TryParse(amount[0], out long creditBet) == true)
            {
                if (creditBet <= 0)
                {
                    BotProgram.QueueMessage("Bet amount must be greater than 0!");
                    return;
                }

                string name        = e.Command.ChatMessage.DisplayName;
                string nameToLower = name.ToLower();

                User user = BotProgram.GetOrAddUser(nameToLower);

                long credits = user.Credits;

                if (creditBet > credits)
                {
                    BotProgram.QueueMessage("Bet amount is greater than credits!");
                }
                else
                {
                    bool   success = (Rand.Next(0, 2) == 0);
                    string message = string.Empty;

                    if (success)
                    {
                        credits += creditBet;
                        message  = $"{name} won {creditBet} credits :D !";
                    }
                    else
                    {
                        credits -= creditBet;
                        message  = $"{name} lost {creditBet} credits :(";
                    }

                    BotProgram.QueueMessage(message);

                    user.Credits = credits;
                    BotProgram.SaveBotData();
                }
            }
            else
            {
                BotProgram.QueueMessage($"Sorry, please enter a valid bet amount!");
            }
        }
        public override void ExecuteCommand(object sender, OnChatCommandReceivedArgs e)
        {
            List <string> args = e.Command.ArgumentsAsList;

            if (args == null || args.Count != 2)
            {
                BotProgram.QueueMessage("Please specify a single user followed by the amount of credits you wish to transfer!");
                return;
            }

            string giver        = e.Command.ChatMessage.DisplayName;
            string giverToLower = giver.ToLower();

            string receiver        = args[0];
            string receiverToLower = receiver.ToLower();

            if (giverToLower == receiverToLower)
            {
                BotProgram.QueueMessage("You cannot transfer points to yourself!");
                return;
            }

            //If the user transferring points isn't in the database, add them
            User giverUser    = BotProgram.GetOrAddUser(giverToLower);
            User receiverUser = BotProgram.GetUser(receiverToLower);

            if (receiverUser == null)
            {
                BotProgram.QueueMessage($"{receiver} is not in the database!");
                return;
            }

            long transferAmount = -1L;
            bool success        = long.TryParse(args[1], out transferAmount);

            if (success == false || transferAmount <= 0)
            {
                BotProgram.QueueMessage("Please specify a positive whole number of credits greater than 0!");
                return;
            }

            if (giverUser.Credits < transferAmount)
            {
                BotProgram.QueueMessage("The transfer amount is greater than your credits!");
                return;
            }

            giverUser.Credits    -= transferAmount;
            receiverUser.Credits += transferAmount;
            BotProgram.SaveBotData();

            BotProgram.QueueMessage($"{giver} has transferred {transferAmount} points to {receiver} :D !");
        }
        public override void ExecuteCommand(EvtChatCommandArgs e)
        {
            List <string> args = e.Command.ArgumentsAsList;

            if (args.Count < 3)
            {
                BotProgram.MsgHandler.QueueMessage("Usage: \"console\" \"synonymName\" \"input\"");
                return;
            }

            string consoleStr = args[0];

            //Check if a valid console is specified
            if (Enum.TryParse <InputGlobals.InputConsoles>(consoleStr, true, out InputGlobals.InputConsoles console) == false ||
                InputGlobals.Consoles.ContainsKey(console) == false)
            {
                BotProgram.MsgHandler.QueueMessage($"Please specify a valid console.");
                return;
            }

            InputSynonymData inputSyns = BotProgram.BotData.InputSynonyms;

            string synonymName = args[1];

            //Get the actual synonym from the remaining arguments
            string actualSynonym = e.Command.ArgumentsAsString.Remove(0, args[0].Length + 1).Remove(0, args[1].Length + 1);

            //Add to the dictionary if it doesn't exist
            if (inputSyns.SynonymDict.TryGetValue(console, out Dictionary <string, string> dict) == false)
            {
                dict = new Dictionary <string, string>(8);
                inputSyns.SynonymDict[console] = dict;
            }

            string message = string.Empty;

            if (dict.ContainsKey(synonymName) == true)
            {
                message = $"Updated input synonym \"{synonymName}\" for \"{actualSynonym}\"!";
            }
            else
            {
                message = $"Added input synonym \"{synonymName}\" for \"{actualSynonym}\"!";
            }

            //Update value and save bot data
            dict[synonymName] = actualSynonym;

            BotProgram.SaveBotData();

            BotProgram.MsgHandler.QueueMessage(message);
        }
예제 #9
0
        public override void ExecuteCommand(object sender, OnChatCommandReceivedArgs e)
        {
            string msg = e.Command.ArgumentsAsString;

            if (msg == null)
            {
                msg = string.Empty;
            }

            BotProgram.BotData.InfoMessage = msg;

            BotProgram.SaveBotData();
        }
예제 #10
0
        public override void ExecuteCommand(EvtChatCommandArgs e)
        {
            List <string> args = e.Command.ArgumentsAsList;

            if (args.Count == 0)
            {
                BotProgram.MsgHandler.QueueMessage($"The max pause duration is {BotProgram.BotData.MaxPauseHoldDuration} milliseconds.");
                return;
            }

            User user = BotProgram.GetOrAddUser(e.Command.ChatMessage.Username, false);

            //Disallow setting the duration if the user doesn't have a sufficient access level
            if (user.Level < SetAccessLevel)
            {
                BotProgram.MsgHandler.QueueMessage(CommandHandler.INVALID_ACCESS_MESSAGE);
                return;
            }

            if (args.Count > 1)
            {
                BotProgram.MsgHandler.QueueMessage("Usage: \"duration (ms) (-1 to disable)\"");
                return;
            }

            string value = args[0];

            if (int.TryParse(value, out int duration) == false)
            {
                BotProgram.MsgHandler.QueueMessage("Invalid value! Usage: \"duration (ms) (-1 to disable)\"");
                return;
            }

            if (duration < 0)
            {
                duration = -1;
            }

            BotProgram.BotData.MaxPauseHoldDuration = duration;
            BotProgram.SaveBotData();

            if (BotProgram.BotData.MaxPauseHoldDuration > 0)
            {
                BotProgram.MsgHandler.QueueMessage($"Set max pause duration to {duration} milliseconds!");
            }
            else
            {
                BotProgram.MsgHandler.QueueMessage("Disabled max pause duration!");
            }
        }
예제 #11
0
        public override void ExecuteCommand(object sender, OnChatCommandReceivedArgs e)
        {
            List <string> args = e.Command.ArgumentsAsList;

            if (args.Count != 1)
            {
                BotProgram.QueueMessage("Usage: \"username\"");
                return;
            }

            string silencedName = args[0].ToLowerInvariant();
            string selfName     = e.Command.ChatMessage.Username.ToLowerInvariant();

            if (silencedName == selfName)
            {
                BotProgram.QueueMessage("No use in silencing yourself, silly!");
                return;
            }

            User user = BotProgram.GetUser(silencedName);

            if (user == null)
            {
                BotProgram.QueueMessage($"User does not exist in database!");
                return;
            }

            if (user.Silenced == true)
            {
                BotProgram.QueueMessage($"User {silencedName} is already silenced!");
                return;
            }

            //Make sure the user you're silencing is a lower level than you
            User selfUser = BotProgram.GetUser(selfName);

            if (selfUser.Level <= user.Level)
            {
                BotProgram.QueueMessage($"Cannot silence a user at or above your access level!");
                return;
            }

            user.Silenced = true;
            BotProgram.BotData.SilencedUsers.Add(silencedName);
            BotProgram.SaveBotData();

            BotProgram.QueueMessage($"User {silencedName} has been silenced and thus prevented from performing inputs.");
        }
예제 #12
0
        public override void ExecuteCommand(EvtChatCommandArgs e)
        {
            List <string> args = e.Command.ArgumentsAsList;

            if (args.Count == 0)
            {
                BotProgram.MsgHandler.QueueMessage($"The default duration of an input is {BotProgram.BotData.DefaultInputDuration} milliseconds!");
                return;
            }

            User user = BotProgram.GetOrAddUser(e.Command.ChatMessage.Username, false);

            //Disallow setting the duration if the user doesn't have a sufficient access level
            if (user.Level < SetAccessLevel)
            {
                BotProgram.MsgHandler.QueueMessage(CommandHandler.INVALID_ACCESS_MESSAGE);
                return;
            }

            if (args.Count > 1)
            {
                BotProgram.MsgHandler.QueueMessage($"Usage: \"duration (ms)\"");
                return;
            }

            if (int.TryParse(args[0], out int newDefaultDur) == false)
            {
                BotProgram.MsgHandler.QueueMessage("Please enter a valid number!");
                return;
            }

            if (newDefaultDur < 0)
            {
                BotProgram.MsgHandler.QueueMessage("Cannot set a negative duration!");
                return;
            }

            if (newDefaultDur == BotProgram.BotData.DefaultInputDuration)
            {
                BotProgram.MsgHandler.QueueMessage("The duration is already this value!");
                return;
            }

            BotProgram.BotData.DefaultInputDuration = newDefaultDur;
            BotProgram.SaveBotData();

            BotProgram.MsgHandler.QueueMessage($"Set default input duration to {newDefaultDur} milliseconds!");
        }
        public override void ExecuteCommand(object sender, OnChatCommandReceivedArgs e)
        {
            List <string> args = e.Command.ArgumentsAsList;

            if (args.Count != 1)
            {
                BotProgram.QueueMessage("Usage: \"username\"");
                return;
            }

            string unsilencedName = args[0].ToLowerInvariant();
            string selfName       = e.Command.ChatMessage.Username.ToLowerInvariant();

            if (unsilencedName == selfName)
            {
                BotProgram.QueueMessage("Nice try.");
                return;
            }

            User user = BotProgram.GetUser(unsilencedName);

            if (user == null)
            {
                BotProgram.QueueMessage($"User does not exist in database!");
                return;
            }

            if (user.Silenced == false)
            {
                BotProgram.QueueMessage($"User {unsilencedName} is not silenced!");
                return;
            }

            //Make sure the user you're silencing is a lower level than you
            User selfUser = BotProgram.GetUser(selfName);

            if (selfUser.Level <= user.Level)
            {
                BotProgram.QueueMessage($"Cannot unsilence a user at or above your access level!");
                return;
            }

            user.Silenced = false;
            BotProgram.BotData.SilencedUsers.Remove(unsilencedName);
            BotProgram.SaveBotData();

            BotProgram.QueueMessage($"User {unsilencedName} has been unsilenced and can perform inputs once again.");
        }
예제 #14
0
        public override void ExecuteCommand(EvtChatCommandArgs e)
        {
            string name        = e.Command.ChatMessage.DisplayName;
            string nameToLower = name.ToLower();

            User user = BotProgram.GetUser(nameToLower);

            if (ConfirmClearedStatsUsers.Contains(nameToLower) == false)
            {
                BotProgram.MsgHandler.QueueMessage($"WARNING {name}: this clears all miscellaneous user stats, such as credits and message/input counts. If you're sure, retype this command with \"{ConfirmClearStr}\" as an argument to clear or \"{ConfirmStopStr}\" to ignore.");
                ConfirmClearedStatsUsers.Add(nameToLower);
                return;
            }
            else
            {
                //Check for an argument
                List <string> args = e.Command.ArgumentsAsList;

                //Only accept the exact argument
                if (args.Count != 1)
                {
                    return;
                }

                string confirmation = args[0];

                //Confirm - clear stats
                if (confirmation == ConfirmClearStr)
                {
                    ClearUserStats(user);

                    BotProgram.SaveBotData();
                    ConfirmClearedStatsUsers.Remove(nameToLower);
                    BotProgram.MsgHandler.QueueMessage("Successfully cleared stats!");
                }
                //Ignore
                else if (confirmation == ConfirmStopStr)
                {
                    ConfirmClearedStatsUsers.Remove(nameToLower);
                    BotProgram.MsgHandler.QueueMessage("Cancelled clearing stats!");
                }
            }
        }
예제 #15
0
        public override void ExecuteCommand(EvtChatCommandArgs e)
        {
            List <string> args = e.Command.ArgumentsAsList;

            if (args.Count != 1)
            {
                BotProgram.MsgHandler.QueueMessage($"{Globals.CommandIdentifier}removememe usage: memename");
                return;
            }

            string meme = args[0].ToLower();

            if (BotProgram.BotData.Memes.ContainsKey(meme) == true)
            {
                BotProgram.BotData.Memes.TryRemove(meme, out string removedMeme);
                BotProgram.SaveBotData();
                MemesCommand.CacheMemesString();
            }
        }
        public override void ExecuteCommand(EvtChatCommandArgs e)
        {
            List <string> args = e.Command.ArgumentsAsList;

            if (args.Count != 2)
            {
                BotProgram.MsgHandler.QueueMessage("Usage: \"console\" \"synonymName\"");
                return;
            }

            string consoleStr = args[0];

            //Check for a valid console
            if (Enum.TryParse <InputGlobals.InputConsoles>(consoleStr, true, out InputGlobals.InputConsoles console) == false ||
                InputGlobals.Consoles.ContainsKey(console) == false)
            {
                BotProgram.MsgHandler.QueueMessage($"Please specify a valid console.");
                return;
            }

            InputSynonymData inputSyns = BotProgram.BotData.InputSynonyms;

            string synonymName = args[1];

            //Check if input synonyms exist for this console
            if (inputSyns.SynonymDict.TryGetValue(console, out Dictionary <string, string> dict) == false)
            {
                BotProgram.MsgHandler.QueueMessage($"No input synonyms exist for console {console}!");
                return;
            }

            //Remove the synonym
            if (dict.Remove(synonymName) == false)
            {
                BotProgram.MsgHandler.QueueMessage($"No input synonym \"{synonymName}\" exists for console {console}!");
                return;
            }

            //Save bot data
            BotProgram.SaveBotData();

            BotProgram.MsgHandler.QueueMessage($"Successfully removed input synonym \"{synonymName}\"!");
        }
        public override void ExecuteCommand(object sender, OnChatCommandReceivedArgs e)
        {
            List <string> args = e.Command.ArgumentsAsList;

            if (args.Count == 0 || args.Count > 1)
            {
                BotProgram.QueueMessage("Usage: \"controllerPort (starting from 1)\"");
                return;
            }

            if (int.TryParse(args[0], out int portNum) == false)
            {
                BotProgram.QueueMessage("That is not a valid number!");
                return;
            }

            if (portNum <= 0 || portNum > VJoyController.Joysticks.Length)
            {
                BotProgram.QueueMessage($"Please specify a number in the range of 1 through the current controller count ({VJoyController.Joysticks.Length}).");
                return;
            }

            //Change to zero-based index for referencing
            int controllerNum = portNum - 1;

            User user = BotProgram.GetOrAddUser(e.Command.ChatMessage.Username, false);

            if (user.Team == controllerNum)
            {
                BotProgram.QueueMessage("You're already on this controller port!");
                return;
            }

            //Change team and save data
            user.Team = controllerNum;

            BotProgram.SaveBotData();

            BotProgram.QueueMessage($"Changed controller port to {portNum}!");
        }
예제 #18
0
        public override void ExecuteCommand(EvtChatCommandArgs e)
        {
            string logMessage = e.Command.ArgumentsAsString;

            if (string.IsNullOrEmpty(logMessage) == true)
            {
                BotProgram.MsgHandler.QueueMessage("Please enter a message for the log.");
                return;
            }

            DateTime curTime = DateTime.UtcNow;

            User user = BotProgram.GetUser(e.Command.ChatMessage.Username, false);

            string username = string.Empty;

            //Add a new log
            GameLog newLog = new GameLog();

            newLog.LogMessage = logMessage;

            //If the user exists and isn't opted out of bot stats, add their name
            if (user != null && user.OptedOut == false)
            {
                username = e.Command.ChatMessage.Username;
            }

            newLog.User = username;

            string date = curTime.ToShortDateString();
            string time = curTime.ToLongTimeString();

            newLog.DateTimeString = $"{date} at {time}";

            BotProgram.BotData.Logs.Add(newLog);
            BotProgram.SaveBotData();

            BotProgram.MsgHandler.QueueMessage("Successfully logged message!");
        }
예제 #19
0
        public override void ExecuteCommand(EvtChatCommandArgs e)
        {
            List <string> args = e.Command.ArgumentsAsList;

            //See the permissions
            if (args.Count == 0)
            {
                BotProgram.MsgHandler.QueueMessage($"Inputs are allowed for {(AccessLevels.Levels)BotProgram.BotData.InputPermissions} and above. To set the permissions, add one as an argument: {GetValidPermsStr()}");
                return;
            }

            string permsStr = args[0];

            if (Enum.TryParse <AccessLevels.Levels>(permsStr, true, out AccessLevels.Levels perm) == false)
            {
                BotProgram.MsgHandler.QueueMessage($"Please enter a valid permission: {GetValidPermsStr()}");
                return;
            }

            int permissionLvl = (int)perm;

            if (permissionLvl == BotProgram.BotData.InputPermissions)
            {
                BotProgram.MsgHandler.QueueMessage($"The permissions are already {(AccessLevels.Levels)BotProgram.BotData.InputPermissions}!");
                return;
            }

            if (permissionLvl < (int)AccessLevels.Levels.User || permissionLvl > (int)AccessLevels.Levels.Admin)
            {
                BotProgram.MsgHandler.QueueMessage("Invalid permission level!");
                return;
            }

            BotProgram.BotData.InputPermissions = permissionLvl;
            BotProgram.SaveBotData();

            BotProgram.MsgHandler.QueueMessage($"Set input permissions to {(AccessLevels.Levels)BotProgram.BotData.InputPermissions} and above!");
        }
        public override void ExecuteCommand(object sender, OnChatCommandReceivedArgs e)
        {
            int randNum = 1;

            try
            {
                randNum = Rand.Next(0, RandJumpRopeChance);
            }
            catch (Exception exc)
            {
                Console.WriteLine("EXCEPTION: " + exc.Message);
            }

            if (randNum == 0 && JumpRopeCount > 0)
            {
                if (JumpRopeCount > BotProgram.BotData.JRData.Streak)
                {
                    BotProgram.BotData.JRData.User   = e.Command.ChatMessage.Username;
                    BotProgram.BotData.JRData.Streak = JumpRopeCount;
                    BotProgram.SaveBotData();

                    BotProgram.QueueMessage($"Ouch! I tripped and fell after {JumpRopeCount} attempt(s) at Jump Rope! Wow, it's a new record!");
                }
                else
                {
                    BotProgram.QueueMessage($"Ouch! I tripped and fell after {JumpRopeCount} attempt(s) at Jump Rope!");
                }

                JumpRopeCount = 0;

                RandJumpRopeChance = Rand.Next(4, 9);
            }
            else
            {
                JumpRopeCount++;
                BotProgram.QueueMessage($"Yay :D I succeeded in Jump Rope {JumpRopeCount} time(s) in a row!");
            }
        }
        public override void ExecuteCommand(object sender, OnChatCommandReceivedArgs e)
        {
            List <string> args = e.Command.ArgumentsAsList;

            if (args.Count != 1)
            {
                BotProgram.QueueMessage($"{Globals.CommandIdentifier}removemacro usage: \"#macroname\"");
                return;
            }

            string macroName = args[0].ToLowerInvariant();

            if (BotProgram.BotData.Macros.ContainsKey(macroName) == true)
            {
                BotProgram.BotData.Macros.Remove(macroName);
                BotProgram.SaveBotData();

                BotProgram.QueueMessage($"Removed macro {macroName}.");
            }
            else
            {
                BotProgram.QueueMessage($"Macro \"{macroName}\" could not be found.");
            }
        }
        public override void ExecuteCommand(EvtChatCommandArgs e)
        {
            List <string> args = e.Command.ArgumentsAsList;

            if (args.Count != 1)
            {
                BotProgram.MsgHandler.QueueMessage($"Enter \"{ConfirmationArg}\" as an argument to confirm clearing all game logs.");
                return;
            }

            string arg = args[0];

            if (arg != ConfirmationArg)
            {
                BotProgram.MsgHandler.QueueMessage($"Enter \"{ConfirmationArg}\" as an argument to confirm clearing all game logs.");
                return;
            }

            //Clear all logs
            BotProgram.BotData.Logs.Clear();
            BotProgram.SaveBotData();

            BotProgram.MsgHandler.QueueMessage("Successfully cleared all game logs!");
        }
        public override void ExecuteCommand(EvtChatCommandArgs e)
        {
            List <string> args = e.Command.ArgumentsAsList;

            if (args.Count < 2)
            {
                BotProgram.MsgHandler.QueueMessage($"{Globals.CommandIdentifier}addmacro usage: \"#macroname\" \"command\"");
                return;
            }

            //Make sure the first argument has at least two characters
            if (args[0].Length < 2)
            {
                BotProgram.MsgHandler.QueueMessage("Macros need to be at least two characters!");
                return;
            }

            string macroName = args[0].ToLowerInvariant();

            if (macroName[0] != Globals.MacroIdentifier)
            {
                BotProgram.MsgHandler.QueueMessage($"Macros must start with '{Globals.MacroIdentifier}'.");
                return;
            }

            //For simplicity with wait inputs, force the first character in the macro name to be alphanumeric
            if (char.IsLetterOrDigit(args[0][1]) == false)
            {
                BotProgram.MsgHandler.QueueMessage("The first character in macro names must be alphanumeric!");
                return;
            }

            if (macroName.Length > MAX_MACRO_LENGTH)
            {
                BotProgram.MsgHandler.QueueMessage($"The max macro length is {MAX_MACRO_LENGTH} characters!");
                return;
            }

            string macroVal = e.Command.ArgumentsAsString.Remove(0, macroName.Length + 1).ToLowerInvariant();

            bool   isDynamic = false;
            string parsedVal = macroVal;

            //Check for a dynamic macro
            if (macroName.Contains("(*") == true)
            {
                isDynamic = true;

                //Dynamic macros can't be fully verified until we do some brute forcing
                //An example is: "a500ms [b .]*<0>"
                //The <0> should be a number, so if we use a valid input it won't work
                //The brute force approach would check with all possible combinations of the first input (Ex. "a") and a number
                //If any are valid, it's a valid dynamic macro

                //NOTE: We need to verify that the dynamic macro takes the form of "#macroname(*,*)"
                //It needs to have an open parenthesis followed by a number of asterisks separated by commas, then ending with a closed parenthesis
                //string parseMsg = string.Empty;
                //try
                //{
                //    parseMsg = Parser.Expandify(Parser.PopulateMacros(parsedVal));
                //}
                //catch (Exception exception)
                //{
                //    BotProgram.MsgHandler.QueueMessage("Invalid dynamic macro. Ensure that variables are listed in order (Ex. (*,*,...) = <0>, <1>,...)");
                //    Console.WriteLine(exception.Message);
                //    return;
                //}
                //
                //MatchCollection matches = Regex.Matches(parseMsg, @"<[0-9]+>", RegexOptions.Compiled);
                //
                ////Kimimaru: Replace all variables with a valid input to verify its validity
                ////Any input will do, so just grab the first one
                //string input = InputGlobals.ValidInputs[0];
                //
                //for (int i = 0; i < matches.Count; i++)
                //{
                //    Match match = matches[i];
                //
                //    parsedVal = parsedVal.Replace(match.Value, input);
                //}
            }

            //Validate input if not dynamic
            if (isDynamic == false)
            {
                try
                {
                    string parse_message = Parser.Expandify(Parser.PopulateMacros(parsedVal));

                    Parser.InputSequence inputSequence = Parser.ParseInputs(parse_message, 0, true, true);
                    //var val = Parser.Parse(parse_message);

                    if (inputSequence.InputValidationType != Parser.InputValidationTypes.Valid)//val.Item1 == false)
                    {
                        BotProgram.MsgHandler.QueueMessage("Invalid macro.");
                        return;
                    }
                }
                catch
                {
                    BotProgram.MsgHandler.QueueMessage("Invalid macro.");
                    return;
                }
            }

            //Parser.InputSequence inputSequence = default;
            //
            //try
            //{
            //    //Parse the macro to check for valid input
            //    string parse_message = Parser.Expandify(Parser.PopulateMacros(parsedVal));
            //
            //    inputSequence = Parser.ParseInputs(parse_message);
            //}
            //catch
            //{
            //    if (isDynamic == false)
            //    {
            //        BotProgram.MsgHandler.QueueMessage("Invalid macro.");
            //    }
            //    else
            //    {
            //        BotProgram.MsgHandler.QueueMessage("Invalid dynamic macro. Ensure that variables are listed in order (Ex. (*,*,...) = <0>, <1>,...)");
            //    }
            //    return;
            //}

            //if (inputSequence.InputValidationType != Parser.InputValidationTypes.Valid)
            //{
            //    if (isDynamic == false)
            //    {
            //        BotProgram.MsgHandler.QueueMessage("Invalid macro.");
            //    }
            //    else
            //    {
            //        BotProgram.MsgHandler.QueueMessage("Invalid dynamic macro. Ensure that variables are listed in order (Ex. (*,*,...) = <0>, <1>,...)");
            //    }
            //}
            //else
            //{
            string message = string.Empty;

            if (BotProgram.BotData.Macros.ContainsKey(macroName) == false)
            {
                if (isDynamic == false)
                {
                    message = $"Added macro {macroName}!";
                }
                else
                {
                    message = $"Added dynamic macro {macroName}! Dynamic macros can't be validated beforehand, so verify it works manually.";
                }

                AddMacroToParserList(macroName);
            }
            else
            {
                if (isDynamic == false)
                {
                    message = $"Updated macro {macroName}!";
                }
                else
                {
                    message = $"Updated dynamic macro {macroName}! Dynamic macros can't be validated beforehand, so verify it works manually.";
                }
            }

            BotProgram.BotData.Macros[macroName] = macroVal;
            BotProgram.SaveBotData();

            BotProgram.MsgHandler.QueueMessage(message);
            //}
        }
        public override void ExecuteCommand(object sender, OnChatCommandReceivedArgs e)
        {
            List <string> args = e.Command.ArgumentsAsList;

            if (args.Count < 1)
            {
                BotProgram.QueueMessage("Usage: state #");
                return;
            }

            string stateNumStr = args[0];

            if (int.TryParse(stateNumStr, out int stateNum) == false)
            {
                BotProgram.QueueMessage("Invalid state number.");
                return;
            }

            string saveStateStr = $"savestate{stateNum}";

            if (InputGlobals.CurrentConsole.ButtonInputMap.ContainsKey(saveStateStr) == false)
            {
                BotProgram.QueueMessage("Invalid state number.");
                return;
            }

            //Savestates are always performed on the first controller
            VJoyController joystick = VJoyController.GetController(0);

            joystick.PressButton(saveStateStr);
            joystick.UpdateJoystickEfficient();

            //Track the time of the savestate
            DateTime curTime = DateTime.UtcNow;

            //Add a new savestate log
            GameLog newStateLog = new GameLog();

            newStateLog.User = e.Command.ChatMessage.Username;

            string date = curTime.ToShortDateString();
            string time = curTime.ToLongTimeString();

            newStateLog.DateTimeString = $"{date} at {time}";

            newStateLog.User       = e.Command.ChatMessage.Username;
            newStateLog.LogMessage = string.Empty;

            //Add the message if one was specified
            if (args.Count > 1)
            {
                string message = e.Command.ArgumentsAsString.Remove(0, stateNumStr.Length + 1);
                newStateLog.LogMessage = message;
            }

            //Add or replace the log and save the bot data
            BotProgram.BotData.SavestateLogs[stateNum] = newStateLog;
            BotProgram.SaveBotData();

            BotProgram.QueueMessage($"Saved state {stateNum}!");

            //Wait a bit before releasing the input
            const float wait = 50f;
            Stopwatch   sw   = Stopwatch.StartNew();

            while (sw.ElapsedMilliseconds < wait)
            {
            }

            joystick.ReleaseButton(saveStateStr);
            joystick.UpdateJoystickEfficient();
        }
        public override void ExecuteCommand(object sender, OnChatCommandReceivedArgs e)
        {
            List <string> args = e.Command.ArgumentsAsList;

            if (args.Count != 1)
            {
                BotProgram.QueueMessage($"Usage: \"# of controllers (min: {VJoyController.MIN_VJOY_DEVICE_ID}, max: {VJoyController.MAX_VJOY_DEVICE_ID})\"");
                return;
            }

            if (int.TryParse(args[0], out int newJoystickCount) == false)
            {
                BotProgram.QueueMessage("Invalid number of controllers!");
                return;
            }

            if (newJoystickCount < VJoyController.MIN_VJOY_DEVICE_ID)
            {
                BotProgram.QueueMessage($"Value is less than {VJoyController.MIN_VJOY_DEVICE_ID}!");
                return;
            }

            if (newJoystickCount > VJoyController.MAX_VJOY_DEVICE_ID)
            {
                BotProgram.QueueMessage($"Value is greater than {VJoyController.MAX_VJOY_DEVICE_ID}, which is the max number of supported controllers!");
                return;
            }

            if (newJoystickCount == BotProgram.BotData.JoystickCount)
            {
                BotProgram.QueueMessage("There are already that many controllers plugged in!");
                return;
            }

            //We changed count, so let's stop all inputs and reinitialize the vJoy devices
            BotProgram.QueueMessage($"Changing controller count from {BotProgram.BotData.JoystickCount} to {newJoystickCount}. Stopping all inputs and reinitializing.");

            InputHandler.CancelRunningInputs();

            //Wait until no inputs are running
            while (InputHandler.CurrentRunningInputs > 0)
            {
            }

            //Reinitialize the vJoy devices
            VJoyController.CleanUp();

            //Kimimaru: Time out so we don't softlock everything if all devices cannot be freed
            //While this is an issue if it happens, we'll let the streamer know without permanently suspending inputs
            const long timeOut = 60000;

            Stopwatch sw = Stopwatch.StartNew();

            //Wait until all vJoy devices are no longer owned
            while (true)
            {
                int freeCount = 0;

                for (int i = 0; i < VJoyController.Joysticks.Length; i++)
                {
                    VjdStat stat = VJoyController.VJoyInstance.GetVJDStatus(VJoyController.Joysticks[i].ControllerID);
                    if (stat != VjdStat.VJD_STAT_OWN)
                    {
                        freeCount++;
                    }
                }

                //We're done if all are no longer owned
                if (freeCount == VJoyController.Joysticks.Length)
                {
                    break;
                }

                if (sw.ElapsedMilliseconds >= timeOut)
                {
                    BotProgram.QueueMessage($"ERROR: Unable to free all vJoy controllers. {freeCount}/{VJoyController.Joysticks.Length} freed.");
                    break;
                }
            }

            int acquiredCount = VJoyController.InitControllers(newJoystickCount);

            Console.WriteLine($"Acquired {acquiredCount} controllers!");

            const long wait = 500L;

            sw.Stop();
            sw.Reset();
            sw.Start();

            //Wait again to reinitialize
            while (sw.ElapsedMilliseconds < wait)
            {
            }

            InputHandler.ResumeRunningInputs();

            BotProgram.BotData.JoystickCount = newJoystickCount;
            BotProgram.SaveBotData();

            BotProgram.QueueMessage("Controllers reinitialized and inputs resumed!");
        }
        public override void ExecuteCommand(object sender, OnChatCommandReceivedArgs e)
        {
            List <string> args = e.Command.ArgumentsAsList;

            if (args.Count < 2)
            {
                BotProgram.QueueMessage($"{Globals.CommandIdentifier}addmacro usage: \"#macroname\" \"command\"");
                return;
            }

            string macroName = args[0].ToLowerInvariant();

            string macroVal = e.Command.ArgumentsAsString.Remove(0, macroName.Length + 1).ToLowerInvariant();

            if (macroName[0] != Globals.MacroIdentifier)
            {
                BotProgram.QueueMessage($"Macros must start with '{Globals.MacroIdentifier}'.");
                return;
            }

            if (macroName.Length > MAX_MACRO_LENGTH)
            {
                BotProgram.QueueMessage($"The max macro length is {MAX_MACRO_LENGTH} characters!");
                return;
            }

            bool   isDynamic = false;
            string parsedVal = macroVal;

            //Check for a dynamic macro
            if (macroName.Contains("(*") == true)
            {
                isDynamic = true;

                //NOTE: We need to verify that the dynamic macro takes the form of "#macroname(*,*)"
                //It needs to have an open parenthesis followed by a number of asterisks separated by commas, then ending with a closed parenthesis
                string parseMsg = string.Empty;
                try
                {
                    parseMsg = Parser.Expandify(Parser.PopulateMacros(parsedVal));
                }
                catch
                {
                    BotProgram.QueueMessage("Invalid dynamic macro. Ensure that variables are listed in order (Ex. (*,*,...) = <0>, <1>,...)");
                    return;
                }

                MatchCollection matches = Regex.Matches(parseMsg, @"<[0-9]+>", RegexOptions.Compiled);

                //Kimimaru: Replace all variables with a valid input to verify its validity
                //Any input will do, so just grab the first one
                string input = InputGlobals.ValidInputs[0];

                for (int i = 0; i < matches.Count; i++)
                {
                    Match match = matches[i];

                    parsedVal = parsedVal.Replace(match.Value, input);
                }
            }

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

            try
            {
                //Parse the macro to check for valid input
                string parse_message = Parser.Expandify(Parser.PopulateMacros(parsedVal));

                parsedData = Parser.Parse(parse_message);
            }
            catch
            {
                if (isDynamic == false)
                {
                    BotProgram.QueueMessage("Invalid macro.");
                }
                else
                {
                    BotProgram.QueueMessage("Invalid dynamic macro. Ensure that variables are listed in order (Ex. (*,*,...) = <0>, <1>,...)");
                }
                return;
            }

            if (parsedData.valid == false)
            {
                if (isDynamic == false)
                {
                    BotProgram.QueueMessage("Invalid macro.");
                }
                else
                {
                    BotProgram.QueueMessage("Invalid dynamic macro. Ensure that variables are listed in order (Ex. (*,*,...) = <0>, <1>,...)");
                }
            }
            else
            {
                string message = string.Empty;

                if (BotProgram.BotData.Macros.ContainsKey(macroName) == false)
                {
                    if (isDynamic == false)
                    {
                        message = $"Added macro {macroName}!";
                    }
                    else
                    {
                        message = $"Added dynamic macro {macroName}!";
                    }
                }
                else
                {
                    if (isDynamic == false)
                    {
                        message = $"Updated macro {macroName}!";
                    }
                    else
                    {
                        message = $"Updated dynamic macro {macroName}!";
                    }
                }

                BotProgram.BotData.Macros[macroName] = macroVal;
                BotProgram.SaveBotData();

                BotProgram.QueueMessage(message);
            }
        }
예제 #27
0
        public override void ExecuteCommand(EvtChatCommandArgs e)
        {
            List <string> args = e.Command.ArgumentsAsList;

            if (args.Count != 2)
            {
                BotProgram.MsgHandler.QueueMessage($"{Globals.CommandIdentifier}setlevel usage: \"username\" \"level\"");
                return;
            }

            string levelUsername = args[0].ToLowerInvariant();
            string levelStr      = args[1];

            string curUserName = e.Command.ChatMessage.Username.ToLowerInvariant();

            if (levelUsername == curUserName)
            {
                BotProgram.MsgHandler.QueueMessage("You cannot set your own level!");
                return;
            }

            User levelUser = BotProgram.GetUser(levelUsername, true);

            if (levelUser == null)
            {
                BotProgram.MsgHandler.QueueMessage($"User does not exist in database!");
                return;
            }

            User curUser = BotProgram.GetUser(e.Command.ChatMessage.Username, true);

            if (curUser == null)
            {
                BotProgram.MsgHandler.QueueMessage("Invalid user of this command; something went wrong?!");
                return;
            }

            if (levelUser.Level >= curUser.Level)
            {
                BotProgram.MsgHandler.QueueMessage("You can't set the level of a user with a level equal to or greater than yours!");
                return;
            }

            if (int.TryParse(levelStr, out int levelNum) == false)
            {
                BotProgram.MsgHandler.QueueMessage("Invalid level specified.");
                return;
            }

            AccessLevels.Levels[] levelArray = EnumUtility.GetValues <AccessLevels.Levels> .EnumValues;

            bool   found   = false;
            string lvlName = string.Empty;

            for (int i = 0; i < levelArray.Length; i++)
            {
                if (levelNum == (int)levelArray[i])
                {
                    found   = true;
                    lvlName = levelArray[i].ToString();
                    break;
                }
            }

            if (found == false)
            {
                BotProgram.MsgHandler.QueueMessage("Invalid level specified.");
                return;
            }

            if (levelNum > curUser.Level)
            {
                BotProgram.MsgHandler.QueueMessage("You cannot set a level greater than your own!");
                return;
            }

            levelUser.SetLevel(levelNum);

            BotProgram.SaveBotData();

            BotProgram.MsgHandler.QueueMessage($"Set {levelUsername}'s level to {levelNum}, {lvlName}!");
        }
예제 #28
0
        public override void ExecuteCommand(EvtChatCommandArgs e)
        {
            List <string> args = e.Command.ArgumentsAsList;

            if (args.Count != 1)
            {
                BotProgram.MsgHandler.QueueMessage($"Usage: \"# of controllers (min: {InputGlobals.ControllerMngr.MinControllers}, max: {InputGlobals.ControllerMngr.MaxControllers})\"");
                return;
            }

            if (int.TryParse(args[0], out int newJoystickCount) == false)
            {
                BotProgram.MsgHandler.QueueMessage("Invalid number of controllers!");
                return;
            }

            if (newJoystickCount < InputGlobals.ControllerMngr.MinControllers)
            {
                BotProgram.MsgHandler.QueueMessage($"Value is less than {InputGlobals.ControllerMngr.MinControllers}!");
                return;
            }

            if (newJoystickCount > InputGlobals.ControllerMngr.MaxControllers)
            {
                BotProgram.MsgHandler.QueueMessage($"Value is greater than {InputGlobals.ControllerMngr.MaxControllers}, which is the max number of supported controllers!");
                return;
            }

            if (newJoystickCount == BotProgram.BotData.JoystickCount)
            {
                BotProgram.MsgHandler.QueueMessage("There are already that many controllers plugged in!");
                return;
            }

            //We changed count, so let's stop all inputs and reinitialize the devices
            BotProgram.MsgHandler.QueueMessage($"Changing controller count from {BotProgram.BotData.JoystickCount} to {newJoystickCount}. Stopping all inputs and reinitializing.");

            InputHandler.CancelRunningInputs();

            //Wait until no inputs are running
            while (InputHandler.CurrentRunningInputs > 0)
            {
            }

            //Reinitialize the virtual controllers
            InputGlobals.ControllerMngr.CleanUp();

            //Kimimaru: Time out so we don't softlock everything if all devices cannot be freed
            //While this is an issue if it happens, we'll let the streamer know without permanently suspending inputs
            const long timeOut = 60000L;

            //Wait at least this much time before checking to give it some time
            const long minWait = 300L;

            Stopwatch sw = Stopwatch.StartNew();

            //Wait until all devices are no longer owned
            while (true)
            {
                if (sw.ElapsedMilliseconds < minWait)
                {
                    continue;
                }

                int freeCount = 0;

                for (int i = 0; i < InputGlobals.ControllerMngr.ControllerCount; i++)
                {
                    if (InputGlobals.ControllerMngr.GetController(i).IsAcquired == false)
                    {
                        freeCount++;
                    }
                }

                //We're done if all are no longer owned
                if (freeCount == InputGlobals.ControllerMngr.ControllerCount)
                {
                    break;
                }

                if (sw.ElapsedMilliseconds >= timeOut)
                {
                    BotProgram.MsgHandler.QueueMessage($"ERROR: Unable to free all virtual controllers. {freeCount}/{InputGlobals.ControllerMngr.ControllerCount} freed.");
                    break;
                }
            }

            int acquiredCount = InputGlobals.ControllerMngr.InitControllers(newJoystickCount);

            Console.WriteLine($"Acquired {acquiredCount} controllers!");

            const long wait = 500L;

            sw.Stop();
            sw.Reset();
            sw.Start();

            //Wait again to reinitialize
            while (sw.ElapsedMilliseconds < wait)
            {
            }

            InputHandler.ResumeRunningInputs();

            BotProgram.BotData.JoystickCount = newJoystickCount;
            BotProgram.SaveBotData();

            BotProgram.MsgHandler.QueueMessage("Controllers reinitialized and inputs resumed!");
        }
        public override void ExecuteCommand(EvtChatCommandArgs e)
        {
            string name        = e.Command.ChatMessage.DisplayName;
            string nameToLower = name.ToLower();

            if (DuelCommand.DuelRequests.ContainsKey(nameToLower) == true)
            {
                DuelCommand.DuelData data = DuelCommand.DuelRequests[nameToLower];
                DuelCommand.DuelRequests.Remove(nameToLower);

                TimeSpan diff = DateTime.Now - data.CurDuelTime;

                if (diff.TotalMinutes >= DuelCommand.DUEL_MINUTES)
                {
                    BotProgram.MsgHandler.QueueMessage("You are not in a duel or your duel has expired!");
                    return;
                }

                long   betAmount     = data.BetAmount;
                string dueled        = data.UserDueling;
                string dueledToLower = dueled.ToLower();

                User duelerUser = BotProgram.GetUser(nameToLower);
                User dueledUser = BotProgram.GetUser(dueledToLower);

                //First confirm both users have enough credits for the duel, as they could've lost some in that time
                if (duelerUser.Credits < betAmount || dueledUser.Credits < betAmount)
                {
                    BotProgram.MsgHandler.QueueMessage("At least one user involved in the duel no longer has enough points for the duel! The duel is off!");
                    return;
                }

                //50/50 chance of either user winning
                int val = Rand.Next(0, 2);

                string message = string.Empty;

                if (val == 0)
                {
                    duelerUser.AddCredits(betAmount);
                    dueledUser.SubtractCredits(betAmount);

                    message = $"{name} won the bet against {dueled} for {betAmount} credit(s)!";
                }
                else
                {
                    duelerUser.SubtractCredits(betAmount);
                    dueledUser.AddCredits(betAmount);

                    message = $"{dueled} won the bet against {name} for {betAmount} credit(s)!";
                }

                BotProgram.SaveBotData();

                BotProgram.MsgHandler.QueueMessage(message);
            }
            else
            {
                BotProgram.MsgHandler.QueueMessage("You are not in a duel or your duel has expired!");
            }
        }
예제 #30
0
        public override void ExecuteCommand(EvtChatCommandArgs e)
        {
            List <string> args = e.Command.ArgumentsAsList;

            if (args.Count < 1)
            {
                BotProgram.MsgHandler.QueueMessage("Usage: state #");
                return;
            }

            string stateNumStr = args[0];

            if (int.TryParse(stateNumStr, out int stateNum) == false)
            {
                BotProgram.MsgHandler.QueueMessage("Invalid state number.");
                return;
            }

            string saveStateStr = $"ss{stateNum}";

            if (InputGlobals.CurrentConsole.ButtonInputMap.ContainsKey(saveStateStr) == false)
            {
                BotProgram.MsgHandler.QueueMessage("Invalid state number.");
                return;
            }

            User user = BotProgram.GetOrAddUser(e.Command.ChatMessage.Username, false);

            //Check if the user can perform this input
            ParserPostProcess.InputValidation inputValidation = ParserPostProcess.CheckInputPermissions(user.Level, saveStateStr, BotProgram.BotData.InputAccess.InputAccessDict);

            //If the input isn't valid, exit
            if (inputValidation.IsValid == false)
            {
                if (string.IsNullOrEmpty(inputValidation.Message) == false)
                {
                    BotProgram.MsgHandler.QueueMessage(inputValidation.Message);
                }

                return;
            }

            //Savestates are always performed on the first controller
            IVirtualController joystick = InputGlobals.ControllerMngr.GetController(0);

            joystick.PressButton(InputGlobals.CurrentConsole.ButtonInputMap[saveStateStr]);
            joystick.UpdateController();

            //Track the time of the savestate
            DateTime curTime = DateTime.UtcNow;

            //Add a new savestate log
            GameLog newStateLog = new GameLog();

            newStateLog.User = e.Command.ChatMessage.Username;

            string date = curTime.ToShortDateString();
            string time = curTime.ToLongTimeString();

            newStateLog.DateTimeString = $"{date} at {time}";

            newStateLog.User       = e.Command.ChatMessage.Username;
            newStateLog.LogMessage = string.Empty;

            //Add the message if one was specified
            if (args.Count > 1)
            {
                string message = e.Command.ArgumentsAsString.Remove(0, stateNumStr.Length + 1);
                newStateLog.LogMessage = message;
            }

            //Add or replace the log and save the bot data
            BotProgram.BotData.SavestateLogs[stateNum] = newStateLog;
            BotProgram.SaveBotData();

            BotProgram.MsgHandler.QueueMessage($"Saved state {stateNum}!");

            //Wait a bit before releasing the input
            const float wait = 50f;
            Stopwatch   sw   = Stopwatch.StartNew();

            while (sw.ElapsedMilliseconds < wait)
            {
            }

            joystick.ReleaseButton(InputGlobals.CurrentConsole.ButtonInputMap[saveStateStr]);
            joystick.UpdateController();
        }