private void ExecuteNewArg(User user) { //Generate the exercise Parser.InputSequence newSequence = GenerateExercise(InputGlobals.CurrentConsole); //Give greater credit rewards for longer input sequences long creditReward = newSequence.Inputs.Count * BaseCreditReward; InputExercise inputExercise = new InputExercise(newSequence, creditReward); UserExercises[user.Name] = inputExercise; OutputInputExercise(inputExercise); }
public override void ExecuteCommand(EvtChatCommandArgs e) { string args = e.Command.ArgumentsAsString; if (string.IsNullOrEmpty(args) == true) { BotProgram.MsgHandler.QueueMessage("Usage: \"Input\""); return; } //Parse the input //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(args)); inputSequence = Parser.ParseInputs(parse_message, 0, true, true); //parsedVal = Parser.Parse(parse_message); } catch { inputSequence.InputValidationType = Parser.InputValidationTypes.Invalid; //parsedVal.Item1 = false; } if (inputSequence.InputValidationType != Parser.InputValidationTypes.Valid) { BotProgram.MsgHandler.QueueMessage("Invalid input. Note that length cannot be determined for dynamic macros without inputs filled in."); return; } BotProgram.MsgHandler.QueueMessage($"Total length: {inputSequence.TotalDuration}ms"); }
//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 < 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); //} }