diff options
author | /dev/humancontroller <devhc@example.com> | 2014-07-14 00:50:56 +0200 |
---|---|---|
committer | /dev/humancontroller <devhc@example.com> | 2017-03-09 13:51:18 +0100 |
commit | 7f4c1d68907d33b9e34ae22079e72b0a21f3fb1e (patch) | |
tree | d449a0fe84a124b5d64163a8c738fd7085f69ac6 /src | |
parent | b392b0d97f3ea048478059873ed6dec8afd9634b (diff) |
implement part 2 of the multi-protocol functionality: pk3 control
this contains a simple method to control the serving of alternate pk3 files to clients using the alternate-2 protocol (69); there's also a fixup for the VoIP part
the new fs_pk3PrefixPairs cvar has the format "P1&A1|P2&A2|...", where, for each i, Pi and Ai are corresponding primary and alternate pk3 filename prefixes, one of which one may be empty (eg. "P1&|&A2|...") to denote no correspondence
Diffstat (limited to 'src')
-rw-r--r-- | src/client/cl_main.c | 4 | ||||
-rw-r--r-- | src/qcommon/cvar.c | 9 | ||||
-rw-r--r-- | src/qcommon/files.c | 133 | ||||
-rw-r--r-- | src/qcommon/q_shared.h | 1 | ||||
-rw-r--r-- | src/qcommon/qcommon.h | 11 | ||||
-rw-r--r-- | src/server/sv_client.c | 21 | ||||
-rw-r--r-- | src/server/sv_init.c | 98 |
7 files changed, 240 insertions, 37 deletions
diff --git a/src/client/cl_main.c b/src/client/cl_main.c index 91ce5d81..7d266e67 100644 --- a/src/client/cl_main.c +++ b/src/client/cl_main.c @@ -2035,7 +2035,7 @@ CL_PK3List_f ================== */ void CL_OpenedPK3List_f( void ) { - Com_Printf("Opened PK3 Names: %s\n", FS_LoadedPakNames()); + Com_Printf("Opened PK3 Names: %s\n", FS_LoadedPakNames( qfalse )); } /* @@ -2044,7 +2044,7 @@ CL_PureList_f ================== */ void CL_ReferencedPK3List_f( void ) { - Com_Printf("Referenced PK3 Names: %s\n", FS_ReferencedPakNames()); + Com_Printf("Referenced PK3 Names: %s\n", FS_ReferencedPakNames( qfalse )); } /* diff --git a/src/qcommon/cvar.c b/src/qcommon/cvar.c index d22679e8..cabaf98f 100644 --- a/src/qcommon/cvar.c +++ b/src/qcommon/cvar.c @@ -403,6 +403,9 @@ cvar_t *Cvar_Get( const char *var_name, const char *var_value, int flags ) { // ZOID--needs to be set so that cvars the game sets as // SERVERINFO get sent to clients cvar_modifiedFlags |= flags; + if ( flags & CVAR_ALTERNATE_SYSTEMINFO ) { + cvar_modifiedFlags |= CVAR_SYSTEMINFO; + } return var; } @@ -452,6 +455,9 @@ cvar_t *Cvar_Get( const char *var_name, const char *var_value, int flags ) { var->flags = flags; // note what types of cvars have been modified (userinfo, archive, serverinfo, systeminfo) cvar_modifiedFlags |= var->flags; + if ( var->flags & CVAR_ALTERNATE_SYSTEMINFO ) { + cvar_modifiedFlags |= CVAR_SYSTEMINFO; + } hash = generateHashValue(var_name); var->hashIndex = hash; @@ -555,6 +561,9 @@ cvar_t *Cvar_Set2( const char *var_name, const char *value, qboolean force ) { // note what types of cvars have been modified (userinfo, archive, serverinfo, systeminfo) cvar_modifiedFlags |= var->flags; + if ( var->flags & CVAR_ALTERNATE_SYSTEMINFO ) { + cvar_modifiedFlags |= CVAR_SYSTEMINFO; + } if (!force) { diff --git a/src/qcommon/files.c b/src/qcommon/files.c index 27902711..e172f528 100644 --- a/src/qcommon/files.c +++ b/src/qcommon/files.c @@ -192,7 +192,7 @@ typedef struct fileInPack_s { struct fileInPack_s* next; // next file in the hash } fileInPack_t; -typedef struct { +typedef struct pack_s { char pakPathname[MAX_OSPATH]; // /tremulous/baseq3 char pakFilename[MAX_OSPATH]; // /tremulous/base/pak0.pk3 char pakBasename[MAX_OSPATH]; // pak0 @@ -205,6 +205,9 @@ typedef struct { int hashSize; // hash table size (power of 2) fileInPack_t* *hashTable; // hash table fileInPack_t* buildBuffer; // buffer with the filenames etc. + qboolean onlyPrimary; + qboolean onlyAlternate; + struct pack_s *primaryVersion; } pack_t; typedef struct { @@ -1716,7 +1719,11 @@ CONVENIENCE FUNCTIONS FOR ENTIRE FILES ====================================================================================== */ -int FS_FileIsInPAK(const char *filename, int *pChecksum ) { +int FS_FileIsInPAK( const char *filename, int *pChecksum ) { + return FS_FileIsInPAK_A( qfalse, filename, pChecksum ); +} + +int FS_FileIsInPAK_A( qboolean alternate, const char *filename, int *pChecksum ) { searchpath_t *search; pack_t *pak; fileInPack_t *pakFile; @@ -1757,6 +1764,9 @@ int FS_FileIsInPAK(const char *filename, int *pChecksum ) { if ( !FS_PakIsPure(search->pack) ) { continue; } + if ( ( alternate && search->pack->onlyPrimary ) || ( !alternate && search->pack->onlyAlternate ) ) { + continue; + } // look through all the pak file elements pak = search->pack; @@ -2732,7 +2742,10 @@ void FS_Path_f( void ) { Com_Printf ("We are looking in the current search path:\n"); for (s = fs_searchpaths; s; s = s->next) { if (s->pack) { - Com_Printf ("%s (%i files)\n", s->pack->pakFilename, s->pack->numfiles); + Com_Printf ("%s (%i files%s)\n", s->pack->pakFilename, s->pack->numfiles, + s->pack->onlyPrimary ? ", not for 1.1" : s->pack->onlyAlternate ? ", only for 1.1" : ""); + if (s->pack->primaryVersion) + Com_Printf (" (the 1.1 version of %s)\n", s->pack->primaryVersion->pakFilename); if ( fs_numServerPaks ) { if ( !FS_PakIsPure(s->pack) ) { Com_Printf( " not on the pure list\n" ); @@ -2869,6 +2882,14 @@ void FS_AddGameDirectory( const char *path, const char *dir ) { int pakwhich; int len; + char prefixBuf[MAX_STRING_CHARS]; + char *p; + const char *prefixes[10][2]; + int lengths[10][2]; + int numPairs, i; + searchpath_t *otherSearchpaths; + searchpath_t *srch; + // Unique for ( sp = fs_searchpaths ; sp ; sp = sp->next ) { if ( sp->dir && !Q_stricmp(sp->dir->path, path) && !Q_stricmp(sp->dir->gamedir, dir)) { @@ -2897,6 +2918,42 @@ void FS_AddGameDirectory( const char *path, const char *dir ) { qsort( pakdirs, numdirs, sizeof(char *), paksort ); } + Q_strncpyz( prefixBuf, Cvar_VariableString( "fs_pk3PrefixPairs" ), sizeof( prefixBuf ) ); + numPairs = 0; + p = prefixBuf; + if ( !p[0] ) + p = NULL; + while ( p ) { + prefixes[numPairs][0] = p; + p = strchr( p, '&' ); + if ( !p ) { + Com_Printf( S_COLOR_YELLOW "WARNING: fs_pk3PrefixPairs ends with an incomplete pair\n" ); + break; + } + lengths[numPairs][0] = (int)( p - prefixes[numPairs][0] ); + *p++ = '\0'; + prefixes[numPairs][1] = p; + p = strchr( p, '|' ); + if ( p ) { + lengths[numPairs][1] = (int)( p - prefixes[numPairs][1] ); + *p++ = '\0'; + } else { + lengths[numPairs][1] = (int)strlen( prefixes[numPairs][1] ); + } + if ( lengths[numPairs][0] == 0 && lengths[numPairs][1] == 0 ) { + Com_Printf( S_COLOR_YELLOW "WARNING: fs_pk3PrefixPairs contains a null-null pair, skipping this pair\n" ); + continue; + } + if ( lengths[numPairs][0] != 0 && lengths[numPairs][1] != 0 && + !Q_stricmpn( prefixes[numPairs][0], prefixes[numPairs][1], MIN( lengths[numPairs][0], lengths[numPairs][1] ) ) ) { + Com_Printf( S_COLOR_YELLOW "WARNING: in fs_pk3PrefixPairs, one of '%s' and '%s' is a real prefix of the other, skipping this pair\n", + prefixes[numPairs][0], prefixes[numPairs][1] ); + continue; + } + ++numPairs; + } + otherSearchpaths = fs_searchpaths; + pakfilesi = 0; pakdirsi = 0; @@ -2939,6 +2996,20 @@ void FS_AddGameDirectory( const char *path, const char *dir ) { search->next = fs_searchpaths; fs_searchpaths = search; + pak->onlyPrimary = qfalse; + pak->onlyAlternate = qfalse; + for ( i = 0 ; i < numPairs ; ++i ) { + if ( lengths[i][0] != 0 && !Q_stricmpn( pak->pakBasename, prefixes[i][0], lengths[i][0] ) ) { + pak->onlyPrimary = qtrue; + break; + } + else if ( lengths[i][1] != 0 && !Q_stricmpn( pak->pakBasename, prefixes[i][1], lengths[i][1] ) ) { + pak->onlyAlternate = qtrue; + break; + } + } + pak->primaryVersion = NULL; + pakfilesi++; } else { @@ -2972,6 +3043,29 @@ void FS_AddGameDirectory( const char *path, const char *dir ) { Sys_FreeFileList( pakfiles ); Sys_FreeFileList( pakdirs ); + if ( numPairs > 0 ) { + int bnlengths[2]; + for ( search = fs_searchpaths ; search != otherSearchpaths ; search = search->next ) { + if ( !( search->pack && search->pack->onlyPrimary ) ) { + continue; + } + bnlengths[0] = (int)strlen( search->pack->pakBasename ); + for ( srch = fs_searchpaths ; srch != otherSearchpaths ; srch = srch->next ) { + if ( !( srch->pack && srch->pack->onlyAlternate ) ) { + continue; + } + bnlengths[1] = (int)strlen( srch->pack->pakBasename ); + for ( i = 0 ; i < numPairs ; ++i ) { + if ( lengths[i][0] != 0 && lengths[i][1] != 0 && bnlengths[0] >= lengths[i][0] && bnlengths[1] >= lengths[i][1] && + !Q_stricmp( search->pack->pakBasename + lengths[i][0], srch->pack->pakBasename + lengths[i][1] ) ) { + srch->pack->primaryVersion = search->pack; + break; + } + } + } + } + } + // // add the directory to the search path // @@ -3230,6 +3324,7 @@ static void FS_Startup( const char *gameName ) } fs_homepath = Cvar_Get ("fs_homepath", homePath, CVAR_INIT|CVAR_PROTECTED ); fs_gamedirvar = Cvar_Get ("fs_game", "gpp", CVAR_INIT|CVAR_SYSTEMINFO ); + Cvar_Get( "fs_pk3PrefixPairs", "", CVAR_ARCHIVE|CVAR_LATCH ); // add search path elements in reverse priority order if (fs_basepath->string[0]) { @@ -3304,7 +3399,7 @@ Returns a space separated string containing the checksums of all loaded pk3 file Servers with sv_pure set will get this string and pass it to clients. ===================== */ -const char *FS_LoadedPakChecksums( void ) { +const char *FS_LoadedPakChecksums( qboolean alternate ) { static char info[BIG_INFO_STRING]; searchpath_t *search; @@ -3315,6 +3410,9 @@ const char *FS_LoadedPakChecksums( void ) { if ( !search->pack ) { continue; } + if ( ( alternate && search->pack->onlyPrimary ) || ( !alternate && search->pack->onlyAlternate ) ) { + continue; + } Q_strcat( info, sizeof( info ), va("%i ", search->pack->checksum ) ); } @@ -3330,7 +3428,7 @@ Returns a space separated string containing the names of all loaded pk3 files. Servers with sv_pure set will get this string and pass it to clients. ===================== */ -const char *FS_LoadedPakNames( void ) { +const char *FS_LoadedPakNames( qboolean alternate ) { static char info[BIG_INFO_STRING]; searchpath_t *search; @@ -3341,6 +3439,9 @@ const char *FS_LoadedPakNames( void ) { if ( !search->pack ) { continue; } + if ( ( alternate && search->pack->onlyPrimary ) || ( !alternate && search->pack->onlyAlternate ) ) { + continue; + } if (*info) { Q_strcat(info, sizeof( info ), " " ); @@ -3360,7 +3461,7 @@ Servers with sv_pure use these checksums to compare with the checksums the clien back to the server. ===================== */ -const char *FS_LoadedPakPureChecksums( void ) { +const char *FS_LoadedPakPureChecksums( qboolean alternate ) { static char info[BIG_INFO_STRING]; searchpath_t *search; @@ -3371,6 +3472,9 @@ const char *FS_LoadedPakPureChecksums( void ) { if ( !search->pack ) { continue; } + if ( ( alternate && search->pack->onlyPrimary ) || ( !alternate && search->pack->onlyAlternate ) ) { + continue; + } Q_strcat( info, sizeof( info ), va("%i ", search->pack->pure_checksum ) ); } @@ -3386,7 +3490,7 @@ Returns a space separated string containing the checksums of all referenced pk3 The server will send this to the clients so they can check which files should be auto-downloaded. ===================== */ -const char *FS_ReferencedPakChecksums( void ) { +const char *FS_ReferencedPakChecksums( qboolean alternate ) { static char info[BIG_INFO_STRING]; searchpath_t *search; @@ -3396,7 +3500,11 @@ const char *FS_ReferencedPakChecksums( void ) { for ( search = fs_searchpaths ; search ; search = search->next ) { // is the element a pak file? if ( search->pack ) { - if (search->pack->referenced || Q_stricmpn(search->pack->pakGamename, BASEGAME, strlen(BASEGAME))) { + if ( ( alternate && search->pack->onlyPrimary ) || ( !alternate && search->pack->onlyAlternate ) ) { + continue; + } + if (search->pack->referenced || (search->pack->primaryVersion && search->pack->primaryVersion->referenced) || + (fs_gamedirvar->string[0] && Q_stricmp(fs_gamedirvar->string, BASEGAME) && !Q_stricmp(search->pack->pakGamename, fs_gamedirvar->string))) { Q_strcat( info, sizeof( info ), va("%i ", search->pack->checksum ) ); } } @@ -3460,7 +3568,7 @@ Returns a space separated string containing the names of all referenced pk3 file The server will send this to the clients so they can check which files should be auto-downloaded. ===================== */ -const char *FS_ReferencedPakNames( void ) { +const char *FS_ReferencedPakNames( qboolean alternate ) { static char info[BIG_INFO_STRING]; searchpath_t *search; @@ -3471,7 +3579,11 @@ const char *FS_ReferencedPakNames( void ) { for ( search = fs_searchpaths ; search ; search = search->next ) { // is the element a pak file? if ( search->pack ) { - if (search->pack->referenced || Q_stricmpn(search->pack->pakGamename, BASEGAME, strlen(BASEGAME))) { + if ( ( alternate && search->pack->onlyPrimary ) || ( !alternate && search->pack->onlyAlternate ) ) { + continue; + } + if (search->pack->referenced || (search->pack->primaryVersion && search->pack->primaryVersion->referenced) || + (fs_gamedirvar->string[0] && Q_stricmp(fs_gamedirvar->string, BASEGAME) && !Q_stricmp(search->pack->pakGamename, fs_gamedirvar->string))) { if (*info) { Q_strcat(info, sizeof( info ), " " ); } @@ -3634,6 +3746,7 @@ void FS_InitFilesystem( void ) { Com_StartupVariable("fs_basepath"); Com_StartupVariable("fs_homepath"); Com_StartupVariable("fs_game"); + Com_StartupVariable("fs_pk3PrefixPairs"); if(!FS_FilenameCompare(Cvar_VariableString("fs_game"), BASEGAME)) Cvar_Set("fs_game", ""); diff --git a/src/qcommon/q_shared.h b/src/qcommon/q_shared.h index 6d6aa461..1ec69f44 100644 --- a/src/qcommon/q_shared.h +++ b/src/qcommon/q_shared.h @@ -959,6 +959,7 @@ default values. #define CVAR_SERVER_CREATED 0x0800 // cvar was created by a server the client connected to. #define CVAR_VM_CREATED 0x1000 // cvar was created exclusively in one of the VMs. #define CVAR_PROTECTED 0x2000 // prevent modifying this var from VMs or the server +#define CVAR_ALTERNATE_SYSTEMINFO 0x1000000 // These flags are only returned by the Cvar_Flags() function #define CVAR_MODIFIED 0x40000000 // Cvar was modified #define CVAR_NONEXISTENT 0x80000000 // Cvar doesn't exist. diff --git a/src/qcommon/qcommon.h b/src/qcommon/qcommon.h index 895c01d4..5dc5ab0c 100644 --- a/src/qcommon/qcommon.h +++ b/src/qcommon/qcommon.h @@ -647,6 +647,7 @@ long FS_FOpenFileRead( const char *qpath, fileHandle_t *file, qboolean uniqueFI // file IO goes through FS_ReadFile, which Does The Right Thing already. int FS_FileIsInPAK(const char *filename, int *pChecksum ); +int FS_FileIsInPAK_A(qboolean alternate, const char *filename, int *pChecksum ); // returns 1 if a file is in the PAK file, otherwise -1 int FS_Write( const void *buffer, int len, fileHandle_t f ); @@ -695,14 +696,14 @@ int FS_Seek( fileHandle_t f, long offset, int origin ); qboolean FS_FilenameCompare( const char *s1, const char *s2 ); -const char *FS_LoadedPakNames( void ); -const char *FS_LoadedPakChecksums( void ); -const char *FS_LoadedPakPureChecksums( void ); +const char *FS_LoadedPakNames( qboolean alternate ); +const char *FS_LoadedPakChecksums( qboolean alternate ); +const char *FS_LoadedPakPureChecksums( qboolean alternate ); // Returns a space separated string containing the checksums of all loaded pk3 files. // Servers with sv_pure set will get this string and pass it to clients. -const char *FS_ReferencedPakNames( void ); -const char *FS_ReferencedPakChecksums( void ); +const char *FS_ReferencedPakNames( qboolean alternate ); +const char *FS_ReferencedPakChecksums( qboolean alternate ); const char *FS_ReferencedPakPureChecksums( void ); // Returns a space separated string containing the checksums of all loaded // AND referenced pk3 files. Servers with sv_pure set will get this string diff --git a/src/server/sv_client.c b/src/server/sv_client.c index 91743f8e..126a9d05 100644 --- a/src/server/sv_client.c +++ b/src/server/sv_client.c @@ -459,6 +459,8 @@ void SV_DropClient( client_t *drop, const char *reason ) { } } +extern char alternateInfos[2][2][BIG_INFO_STRING]; + /* ================ SV_SendClientGameState @@ -475,6 +477,7 @@ static void SV_SendClientGameState( client_t *client ) { entityState_t *base, nullstate; msg_t msg; byte msgBuffer[MAX_MSGLEN]; + const char *configstring; Com_DPrintf ("SV_SendClientGameState() for %s\n", client->name); Com_DPrintf( "Going from CS_CONNECTED to CS_PRIMED for %s\n", client->name ); @@ -505,10 +508,16 @@ static void SV_SendClientGameState( client_t *client ) { // write the configstrings for ( start = 0 ; start < MAX_CONFIGSTRINGS ; start++ ) { - if (sv.configstrings[start].s[0]) { + if ( start <= CS_SYSTEMINFO && client->netchan.alternateProtocol != 0 ) { + configstring = alternateInfos[start][ client->netchan.alternateProtocol - 1 ]; + } else { + configstring = sv.configstrings[start].s; + } + + if (configstring[0]) { MSG_WriteByte( &msg, svc_configstring ); MSG_WriteShort( &msg, start ); - MSG_WriteBigString( &msg, sv.configstrings[start].s ); + MSG_WriteBigString( &msg, configstring ); } } @@ -713,7 +722,7 @@ int SV_WriteDownloadToClient(client_t *cl, msg_t *msg) // Check for pk3 filename extension if(!Q_stricmp(pakptr + 1, "pk3")) { - const char *referencedPaks = FS_ReferencedPakNames(); + const char *referencedPaks = FS_ReferencedPakNames( cl->netchan.alternateProtocol == 2 ); // Check whether the file appears in the list of referenced // paks to prevent downloading of arbitrary files. @@ -970,9 +979,9 @@ static void SV_VerifyPaks_f( client_t *cl ) { nChkSum1 = nChkSum2 = 0; // we run the game, so determine which cgame and ui the client "should" be running - bGood = (FS_FileIsInPAK("vm/cgame.qvm", &nChkSum1) == 1); + bGood = (FS_FileIsInPAK_A(cl->netchan.alternateProtocol == 2, "vm/cgame.qvm", &nChkSum1) == 1); if (bGood) - bGood = (FS_FileIsInPAK("vm/ui.qvm", &nChkSum2) == 1); + bGood = (FS_FileIsInPAK_A(cl->netchan.alternateProtocol == 2, "vm/ui.qvm", &nChkSum2) == 1);; nClientPaks = Cmd_Argc(); @@ -1048,7 +1057,7 @@ static void SV_VerifyPaks_f( client_t *cl ) { break; // get the pure checksums of the pk3 files loaded by the server - pPaks = FS_LoadedPakPureChecksums(); + pPaks = FS_LoadedPakPureChecksums( cl->netchan.alternateProtocol == 2 ); Cmd_TokenizeString( pPaks ); nServerPaks = Cmd_Argc(); if (nServerPaks > 1024) diff --git a/src/server/sv_init.c b/src/server/sv_init.c index 16726b40..b661284a 100644 --- a/src/server/sv_init.c +++ b/src/server/sv_init.c @@ -24,6 +24,8 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "server.h" +char alternateInfos[2][2][BIG_INFO_STRING]; + /* =============== SV_SendConfigstring @@ -34,6 +36,7 @@ given client */ static void SV_SendConfigstring(client_t *client, int index) { + const char *configstring; int maxChunkSize = MAX_STRING_CHARS - 24; int len; @@ -44,7 +47,13 @@ static void SV_SendConfigstring(client_t *client, int index) return; } - len = strlen(sv.configstrings[index].s); + if ( index <= CS_SYSTEMINFO && client->netchan.alternateProtocol != 0 ) { + configstring = alternateInfos[index][ client->netchan.alternateProtocol - 1 ]; + } else { + configstring = sv.configstrings[index].s; + } + + len = strlen(configstring); if( len >= maxChunkSize ) { int sent = 0; @@ -62,7 +71,7 @@ static void SV_SendConfigstring(client_t *client, int index) else { cmd = "bcs1"; } - Q_strncpyz( buf, &sv.configstrings[index].s[sent], + Q_strncpyz( buf, &configstring[sent], maxChunkSize ); SV_SendServerCommand( client, "%s %i \"%s\"\n", cmd, @@ -74,7 +83,7 @@ static void SV_SendConfigstring(client_t *client, int index) } else { // standard cs, just send it SV_SendServerCommand( client, "cs %i \"%s\"\n", index, - sv.configstrings[index].s ); + configstring ); } } @@ -112,6 +121,7 @@ SV_SetConfigstring =============== */ void SV_SetConfigstring (int index, const char *val) { + qboolean modified[3] = { qfalse, qfalse, qfalse }; int i; client_t *client; @@ -123,14 +133,50 @@ void SV_SetConfigstring (int index, const char *val) { val = ""; } - // don't bother broadcasting an update if no change - if ( !strcmp( val, sv.configstrings[ index ].s ) ) { - return; - } + if ( index <= CS_SYSTEMINFO ) { + for ( i = 1; i < 3; ++i ) { + char info[BIG_INFO_STRING]; - // change the string in sv - Z_Free( sv.configstrings[index].s ); - sv.configstrings[index].s = CopyString( val ); + if ( index == CS_SERVERINFO ) { + Q_strncpyz( info, val, MAX_INFO_STRING ); + Info_SetValueForKey( info, "protocol", ( i == 1 ? "70" : "69" ) ); + } else { + Q_strncpyz( info, val, BIG_INFO_STRING ); + Info_SetValueForKey_Big( info, "sv_voipProtocol", NULL ); + Info_SetValueForKey_Big( info, "voip", va("%i", sv_voip->integer) ); + if ( i == 2 ) { + Info_SetValueForKey_Big( info, "sv_paks", Cvar_VariableString( "sv_alternatePaks" ) ); + Info_SetValueForKey_Big( info, "sv_pakNames", Cvar_VariableString( "sv_alternatePakNames" ) ); + Info_SetValueForKey_Big( info, "sv_referencedPaks", Cvar_VariableString( "sv_referencedAlternatePaks" ) ); + Info_SetValueForKey_Big( info, "sv_referencedPakNames", Cvar_VariableString( "sv_referencedAlternatePakNames" ) ); + } + } + + if ( strcmp( info, alternateInfos[index][i - 1] ) ) { + modified[i] = qtrue; + strcpy( alternateInfos[index][i - 1], info ); + } + } + + if ( strcmp( val, sv.configstrings[index].s ) ) { + modified[0] = qtrue; + Z_Free( sv.configstrings[index].s ); + sv.configstrings[index].s = CopyString( val ); + } + + if ( !modified[0] && !modified[1] && !modified[2] ) { + return; + } + } else { + // don't bother broadcasting an update if no change + if ( !strcmp( val, sv.configstrings[ index ].s ) ) { + return; + } + + // change the string in sv + Z_Free( sv.configstrings[index].s ); + sv.configstrings[index].s = CopyString( val ); + } // send it to all the clients if we aren't // spawning a new server @@ -138,6 +184,10 @@ void SV_SetConfigstring (int index, const char *val) { // send the data to all relevent clients for (i = 0, client = svs.clients; i < sv_maxclients->integer ; i++, client++) { + if ( index <= CS_SYSTEMINFO && !modified[ client->netchan.alternateProtocol ] ) { + continue; + } + if ( client->state < CS_ACTIVE ) { if ( client->state == CS_PRIMED ) client->csUpdated[ index ] = qtrue; @@ -396,6 +446,9 @@ static void SV_ClearServer(void) { int i; for ( i = 0 ; i < MAX_CONFIGSTRINGS ; i++ ) { + if ( i <= CS_SYSTEMINFO ) { + alternateInfos[i][0][0] = alternateInfos[i][1][0] = '\0'; + } if ( sv.configstrings[i].s ) { Z_Free( sv.configstrings[i].s ); } @@ -486,6 +539,9 @@ void SV_SpawnServer( char *server, qboolean killBots ) { // wipe the entire per-level structure SV_ClearServer(); for ( i = 0 ; i < MAX_CONFIGSTRINGS ; i++ ) { + if ( i <= CS_SYSTEMINFO ) { + alternateInfos[i][0][0] = alternateInfos[i][1][0] = '\0'; + } sv.configstrings[i].s = CopyString(""); sv.configstrings[i].restricted = qfalse; Com_Memset(&sv.configstrings[i].clientList, 0, sizeof(clientList_t)); @@ -563,13 +619,17 @@ void SV_SpawnServer( char *server, qboolean killBots ) { if ( sv_pure->integer ) { // the server sends these to the clients so they will only // load pk3s also loaded at the server - p = FS_LoadedPakChecksums(); + p = FS_LoadedPakChecksums( qfalse ); Cvar_Set( "sv_paks", p ); + p = FS_LoadedPakChecksums( qtrue ); + Cvar_Set( "sv_alternatePaks", p ); if (strlen(p) == 0) { Com_Printf( "WARNING: sv_pure set but no PK3 files loaded\n" ); } - p = FS_LoadedPakNames(); + p = FS_LoadedPakNames( qfalse ); Cvar_Set( "sv_pakNames", p ); + p = FS_LoadedPakNames( qtrue ); + Cvar_Set( "sv_alternatePakNames", p ); // if a dedicated pure server we need to touch the cgame because it could be in a // seperate pk3 file and the client will need to load the latest cgame.qvm @@ -580,13 +640,19 @@ void SV_SpawnServer( char *server, qboolean killBots ) { else { Cvar_Set( "sv_paks", "" ); Cvar_Set( "sv_pakNames", "" ); + Cvar_Set( "sv_alternatePaks", "" ); + Cvar_Set( "sv_alternatePakNames", "" ); } // the server sends these to the clients so they can figure // out which pk3s should be auto-downloaded - p = FS_ReferencedPakChecksums(); + p = FS_ReferencedPakChecksums( qfalse ); Cvar_Set( "sv_referencedPaks", p ); - p = FS_ReferencedPakNames(); + p = FS_ReferencedPakChecksums( qtrue ); + Cvar_Set( "sv_referencedAlternatePaks", p ); + p = FS_ReferencedPakNames( qfalse ); Cvar_Set( "sv_referencedPakNames", p ); + p = FS_ReferencedPakNames( qtrue ); + Cvar_Set( "sv_referencedAlternatePakNames", p ); // save systeminfo and serverinfo strings Q_strncpyz( systemInfo, Cvar_InfoString_Big( CVAR_SYSTEMINFO ), sizeof( systemInfo ) ); @@ -658,6 +724,10 @@ void SV_Init (void) Cvar_Get ("sv_pakNames", "", CVAR_SYSTEMINFO | CVAR_ROM ); Cvar_Get ("sv_referencedPaks", "", CVAR_SYSTEMINFO | CVAR_ROM ); Cvar_Get ("sv_referencedPakNames", "", CVAR_SYSTEMINFO | CVAR_ROM ); + Cvar_Get ("sv_alternatePaks", "", CVAR_ALTERNATE_SYSTEMINFO | CVAR_ROM ); + Cvar_Get ("sv_alternatePakNames", "", CVAR_ALTERNATE_SYSTEMINFO | CVAR_ROM ); + Cvar_Get ("sv_referencedAlternatePaks", "", CVAR_ALTERNATE_SYSTEMINFO | CVAR_ROM ); + Cvar_Get ("sv_referencedAlternatePakNames", "", CVAR_ALTERNATE_SYSTEMINFO | CVAR_ROM ); // server vars sv_rconPassword = Cvar_Get ("rconPassword", "", CVAR_TEMP ); |