|
|
@ -26,7 +26,7 @@ class Command extends AcediaObject |
|
|
|
//! |
|
|
|
//! |
|
|
|
//! Command class provides an automated way to add a command to a server through |
|
|
|
//! Command class provides an automated way to add a command to a server through |
|
|
|
//! AcediaCore's features. It takes care of: |
|
|
|
//! AcediaCore's features. It takes care of: |
|
|
|
//! |
|
|
|
//! |
|
|
|
//! 1. Verifying that player has passed correct (expected parameters); |
|
|
|
//! 1. Verifying that player has passed correct (expected parameters); |
|
|
|
//! 2. Parsing these parameters into usable values (both standard, built-in |
|
|
|
//! 2. Parsing these parameters into usable values (both standard, built-in |
|
|
|
//! types like `bool`, `int`, `float`, etc. and more advanced types such |
|
|
|
//! types like `bool`, `int`, `float`, etc. and more advanced types such |
|
|
@ -54,92 +54,97 @@ class Command extends AcediaObject |
|
|
|
//! |
|
|
|
//! |
|
|
|
//! # Implementation |
|
|
|
//! # Implementation |
|
|
|
//! |
|
|
|
//! |
|
|
|
//! The idea of `Command`'s implementation is simple: command is basically the `Command.Data` struct |
|
|
|
//! The idea of `Command`'s implementation is simple: command is basically the |
|
|
|
//! that is filled via `CommandDataBuilder`. |
|
|
|
//! `Command.Data` struct that is filled via `CommandDataBuilder`. |
|
|
|
//! Whenever command is called it uses `CommandParser` to parse user's input based on its |
|
|
|
//! Whenever command is called it uses `CommandParser` to parse user's input |
|
|
|
//! `Command.Data` and either report error (in case of failure) or pass make |
|
|
|
//! based on its `Command.Data` and either report error (in case of failure) or |
|
|
|
//! `Executed()`/`ExecutedFor()` calls (in case of success). |
|
|
|
//! pass make `Executed()`/`ExecutedFor()` calls (in case of success). |
|
|
|
//! |
|
|
|
//! |
|
|
|
//! When command is called is decided by `Commands_Feature` that tracks possible user inputs |
|
|
|
//! When command is called is decided by `Commands_Feature` that tracks possible |
|
|
|
//! (and provides `HandleInput()`/`HandleInputWith()` methods for adding custom command inputs). |
|
|
|
//! user inputs (and provides `HandleInput()`/`HandleInputWith()` methods for |
|
|
|
//! That feature basically parses first part of the command: its name (not the subcommand's names) |
|
|
|
//! adding custom command inputs). That feature basically parses first part of |
|
|
|
//! and target players (using `PlayersParser`, but only if command is targeted). |
|
|
|
//! 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 |
|
|
|
//! Majority of the command-related code either serves to build `Command.Data` |
|
|
|
//! input by using it (`CommandParser`). |
|
|
|
//! or to parse command input by using it (`CommandParser`). |
|
|
|
|
|
|
|
|
|
|
|
/// Possible errors that can arise when parsing command parameters from user input |
|
|
|
/// Possible errors that can arise when parsing command parameters from user |
|
|
|
|
|
|
|
/// input |
|
|
|
enum ErrorType { |
|
|
|
enum ErrorType { |
|
|
|
// No error |
|
|
|
/// No error |
|
|
|
CET_None, |
|
|
|
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, |
|
|
|
CET_BadParser, |
|
|
|
// Sub-command name was not specified or was incorrect |
|
|
|
/// Sub-command name was not specified or was incorrect |
|
|
|
// (this should not be possible) |
|
|
|
/// (this should not be possible) |
|
|
|
CET_NoSubCommands, |
|
|
|
CET_NoSubCommands, |
|
|
|
// Specified sub-command does not exist |
|
|
|
/// Specified sub-command does not exist |
|
|
|
// (only relevant when it is enforced for parser, e.g. by an alias) |
|
|
|
/// (only relevant when it is enforced for parser, e.g. by an alias) |
|
|
|
CET_BadSubCommand, |
|
|
|
CET_BadSubCommand, |
|
|
|
// Required param for command / option was not specified |
|
|
|
/// Required param for command / option was not specified |
|
|
|
CET_NoRequiredParam, |
|
|
|
CET_NoRequiredParam, |
|
|
|
CET_NoRequiredParamForOption, |
|
|
|
CET_NoRequiredParamForOption, |
|
|
|
// Unknown option key was specified |
|
|
|
/// Unknown option key was specified |
|
|
|
CET_UnknownOption, |
|
|
|
CET_UnknownOption, |
|
|
|
|
|
|
|
/// Unknown short option key was specified |
|
|
|
CET_UnknownShortOption, |
|
|
|
CET_UnknownShortOption, |
|
|
|
// Same option appeared twice in one command call |
|
|
|
/// Same option appeared twice in one command call |
|
|
|
CET_RepeatedOption, |
|
|
|
CET_RepeatedOption, |
|
|
|
// Part of user's input could not be interpreted as a part of |
|
|
|
/// Part of user's input could not be interpreted as a part of |
|
|
|
// command's call |
|
|
|
/// command's call |
|
|
|
CET_UnusedCommandParameters, |
|
|
|
CET_UnusedCommandParameters, |
|
|
|
// In one short option specification (e.g. '-lah') several options require parameters: |
|
|
|
/// In one short option specification (e.g. '-lah') several options require |
|
|
|
// this introduces ambiguity and is not allowed |
|
|
|
/// parameters: this introduces ambiguity and is not allowed |
|
|
|
CET_MultipleOptionsWithParams, |
|
|
|
CET_MultipleOptionsWithParams, |
|
|
|
// (For targeted commands only) |
|
|
|
/// Targets are specified incorrectly (for targeted commands only) |
|
|
|
// Targets are specified incorrectly (or none actually specified) |
|
|
|
|
|
|
|
CET_IncorrectTargetList, |
|
|
|
CET_IncorrectTargetList, |
|
|
|
|
|
|
|
// No targets are specified (for targeted commands only) |
|
|
|
CET_EmptyTargetList |
|
|
|
CET_EmptyTargetList |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
/// Structure that contains all the information about how `Command` was called. |
|
|
|
/// Structure that contains all the information about how `Command` was called. |
|
|
|
struct CallData { |
|
|
|
struct CallData { |
|
|
|
// Targeted players (if applicable) |
|
|
|
/// Targeted players (if applicable) |
|
|
|
var public array<EPlayer> targetPlayers; |
|
|
|
var public array<EPlayer> targetPlayers; |
|
|
|
// Specified sub-command and parameters/options |
|
|
|
/// Specified sub-command and parameters/options |
|
|
|
var public Text subCommandName; |
|
|
|
var public Text subCommandName; |
|
|
|
// Provided parameters and specified options |
|
|
|
/// Provided parameters and specified options |
|
|
|
var public HashTable parameters; |
|
|
|
var public HashTable parameters; |
|
|
|
var public HashTable options; |
|
|
|
var public HashTable options; |
|
|
|
// Errors that occurred during command call processing are described by |
|
|
|
/// Errors that occurred during command call processing are described by |
|
|
|
// error type and optional error textual name of the object |
|
|
|
/// error type. |
|
|
|
// (parameter, option, etc.) that caused it. |
|
|
|
|
|
|
|
var public ErrorType parsingError; |
|
|
|
var public ErrorType parsingError; |
|
|
|
|
|
|
|
/// Optional error textual name of the object (parameter, option, etc.) |
|
|
|
|
|
|
|
/// that caused it. |
|
|
|
var public Text errorCause; |
|
|
|
var public Text errorCause; |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
/// Possible types of parameters. |
|
|
|
/// Possible types of parameters. |
|
|
|
enum ParameterType { |
|
|
|
enum ParameterType { |
|
|
|
// Parses into `BoolBox` |
|
|
|
/// Parses into `BoolBox` |
|
|
|
CPT_Boolean, |
|
|
|
CPT_Boolean, |
|
|
|
// Parses into `IntBox` |
|
|
|
/// Parses into `IntBox` |
|
|
|
CPT_Integer, |
|
|
|
CPT_Integer, |
|
|
|
// Parses into `FloatBox` |
|
|
|
/// Parses into `FloatBox` |
|
|
|
CPT_Number, |
|
|
|
CPT_Number, |
|
|
|
// Parses into `Text` |
|
|
|
/// Parses into `Text` |
|
|
|
CPT_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, |
|
|
|
CPT_Remainder, |
|
|
|
// Parses into `HashTable` |
|
|
|
/// Parses into `HashTable` |
|
|
|
CPT_Object, |
|
|
|
CPT_Object, |
|
|
|
// Parses into `ArrayList` |
|
|
|
/// Parses into `ArrayList` |
|
|
|
CPT_Array, |
|
|
|
CPT_Array, |
|
|
|
// Parses into any JSON value |
|
|
|
/// Parses into any JSON value |
|
|
|
CPT_JSON, |
|
|
|
CPT_JSON, |
|
|
|
// Parses into an array of specified players |
|
|
|
/// Parses into an array of specified players |
|
|
|
CPT_Players |
|
|
|
CPT_Players |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
/// Possible forms a boolean variable can be used as. |
|
|
|
/// 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. |
|
|
|
/// Boolean parameter can define it's preferred format, which will be used for |
|
|
|
|
|
|
|
/// help page generation. |
|
|
|
enum PreferredBooleanFormat { |
|
|
|
enum PreferredBooleanFormat { |
|
|
|
PBF_TrueFalse, |
|
|
|
PBF_TrueFalse, |
|
|
|
PBF_EnableDisable, |
|
|
|
PBF_EnableDisable, |
|
|
@ -149,91 +154,117 @@ enum PreferredBooleanFormat { |
|
|
|
|
|
|
|
|
|
|
|
// Defines a singular command parameter |
|
|
|
// Defines a singular command parameter |
|
|
|
struct Parameter { |
|
|
|
struct Parameter { |
|
|
|
// Display name (for the needs of help page displaying) |
|
|
|
/// Display name (for the needs of help page displaying) |
|
|
|
var Text displayName; |
|
|
|
var Text displayName; |
|
|
|
// Type of value this parameter would store |
|
|
|
/// Type of value this parameter would store |
|
|
|
var ParameterType type; |
|
|
|
var ParameterType type; |
|
|
|
// Does it take only a singular value or can it contain several of them, |
|
|
|
/// Does it take only a singular value or can it contain several of them, |
|
|
|
// written in a list |
|
|
|
/// written in a list |
|
|
|
var bool allowsList; |
|
|
|
var bool allowsList; |
|
|
|
// Variable name that will be used as a key to store parameter's value |
|
|
|
/// Variable name that will be used as a key to store parameter's value |
|
|
|
var Text variableName; |
|
|
|
var Text variableName; |
|
|
|
// (For `CPT_Boolean` type variables only) - preferred boolean format, |
|
|
|
/// (For `CPT_Boolean` type variables only) - preferred boolean format, |
|
|
|
// used in help pages |
|
|
|
/// used in help pages |
|
|
|
var PreferredBooleanFormat booleanFormat; |
|
|
|
var PreferredBooleanFormat booleanFormat; |
|
|
|
// `CPT_Text` can be attempted to be auto-resolved as an alias from some source during parsing. |
|
|
|
/// `CPT_Text` can be attempted to be auto-resolved as an alias from some |
|
|
|
// For command to attempt that, this field must be not-`none` and contain the name of |
|
|
|
/// source during parsing. |
|
|
|
// the alias source (either "weapon", "color", "feature", "entity" or some kind of custom alias |
|
|
|
/// For command to attempt that, this field must be not-`none` and contain |
|
|
|
// source name). |
|
|
|
/// 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. |
|
|
|
/// |
|
|
|
|
|
|
|
/// Only relevant when given value is prefixed with "$" character. |
|
|
|
var Text aliasSourceName; |
|
|
|
var Text aliasSourceName; |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
// Defines a sub-command of a this command (specified as "<command> <sub_command>"). |
|
|
|
/// Defines a sub-command of a this command |
|
|
|
// |
|
|
|
/// (specified as "<command> <sub_command>"). |
|
|
|
// 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. |
|
|
|
/// 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 { |
|
|
|
struct SubCommand { |
|
|
|
// Cannot be `none` |
|
|
|
/// Name of the sub command. Cannot be `none`. |
|
|
|
var Text name; |
|
|
|
var Text name; |
|
|
|
// Can be `none` |
|
|
|
/// Human-readable description of the subcommand. Can be `none`. |
|
|
|
var Text description; |
|
|
|
var Text description; |
|
|
|
|
|
|
|
/// List of required parameters of this [`Command`]. |
|
|
|
var array<Parameter> required; |
|
|
|
var array<Parameter> required; |
|
|
|
|
|
|
|
/// List of optional parameters of this [`Command`]. |
|
|
|
var array<Parameter> optional; |
|
|
|
var array<Parameter> optional; |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
// Defines command's option (options are specified by "--long" or "-l"). |
|
|
|
/// Defines command's option (options are specified by "--long" or "-l"). |
|
|
|
// Options are independent from sub-commands. |
|
|
|
/// Options are independent from sub-commands. |
|
|
|
struct Option { |
|
|
|
struct Option { |
|
|
|
|
|
|
|
/// [`Option`]'s short name, i.e. a single letter "f" that can be specified |
|
|
|
|
|
|
|
/// in, e.g. "-laf" type option listings |
|
|
|
var BaseText.Character shortName; |
|
|
|
var BaseText.Character shortName; |
|
|
|
|
|
|
|
/// [`Option`]'s full name, e.g. "--force". |
|
|
|
var Text longName; |
|
|
|
var Text longName; |
|
|
|
|
|
|
|
/// Human-readable description of the option. Can be `none`. |
|
|
|
var Text description; |
|
|
|
var Text description; |
|
|
|
// Option can also have their own parameters |
|
|
|
/// List of required parameters of this [`Command::Option`]. |
|
|
|
var array<Parameter> required; |
|
|
|
var array<Parameter> required; |
|
|
|
|
|
|
|
/// List of required parameters of this [`Command::Option`]. |
|
|
|
var array<Parameter> optional; |
|
|
|
var array<Parameter> optional; |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
// Structure that defines what sub-commands and options command has |
|
|
|
/// Structure that defines what sub-commands and options command has |
|
|
|
// (and what parameters they take) |
|
|
|
/// (and what parameters they take) |
|
|
|
struct Data { |
|
|
|
struct Data { |
|
|
|
// Default command name that will be used unless Acedia is configured to |
|
|
|
/// Command group this command belongs to |
|
|
|
// do otherwise |
|
|
|
|
|
|
|
var protected Text name; |
|
|
|
|
|
|
|
// Command group this command belongs to |
|
|
|
|
|
|
|
var protected Text group; |
|
|
|
var protected Text group; |
|
|
|
// Short summary of what command does (recommended to |
|
|
|
/// Short summary of what command does (recommended to |
|
|
|
// keep it to 80 characters) |
|
|
|
/// keep it to 80 characters) |
|
|
|
var protected Text summary; |
|
|
|
var protected Text summary; |
|
|
|
|
|
|
|
/// Available subcommands. |
|
|
|
var protected array<SubCommand> subCommands; |
|
|
|
var protected array<SubCommand> subCommands; |
|
|
|
|
|
|
|
/// Available options, common to all subcommands. |
|
|
|
var protected array<Option> options; |
|
|
|
var protected array<Option> options; |
|
|
|
|
|
|
|
/// `true` iff related [`Command`] targets players. |
|
|
|
var protected bool requiresTarget; |
|
|
|
var protected bool requiresTarget; |
|
|
|
}; |
|
|
|
}; |
|
|
|
var protected Data commandData; |
|
|
|
var protected Data commandData; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Setting variable that defines a name that will be chosen for command by |
|
|
|
|
|
|
|
/// default. |
|
|
|
|
|
|
|
var protected const string preferredName; |
|
|
|
|
|
|
|
/// Name that was used to register this command. |
|
|
|
|
|
|
|
var protected Text usedName; |
|
|
|
|
|
|
|
/// Settings variable that defines a class to be used for this [`Command`]'s |
|
|
|
|
|
|
|
/// permissions config |
|
|
|
|
|
|
|
var protected const class<CommandPermissions> permissionsConfigClass; |
|
|
|
|
|
|
|
|
|
|
|
// We do not really ever need to create more than one instance of each class |
|
|
|
// We do not really ever need to create more than one instance of each class |
|
|
|
// of `Command`, so we will simply store and reuse one created instance. |
|
|
|
// of `Command`, so we will simply store and reuse one created instance. |
|
|
|
var private Command mainInstance; |
|
|
|
var private Command mainInstance; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// When command is being executed we create several instances of |
|
|
|
// When command is being executed we create several instances of `ConsoleWriter` that can be used |
|
|
|
/// `ConsoleWriter` that can be used for command output. |
|
|
|
// for command output. They will also be automatically deallocated once command is executed. |
|
|
|
/// They will also be automatically deallocated once command is executed. |
|
|
|
// |
|
|
|
/// |
|
|
|
// DO NOT modify them or deallocate any of them manually. |
|
|
|
/// DO NOT modify them or deallocate any of them manually. |
|
|
|
// |
|
|
|
/// |
|
|
|
// This should make output more convenient and standardized. |
|
|
|
/// This should make output more convenient and standardized. |
|
|
|
// |
|
|
|
/// |
|
|
|
// 1. `publicConsole` - sends messages to all present players; |
|
|
|
/// 1. `publicConsole` - sends messages to all present players; |
|
|
|
// 2. `callerConsole` - sends messages to the player that called the command; |
|
|
|
/// 2. `callerConsole` - sends messages to the player that called the command; |
|
|
|
// 3. `targetConsole` - sends messages to the player that is currently being targeted |
|
|
|
/// 3. `targetConsole` - sends messages to the player that is currently being |
|
|
|
// (different each call of `ExecutedFor()` and `none` during `Executed()` call); |
|
|
|
/// targeted (different each call of `ExecutedFor()` and `none` during |
|
|
|
// 4. `othersConsole` - sends messaged to every player that is neither "caller" or "target". |
|
|
|
/// `Executed()` call); |
|
|
|
|
|
|
|
/// 4. `othersConsole` - sends messaged to every player that is neither |
|
|
|
|
|
|
|
/// "caller" or "target". |
|
|
|
var protected ConsoleWriter publicConsole, othersConsole; |
|
|
|
var protected ConsoleWriter publicConsole, othersConsole; |
|
|
|
var protected ConsoleWriter callerConsole, targetConsole; |
|
|
|
var protected ConsoleWriter callerConsole, targetConsole; |
|
|
|
|
|
|
|
|
|
|
|
protected function Constructor() { |
|
|
|
protected function Constructor() { |
|
|
|
local CommandDataBuilder dataBuilder; |
|
|
|
local CommandDataBuilder dataBuilder; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (permissionsConfigClass != none) { |
|
|
|
|
|
|
|
permissionsConfigClass.static.Initialize(); |
|
|
|
|
|
|
|
} |
|
|
|
dataBuilder = CommandDataBuilder(_.memory.Allocate(class'CommandDataBuilder')); |
|
|
|
dataBuilder = CommandDataBuilder(_.memory.Allocate(class'CommandDataBuilder')); |
|
|
|
|
|
|
|
// Let user fill-in the rest |
|
|
|
BuildData(dataBuilder); |
|
|
|
BuildData(dataBuilder); |
|
|
|
commandData = dataBuilder.BorrowData(); |
|
|
|
commandData = dataBuilder.BorrowData(); |
|
|
|
dataBuilder.FreeSelf(); |
|
|
|
dataBuilder.FreeSelf(); |
|
|
@ -246,8 +277,10 @@ protected function Finalizer() { |
|
|
|
local array<Option> options; |
|
|
|
local array<Option> options; |
|
|
|
|
|
|
|
|
|
|
|
DeallocateConsoles(); |
|
|
|
DeallocateConsoles(); |
|
|
|
_.memory.Free(commandData.name); |
|
|
|
_.memory.Free(usedName); |
|
|
|
_.memory.Free(commandData.summary); |
|
|
|
_.memory.Free(commandData.summary); |
|
|
|
|
|
|
|
usedName = none; |
|
|
|
|
|
|
|
commandData.summary = none; |
|
|
|
subCommands = commandData.subCommands; |
|
|
|
subCommands = commandData.subCommands; |
|
|
|
for (i = 0; i < options.length; i += 1) { |
|
|
|
for (i = 0; i < options.length; i += 1) { |
|
|
|
_.memory.Free(subCommands[i].name); |
|
|
|
_.memory.Free(subCommands[i].name); |
|
|
@ -270,43 +303,55 @@ protected function Finalizer() { |
|
|
|
commandData.options.length = 0; |
|
|
|
commandData.options.length = 0; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private final function CleanParameters(array<Parameter> parameters) { |
|
|
|
/// Initializes command, providing it with a specific name. |
|
|
|
local int i; |
|
|
|
/// |
|
|
|
|
|
|
|
/// Argument cannot be `none`, otherwise initialization fails. |
|
|
|
|
|
|
|
/// [`Command`] can only be successfully initialized once. |
|
|
|
|
|
|
|
public final function bool Initialize(BaseText commandName) { |
|
|
|
|
|
|
|
if (commandName == none) return false; |
|
|
|
|
|
|
|
if (usedName != none) return false; |
|
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < parameters.length; i += 1) { |
|
|
|
usedName = commandName.LowerCopy(); |
|
|
|
_.memory.Free(parameters[i].displayName); |
|
|
|
return true; |
|
|
|
_.memory.Free(parameters[i].variableName); |
|
|
|
|
|
|
|
_.memory.Free(parameters[i].aliasSourceName); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/// Overload this method to use `builder` to define parameters and options for your command. |
|
|
|
/// Overload this method to use `builder` to define parameters and options for |
|
|
|
|
|
|
|
/// your command. |
|
|
|
protected function BuildData(CommandDataBuilder builder){} |
|
|
|
protected function BuildData(CommandDataBuilder builder){} |
|
|
|
|
|
|
|
|
|
|
|
/// Overload this method to perform required actions when your command is called. |
|
|
|
/// Overload this method to perform required actions when your command is |
|
|
|
/// |
|
|
|
/// called. |
|
|
|
/// [`arguments`] is a `struct` filled with parameters that your command has been called with. |
|
|
|
|
|
|
|
/// Guaranteed to not be in error state. |
|
|
|
|
|
|
|
/// |
|
|
|
/// |
|
|
|
|
|
|
|
/// [`arguments`] is a `struct` filled with parameters that your command has |
|
|
|
|
|
|
|
/// been called with. Guaranteed to not be in error state. |
|
|
|
/// [`instigator`] is a player that instigated this execution. |
|
|
|
/// [`instigator`] is a player that instigated this execution. |
|
|
|
protected function Executed(CallData arguments, EPlayer instigator){} |
|
|
|
/// [`permissions`] is a config with permissions for this command call. |
|
|
|
|
|
|
|
protected function Executed( |
|
|
|
/// Overload this method to perform required actions when your command is called with a given player |
|
|
|
CallData arguments, |
|
|
|
/// as a target. |
|
|
|
EPlayer instigator, |
|
|
|
|
|
|
|
CommandPermissions permissions) {} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Overload this method to perform required actions when your command is called |
|
|
|
|
|
|
|
/// with a given player as a target. |
|
|
|
/// |
|
|
|
/// |
|
|
|
/// If several players have been specified - this method will be called once for each. |
|
|
|
/// If several players have been specified - this method will be called once |
|
|
|
|
|
|
|
/// for each. |
|
|
|
/// |
|
|
|
/// |
|
|
|
/// If your command does not require a target - this method will not be called. |
|
|
|
/// If your command does not require a target - this method will not be called. |
|
|
|
/// |
|
|
|
/// |
|
|
|
/// [`target`] is a player that this command must perform an action on. |
|
|
|
/// [`target`] is a player that this command must perform an action on. |
|
|
|
/// [`arguments`] is a `struct` filled with parameters that your command has been called with. |
|
|
|
/// [`arguments`] is a `struct` filled with parameters that your command has |
|
|
|
/// Guaranteed to not be in error state. |
|
|
|
/// been called with. Guaranteed to not be in error state. |
|
|
|
/// |
|
|
|
|
|
|
|
/// [`instigator`] is a player that instigated this execution. |
|
|
|
/// [`instigator`] is a player that instigated this execution. |
|
|
|
protected function ExecutedFor(EPlayer target, CallData arguments, EPlayer instigator) {} |
|
|
|
/// [`permissions`] is a config with permissions for this command call. |
|
|
|
|
|
|
|
protected function ExecutedFor( |
|
|
|
/// Returns an instance of command (of particular class) that is stored "as a singleton" in |
|
|
|
EPlayer target, |
|
|
|
/// command's class itself. Do not deallocate it. |
|
|
|
CallData arguments, |
|
|
|
|
|
|
|
EPlayer instigator, |
|
|
|
|
|
|
|
CommandPermissions permissions) {} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Returns an instance of command (of particular class) that is stored |
|
|
|
|
|
|
|
/// "as a singleton" in command's class itself. Do not deallocate it. |
|
|
|
public final static function Command GetInstance() { |
|
|
|
public final static function Command GetInstance() { |
|
|
|
if (default.mainInstance == none) { |
|
|
|
if (default.mainInstance == none) { |
|
|
|
default.mainInstance = Command(__().memory.Allocate(default.class)); |
|
|
|
default.mainInstance = Command(__().memory.Allocate(default.class)); |
|
|
@ -314,18 +359,19 @@ public final static function Command GetInstance() { |
|
|
|
return default.mainInstance; |
|
|
|
return default.mainInstance; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/// Forces command to process (parse) player's input, producing a structure with parsed data in |
|
|
|
/// Forces command to process (parse) player's input, producing a structure with |
|
|
|
/// Acedia's format instead. |
|
|
|
/// parsed data in Acedia's format instead. |
|
|
|
/// |
|
|
|
/// |
|
|
|
/// Use `Execute()` for actually performing command's actions. |
|
|
|
/// Use `Execute()` for actually performing command's actions. |
|
|
|
/// |
|
|
|
/// |
|
|
|
/// [`subCommandName`] can be optionally specified to use as sub-command. |
|
|
|
/// [`subCommandName`] can be optionally specified to use as sub-command. |
|
|
|
/// If this argument's value is `none` - sub-command name will be parsed from the `parser`'s data. |
|
|
|
/// If this argument's value is `none` - sub-command name will be parsed from |
|
|
|
|
|
|
|
/// the `parser`'s data. |
|
|
|
/// |
|
|
|
/// |
|
|
|
/// Returns `CallData` structure that contains all the information about parameters specified in |
|
|
|
/// Returns `CallData` structure that contains all the information about |
|
|
|
/// `parser`'s contents. |
|
|
|
/// parameters specified in `parser`'s contents. |
|
|
|
/// Returned structure contains objects that must be deallocated, which can easily be done by |
|
|
|
/// Returned structure contains objects that must be deallocated, which can |
|
|
|
/// the auxiliary `DeallocateCallData()` method. |
|
|
|
/// easily be done by the auxiliary `DeallocateCallData()` method. |
|
|
|
public final function CallData ParseInputWith( |
|
|
|
public final function CallData ParseInputWith( |
|
|
|
Parser parser, |
|
|
|
Parser parser, |
|
|
|
EPlayer callerPlayer, |
|
|
|
EPlayer callerPlayer, |
|
|
@ -363,16 +409,27 @@ public final function CallData ParseInputWith( |
|
|
|
return callData; |
|
|
|
return callData; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/// Executes caller `Command` with data provided by `callData` if it is in a correct state and |
|
|
|
/// Executes caller `Command` with data provided by `callData` if it is in |
|
|
|
/// reports error to `callerPlayer` if `callData` is invalid. |
|
|
|
/// a correct state and reports error to `callerPlayer` if `callData` is |
|
|
|
|
|
|
|
/// invalid. |
|
|
|
/// |
|
|
|
/// |
|
|
|
/// Returns `true` if command was successfully executed and `false` otherwise. |
|
|
|
/// Returns `true` if command was successfully executed and `false` otherwise. |
|
|
|
/// Execution is considered successful if `Execute()` call was made, regardless of whether `Command` |
|
|
|
/// Execution is considered successful if `Execute()` call was made, regardless |
|
|
|
/// can actually perform required action. |
|
|
|
/// of whether `Command` can actually perform required action. |
|
|
|
/// For example, giving a weapon to a player can fail because he does not have enough space in his |
|
|
|
/// For example, giving a weapon to a player can fail because he does not have |
|
|
|
/// inventory, but it will still be considered a successful execution as far as return value is |
|
|
|
/// enough space in his inventory, but it will still be considered a successful |
|
|
|
/// concerned. |
|
|
|
/// execution as far as return value is concerned. |
|
|
|
public final function bool Execute(CallData callData, EPlayer callerPlayer) { |
|
|
|
/// |
|
|
|
|
|
|
|
/// [`permissions`] argument is supposed to specify permissions with which this |
|
|
|
|
|
|
|
/// command runs. |
|
|
|
|
|
|
|
/// If [`permissionsConfigClass`] is `none`, it must always be `none`. |
|
|
|
|
|
|
|
/// If [`permissionsConfigClass`] is not `none`, then [`permissions`] argument |
|
|
|
|
|
|
|
/// being `none` should mean running with minimal priviledges. |
|
|
|
|
|
|
|
public final function bool Execute( |
|
|
|
|
|
|
|
CallData callData, |
|
|
|
|
|
|
|
EPlayer callerPlayer, |
|
|
|
|
|
|
|
CommandPermissions permissions |
|
|
|
|
|
|
|
) { |
|
|
|
local int i; |
|
|
|
local int i; |
|
|
|
local array<EPlayer> targetPlayers; |
|
|
|
local array<EPlayer> targetPlayers; |
|
|
|
|
|
|
|
|
|
|
@ -389,11 +446,11 @@ public final function bool Execute(CallData callData, EPlayer callerPlayer) { |
|
|
|
callerConsole = _.console.For(callerPlayer); |
|
|
|
callerConsole = _.console.For(callerPlayer); |
|
|
|
callerConsole |
|
|
|
callerConsole |
|
|
|
.Write(P("Executing command `")) |
|
|
|
.Write(P("Executing command `")) |
|
|
|
.Write(commandData.name) |
|
|
|
.Write(usedName) |
|
|
|
.Say(P("`")); |
|
|
|
.Say(P("`")); |
|
|
|
// `othersConsole` should also exist in time for `Executed()` call |
|
|
|
// `othersConsole` should also exist in time for `Executed()` call |
|
|
|
othersConsole = _.console.ForAll().ButPlayer(callerPlayer); |
|
|
|
othersConsole = _.console.ForAll().ButPlayer(callerPlayer); |
|
|
|
Executed(callData, callerPlayer); |
|
|
|
Executed(callData, callerPlayer, permissions); |
|
|
|
_.memory.Free(othersConsole); |
|
|
|
_.memory.Free(othersConsole); |
|
|
|
if (commandData.requiresTarget) { |
|
|
|
if (commandData.requiresTarget) { |
|
|
|
for (i = 0; i < targetPlayers.length; i += 1) { |
|
|
|
for (i = 0; i < targetPlayers.length; i += 1) { |
|
|
@ -402,7 +459,7 @@ public final function bool Execute(CallData callData, EPlayer callerPlayer) { |
|
|
|
.ForAll() |
|
|
|
.ForAll() |
|
|
|
.ButPlayer(callerPlayer) |
|
|
|
.ButPlayer(callerPlayer) |
|
|
|
.ButPlayer(targetPlayers[i]); |
|
|
|
.ButPlayer(targetPlayers[i]); |
|
|
|
ExecutedFor(targetPlayers[i], callData, callerPlayer); |
|
|
|
ExecutedFor(targetPlayers[i], callData, callerPlayer, permissions); |
|
|
|
_.memory.Free(othersConsole); |
|
|
|
_.memory.Free(othersConsole); |
|
|
|
_.memory.Free(targetConsole); |
|
|
|
_.memory.Free(targetConsole); |
|
|
|
} |
|
|
|
} |
|
|
@ -413,6 +470,209 @@ public final function bool Execute(CallData callData, EPlayer callerPlayer) { |
|
|
|
return true; |
|
|
|
return true; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Auxiliary method that cleans up all data and deallocates all objects inside provided structure. |
|
|
|
|
|
|
|
public final static function DeallocateCallData(/* take */ CallData callData) { |
|
|
|
|
|
|
|
__().memory.Free(callData.subCommandName); |
|
|
|
|
|
|
|
__().memory.Free(callData.parameters); |
|
|
|
|
|
|
|
__().memory.Free(callData.options); |
|
|
|
|
|
|
|
__().memory.Free(callData.errorCause); |
|
|
|
|
|
|
|
__().memory.FreeMany(callData.targetPlayers); |
|
|
|
|
|
|
|
if (callData.targetPlayers.length > 0) { |
|
|
|
|
|
|
|
callData.targetPlayers.length = 0; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private final function CleanParameters(array<Parameter> parameters) { |
|
|
|
|
|
|
|
local int i; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < parameters.length; i += 1) { |
|
|
|
|
|
|
|
_.memory.Free(parameters[i].displayName); |
|
|
|
|
|
|
|
_.memory.Free(parameters[i].variableName); |
|
|
|
|
|
|
|
_.memory.Free(parameters[i].aliasSourceName); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Returns name (in lower case) of the caller command class. |
|
|
|
|
|
|
|
public final static function Text GetPreferredName() { |
|
|
|
|
|
|
|
return __().text.FromString(Locs(default.preferredName)); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Returns name (in lower case) of the caller command class. |
|
|
|
|
|
|
|
public final static function string GetPreferredName_S() { |
|
|
|
|
|
|
|
return Locs(default.preferredName); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Returns name (in lower case) of the caller command class. |
|
|
|
|
|
|
|
public final function Text GetName() { |
|
|
|
|
|
|
|
if (usedName == none) { |
|
|
|
|
|
|
|
return P("").Copy(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return usedName.LowerCopy(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Returns name (in lower case) of the caller command class. |
|
|
|
|
|
|
|
public final function string GetName_S() { |
|
|
|
|
|
|
|
if (usedName == none) { |
|
|
|
|
|
|
|
return ""; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return _.text.IntoString(/*take*/ usedName.LowerCopy()); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Returns group name (in lower case) of the caller command class. |
|
|
|
|
|
|
|
public final function Text GetGroupName() { |
|
|
|
|
|
|
|
if (commandData.group == none) { |
|
|
|
|
|
|
|
return P("").Copy(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return commandData.group.LowerCopy(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Returns group name (in lower case) of the caller command class. |
|
|
|
|
|
|
|
public final function string GetGroupName_S() { |
|
|
|
|
|
|
|
if (commandData.group == none) { |
|
|
|
|
|
|
|
return ""; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return _.text.IntoString(/*take*/ commandData.group.LowerCopy()); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Loads permissions config with a given name for the caller [`Command`] class. |
|
|
|
|
|
|
|
/// |
|
|
|
|
|
|
|
/// Permission configs describe allowed usage of the [`Command`]. |
|
|
|
|
|
|
|
/// Basic settings are contained inside [`CommandPermissions`], but commands |
|
|
|
|
|
|
|
/// should derive their own child classes for storing their settings. |
|
|
|
|
|
|
|
/// |
|
|
|
|
|
|
|
/// Returns `none` if caller [`Command`] class didn't specify custom permission |
|
|
|
|
|
|
|
/// settings class or provided name is invalid (according to |
|
|
|
|
|
|
|
/// [`BaseText::IsValidName()`]). |
|
|
|
|
|
|
|
/// Otherwise guaranteed to return a config reference. |
|
|
|
|
|
|
|
public final static function CommandPermissions LoadConfig(BaseText configName) { |
|
|
|
|
|
|
|
if (configName == none) return none; |
|
|
|
|
|
|
|
if (default.permissionsConfigClass == none) return none; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// This creates default config if it is missing |
|
|
|
|
|
|
|
default.permissionsConfigClass.static.NewConfig(configName); |
|
|
|
|
|
|
|
return CommandPermissions(default.permissionsConfigClass.static |
|
|
|
|
|
|
|
.GetConfigInstance(configName)); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Loads permissions config with a given name for the caller [`Command`] class. |
|
|
|
|
|
|
|
/// |
|
|
|
|
|
|
|
/// Permission configs describe allowed usage of the [`Command`]. |
|
|
|
|
|
|
|
/// Basic settings are contained inside [`CommandPermissions`], but commands |
|
|
|
|
|
|
|
/// should derive their own child classes for storing their settings. |
|
|
|
|
|
|
|
/// |
|
|
|
|
|
|
|
/// Returns `none` if caller [`Command`] class didn't specify custom permission |
|
|
|
|
|
|
|
/// settings class or provided name is invalid (according to |
|
|
|
|
|
|
|
/// [`BaseText::IsValidName()`]). |
|
|
|
|
|
|
|
/// Otherwise guaranteed to return a config reference. |
|
|
|
|
|
|
|
public final static function CommandPermissions LoadConfig_S(string configName) { |
|
|
|
|
|
|
|
local MutableText wrapper; |
|
|
|
|
|
|
|
local CommandPermissions result; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
wrapper = __().text.FromStringM(configName); |
|
|
|
|
|
|
|
result = LoadConfig(wrapper); |
|
|
|
|
|
|
|
__().memory.Free(wrapper); |
|
|
|
|
|
|
|
return result; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Returns subcommands of caller [`Command`] according to the provided |
|
|
|
|
|
|
|
/// permissions. |
|
|
|
|
|
|
|
/// |
|
|
|
|
|
|
|
/// If provided `none` as permissions, returns all available sub commands. |
|
|
|
|
|
|
|
public final function array<Text> GetSubCommands(optional CommandPermissions permissions) { |
|
|
|
|
|
|
|
local int i, j; |
|
|
|
|
|
|
|
local bool addSubCommand; |
|
|
|
|
|
|
|
local array<string> forbiddenCommands; |
|
|
|
|
|
|
|
local array<Text> result; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
forbiddenCommands = permissions.forbiddenSubCommands; |
|
|
|
|
|
|
|
if (permissions != none) { |
|
|
|
|
|
|
|
forbiddenCommands = permissions.forbiddenSubCommands; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
for (i = 0; i < commandData.subCommands.length; i += 1) { |
|
|
|
|
|
|
|
addSubCommand = true; |
|
|
|
|
|
|
|
for (j = 0; j < forbiddenCommands.length; j += 1) { |
|
|
|
|
|
|
|
if (commandData.subCommands[i].name.ToString() ~= forbiddenCommands[j]) { |
|
|
|
|
|
|
|
addSubCommand = false; |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if (addSubCommand) { |
|
|
|
|
|
|
|
result[result.length] = commandData.subCommands[i].name.LowerCopy(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return result; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Returns sub commands of caller [`Command`] according to the provided |
|
|
|
|
|
|
|
/// permissions. |
|
|
|
|
|
|
|
/// |
|
|
|
|
|
|
|
/// If provided `none` as permissions, returns all available sub commands. |
|
|
|
|
|
|
|
public final function array<string> GetSubCommands_S(optional CommandPermissions permissions) { |
|
|
|
|
|
|
|
return _.text.IntoStrings(GetSubCommands(permissions)); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Checks whether a given sub command (case insensitive) is allowed to be |
|
|
|
|
|
|
|
/// executed with given permissions. |
|
|
|
|
|
|
|
/// |
|
|
|
|
|
|
|
/// If `none` is passed as either argument, returns `true`. |
|
|
|
|
|
|
|
/// |
|
|
|
|
|
|
|
/// Doesn't check for the existence of sub command, only that permissions do not |
|
|
|
|
|
|
|
/// explicitly forbid it. |
|
|
|
|
|
|
|
/// In case non-existing subcommand is passed as an argument, the result |
|
|
|
|
|
|
|
/// should be considered undefined. |
|
|
|
|
|
|
|
public final function bool IsSubCommandAllowed( |
|
|
|
|
|
|
|
BaseText subCommand, |
|
|
|
|
|
|
|
CommandPermissions permissions |
|
|
|
|
|
|
|
) { |
|
|
|
|
|
|
|
if (subCommand == none) return true; |
|
|
|
|
|
|
|
if (permissions == none) return true; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return IsSubCommandAllowed_S(subCommand.ToString(), permissions); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Checks whether a given sub command (case insensitive) is allowed to be |
|
|
|
|
|
|
|
/// executed with given permissions. |
|
|
|
|
|
|
|
/// |
|
|
|
|
|
|
|
/// If `none` is passed for permissions, always returns `true`. |
|
|
|
|
|
|
|
/// |
|
|
|
|
|
|
|
/// Doesn't check for the existence of sub command, only that permissions do not |
|
|
|
|
|
|
|
/// explicitly forbid it. |
|
|
|
|
|
|
|
/// In case non-existing sub command is passed as an argument, the result |
|
|
|
|
|
|
|
/// should be considered undefined. |
|
|
|
|
|
|
|
public final function bool IsSubCommandAllowed_S( |
|
|
|
|
|
|
|
string subCommand, |
|
|
|
|
|
|
|
CommandPermissions permissions |
|
|
|
|
|
|
|
) { |
|
|
|
|
|
|
|
local int i; |
|
|
|
|
|
|
|
local array<string> forbiddenCommands; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (permissions == none) { |
|
|
|
|
|
|
|
return true; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
forbiddenCommands = permissions.forbiddenSubCommands; |
|
|
|
|
|
|
|
for (i = 0; i < forbiddenCommands.length; i += 1) { |
|
|
|
|
|
|
|
if (subCommand ~= forbiddenCommands[i]) { |
|
|
|
|
|
|
|
return false; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return true; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Returns `Command.Data` struct that describes caller `Command`. |
|
|
|
|
|
|
|
/// |
|
|
|
|
|
|
|
/// Returned struct contains `Text` references that are used internally by |
|
|
|
|
|
|
|
/// the `Command` and not their copies. |
|
|
|
|
|
|
|
/// |
|
|
|
|
|
|
|
/// Generally this is undesired approach and leaves `Command` more vulnerable to |
|
|
|
|
|
|
|
/// modification, but copying all the data inside would not only introduce |
|
|
|
|
|
|
|
/// a largely pointless computational overhead, but also would require some |
|
|
|
|
|
|
|
/// cumbersome logic. |
|
|
|
|
|
|
|
/// This might change in the future, so deallocating any objects in the returned |
|
|
|
|
|
|
|
/// `struct` would lead to undefined behavior. |
|
|
|
|
|
|
|
public final function Data BorrowData() { |
|
|
|
|
|
|
|
return commandData; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private final function DeallocateConsoles() { |
|
|
|
private final function DeallocateConsoles() { |
|
|
|
if (publicConsole != none && publicConsole.IsAllocated()) { |
|
|
|
if (publicConsole != none && publicConsole.IsAllocated()) { |
|
|
|
_.memory.Free(publicConsole); |
|
|
|
_.memory.Free(publicConsole); |
|
|
@ -432,20 +692,8 @@ private final function DeallocateConsoles() { |
|
|
|
othersConsole = none; |
|
|
|
othersConsole = none; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/// Auxiliary method that cleans up all data and deallocates all objects inside provided structure. |
|
|
|
/// Reports given error to the `callerPlayer`, appropriately picking |
|
|
|
public final static function DeallocateCallData(/* take */ CallData callData) { |
|
|
|
/// message color |
|
|
|
__().memory.Free(callData.subCommandName); |
|
|
|
|
|
|
|
__().memory.Free(callData.parameters); |
|
|
|
|
|
|
|
__().memory.Free(callData.options); |
|
|
|
|
|
|
|
__().memory.Free(callData.errorCause); |
|
|
|
|
|
|
|
__().memory.FreeMany(callData.targetPlayers); |
|
|
|
|
|
|
|
if (callData.targetPlayers.length > 0) { |
|
|
|
|
|
|
|
callData.targetPlayers.length = 0; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Reports given error to the `callerPlayer`, appropriately picking |
|
|
|
|
|
|
|
// message color |
|
|
|
|
|
|
|
private final function ReportError(CallData callData, EPlayer callerPlayer) { |
|
|
|
private final function ReportError(CallData callData, EPlayer callerPlayer) { |
|
|
|
local Text errorMessage; |
|
|
|
local Text errorMessage; |
|
|
|
local ConsoleWriter console; |
|
|
|
local ConsoleWriter console; |
|
|
@ -551,35 +799,7 @@ private final function array<EPlayer> ParseTargets(Parser parser, EPlayer caller |
|
|
|
return targetPlayers; |
|
|
|
return targetPlayers; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/// Returns name (in lower case) of the caller command class. |
|
|
|
|
|
|
|
public final function Text GetName() { |
|
|
|
|
|
|
|
if (commandData.name == none) { |
|
|
|
|
|
|
|
return P("").Copy(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return commandData.name.LowerCopy(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Returns group name (in lower case) of the caller command class. |
|
|
|
|
|
|
|
public final function Text GetGroupName() { |
|
|
|
|
|
|
|
if (commandData.group == none) { |
|
|
|
|
|
|
|
return P("").Copy(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return commandData.group.LowerCopy(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Returns `Command.Data` struct that describes caller `Command`. |
|
|
|
|
|
|
|
/// |
|
|
|
|
|
|
|
/// Returned struct contains `Text` references that are used internally by the `Command` and |
|
|
|
|
|
|
|
/// not their copies. |
|
|
|
|
|
|
|
/// |
|
|
|
|
|
|
|
/// Generally this is undesired approach and leaves `Command` more vulnerable to modification, |
|
|
|
|
|
|
|
/// but copying all the data inside would not only introduce a largely pointless computational |
|
|
|
|
|
|
|
/// overhead, but also would require some cumbersome logic. |
|
|
|
|
|
|
|
/// This might change in the future, so deallocating any objects in the returned `struct` would lead |
|
|
|
|
|
|
|
/// to undefined behavior. |
|
|
|
|
|
|
|
public final function Data BorrowData() { |
|
|
|
|
|
|
|
return commandData; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
defaultproperties { |
|
|
|
defaultproperties { |
|
|
|
|
|
|
|
preferredName = "" |
|
|
|
|
|
|
|
permissionsConfigClass = none |
|
|
|
} |
|
|
|
} |