private void ButtonSave_Click(object sender, EventArgs e) { if (textBoxName.Text == "") { MessageBox.Show("You must specify a name for the command.", "Name Required", MessageBoxButtons.OK); return; } ToolCommand triggerMatch = null; if (conditionType == ToolCommand.TriggerType.CustomServerCommand) { if (string.IsNullOrWhiteSpace(textBoxCustomServerCommand.Text)) { MessageBox.Show("You must specify text for the custom server command.", "Custom Server Command Text Required", MessageBoxButtons.OK); return; } if (RuntimeCommand.RuntimeCommandAutoCompleteNames.Contains(textBoxCustomServerCommand.Text)) { MessageBox.Show( "There is already a Runtime Command using that trigger, please choose a different trigger.", "Custom Server Command Trigger Conflict", MessageBoxButtons.OK ); return; } if ((currentConnection?.Settings?.Commands?.Count ?? 0) > 0) { triggerMatch = currentConnection.Settings.Commands.DefaultIfEmpty(null).FirstOrDefault(x => x.CustomServerCommand == textBoxCustomServerCommand.Text); } } ToolCommand nameMatch = null; if (GlobalToolCommands.Value.Count > 0) { nameMatch = GlobalToolCommands.Value.DefaultIfEmpty(null).FirstOrDefault(x => x.Name == textBoxName.Text); } if (nameMatch == null && currentConnection.Settings.Commands.Count > 0) { nameMatch = currentConnection.Settings.Commands.DefaultIfEmpty(null).FirstOrDefault(x => x.Name == textBoxName.Text); } if (isEditing) { if (nameMatch != null && nameMatch != commandEditTarget) { MessageBox.Show("The selected name is used by another conditional command, please choose a unique name.", "Unique Name Required", MessageBoxButtons.OK ); return; } else { nameMatch = null; } if (conditionType == ToolCommand.TriggerType.CustomServerCommand && triggerMatch != null && triggerMatch != commandEditTarget) { MessageBox.Show("The selected trigger is used by another command, please choose a unique trigger.", "Unique Trigger Required", MessageBoxButtons.OK ); return; } else { triggerMatch = null; } if (GlobalToolCommands.Value.Contains(commandEditTarget)) { GlobalToolCommands.Value.Remove(commandEditTarget); } else if (currentConnection.Settings.Commands.Contains(commandEditTarget)) { currentConnection.Settings.Commands.Remove(commandEditTarget); } commandEditTarget.Disable(); if (listBox != null) { listBox.Items.Remove(listBox.SelectedItem); } } if (nameMatch != null) { MessageBox.Show("The selected name is used by another conditional command, please choose a unique name.", "Unique Name Required", MessageBoxButtons.OK); return; } if (conditionType == ToolCommand.TriggerType.CustomServerCommand && triggerMatch != null) { MessageBox.Show("The selected trigger is used by another command, please choose a unique trigger.", "Unique Trigger Required", MessageBoxButtons.OK ); return; } #region Get Player Count Operator Value Enum.TryParse(comboBoxConditionType.SelectedValue.ToString(), out conditionType); switch (buttonCondition_PlayerCount_OperatorSelection.Text) { case ">": conditionOperator = ToolCommand.Operator.GreatherThan; break; case "<": conditionOperator = ToolCommand.Operator.LessThan; break; case "=": conditionOperator = ToolCommand.Operator.EqualTo; break; case ">=": conditionOperator = ToolCommand.Operator.GreaterThanOrEqualTo; break; case "<=": conditionOperator = ToolCommand.Operator.LessThanOrEqualTo; break; } #endregion List <string> commands = new List <string>( autoCompleteTextBoxCommands.Text.Split(new string[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries) ); int runTime; switch (conditionType) { case ToolCommand.TriggerType.EveryXMinutes: runTime = (int)numericUpDownRunIntervalMinutes.Value; break; case ToolCommand.TriggerType.Daily: runTime = comboBoxDailyCommandTime.SelectedIndex; break; default: runTime = 0; break; } ToolCommand command = new ToolCommand( textBoxName.Text, true, commands, conditionType, conditionOperator, (int)numericUpDownThreshold.Value, currentConnection.Settings, textBoxCustomServerCommand.Text, selectionRangeSliderPlayerCountRange.SelectedMin, selectionRangeSliderPlayerCountRange.SelectedMax, runTime, textBoxCommandTag.Text ); if (command.IsGlobalToolCommand) { command.IsGlobalToolCommand = true; GlobalToolCommands.Value.Add(command); } else { currentConnection.Settings.Commands.Add(command); command.Initialize(currentConnection); } if (listBox != null) { listBox.Items.Add( new Tuple <string, ToolCommand>(command.Name, command) ); } SaveSettings(); Close(); }
public ToolCommandEditor(ListBox listBox = null, ToolCommand command = null) { InitializeComponent(); //autoCompleteTextBoxCommands.Values = autoCompleteTextBoxCommandsList; autoCompleteTextBoxCommands.HandleCreated += (o, e) => { autoCompleteTextBoxCommands.Values = autoCompleteTextBoxCommandsList; //List<string> vals = new List<string>(ConsoleAutoCompleteStrings); //vals.AddRange((IEnumerable<string>)RuntimeCommand.RuntimeCommands); //autoCompleteTextBoxCommands.Values = vals.ToArray(); }; commandEditor = this; if (listBox != null) { this.listBox = listBox; } comboBoxConditionType.DataSource = Enum.GetValues(typeof(ToolCommand.TriggerType)); if (command != null) { isEditing = true; commandEditTarget = command; // set controls to display existing properties textBoxName.Text = command.Name; conditionType = command.ConditionType; comboBoxConditionType.SelectedItem = (conditionType); conditionOperator = command.ConditionOperator; buttonOperatorSelection_SetText(); numericUpDownThreshold.Value = command.ConditionThreshold; selectionRangeSliderPlayerCountRange.SelectedMin = command.PlayerCountRangeMin; selectionRangeSliderPlayerCountRange.SelectedMax = command.PlayerCountRangeMax; comboBoxDailyCommandTime.SelectedIndex = command.RunTime; textBoxCustomServerCommand.Text = command.CustomServerCommand; textBoxCommandTag.Text = command.Tag; switch (conditionType) { case ToolCommand.TriggerType.EveryXMinutes: numericUpDownRunIntervalMinutes.Value = command.RunTime; checkBoxGlobalCommand.Enabled = true; break; case ToolCommand.TriggerType.Daily: comboBoxDailyCommandTime.SelectedIndex = command.RunTime; checkBoxGlobalCommand.Enabled = true; break; default: break; } if (command.IsGlobalToolCommand) { checkBoxGlobalCommand.Checked = true; checkBoxGlobalCommand.CheckState = CheckState.Checked; } foreach (string commandString in command.CommandStrings) { autoCompleteTextBoxCommands.AppendText(commandString + System.Environment.NewLine); } } textBoxName.Select(); textBoxName.Focus(); }
/// <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; } } } } }