diff --git a/sources/BaseAPI/API/Commands/Command.uc b/sources/BaseAPI/API/Commands/Command.uc index d3f67d9..0c60987 100644 --- a/sources/BaseAPI/API/Commands/Command.uc +++ b/sources/BaseAPI/API/Commands/Command.uc @@ -1,12 +1,8 @@ /** - * This class is meant to represent a command type: to create new command - * one should extend it, then simply define required sub-commands/options and - * parameters in `BuildData()` and overload `Executed()` / `ExecutedFor()` - * to perform required actions when command is executed by a player. - * `Executed()` is called first, whenever command is executed and - * `ExecuteFor()` is called only for targeted commands, once for each - * targeted player. - * Copyright 2021-2022 Anton Tarasenko + * Author: dkanus + * Home repo: https://www.insultplayers.ru/git/AcediaFramework/AcediaCore + * License: GPL + * Copyright 2021-2023 Anton Tarasenko *------------------------------------------------------------------------------ * This file is part of Acedia. * @@ -26,277 +22,234 @@ class Command extends AcediaObject dependson(BaseText); -/** - * # `Command` - * - * Command class provides an automated way to add a command to a server through - * AcediaCore's features. It takes care of: - * - * 1. Verifying that player has passed correct (expected parameters); - * 2. Parsing these parameters into usable values (both standard, built-in - * types like `bool`, `int`, `float`, etc. and more advanced types such - * as players lists and JSON values); - * 3. Allowing you to easily specify a set of players you are targeting by - * supporting several ways to refer to them, such as *by name*, *by id* - * and *by selector* (@ and @self refer to caller player, @all refers - * to all players). - * 4. It can be registered inside AcediaCore's commands feature and be - * automatically called through the unified system that supports *chat* - * and *mutate* inputs (as well as allowing you to hook in any other - * input source); - * 5. Will also automatically provide a help page through built-in "help" - * command; - * 6. Subcommand support - when one command can have several distinct - * functions, depending on how its called (e.g. "inventory add" vs - * "inventory remove"). These subcommands have a special treatment in - * help pages, which makes them more preferable, compared to simply - * matching first `Text` argument; - * 7. Add support for "options" - additional flags that can modify commands - * behavior and behave like usual command options "--force"/"-f". - * Their short versions can even be combined: - * "give@ $ebr --ammo --force" can be rewritten as "give@ $ebr -af". - * And they can have their own parameters: "give@all --list sharp". - * - * ## Usage - * - * To create a custom command you need to simply: - * - * 1. Create a custom command class derived from `Command`; - * 2. Define `BuildData()` function and use given `CommandDataBuilder` to - * fill-in data about what parameters your command takes. You can also - * add optional descriptions that would appear in your command's - * help page. - * 3. Overload `Executed()` or `ExecutedFor()` (or both) method and add - * whatever logic you want to execute once your command was called. - * All parameters and options will be listed inside passed `CallData` - * parameter. These methods will only be called if all necessary - * parameters were correctly specified. - * - * ## Implementation - * - * The idea of `Command`'s implementation is simple: command is basically - * the `Command.Data` struct that is filled via `CommandDataBuilder`. - * Whenever command is called it uses `CommandParser` to parse user's input - * based on its `Command.Data` and either report error (in case of failure) or - * pass make `Executed()`/`ExecutedFor()` calls (in case of success). - * When command is called is decided by `Commands_Feature` that tracks - * possible user inputs (and provides `HandleInput()`/`HandleInputWith()` - * methods for adding custom command inputs). That feature basically parses - * first part of the command: its name (not the subcommand's names) and target - * players (using `PlayersParser`, but only if command is targeted). - * - * Majority of the command-related code either serves to build - * `Command.Data` or to parse command input by using it (`CommandParser`). - */ - -/** - * Possible errors that can arise when parsing command parameters from - * user input - */ -enum ErrorType -{ - // No error +//! This class is meant to represent a command type. +//! +//! Command class provides an automated way to add a command to a server through +//! AcediaCore's features. It takes care of: +//! +//! 1. Verifying that player has passed correct (expected parameters); +//! 2. Parsing these parameters into usable values (both standard, built-in +//! types like `bool`, `int`, `float`, etc. and more advanced types such +//! as players lists and JSON values); +//! 3. Allowing you to easily specify a set of players you are targeting by +//! supporting several ways to refer to them, such as *by name*, *by id* +//! and *by selector* (@ and @self refer to caller player, @all refers +//! to all players). +//! 4. It can be registered inside AcediaCore's commands feature and be +//! automatically called through the unified system that supports *chat* +//! and *mutate* inputs (as well as allowing you to hook in any other +//! input source); +//! 5. Will also automatically provide a help page through built-in "help" +//! command; +//! 6. Subcommand support - when one command can have several distinct +//! functions, depending on how its called (e.g. "inventory add" vs +//! "inventory remove"). These subcommands have a special treatment in +//! help pages, which makes them more preferable, compared to simply +//! matching first `Text` argument; +//! 7. Add support for "options" - additional flags that can modify commands +//! behavior and behave like usual command options "--force"/"-f". +//! Their short versions can even be combined: +//! "give@ $ebr --ammo --force" can be rewritten as "give@ $ebr -af". +//! And they can have their own parameters: "give@all --list sharp". +//! +//! # Implementation +//! +//! The idea of `Command`'s implementation is simple: command is basically the `Command.Data` struct +//! that is filled via `CommandDataBuilder`. +//! Whenever command is called it uses `CommandParser` to parse user's input based on its +//! `Command.Data` and either report error (in case of failure) or pass make +//! `Executed()`/`ExecutedFor()` calls (in case of success). +//! +//! When command is called is decided by `Commands_Feature` that tracks possible user inputs +//! (and provides `HandleInput()`/`HandleInputWith()` methods for adding custom command inputs). +//! That feature basically parses first part of the command: its name (not the subcommand's names) +//! and target players (using `PlayersParser`, but only if command is targeted). +//! +//! Majority of the command-related code either serves to build `Command.Data` or to parse command +//! input by using it (`CommandParser`). + +/// Possible errors that can arise when parsing command parameters from user input +enum ErrorType { + // No error CET_None, - // Bad parser was provided to parse user input - // (this should not be possible) + // Bad parser was provided to parse user input (this should not be possible) CET_BadParser, - // Sub-command name was not specified or was incorrect - // (this should not be possible) + // Sub-command name was not specified or was incorrect + // (this should not be possible) CET_NoSubCommands, - // Specified sub-command does not exist - // (only relevant when it is enforced for parser, e.g. by an alias) + // Specified sub-command does not exist + // (only relevant when it is enforced for parser, e.g. by an alias) CET_BadSubCommand, - // Required param for command / option was not specified + // Required param for command / option was not specified CET_NoRequiredParam, CET_NoRequiredParamForOption, - // Unknown option key was specified + // Unknown option key was specified CET_UnknownOption, CET_UnknownShortOption, - // Same option appeared twice in one command call + // Same option appeared twice in one command call CET_RepeatedOption, - // Part of user's input could not be interpreted as a part of - // command's call + // Part of user's input could not be interpreted as a part of + // command's call CET_UnusedCommandParameters, - // In one short option specification (e.g. '-lah') several options - // require parameters: this introduces ambiguity and is not allowed + // In one short option specification (e.g. '-lah') several options require parameters: + // this introduces ambiguity and is not allowed CET_MultipleOptionsWithParams, - // (For targeted commands only) - // Targets are specified incorrectly (or none actually specified) + // (For targeted commands only) + // Targets are specified incorrectly (or none actually specified) CET_IncorrectTargetList, CET_EmptyTargetList }; -/** - * Structure that contains all the information about how `Command` was called. - */ -struct CallData -{ - // Targeted players (if applicable) - var public array targetPlayers; - // Specified sub-command and parameters/options - var public Text subCommandName; - // Provided parameters and specified options - var public HashTable parameters; - var public HashTable options; - // Errors that occurred during command call processing are described by - // error type and optional error textual name of the object - // (parameter, option, etc.) that caused it. - var public ErrorType parsingError; - var public Text errorCause; +/// Structure that contains all the information about how `Command` was called. +struct CallData { + // Targeted players (if applicable) + var public array targetPlayers; + // Specified sub-command and parameters/options + var public Text subCommandName; + // Provided parameters and specified options + var public HashTable parameters; + var public HashTable options; + // Errors that occurred during command call processing are described by + // error type and optional error textual name of the object + // (parameter, option, etc.) that caused it. + var public ErrorType parsingError; + var public Text errorCause; }; -/** - * Possible types of parameters. - */ -enum ParameterType -{ - // Parses into `BoolBox` +/// Possible types of parameters. +enum ParameterType { + // Parses into `BoolBox` CPT_Boolean, - // Parses into `IntBox` + // Parses into `IntBox` CPT_Integer, - // Parses into `FloatBox` + // Parses into `FloatBox` CPT_Number, - // Parses into `Text` + // Parses into `Text` CPT_Text, - // Special parameter that consumes the rest of the input into `Text` + // Special parameter that consumes the rest of the input into `Text` CPT_Remainder, - // Parses into `HashTable` + // Parses into `HashTable` CPT_Object, - // Parses into `ArrayList` + // Parses into `ArrayList` CPT_Array, - // Parses into any JSON value + // Parses into any JSON value CPT_JSON, - // Parses into an array of specified players + // Parses into an array of specified players CPT_Players }; -/** - * Possible forms a boolean variable can be used as. - * Boolean parameter can define it's preferred format, which will be used - * for help page generation. - */ -enum PreferredBooleanFormat -{ +/// Possible forms a boolean variable can be used as. +/// Boolean parameter can define it's preferred format, which will be used for help page generation. +enum PreferredBooleanFormat { PBF_TrueFalse, PBF_EnableDisable, PBF_OnOff, PBF_YesNo }; -// Defines a singular command parameter -struct Parameter -{ - // Display name (for the needs of help page displaying) - var Text displayName; - // Type of value this parameter would store - var ParameterType type; - // Does it take only a singular value or can it contain several of them, - // written in a list - var bool allowsList; - // Variable name that will be used as a key to store parameter's value - var Text variableName; - // (For `CPT_Boolean` type variables only) - preferred boolean format, - // used in help pages +// Defines a singular command parameter +struct Parameter { + // Display name (for the needs of help page displaying) + var Text displayName; + // Type of value this parameter would store + var ParameterType type; + // Does it take only a singular value or can it contain several of them, + // written in a list + var bool allowsList; + // Variable name that will be used as a key to store parameter's value + var Text variableName; + // (For `CPT_Boolean` type variables only) - preferred boolean format, + // used in help pages var PreferredBooleanFormat booleanFormat; - // `CPT_Text` can be attempted to be auto-resolved as an alias from - /// some source during parsing. For command to attempt that, this field must - // be not-`none` and contain the name of the alias source (either "weapon", - // "color", "feature", "entity" or some kind of custom alias source name). - // Only relevant when given value is prefixed with "$" character. - var Text aliasSourceName; + // `CPT_Text` can be attempted to be auto-resolved as an alias from some source during parsing. + // For command to attempt that, this field must be not-`none` and contain the name of + // the alias source (either "weapon", "color", "feature", "entity" or some kind of custom alias + // source name). + // + // Only relevant when given value is prefixed with "$" character. + var Text aliasSourceName; }; -// Defines a sub-command of a this command (specified as -// " "). -// Using sub-command is not optional, but if none defined -// (in `BuildData()`) / specified by the player - an empty (`name.IsEmpty()`) -// one is automatically created / used. -struct SubCommand -{ - // Cannot be `none` - var Text name; - // Can be `none` +// Defines a sub-command of a this command (specified as " "). +// +// Using sub-command is not optional, but if none defined (in `BuildData()`) / specified by +// the player - an empty (`name.IsEmpty()`) one is automatically created / used. +struct SubCommand { + // Cannot be `none` + var Text name; + // Can be `none` var Text description; - var array required; - var array optional; + var array required; + var array optional; }; -// Defines command's option (options are specified by "--long" or "-l"). -// Options are independent from sub-commands. -struct Option -{ - var BaseText.Character shortName; - var Text longName; - var Text description; - // Option can also have their own parameters - var array required; - var array optional; +// Defines command's option (options are specified by "--long" or "-l"). +// Options are independent from sub-commands. +struct Option { + var BaseText.Character shortName; + var Text longName; + var Text description; + // Option can also have their own parameters + var array required; + var array optional; }; -// Structure that defines what sub-commands and options command has -// (and what parameters they take) -struct Data -{ - // Default command name that will be used unless Acedia is configured to - // do otherwise - var protected Text name; - // Command group this command belongs to - var protected Text group; - // Short summary of what command does (recommended to - // keep it to 80 characters) - var protected Text summary; +// Structure that defines what sub-commands and options command has +// (and what parameters they take) +struct Data { + // Default command name that will be used unless Acedia is configured to + // do otherwise + var protected Text name; + // Command group this command belongs to + var protected Text group; + // Short summary of what command does (recommended to + // keep it to 80 characters) + var protected Text summary; var protected array subCommands; - var protected array