X-Git-Url: https://git.xonotic.org/?a=blobdiff_plain;f=cmd.c;h=abc512eef3a4e547ba72e24e07e1aaad43cbe961;hb=7dc98886864ae8cb34357761dcebed90997fdfef;hp=903b923b2fb8f3c1d66fded30c658d0590ef8b69;hpb=ea4bbbacf1001652d8f0bc907855aff6f2023dc3;p=xonotic%2Fdarkplaces.git diff --git a/cmd.c b/cmd.c index 903b923b..abc512ee 100644 --- a/cmd.c +++ b/cmd.c @@ -22,8 +22,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "quakedef.h" #include "thread.h" -cmd_state_t *cmd_client; -cmd_state_t *cmd_server; +cmd_state_t *cmd_local; cmd_state_t *cmd_serverfromclient; cmd_userdefined_t cmd_userdefined_all; @@ -87,12 +86,8 @@ static void Cmd_Defer_f (cmd_state_t *cmd) Con_Printf("No commands are pending.\n"); else { - llist_t *pos; - List_For_Each(pos, &cbuf->deferred) - { - current = List_Entry(*pos, cmd_input_t, list); + List_For_Each_Entry(current, &cbuf->deferred, list) Con_Printf("-> In %9.2f: %s\n", current->delay, current->text); - } } } else if(Cmd_Argc(cmd) == 2 && !strcasecmp("clear", Cmd_Argv(cmd, 1))) @@ -184,7 +179,7 @@ static cmd_input_t *Cbuf_LinkGet(cmd_buf_t *cbuf, cmd_input_t *existing) ret = existing; else if(!List_Is_Empty(&cbuf->free)) { - ret = List_Entry(*cbuf->free.next, cmd_input_t, list); + ret = List_Entry(cbuf->free.next, cmd_input_t, list); ret->length = 0; ret->pending = false; } @@ -199,6 +194,11 @@ static cmd_input_t *Cmd_AllocInputNode(void) return node; } + +// Cloudwalk FIXME: The entire design of this thing is overly complicated. +// We could very much safely have one input node per line whether or not +// the command was terminated. We don't need to split up input nodes per command +// executed. static size_t Cmd_ParseInput (cmd_input_t **output, char **input) { size_t pos, cmdsize = 0, start = 0; @@ -285,6 +285,7 @@ static size_t Cmd_ParseInput (cmd_input_t **output, char **input) if(!*output) *output = Cmd_AllocInputNode(); + // Append, since this input line hasn't closed yet. if((*output)->pending) offset = (*output)->length; @@ -297,6 +298,11 @@ static size_t Cmd_ParseInput (cmd_input_t **output, char **input) } strlcpy(&(*output)->text[offset], &(*input)[start], cmdsize + 1); + + /* + * If we were still looking ahead by the time we broke from the loop, the command input + * hasn't terminated yet and we're still expecting more, so keep this node open for appending later. + */ (*output)->pending = !lookahead; } @@ -317,12 +323,14 @@ static void Cbuf_LinkCreate(cmd_state_t *cmd, llist_t *head, cmd_input_t *existi // Slide the pointer down until we reach the end while(*in) { + // Check if the current node is still accepting input (input line hasn't terminated) current = Cbuf_LinkGet(cbuf, existing); newsize = Cmd_ParseInput(¤t, &in); // Valid command if(newsize) { + // current will match existing if the input line hasn't terminated yet if(current != existing) { current->source = cmd; @@ -358,7 +366,7 @@ void Cbuf_AddText (cmd_state_t *cmd, const char *text) Con_Print("Cbuf_AddText: overflow\n"); else { - Cbuf_LinkCreate(cmd, &llist, (List_Is_Empty(&cbuf->start) ? NULL : List_Entry(*cbuf->start.prev, cmd_input_t, list)), text); + Cbuf_LinkCreate(cmd, &llist, (List_Is_Empty(&cbuf->start) ? NULL : List_Entry(cbuf->start.prev, cmd_input_t, list)), text); if(!List_Is_Empty(&llist)) List_Splice_Tail(&llist, &cbuf->start); } @@ -386,7 +394,7 @@ void Cbuf_InsertText (cmd_state_t *cmd, const char *text) Con_Print("Cbuf_InsertText: overflow\n"); else { - Cbuf_LinkCreate(cmd, &llist, List_Entry(*cbuf->start.next, cmd_input_t, list), text); + Cbuf_LinkCreate(cmd, &llist, List_Entry(cbuf->start.next, cmd_input_t, list), text); if(!List_Is_Empty(&llist)) List_Splice(&llist, &cbuf->start); } @@ -401,7 +409,6 @@ Cbuf_Execute_Deferred --blub */ static void Cbuf_Execute_Deferred (cmd_buf_t *cbuf) { - llist_t *pos; cmd_input_t *current; double eat; @@ -412,14 +419,13 @@ static void Cbuf_Execute_Deferred (cmd_buf_t *cbuf) return; cbuf->deferred_oldtime = host.realtime; - List_For_Each(pos, &cbuf->deferred) + List_For_Each_Entry(current, &cbuf->deferred, list) { - current = List_Entry(*pos, cmd_input_t, list); current->delay -= eat; if(current->delay <= 0) { cbuf->size += current->length; - List_Move(pos, &cbuf->start); + List_Move(¤t->list, &cbuf->start); // We must return and come back next frame or the engine will freeze. Fragile... like glass :3 return; } @@ -448,7 +454,7 @@ void Cbuf_Execute (cmd_buf_t *cbuf) * commands down. This is necessary because commands (exec, alias) * can insert data at the beginning of the text buffer */ - current = List_Entry(*cbuf->start.next, cmd_input_t, list); + current = List_Entry(cbuf->start.next, cmd_input_t, list); // Recycle memory so using WASD doesn't cause a malloc and free List_Move_Tail(¤t->list, &cbuf->free); @@ -503,12 +509,7 @@ static void Cbuf_Frame_Input(void) char *line; while ((line = Sys_ConsoleInput())) - { - if (cls.state == ca_dedicated) - Cbuf_AddText(cmd_server, line); - else - Cbuf_AddText(cmd_client, line); - } + Cbuf_AddText(cmd_local, line); } void Cbuf_Frame(cmd_buf_t *cbuf) @@ -1587,12 +1588,12 @@ static void Cmd_Apropos_f(cmd_state_t *cmd) Cvar_PrintHelp(cvar, cvar->name, true); count++; } - for (int i = 0; i < cvar->aliasindex; i++) + for (char **cvar_alias = cvar->aliases; cvar_alias && *cvar_alias; cvar_alias++) { - if (matchpattern_with_separator(cvar->aliases[i], partial, true, "", false)) + if (matchpattern_with_separator(*cvar_alias, partial, true, "", false)) { Con_Printf ("cvar "); - Cvar_PrintHelp(cvar, cvar->aliases[i], true); + Cvar_PrintHelp(cvar, *cvar_alias, true); count++; } } @@ -1662,24 +1663,19 @@ void Cmd_Init(void) cbuf->free.prev = cbuf->free.next = &(cbuf->free); // FIXME: Get rid of cmd_iter_all eventually. This is just a hack to reduce the amount of work to make the interpreters dynamic. - cmd_iter_all = (cmd_iter_t *)Mem_Alloc(tempmempool, sizeof(cmd_iter_t) * 4); - - // client console can see server cvars because the user may start a server - cmd_iter_all[0].cmd = cmd_client = Cmd_AddInterpreter(cbuf, &cvars_all, CF_CLIENT | CF_SERVER, CF_CLIENT | CF_CLIENT_FROM_SERVER, &cmd_userdefined_all); - cmd_client->Handle = Cmd_CL_Callback; - cmd_client->NotFound = NULL; + cmd_iter_all = (cmd_iter_t *)Mem_Alloc(tempmempool, sizeof(cmd_iter_t) * 3); - // dedicated server console can only see server cvars, there is no client - cmd_iter_all[1].cmd = cmd_server = Cmd_AddInterpreter(cbuf, &cvars_all, CF_SERVER, CF_SERVER, &cmd_userdefined_all); - cmd_server->Handle = Cmd_SV_Callback; - cmd_server->NotFound = NULL; + // local console + cmd_iter_all[0].cmd = cmd_local = Cmd_AddInterpreter(cbuf, &cvars_all, CF_CLIENT | CF_SERVER, CF_CLIENT | CF_CLIENT_FROM_SERVER | CF_SERVER_FROM_CLIENT, &cmd_userdefined_all); + cmd_local->Handle = Cmd_CL_Callback; + cmd_local->NotFound = NULL; // server commands received from clients have no reason to access cvars, cvar expansion seems perilous. - cmd_iter_all[2].cmd = cmd_serverfromclient = Cmd_AddInterpreter(cbuf, &cvars_null, 0, CF_SERVER_FROM_CLIENT | CF_USERINFO, &cmd_userdefined_null); + cmd_iter_all[1].cmd = cmd_serverfromclient = Cmd_AddInterpreter(cbuf, &cvars_null, 0, CF_SERVER_FROM_CLIENT | CF_USERINFO, &cmd_userdefined_null); cmd_serverfromclient->Handle = Cmd_SV_Callback; cmd_serverfromclient->NotFound = Cmd_SV_NotFound; - cmd_iter_all[3].cmd = NULL; + cmd_iter_all[2].cmd = NULL; // // register our commands // @@ -1850,7 +1846,7 @@ void Cmd_AddCommand(int flags, const char *cmd_name, xcommand_t function, const cmd_state_t *cmd; int i; - for (i = 0; i < 3; i++) + for (i = 0; i < 2; i++) { cmd = cmd_iter_all[i].cmd; if (flags & cmd->cmd_flags) @@ -2167,6 +2163,18 @@ void Cmd_ClearCSQCCommands (cmd_state_t *cmd) extern cvar_t sv_cheats; +/* + * Cloudwalk FIXME: This idea sounded great in my head but... + * How do we handle commands that can be received by the client, + * but which the server can also execute locally? + * + * If we create a callback where the engine will forward to server + * but try to execute the command locally if it's dedicated, + * we're back to intermixing client and server code which I'm + * trying to avoid. There's no other way I can think of to + * implement that behavior that doesn't involve an #ifdef, or + * making a mess of hooks. + */ qbool Cmd_Callback(cmd_state_t *cmd, cmd_function_t *func, const char *text, cmd_source_t src) { if (func->function) @@ -2178,15 +2186,27 @@ qbool Cmd_Callback(cmd_state_t *cmd, cmd_function_t *func, const char *text, cmd qbool Cmd_CL_Callback(cmd_state_t *cmd, cmd_function_t *func, const char *text, cmd_source_t src) { - if(func->qcfunc && (func->flags & CF_CLIENT)) - return CL_VM_ConsoleCommand(text); - else if ((func->flags & CF_SERVER_FROM_CLIENT) && src == src_local) + // TODO: Assign these functions to QC commands directly? + if(func->qcfunc) { - CL_ForwardToServer_f(cmd); - return true; + if(((func->flags & CF_CLIENT) && CL_VM_ConsoleCommand(text)) || + ((func->flags & CF_SERVER) && SV_VM_ConsoleCommand(text))) + return true; } - else - return Cmd_Callback(cmd, func, text, src); + if (func->flags & CF_SERVER_FROM_CLIENT) + { + if(host_isclient.integer) + { + CL_ForwardToServer_f(cmd); + return true; + } + else if(!(func->flags & CF_SERVER)) + { + Con_Printf("Cannot execute client commands from a dedicated server console.\n"); + return true; + } + } + return Cmd_Callback(cmd, func, text, src); } qbool Cmd_SV_Callback(cmd_state_t *cmd, cmd_function_t *func, const char *text, cmd_source_t src) @@ -2201,8 +2221,7 @@ qbool Cmd_SV_Callback(cmd_state_t *cmd, cmd_function_t *func, const char *text, func->function(cmd); return true; } - else - return Cmd_Callback(cmd, func, text, src); + return false; } qbool Cmd_SV_NotFound(cmd_state_t *cmd, cmd_function_t *func, const char *text, cmd_source_t src) @@ -2391,3 +2410,7 @@ void Cmd_RestoreInitState(void) } Cvar_RestoreInitState(&cvars_all); } + +void Cmd_NoOperation_f(cmd_state_t *cmd) +{ +}