- Change runtime standalone detection:

* com_standalone now read-only
  * add new cvars com_basegame, com_homepath
  * standalone now automatically detected when com_basegame is set to something different than baseq3 and no id pak pk3s are found
  * This fixes https://bugzilla.icculus.org/show_bug.cgi?id=4699
- Replace a few hardcoded string literals with macros
- Add checks for Team Arena PK3s to FS_CheckPak0()
This commit is contained in:
Thilo Schulz 2011-02-04 12:04:56 +00:00
parent 774955c748
commit 3148416c04
13 changed files with 236 additions and 83 deletions

28
README
View file

@ -141,7 +141,14 @@ New cvars
com_ansiColor - enable use of ANSI escape codes in the tty
com_altivec - enable use of altivec on PowerPC systems
com_standalone - Run in standalone mode
com_standalone (read only) - If set to 1, quake3 is running in
standalone mode.
com_basegame - Use a different base than baseq3. If no
original Quake3 or TeamArena pak files
are found, this will enable running in
standalone mode.
com_homepath - Specify name that is to be appended to the
home path
com_maxfpsUnfocused - Maximum frames per second when unfocused
com_maxfpsMinimized - Maximum frames per second when minimized
com_busyWait - Will use a busy loop to wait for rendering
@ -334,11 +341,22 @@ Creating standalone games
your own binaries. Instead, you can just use the pre-built binaries on the
website. Just make sure the game is called with:
+set com_standalone 1 +set fs_game <yourgamedir>
+set com_basegame <yournewbase>
in any links/scripts you install for your users to start the game. Note that
the com_standalone setting is rendered ineffective, if the binary detects pk3
files in the directory "baseq3", so you cannot use that one as game dir.
in any links/scripts you install for your users to start the game. The
binary must not detect any original quake3 game pak files. If this
condition is met, the game will set com_standalone to 1 and is then running
in stand alone mode.
If you want the engine to use a different directory in your homepath than
e.g. "Quake3" on Windows or ".q3a" on Linux, then set a new name at startup
by adding
+set com_homepath <homedirname>
to the command line. Example line:
+set com_basegame basefoo +set com_homepath .foo
If you really changed parts that would make vanilla ioquake3 incompatible with
your mod, we have included another way to conveniently build a stand-alone

View file

