4
\$\begingroup\$

I'm making a console, like in Half-Life so that the devs can add their commands.

I'm making this in Unity's C#.

I have a problem when dealing with the commands. When you want to add a commands, you create a class Command and add it through a method to the Console List of Commands.

The code of the class Command is the following one:

public class Command
    {
        /// <summary>The string by which this command will be called</summary>
        public string commandKey;
        /// <summary>The information of this command that the help option will show</summary>
        public string helpInfo;

        public delegate string stringVoid();
        public delegate string stringString(string consoleInput);
        public delegate void voidCmd();
        public delegate void voidString(string consoleInput);

        public stringVoid _stringVoid;
        public stringString _stringString;
        public voidCmd _voidCmd;
        public voidString _voidString;

        public Command(string commandInput, string helpTooltip)
        {
            commandKey = commandInput;
            helpInfo = helpTooltip;
        }

        #region Add Command Methods
        public Command addVoidCommand(voidCmd voidCommand)
        {
            _voidCmd = voidCommand;
            return this;
        }
        public Command addStringVoid(stringVoid stringVoidCmd)
        {
            _stringVoid = stringVoidCmd;
            return this;
        }

        public Command addStringString(stringString stringStringCmd)
        {
            _stringString = stringStringCmd;
            return this;
        }

        public Command addVoidString(voidString voidStringCmd)
        {
            _voidString = voidStringCmd;
            return this;
        }
        #endregion
    }

As you can see users can add four types of delegates methods:

  • Void methods with no parameters.
  • String methods with no parameters.
  • Void methods with a string parameter.
  • String method with a string parameter.

This makes the class very heavy, and makes the users have to navigate through a lot of options to add a class.

I want to have some way to add methods without having to go through so many options, and, from my side, taking out the need of searching through so many options when a command is called from console.

You can find the whole script/project here.

In conclusion, I want to have a way that the user simply write

// way I want it to work
new Command("commandName", "this is an example" ExampleCommand);
new Command("commandString", "this is another example" ExampleString);

void ExampleCommand(){ }
string ExamplesString(string ble){ return ble + "bla"; }

// way it currently works
new Command("commandName", "this is an example").addVoidCommand(ExampleCommand);
new Command("commandString", "this is another example").addStringString(ExampleString);

To simplify everything. Is any way I can achieve this with delegates, Unity Actions or something else?

Thank you very much.

\$\endgroup\$
  • \$\begingroup\$ I never played CS in my life, can you please describe what that console is like? \$\endgroup\$ – Bálint Apr 1 '17 at 18:05
  • \$\begingroup\$ @Bálint it is a screen that accept input and can execute commands. It's used to change values or call methods in the game, without the need to bind them to a key. You simply open the console, type your method and it execute that method, if it has a parameter, it takes it into consideration. You can see an example here: youtu.be/b4MPEpLTSMc?t=19s \$\endgroup\$ – Javier Bullrich Apr 1 '17 at 18:06
  • \$\begingroup\$ Note that "console" is not unique to HL or CS. It is a pretty standard feature in software, not unique to games. \$\endgroup\$ – Gnemlock Apr 2 '17 at 0:34
  • \$\begingroup\$ @Gnemlock I know, I was using HL as a reference of what I'm trying to achieve. \$\endgroup\$ – Javier Bullrich Apr 2 '17 at 16:51
3
\$\begingroup\$

The way I implemented this myself might not be perfect or the most C# solution (since I use C++) but it works pretty well for me and even provides some additional features.

So, in this solution all your console command callbacks would have the same signature: void ConsoleCommand(List<string> arguments);. Now as you can see, all the parameters are passed into the command as a list of strings, and that is indeed the downside of this approach: the command needs to do its own argument parsing, and convert the data it gets into correct datatypes and so on. This can be quite error prone.

However, there's also a small benefit into doing this: optional parameters. Let's take a console command that spawns in an enemy for an example. The user would type in /spawnEnemy 100 200 and the console command would spawn the enemy at the given coords. But here comes the trick: if the user types in just /spawnEnemy instead, the command could decide to perhaps use the mouse cursor's position for an example.

void SpawnEnemy(List<string> arguments)
{
    if (arguments.Size == 2)
    {
        ActualSpawnEnemy(arguments[0].ToInt(), arguments[1].ToInt());
    }
    else if (arguments.Size == 0)
    {
        ActualSpawnEnemy(Mouse.X, Mouse.Y);
    }
    else
    {
        // Display something to the user.
    }
}

void ActualSpawnEnemy(int x, int y)
{
    ...
}
\$\endgroup\$
  • 1
    \$\begingroup\$ Based on how little I've touched the Minecraft command code, I'm pretty sure it handles things this way. There's no other way that really "works" well due to the wide variety of possible parameter options. \$\endgroup\$ – Draco18s Apr 3 '17 at 15:33
2
\$\begingroup\$

Use a Delegate:
Change your constructor to something like this:

public Command(string commandInput, string helpTooltip, Delegate invoker)

Now the constructor callers have to look like this:

new Command("commandName", "this is an example", (Action)ExampleCommand);
new Command("commandString", "this is another example", (Func<string, string>)ExamplesString);

The invoker Delegate has a method named DynamicInvoke which takes an array of arguments (if any) and returns an object with the return value (or null if the method return type is Void).

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.