Skip to content

Commit

Permalink
cmd: fixed nested commands offset after command execution
Browse files Browse the repository at this point in the history
cmd: fixed handling of truncated command buffer leftover
cmd: handle 'wait' command(s) much more correctly and made its timing really 1-frame-precise

Merge of ec-/Quake3e@51b6ae4
  • Loading branch information
ensiform committed Mar 7, 2024
1 parent ae35f72 commit 8a608f6
Show file tree
Hide file tree
Showing 4 changed files with 105 additions and 46 deletions.
12 changes: 5 additions & 7 deletions src/client/cl_cgame.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,17 +36,15 @@ extern void startCamera( int camNum, int time );
extern qboolean getCameraInfo( int camNum, int time, vec3_t *origin, vec3_t *angles, float *fov );
#endif

static int nestedCmdOffset; // nested command buffer offset

static void CL_Callvote_f( void ) {
CL_ForwardCommandToServer( Cmd_Cmd() );
}


static void CL_CompleteCallvote( char *args, int argNum ) {
static void CL_CompleteCallvote( const char *args, int argNum ) {
if( argNum >= 2 )
{
char *p;
const char *p;
if ( argNum == 3 && !Q_stricmp( Cmd_Argv( 1 ), "map" ) ) {
if ( cl_connectedToPureServer ) {
Field_CompleteFilename( "maps", "bsp", qtrue, FS_MATCH_PK3s | FS_MATCH_STICK );
Expand Down Expand Up @@ -737,7 +735,7 @@ static intptr_t CL_CgameSystemCalls( intptr_t *args ) {
case CG_SENDCONSOLECOMMAND:
{
const char *cmd = (const char *)VMA(1);
nestedCmdOffset = Cbuf_Add( cmd, nestedCmdOffset );
Cbuf_NestedAdd( cmd );
return 0;
}
case CG_ADDCOMMAND:
Expand Down Expand Up @@ -1321,7 +1319,7 @@ void CL_InitCGame( void ) {
const char *mapname;
int t1, t2;

nestedCmdOffset = 0;
Cbuf_NestedReset();

t1 = Sys_Milliseconds();

Expand Down Expand Up @@ -1402,7 +1400,7 @@ qboolean CL_GameCommand( void ) {

bRes = (qboolean)VM_Call( cgvm, 0, CG_CONSOLE_COMMAND );

nestedCmdOffset = 0;
Cbuf_NestedReset();

return bRes;
}
Expand Down
124 changes: 88 additions & 36 deletions src/qcommon/cmd.c
Original file line number Diff line number Diff line change
Expand Up @@ -108,23 +108,47 @@ void Cbuf_AddText( const char *text ) {
}


static int nestedCmdOffset;

void Cbuf_NestedReset( void ) {
nestedCmdOffset = 0;
}

/*
============
Cbuf_Add
Cbuf_NestedAdd
// Adds command text at the specified position of the buffer, adds \n when needed
============
*/
int Cbuf_Add( const char *text, int pos ) {
void Cbuf_NestedAdd( const char *text ) {

int len = (int)strlen( text );
int pos = nestedCmdOffset;
qboolean separate = qfalse;
int i;

if ( len == 0 ) {
return cmd_text.cursize;
if ( len <= 0 ) {
nestedCmdOffset = cmd_text.cursize;
return;
}

#if 0
if ( cmd_text.cursize > 0 ) {
const int c = cmd_text.data[cmd_text.cursize - 1];
// insert separator for already existing command(s)
if ( c != '\n' && c != ';' && text[0] != '\n' && text[0] != ';' ) {
if ( cmd_text.cursize < cmd_text.maxsize ) {
cmd_text.data[cmd_text.cursize++] = ';';
} else {
Com_Printf( S_COLOR_YELLOW "%s(%i) overflowed\n", __func__, pos );
nestedCmdOffset = cmd_text.cursize;
return;
}
}
}
#endif

if ( pos > cmd_text.cursize || pos < 0 ) {
// insert at the text end
pos = cmd_text.cursize;
Expand All @@ -139,7 +163,8 @@ int Cbuf_Add( const char *text, int pos ) {

if ( len + cmd_text.cursize > cmd_text.maxsize ) {
Com_Printf( S_COLOR_YELLOW "%s(%i) overflowed\n", __func__, pos );
return cmd_text.cursize;
nestedCmdOffset = cmd_text.cursize;
return;
}

// move the existing command text
Expand All @@ -158,7 +183,7 @@ int Cbuf_Add( const char *text, int pos ) {

cmd_text.cursize += len;

return pos + len;
nestedCmdOffset = cmd_text.cursize;
}


Expand Down Expand Up @@ -206,19 +231,20 @@ void Cbuf_ExecuteText( cbufExec_t exec_when, const char *text )
switch (exec_when)
{
case EXEC_NOW:
cmd_wait = 0; // discard any pending waiting
if ( text && text[0] != '\0' ) {
Com_DPrintf(S_COLOR_YELLOW "EXEC_NOW %s\n", text);
Cmd_ExecuteString (text);
Cmd_ExecuteString( text );
} else {
Cbuf_Execute();
Com_DPrintf(S_COLOR_YELLOW "EXEC_NOW %s\n", cmd_text.data);
Com_DPrintf( S_COLOR_YELLOW "EXEC_NOW %s\n", cmd_text.data );
}
break;
case EXEC_INSERT:
Cbuf_InsertText (text);
Cbuf_InsertText( text );
break;
case EXEC_APPEND:
Cbuf_AddText (text);
Cbuf_AddText( text );
break;
default:
Com_Error (ERR_FATAL, "Cbuf_ExecuteText: bad exec_when");
Expand All @@ -233,25 +259,23 @@ Cbuf_Execute
*/
void Cbuf_Execute( void )
{
int i;
char *text;
char line[MAX_CMD_LINE];
int quotes;
char line[MAX_CMD_LINE], *text;
int i, n, quotes;

if ( cmd_wait > 0 ) {
// delay command buffer execution
cmd_wait--;
return;
}

// This will keep // style comments all on one line by not breaking on
// a semicolon. It will keep /* ... */ style comments all on one line by not
// breaking it for semicolon or newline.
qboolean in_star_comment = qfalse;
qboolean in_slash_comment = qfalse;

while ( cmd_text.cursize > 0 )
{
if ( cmd_wait > 0 ) {
// skip out while text still remains in buffer, leaving it
// for next frame
cmd_wait--;
break;
}

// find a \n or ; line break or comment: // or /* */
text = (char *)cmd_text.data;

Expand Down Expand Up @@ -285,36 +309,64 @@ void Cbuf_Execute( void )
}
}

if ( i >= (MAX_CMD_LINE - 1) )
i = MAX_CMD_LINE - 1;
// copy up to (MAX_CMD_LINE - 1) chars but keep buffer position intact to prevent parsing truncated leftover
if ( i > (MAX_CMD_LINE - 1) )
n = MAX_CMD_LINE - 1;
else
n = i;

Com_Memcpy( line, text, i );
line[i] = '\0';
Com_Memcpy( line, text, n );
line[n] = '\0';

// delete the text from the command buffer and move remaining commands down
// this is necessary because commands (exec) can insert data at the
// beginning of the text buffer

if ( i == cmd_text.cursize )
cmd_text.cursize = 0;
else
{
i++;
cmd_text.cursize -= i;
// skip all repeating newlines/semicolons
while ( ( text[i] == '\n' || text[i] == '\r' || text[i] == ';' ) && cmd_text.cursize > 0 ) {
cmd_text.cursize--;
i++;
if ( i == cmd_text.cursize ) {
//cmd_text.cursize = 0;
} else {
++i;
// skip all repeating newlines/semicolons/whitespaces
while ( i < cmd_text.cursize && (text[i] == '\n' || text[i] == '\r' || text[i] == ';' || ( text[i] != '\0' && text[i] <= ' ' ) ) ) {
++i;
}
}

cmd_text.cursize -= i;

if ( cmd_text.cursize ) {
memmove( text, text + i, cmd_text.cursize );
}

if ( nestedCmdOffset > 0 ) {
nestedCmdOffset -= i;
if ( nestedCmdOffset < 0 ) {
nestedCmdOffset = 0;
}
memmove( text, text+i, cmd_text.cursize );
}

// execute the command line
Cmd_ExecuteString( line );

// break on wait command
if ( cmd_wait > 0 ) {
break;
}
}
}


/*
============
Cbuf_Wait
============
*/
qboolean Cbuf_Wait( void )
{
return (cmd_wait > 0) ? qtrue : qfalse;
}


/*
==============================================================================
Expand Down
5 changes: 4 additions & 1 deletion src/qcommon/common.c
Original file line number Diff line number Diff line change
Expand Up @@ -4633,7 +4633,10 @@ void Com_Frame( qboolean noDelay ) {
timeBeforeEvents = Sys_Milliseconds();
}
Com_EventLoop();
Cbuf_Execute();

if ( !Cbuf_Wait() ) {
Cbuf_Execute();
}

//
// client side
Expand Down
10 changes: 8 additions & 2 deletions src/qcommon/qcommon.h
Original file line number Diff line number Diff line change
Expand Up @@ -476,8 +476,11 @@ void Cbuf_Init( void );
void Cbuf_AddText( const char *text );
// Adds command text at the end of the buffer, does NOT add a final \n

int Cbuf_Add( const char *text, int pos );
// Adds command text at the specified position of the buffer, adds \n when needed
void Cbuf_NestedAdd( const char *text );
// Adds nested command text at the specified position of the buffer, adds \n when needed

void Cbuf_NestedReset( void );
// Resets nested cmd offset

void Cbuf_InsertText( const char *text );
// Adds command text at the beginning of the buffer, add \n
Expand All @@ -491,6 +494,9 @@ void Cbuf_Execute( void );
// Normally called once per frame, but may be explicitly invoked.
// Do not call inside a command function, or current args will be destroyed.

qboolean Cbuf_Wait( void );
// Checks if wait command timeout remaining

//===========================================================================

/*
Expand Down

0 comments on commit 8a608f6

Please sign in to comment.