diff options
author | Andrey Nazarov <skuller@skuller.net> | 2008-02-28 12:09:10 +0000 |
---|---|---|
committer | Andrey Nazarov <skuller@skuller.net> | 2008-02-28 12:09:10 +0000 |
commit | bf6d45c620f098c84d602e9347bc7cf457c38b5a (patch) | |
tree | ec075676ff09467ea910c51fb45fb37185a1ddf3 | |
parent | 4034314816f7ec9e26c9b9bfc2630c8ca0a24874 (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.c | 9 | ||||
-rw-r--r-- | source/cl_demo.c | 9 | ||||
-rw-r--r-- | source/cl_draw.c | 2 | ||||
-rw-r--r-- | source/cl_keys.c | 20 | ||||
-rw-r--r-- | source/cl_local.h | 2 | ||||
-rw-r--r-- | source/cl_main.c | 139 | ||||
-rw-r--r-- | source/cmd.c | 159 | ||||
-rw-r--r-- | source/com_local.h | 19 | ||||
-rw-r--r-- | source/com_public.h | 6 | ||||
-rw-r--r-- | source/common.c | 32 | ||||
-rw-r--r-- | source/cvar.c | 73 | ||||
-rw-r--r-- | source/files.c | 6 | ||||
-rw-r--r-- | source/gl_state.c | 1 | ||||
-rw-r--r-- | source/mvd_client.c | 59 | ||||
-rw-r--r-- | source/mvd_local.h | 2 | ||||
-rw-r--r-- | source/mvd_parse.c | 4 | ||||
-rw-r--r-- | source/prompt.c | 80 | ||||
-rw-r--r-- | source/q_shared.h | 2 | ||||
-rw-r--r-- | source/snd_main.c | 7 | ||||
-rw-r--r-- | source/sv_ccmds.c | 12 | ||||
-rw-r--r-- | source/sv_game.c | 18 | ||||
-rw-r--r-- | source/sv_local.h | 12 | ||||
-rw-r--r-- | source/sv_main.c | 25 | ||||
-rw-r--r-- | source/sv_send.c | 4 | ||||
-rw-r--r-- | source/sv_user.c | 94 |
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( ® ); } @@ -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: { |