void FakeClientCommand (edict_t *fakeClient, const char *format, ...) { // the purpose of this function is to provide fakeclients (bots) with the same client // command-scripting advantages (putting multiple commands in one line between semicolons) // as real players. It is an improved version of botman's FakeClientCommand, in which you // supply directly the whole string as if you were typing it in the bot's "console". It // is supposed to work exactly like the pfnClientCommand (server-sided client command). va_list ap; static char command[256]; int start, stop, i, index, stringIndex = 0; if (FNullEnt (fakeClient)) return; // reliability check // concatenate all the arguments in one string va_start (ap, format); _vsnprintf (command, sizeof (command), format, ap); va_end (ap); if (IsNullString (command)) return; // if nothing in the command buffer, return g_isFakeCommand = true; // set the "fakeclient command" flag int length = strlen (command); // get the total length of the command string // process all individual commands (separated by a semicolon) one each a time while (stringIndex < length) { start = stringIndex; // save field start position (first character) while (stringIndex < length && command[stringIndex] != ';') stringIndex++; // reach end of field if (command[stringIndex - 1] == '\n') stop = stringIndex - 2; // discard any trailing '\n' if needed else stop = stringIndex - 1; // save field stop position (last character before semicolon or end) for (i = start; i <= stop; i++) g_fakeArgv[i - start] = command[i]; // store the field value in the g_fakeArgv global string g_fakeArgv[i - start] = 0; // terminate the string stringIndex++; // move the overall string index one step further to bypass the semicolon index = 0; g_fakeArgc = 0; // let's now parse that command and count the different arguments // count the number of arguments while (index < i - start) { while (index < i - start && g_fakeArgv[index] == ' ') index++; // ignore spaces // is this field a group of words between quotes or a single word ? if (g_fakeArgv[index] == '"') { index++; // move one step further to bypass the quote while (index < i - start && g_fakeArgv[index] != '"') index++; // reach end of field index++; // move one step further to bypass the quote } else while (index < i - start && g_fakeArgv[index] != ' ') index++; // this is a single word, so reach the end of field g_fakeArgc++; // we have processed one argument more } // tell now the MOD DLL to execute this ClientCommand... MDLL_ClientCommand (fakeClient); } g_fakeArgv[0] = 0; // when it's done, reset the g_fakeArgv field g_isFakeCommand = false; // reset the "fakeclient command" flag g_fakeArgc = 0; // and the argument count }
// UTIL_FakeClientCommand // PURPOSE: Sends a fake client command to GameDLL // HOW DOES IT WORK: // 1) Stores command and arguments into a global and sets the global "fake" flag to true // 2) Invokes ClientCommand in GameDLL // 3) meta_api.cpp overrides Cmd_Args, Cmd_Argv, Cmd_Argc and gives them fake values if the "fake" flag is set // 4) unsets the global "fake" flag void UTIL_FakeClientCommand(edict_t *pEdict, const char *cmd, const char *arg1, const char *arg2, bool fwd) { if (!cmd) return; // no command // store command g_fakecmd.argv[0] = cmd; // if only arg2 is passed, swap the arguments if (!arg1 && arg2) { arg1 = arg2; arg2 = NULL; } // store arguments if (arg2) { // both arguments passed g_fakecmd.argc = 3; // 2 arguments + 1 command // store arguments g_fakecmd.argv[1] = arg1; g_fakecmd.argv[2] = arg2; // build argument line ke::SafeSprintf(g_fakecmd.args, sizeof(g_fakecmd.args), "%s %s", arg1, arg2); } else if (arg1) { // only one argument passed g_fakecmd.argc = 2; // 1 argument + 1 command // store argument g_fakecmd.argv[1] = arg1; // build argument line ke::SafeSprintf(g_fakecmd.args, sizeof(g_fakecmd.args), "%s", arg1); } else g_fakecmd.argc = 1; // no argmuents -> only one command /* Notify plugins about this command */ if (fwd) { /* Set flag so read_argc/v/s functions will give proper value */ g_fakecmd.notify = true; if (executeForwards(FF_ClientCommand, static_cast<cell>(GET_PLAYER_POINTER(pEdict)->index)) > 0) { g_fakecmd.notify = false; return; } /* check for command and if needed also for first argument and call proper function */ CmdMngr::iterator aa = g_commands.clcmdprefixbegin(cmd); if (!aa) { aa = g_commands.clcmdbegin(); } while (aa) { if ((*aa).matchCommandLine(cmd, arg1) && (*aa).getPlugin()->isExecutable((*aa).getFunction())) { if (executeForwards((*aa).getFunction(), static_cast<cell>(GET_PLAYER_POINTER(pEdict)->index)), static_cast<cell>((*aa).getFlags()), static_cast<cell>((*aa).getId()) > 0) { g_fakecmd.notify = false; return; } } ++aa; } /* Unset flag */ g_fakecmd.notify = false; } // set the global "fake" flag so the Cmd_Arg* functions will be superceded g_fakecmd.fake = true; // tell the GameDLL that the client sent a command MDLL_ClientCommand(pEdict); // unset the global "fake" flag g_fakecmd.fake = false; }