Handling Command Calls
The system goes through a few steps between when a user enters a command in an input field, and when a command listener is called.
For a command that is handled locally, these steps are:
- User enters command string
- CosmosConsole parses command string into Command data
- Command data is validated
- Command listeners are invoked
For a command that is handled over the network the steps are slightly different:
- User enters command string (in client console)
- Command string is send over network to the connected server console
- CosmosConsole on server parsers command string into Command data
- Command data is validated
- Command listeners (on the server) are invoked
The system can stop early at the parsing and validation steps if either of these fail. In that case the command listeners will not be invoked.
Example Command
For the following examples we'll define a "calculate" command that does some calculation on the numbers that are passed to it as parameters. In the console configuration we define it as follows:
The "type" parameter specifies what calculation you want to do. If we enter:
calculate sum 3 4
We want it to reply with:
Answer: 7
And similarly we want that to work for "multiply" and "average" calculations too, with an arbitrary list of numbers, such that:
calculate average 7 14 30 8 16
Replies with:
Answer: 15
Listeners
You can register a command listeners in script using CosmosConsole.AddCommandListener. This is an example Monobehaviour script to handle the "calculate" command defined above:
public class CalculateCommandHandler : MonoBehaviour
{
void Start()
{
CosmosConsole console = UnityCosmosConsole.Current;
console.AddCommandListener("calculate", HandleCalculateCommand);
}
private void OnDestroy()
{
CosmosConsole console = UnityCosmosConsole.Current;
console.RemoveCommandListener("calculate", HandleCalculateCommand);
}
private void HandleCalculateCommand(ICommandSender sender, Command command)
{
// TODO
}
}
We maintain the command listener based on the MonoBehaviour lifetime by adding it in Start() and removing it in OnDestroy(), similar to how C# events are commonly handled.
This script makes use of the UnityCosmosConsole utility script for the CosmosConsole instance
Alternatively for adding and removing the command listener, CosmosConsole.AddCommandListener returns a CommandHandle that you can pass to CosmosConsole.RemoveCommandListener or CosmosConsole.RemoveListeners at the end of its lifetime.
Parameters
Let's zoom in on the callback method for the command listener shown above. You can obtain the Parameters data from the Command data. Next we retrieve the parameter with the key "type" to determine the calculation we want to do. Finally we iterate over the remaining (key-less) parameters and add these to a list of numbers
private void HandleCalculateCommand(ICommandSender sender, Command command)
{
Parameters parameters = command.parameters;
string calcType = parameters.Get("type");
List<float> numbers = new List<float>();
// Parameter 0 is used by the 'type' parameter so the entered numbers start from index 1
for (int i = 1; i < command.parameters.Count; i++)
numbers.Add(parameters.GetFloat(i));
// TODO
}
Since "type" is a required parameter, we can assume parameters.Get("type") will always succeed otherwise the listener would not have been invoked. In case of optional parameters, you can use the Parameters.Try[...] methods like Parameters.TryGet(...) to verify if a parameter was specified by the user.
Output
Now that we have all the data we need, we can do the calculation using some LINQ wizardry:
private void HandleCalculateCommand(ICommandSender sender, Command command)
{
Parameters parameters = command.parameters;
string calcType = parameters.Get("type");
List<float> numbers = new List<float>();
// Parameter 0 is used by the 'type' parameter so the entered numbers start from index 1
for (int i = 1; i < command.parameters.Count; i++)
numbers.Add(parameters.GetFloat(i));
float result = 0;
switch (calcType)
{
case "sum": result = numbers.Aggregate((n1, n2) => n1 + n2); break;
case "multiply": result = numbers.Aggregate((n1, n2) => n1 * n2); break;
case "average": result = numbers.Aggregate((n1, n2) => n1 + n2) / numbers.Count; break;
}
sender.LogMessage("Answer: " + result);
}
sender.LogMessage outputs to the console that originally called the command, even if it's a remote client.
Finally add the CalculateCommandHandler script to the scene with the console and you'll be able to call the command.
Throwing Exceptions
If you want to add some additional validation to your parameters that goes beyond the scope of the Validation field of the parameter definition in the console configuration, you can use the CommandInvalidParametersException. For example, if we want the calculation in our example to only work when you have at least 2 numbers entered, we could add the following check at the start:
private void HandleCalculateCommand(ICommandSender sender, Command command)
{
Parameters parameters = command.parameters;
if (parameters.Count < 3)
throw new CommandInvalidParametersException("Enter at least two numbers");
string calcType = parameters.Get("type");
List<float> numbers = new List<float>();
// Parameter 0 is used by the 'type' parameter so the entered numbers start from index 1
for (int i = 1; i < parameters.Count; i++)
numbers.Add(parameters.GetFloat(i));
float result = 0;
switch (calcType)
{
case "sum": result = numbers.Aggregate((n1, n2) => n1 + n2); break;
case "multiply": result = numbers.Aggregate((n1, n2) => n1 * n2); break;
case "average": result = numbers.Aggregate((n1, n2) => n1 + n2) / numbers.Count; break;
}
sender.LogMessage("Answer: " + result);
}
Then the output would look like this:
Note that is way of adding parameter validation is only recommended if you have a single listener for that particular command. If you want to validate parameters before any listeners are invoked, see the section on Custom Command Validation.