summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrey Nazarov <skuller@skuller.net>2008-02-28 12:09:10 +0000
committerAndrey Nazarov <skuller@skuller.net>2008-02-28 12:09:10 +0000
commitbf6d45c620f098c84d602e9347bc7cf457c38b5a (patch)
treeec075676ff09467ea910c51fb45fb37185a1ddf3
parent4034314816f7ec9e26c9b9bfc2630c8ca0a24874 (diff)
Do not spam dedicated server console with heartbeats.
Added autocompletion of options for some commands. Made logfile_prefix not empty by default. Re-enabled `anti-kick' exploit fix.
-rw-r--r--source/cl_console.c9
-rw-r--r--source/cl_demo.c9
-rw-r--r--source/cl_draw.c2
-rw-r--r--source/cl_keys.c20
-rw-r--r--source/cl_local.h2
-rw-r--r--source/cl_main.c139
-rw-r--r--source/cmd.c159
-rw-r--r--source/com_local.h19
-rw-r--r--source/com_public.h6
-rw-r--r--source/common.c32
-rw-r--r--source/cvar.c73
-rw-r--r--source/files.c6
-rw-r--r--source/gl_state.c1
-rw-r--r--source/mvd_client.c59
-rw-r--r--source/mvd_local.h2
-rw-r--r--source/mvd_parse.c4
-rw-r--r--source/prompt.c80
-rw-r--r--source/q_shared.h2
-rw-r--r--source/snd_main.c7
-rw-r--r--source/sv_ccmds.c12
-rw-r--r--source/sv_game.c18
-rw-r--r--source/sv_local.h12
-rw-r--r--source/sv_main.c25
-rw-r--r--source/sv_send.c4
-rw-r--r--source/sv_user.c94
25 files changed, 480 insertions, 316 deletions
diff --git a/source/cl_console.c b/source/cl_console.c
index e07579e..3640a7f 100644
--- a/source/cl_console.c
+++ b/source/cl_console.c
@@ -182,8 +182,11 @@ static void Con_Clear_f( void ) {
con.display = con.current;
}
-static const char *Con_Dump_g( const char *partial, int state ) {
- return Com_FileNameGenerator( "", ".txt", partial, qtrue, state );
+static const char *Con_Dump_g( const char *partial, int argnum, int state ) {
+ if( argnum == 1 ) {
+ return Com_FileNameGenerator( "", ".txt", partial, qtrue, state );
+ }
+ return NULL;
}
/*
@@ -362,7 +365,7 @@ static const cmdreg_t c_console[] = {
{ "togglechat2", Con_ToggleChat2_f },
{ "messagemode", Con_MessageMode_f },
{ "messagemode2", Con_MessageMode2_f },
- { "remotemode", Con_RemoteMode_f, CL_Connect_g },
+ { "remotemode", Con_RemoteMode_f, CL_Server_g },
{ "clear", Con_Clear_f },
{ "clearnotify", Con_ClearNotify_f },
{ "condump", Con_Dump_f, Con_Dump_g },
diff --git a/source/cl_demo.c b/source/cl_demo.c
index dfaf463..a505058 100644
--- a/source/cl_demo.c
+++ b/source/cl_demo.c
@@ -646,9 +646,12 @@ static void CL_PlayDemo_f( void ) {
}
}
-static const char *CL_PlayDemo_g( const char *partial, int state ) {
- return Com_FileNameGeneratorByFilter( "demos", "*.dm2;*.dm2.gz",
- partial, qfalse, state );
+static const char *CL_PlayDemo_g( const char *partial, int argnum, int state ) {
+ if( argnum == 1 ) {
+ return Com_FileNameGeneratorByFilter( "demos", "*.dm2;*.dm2.gz",
+ partial, qfalse, state );
+ }
+ return NULL;
}
static void CL_ParseInfoString( demoInfo_t *info, int clientNum, int index, const char *string ) {
diff --git a/source/cl_draw.c b/source/cl_draw.c
index eeec143..a5ec50e 100644
--- a/source/cl_draw.c
+++ b/source/cl_draw.c
@@ -822,7 +822,7 @@ cmdreg_t scr_drawcmds[] = {
#if USE_CHATHUD
{ "clearchat", SCR_ClearChatHUD_f },
#endif
- { "draw", SCR_Draw_f, Cvar_Generator },
+ { "draw", SCR_Draw_f, Cvar_Set_g },
{ "undraw", SCR_UnDraw_f/*, SCR_DrawStringGenerator*/ },
{ "scoreshot", SCR_ScoreShot_f },
{ NULL }
diff --git a/source/cl_keys.c b/source/cl_keys.c
index b415ada..116c2f0 100644
--- a/source/cl_keys.c
+++ b/source/cl_keys.c
@@ -375,7 +375,7 @@ void Key_SetBinding( int keynum, const char *binding ) {
keybindings[keynum] = Z_CopyString( binding );
}
-static const char *Key_Name_g( const char *partial, int state ) {
+static const char *Key_NameGenerator( const char *partial, int state ) {
static int length;
static keyname_t *k;
const char *name;
@@ -396,6 +396,20 @@ static const char *Key_Name_g( const char *partial, int state ) {
return NULL;
}
+static const char *Key_Bind_g( const char *partial, int argnum, int state ) {
+ if( argnum == 1 ) {
+ return Key_NameGenerator( partial, state );
+ }
+ return Prompt_Completer( partial, 2, argnum, state );
+}
+
+static const char *Key_Unbind_g( const char *partial, int argnum, int state ) {
+ if( argnum == 1 ) {
+ return Key_NameGenerator( partial, state );
+ }
+ return NULL;
+}
+
/*
===================
Key_Unbind_f
@@ -522,8 +536,8 @@ void Key_FillAPI( keyAPI_t *api ) {
}
static cmdreg_t c_keys[] = {
- { "bind", Key_Bind_f, Key_Name_g, Cmd_Mixed_g },
- { "unbind", Key_Unbind_f, Key_Name_g },
+ { "bind", Key_Bind_f, Key_Bind_g },
+ { "unbind", Key_Unbind_f, Key_Unbind_g },
{ "unbindall", Key_Unbindall_f },
{ "bindlist", Key_Bindlist_f },
diff --git a/source/cl_local.h b/source/cl_local.h
index bebd898..a03112f 100644
--- a/source/cl_local.h
+++ b/source/cl_local.h
@@ -504,7 +504,7 @@ void CL_ClientCommand( const char *string );
void CL_UpdateLocalFovSetting( void );
void CL_FillAPI( clientAPI_t *api );
void CL_SendRcon( const netadr_t *adr, const char *pass, const char *cmd );
-const char *CL_Connect_g( const char *partial, int state );
+const char *CL_Server_g( const char *partial, int argnum, int state );
//
// cl_input
diff --git a/source/cl_main.c b/source/cl_main.c
index 0df8e61..c65989c 100644
--- a/source/cl_main.c
+++ b/source/cl_main.c
@@ -415,6 +415,24 @@ static void CL_CheckForResend( void ) {
}
}
+static const char *CL_Connect_g( const char *partial, int argnum, int state ) {
+ static int protocol;
+
+ if( !state ) {
+ protocol = 34;
+ }
+
+ if( argnum == 1 ) {
+ return Com_AddressGenerator( partial, state );
+ } else if( argnum == 2 ) {
+ if( !partial[0] || ( partial[0] == '3' && !partial[1] ) ) {
+ while( protocol <= 36 ) {
+ return va( "%d", protocol++ );
+ }
+ }
+ }
+ return NULL;
+}
/*
================
@@ -430,7 +448,7 @@ static void CL_Connect_f( void ) {
if( argc < 2 ) {
usage:
- Com_Printf( "Usage: connect <server> [34|35|36]\n" );
+ Com_Printf( "Usage: %s <server> [34|35|36]\n", Cmd_Argv( 0 ) );
return;
}
@@ -510,35 +528,6 @@ static void CL_PassiveConnect_f( void ) {
NET_AdrToString( &address ) );
}
-const char *CL_Connect_g( const char *partial, int state ) {
- static int length;
- static int index;
- cvar_t *var;
- char buffer[MAX_QPATH];
-
- if( !state ) {
- length = strlen( partial );
- index = 0;
- }
-
- while( index < 1024 ) {
- Com_sprintf( buffer, sizeof( buffer ), "adr%i", index );
- index++;
- var = Cvar_FindVar( buffer );
- if( !var ) {
- break;
- }
- if( !var->string[0] ) {
- continue;
- }
- if( !strncmp( partial, var->string, length ) ) {
- return var->string;
- }
- }
-
- return NULL;
-}
-
void CL_SendRcon( const netadr_t *adr, const char *pass, const char *cmd ) {
neterr_t ret;
@@ -595,6 +584,10 @@ static void CL_Rcon_f( void ) {
CL_SendRcon( &address, rcon_password->string, Cmd_RawArgs() );
}
+const char *CL_Rcon_g( const char *partial, int argnum, int state ) {
+ return Prompt_Completer( partial, 1, argnum, state );
+}
+
/*
=====================
@@ -711,6 +704,13 @@ static void CL_Disconnect_f( void ) {
}
+const char *CL_Server_g( const char *partial, int argnum, int state ) {
+ if( argnum == 1 ) {
+ return Com_AddressGenerator( partial, state );
+ }
+ return NULL;
+}
+
/*
================
CL_ServerStatus_f
@@ -1183,6 +1183,28 @@ static void CL_Skins_f ( void ) {
}
}
+const char *CL_NickGenerator( const char *partial, int state ) {
+ static int length;
+ static int i;
+ clientinfo_t *ci;
+
+ if( !state ) {
+ if( cls.state < ca_loading ) {
+ return NULL;
+ }
+ length = strlen( partial );
+ i = 0;
+ }
+ while( i < MAX_CLIENTS ) {
+ ci = &cl.clientinfo[i++];
+ if( ci->name[0] && !strncmp( ci->name, partial, length ) ) {
+ return ci->name;
+ }
+ }
+ return NULL;
+}
+
+
/*
=================
CL_ConnectionlessPacket
@@ -1990,27 +2012,36 @@ static void CL_DumpLayout_f( void ) {
Com_Printf( "Dumped layout program to %s.\n", buffer );
}
+static const cmd_option_t o_writeconfig[] = {
+ { "a", "aliases", "write aliases" },
+ { "b", "bindings", "write bindings" },
+ { "c", "cvars", "write archived cvars" },
+ { "h", "help", "display this help message" },
+ { "m", "modified", "write modified cvars" },
+ { NULL }
+};
+
+static const char *CL_ConfigGenerator( const char *partial, int state ) {
+ return Com_FileNameGeneratorByFilter( "", "*.cfg", partial, qtrue, state );
+}
+
+static const char *CL_WriteConfig_g( const char *partial, int argnum, int state ) {
+ return Cmd_Completer( o_writeconfig, partial, argnum, state, CL_ConfigGenerator );
+}
+
/*
===============
CL_WriteConfig_f
===============
*/
static void CL_WriteConfig_f( void ) {
- static const cmd_option_t options[] = {
- { "a", "aliases", "write aliases" },
- { "b", "bindings", "write bindings" },
- { "c", "cvars", "write archived cvars" },
- { "h", "help", "display this help message" },
- { "m", "modified", "write modified cvars" },
- { NULL }
- };
char buffer[MAX_QPATH];
qboolean aliases = qfalse, bindings = qfalse, modified = qfalse;
int mask = 0;
fileHandle_t f;
int c;
- while( ( c = Cmd_ParseOptions( options ) ) != -1 ) {
+ while( ( c = Cmd_ParseOptions( o_writeconfig ) ) != -1 ) {
switch( c ) {
case 'a':
aliases = qtrue;
@@ -2022,9 +2053,9 @@ static void CL_WriteConfig_f( void ) {
mask |= CVAR_ARCHIVE;
break;
case 'h':
- Cmd_PrintUsage( options, "<filename>" );
+ Cmd_PrintUsage( o_writeconfig, "<filename>" );
Com_Printf( "Save current configuration into file.\n" );
- Cmd_PrintHelp( options );
+ Cmd_PrintHelp( o_writeconfig );
return;
case 'm':
modified = qtrue;
@@ -2075,6 +2106,9 @@ static void CL_WriteConfig_f( void ) {
Com_Printf( "Wrote %s.\n", buffer );
}
+static const char *CL_Say_g( const char *partial, int argnum, int state ) {
+ return CL_NickGenerator( partial, state );
+}
static int CL_Mapname_m( char *buffer, int size ) {
if( !cl.mapname[0] ) {
@@ -2309,14 +2343,14 @@ static const cmdreg_t c_client[] = {
{ "connect", CL_Connect_f, CL_Connect_g },
{ "passive", CL_PassiveConnect_f },
{ "reconnect", CL_Reconnect_f },
- { "rcon", CL_Rcon_f, Cmd_Command_g },
+ { "rcon", CL_Rcon_f, CL_Rcon_g },
{ "precache", CL_Precache_f },
{ "download", CL_Download_f },
- { "serverstatus", CL_ServerStatus_f, CL_Connect_g },
+ { "serverstatus", CL_ServerStatus_f, CL_Server_g },
{ "dumpclients", CL_DumpClients_f },
{ "dumpstatusbar", CL_DumpStatusbar_f },
{ "dumplayout", CL_DumpLayout_f },
- { "writeconfig", CL_WriteConfig_f, Cmd_Exec_g },
+ { "writeconfig", CL_WriteConfig_f, CL_WriteConfig_g },
{ "vid_restart", CL_RestartRefresh_f },
//
@@ -2325,11 +2359,14 @@ static const cmdreg_t c_client[] = {
// the only thing this does is allow command completion
// to work -- all unknown commands are automatically
// forwarded to the server
+ { "say", NULL, CL_Say_g },
+ { "say_team", NULL, CL_Say_g },
+
{ "wave" }, { "inven" }, { "kill" }, { "use" },
- { "drop" }, { "say" }, { "say_team" }, { "info" },
- { "prog" }, { "give" }, { "god" }, { "notarget" },
- { "noclip" }, { "invuse" }, { "invprev" }, { "invnext" },
- { "invdrop" }, { "weapnext" }, { "weapprev" },
+ { "drop" }, { "info" }, { "prog" },
+ { "give" }, { "god" }, { "notarget" }, { "noclip" },
+ { "invuse" }, { "invprev" }, { "invnext" }, { "invdrop" },
+ { "weapnext" }, { "weapprev" },
{ NULL }
};
@@ -2340,6 +2377,7 @@ CL_InitLocal
=================
*/
static void CL_InitLocal ( void ) {
+ cvar_t *var;
int i;
cls.state = ca_disconnected;
@@ -2356,7 +2394,8 @@ static void CL_InitLocal ( void ) {
Cmd_Register( c_client );
for ( i = 0 ; i < MAX_LOCAL_SERVERS ; i++ ) {
- Cvar_Get( va( "adr%i", i ), "", CVAR_ARCHIVE );
+ var = Cvar_Get( va( "adr%i", i ), "", CVAR_ARCHIVE );
+ var->generator = Com_AddressGenerator;
}
//
@@ -2386,7 +2425,7 @@ static void CL_InitLocal ( void ) {
rcon_password = Cvar_Get ( "rcon_password", "", CVAR_PRIVATE );
rcon_address = Cvar_Get ( "rcon_address", "", CVAR_PRIVATE );
- rcon_address->generator = CL_Connect_g;
+ rcon_address->generator = Com_AddressGenerator;
cl_thirdperson = Cvar_Get( "cl_thirdperson", "0", CVAR_CHEAT );
cl_thirdperson_angle = Cvar_Get( "cl_thirdperson_angle", "0", 0 );
diff --git a/source/cmd.c b/source/cmd.c
index 0977d28..71d4abe 100644
--- a/source/cmd.c
+++ b/source/cmd.c
@@ -255,6 +255,7 @@ char *Cmd_AliasCommand( const char *name ) {
void Cmd_AliasSet( const char *name, const char *cmd ) {
cmdalias_t *a;
unsigned hash;
+ int len;
// if the alias already exists, reuse it
a = Cmd_AliasFind( name );
@@ -264,8 +265,9 @@ void Cmd_AliasSet( const char *name, const char *cmd ) {
return;
}
- a = Cmd_Malloc( sizeof( cmdalias_t ) + strlen( name ) );
- strcpy( a->name, name );
+ len = strlen( name );
+ a = Cmd_Malloc( sizeof( cmdalias_t ) + len );
+ memcpy( a->name, name, len + 1 );
a->value = Cmd_CopyString( cmd );
List_Append( &cmd_alias, &a->listEntry );
@@ -287,10 +289,10 @@ void Cmd_Alias_f( void ) {
if( Cmd_Argc() < 2 ) {
if( LIST_EMPTY( &cmd_alias ) ) {
- Com_Printf( "No alias commands registered\n" );
+ Com_Printf( "No alias commands registered.\n" );
return;
}
- Com_Printf( "Current alias commands:\n" );
+ Com_Printf( "Registered alias commands:\n" );
LIST_FOR_EACH( cmdalias_t, a, &cmd_alias, listEntry ) {
Com_Printf( "\"%s\" = \"%s\"\n", a->name, a->value );
}
@@ -349,7 +351,7 @@ static void Cmd_UnAlias_f( void ) {
List_Init( &cmd_aliasHash[hash] );
}
List_Init( &cmd_alias );
- Com_Printf( "Removed all aliases\n" );
+ Com_Printf( "Removed all alias commands.\n" );
return;
default:
return;
@@ -366,7 +368,7 @@ static void Cmd_UnAlias_f( void ) {
s = Cmd_Argv( 1 );
a = Cmd_AliasFind( s );
if( !a ) {
- Com_Printf( "\"%s\" is undefined\n", s );
+ Com_Printf( "\"%s\" is undefined.\n", s );
return;
}
@@ -387,6 +389,26 @@ void Cmd_WriteAliases( fileHandle_t f ) {
}
#endif
+const char *Cmd_Alias_g( const char *partial, int argnum, int state ) {
+ switch( argnum ) {
+ case 0:
+ return NULL;
+ case 1:
+ return Cmd_AliasGenerator( partial, state );
+ case 2:
+ return Cmd_MixedGenerator( partial, state );
+ default:
+ return NULL;
+ }
+}
+
+const char *Cmd_UnAlias_g( const char *partial, int argnum, int state ) {
+ if( argnum == 1 ) {
+ return Cmd_AliasGenerator( partial, state );
+ }
+ return NULL;
+}
+
/*
=============================================================================
@@ -460,13 +482,13 @@ void Cmd_AddMacro( const char *name, xmacro_t function ) {
return;
}
- hash = Com_HashString( name, MACRO_HASH_SIZE );
-
macro = Cmd_Malloc( sizeof( cmd_macro_t ) );
macro->name = name;
macro->function = function;
macro->next = cmd_macros;
cmd_macros = macro;
+
+ hash = Com_HashString( name, MACRO_HASH_SIZE );
macro->hashNext = cmd_macroHash[hash];
cmd_macroHash[hash] = macro;
}
@@ -487,10 +509,8 @@ typedef struct cmd_function_s {
list_t listEntry;
xcommand_t function;
- xgenerator_t generator1;
- xgenerator_t generator2;
- xgenerator_t generator3;
- char *name;
+ xcompleter_t completer;
+ char *name;
} cmd_function_t;
static list_t cmd_functions; /* possible commands to execute */
@@ -794,6 +814,49 @@ void Cmd_PrintHint( void ) {
Com_Printf( "Try '%s --help' for more information.\n", cmd_argv[0] );
}
+const char *Cmd_Completer( const cmd_option_t *opt, const char *partial,
+ int argnum, int state, xgenerator_t generator )
+{
+ static int length;
+ static const cmd_option_t *o;
+ const char *s;
+
+ if( !state ) {
+ length = strlen( partial );
+ o = opt;
+ }
+
+ if( partial[0] == '-' ) {
+ while( o->sh ) {
+ if( partial[1] == '-' ) {
+ if( !strncmp( o->lo, partial + 2, length - 2 ) ) {
+ s = va( "--%s", o->lo );
+ o++;
+ return s;
+ }
+ } else if( !partial[1] || o->sh[0] == partial[1] ) {
+ s = va( "-%c", o->sh[0] );
+ o++;
+ return s;
+
+ }
+ o++;
+ }
+ } else {
+ /* if( argnum > 1 ) {
+ s = cmd_argv[argnum - 1];
+ }*/
+ if( generator ) {
+ return (*generator)( partial, state );
+ }
+ if( !partial[0] ) {
+ return "-";
+ }
+ }
+
+ return NULL;
+}
+
/*
======================
@@ -1087,18 +1150,14 @@ static void Cmd_RegCommand( const cmdreg_t *reg ) {
return;
}
cmd->function = reg->function;
- cmd->generator1 = reg->generator1;
- cmd->generator2 = reg->generator2;
- cmd->generator3 = reg->generator3;
+ cmd->completer = reg->completer;
return;
}
cmd = Cmd_Malloc( sizeof( *cmd ) );
cmd->name = ( char * )reg->name;
cmd->function = reg->function;
- cmd->generator1 = reg->generator1;
- cmd->generator2 = reg->generator2;
- cmd->generator3 = reg->generator3;
+ cmd->completer = reg->completer;
List_Append( &cmd_functions, &cmd->listEntry );
@@ -1116,9 +1175,7 @@ void Cmd_AddCommand( const char *name, xcommand_t function ) {
reg.name = name;
reg.function = function;
- reg.generator1 = NULL;
- reg.generator2 = NULL;
- reg.generator3 = NULL;
+ reg.completer = NULL;
Cmd_RegCommand( &reg );
}
@@ -1162,44 +1219,24 @@ Cmd_Exists
============
*/
qboolean Cmd_Exists( const char *name ) {
- cmd_function_t *cmd;
-
- cmd = Cmd_Find( name );
- if( !cmd ) {
- return qfalse;
- }
+ cmd_function_t *cmd = Cmd_Find( name );
- return qtrue;
+ return cmd ? qtrue : qfalse;
}
xcommand_t Cmd_FindFunction( const char *name ) {
- cmd_function_t *cmd;
-
- cmd = Cmd_Find( name );
- if( !cmd ) {
- return NULL;
- }
+ cmd_function_t *cmd = Cmd_Find( name );
- return cmd->function;
+ return cmd ? cmd->function : NULL;
}
-xgenerator_t Cmd_FindGenerator( const char *name, int index ) {
+xcompleter_t Cmd_FindCompleter( const char *name ) {
cmd_function_t *cmd = Cmd_Find( name );
- if( !cmd ) {
- return NULL;
- }
-
- switch( index ) {
- case 1: return cmd->generator1;
- case 2: return cmd->generator2;
- case 3: return cmd->generator3;
- }
-
- return NULL;
+ return cmd ? cmd->completer : NULL;
}
-const char *Cmd_Command_g( const char *partial, int state ) {
+const char *Cmd_CommandGenerator( const char *partial, int state ) {
static int length;
static cmd_function_t *cmd;
const char *name;
@@ -1220,7 +1257,7 @@ const char *Cmd_Command_g( const char *partial, int state ) {
return NULL;
}
-const char *Cmd_Alias_g( const char *partial, int state ) {
+const char *Cmd_AliasGenerator( const char *partial, int state ) {
static int length;
static cmdalias_t *alias;
const char *name;
@@ -1241,7 +1278,7 @@ const char *Cmd_Alias_g( const char *partial, int state ) {
return NULL;
}
-const char *Cmd_Mixed_g( const char *partial, int state ) {
+const char *Cmd_MixedGenerator( const char *partial, int state ) {
static xgenerator_t g;
const char *match;
@@ -1251,7 +1288,7 @@ const char *Cmd_Mixed_g( const char *partial, int state ) {
}
if( !state ) {
- g = Cmd_Command_g;
+ g = Cmd_CommandGenerator;
}
match = g( partial, state );
@@ -1259,9 +1296,9 @@ const char *Cmd_Mixed_g( const char *partial, int state ) {
return match;
}
- if( g == Cmd_Command_g ) {
+ if( g == Cmd_CommandGenerator ) {
g( partial, 2 );
- g = Cmd_Alias_g;
+ g = Cmd_AliasGenerator;
match = g( partial, 0 );
if( match ) {
@@ -1368,8 +1405,11 @@ static void Cmd_Exec_f( void ) {
FS_FreeFile( f );
}
-const char *Cmd_Exec_g( const char *partial, int state ) {
- return Com_FileNameGeneratorByFilter( "", "*.cfg", partial, qtrue, state );
+const char *Cmd_Exec_g( const char *partial, int argnum, int state ) {
+ if( argnum == 1 ) {
+ return Com_FileNameGeneratorByFilter( "", "*.cfg", partial, qtrue, state );
+ }
+ return NULL;
}
/*
@@ -1496,9 +1536,7 @@ static void Cmd_Complete_f( void ) {
cmd->name = ( char * )( cmd + 1 );
memcpy( cmd->name, name, len );
cmd->function = NULL;
- cmd->generator1 = NULL;
- cmd->generator2 = NULL;
- cmd->generator3 = NULL;
+ cmd->completer = NULL;
List_Append( &cmd_functions, &cmd->listEntry );
@@ -1522,7 +1560,6 @@ void Cmd_FillAPI( cmdAPI_t *api ) {
api->ExecuteText = Cbuf_ExecuteText;
api->FindFunction = Cmd_FindFunction;
api->FindMacroFunction = Cmd_FindMacroFunction;
- api->FindGenerator = Cmd_FindGenerator;
}
static const cmdreg_t c_cmd[] = {
@@ -1531,8 +1568,8 @@ static const cmdreg_t c_cmd[] = {
{ "exec", Cmd_Exec_f, Cmd_Exec_g },
{ "echo", Cmd_Echo_f },
{ "_echo", Cmd_ColoredEcho_f },
- { "alias", Cmd_Alias_f, Cmd_Alias_g, Cmd_Mixed_g },
- { "unalias", Cmd_UnAlias_f, Cmd_Alias_g },
+ { "alias", Cmd_Alias_f, Cmd_Alias_g },
+ { "unalias", Cmd_UnAlias_f, Cmd_UnAlias_g },
{ "wait", Cmd_Wait_f },
{ "text", Cmd_Text_f },
{ "complete", Cmd_Complete_f },
diff --git a/source/com_local.h b/source/com_local.h
index 58279e6..68e91d9 100644
--- a/source/com_local.h
+++ b/source/com_local.h
@@ -118,15 +118,15 @@ qboolean Cmd_Exists( const char *cmd_name );
xcommand_t Cmd_FindFunction( const char *name );
xmacro_t Cmd_FindMacroFunction( const char *name );
-xgenerator_t Cmd_FindGenerator( const char *name, int index );
+xcompleter_t Cmd_FindCompleter( const char *name );
char *Cmd_AliasCommand( const char *name );
void Cmd_AliasSet( const char *name, const char *cmd );
-const char *Cmd_Command_g( const char *text, int state );
-const char *Cmd_Alias_g( const char *text, int state );
-const char *Cmd_Mixed_g( const char *partial, int state );
-const char *Cmd_Exec_g( const char *partial, int state );
+const char *Cmd_CommandGenerator( const char *partial, int state );
+const char *Cmd_AliasGenerator( const char *partial, int state );
+const char *Cmd_MixedGenerator( const char *partial, int state );
+const char *Cmd_Exec_g( const char *partial, int argnum, int state );
// attempts to match a partial command for automatic command line completion
// returns NULL if nothing fits
@@ -199,6 +199,9 @@ void Cmd_PrintHelp( const cmd_option_t *opt );
void Cmd_PrintUsage( const cmd_option_t *opt, const char *suffix );
void Cmd_PrintHint( void );
+const char *Cmd_Completer( const cmd_option_t *opt, const char *partial,
+ int argnum, int state, xgenerator_t generator );
+
/*
==============================================================
@@ -243,7 +246,9 @@ cvar_t *Cvar_FullSet( const char *var_name, const char *value,
void Cvar_ClampInteger( cvar_t *var, int min, int max );
void Cvar_ClampValue( cvar_t *var, float min, float max );
-const char *Cvar_Generator( const char *text, int state );
+const char *Cvar_Set_g( const char *partial, int argnum, int state );
+
+const char *Cvar_Generator( const char *partial, int state );
// attempts to match a partial variable name for command line completion
// returns NULL if nothing fits
@@ -933,6 +938,7 @@ const char *Com_FileNameGenerator( const char *path, const char *ext, const char
qboolean stripExtension, int state );
const char *Com_FileNameGeneratorByFilter( const char *path, const char *filter, const char *partial,
qboolean stripExtension, int state );
+const char *Com_AddressGenerator( const char *partial, int state );
int Com_Time_m( char *buffer, int size );
int Com_Uptime_m( char *buffer, int size );
@@ -1114,5 +1120,6 @@ void SV_Shutdown( const char *finalmsg, killtype_t type );
void SV_Frame (int msec);
qboolean MVD_GetDemoPercent( int *percent, int *bufferPercent );
+const char *Prompt_Completer( const char *partial, int firstarg, int argnum, int state );
diff --git a/source/com_public.h b/source/com_public.h
index ffec357..2a9b4f7 100644
--- a/source/com_public.h
+++ b/source/com_public.h
@@ -39,13 +39,12 @@ typedef enum cbufExecWhen_e {
typedef void ( *xcommand_t )( void );
typedef int ( *xmacro_t )( char *, int );
+typedef const char *( *xcompleter_t )( const char *, int, int );
typedef struct cmdreg_s {
const char *name;
xcommand_t function;
- xgenerator_t generator1;
- xgenerator_t generator2;
- xgenerator_t generator3;
+ xcompleter_t completer;
} cmdreg_t;
typedef struct cmdAPI_s {
@@ -62,7 +61,6 @@ typedef struct cmdAPI_s {
void (*RemoveCommand)( const char *cmd_name );
xcommand_t (*FindFunction)( const char *name );
xmacro_t (*FindMacroFunction)( const char *name );
- xgenerator_t (*FindGenerator)( const char *name, int index );
} cmdAPI_t;
extern cmdAPI_t cmd;
diff --git a/source/common.c b/source/common.c
index 9a4ba50..63fba19 100644
--- a/source/common.c
+++ b/source/common.c
@@ -1131,6 +1131,34 @@ finish:
return NULL;
}
+const char *Com_AddressGenerator( const char *partial, int state ) {
+ static int length;
+ static int index;
+ cvar_t *var;
+ char buffer[MAX_QPATH];
+
+ if( !state ) {
+ length = strlen( partial );
+ index = 0;
+ }
+
+ while( index < 1024 ) {
+ Com_sprintf( buffer, sizeof( buffer ), "adr%i", index );
+ index++;
+ var = Cvar_FindVar( buffer );
+ if( !var ) {
+ break;
+ }
+ if( !var->string[0] ) {
+ continue;
+ }
+ if( !strncmp( partial, var->string, length ) ) {
+ return var->string;
+ }
+ }
+
+ return NULL;
+}
/*
===============
@@ -1220,7 +1248,7 @@ Qcommon_Init
=================
*/
void Qcommon_Init( int argc, char **argv ) {
- static const char *version = APPLICATION " " VERSION " " __DATE__ " " BUILDSTRING " " CPUSTRING;
+ static const char version[] = APPLICATION " " VERSION " " __DATE__ " " BUILDSTRING " " CPUSTRING;
if( setjmp( abortframe ) )
Sys_Error( "Error during initialization: %s", com_errorMsg );
@@ -1256,7 +1284,7 @@ void Qcommon_Init( int argc, char **argv ) {
logfile_active = Cvar_Get( "logfile", "0", 0 );
logfile_flush = Cvar_Get( "logfile_flush", "0", 0 );
logfile_name = Cvar_Get( "logfile_name", COM_LOGFILE_NAME, 0 );
- logfile_prefix = Cvar_Get( "logfile_prefix", "", 0 );
+ logfile_prefix = Cvar_Get( "logfile_prefix", "[%Y-%m-%d %H:%M] ", 0 );
#ifdef DEDICATED_ONLY
dedicated = Cvar_Get ("dedicated", "1", CVAR_ROM);
#else
diff --git a/source/cvar.c b/source/cvar.c
index 1c104e2..9cdf1ce 100644
--- a/source/cvar.c
+++ b/source/cvar.c
@@ -123,20 +123,20 @@ void Cvar_VariableStringBuffer( const char *var_name, char *buffer, int size ) {
Q_strncpyz( buffer, Cvar_VariableString( var_name ), size );
}
-const char *Cvar_Generator( const char *text, int state ) {
+const char *Cvar_Generator( const char *partial, int state ) {
static int length;
static cvar_t *cvar;
const char *name;
if( !state ) {
- length = strlen( text );
+ length = strlen( partial );
cvar = cvar_vars;
}
while( cvar ) {
name = cvar->name;
cvar = cvar->next;
- if( !strncmp( text, name, length ) ) {
+ if( !strncmp( partial, name, length ) ) {
return name;
}
}
@@ -632,6 +632,13 @@ void Cvar_Command( cvar_t *v ) {
}
}
+const char *Cvar_Set_g( const char *partial, int argnum, int state ) {
+ if( argnum == 1 ) {
+ return Cvar_Generator( partial, state );
+ }
+ return NULL;
+}
+
/*
============
@@ -740,22 +747,28 @@ Cvar_List_f
============
*/
+
+static const cmd_option_t o_cvarlist[] = {
+ { "a", "archive", "list archived cvars" },
+ { "c", "cheat", "list cheat protected cvars" },
+ { "h", "help", "display this help message" },
+ { "l", "latched", "list latched cvars" },
+ { "m", "modified", "list modified cvars" },
+ { "n", "noset", "list command line cvars" },
+ { "r", "rom", "list read-only cvars" },
+ { "s", "serverinfo", "list serverinfo cvars" },
+ { "t", "custom", "list user-created cvars" },
+ { "u", "userinfo", "list userinfo cvars" },
+ { "v", "verbose", "display flags of each cvar" },
+ { "w:string", "wildcard", "list cvars matching wildcard" },
+ { NULL }
+};
+
+static const char *Cvar_List_g( const char *partial, int argnum, int state ) {
+ return Cmd_Completer( o_cvarlist, partial, argnum, state, NULL );
+}
+
static void Cvar_List_f( void ) {
- static const cmd_option_t options[] = {
- { "a", "archive", "list archived cvars" },
- { "c", "cheat", "list cheat protected cvars" },
- { "h", "help", "display this help message" },
- { "l", "latched", "list latched cvars" },
- { "m", "modified", "list modified cvars" },
- { "n", "noset", "list command line cvars" },
- { "r", "rom", "list read-only cvars" },
- { "s", "serverinfo", "list serverinfo cvars" },
- { "t", "custom", "list user-created cvars" },
- { "u", "userinfo", "list userinfo cvars" },
- { "v", "verbose", "display flags of each cvar" },
- { "w:string", "wildcard", "list cvars matching wildcard" },
- { NULL }
- };
cvar_t *var;
int i, total;
qboolean verbose = qfalse, modified = qfalse, latched = qfalse;
@@ -764,7 +777,7 @@ static void Cvar_List_f( void ) {
char buffer[6];
int c;
- while( ( c = Cmd_ParseOptions( options ) ) != -1 ) {
+ while( ( c = Cmd_ParseOptions( o_cvarlist ) ) != -1 ) {
switch( c ) {
case 'a':
mask |= CVAR_ARCHIVE;
@@ -773,9 +786,9 @@ static void Cvar_List_f( void ) {
mask |= CVAR_CHEAT;
break;
case 'h':
- Cmd_PrintUsage( options, NULL );
+ Cmd_PrintUsage( o_cvarlist, NULL );
Com_Printf( "List registered console variables.\n" );
- Cmd_PrintHelp( options );
+ Cmd_PrintHelp( o_cvarlist );
Com_Printf(
"Flags legend:\n"
"C: cheat protected\n"
@@ -1024,15 +1037,15 @@ void Cvar_FillAPI( cvarAPI_t *api ) {
}
static const cmdreg_t c_cvar[] = {
- { "set", Cvar_Set_f, Cvar_Generator },
- { "setu", Cvar_SetFlag_f, Cvar_Generator },
- { "sets", Cvar_SetFlag_f, Cvar_Generator },
- { "seta", Cvar_SetFlag_f, Cvar_Generator },
- { "cvarlist", Cvar_List_f },
- { "toggle", Cvar_Toggle_f, Cvar_Generator },
- { "inc", Cvar_Inc_f, Cvar_Generator },
- { "dec", Cvar_Inc_f, Cvar_Generator },
- { "reset", Cvar_Reset_f, Cvar_Generator },
+ { "set", Cvar_Set_f, Cvar_Set_g },
+ { "setu", Cvar_SetFlag_f, Cvar_Set_g },
+ { "sets", Cvar_SetFlag_f, Cvar_Set_g },
+ { "seta", Cvar_SetFlag_f, Cvar_Set_g },
+ { "cvarlist", Cvar_List_f, Cvar_List_g },
+ { "toggle", Cvar_Toggle_f, Cvar_Set_g },
+ { "inc", Cvar_Inc_f, Cvar_Set_g },
+ { "dec", Cvar_Inc_f, Cvar_Set_g },
+ { "reset", Cvar_Reset_f, Cvar_Set_g },
{ NULL }
};
diff --git a/source/files.c b/source/files.c
index c3e624d..738ffb0 100644
--- a/source/files.c
+++ b/source/files.c
@@ -2221,11 +2221,15 @@ static void FS_Stats_f( void ) {
}
}
-static const char *FS_Link_g( const char *partial, int state ) {
+static const char *FS_Link_g( const char *partial, int argnum, int state ) {
static int length;
static fsLink_t *link;
char *name;
+ if( argnum != 1 ) {
+ return NULL;
+ }
+
if( !state ) {
length = strlen( partial );
link = fs_links;
diff --git a/source/gl_state.c b/source/gl_state.c
index 64e3ca9..9f74f99 100644
--- a/source/gl_state.c
+++ b/source/gl_state.c
@@ -262,6 +262,7 @@ void GL_SetDefaultState( void ) {
qglEnableClientState( GL_TEXTURE_COORD_ARRAY );
GL_SelectTMU( 0 );
+ GL_BindTexture( 0 );
qglEnable( GL_TEXTURE_2D );
GL_Bits( GLS_DEFAULT );
}
diff --git a/source/mvd_client.c b/source/mvd_client.c
index 837e24a..96f1ecf 100644
--- a/source/mvd_client.c
+++ b/source/mvd_client.c
@@ -952,6 +952,18 @@ void MVD_StreamedRecord_f( void ) {
SZ_Clear( &msg_write );
}
+static const cmd_option_t o_mvdconnect[] = {
+ { "h", "help", "display this message" },
+ { "e:string", "encoding", "specify default encoding as <string>" },
+ { "i:number", "id", "specify remote stream ID as <number>" },
+ { "n:string", "name", "specify channel name as <string>" },
+ { "r:string", "referer", "specify referer as <string> in HTTP request" },
+ { NULL }
+};
+
+const char *MVD_Connect_g( const char *partial, int argnum, int state ) {
+ return Cmd_Completer( o_mvdconnect, partial, argnum, state, Com_AddressGenerator );
+}
/*
==============
@@ -961,14 +973,6 @@ MVD_Connect_f
==============
*/
void MVD_Connect_f( void ) {
- static const cmd_option_t options[] = {
- { "h", "help", "display this message" },
- { "e:string", "encoding", "specify default encoding as <string>" },
- { "i:number", "id", "specify remote stream ID as <number>" },
- { "n:string", "name", "specify channel name as <string>" },
- { "r:string", "referer", "specify referer as <string> in HTTP request" },
- { NULL }
- };
netadr_t adr;
netstream_t stream;
char buffer[MAX_STRING_CHARS];
@@ -980,12 +984,12 @@ void MVD_Connect_f( void ) {
uint16_t port;
int c;
- while( ( c = Cmd_ParseOptions( options ) ) != -1 ) {
+ while( ( c = Cmd_ParseOptions( o_mvdconnect ) ) != -1 ) {
switch( c ) {
case 'h':
- Cmd_PrintUsage( options, "<uri>" );
+ Cmd_PrintUsage( o_mvdconnect, "<uri>" );
Com_Printf( "Create new MVD channel and connect to URI.\n" );
- Cmd_PrintHelp( options );
+ Cmd_PrintHelp( o_mvdconnect );
Com_Printf(
"Full URI syntax: [http://][user:pass@]<host>[:port][/resource]\n"
"If resource is given, default port is 80 and stream ID is ignored.\n"
@@ -1228,18 +1232,23 @@ static void MVD_Control_f( void ) {
}
}
-const char *MVD_Play_g( const char *partial, int state ) {
- return Com_FileNameGeneratorByFilter( "demos", "*.mvd2;*.mvd2.gz",
+static const cmd_option_t o_mvdplay[] = {
+ { "h", "help", "display this message" },
+ { "l:number", "loop", "replay <number> of times (0 means forever)" },
+ { "n:string", "name", "specify channel name as <string>" },
+ { NULL }
+};
+
+static const char *MVD_FileGenerator( const char *partial, int state ) {
+ return Com_FileNameGeneratorByFilter( "demos", "*.mvd2;*.mvd2.gz",
partial, qfalse, state );
}
+const char *MVD_Play_g( const char *partial, int argnum, int state ) {
+ return Cmd_Completer( o_mvdplay, partial, argnum, state, MVD_FileGenerator );
+}
+
void MVD_Play_f( void ) {
- static const cmd_option_t options[] = {
- { "h", "help", "display this message" },
- { "l:number", "loop", "replay <number> of times (0 means forever)" },
- { "n:string", "name", "specify channel name as <string>" },
- { NULL }
- };
char *name = NULL, *s;
char buffer[MAX_OSPATH];
int loop = 1, len;
@@ -1248,12 +1257,12 @@ void MVD_Play_f( void ) {
string_entry_t *entry, *head;
int i;
- while( ( c = Cmd_ParseOptions( options ) ) != -1 ) {
+ while( ( c = Cmd_ParseOptions( o_mvdplay ) ) != -1 ) {
switch( c ) {
case 'h':
- Cmd_PrintUsage( options, "[/]<filename>" );
+ Cmd_PrintUsage( o_mvdplay, "[/]<filename>" );
Com_Printf( "Create new MVD channel and begin demo playback.\n" );
- Cmd_PrintHelp( options );
+ Cmd_PrintHelp( o_mvdplay );
Com_Printf( "Final path is formatted as demos/<filename>.mvd2.\n"
"Prepend slash to specify raw path.\n" );
return;
@@ -1296,9 +1305,9 @@ void MVD_Play_f( void ) {
continue;
}
- len = strlen( buffer ) + 1;
+ len = strlen( buffer );
entry = Z_Malloc( sizeof( *entry ) + len );
- memcpy( entry->string, buffer, len );
+ memcpy( entry->string, buffer, len + 1 );
entry->next = head;
head = entry;
}
@@ -1360,7 +1369,7 @@ void MVD_Shutdown( void ) {
static const cmdreg_t c_mvd[] = {
{ "mvdplay", MVD_Play_f, MVD_Play_g },
- { "mvdconnect", MVD_Connect_f },
+ { "mvdconnect", MVD_Connect_f, MVD_Connect_g },
{ "mvdisconnect", MVD_Disconnect_f },
{ "mvdkill", MVD_Kill_f },
{ "mvdspawn", MVD_Spawn_f },
diff --git a/source/mvd_local.h b/source/mvd_local.h
index c96465f..27ba581 100644
--- a/source/mvd_local.h
+++ b/source/mvd_local.h
@@ -187,7 +187,7 @@ void MVD_Shutdown( void );
mvd_t *MVD_SetChannel( int arg );
-const char *MVD_Play_g( const char *partial, int state );
+const char *MVD_Play_g( const char *partial, int argnum, int state );
void MVD_Connect_f( void );
void MVD_Spawn_f( void );
diff --git a/source/mvd_parse.c b/source/mvd_parse.c
index 505ff6b..13ff8c1 100644
--- a/source/mvd_parse.c
+++ b/source/mvd_parse.c
@@ -266,7 +266,7 @@ static void MVD_ParseMulticast( mvd_t *mvd, mvd_ops_t op, int extrabits ) {
}
// do not send unreliables to connecting clients
- if( !reliable && ( cl->state != cs_spawned || cl->download || cl->nodata ) ) {
+ if( !reliable && ( cl->state != cs_spawned || cl->download || ( cl->flags & CF_NODATA ) ) ) {
continue;
}
@@ -541,7 +541,7 @@ static void MVD_ParseSound( mvd_t *mvd, int extrabits ) {
cl = client->cl;
// do not send unreliables to connecting clients
- if( cl->state != cs_spawned || cl->download || cl->nodata ) {
+ if( cl->state != cs_spawned || cl->download || ( cl->flags & CF_NODATA ) ) {
continue;
}
diff --git a/source/prompt.c b/source/prompt.c
index 49fdd3d..0c92ae3 100644
--- a/source/prompt.c
+++ b/source/prompt.c
@@ -56,7 +56,21 @@ static void Prompt_FreeMatches( void ) {
}
-static void Prompt_FooGenerator( xgenerator_t generator, const char *partial ) {
+static void Prompt_RunCompleter( xcompleter_t completer, const char *partial, int argnum ) {
+ const char *match;
+
+ match = (*completer)( partial, argnum, 0 );
+ while( match ) {
+ matches[numMatches++] = Z_CopyString( match );
+ if( numMatches == MAX_MATCHES ) {
+ (*completer)( partial, argnum, 2 );
+ return;
+ }
+ match = (*completer)( partial, argnum, 1 );
+ }
+}
+
+static void Prompt_RunGenerator( xgenerator_t generator, const char *partial ) {
const char *match;
match = (*generator)( partial, 0 );
@@ -71,15 +85,15 @@ static void Prompt_FooGenerator( xgenerator_t generator, const char *partial ) {
}
static void Prompt_GenerateMatches( const char *partial ) {
- Prompt_FooGenerator( Cmd_Command_g, partial );
+ Prompt_RunGenerator( Cmd_CommandGenerator, partial );
numCommands = numMatches;
if( numMatches != MAX_MATCHES ) {
- Prompt_FooGenerator( Cvar_Generator, partial );
+ Prompt_RunGenerator( Cvar_Generator, partial );
numCvars = numMatches - numCommands;
if( numMatches != MAX_MATCHES ) {
- Prompt_FooGenerator( Cmd_Alias_g, partial );
+ Prompt_RunGenerator( Cmd_AliasGenerator, partial );
numAliases = numMatches - numCvars - numCommands;
}
}
@@ -175,6 +189,40 @@ static void Prompt_ShowIndividualMatches( commandPrompt_t *prompt ) {
}
}
+const char *Prompt_Completer( const char *partial, int firstarg, int argnum, int state ) {
+ static xcompleter_t completer;
+ static xgenerator_t generator;
+ int relative = argnum - firstarg;
+
+ if( relative < 0 ) {
+ return NULL;
+ }
+
+ if( !state ) {
+ if( relative > 0 ) {
+ char *s = Cmd_Argv( firstarg );
+
+ generator = NULL;
+ completer = Cmd_FindCompleter( s );
+ if( !completer && relative == 1 ) {
+ cvar_t *v = Cvar_FindVar( s );
+ generator = v->generator;
+ }
+ } else {
+ completer = NULL;
+ generator = Cmd_MixedGenerator;
+ }
+ }
+
+ if( completer ) {
+ return (*completer)( partial, relative, state );
+ } else if( generator ) {
+ return (*generator)( partial, state );
+ } else {
+ return NULL;
+ }
+}
+
/*
====================
Prompt_CompleteCommand
@@ -185,7 +233,6 @@ void Prompt_CompleteCommand( commandPrompt_t *prompt, qboolean backslash ) {
char *text, *partial, *s;
int i, argc, pos, currentArg, size, length, relative;
char *first, *last;
- xgenerator_t generator;
text = inputLine->text;
size = sizeof( inputLine->text );
@@ -228,17 +275,16 @@ void Prompt_CompleteCommand( commandPrompt_t *prompt, qboolean backslash ) {
}
if( relative ) {
- cvar_t *v = Cvar_FindVar( s );
- if( v && v->generator ) {
- generator = v->generator;
- } else {
- generator = Cmd_FindGenerator( s, relative );
- }
- if( generator ) {
- Prompt_FooGenerator( generator, partial );
+ xcompleter_t completer = Cmd_FindCompleter( s );
+ if( completer ) {
+ Prompt_RunCompleter( completer, partial, relative );
+ } else if( relative == 1 ) {
+ cvar_t *v = Cvar_FindVar( s );
+ if( v && v->generator ) {
+ Prompt_RunGenerator( v->generator, partial );
+ }
}
} else {
- generator = NULL;
Prompt_GenerateMatches( partial );
}
@@ -312,8 +358,8 @@ void Prompt_CompleteCommand( commandPrompt_t *prompt, qboolean backslash ) {
inputLine->cursorPos = pos + 1;
prompt->printf( "]\\%s\n", Cmd_ArgsFrom( 0 ) );
- if( generator ) {
- goto multicolumn;
+ if( relative ) {
+ goto multi;
}
switch( com_completion_mode->integer ) {
@@ -324,7 +370,7 @@ void Prompt_CompleteCommand( commandPrompt_t *prompt, qboolean backslash ) {
}
break;
case 1:
- multicolumn:
+ multi:
// print in multiple columns
Prompt_ShowMatches( prompt, sortedMatches, 0, numMatches );
break;
diff --git a/source/q_shared.h b/source/q_shared.h
index 59e6812..bb2955b 100644
--- a/source/q_shared.h
+++ b/source/q_shared.h
@@ -592,8 +592,8 @@ CVARS (console variables)
struct cvar_s;
-typedef const char *( *xgenerator_t )( const char *, int );
typedef void (*xchanged_t)( struct cvar_s * );
+typedef const char *( *xgenerator_t )( const char *, int );
// nothing outside the cvar.*() functions should modify these fields!
typedef struct cvar_s {
diff --git a/source/snd_main.c b/source/snd_main.c
index 96a7a1c..616957e 100644
--- a/source/snd_main.c
+++ b/source/snd_main.c
@@ -138,9 +138,12 @@ static void S_SoundInfo_f( void ) {
}
-const char *S_Play_g( const char *partial, int state ) {
- return Com_FileNameGeneratorByFilter( "sound", "*.wav", partial,
+const char *S_Play_g( const char *partial, int argnum, int state ) {
+ if( argnum == 1 ) {
+ return Com_FileNameGeneratorByFilter( "sound", "*.wav", partial,
qfalse, state );
+ }
+ return NULL;
}
static void S_Play_f( void ) {
diff --git a/source/sv_ccmds.c b/source/sv_ccmds.c
index 8d8852e..9641cb6 100644
--- a/source/sv_ccmds.c
+++ b/source/sv_ccmds.c
@@ -75,7 +75,7 @@ static void SV_SetMaster_f( void ) {
svs.last_heartbeat = 0;
}
-static const char *SV_SetPlayer_g( const char *partial, int state ) {
+static const char *SV_SetPlayer_g( const char *partial, int argnum, int state ) {
static int length;
static int index;
client_t *client;
@@ -83,6 +83,9 @@ static const char *SV_SetPlayer_g( const char *partial, int state ) {
if( !svs.initialized ) {
return NULL;
}
+ if( argnum != 1 ) {
+ return NULL;
+ }
if( !state ) {
length = strlen( partial );
@@ -216,8 +219,11 @@ static void SV_Map_f( void ) {
SV_Map( Cmd_Argv( 1 ), qtrue );
}
-static const char *SV_Map_g( const char *partial, int state ) {
- return Com_FileNameGenerator( "maps", ".bsp", partial, qtrue, state );
+static const char *SV_Map_g( const char *partial, int argnum, int state ) {
+ if( argnum == 1 ) {
+ return Com_FileNameGenerator( "maps", ".bsp", partial, qtrue, state );
+ }
+ return NULL;
}
//===============================================================
diff --git a/source/sv_game.c b/source/sv_game.c
index 07742ca..53b22fe 100644
--- a/source/sv_game.c
+++ b/source/sv_game.c
@@ -81,27 +81,26 @@ static void PF_Unicast( edict_t *ent, qboolean reliable ) {
svc_ops_t op;
sizebuf_t *buf;
- if( !ent )
- return;
+ if( !ent ) {
+ goto clear;
+ }
clientNum = NUM_FOR_EDICT( ent ) - 1;
if( clientNum < 0 || clientNum >= sv_maxclients->integer ) {
Com_WPrintf( "PF_Unicast to a non-client %d\n", clientNum );
- return;
+ goto clear;
}
client = svs.udp_client_pool + clientNum;
if( client->state == cs_free ) {
Com_WPrintf( "PF_Unicast to a free client %d\n", clientNum );
- return;
+ goto clear;
}
-#if 0
- // HACK: fixes 'anti-votekick' exploit
+ // HACK: fix anti-kicking exploit
if( msg_write.data[0] == svc_disconnect ) {
- SV_RemoveClient( client );
+ client->flags |= CF_DROP;
}
-#endif
if( reliable ) {
flags = MSG_RELIABLE;
@@ -140,6 +139,7 @@ static void PF_Unicast( edict_t *ent, qboolean reliable ) {
}
}
+clear:
SZ_Clear( &msg_write );
}
@@ -542,7 +542,7 @@ static void PF_StartSound( edict_t *edict, int channel,
FOR_EACH_CLIENT( client ) {
// do not send sounds to connecting clients
- if( client->state != cs_spawned || client->download || client->nodata ) {
+ if( client->state != cs_spawned || client->download || ( client->flags & CF_NODATA ) ) {
continue;
}
diff --git a/source/sv_local.h b/source/sv_local.h
index 0755e56..2847f1a 100644
--- a/source/sv_local.h
+++ b/source/sv_local.h
@@ -143,17 +143,25 @@ typedef struct {
#define FOR_EACH_CLIENT( client ) \
LIST_FOR_EACH( client_t, client, &svs.udp_client_list, entry )
+typedef enum {
+ CF_RECONNECTED = ( 1 << 0 ),
+ CF_NODATA = ( 1 << 1 ),
+ CF_DEFLATE = ( 1 << 2 ),
+ CF_DROP = ( 1 << 3 )
+} client_flags_t;
+
typedef struct client_s {
list_t entry;
clstate_t state;
+ client_flags_t flags;
+
char userinfo[MAX_INFO_STRING]; // name, etc
char *versionString;
char reconnect_var[16];
char reconnect_val[16];
- qboolean reconnect_done;
int lastframe; // for delta compression
usercmd_t lastcmd; // for filling in big drops
@@ -177,7 +185,6 @@ typedef struct client_s {
int number; // client slot number
clientSetting_t settings[CLS_MAX];
- qboolean nodata;
client_frame_t frames[UPDATE_BACKUP]; // updates can be delta'd from here
@@ -190,7 +197,6 @@ typedef struct client_s {
int challenge; // challenge of this user, randomly generated
int protocol; // major version
int version; // minor version
- qboolean zlib;
time_t connect_time;
diff --git a/source/sv_main.c b/source/sv_main.c
index e4d58a9..22241db 100644
--- a/source/sv_main.c
+++ b/source/sv_main.c
@@ -512,7 +512,7 @@ static void SVC_DirectConnect( void ) {
char *ncstring, *acstring;
int reserved;
byte *buffer;
- qboolean zlib;
+ int zlib;
protocol = atoi( Cmd_Argv( 1 ) );
qport = atoi( Cmd_Argv( 2 ) ) ;
@@ -588,9 +588,9 @@ static void SVC_DirectConnect( void ) {
// set maximum message length
maxlength = MAX_PACKETLEN_WRITABLE_DEFAULT;
- zlib = qfalse;
+ zlib = 0;
if( protocol >= PROTOCOL_VERSION_R1Q2 ) {
- zlib = qtrue;
+ zlib = CF_DEFLATE;
s = Cmd_Argv( 5 );
if( *s ) {
maxlength = atoi( s );
@@ -644,7 +644,7 @@ static void SVC_DirectConnect( void ) {
// set zlib
s = Cmd_Argv( 7 );
if( *s && !atoi( s ) ) {
- zlib = qfalse;
+ zlib = 0;
}
// set minor protocol version
@@ -804,7 +804,7 @@ static void SVC_DirectConnect( void ) {
newcl->challenge = challenge; // save challenge for checksumming
newcl->protocol = protocol;
newcl->version = version;
- newcl->zlib = zlib;
+ newcl->flags = zlib;
newcl->edict = EDICT_NUM( number + 1 );
newcl->gamedir = fs_game->string;
newcl->mapname = sv.name;
@@ -911,6 +911,11 @@ static void SVC_DirectConnect( void ) {
newcl->WriteFrame = SV_WriteFrameToClient_Enhanced;
}
+ // loopback client doesn't need to reconnect
+ if( NET_IsLocalAddress( &net_from ) ) {
+ newcl->flags |= CF_RECONNECTED;
+ }
+
// add them to the linked list of connected clients
List_SeqAdd( &svs.udp_client_list, &newcl->entry );
@@ -1224,9 +1229,7 @@ void SV_SendAsyncPackets( void ) {
}
// spawned clients are handled elsewhere
- if( client->state == cs_spawned && !client->download &&
- !client->nodata )
- {
+ if( client->state == cs_spawned && !client->download && !( client->flags & CF_NODATA ) ) {
continue;
}
@@ -1293,6 +1296,8 @@ static void SV_CheckTimeouts( void ) {
SV_RemoveClient( client );
continue;
}
+ } else if( client->flags & CF_DROP ) {
+ SV_DropClient( client, NULL );
} else {
point = svs.droppoint;
if( client->state == cs_assigned && point < svs.ghostpoint ) {
@@ -1413,7 +1418,7 @@ static void SV_MasterHeartbeat( void ) {
// send to group master
for( i = 0; i < MAX_MASTERS; i++ ) {
if( master_adr[i].port ) {
- Com_Printf( "Sending heartbeat to %s\n",
+ Com_DPrintf( "Sending heartbeat to %s\n",
NET_AdrToString( &master_adr[i] ) );
NET_SendPacket( NS_SERVER, &master_adr[i], length + 14, buffer );
}
@@ -1439,7 +1444,7 @@ static void SV_MasterShutdown( void ) {
// send to group master
for( i = 0; i < MAX_MASTERS; i++ ) {
if( master_adr[i].port ) {
- Com_Printf( "Sending shutdown to %s\n",
+ Com_DPrintf( "Sending shutdown to %s\n",
NET_AdrToString( &master_adr[i] ) );
OOB_PRINT( NS_SERVER, &master_adr[i], "shutdown" );
}
diff --git a/source/sv_send.c b/source/sv_send.c
index c87a16c..cabf340 100644
--- a/source/sv_send.c
+++ b/source/sv_send.c
@@ -282,7 +282,7 @@ void SV_Multicast( vec3_t origin, multicast_t to ) {
}
// do not send unreliables to connecting clients
if( !( flags & MSG_RELIABLE ) && ( client->state != cs_spawned ||
- client->download || client->nodata ) )
+ client->download || ( client->flags & CF_NODATA ) ) )
{
continue;
}
@@ -766,7 +766,7 @@ void SV_SendClientMessages( void ) {
// send a message to each connected client
FOR_EACH_CLIENT( client ) {
- if( client->state != cs_spawned || client->download || client->nodata )
+ if( client->state != cs_spawned || client->download || ( client->flags & CF_NODATA ) )
goto finish;
// if the reliable message overflowed,
diff --git a/source/sv_user.c b/source/sv_user.c
index 010e707..ff2ed69 100644
--- a/source/sv_user.c
+++ b/source/sv_user.c
@@ -399,13 +399,9 @@ void SV_New_f( void ) {
}
// send reconnect var request
- if( sv_force_reconnect->string[0] && !sv_client->reconnect_done ) {
- if( NET_IsLocalAddress( &sv_client->netchan->remote_address ) ) {
- sv_client->reconnect_done = qtrue;
- } else {
- SV_ClientCommand( sv_client, "cmd \177c connect $%s\n",
- sv_client->reconnect_var );
- }
+ if( sv_force_reconnect->string[0] && !( sv_client->flags & CF_RECONNECTED ) ) {
+ SV_ClientCommand( sv_client, "cmd \177c connect $%s\n",
+ sv_client->reconnect_var );
}
Com_DPrintf( "Going from cs_connected to cs_primed for %s\n",
@@ -415,7 +411,7 @@ void SV_New_f( void ) {
memset( &sv_client->lastcmd, 0, sizeof( sv_client->lastcmd ) );
#if USE_ZLIB
- if( !sv_client->zlib ) {
+ if( !( sv_client->flags & CF_DEFLATE ) ) {
write_plain_configstrings();
write_plain_baselines();
} else {
@@ -455,7 +451,7 @@ void SV_Begin_f( void ) {
return;
}
- if( sv_force_reconnect->string[0] && !sv_client->reconnect_done ) {
+ if( sv_force_reconnect->string[0] && !( sv_client->flags & CF_RECONNECTED ) ) {
if( dedicated->integer ) {
Com_Printf( "%s[%s]: failed to reconnect\n", sv_client->name,
NET_AdrToString( &sv_client->netchan->remote_address ) );
@@ -704,59 +700,8 @@ static void SV_ShowServerinfo_f( void ) {
Com_EndRedirect();
}
-
-void SV_Nextserver( void ) {
-#if 0
- client_t *client;
- char *v;
-
- //ZOID, ss_pic can be nextserver'd in coop mode
- if (sv.state == ss_game)
- return; // can't nextserver while playing a normal game
-
- FOR_EACH_CLIENT( client ) {
- SV_ClientReset( client );
- }
-
- v = sv_nextserver->string;
- if (!v[0])
- Cbuf_AddText ("killserver\n");
- else
- {
- Cbuf_AddText (v);
- Cbuf_AddText ("\n");
- }
- Cvar_Set ("nextserver","");
-#endif
-}
-
-/*
-==================
-SV_Nextserver_f
-
-A cinematic has completed or been aborted by a client, so move
-to the next server.
-==================
-*/
-static void SV_Nextserver_f( void ) {
- if( !NET_IsLocalAddress( &sv_client->netchan->remote_address ) ) {
- Com_DPrintf( "Nextserver() from remote client, from %s\n",
- sv_client->name );
- return;
- }
- if ( atoi( Cmd_Argv( 1 ) ) != sv.spawncount ) {
- Com_DPrintf( "Nextserver() from wrong level, from %s\n",
- sv_client->name );
- return; // leftover from last server
- }
-
- Com_DPrintf( "Nextserver() from %s\n", sv_client->name );
-
- SV_Nextserver ();
-}
-
static void SV_NoGameData_f( void ) {
- sv_client->nodata ^= 1;
+ sv_client->flags ^= CF_NODATA;
}
static void SV_CvarResult_f( void ) {
@@ -776,7 +721,7 @@ static void SV_CvarResult_f( void ) {
if( sv_client->reconnect_var[0] ) {
v = Cmd_Argv( 2 );
if( !strcmp( v, sv_client->reconnect_val ) ) {
- sv_client->reconnect_done = qtrue;
+ sv_client->flags |= CF_RECONNECTED;
}
}
}
@@ -803,15 +748,13 @@ static void SV_AC_Info_f( void ) {
#endif
-static ucmd_t ucmds[] = {
+static const ucmd_t ucmds[] = {
// auto issued
{ "new", SV_New_f },
{ "begin", SV_Begin_f },
{ "baselines", NULL },
{ "configstrings", NULL },
-
- { "nextserver", SV_Nextserver_f },
-
+ { "nextserver", NULL },
{ "disconnect", SV_Disconnect_f },
// issued by hand at client consoles
@@ -854,9 +797,10 @@ static void SV_ExecuteUserCommand( const char *s ) {
}
return;
}
- if( sv.state == ss_game || sv.state == ss_broadcast ) {
- ge->ClientCommand( sv_player );
+ if( sv.state < ss_game ) {
+ return;
}
+ ge->ClientCommand( sv_player );
}
/*
@@ -867,9 +811,6 @@ USER CMD EXECUTION
===========================================================================
*/
-static int net_drop;
-
-
/*
==================
SV_ClientThink
@@ -905,7 +846,7 @@ static inline void SV_SetLastFrame( int lastframe ) {
SV_OldClientExecuteMove
==================
*/
-static void SV_OldClientExecuteMove( void ) {
+static void SV_OldClientExecuteMove( int net_drop ) {
usercmd_t oldest, oldcmd, newcmd;
int lastframe;
@@ -962,7 +903,7 @@ static void SV_OldClientExecuteMove( void ) {
SV_NewClientExecuteMove
==================
*/
-static void SV_NewClientExecuteMove( int c ) {
+static void SV_NewClientExecuteMove( int c, int net_drop ) {
usercmd_t cmds[MAX_PACKET_FRAMES][MAX_PACKET_USERCMDS];
usercmd_t *lastcmd, *cmd;
int lastframe;
@@ -1063,6 +1004,7 @@ void SV_ExecuteClientMessage( client_t *client ) {
qboolean move_issued;
int stringCmdCount;
int userinfoUpdateCount;
+ int net_drop;
sv_client = client;
sv_player = sv_client->edict;
@@ -1073,7 +1015,7 @@ void SV_ExecuteClientMessage( client_t *client ) {
userinfoUpdateCount = 0;
net_drop = client->netchan->dropped;
- if( net_drop ) {
+ if( net_drop > 0 ) {
client->frameflags |= FF_CLIENTDROP;
}
@@ -1117,7 +1059,7 @@ void SV_ExecuteClientMessage( client_t *client ) {
move_issued = qtrue;
- SV_OldClientExecuteMove();
+ SV_OldClientExecuteMove( net_drop );
break;
case clc_stringcmd:
@@ -1164,7 +1106,7 @@ void SV_ExecuteClientMessage( client_t *client ) {
}
move_issued = qtrue;
- SV_NewClientExecuteMove( c );
+ SV_NewClientExecuteMove( c, net_drop );
break;
case clc_userinfo_delta: {