Table of Contents
Per revision "R24" console command handling has been significantly changed. ClientCommand (g_cmds.c) and ConsoleCommand (g_svcmds.c) now employ a loop structure by which to check the command the user/player enters against a table. If it successfully finds a match, the loop breaks and a validation check is made, based on the parameters specified in the table. If this validation check is successful, either ClientCommand or ConsoleCommand, then calls the associated command handler specified inside the corresponding table.
This provides significant "modularity" to adding/maintaining console commands, and provides increased flexibility to the "child" command handlers. Since all "child" command handlers which require "arguments" now must be written with the ability to trap those arguments themselves, "commands" having similar functionality can now be called from the same handler.
To successfully add a command, either as a "ClientCommand" (g_cmds.c) or a ConsoleCommand (g_svcmds.c) the following needs to happen.
# Functions to be called from ClientCommand (g_cmds.c) must have, and only have the parameter `gentity_t *ent`. eg:
# Functions being called from ConsoleCommand (g_svcmds.c) must have no parameters. eg:
# If the function is contained in another code file, it must be declared in a header file, either "g_local.h" or a header file referenced by an `#include` in "g_local.h" # If the function is in the same file, it must be placed above/before either the "ClientCommand" (g_cmds.c) or ConsoleCommand (g_svcmds.c) and preferably be defined as `static`. # An entry must be made in the corresponding array (`commands_t cmd` for a "ClientCommand" in g_cmds.c, and `svcmds` for a ConsoleCommand in g_svccmds.c). See below for the way the two command tables/arrays are structured. # All fields for the array/table must be entered--if they are to be "null," "0" or "NULL" should be entered.
Getting a command to work properly is another story and completely up to the person writing the command. Here are some considerations:
# Should the command only run if entered from the server? If so, the command must be placed/processed under g_svcmds.c Adding the command into g_cmds.c will otherwise give any/all players access to it. # Does the command need to process "arguments?" If so, inside the function, "trap_Argv" can be called in order to parse them. # Are there certain conditions when the command should be ignored? See the command flags below.
# The "cmdName" must be entered into the "cmd" array with quotation marks. It is a literal string. # The "cmdHandler" is the name of the function to be called. Only the name of the function should be entered--`( gentity_t *ent )` must not trail the name!!! # "ent" is the entity which entered the command. This is the only parameter common to all commands entered into the console which are a "ClientCommand."
The "cmdFlags" are below.
Note: I am not going to analyze the validation inside ClientCommand, there are too many details and doing so is just rewriting the code in plain language! :) That said, here are some considerations.
# If a command is to be enabled during intermission, it must be flagged with "CMD_INTERMISSION" as the stock validation check ignores commands when the game is in intermission if they are not flagged as such. # Cheat commands are checked against the value for the cvar "g_cheats" and not sv_cheats. (Sorry if I am stating the obvious for experienced Q3-based game modders.)