public void EmployeeApiReturnsData() { var processedString = EmployeeList.Aggregate("", (current, employee) => current + ($"ID: {employee.Id}\r\n" + $"Name: {employee.Name}\r\n" + $"Start Date: {employee.StartDate:dd/MM/yyyy}\r\n\r\n")); ProcessedCommand.Should().BeEquivalentTo(processedString); }
private static void ParseCommands(string commandFile, string outputFolder) { using (StreamReader reader = new StreamReader(commandFile)) { RawCommands rawCommands = RawCommands.FromJson(reader.ReadToEnd()); ProcessedCommands processedModeratorCommands = new ProcessedCommands(); ProcessedCommands processedViewerCommands = new ProcessedCommands(); ProcessedCommands processedPawnCommands = new ProcessedCommands(); foreach (RawCommand rawCommand in rawCommands.Commands) { if (string.IsNullOrWhiteSpace(rawCommand.Name)) { continue; } if (rawCommand.Usage.StartsWith("!rwdata")) { continue; } ProcessedCommand processedCommand = ProcessedCommand.FromRawCommand(rawCommand); if (rawCommand.UserLevel == UserLevel.Moderator) { processedModeratorCommands.Commands.Add(processedCommand); } else { if (IsPawnCommand(rawCommand.Usage)) { processedPawnCommands.Commands.Add(processedCommand); } else { processedViewerCommands.Commands.Add(processedCommand); } } } string outputFileModerator = Path.Combine(outputFolder, "SiteCommandsModerator.json"); string outputFileViewer = Path.Combine(outputFolder, "SiteCommandsViewer.json"); string outputFilePawn = Path.Combine(outputFolder, "SiteCommandsPawn.json"); GenerateCommandsOutput(processedModeratorCommands, outputFileModerator); GenerateCommandsOutput(processedViewerCommands, outputFileViewer); GenerateCommandsOutput(processedPawnCommands, outputFilePawn); } }
private void HandleInput(string input) { if (!input.StartsWith(MessageUtils.CommandPrefix)) { AddMessage(MessageUtils.InvalidInput); return; } string[] words = InputUtils.ProcessInput(input); if (words.Length > 0) { string keyword = words[0]; string[] args = words.Skip(1).ToArray(); ProcessedCommand processedCommand = gameController.ProcessCommand(keyword, args); AddMessage(processedCommand.Result); // Tells the Game Controller the command has been processed and displayed so it can process additional commands if needed gameController.CommandAddedToMessages(processedCommand); } }
// Called after a command from user's input has been processed and displayed // Processes a new command if needed, e.g. displays the turn info or ends a battle after a character has played public void CommandAddedToMessages(ProcessedCommand processedCommand) { if (processedCommand.Command is null) { return; } if (battleController.InBattle) { BattleUpdate battleUpdate = battleController.CheckState(); if (battleUpdate == BattleUpdate.Error) { return; } ProcessedCommand additionalCommand = ProcessNewBattleCommand(battleUpdate); // Lets the console know a new command has been processed and needs to be displayed OnAdditionalCommandProcessed(additionalCommand); } }
public void EmployeeApiReturnsData() => ProcessedCommand.Should().BeEquivalentTo(Employee.ToString());
/// <summary> /// Matches a trigger. Also allows for the variable replacement triggers to be explicitly ignored by the caller /// regardless of how they're setup by the user. This is important because the screen rendering code from AvalonEdit /// will hit those triggers over and over as each line comes in. Variable replace should be ignored in those cases /// because they've already been processed (and in some cases it will cause them to re-process out of order). If you're /// reading variables in from a prompt and getting say, a room name, you want that to process once, when you're there /// and not out of order. To be clear, this isn't replace @ variables in the pattern, it's the part that sets the /// the variable later down the line. The first "variable replacement" has to happen in both cases. /// </summary> /// <param name="line"></param> /// <param name="skipVariableSet">Default false: Whether to explicitly skip variable setting (not replacing).</param> public bool IsMatch(string line, bool skipVariableSet = false) { Match match; // Does this trigger contain any variables? If so, we'll need to special handle it. We're also // going to require that the VariableReplacement value is set to true so the player has to // specifically opt into this. Since the Gag triggers run -a lot- on the terminal rendering // the bool will be more performant as a first check before the string contains check. This is // a micro optimization that had real payoff in the performance profiler. if (this.VariableReplacement && Pattern.Contains('@', StringComparison.Ordinal)) { // Replace any variables with their literal values. string tempPattern = this.Conveyor.ReplaceVariablesWithValue(Pattern); var tempRegex = new Regex(tempPattern, RegexOptions.IgnoreCase); match = tempRegex.Match(line); } else { // Run the match normal Match, this will be most all cases. match = _regex?.Match(line); } // If it's not a match, get out. if (match == null || !match.Success) { return(false); } // If it's supposed to auto disable itself after it fires then set that. if (this.DisableAfterTriggered) { this.Enabled = false; } // Save the match for CLR processing if needed. this.Match = match; // Do we skip the variable set (used mainly when this is called from gags)... also skips the TriggeringText and // ProcessedCommand sets because they're not needed in this case. I haven't had ANY issues with this in a lot of // testing but since Trigger is a reference we need to be careful about race conditions that might arise from // using the below properties if anything that's async takes advantage of this (you could get some hard to track down // bugs in that case where one trigger set the ProcessedCommand and another set it to another value before the first // had finished its Command). if (skipVariableSet == false) { // Save the text that triggered this trigger so that it can be used if needed elsewhere like in // a CLR trigger. TriggeringText = line; // Setup the command that we may or may not process ProcessedCommand = this.Command; // Allow the user to have the content of the last trigger if they need it. if (this.IsLua == false) { ProcessedCommand = ProcessedCommand.Replace("%0", TriggeringText); } else { ProcessedCommand = ProcessedCommand.Replace("%0", TriggeringText.Replace("\"", "\\\"")); } // Go through any groups backwards that came back in the trigger match. Groups are matched in reverse // order so that %1 doesn't overwrite %12 and leave a trailing 2. for (int i = match.Groups.Count - 1; i >= 0; i--) { // If it's a named match, we specifically named it in the trigger and thus we're going // to automatically store it in a variable that can then be used later by aliases, triggers, etc. // If there are variables that came back that aren't named, throw those into the more generic // %1, %2, %3 values. if (!string.IsNullOrWhiteSpace(match.Groups[i].Name) && !match.Groups[i].Name.IsNumeric() && !string.IsNullOrWhiteSpace(match.Groups[i].Value)) { Conveyor.SetVariable(match.Groups[i].Name, match.Groups[i].Value); } else { // TODO - Consider StringBuilder // TODO - Consider doing both the variables sets, and then ALSO the pattern matches. // Replace %1, %2, etc. variables with their values from the pattern match. if (this.IsLua == false) { ProcessedCommand = ProcessedCommand.Replace($"%{i}", match.Groups[i].Value); } else { ProcessedCommand = ProcessedCommand.Replace($"%{i}", match.Groups[i].Value.Replace("\"", "\\\"")); } } } } // If the profile setting to track the last trigger date is set then set it. if (this.Conveyor.ProfileSettings.TrackTriggerLastMatched) { this.LastMatched = DateTime.Now; } return(match.Success); }
private void OnAdditionalCommandProcessed(ProcessedCommand processedCommand) => AdditionalCommandProcessed?.Invoke(this, new ProcessedCommandEventArgs() { ProcessedCommand = processedCommand });