Creating Custom Commands
What Are Custom Commands
Custom commands are shrubbot like commands that are not implemented by the silEnT mod, but instead by server admins. There are three ways to create custom commands. One is to simply use the [command] blocks in the shrubbot.cfg. Second one is to combine [command] block with a Lua script that will do more complicated work than what just the rcon can do. And the third method is to implement everything with Lua. The following sections describe each of these methods.
Shrubbot.cfg Method
The shrubbot.cfg file on your server can include following blocks:
[command] command = The name of the command. exec = The executed command. These must be commands available to /rcon and these will be executed with rcon privileges. desc = The help description of the command. syntax = List of parameters if the command uses them. This is used with !help and it is optional. levels = Space separated list of levels that are allowed to use the command.
These commands appear in the !help output just as if they were implemented by the silEnT mod itself. Also, !help <command name> can be used to see detailed help about the commands. The exec line defines the commands that will be executed by the mod. The exec field supports the following:
- The commands can be anything that can be executed with /rcon.
- The commands can use all shortcuts that players can use with their chat messages.
- Additional shortcut [i] is available. This will be replaced with the client slot number of the player who called the command. If the command was called from the server console, or /rcon, this shortcut will not be replaced.
- The shrubbot custom commands support parameter place holders. These are [1] - [9], where the number is the n:th parameter given to the custom command. When these are used, the server will substitute the placeholder with the n:th parameter given to the command.
- There is also the possibility to add ? to the parameter placeholders. If the question mark is added, the parameter is substituted with a player name if only one name matches the pattern. If there are no matches or there are several matches, the command will fail and reports an informative error. All placeholders can have the question mark if that is needed for the command.
Example
[command] command = crybaby exec = playsound path/to/sound.wav; chat ^7[1?]^7 is crying like a little baby! desc = Make someone cry like a baby syntax = [name] levels = 0 1 2 3 4 5
[command] command = takess exec = pb_sv_getss [1] desc = Send pb SS of player to server. Use /pb_plist & type !takess PB slot number. syntax = levels = 5
[command] command = omnifix exec = bot kickall desc = To kick all bots if their are more then 5 vs 5 players playing. syntax = levels = 21
Note:
If the command breaks because the name that substitutes a placeholder has spaces, use " characters to surround the placeholder. Like this "[1?]". It will ensure that the full name is parsed as one parameter instead of getting interpreted as separate parameters.
Combining shrubbot.cfg and Lua Scripts
One method to extend what the commands can do, is to use a Lua script to implement the actual command operation. To do this, create a custom command to the shrubbot.cfg, which executes a command, that is not recognized by the silEnT mod. Such commands will pass through to the et_ConsoleCommand Lua callback. Where it can be intercepted and proper actions can be taken. The advantage of this method is that the command privileges and the help are handled by the silEnT mod. This includes the Admin Level Protection. In other words, it is easy to ensure that the command is not used by unwanted persons.
Example
For the purposes of this example, the command is mycommand. It will be executed when the user enters !mycommand to the console, assuming that player has been assigned level 2 or higher shrubbot level.
1. Create your command in the shrubbot file. Open your shrubbot.cfg file (in silent\database directory) and add the following block:
[command] command = mycommand exec = mycommand_lua [i] desc = Does something cool for people over level 2 syntax = levels = 2 3 4 5
Note: Be careful with the called command. If the command that is directed to Lua, and the custom command in shrubbot.cfg have the same name, an infinite loop can form if the Lua script does not return 1. This can happen because if the command is not handled by the Lua script, it will again get handled as a shrubbot custom command.
2. Create a LUA file in your silent directory on the server. Call it mycommand.lua (or whatever name you want to give it). Begin with the following stub:
function et_ConsoleCommand(command) -- if the user types !mycommand in the console if et.trap_Argv(0) == "mycommand_lua" then -- Do your custom processing here local clientNum = et.trap_Argv(1) et.trap_SendServerCommand(clientNum, "chat \"Your command "..et.trap_Argv(0).." has been received\"") return 1 -- Tells silEnT that this script handled this command end return 0 -- Tells silEnT that this script did not handle this command end
3. Update your server config to load the LUA file. Add or modify the following server var (lua_modules):
set lua_modules "mycommand.lua"
4. Restart your server. Assuming you are on a shrubbot level 2 or higher, !mycommand will execute and do cool stuff.
Only With Lua
Some servers use quite large and complicated additional command implementations that are implemented entirely by Lua scripting. This is not the recommended method to do admin systems, unless you have a pressing need for this.
Example
function SplitToArguments(line) local array = {} local aindex = 0 for i in string.gmatch(line, "%S+") do array[aindex] = string.lower(i) aindex = aindex + 1 end return array end function CheckCommand(clientNum, arguments) if( arguments[0] == "!mycommand" ) then et.trap_SendServerCommand(clientNum, "chat \"Your command "..arguments[0].." has been received\"") return 1 end return 0 end function et_ClientCommand(clientNum, command) local level = et.G_shrubbot_level(clientNum) local flood = et.ClientIsFlooding(clientNum) -- we're not interested if the level is too low or if the client is flooding if (level < 1) or (flood == 1) then return 0 end local arg0 = string.lower(et.trap_Argv(0)) local arguments -- check to see if the command was given through any of the chat methods or as sparse text from the console if arg0 == "say" or arg0 == "say_team" or arg0 == "say_buddy" or arg0 == "say_teamnl" then arguments = SplitToArguments(et.trap_Argv(1)) else arguments = SplitToArguments(et.ConcatArgs(0)) end -- actual command handling return CheckCommand(clientNum, arguments) end
This example shows the same functionality as the combined example above. Do note, that if the full admin system is made manually, handling the command arguments require special care. In the above example it shows how the arguments are handled differently depending if the script is handling player chatting, or if the commands are read from sparse texts that players write to console. For safety, ConcatArgs could be used for both, just in case there are bugs in the silEnT implementation, but splitting the single argument should work equally well in all cases.