#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;
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, cmd_input_t, list)
Con_Printf("-> In %9.2f: %s\n", current->delay, current->text);
- }
}
}
else if(Cmd_Argc(cmd) == 2 && !strcasecmp("clear", Cmd_Argv(cmd, 1)))
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;
}
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;
if(!*output)
*output = Cmd_AllocInputNode();
+ // Append, since this input line hasn't closed yet.
if((*output)->pending)
offset = (*output)->length;
}
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;
}
// 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;
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);
}
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_Is_Empty(&cbuf->start) ? NULL : List_Entry(cbuf->start.next, cmd_input_t, list)), text);
if(!List_Is_Empty(&llist))
List_Splice(&llist, &cbuf->start);
}
*/
static void Cbuf_Execute_Deferred (cmd_buf_t *cbuf)
{
- llist_t *pos;
cmd_input_t *current;
double eat;
return;
cbuf->deferred_oldtime = host.realtime;
- List_For_Each(pos, &cbuf->deferred)
+ List_For_Each_Entry(current, &cbuf->deferred, cmd_input_t, 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;
}
* 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);
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)
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++;
}
}
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
//
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)
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)
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)
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)
}
Cvar_RestoreInitState(&cvars_all);
}
+
+void Cmd_NoOperation_f(cmd_state_t *cmd)
+{
+}