@ -144,16 +144,19 @@ int Export_BotLibSetup(void)
if(botDeveloper)
{
char *homedir, *gamedir;
char *homedir, *gamedir, *basedir;
char logfilename[MAX_OSPATH];
homedir = LibVarGetString("homedir");
gamedir = LibVarGetString("gamedir");
basedir = LibVarGetString("com_basegame");
if (*homedir)
{
if(*gamedir)
Com_sprintf(logfilename, sizeof(logfilename), "%s%c%s%cbotlib.log", homedir, PATH_SEP, gamedir, PATH_SEP);
else if(*basedir)
Com_sprintf(logfilename, sizeof(logfilename), "%s%c%s%cbotlib.log", homedir, PATH_SEP, basedir, PATH_SEP);
else
Com_sprintf(logfilename, sizeof(logfilename), "%s%c" BASEGAME "%cbotlib.log", homedir, PATH_SEP, PATH_SEP);
}

View file

@ -2106,7 +2106,7 @@ void CL_CheckForResend( void ) {
case CA_CONNECTING:
// requesting a challenge .. IPv6 users always get in as authorize server supports no ipv6.
#ifndef STANDALONE
if (!Cvar_VariableIntegerValue("com_standalone") && clc.serverAddress.type == NA_IP && !Sys_IsLANAddress( clc.serverAddress ) )
if (!com_standalone->integer && clc.serverAddress.type == NA_IP && !Sys_IsLANAddress( clc.serverAddress ) )
CL_RequestAuthorization();
#endif

View file

@ -121,7 +121,7 @@ void Main_MenuEvent (void* ptr, int event) {
break;
case ID_TEAMARENA:
trap_Cvar_Set( "fs_game", "missionpack");
trap_Cvar_Set( "fs_game", BASETA);
trap_Cmd_ExecuteText( EXEC_APPEND, "vid_restart;" );
break;
@ -248,7 +248,7 @@ static qboolean UI_TeamArenaExists( void ) {
for( i = 0; i < numdirs; i++ ) {
dirlen = strlen( dirptr ) + 1;
descptr = dirptr + dirlen;
if (Q_stricmp(dirptr, "missionpack") == 0) {
if (Q_stricmp(dirptr, BASETA) == 0) {
return qtrue;
}
dirptr += dirlen + strlen(descptr) + 1;

View file

@ -83,6 +83,8 @@ cvar_t *com_minimized;
cvar_t *com_maxfpsMinimized;
cvar_t *com_abnormalExit;
cvar_t *com_standalone;
cvar_t *com_basegame;
cvar_t *com_homepath;
cvar_t *com_busyWait;
// com_speeds times
@ -2616,12 +2618,19 @@ void Com_Init( char *commandLine ) {
Cmd_Init ();
// get the developer cvar set as early as possible
Com_StartupVariable( "developer" );
com_developer = Cvar_Get("developer", "0", CVAR_TEMP);
// done early so bind command exists
CL_InitKeyCommands();
com_standalone = Cvar_Get("com_standalone", "0", CVAR_ROM);
com_basegame = Cvar_Get("com_basegame", BASEGAME, CVAR_INIT);
com_homepath = Cvar_Get("com_homepath", "", CVAR_INIT);
if(!com_basegame->string[0])
Cvar_ForceReset("com_basegame");
// Com_StartupVariable(
FS_InitFilesystem ();
Com_InitJournaling();
@ -2690,7 +2699,6 @@ void Com_Init( char *commandLine ) {
com_minimized = Cvar_Get( "com_minimized", "0", CVAR_ROM );
com_maxfpsMinimized = Cvar_Get( "com_maxfpsMinimized", "0", CVAR_ARCHIVE );
com_abnormalExit = Cvar_Get( "com_abnormalExit", "0", CVAR_ROM );
com_standalone = Cvar_Get( "com_standalone", "0", CVAR_INIT );
com_busyWait = Cvar_Get("com_busyWait", "0", CVAR_ARCHIVE);
com_introPlayed = Cvar_Get( "com_introplayed", "0", CVAR_ARCHIVE);
@ -2806,7 +2814,7 @@ void Com_WriteConfiguration( void ) {
#ifndef DEDICATED
fs = Cvar_Get ("fs_game", "", CVAR_INIT|CVAR_SYSTEMINFO );
#ifndef STANDALONE
if(!Cvar_VariableIntegerValue("com_standalone"))
if(!com_standalone->integer)
{
if (UI_usesUniqueCDKey() && fs && fs->string[0] != 0) {
Com_WriteCDKey( fs->string, &cl_cdkey[16] );

View file

@ -175,7 +175,7 @@ or configs will never get loaded from disk!
// every time a new demo pk3 file is built, this checksum must be updated.
// the easiest way to get it is to just run the game and see what it spits out
#define DEMO_PAK0_CHECKSUM 2985612116u
static const unsigned pak_checksums[] = {
static const unsigned int pak_checksums[] = {
1566731103u,
298122907u,
412165236u,
@ -187,6 +187,14 @@ static const unsigned pak_checksums[] = {
977125798u
};
static const unsigned int missionpak_checksums[] =
{
2430342401u,
511014160u,
2662638993u,
1438664554u
};
// if this is defined, the executable positively won't work with any paks other
// than the demo pak, even if productid is present. This is only used for our
// last demo release to prevent the mac and linux users from using the demo
@ -2195,7 +2203,7 @@ int FS_GetModList( char *listbuf, int bufsize ) {
continue;
}
// we drop "baseq3" "." and ".."
if (Q_stricmp(name, BASEGAME) && Q_stricmpn(name, ".", 1)) {
if (Q_stricmp(name, com_basegame->string) && Q_stricmpn(name, ".", 1)) {
// now we need to find some .pk3 files to validate the mod
// NOTE TTimo: (actually I'm not sure why .. what if it's a mod under developement with no .pk3?)
// we didn't keep the information when we merged the directory names, as to what OS Path it was found under
@ -2546,7 +2554,8 @@ void FS_AddGameDirectory( const char *path, const char *dir ) {
FS_idPak
================
*/
qboolean FS_idPak( char *pak, char *base ) {
qboolean FS_idPak(char *pak, char *base, int numPaks)
{
int i;
for (i = 0; i < NUM_ID_PAKS; i++) {
@ -2554,7 +2563,7 @@ qboolean FS_idPak( char *pak, char *base ) {
break;
}
}
if (i < NUM_ID_PAKS) {
if (i < numPaks) {
return qtrue;
}
return qfalse;
@ -2621,8 +2630,8 @@ qboolean FS_ComparePaks( char *neededpaks, int len, qboolean dlstring ) {
havepak = qfalse;
// never autodownload any of the id paks
if ( FS_idPak(fs_serverReferencedPakNames[i], "baseq3")
|| FS_idPak(fs_serverReferencedPakNames[i], "missionpack") ) {
if ( FS_idPak(fs_serverReferencedPakNames[i], BASEGAME, NUM_ID_PAKS)
|| FS_idPak(fs_serverReferencedPakNames[i], BASETA, NUM_TA_PAKS) ) {
continue;
}
@ -2855,7 +2864,7 @@ static void FS_Startup( const char *gameName )
}
#ifndef STANDALONE
if(!Cvar_VariableIntegerValue("com_standalone"))
if(!com_standalone->integer)
{
cvar_t *fs;
@ -2897,16 +2906,20 @@ static void FS_Startup( const char *gameName )
===================
FS_CheckPak0
Checks that pak0.pk3 is present and its checksum is correct
Check whether any of the original id pak files is present,
and start up in standalone mode, if there are none and a
different com_basegame was set.
Note: If you're building a game that doesn't depend on the
Q3 media pak0.pk3, you'll want to remove this function
Q3 media pak0.pk3, you'll want to remove this by defining
STANDALONE in q_shared.h
===================
*/
static void FS_CheckPak0( void )
{
searchpath_t *path;
pack_t *curpack;
qboolean founddemo = qfalse;
unsigned foundPak = 0;
unsigned int foundPak = 0, foundTA = 0;
for( path = fs_searchpaths; path; path = path->next )
{
@ -2915,12 +2928,118 @@ static void FS_CheckPak0( void )
if(!path->pack)
continue;
if(!Q_stricmpn( path->pack->pakGamename, "demoq3", MAX_OSPATH )
curpack = path->pack;
if(!Q_stricmpn( curpack->pakGamename, "demoq3", MAX_OSPATH )
&& !Q_stricmpn( pakBasename, "pak0", MAX_OSPATH ))
{
founddemo = qtrue;
if(curpack->checksum == DEMO_PAK0_CHECKSUM)
founddemo = qtrue;
}
if( path->pack->checksum == DEMO_PAK0_CHECKSUM )
else if(!Q_stricmpn( curpack->pakGamename, BASEGAME, MAX_OSPATH )
&& strlen(pakBasename) == 4 && !Q_stricmpn( pakBasename, "pak", 3 )
&& pakBasename[3] >= '0' && pakBasename[3] <= '0' + NUM_ID_PAKS - 1)
{
if( curpack->checksum != pak_checksums[pakBasename[3]-'0'] )
{
if(pakBasename[3] == '0')
{
Com_Printf("\n\n"
"**************************************************\n"
"WARNING: " BASEGAME "/pak0.pk3 is present but its checksum (%u)\n"
"is not correct. Please re-copy pak0.pk3 from your\n"
"legitimate Q3 CDROM.\n"
"**************************************************\n\n\n",
curpack->checksum );
}
else
{
Com_Printf("\n\n"
"**************************************************\n"
"WARNING: " BASEGAME "/pak%d.pk3 is present but its checksum (%u)\n"
"is not correct. Please re-install the point release\n"
"**************************************************\n\n\n",
pakBasename[3]-'0', curpack->checksum );
}
}
foundPak |= 1<<(pakBasename[3]-'0');
}
else if(!Q_stricmpn(curpack->pakGamename, BASETA, MAX_OSPATH)
&& strlen(pakBasename) == 4 && !Q_stricmpn(pakBasename, "pak", 3)
&& pakBasename[3] >= '0' && pakBasename[3] <= '0' + NUM_TA_PAKS - 1)
{
if(curpack->checksum != missionpak_checksums[pakBasename[3]-'0'])
{
Com_Printf("\n\n"
"**************************************************\n"
"WARNING: " BASETA "/pak%d.pk3 is present but its checksum (%u)\n"
"is not correct. Please re-install Team Arena\n"
"**************************************************\n\n\n",
pakBasename[3]-'0', curpack->checksum );
}
foundTA |= 1 << (pakBasename[3]-'0');
}
else
{
int index;
// Finally check whether this pak's checksum is listed because the user tried
// to trick us by renaming the file, and set foundPak's highest bit to indicate this case.
for(index = 0; index < ARRAY_LEN(pak_checksums); index++)
{
if(curpack->checksum == pak_checksums[index])
{
Com_Printf("\n\n"
"**************************************************\n"
"WARNING: %s is renamed pak file %s%cpak%d.pk3\n"
"Running in standalone mode won't work\n"
"Please rename, or remove this file\n"
"**************************************************\n\n\n",
curpack->pakFilename, BASEGAME, PATH_SEP, index);
foundPak |= 0x80000000;
}
}
for(index = 0; index < ARRAY_LEN(missionpak_checksums); index++)
{
if(curpack->checksum == missionpak_checksums[index])
{
Com_Printf("\n\n"
"**************************************************\n"
"WARNING: %s is renamed pak file %s%cpak%d.pk3\n"
"Running in standalone mode won't work\n"
"Please rename, or remove this file\n"
"**************************************************\n\n\n",
curpack->pakFilename, BASETA, PATH_SEP, index);
foundTA |= 0x80000000;
}
}
}
}
if(com_basegame->string[0] &&
Q_stricmp(com_basegame->string, BASEGAME) &&
!foundPak && !foundTA
)
{
Cvar_Set("com_standalone", "1");
}
else
Cvar_Set("com_standalone", "0");
if(!com_standalone->integer)
{
if(!(foundPak & 0x01))
{
if(founddemo)
{
Com_Printf( "\n\n"
"**************************************************\n"
@ -2928,57 +3047,25 @@ static void FS_CheckPak0( void )
"from the demo. This may work fine, but it is not\n"
"guaranteed or supported.\n"
"**************************************************\n\n\n" );
}
}
else if(!Q_stricmpn( path->pack->pakGamename, BASEGAME, MAX_OSPATH )
&& strlen(pakBasename) == 4 && !Q_stricmpn( pakBasename, "pak", 3 )
&& pakBasename[3] >= '0' && pakBasename[3] <= '8')
{
if( path->pack->checksum != pak_checksums[pakBasename[3]-'0'] )
{
if(pakBasename[0] == '0')
{
Com_Printf("\n\n"
"**************************************************\n"
"WARNING: pak0.pk3 is present but its checksum (%u)\n"
"is not correct. Please re-copy pak0.pk3 from your\n"
"legitimate Q3 CDROM.\n"
"**************************************************\n\n\n",
path->pack->checksum );
}
else
{
Com_Printf("\n\n"
"**************************************************\n"
"WARNING: pak%d.pk3 is present but its checksum (%u)\n"
"is not correct. Please re-install the point release\n"
"**************************************************\n\n\n",
pakBasename[3]-'0', path->pack->checksum );
}
foundPak |= 0x01;
}
foundPak |= 1<<(pakBasename[3]-'0');
}
}
if( (!Cvar_VariableIntegerValue("com_standalone") ||
!fs_gamedirvar->string[0] ||
!Q_stricmp(fs_gamedirvar->string, BASEGAME) ||
!Q_stricmp(fs_gamedirvar->string, "missionpack") )
&&
(!founddemo && (foundPak & 0x1ff) != 0x1ff) )
if(!com_standalone->integer && (foundPak & 0x1ff) != 0x1ff)
{
char errorText[MAX_STRING_CHARS] = "";
if((foundPak&1) != 1 )
if((foundPak & 0x01) != 0x01)
{
Q_strcat(errorText, sizeof(errorText),
"\"pak0.pk3\" is missing. Please copy it "
"from your legitimate Q3 CDROM. ");
}
if((foundPak&0x1fe) != 0x1fe )
if((foundPak & 0x1fe) != 0x1fe)
{
Q_strcat(errorText, sizeof(errorText),
"Point Release files are missing. Please "
@ -2993,8 +3080,26 @@ static void FS_CheckPak0( void )
Com_Error(ERR_FATAL, "%s", errorText);
}
if(foundPak & 1)
Cvar_Set("com_standalone", "0");
if(!com_standalone->integer && foundTA && (foundTA & 0x0f) != 0x0f)
{
char errorText[MAX_STRING_CHARS] = "";
if((foundTA & 0x01) != 0x01)
{
Com_sprintf(errorText, sizeof(errorText),
"\"" BASETA "%cpak0.pk3\" is missing. Please copy it "
"from your legitimate Quake 3 Team Arena CDROM. ", PATH_SEP);
}
if((foundTA & 0x0e) != 0x0e)
{
Q_strcat(errorText, sizeof(errorText),
"Team Arena Point Release files are missing. Please "
"re-install the latest Team Arena point release.");
}
Com_Error(ERR_FATAL, "%s", errorText);
}
}
#endif
@ -3123,7 +3228,7 @@ 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 (search->pack->referenced || Q_stricmpn(search->pack->pakGamename, com_basegame->string, strlen(com_basegame->string))) {
Q_strcat( info, sizeof( info ), va("%i ", search->pack->checksum ) );
}
}
@ -3198,7 +3303,7 @@ 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 (search->pack->referenced || Q_stricmpn(search->pack->pakGamename, com_basegame->string, strlen(com_basegame->string))) {
if (*info) {
Q_strcat(info, sizeof( info ), " " );
}
@ -3362,7 +3467,7 @@ void FS_InitFilesystem( void ) {
Com_StartupVariable( "fs_game" );
// try to start up normally
FS_Startup( BASEGAME );
FS_Startup(com_basegame->string);
#ifndef STANDALONE
FS_CheckPak0( );
@ -3397,7 +3502,7 @@ void FS_Restart( int checksumFeed ) {
FS_ClearPakReferences(0);
// try to start up normally
FS_Startup( BASEGAME );
FS_Startup(com_basegame->string);
#ifndef STANDALONE
FS_CheckPak0( );

View file

@ -36,6 +36,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#else
#define PRODUCT_NAME "ioq3"
#define BASEGAME "baseq3"
#define BASETA "missionpack"
#define CLIENT_WINDOW_TITLE "ioquake3"
#define CLIENT_WINDOW_MIN_TITLE "ioq3"
#define GAMENAME_FOR_MASTER "Quake3Arena"

View file

@ -573,8 +573,9 @@ issues.
#define FS_UI_REF 0x02
#define FS_CGAME_REF 0x04
#define FS_QAGAME_REF 0x08
// number of id paks that will never be autodownloaded from baseq3
// number of id paks that will never be autodownloaded from baseq3/missionpack
#define NUM_ID_PAKS 9
#define NUM_TA_PAKS 4
#define MAX_FILE_HANDLES 64
@ -702,7 +703,7 @@ void FS_PureServerSetLoadedPaks( const char *pakSums, const char *pakNames );
// sole exception of .cfg files.
qboolean FS_CheckDirTraversal(const char *checkdir);
qboolean FS_idPak( char *pak, char *base );
qboolean FS_idPak(char *pak, char *base, int numPaks);
qboolean FS_ComparePaks( char *neededpaks, int len, qboolean dlstring );
void FS_Rename( const char *from, const char *to );
@ -831,6 +832,9 @@ extern cvar_t *com_maxfpsUnfocused;
extern cvar_t *com_minimized;
extern cvar_t *com_maxfpsMinimized;
extern cvar_t *com_altivec;
extern cvar_t *com_standalone;
extern cvar_t *com_basegame;
extern cvar_t *com_homepath;
// both client and server must agree to pause
extern cvar_t *cl_paused;

View file

@ -1279,7 +1279,7 @@ void SV_AddOperatorCommands( void ) {
Cmd_AddCommand ("heartbeat", SV_Heartbeat_f);
Cmd_AddCommand ("kick", SV_Kick_f);
#ifndef STANDALONE
if(!Cvar_VariableIntegerValue("com_standalone"))
if(!com_standalone->integer)
{
Cmd_AddCommand ("banUser", SV_Ban_f);
Cmd_AddCommand ("banClient", SV_BanNum_f);

View file

@ -97,7 +97,7 @@ void SV_GetChallenge(netadr_t from)
#ifndef STANDALONE
// Drop the authorize stuff if this client is coming in via v6 as the auth server does not support ipv6.
// Drop also for addresses coming in on local LAN and for stand-alone games independent from id's assets.
if(challenge->adr.type == NA_IP && !Cvar_VariableIntegerValue("com_standalone") && !Sys_IsLANAddress(from))
if(challenge->adr.type == NA_IP && !com_standalone->integer && !Sys_IsLANAddress(from))
{
// look up the authorize server's IP
if (svs.authorizeAddress.type == NA_BAD)
@ -882,8 +882,8 @@ void SV_WriteDownloadToClient( client_t *cl , msg_t *msg )
// now that we know the file is referenced,
// check whether it's legal to download it.
missionPack = FS_idPak(pakbuf, "missionpack");
idPack = missionPack || FS_idPak(pakbuf, BASEGAME);
missionPack = FS_idPak(pakbuf, BASETA, NUM_TA_PAKS);
idPack = missionPack || FS_idPak(pakbuf, BASEGAME, NUM_ID_PAKS);
break;
}

View file

@ -55,12 +55,20 @@ char *Sys_DefaultHomePath(void)
{
if( ( p = getenv( "HOME" ) ) != NULL )
{
Q_strncpyz( homePath, p, sizeof( homePath ) );
Com_sprintf(homePath, sizeof(homePath), "%s%c", p, PATH_SEP);
#ifdef MACOS_X
Q_strcat( homePath, sizeof( homePath ),
"/Library/Application Support/Quake3" );
Q_strcat(homePath, sizeof(homePath),
"Library/Application Support/");
if(com_homepath->string[0])
Q_strcat(homePath, sizeof(homePath), com_homepath->string);
else
Q_strcat(homePath, sizeof(homePath), "Quake3");
#else
Q_strcat( homePath, sizeof( homePath ), "/.q3a" );
if(com_homepath->string[0])
Q_strcat(homePath, sizeof(homePath), com_homepath->string);
else
Q_strcat(homePath, sizeof(homePath), ".q3a");
#endif
}
}

View file

@ -88,8 +88,14 @@ char *Sys_DefaultHomePath( void )
FreeLibrary(shfolder);
return NULL;
}
Q_strncpyz( homePath, szPath, sizeof( homePath ) );
Q_strcat( homePath, sizeof( homePath ), "\\Quake3" );
Com_Sprintf(homePath, sizeof(homePath), "%s%c", szPath, PATH_SEP);
if(com_homepath->string[0])
Q_strcat(homePath, sizeof(homePath), com_homepath->string);
else
Q_strcat(homePath, sizeof(homePath), "Quake3");
FreeLibrary(shfolder);
}

View file

@ -65,7 +65,7 @@ static const int numNetSources = sizeof(netSources) / sizeof(const char*);
static const serverFilter_t serverFilters[] = {
{"All", "" },
{"Quake 3 Arena", "" },
{"Team Arena", "missionpack" },
{"Team Arena", BASETA },
{"Rocket Arena", "arena" },
{"Alliance", "alliance20" },
{"Weapons Factory Arena", "wfa" },