Skip to content

dev:Command Handling

Väinämö Łūmikērø edited this page Feb 2, 2017 · 6 revisions

Command Types

There are three types of commands in Forestual 2 - primary commands, secondary commands and tertiary commands.

Type Description Example Restrictions
Primary Command without parameters. /version,
/shutdown
May only consist of letters (a-zA-Z), numbers (0-9) and -.
Secondary Command with optional parameters. /ping [account],
/motd [content]
Same as for Primary applies.
Tertiary Command with required (and optional) parameters. /join <channel>,
/bann <account> <duration> [reason]
Same as for Secondary applies plus
optional parameters must be at the end
and may not be followed by required parameters.

Try not to use more than 1 string parameter (with spaces allowed) at the moment. This will presumably crash the system.
However, we're working on a solution for this problem (Core/#2).


Defining a Command

this refers to the extension handling the commands.

// Creating the commands
var Shutdown = new Command("shutdown", this);
var Motd = new Command("motd", this);
var Bann = new Command("bann", this);

// Applying parameters
Motd.AddParameter<string>("content", 0, ParameterType.Optional);

Bann.AddParameter<string>("account", 0, ParameterType.Required);
Bann.AddParameter<int>("duration", 1, ParameterType.Required);
Bann.AddParameter<string>("reason", 2, ParameterType.Optional);

Validating a Command

bool Valid;

// This may seem futile as the string equality operator (==) should work fine, but it's not. See "Why is this useful?" below.
Valid = Shutdown.Validate("/shutdown 5"); // false, because shutdown doesn't accept parameters.
Valid = Shutdown.Validate("/shutdown"); // true

Valid = Motd.Validate("/motd"); // true, because the content parameter is optional.
Valid = Motd.Validate("/motd Welcome"); // true

Valid = Bann.Validate("/bann vainamo"); // false, because bann requires a duration.
Valid = Bann.Validate("/bann vainamo foo"); // true, because Validate() does not check the parameter types.
Valid = Bann.Validate("/bann vainamo 7 <Some Reason Here>"); // true

Parsing a Command

string Content = "/bann vainamo 7 <Some Reason Here>"; // Demo purpose. Obviously you would not set the content yourself.

// Extra validation because Parse() does validate the command but returns the default value if the validation fails.
if (Bann.Validate(Content)) {
    try {
        var Target = Bann.Parse<string>(Content, "account");
        var Duration = Bann.Parse<int>(Content, "duration");
        var Reason = Bann.Parse<string>(Content, "reason");
    
        // Do stuff
    } catch {
        /*
        A FormatException is thrown, when the parameter value in content
        does not match the type. For example a "foo" when an int is required.
        An InvalidCastException is thrown, when the T type in Parse<T> does
        not match the parameter type. For example Parse<string>(content, "duration").
        */
    }
}

Why is this useful?

  • Fallback Mechanism
    The system uses a fallback mechanism to solve what we call conflicts. Conflicts occur when two or more extensions use the same command, for example two games using /start to begin a new match. To distinguish between conflicted commands, the command systems allows prefixing each command with the extension namespace it belongs to. So /race:start is additionally valid in ml.festival.race but not in ml.festival.quiz (/quiz:start).
    This system even has a Fallback Fallback (...) Mechanism. In case the namespace of two extensions (using the same command) end in the same word (eg. ml.festival.quiz and de.vainamo.quiz), the commands could still be distinguished by adding festival. (or vainamo. respectively) to the prefix quiz:. In case this part is also the same, continue adding parts from the namespace until the conflict ends. Note that the order of the namespace parts has to be preserved. /ml.quiz:start is not the same as /ml.festival.quiz:start!
  • Strict Validation
    Validating a secondary command using string.StartsWith("/command") would also validate commands starting with command (for example /commands). Using Command.Validate() prevents this.
  • Flexible Case Recognition
    If Command.IgnoreCase is set to true, commands with different cases (/cOMmand, /Command, /COMMAND) would still be valid.