playing with the console command list Created 2 months ago2019-01-07 21:42:17 UTC by tschumann tschumann

Created 2 months ago2019-01-07 21:42:17 UTC by tschumann tschumann

Posted 2 months ago2019-01-07 21:42:17 UTC Post #341578
cl_enginefunc_t provides GetFirstCmdFunctionHandle, GetNextCmdFunctionHandle and GetCmdFunctionName for playing with the engine's list of console commands, though it looks like the definitions aren't quite right - they should probably be this (some documentation from prsearle):
typedef void (*xcommand_t) (void);    // Pointer to console command handler

typedef struct cmd_function_s {
    struct cmd_function_s *next;    // Next console command structure
    const char *name;                // Console command as typed at console (e.g. "stopsound")
    xcommand_t  function;            // Pointer to function called when command is entered
    const char *description;        // Command description ???
    qboolean    pure;                // ???
} cmd_function_t;

...

typedef cmd_function_t*                (*pfnEngSrc_GetFirstCmdFunctionHandle_t)();
typedef cmd_function_t*                (*pfnEngSrc_GetNextCmdFunctionHandle_t)(cmd_function_t* cmdhandle);
typedef const char *                (*pfnEngSrc_GetCmdFunctionName_t)(cmd_function_t* cmdhandle);
So it looks like it's possible to modify or remove entries in the engine's command list (though maybe we're not meant to given that the definitions in the SDK aren't usable). My question is how modifying the function attribute of cmd_function_t would work - it doesn't seem to take any arguments and from a quick look at Quake's code it looks like the passed arguments are stored in a global char* pointer which the client code probably doesn't have access to. Seems like there isn't a way to usefully override a console command based on the arguments that get passed?

edit: is multi-line code formatting possible?
Posted 2 months ago2019-01-07 22:17:27 UTC Post #341579
You can get the command arguments using cl_enginefunc_t::Cmd_Argc and cl_enginefunc_t::Cmd_Argv, just like you'd do it on the server side.

All the function member does is store the callback invoked for a named command, you can't control which one is executed based on inputs, you'd have to do that in the callback itself.

If your goal is to override an engine command conditionally based on what's passed into it you can create your own callback that stores off the original function and that forwards calls unless your condition is matched.

Unfortunately you can't add state to the callback since it's all basic C style code, so you'll have to either use global variables or create a lookup table to get a stateful object that will handle the callback. If you're going to do that registering the same callback for all your commands and then using the first argument to find the handler should do.

The complete definition for the engine's data structure is this:
typedef struct cmd_function_s
{
  cmd_function_s *next;
  char *name;
  xcommand_t function;
  int flags;
} cmd_function_t;
The flags member is used to keep track of where commands came from so they can be removed (client, server, GameUI). Otherwise, if a library gets unloaded the command can still be executed, but the callback will point to freed memory.

As for multi-line formatting, see this: https://twhl.info/wiki/page/TWHL:_WikiCode_Syntax#h5bfbcfa35e405
Posted 2 months ago2019-01-08 04:41:05 UTC Post #341585
Ah thanks - I thought about Cmd_Argc and Cmd_Argv after I posted but I wasn't sure if they'd have the right data in them (I guess they have to).
And yeah I was thinking store the original and only pass off to it if some condition was met, otherwise just print an error or something.
You must be logged in to post a response.