Browse Source

Change how `Command` data is filled and displayed

pull/8/head
Anton Tarasenko 4 years ago
parent
commit
2627b56b95
  1. 2
      sources/Commands/BuiltInCommands/ACommandDosh.uc
  2. 261
      sources/Commands/BuiltInCommands/ACommandHelp.uc
  3. 2
      sources/Commands/BuiltInCommands/ACommandNick.uc
  4. 314
      sources/Commands/Command.uc
  5. 55
      sources/Commands/CommandDataBuilder.uc
  6. 22
      sources/Commands/Commands.uc

2
sources/Commands/BuiltInCommands/ACommandDosh.uc

@ -22,6 +22,7 @@ class ACommandDosh extends Command;
//'dosh' for giving dosh (subcommand for setting it, options for min/max resulting value, silent)
protected function BuildData(CommandDataBuilder builder)
{
builder.Name(P("dosh")).Summary(P("Changes how much money player has."));
builder.RequireTarget();
builder.ParamInteger(P("amount"))
.Describe(P("Gives (takes if negative) players a specified <amount>"
@ -99,5 +100,4 @@ protected function ExecutedFor(APlayer player, CommandCall result)
defaultproperties
{
commandName = "dosh"
}

261
sources/Commands/BuiltInCommands/ACommandHelp.uc

@ -22,13 +22,22 @@ class ACommandHelp extends Command
var LoggerAPI.Definition testMsg;
var public const int TSPACE, TCOMMAND_NAME_FALLBACK, TPLUS;
var public const int TOPEN_BRACKET, TCLOSE_BRACKET, TCOLUMN_SPACE;
var public const int TKEY, TDOUBLE_KEY, TCOMMA_SPACE, TBOOLEAN, TINDENT;
var public const int TBOOLEAN_TRUE_FALSE, TBOOLEAN_ENABLE_DISABLE;
var public const int TBOOLEAN_ON_OFF, TBOOLEAN_YES_NO;
var public const int TOPTIONS, TCMD_WITH_TARGET, TCMD_WITHOUT_TARGET;
protected function BuildData(CommandDataBuilder builder)
{
builder.Name(P("help"))
.Summary(P("Detailed information about available commands."));
builder.OptionalParams()
.ParamTextList(P("commands"))
.Describe(P("Displays information about all specified commands."));
.Describe(P("Display information about all specified commands."));
builder.Option(P("list"))
.Describe(P("Displays list of all available commands."));
.Describe(P("Display list of all available commands."));
}
protected function Executed(CommandCall callInfo)
@ -37,22 +46,34 @@ protected function Executed(CommandCall callInfo)
local DynamicArray commandsToDisplay;
local APlayer callerPlayer;
callerPlayer = callInfo.GetCallerPlayer();
if (callerPlayer == none) return;
if (callerPlayer == none) {
return;
}
// Command list
// Print command list if "--list" option was specified
if (callInfo.GetOptions().HasKey(P("list"))) {
DisplayCommandList(callerPlayer);
}
// Help pages
parameters = callInfo.GetParameters();
commandsToDisplay = DynamicArray(parameters.GetItem(P("commands")));
DisplayCommandHelpPages(callerPlayer, commandsToDisplay);
// Help pages.
// Only need to print them if:
// 1. Any commands are specified as parameters;
// 2. No commands or "--list" option was specified, then we want to
// print a help page for this command.
if ( !callInfo.GetOptions().HasKey(P("list"))
|| callInfo.GetParameters().HasKey(P("commands")))
{
parameters = callInfo.GetParameters();
commandsToDisplay = DynamicArray(parameters.GetItem(P("commands")));
DisplayCommandHelpPages(callerPlayer, commandsToDisplay);
}
}
private final function DisplayCommandList(APlayer player)
{
local int i;
local ConsoleWriter console;
local Command nextCommand;
local Command.Data nextData;
local array<Text> commandNames;
local Commands commandsFeature;
if (player == none) return;
@ -61,8 +82,17 @@ private final function DisplayCommandList(APlayer player)
console = player.Console();
commandNames = commandsFeature.GetCommandNames();
for (i = 0; i < commandNames.length; i += 1) {
console.WriteLine(commandNames[i]);
for (i = 0; i < commandNames.length; i += 1)
{
nextCommand = commandsFeature.GetCommand(commandNames[i]);
if (nextCommand == none) continue;
nextData = nextCommand.GetData();
console.UseColor(_.color.textEmphasis)
.Write(nextData.name)
.ResetColor()
.Write(T(TCOLUMN_SPACE))
.WriteLine(nextData.summary);
}
_.memory.FreeMany(commandNames);
}
@ -72,7 +102,6 @@ private final function DisplayCommandHelpPages(
DynamicArray commandList)
{
local int i;
local Text nextHelpPage;
local Command nextCommand;
local Commands commandsFeature;
if (player == none) return;
@ -80,25 +109,217 @@ private final function DisplayCommandHelpPages(
if (commandsFeature == none) return;
// If arguments were empty - at least display our own help page
if (commandList.GetLength() == 1 && Text(commandList.GetItem(0)).IsEmpty())
if (commandList == none)
{
nextHelpPage = PrintHelp();
player.Console().WriteLine(nextHelpPage).Flush();
nextHelpPage.FreeSelf();
PrintHelpPage(player.Console(), GetData());
return;
}
// Otherwise - print help for specified commands
for (i = 0; i < commandList.GetLength(); i += 1)
{
nextCommand = commandsFeature.GetCommand(Text(commandList.GetItem(i)));
if (nextCommand == none) continue;
nextHelpPage = nextCommand.PrintHelp();
player.Console().WriteLine(nextHelpPage);
nextHelpPage.FreeSelf();
PrintHelpPage(player.Console(), nextCommand.GetData());
}
}
// Following methods are mostly self-explanatory,
// all assume that passed `cout != none`
private final function PrintHelpPage(ConsoleWriter cout, Command.Data data)
{
local Text commandNameUpperCase;
// Get capitalized command name
commandNameUpperCase = data.name.UpperCopy();
// Print header: name + basic info
cout.UseColor(_.color.textHeader)
.Write(commandNameUpperCase)
.UseColor(_.color.textDefault);
commandNameUpperCase.FreeSelf();
if (data.requiresTarget) {
cout.WriteLine(T(TCMD_WITH_TARGET));
}
else {
cout.WriteLine(T(TCMD_WITHOUT_TARGET));
}
// Print commands and options
PrintCommands(cout, data);
PrintOptions(cout, data);
// Clean up
cout.ResetColor().Flush();
}
private final function PrintCommands(ConsoleWriter cout, Command.Data data)
{
local int i;
local array<SubCommand> subCommands;
subCommands = data.subCommands;
for (i = 0; i < subCommands.length; i += 1) {
PrintSubCommand(cout, subCommands[i], data.name);
}
}
private final function PrintSubCommand(
ConsoleWriter cout,
SubCommand subCommand,
Text commandName)
{
// Command + parameters
// Command name + sub command name
cout.UseColor(_.color.textEmphasis)
.Write(commandName)
.Write(T(TSPACE));
if (subCommand.name != none && !subCommand.name.IsEmpty()) {
cout.Write(subCommand.name).Write(T(TSPACE));
}
cout.UseColor(_.color.textDefault);
// Parameters
PrintParameters(cout, subCommand.required, subCommand.optional);
cout.Flush();
// Description
if (subCommand.description != none && !subCommand.description.IsEmpty()) {
cout.WriteBlock(subCommand.description);
}
}
private final function PrintOptions(ConsoleWriter cout, Command.Data data)
{
local int i;
local array<Option> options;
options = data.options;
if (options.length <= 0) {
return;
}
cout.UseColor(_.color.textSubHeader)
.WriteLine(T(TOPTIONS))
.UseColor(_.color.textDefault);
for (i = 0; i < options.length; i += 1) {
PrintOption(cout, options[i]);
}
}
private final function PrintOption(
ConsoleWriter cout,
Option option)
{
local Text shortNameAsText;
// Option short and long names with added key characters
shortNameAsText = _.text.FromCharacter(option.shortName);
cout.UseColor(_.color.textEmphasis)
.Write(T(TKEY)).Write(shortNameAsText) // "-"
.UseColor(_.color.textDefault)
.Write(T(TCOMMA_SPACE)) // ", "
.UseColor(_.color.textEmphasis)
.Write(T(TDOUBLE_KEY)).Write(option.longName) // "--"
.UseColor(_.color.textDefault);
shortNameAsText.FreeSelf();
// Parameters
if (option.required.length != 0 || option.optional.length != 0)
{
cout.Write(T(TSPACE));
PrintParameters(cout, option.required, option.optional);
cout.Flush();
}
// Description
if (option.description != none && !option.description.IsEmpty()) {
cout.WriteBlock(option.description);
}
}
private final function PrintParameters(
ConsoleWriter cout,
array<Parameter> required,
array<Parameter> optional)
{
local int i;
// Print required
for (i = 0; i < required.length; i += 1)
{
PrintParameter(cout, required[i]);
if (i < required.length - 1) {
cout.Write(T(TSPACE));
}
}
if (optional.length <= 0) {
return;
}
// Print optional
cout.Write(T(TSPACE)).Write(T(TOPEN_BRACKET));
for (i = 0; i < optional.length; i += 1)
{
PrintParameter(cout, optional[i]);
if (i < optional.length - 1) {
cout.Write(T(TSPACE));
}
}
cout.Write(T(TCLOSE_BRACKET));
}
private final function PrintParameter(ConsoleWriter cout, Parameter parameter)
{
switch (parameter.type)
{
case CPT_Boolean:
cout.UseColor(_.color.typeBoolean);
break;
case CPT_Integer:
cout.UseColor(_.color.typeNumber);
break;
case CPT_Number:
cout.UseColor(_.color.typeNumber);
break;
case CPT_Text:
cout.UseColor(_.color.typeString);
break;
case CPT_Object:
cout.UseColor(_.color.typeLiteral);
break;
case CPT_Array:
cout.UseColor(_.color.typeLiteral);
break;
default:
cout.UseColor(_.color.textDefault);
}
cout.Write(parameter.displayName);
if (parameter.allowsList) {
cout.Write(T(TPLUS));
}
player.Console().Flush();
cout.UseColor(_.color.textDefault);
}
defaultproperties
{
commandName = "help"
TSPACE = 0
stringConstants(0) = " "
TPLUS = 1
stringConstants(1) = "(+)"
TOPEN_BRACKET = 2
stringConstants(2) = "["
TCLOSE_BRACKET = 3
stringConstants(3) = "]"
TKEY = 4
stringConstants(4) = "-"
TDOUBLE_KEY = 5
stringConstants(5) = "--"
TCOMMA_SPACE = 6
stringConstants(6) = ", "
TCOLUMN_SPACE = 7
stringConstants(7) = ": "
TINDENT = 8
stringConstants(8) = " "
TBOOLEAN = 9
stringConstants(9) = "boolean"
TBOOLEAN_TRUE_FALSE = 10
stringConstants(10) = "true/false"
TBOOLEAN_ENABLE_DISABLE = 11
stringConstants(11) = "enable/disable"
TBOOLEAN_ON_OFF = 12
stringConstants(12) = "on/off"
TBOOLEAN_YES_NO = 13
stringConstants(13) = "yes/no"
TCMD_WITH_TARGET = 14
stringConstants(14) = ": This command requires target to be specified."
TCMD_WITHOUT_TARGET = 15
stringConstants(15) = ": This command does not require target to be specified."
TOPTIONS = 16
stringConstants(16) = "OPTIONS"
}

2
sources/Commands/BuiltInCommands/ACommandNick.uc

@ -22,6 +22,7 @@ class ACommandNick extends Command;
//'dosh' for giving dosh (subcommand for setting it, options for min/max resulting value, silent)
protected function BuildData(CommandDataBuilder builder)
{
builder.Name(P("nick")).Summary(P("Changes player's nickname."));
builder.RequireTarget();
builder.ParamText(P("nick"))
.Describe(P("Sets new nickname to the targeted players."));
@ -34,5 +35,4 @@ protected function ExecutedFor(APlayer player, CommandCall result)
defaultproperties
{
commandName = "nick"
}

314
sources/Commands/Command.uc

@ -130,27 +130,22 @@ struct Option
// (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;
// Short summary of what command does (recommended to
// keep it to 80 characters)
var protected Text summary;
var protected array<SubCommand> subCommands;
var protected array<Option> options;
var protected bool requiresTarget;
};
var private Data commandData;
// Default command name that will be used unless Acedia is configured to
// do otherwise
var private const string commandName;
// 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.
var private Command mainInstance;
var public const int TSPACE, TCOMMAND_NAME_FALLBACK, TPLUS;
var public const int TOPEN_BRACKET, TCLOSE_BRACKET;
var public const int TKEY, TDOUBLE_KEY, TCOMMA_SPACE, TBOOLEAN, TINDENT;
var public const int TBOOLEAN_TRUE_FALSE, TBOOLEAN_ENABLE_DISABLE;
var public const int TBOOLEAN_ON_OFF, TBOOLEAN_YES_NO;
var public const int TOPTIONS, TCMD_WITH_TARGET, TCMD_WITHOUT_TARGET;
protected function Constructor()
{
local CommandDataBuilder dataBuilder;
@ -204,21 +199,6 @@ public final static function Command GetInstance()
return default.mainInstance;
}
/**
* Returns name (in lower case) of the caller command class.
*
* @return Name (in lower case) of the caller command class.
* Guaranteed to be not `none`.
*/
public final static function Text GetName()
{
local Text name, lowerCaseName;
name = __().text.FromString(default.commandName);
lowerCaseName = name.LowerCopy();
name.FreeSelf();
return lowerCaseName;
}
/**
* Forces command to process (parse and, if successful, execute itself)
* player's input.
@ -279,7 +259,6 @@ private final function ReportError(
CommandCall callInfo)
{
local Text errorMessage;
local Color previousConsoleColor;
local ConsoleWriter console;
if (callerPlayer == none) return;
if (callInfo == none) return;
@ -287,19 +266,18 @@ private final function ReportError(
// Setup console color
console = callerPlayer.Console();
previousConsoleColor = console.GetColor();
if (callInfo.GetError() == CET_EmptyTargetList) {
console.SetColor(_.color.TextWarning);
console.UseColor(_.color.textWarning);
}
else {
console.SetColor(_.color.TextFailure);
console.UseColor(_.color.textFailure);
}
// Send message
errorMessage = callInfo.PrintErrorMessage();
console.Write(errorMessage);
console.Say(errorMessage);
errorMessage.FreeSelf();
// Restore console color
console.SetColor(previousConsoleColor).Flush();
console.ResetColor().Flush();
}
// Creates (and returns) empty `CommandCall` with given error type and
@ -344,265 +322,37 @@ private final function Text.Character GetNewLine(Text.Formatting formatting)
}
/**
* Returns colored `Text` with auto-generated help page for the caller command.
* Returns name (in lower case) of the caller command class.
*
* @return Auto-generated help page for the caller `Command` class.
* @return Name (in lower case) of the caller command class.
* Guaranteed to be not `none`.
*/
public final function Text PrintHelp()
public final function Text GetName()
{
local Text result, commandNameAsText, commandNameRandomCase;
local MutableText builder, subBuilder;
local Text.Formatting defaultFormatting;
defaultFormatting = _.text.FormattingFromColor(_.color.TextDefault);
builder = _.text.Empty();
// Get capitalized command name
commandNameRandomCase = _.text.FromString(commandName);
commandNameAsText = commandNameRandomCase.UpperCopy();
commandNameRandomCase.FreeSelf();
// Print header: name + basic info
builder.Append(commandNameAsText, defaultFormatting);
if (commandData.requiresTarget) {
builder.Append(T(TCMD_WITH_TARGET), defaultFormatting);
}
else {
builder.Append(T(TCMD_WITHOUT_TARGET), defaultFormatting);
if (commandData.name == none) {
return P("").Copy();
}
// Print commands part
subBuilder = PrintCommands(commandNameAsText);
builder.Append(subBuilder);
_.memory.Free(subBuilder);
// Print options part
subBuilder = PrintOptions();
builder.Append(subBuilder);
_.memory.Free(subBuilder);
result = builder.Copy();
builder.FreeSelf();
return result;
return commandData.name.LowerCopy();
}
private final function MutableText PrintCommands(Text commandNameAsText)
{
local int i;
local Text.Character newLine;
local MutableText builder, subBuilder;
local array<SubCommand> subCommands;
newLine = GetNewLine(_.text.FormattingFromColor(_.color.TextDefault));
subCommands = commandData.subCommands;
builder = _.text.Empty();
for (i = 0; i < subCommands.length; i += 1)
{
builder.AppendCharacter(newLine);
subBuilder = PrintSubCommand(commandNameAsText, subCommands[i]);
builder.AppendCharacter(newLine).Append(subBuilder);
_.memory.Free(subBuilder);
}
return builder;
}
private final function MutableText PrintOptions()
{
local int i;
local Text.Character newLine;
local MutableText builder, subBuilder;
local array<Option> options;
options = commandData.options;
if (options.length <= 0) {
return none;
}
newLine = GetNewLine(_.text.FormattingFromColor(_.color.TextDefault));
builder = _.text.Empty();
builder.AppendCharacter(newLine)
.Append(T(TOPTIONS))
.AppendCharacter(newLine);
for (i = 0; i < options.length; i += 1)
{
subBuilder = PrintOption(options[i]);
builder.AppendCharacter(newLine).Append(subBuilder);
_.memory.Free(subBuilder);
}
return builder;
}
private final function MutableText PrintSubCommand(
Text usedCommandName,
SubCommand subCommand)
{
local MutableText builder, subBuilder;
local Text.Formatting defaultFormatting, emphasisFormatting;
defaultFormatting = _.text.FormattingFromColor(_.color.TextDefault);
emphasisFormatting = _.text.FormattingFromColor(_.color.TextEmphasis);
// Command + parameters
builder = _.text.Empty().Append(usedCommandName, emphasisFormatting);
if (subCommand.name != none && !subCommand.name.IsEmpty())
{
builder.Append(T(TSPACE), defaultFormatting)
.Append(subCommand.name, emphasisFormatting);
}
subBuilder = PrintParameters(subCommand.required, subCommand.optional);
builder.Append(T(TSPACE), defaultFormatting).Append(subBuilder);
_.memory.Free(subBuilder);
// Text description
builder.AppendCharacter(GetNewLine(defaultFormatting))
.Append(T(TINDENT), defaultFormatting)
.Append(subCommand.description, defaultFormatting);
return builder;
}
private final function MutableText PrintOption(Option option)
{
local Text.Character shortName;
local MutableText builder, subBuilder;
local Text.Formatting defaultFormatting, emphasisFormatting;
defaultFormatting = _.text.FormattingFromColor(_.color.TextDefault);
emphasisFormatting = _.text.FormattingFromColor(_.color.TextEmphasis);
// Option name
shortName = option.shortName;
shortName.formatting = emphasisFormatting;
builder = _.text.Empty()
.Append(T(TKEY), emphasisFormatting) // "-"
.AppendCharacter(shortName)
.Append(T(TCOMMA_SPACE), defaultFormatting) //", "
.Append(T(TDOUBLE_KEY), emphasisFormatting) //"--"
.Append(option.longName, emphasisFormatting)
.Append(T(TSPACE), defaultFormatting);
// Possible options
if (option.required.length != 0 || option.optional.length != 0)
{
subBuilder = PrintParameters(option.required, option.optional);
builder.Append(subBuilder);
_.memory.Free(subBuilder);
// If there actually were options - start a new line
builder.AppendCharacter(GetNewLine(defaultFormatting))
.Append(T(TINDENT), defaultFormatting);
}
// Text description
return builder.Append(option.description, defaultFormatting);
}
private final function MutableText PrintParameters(
array<Parameter> required,
array<Parameter> optional)
{
local int i;
local MutableText builder, subBuilder;
local Text.Formatting defaultFormatting;
defaultFormatting = _.text.FormattingFromColor(_.color.TextDefault);
builder = _.text.Empty();
// Print required
for (i = 0; i < required.length; i += 1)
{
subBuilder = PrintParameter(required[i]);
builder.Append(subBuilder);
_.memory.Free(subBuilder);
if (i < required.length - 1) {
builder.Append(T(TSPACE), defaultFormatting);
}
}
if (optional.length <= 0) {
return builder;
}
// Print optional
builder.Append(T(TSPACE), defaultFormatting)
.Append(T(TOPEN_BRACKET), defaultFormatting);
for (i = 0; i < optional.length; i += 1)
{
subBuilder = PrintParameter(optional[i]);
builder.Append(subBuilder);
_.memory.Free(subBuilder);
if (i < optional.length - 1) {
builder.Append(T(TSPACE), defaultFormatting);
}
}
builder.Append(T(TCLOSE_BRACKET), defaultFormatting);
return builder;
}
private final function MutableText PrintParameter(Parameter parameter)
{
local MutableText builder;
local Text.Formatting defaultFormatting, typeFormatting;
defaultFormatting = _.text.FormattingFromColor(_.color.TextDefault);
switch (parameter.type)
{
case CPT_Boolean:
typeFormatting = _.text.FormattingFromColor(_.color.TypeBoolean);
break;
case CPT_Integer:
typeFormatting = _.text.FormattingFromColor(_.color.TypeNumber);
break;
case CPT_Number:
typeFormatting = _.text.FormattingFromColor(_.color.TypeNumber);
break;
case CPT_Text:
typeFormatting = _.text.FormattingFromColor(_.color.TypeString);
break;
case CPT_Object:
typeFormatting = _.text.FormattingFromColor(_.color.TypeLiteral);
break;
case CPT_Array:
typeFormatting = _.text.FormattingFromColor(_.color.TypeLiteral);
break;
default:
}
builder = _.text.Empty().Append(parameter.displayName, typeFormatting);
if (parameter.allowsList) {
builder.Append(T(TPLUS), typeFormatting);
}
return builder;
}
private final function Text PrintBooleanType(PreferredBooleanFormat booleanType)
/**
* Returns `Command.Data` struct that describes caller `Command`.
*
* @return `Command.Data` 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 GetData()
{
switch (booleanType)
{
case PBF_TrueFalse:
return T(TBOOLEAN_TRUE_FALSE);
case PBF_EnableDisable:
return T(TBOOLEAN_ENABLE_DISABLE);
case PBF_OnOff:
return T(TBOOLEAN_ON_OFF);
case PBF_YesNo:
return T(TBOOLEAN_YES_NO);
default:
}
return T(TBOOLEAN);
return commandData;
}
defaultproperties
{
TSPACE = 0
stringConstants(0) = " "
TPLUS = 1
stringConstants(1) = "(+)"
TOPEN_BRACKET = 2
stringConstants(2) = "["
TCLOSE_BRACKET = 3
stringConstants(3) = "]"
TKEY = 4
stringConstants(4) = "-"
TDOUBLE_KEY = 5
stringConstants(5) = "--"
TCOMMA_SPACE = 6
stringConstants(6) = ", "
TINDENT = 7
stringConstants(7) = " "
TBOOLEAN = 8
stringConstants(8) = "boolean"
TBOOLEAN_TRUE_FALSE = 9
stringConstants(9) = "true/false"
TBOOLEAN_ENABLE_DISABLE = 10
stringConstants(10) = "enable/disable"
TBOOLEAN_ON_OFF = 11
stringConstants(11) = "on/off"
TBOOLEAN_YES_NO = 12
stringConstants(12) = "yes/no"
TCMD_WITH_TARGET = 13
stringConstants(13) = ": This command requires target to be specified."
TCMD_WITHOUT_TARGET = 14
stringConstants(14) = ": This command does not require target to be specified."
TOPTIONS = 15
stringConstants(15) = "OPTIONS"
// Under normal conditions we only create one instance of each, so
// there is no need to object pools
usesObjectPool = false
}

55
sources/Commands/CommandDataBuilder.uc

@ -42,6 +42,7 @@ class CommandDataBuilder extends AcediaObject
*/
// "Prepared data"
var private Text commandName, commandSummary;
var private array<Command.SubCommand> subcommands;
var private array<Command.Option> options;
var private bool requiresTarget;
@ -82,6 +83,8 @@ protected function Finalizer()
options.length = 0;
optionsIsOptional.length = 0;
selectedParameterArray.length = 0;
commandName = none;
commandSummary = none;
selectedItemName = none;
selectedDescription = none;
requiresTarget = false;
@ -449,6 +452,50 @@ public final function CommandDataBuilder Describe(Text description)
return self;
}
/**
* Sets new name of `Command.Data` under construction. This is a name that will
* be used unless Acedia is configured to do otherwise.
*
* @return Returns the caller `CommandDataBuilder` to allow for
* method chaining.
*/
public final function CommandDataBuilder Name(Text newName)
{
if (newName != none && newName == commandName) {
return self;
}
_.memory.Free(commandName);
if (newName != none) {
commandName = newName.Copy();
}
else {
commandName = none;
}
return self;
}
/**
* Sets new summary of `Command.Data` under construction. Summary gives a short
* description of the command on the whole, to be displayed in a command list.
*
* @return Returns the caller `CommandDataBuilder` to allow for
* method chaining.
*/
public final function CommandDataBuilder Summary(Text newSummary)
{
if (newSummary != none && newSummary == commandSummary) {
return self;
}
_.memory.Free(commandSummary);
if (newSummary != none) {
commandSummary = newSummary.Copy();
}
else {
commandSummary = none;
}
return self;
}
/**
* Makes caller builder to mark `Command.Data` under construction to require
* a player target.
@ -497,9 +544,11 @@ public final function Command.Data GetData()
{
local Command.Data newData;
RecordSelection();
newData.subcommands = subcommands;
newData.options = options;
newData.requiresTarget = requiresTarget;
newData.name = commandName;
newData.summary = commandSummary;
newData.subcommands = subcommands;
newData.options = options;
newData.requiresTarget = requiresTarget;
return newData;
}

22
sources/Commands/Commands.uc

@ -66,24 +66,26 @@ protected function OnDisabled()
public final function RegisterCommand(class<Command> commandClass)
{
local Text commandName;
local Command commandInstance;
local Command newCommandInstance, existingCommandInstance;
if (commandClass == none) return;
if (registeredCommands == none) return;
commandName = commandClass.static.GetName();
commandInstance = Command(registeredCommands.GetItem(commandName));
if (commandInstance != none)
newCommandInstance = Command(_.memory.Allocate(commandClass, true));
commandName = newCommandInstance.GetName();
// Check for duplicates and report them
existingCommandInstance = Command(registeredCommands.GetItem(commandName));
if (existingCommandInstance != none)
{
_.logger.Auto(errCommandDuplicate)
.ArgClass(commandInstance.class)
.Arg(commandName.Copy())
.ArgClass(existingCommandInstance.class)
.Arg(commandName)
.ArgClass(commandClass);
commandName.FreeSelf();
_.memory.Free(newCommandInstance);
return;
}
commandInstance = Command(_.memory.Allocate(commandClass, true));
// Otherwise record new command
// `commandName` used as a key, do not deallocate it
registeredCommands.SetItem(commandName, commandInstance, true);
registeredCommands.SetItem(commandName, newCommandInstance, true);
}
/**
@ -157,5 +159,5 @@ defaultproperties
{
useChatInput = true
requiredListeners(0) = class'BroadcastListener_Commands'
errCommandDuplicate = (l=LOG_Error,m="Command `%1` with name '%2' is already registered. Command `%3` will be ignored.")
errCommandDuplicate = (l=LOG_Error,m="Command `%1` is already registered with name '%2'. Command `%3` with the same name will be ignored.")
}
Loading…
Cancel
Save