Commands are a powerful real-time way of handling user command input. Commands are put to heavy use in the NLNET service code as you'll read later but can be used in many places. There are two main macros that govern the creation of commands in NeL: NLMISC_COMMAND and NLMISC_CATEGORISED_COMMAND. NLMISC_COMMAND calls NLMISC_CATEGORISED_COMMAND with a default category of "commands" so we'll discuss NLMISC_CATEGORISED_COMMAND indepth. Below is the definition of the macro.
NLMISC_CATEGORISED_COMMAND(category, name, help, args) {
// expression/logic here
}
The NLMISC_CATEGORISED_COMMAND macro takes four parameters. The category parameter simply specifies the category of the command within the help system. This is particularly useful if you have a program or service with a large number of commands. The name parameter specifies the name of the command that the user will call to execute the command - this will make more sense later when we discuss using the NLMISC::ICommand::execute static method. The last two arguments, help and args are also for the help system. The help argument is a string that you provide to advise the user on what the command is and how to use it. The args argument is a string that you provide to explain the type and number of arguments to provide to the command system. Here is an example of a fully functioning command:
NLMISC_COMMAND(square, "display the square of the parameter", "<value>")
{
// check the number of args passed.
if(args.size() != 1)
return false; // return not ok, too many arguments.
// convert the argument from a string to an integer
uint32 val = atoi(args[0].c_str());
log.displayNL("The square of %d is %d", val, val*val);
// return ok status.
return true;
}
The block of logic defined above is actually your specialization of the abstract method NLMISC::ICommand::execute. When the system calls your command it will pass this block of logic the following arguments for you to work with:
Once you have created commands if your application is a NLNET service you may begin using them immediate from the service console. However if you're programming a new console application or even a game you can capture user input and pass it directly the command system. This is a quick and easy way of creating a command console for clients. See the following code for an example of executing commands outside of the service infrastructure:
// assume that our "square" example above is in this example.
int main()
{
NLMISC::createDebug();
while(true)
{
// display our command prompt
std::cout << "> ";
// get input from the console.
std::string command;
std::getline(std::cin, command, '\n');
// exit the application
if(command == "quit")
break;
// attempt to execute the command entered by the user.
// For example assume the user entered "square 2"
NLMISC::ICommand::execute(command, NLMISC::InfoLog);
}
}
You see here how we quickly developed an application in which a user can execute commands that you have created with a small amount of code.
All commands should following the naming convention of NeL functions, for example: updateSomething and displayStuff.
The macros, interfaces and examples above will cover the vast majority of developer needs. But you will find circumstances where your command needs some special attention. There are two more advanced topics to cover with NeL commands: command friendship and object command handlers.
At the core of the command system are the macros mentioned above which dynamically generate a new class for your command. If this command needed access to some private members of an object that, for example, displays the current thresholds you would need your command to be a friend of this other class. NeL provides two handy macros to accomplish this and all you need to do is use them in your class definition.
NLMISC_COMMAND_FRIEND(name)
NLMISC_CATEGORISED_COMMAND_FRIEND(category, name)
The custom commands handler is a much more extensive subject.
// Basic custom command handler
class CMyClass : public CCommandsHandler<CMyClass>
{
public:
NLMISC_COMMAND_HANDLER_TABLE_BEGIN(CMyClass)
NLMISC_COMMAND_HANDLER_ADD(CMyClass, theCommand1, "help", "args")
NLMISC_COMMAND_HANDLER_ADD(CMyClass, theCommand2, "other help", "other args")
NLMISC_COMMAND_HANDLER_TABLE_END
NLMISC_CLASS_COMMAND_DECL(theCommand1)
{
// some command logic here.
}
NLMISC_CLASS_COMMAND_DECL(theCommand1)
{
// some command logic here.
}
};
TODO FINISH TALKING ABOUT THIS
class CMySubClass : public CMyClass
{
public:
NLMISC_COMMAND_HANDLER_TABLE_EXTEND_BEGIN(CMyClass)
NLMISC_COMMAND_HANDLER_ADD(CMyClass, addedCommand, "help", "args")
NLMISC_COMMAND_HANDLER_TABLE_END
NLMISC_CLASS_COMMAND_DECL(addedCommand)
{
// some command logic here.
}
};
AND THIS