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(); }
//NOTE: This would result in lots of code duplication if other streaming services were integrated //Is there a better way to do this? private void ProcessMsgAsInput(User userData, EvtUserMessageArgs e) { //Don't process for inputs if a meme string possibleMeme = e.UsrMessage.Message.ToLower(); if (BotProgram.BotData.Memes.TryGetValue(possibleMeme, out string meme) == true) { return; } //Ignore commands as inputs if (possibleMeme.StartsWith(Globals.CommandIdentifier) == true) { return; } //If there are no valid inputs, don't attempt to parse if (InputGlobals.CurrentConsole.ValidInputs == null || InputGlobals.CurrentConsole.ValidInputs.Length == 0) { return; } //Parser.InputSequence inputSequence = default; //(bool, List<List<Parser.Input>>, bool, int) parsedVal = default; Parser.InputSequence inputSequence = default; try { string parse_message = Parser.Expandify(Parser.PopulateMacros(e.UsrMessage.Message)); inputSequence = Parser.ParseInputs(parse_message, userData.Team, true, true); //parsedVal = Parser.Parse(parse_message); //Console.WriteLine(inputSequence.ToString()); //Console.WriteLine("\nReverse Parsed: " + ReverseParser.ReverseParse(inputSequence)); //Console.WriteLine("\nReverse Parsed Natural:\n" + ReverseParser.ReverseParseNatural(inputSequence)); } catch (Exception exception) { string excMsg = exception.Message; //Kimimaru: Sanitize parsing exceptions //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.MsgHandler.QueueMessage($"ERROR: {excMsg}"); inputSequence.InputValidationType = Parser.InputValidationTypes.Invalid; //parsedVal.Item1 = false; } //Check for non-valid messages if (inputSequence.InputValidationType != Parser.InputValidationTypes.Valid) { //Display error message for invalid inputs if (inputSequence.InputValidationType == Parser.InputValidationTypes.Invalid) { BotProgram.MsgHandler.QueueMessage(inputSequence.Error); } return; } //It's a valid message, so process it //Ignore if user is silenced if (userData.Silenced == true) { return; } //Ignore based on user level and permissions if (userData.Level < BotProgram.BotData.InputPermissions) { BotProgram.MsgHandler.QueueMessage($"Inputs are restricted to levels {(AccessLevels.Levels)BotProgram.BotData.InputPermissions} and above"); return; } #region Parser Post-Process Validation /* All this validation is very slow * Find a way to speed it up, ideally without integrating it directly into the parser */ //Check if the user has permission to perform all the inputs they attempted //Also validate that the controller ports they're inputting for are valid ParserPostProcess.InputValidation inputValidation = ParserPostProcess.CheckInputPermissionsAndPorts(userData.Level, inputSequence.Inputs, 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; } //Lastly, check for invalid button combos given the current console if (BotProgram.BotData.InvalidBtnCombos.InvalidCombos.TryGetValue((int)InputGlobals.CurrentConsoleVal, out List <string> invalidCombos) == true) { bool buttonCombosValidated = ParserPostProcess.ValidateButtonCombos(inputSequence.Inputs, invalidCombos); if (buttonCombosValidated == false) { string msg = "Invalid input: buttons ({0}) are not allowed to be pressed at the same time."; string combos = string.Empty; for (int i = 0; i < invalidCombos.Count; i++) { combos += "\"" + invalidCombos[i] + "\""; if (i < (invalidCombos.Count - 1)) { combos += ", "; } } msg = string.Format(msg, combos); BotProgram.MsgHandler.QueueMessage(msg); return; } } #endregion if (InputHandler.StopRunningInputs == false) { //Invoke input event UserMadeInputEvent?.Invoke(userData, e, inputSequence); } else { BotProgram.MsgHandler.QueueMessage("New inputs cannot be processed until all other inputs have stopped."); } }
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 loadStateStr = $"ls{stateNum}"; if (InputGlobals.CurrentConsole.ButtonInputMap.ContainsKey(loadStateStr) == 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, loadStateStr, 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; } //Load states are always performed on the first controller IVirtualController joystick = InputGlobals.ControllerMngr.GetController(0); joystick.PressButton(InputGlobals.CurrentConsole.ButtonInputMap[loadStateStr]); joystick.UpdateController(); BotProgram.MsgHandler.QueueMessage($"Loaded 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[loadStateStr]); joystick.UpdateController(); }