summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
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
commit7f4c1d68907d33b9e34ae22079e72b0a21f3fb1e (patch)
treed449a0fe84a124b5d64163a8c738fd7085f69ac6
parentb392b0d97f3ea048478059873ed6dec8afd9634b (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
-rw-r--r--src/client/cl_main.c4
-rw-r--r--src/qcommon/cvar.c9
-rw-r--r--src/qcommon/files.c133
-rw-r--r--src/qcommon/q_shared.h1
-rw-r--r--src/qcommon/qcommon.h11
-rw-r--r--src/server/sv_client.c21
-rw-r--r--src/server/sv_init.c98
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 );