public int?Execute <TProgram>(TextWriter consoleOut) where TProgram : IRuntimeProgram, new() { Console.SetOut(consoleOut); var command = new RuntimeCommand(); var result = command.Execute <TProgram>(); return(command.Restarted ? (int?)null : result); }
public void RuntimeCommand_Test() { var runtime = new RuntimeCommand(); runtime.Execute(); }
/// <summary> /// Creates a new instance. /// </summary> /// <param name="template">The template that identifies the command - null if this is an application /// configuration.</param> internal CommandConfiguration(Template?template) { RuntimeCommand = new RuntimeCommand <TOptions>(template, () => ParserConfig.ArgumentParsers); }
public void RunCommands(Connection.ChatEventArgs e = null) { foreach (string command in CommandStrings) { string formatted = command.Trim(); formatted = ParseResult.ReplaceDynamicReferences(formatted, Connection); if (command.Trim().StartsWith("!") || command.Trim().StartsWith("%")) { if (command.Trim().StartsWith("!!")) { formatted = formatted.TrimStart("@".ToCharArray()); // I don't remember why this is necessary } else { // Remove the command-enclosing '%' characters formatted = command.RemoveFirst('%', 2); } while (formatted.StartsWith("!")) { // Remove '!' characters formatted = formatted.Remove(0, 1); } if (RuntimeCommand.StringStartsWithCommandName(formatted)) { RuntimeCommand.TryRunCommand($"!{formatted}", null, Connection); } else { Connection.RconCommandQueue.Enqueue( RconCommand.ConsoleLogCommand( formatted, formatted, e?.SendingPlayer?.Name ?? "SERVER" ) ); } } else { if (formatted.StartsWith("!")) { if (RuntimeCommand.StringStartsWithCommandName(formatted.TrimStart(1))) { RuntimeCommand.TryRunCommand(formatted, null, Connection); } else { Connection.RconCommandQueue.Enqueue( RconCommand.ConsoleLogCommand( formatted, formatted, e?.SendingPlayer?.Name ?? "SERVER" ) ); } } else { if (RuntimeCommand.StringStartsWithCommandName(formatted)) { RuntimeCommand.TryRunCommand($"!{formatted}", null, Connection); } else { Connection.RconCommandQueue.Enqueue( RconCommand.ConsoleLogCommand( formatted, formatted, e?.SendingPlayer?.Name ?? "SERVER" ) ); } } } } }
/// <summary> /// Generate a <see cref="ParseResult"/> for the specified <see cref="RuntimeCommand"/> (<paramref name="command"/>) by parsing the command string (<paramref name="message"/>) sent by <see cref="PlayerInfo"/> (<paramref name="player"/>) (or RCON connected admin client) for the specified <see cref="Connection"/> (<paramref name="connection"/>), and store the related <see cref="Message"/> (<paramref name="chatMessage"/>) if applicable. /// </summary> /// <param name="connection">The relevant connection used to Parse the <paramref name="command"/>, respond to the <paramref name="player"/> if applicable, and store the <paramref name="chatMessage"/> if applicable.</param> /// <param name="message">The string that will be parsed for args and DynamicReferences for the <see cref="RuntimeCommand"/> being evaluated</param> /// <param name="player">The player whose message is being parsed.</param> /// <param name="command">The RuntimeCommand being parsed.</param> /// <param name="chatMessage">The ChatMessage containing the RuntimeCommand being parsed.</param> public ParseResult(Connection connection, string message, PlayerInfo player, RuntimeCommand command, Message chatMessage) { if (connection == null) { IsValid = false; } ChatMessage = chatMessage; ReplaceDynamicReferences(message, connection); // Add a copy of the command submitted by the player or server to the list of responses // To player if (player != null) { if (message.Length + player.Name.Length + 3 > 128) { Response.Add("@" + player.Name + ":"); // Response.Add(" " + message); <- Previously there was a space here, but I think that would mess up, becuase it would be ' !whatever...', which would be flagged as a command I'm pretty sure Response.Add("@" + message); } else { Response.Add("@" + player.Name + ": " + message); } } // To server else { if (message.Length + 9 > 128) { Response.Add("@SERVER:"); // Response.Add(" " + message); <- Previously there was a space here, but I think that would mess up, becuase it would be ' !whatever...', which would be flagged as a command I'm pretty sure Response.Add("@" + message); } else { Response.Add($"@SERVER: {message}"); } } // Confirm authorization if (command.AdminCommand && player != null) { if (!connection.Settings.AuthorizedUIDs.Contains(player.Uid ?? "")) { IsValid = false; Add("You are not authorized to use this command."); return; } } // Process Args if (command.Args.Count > 0) { //TODO '!pm Player "message in quotes"' only sends 'message' - i.e. only the first word of the quoted message //TODO '!pm Player message with "quoted content" inside' only sends 'message with quoted' - so it cuts off everything after the first word after quotation mark // message with command trigger trimmed string content = message.TrimStart(command.Trigger.Length).Trim(); foreach (Arg arg in command.Args) { switch (arg.ArgType) { case Arg.Type.PlayerName: List <string> players = null; lock (connection.State.ServerStateLock) { players = connection.State.Players.Select(x => x.Name).ToList(); } Parameters.Add(BestMatch(players, content, arg, false)); break; case Arg.Type.BaseMap: Parameters.Add(BestMatch(MapVariant.BaseMapIDsByNameLower.Keys.ToList(), content, arg)); break; case Arg.Type.MapName: Parameters.Add(BestMatch(connection.MapVariantNames, content, arg, false)); break; case Arg.Type.BaseVariant: Parameters.Add(BestMatch(GameVariant.BaseGamesByNameLower.Keys.ToList(), content, arg)); break; case Arg.Type.VariantName: Parameters.Add(BestMatch(connection.GameVariantNames, content, arg, false)); break; case Arg.Type.String: Parameters.Add(string.IsNullOrWhiteSpace(content) ? null : content); break; case Arg.Type.FileNameJSON: if (!string.IsNullOrWhiteSpace(content) && content.Contains(".json")) { Parameters.Add(content.Substring(0, content.IndexOf(".json") + 5)); } else { Parameters.Add(null); } break; case Arg.Type.LanguageCode: if (!string.IsNullOrWhiteSpace(content) && content.Length >= 4 && content.StartsWith("-") && content.Contains(' ')) { // format is "-ab *whatever*" | ab = any language code content = content.TrimStart(1); Parameters.Add(content.Substring(0, content.IndexOf(' '))); } else { Parameters.Add(null); } break; case Arg.Type.CommandName: if (!string.IsNullOrWhiteSpace(content)) { ToolCommand toolCommand = connection.Settings.Commands.First(x => x.Name.StartsWith(content)); if (toolCommand != null) { Parameters.Add(content); } else { Parameters.Add(null); } } else { Parameters.Add(null); } break; default: break; } if (Parameters[Parameters.Count - 1] != null) { // update content string content = content.Substring(Parameters[Parameters.Count - 1].Length, (content.Length - Parameters[Parameters.Count - 1].Length)).Trim(); } else if (arg.IsRequired) { IsValid = false; Response.Add("Command Failed: Unable to parse " + arg.Name + " parameter."); } // Add response and return if invalid if (!IsValid) { switch (arg.ArgType) { case Arg.Type.PlayerName: Response.Add("Player names must be unquoted and correctly capitalized."); return; case Arg.Type.BaseMap: Response.Add("Base map names must be unquoted, with any spaces removed."); return; case Arg.Type.MapName: Response.Add("Map names must be unquoted and correctly capitalized."); return; case Arg.Type.BaseVariant: Response.Add("Base gametype names must be unquoted, with any spaces removed."); return; case Arg.Type.VariantName: Response.Add("Game variant names must be unquoted and correctly capitalized."); return; case Arg.Type.FileNameJSON: Response.Add("JSON file names must end in '.json'."); return; case Arg.Type.LanguageCode: Response.Add("Language code format is either '-aa' or '-aa-bb'."); return; case Arg.Type.CommandName: Response.Add("Command names must be unquoted and correctly capitalized."); return; default: return; } } } } }