From e2990314706a43f7efabadeb827ec00a1cad4df2 Mon Sep 17 00:00:00 2001 From: Tim Angus Date: Thu, 4 Sep 2025 23:27:43 +0200 Subject: [PATCH] Reduce duplication in FS path search code Co-authored-by: smallmodel <15067410+smallmodel@users.noreply.github.com> --- code/client/cl_main.cpp | 6 +- code/client/cl_parse.cpp | 4 +- code/client/cl_ui.cpp | 4 +- code/fgame/botlib.h | 105 +++++---- code/qcommon/common.c | 6 +- code/qcommon/files.cpp | 482 ++++++++++++++++++--------------------- code/qcommon/md5.c | 2 +- code/qcommon/qcommon.h | 21 +- code/server/sv_ccmds.c | 4 +- code/server/sv_client.c | 2 +- code/sys/sys_unix.c | 37 +-- code/sys/sys_win32.c | 57 +++-- 12 files changed, 347 insertions(+), 383 deletions(-) diff --git a/code/client/cl_main.cpp b/code/client/cl_main.cpp index b4302fbc..7dd8c149 100644 --- a/code/client/cl_main.cpp +++ b/code/client/cl_main.cpp @@ -937,7 +937,7 @@ static void CL_UpdateGUID( const char *prefix, int prefix_len ) fileHandle_t f; int len; - len = FS_SV_FOpenFileRead( QKEY_FILE, &f ); + len = FS_BaseDir_FOpenFileRead( QKEY_FILE, &f ); FS_FCloseFile( f ); if( len != QKEY_SIZE ) @@ -3500,7 +3500,7 @@ static void CL_GenerateQKey(void) unsigned char buff[ QKEY_SIZE ]; fileHandle_t f; - len = FS_SV_FOpenFileRead( QKEY_FILE, &f ); + len = FS_BaseDir_FOpenFileRead( QKEY_FILE, &f ); FS_FCloseFile( f ); if( len == QKEY_SIZE ) { Com_Printf( "QKEY found.\n" ); @@ -3515,7 +3515,7 @@ static void CL_GenerateQKey(void) Com_Printf( "QKEY building random string\n" ); Com_RandomBytes( buff, sizeof(buff) ); - f = FS_SV_FOpenFileWrite( QKEY_FILE ); + f = FS_BaseDir_FOpenFileWrite( QKEY_FILE ); if( !f ) { Com_Printf( "QKEY could not open %s for write\n", QKEY_FILE ); diff --git a/code/client/cl_parse.cpp b/code/client/cl_parse.cpp index 68a9cc7e..4e6b8f79 100644 --- a/code/client/cl_parse.cpp +++ b/code/client/cl_parse.cpp @@ -760,7 +760,7 @@ void CL_ParseDownload ( msg_t *msg ) { // open the file if not opened yet if (!clc.download) { - clc.download = FS_SV_FOpenFileWrite( clc.downloadTempName ); + clc.download = FS_BaseDir_FOpenFileWrite( clc.downloadTempName ); if (!clc.download) { Com_Printf( "Could not create %s\n", clc.downloadTempName ); @@ -787,7 +787,7 @@ void CL_ParseDownload ( msg_t *msg ) { clc.download = 0; // rename the file - FS_SV_Rename ( clc.downloadTempName, clc.downloadName, qfalse ); + FS_BaseDir_Rename ( clc.downloadTempName, clc.downloadName, qfalse ); } *clc.downloadTempName = *clc.downloadName = 0; Cvar_Set( "cl_downloadName", "" ); diff --git a/code/client/cl_ui.cpp b/code/client/cl_ui.cpp index 9abd0b2d..1ee622a4 100644 --- a/code/client/cl_ui.cpp +++ b/code/client/cl_ui.cpp @@ -291,7 +291,7 @@ void LAN_LoadCachedServers(void) fileHandle_t fileIn; cls.numglobalservers = cls.nummplayerservers = cls.numfavoriteservers = 0; cls.numGlobalServerAddresses = 0; - if (FS_SV_FOpenFileRead("servercache.dat", &fileIn)) { + if (FS_BaseDir_FOpenFileRead("servercache.dat", &fileIn)) { FS_Read(&cls.numglobalservers, sizeof(int), fileIn); FS_Read(&cls.nummplayerservers, sizeof(int), fileIn); FS_Read(&cls.numfavoriteservers, sizeof(int), fileIn); @@ -316,7 +316,7 @@ LAN_SaveServersToCache void LAN_SaveServersToCache(void) { int size; - fileHandle_t fileOut = FS_SV_FOpenFileWrite("servercache.dat"); + fileHandle_t fileOut = FS_BaseDir_FOpenFileWrite("servercache.dat"); FS_Write(&cls.numglobalservers, sizeof(int), fileOut); FS_Write(&cls.nummplayerservers, sizeof(int), fileOut); FS_Write(&cls.numfavoriteservers, sizeof(int), fileOut); diff --git a/code/fgame/botlib.h b/code/fgame/botlib.h index d96340a4..1b1c4bdd 100644 --- a/code/fgame/botlib.h +++ b/code/fgame/botlib.h @@ -1,20 +1,34 @@ -// Copyright (C) 1999-2000 Id Software, Inc. +/* +=========================================================================== +Copyright (C) 1999-2005 Id Software, Inc. + +This file is part of Quake III Arena source code. + +Quake III Arena source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake III Arena source code is distributed in the hope that it will be +useful, but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Quake III Arena source code; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ // /***************************************************************************** * name: botlib.h * * desc: bot AI library * - * $Archive: /EF2/Code/DLLs/game/botlib.h $ - * $Author: Singlis $ - * $Revision: 5 $ - * $Modtime: 9/24/03 3:09p $ - * $Date: 9/26/03 2:35p $ + * $Archive: /source/code/game/botai.h $ * *****************************************************************************/ -#pragma once - #define BOTLIB_API_VERSION 2 struct aas_clientmove_s; @@ -65,30 +79,30 @@ struct weaponinfo_s; #define BLERR_CANNOTLOADWEAPONCONFIG 12 //cannot load weapon config //action flags -#define ACTION_ATTACK 0x0000001 -#define ACTION_ATTACKRIGHT 0x0000002 -#define ACTION_USE 0x0000004 -#define ACTION_RESPAWN 0x0000008 -#define ACTION_JUMP 0x0000010 -#define ACTION_MOVEUP 0x0000020 -#define ACTION_CROUCH 0x0000080 -#define ACTION_MOVEDOWN 0x0000100 -#define ACTION_MOVEFORWARD 0x0000200 -#define ACTION_MOVEBACK 0x0000800 -#define ACTION_MOVELEFT 0x0001000 -#define ACTION_MOVERIGHT 0x0002000 -#define ACTION_DELAYEDJUMP 0x0008000 -#define ACTION_TALK 0x0010000 -#define ACTION_GESTURE 0x0020000 -#define ACTION_WALK 0x0080000 -#define ACTION_AFFIRMATIVE 0x0100000 -#define ACTION_NEGATIVE 0x0200000 -#define ACTION_GETFLAG 0x0800000 -#define ACTION_GUARDBASE 0x1000000 -#define ACTION_PATROL 0x2000000 -#define ACTION_FOLLOWME 0x8000000 +#define ACTION_ATTACK 0x00000001 +#define ACTION_USE 0x00000002 +#define ACTION_RESPAWN 0x00000008 +#define ACTION_JUMP 0x00000010 +#define ACTION_MOVEUP 0x00000020 +#define ACTION_CROUCH 0x00000080 +#define ACTION_MOVEDOWN 0x00000100 +#define ACTION_MOVEFORWARD 0x00000200 +#define ACTION_MOVEBACK 0x00000800 +#define ACTION_MOVELEFT 0x00001000 +#define ACTION_MOVERIGHT 0x00002000 +#define ACTION_DELAYEDJUMP 0x00008000 +#define ACTION_TALK 0x00010000 +#define ACTION_GESTURE 0x00020000 +#define ACTION_WALK 0x00080000 +#define ACTION_AFFIRMATIVE 0x00100000 +#define ACTION_NEGATIVE 0x00200000 +#define ACTION_GETFLAG 0x00800000 +#define ACTION_GUARDBASE 0x01000000 +#define ACTION_PATROL 0x02000000 +#define ACTION_FOLLOWME 0x08000000 +#define ACTION_JUMPEDLASTFRAME 0x10000000 -//the bot input, will be converted to an usercmd_t +//the bot input, will be converted to a usercmd_t typedef struct bot_input_s { float thinktime; //time since last output (in seconds) @@ -96,8 +110,7 @@ typedef struct bot_input_s float speed; //speed in the range [0, 400] vec3_t viewangles; //the view angles int actionflags; //one of the ACTION_? flags - int weapon,latchweapon; //weapon to use - int firestate; //right/left hand fire state + int weapon; //weapon to use } bot_input_t; #ifndef BSPTRACE @@ -157,7 +170,7 @@ typedef struct bot_entitystate_s typedef struct botlib_import_s { //print messages from the bot library - void (QDECL *Print)(int type, char *fmt, ...); + void (QDECL *Print)(int type, char *fmt, ...) __attribute__ ((format (printf, 2, 3))); //trace a bbox through the world void (*Trace)(bsp_trace_t *trace, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, int passent, int contentmask); //trace a bbox against a specific entity @@ -171,7 +184,7 @@ typedef struct botlib_import_s // void (*BSPModelMinsMaxsOrigin)(int modelnum, vec3_t angles, vec3_t mins, vec3_t maxs, vec3_t origin); //send a bot client command - void (*BotClientCommand)(int client, const char *command); // was char *, changed for c++ compilation + void (*BotClientCommand)(int client, char *command); //memory allocation void *(*GetMemory)(int size); // allocate from Zone void (*FreeMemory)(void *ptr); // free memory from Zone @@ -255,15 +268,14 @@ typedef struct aas_export_s typedef struct ea_export_s { //ClientCommand elementary actions - void (*EA_Command)(int client, const char *command ); + void (*EA_Command)(int client, char *command ); void (*EA_Say)(int client, char *str); void (*EA_SayTeam)(int client, char *str); // void (*EA_Action)(int client, int action); void (*EA_Gesture)(int client); void (*EA_Talk)(int client); - void (*EA_ToggleFireState)(int client); - void (*EA_Attack)(int client, int primarydangerous, int altdangerous); + void (*EA_Attack)(int client); void (*EA_Use)(int client); void (*EA_Respawn)(int client); void (*EA_MoveUp)(int client); @@ -397,15 +409,15 @@ typedef struct botlib_export_s //shutdown the bot library, returns BLERR_ int (*BotLibShutdown)(void); //sets a library variable returns BLERR_ - int (*BotLibVarSet)(char *var_name, char *value); + int (*BotLibVarSet)(const char *var_name, const char *value); //gets a library variable returns BLERR_ - int (*BotLibVarGet)(char *var_name, char *value, int size); + int (*BotLibVarGet)(const char *var_name, char *value, int size); //sets a C-like define returns BLERR_ int (*PC_AddGlobalDefine)(char *string); int (*PC_LoadSourceHandle)(const char *filename); int (*PC_FreeSourceHandle)(int handle); -// int (*PC_ReadTokenHandle)(int handle, pc_token_t *pc_token); + int (*PC_ReadTokenHandle)(int handle, pc_token_t *pc_token); int (*PC_SourceFileAndLine)(int handle, char *filename, int *line); //start a frame in the bot library @@ -415,7 +427,7 @@ typedef struct botlib_export_s //entity updates int (*BotLibUpdateEntity)(int ent, bot_entitystate_t *state); //just for testing - int (*Test)(int parm0, int parm1, vec3_t parm2, vec3_t parm3); + int (*Test)(int parm0, char *parm1, vec3_t parm2, vec3_t parm3); } botlib_export_t; //linking of bot library @@ -425,14 +437,14 @@ botlib_export_t *GetBotLibAPI( int apiVersion, botlib_import_t *import ); name: default: module(s): description: -"basedir" "" l_utils.c base directory -"gamedir" "" l_utils.c game directory -"cddir" "" l_utils.c CD directory +"basedir" "" - base directory +"gamedir" "" be_interface.c mod game directory +"basegame" "" be_interface.c base game directory "log" "0" l_log.c enable/disable creating a log file "maxclients" "4" be_interface.c maximum number of clients "maxentities" "1024" be_interface.c maximum number of entities -"bot_developer" "0" be_interface.c bot developer mode +"bot_developer" "0" be_interface.c bot developer mode (it's "botDeveloper" in C to prevent symbol clash). "phys_friction" "6" be_aas_move.c ground friction "phys_stopspeed" "100" be_aas_move.c stop speed @@ -502,3 +514,4 @@ name: default: module(s): description: "max_levelitems" "256" be_ai_goal.c maximum number of level items */ + diff --git a/code/qcommon/common.c b/code/qcommon/common.c index 452066a9..fb293386 100644 --- a/code/qcommon/common.c +++ b/code/qcommon/common.c @@ -1556,7 +1556,7 @@ void Com_ReadCDKey( const char *filename ) { Com_sprintf(fbuffer, sizeof(fbuffer), "%s/q3key", filename); - FS_SV_FOpenFileRead( fbuffer, &f ); + FS_BaseDir_FOpenFileRead( fbuffer, &f ); if ( !f ) { Com_Memset( cl_cdkey, '\0', 17 ); return; @@ -1586,7 +1586,7 @@ void Com_AppendCDKey( const char *filename ) { Com_sprintf(fbuffer, sizeof(fbuffer), "%s/q3key", filename); - FS_SV_FOpenFileRead( fbuffer, &f ); + FS_BaseDir_FOpenFileRead( fbuffer, &f ); if (!f) { Com_Memset( &cl_cdkey[16], '\0', 17 ); return; @@ -1631,7 +1631,7 @@ static void Com_WriteCDKey( const char *filename, const char *ikey ) { #ifndef _WIN32 savedumask = umask(0077); #endif - f = FS_SV_FOpenFileWrite( fbuffer ); + f = FS_BaseDir_FOpenFileWrite( fbuffer ); if ( !f ) { Com_Printf ("Couldn't write CD key to %s.\n", fbuffer ); goto out; diff --git a/code/qcommon/files.cpp b/code/qcommon/files.cpp index 5c94ab76..fe043c17 100644 --- a/code/qcommon/files.cpp +++ b/code/qcommon/files.cpp @@ -247,10 +247,7 @@ static char fs_gamedir[MAX_OSPATH]; // this will be a single file name with no cvar_t *fs_debug; static cvar_t *fs_homepath; -#ifdef __APPLE__ -// Also search the .app bundle for .pk3 files -static cvar_t *fs_apppath; -#endif +static cvar_t *fs_apppath; static cvar_t *fs_steampath; static cvar_t *fs_gogpath; static cvar_t *fs_microsoftstorepath; @@ -263,7 +260,15 @@ static int fs_loadCount; // total files read static int fs_loadStack; // total files in memory static int fs_packFiles = 0; // total number of files in packs -static int fs_fakeChkSum; +static cvar_t** const fs_pathVars[] = { + &fs_homepath, + &fs_basepath, + &fs_apppath, + &fs_steampath, + &fs_gogpath, + &fs_microsoftstorepath +}; + static int fs_checksumFeed; static cvar_t* fs_gamedirvar; @@ -644,6 +649,20 @@ char *FS_BuildOSPath( const char *base, const char *game, const char *qpath ) { return ospath[ toggle ]; } +/* +=================== +FS_BaseDir_BuildOSPath + +Qpath may have either forward or backwards slashes +=================== +*/ +char *FS_BaseDir_BuildOSPath( const char *base, const char *qpath ) { + char *ospath = FS_BuildOSPath(base, qpath, ""); + ospath[strlen(ospath) - 1] = '\0'; + + return ospath; +} + /* ============ @@ -652,10 +671,14 @@ FS_CreatePath Creates any directories needed to store the given filename ============ */ -qboolean FS_CreatePath (char *OSPath) { +qboolean FS_CreatePath (const char *OSPath) { char *ofs; char path[MAX_OSPATH]; + if (!OSPath || !*OSPath) { + return qfalse; + } + // make absolutely sure that it can't back up the path // FIXME: is c: allowed??? if ( strstr( OSPath, ".." ) || strstr( OSPath, "::" ) ) { @@ -771,43 +794,33 @@ qboolean FS_FileExists(const char *file) /* ================ -FS_SV_FileExists +FS_BaseDir_FileExists Tests if the file exists ================ */ -qboolean FS_SV_FileExists( const char *file ) +qboolean FS_BaseDir_FileExists( const char *file ) { - char *testpath; - - testpath = FS_BuildOSPath( fs_homepath->string, file, ""); - testpath[strlen(testpath)-1] = '\0'; - - return FS_FileInPathExists(testpath); + return FS_FileInPathExists(FS_BaseDir_BuildOSPath(fs_homepath->string, file)); } /* =========== -FS_SV_FOpenFileWrite - +FS_OSPath_FOpenFileWrite =========== */ -fileHandle_t FS_SV_FOpenFileWrite( const char *filename ) { - char *ospath; +static fileHandle_t FS_OSPath_FOpenFileWrite( const char *ospath, const char *filename ) { fileHandle_t f; if ( !fs_searchpaths ) { Com_Error( ERR_FATAL, "Filesystem call made without initialization" ); } - ospath = FS_BuildOSPath( fs_homepath->string, filename, "" ); - ospath[strlen(ospath)-1] = '\0'; - f = FS_HandleForFile(); fsh[f].zipFile = qfalse; if ( fs_debug->integer ) { - Com_Printf( "FS_SV_FOpenFileWrite: %s\n", ospath ); + Com_Printf( "FS_OSPath_FOpenFileWrite: %s\n", ospath ); } FS_CheckFilenameIsMutable( ospath, __func__ ); @@ -816,7 +829,6 @@ fileHandle_t FS_SV_FOpenFileWrite( const char *filename ) { return 0; } - Com_DPrintf( "writing to: %s\n", ospath ); fsh[f].handleFiles.file.o = Sys_FOpen( ospath, "wb" ); Q_strncpyz( fsh[f].name, filename, sizeof( fsh[f].name ) ); @@ -830,16 +842,28 @@ fileHandle_t FS_SV_FOpenFileWrite( const char *filename ) { /* =========== -FS_SV_FOpenFileRead +FS_BaseDir_FOpenFileWrite + +=========== +*/ +fileHandle_t FS_BaseDir_FOpenFileWrite( const char *filename ) { + return FS_OSPath_FOpenFileWrite( + FS_BaseDir_BuildOSPath(fs_homepath->string, filename), filename); +} + +/* +=========== +FS_BaseDir_FOpenFileRead Search for a file somewhere below the home path then base path in that order =========== */ -long FS_SV_FOpenFileRead(const char *filename, fileHandle_t *fp) +long FS_BaseDir_FOpenFileRead(const char *filename, fileHandle_t *fp) { char *ospath; - fileHandle_t f = 0; + fileHandle_t f = 0; + qboolean skipHome = !Q_stricmp(fs_homepath->string, fs_basepath->string); if ( !fs_searchpaths ) { Com_Error( ERR_FATAL, "Filesystem call made without initialization" ); @@ -853,69 +877,32 @@ long FS_SV_FOpenFileRead(const char *filename, fileHandle_t *fp) // don't let sound stutter S_ClearSoundBuffer(); - // search homepath - ospath = FS_BuildOSPath( fs_homepath->string, filename, "" ); - // remove trailing slash - ospath[strlen(ospath)-1] = '\0'; + for(int i = 0; i < ARRAY_LEN( fs_pathVars ) && !fsh[f].handleFiles.file.o; i++) { + const cvar_t *pathVar = *fs_pathVars[i]; - if ( fs_debug->integer ) { - Com_Printf( "FS_SV_FOpenFileRead (fs_homepath): %s\n", ospath ); + if (!pathVar || !pathVar->string[0]) { + continue; + } + + if (skipHome && pathVar == fs_homepath) { + // home == base, skip + continue; + } + + ospath = FS_BaseDir_BuildOSPath( pathVar->string, filename ); + + if ( fs_debug->integer ) + { + Com_Printf( "FS_BaseDir_FOpenFileRead (%s): %s\n", pathVar->name, ospath ); + } + + fsh[f].handleFiles.file.o = Sys_FOpen( ospath, "rb" ); + fsh[f].handleSync = qfalse; } - fsh[f].handleFiles.file.o = Sys_FOpen( ospath, "rb" ); - fsh[f].handleSync = qfalse; if (!fsh[f].handleFiles.file.o) { - // If fs_homepath == fs_basepath, don't bother - if (Q_stricmp(fs_homepath->string,fs_basepath->string)) - { - // search basepath - ospath = FS_BuildOSPath( fs_basepath->string, filename, "" ); - ospath[strlen(ospath)-1] = '\0'; - - if ( fs_debug->integer ) - { - Com_Printf( "FS_SV_FOpenFileRead (fs_basepath): %s\n", ospath ); - } - - fsh[f].handleFiles.file.o = Sys_FOpen( ospath, "rb" ); - fsh[f].handleSync = qfalse; - } - - // Check fs_steampath - if (!fsh[f].handleFiles.file.o && fs_steampath->string[0]) - { - ospath = FS_BuildOSPath( fs_steampath->string, filename, "" ); - ospath[strlen(ospath)-1] = '\0'; - - if ( fs_debug->integer ) - { - Com_Printf( "FS_SV_FOpenFileRead (fs_steampath): %s\n", ospath ); - } - - fsh[f].handleFiles.file.o = Sys_FOpen( ospath, "rb" ); - fsh[f].handleSync = qfalse; - } - - // Check fs_gogpath - if (!fsh[f].handleFiles.file.o && fs_gogpath->string[0]) - { - ospath = FS_BuildOSPath( fs_gogpath->string, filename, "" ); - ospath[strlen(ospath)-1] = '\0'; - - if ( fs_debug->integer ) - { - Com_Printf( "FS_SV_FOpenFileRead (fs_gogpath): %s\n", ospath ); - } - - fsh[f].handleFiles.file.o = Sys_FOpen( ospath, "rb" ); - fsh[f].handleSync = qfalse; - } - - if ( !fsh[f].handleFiles.file.o ) - { - f = 0; - } + f = 0; } *fp = f; @@ -929,11 +916,11 @@ long FS_SV_FOpenFileRead(const char *filename, fileHandle_t *fp) /* =========== -FS_SV_Rename +FS_BaseDir_Rename =========== */ -void FS_SV_Rename( const char *from, const char *to, qboolean safe ) { +void FS_BaseDir_Rename( const char *from, const char *to, qboolean safe ) { char *from_ospath, *to_ospath; if ( !fs_searchpaths ) { @@ -943,13 +930,11 @@ void FS_SV_Rename( const char *from, const char *to, qboolean safe ) { // don't let sound stutter S_ClearSoundBuffer(); - from_ospath = FS_BuildOSPath( fs_homepath->string, from, "" ); - to_ospath = FS_BuildOSPath( fs_homepath->string, to, "" ); - from_ospath[strlen(from_ospath)-1] = '\0'; - to_ospath[strlen(to_ospath)-1] = '\0'; + from_ospath = FS_BaseDir_BuildOSPath( fs_homepath->string, from ); + to_ospath = FS_BaseDir_BuildOSPath( fs_homepath->string, to ); if ( fs_debug->integer ) { - Com_Printf( "FS_SV_Rename: %s --> %s\n", from_ospath, to_ospath ); + Com_Printf( "FS_BaseDir_Rename: %s --> %s\n", from_ospath, to_ospath ); } if ( safe ) { @@ -959,36 +944,6 @@ void FS_SV_Rename( const char *from, const char *to, qboolean safe ) { rename(from_ospath, to_ospath); } - - -/* -=========== -FS_Rename - -=========== -*/ -void FS_Rename( const char *from, const char *to ) { - char *from_ospath, *to_ospath; - - if ( !fs_searchpaths ) { - Com_Error( ERR_FATAL, "Filesystem call made without initialization\n" ); - } - - // don't let sound stutter - S_ClearSoundBuffer(); - - from_ospath = FS_BuildOSPath( fs_homepath->string, fs_gamedir, from ); - to_ospath = FS_BuildOSPath( fs_homepath->string, fs_gamedir, to ); - - if ( fs_debug->integer ) { - Com_Printf( "FS_Rename: %s --> %s\n", from_ospath, to_ospath ); - } - - FS_CheckFilenameIsMutable( to_ospath, __func__ ); - - rename(from_ospath, to_ospath); -} - /* ============== FS_FCloseFile @@ -1027,40 +982,8 @@ FS_FOpenFileWrite =========== */ fileHandle_t FS_FOpenFileWrite( const char *filename ) { - char *ospath; - fileHandle_t f; - - if ( !fs_searchpaths ) { - Com_Error( ERR_FATAL, "Filesystem call made without initialization" ); - } - - f = FS_HandleForFile(); - fsh[f].zipFile = qfalse; - - ospath = FS_BuildOSPath( fs_homepath->string, fs_gamedir, filename ); - - if ( fs_debug->integer ) { - Com_Printf( "FS_FOpenFileWrite: %s\n", ospath ); - } - - FS_CheckFilenameIsMutable( ospath, __func__ ); - - if( FS_CreatePath( ospath ) ) { - return 0; - } - - // enabling the following line causes a recursive function call loop - // when running with +set logfile 1 +set developer 1 - //Com_DPrintf( "writing to: %s\n", ospath ); - fsh[f].handleFiles.file.o = Sys_FOpen( ospath, "wb" ); - - Q_strncpyz( fsh[f].name, filename, sizeof( fsh[f].name ) ); - - fsh[f].handleSync = qfalse; - if (!fsh[f].handleFiles.file.o) { - f = 0; - } - return f; + return FS_OSPath_FOpenFileWrite( + FS_BuildOSPath(fs_homepath->string, fs_gamedir, filename), filename); } /* @@ -2652,7 +2575,7 @@ void FS_GetModDescription( const char *modDir, char *description, int descriptio FILE *file; Com_sprintf( descPath, sizeof ( descPath ), "%s%cdescription.txt", modDir, PATH_SEP ); - nDescLen = FS_SV_FOpenFileRead( descPath, &descHandle ); + nDescLen = FS_BaseDir_FOpenFileRead( descPath, &descHandle ); if ( nDescLen > 0 ) { file = FS_FileForHandle(descHandle); @@ -2690,15 +2613,18 @@ int FS_GetModList( char *listbuf, int bufsize ) { char **pFiles0 = NULL; qboolean bDrop = qfalse; - // paths to search for mods - const char * const paths[] = { fs_basepath->string, fs_homepath->string, fs_steampath->string, fs_gogpath->string }; - *listbuf = 0; nMods = nTotal = 0; // iterate through paths and get list of potential mods - for (i = 0; i < ARRAY_LEN(paths); i++) { - pFiles0 = Sys_ListFiles(paths[i], NULL, NULL, &dummy, qtrue); + for (i = 0; i < ARRAY_LEN(fs_pathVars); i++) { + const cvar_t *pathVar = *fs_pathVars[i]; + + if (!pathVar || !pathVar->string[0]) { + continue; + } + + pFiles0 = Sys_ListFiles(pathVar->string, NULL, NULL, &dummy, qtrue); // Sys_ConcatenateFileLists frees the lists so Sys_FreeFileList isn't required pFiles = Sys_ConcatenateFileLists(pFiles, pFiles0); } @@ -2727,8 +2653,14 @@ int FS_GetModList( char *listbuf, int bufsize ) { // in order to be a valid mod the directory must contain at least one .pk3 or .pk3dir // we didn't keep the information when we merged the directory names, as to what OS Path it was found under // so we will try each of them here - for (j = 0; j < ARRAY_LEN(paths); j++) { - path = FS_BuildOSPath(paths[j], name, ""); + for (j = 0; j < ARRAY_LEN(fs_pathVars); j++) { + const cvar_t *pathVar = *fs_pathVars[j]; + + if (!pathVar || !pathVar->string[0]) { + continue; + } + + path = FS_BaseDir_BuildOSPath(pathVar->string, name); nPaks = nDirs = nPakDirs = 0; pPaks = Sys_ListFiles(path, ".pk3", NULL, &nPaks, qfalse); pDirs = Sys_ListFiles(path, "/", NULL, &nDirs, qfalse); @@ -3081,17 +3013,21 @@ then loads the zip headers ================ */ void FS_AddGameDirectory(const char *path, const char *dir) { - FS_AddGameDirectory2(path, dir, false); -} - -void FS_AddGameDirectory2( const char *path, const char *dir, qboolean original_paks_priority) { searchpath_t *sp; - int i; searchpath_t *search; pack_t *pak; - char *pakfile; + char curpath[MAX_OSPATH + 1], *pakfile; int numfiles; char **pakfiles; + int pakfilesi; + char **pakfilestmp; + int numdirs; + char **pakdirs; + int pakdirsi; + char **pakdirstmp; + + int pakwhich; + int len; // Unique for ( sp = fs_searchpaths ; sp ; sp = sp->next ) { @@ -3103,59 +3039,133 @@ void FS_AddGameDirectory2( const char *path, const char *dir, qboolean original_ Q_strncpyz( fs_gamedir, dir, sizeof( fs_gamedir ) ); // find all pak files in this directory - pakfile = FS_BuildOSPath( path, dir, "" ); - pakfile[ strlen(pakfile) - 1 ] = 0; // strip the trailing slash + Q_strncpyz(curpath, FS_BaseDir_BuildOSPath(path, dir), sizeof(curpath)); - pakfiles = Sys_ListFiles( pakfile, ".pk3", NULL, &numfiles, qfalse ); + // Get .pk3 files + pakfiles = Sys_ListFiles(curpath, ".pk3", NULL, &numfiles, qfalse); - qsort(pakfiles, numfiles, sizeof(char*), paksort); - - if (original_paks_priority) - { - if (!stricmp(dir, "main")) - { - FS_SortOriginalPaks(pakfiles, numfiles, fs_originalPaks_main, sizeof(fs_originalPaks_main)/sizeof(fs_originalPaks_main[0])); - } - else if (!stricmp(dir, "mainta")) - { - FS_SortOriginalPaks(pakfiles, numfiles, fs_originalPaks_mainta, sizeof(fs_originalPaks_mainta) / sizeof(fs_originalPaks_mainta[0])); - } - else if (!stricmp(dir, "maintt")) - { - FS_SortOriginalPaks(pakfiles, numfiles, fs_originalPaks_maintt, sizeof(fs_originalPaks_maintt) / sizeof(fs_originalPaks_maintt[0])); - } + if ( pakfiles ) { + qsort( pakfiles, numfiles, sizeof(char*), paksort ); } - for ( i = 0 ; i < numfiles ; i++ ) { - pakfile = FS_BuildOSPath( path, dir, pakfiles[i] ); - if ( ( pak = FS_LoadZipFile( pakfile, pakfiles[i] ) ) == 0 ) - continue; - // store the game name for downloading - strcpy(pak->pakGamename, dir); + if ( fs_numServerPaks ) { + numdirs = 0; + pakdirs = NULL; + } else { + // Get top level directories (we'll filter them later since the Sys_ListFiles filtering is terrible) + pakdirs = Sys_ListFiles(curpath, "/", NULL, &numdirs, qfalse); - search = (searchpath_t*)Z_Malloc (sizeof(searchpath_t)); - search->pack = pak; - search->next = fs_searchpaths; - search->dir = NULL; - fs_searchpaths = search; + qsort( pakdirs, numdirs, sizeof(char *), paksort ); + } + + pakfilesi = 0; + pakdirsi = 0; + + while((pakfilesi < numfiles) || (pakdirsi < numdirs)) + { + // Check if a pakfile or pakdir comes next + if (pakfilesi >= numfiles) { + // We've used all the pakfiles, it must be a pakdir. + pakwhich = 0; + } + else if (pakdirsi >= numdirs) { + // We've used all the pakdirs, it must be a pakfile. + pakwhich = 1; + } + else { + // Could be either, compare to see which name comes first + // Need tmp variables for appropriate indirection for paksort() + pakfilestmp = &pakfiles[pakfilesi]; + pakdirstmp = &pakdirs[pakdirsi]; + pakwhich = (paksort(pakfilestmp, pakdirstmp) < 0); + } + + if (pakwhich) { + // The next .pk3 file is before the next .pk3dir + pakfile = FS_BuildOSPath(path, dir, pakfiles[pakfilesi]); + if ((pak = FS_LoadZipFile(pakfile, pakfiles[pakfilesi])) == 0) { + // This isn't a .pk3! Next! + pakfilesi++; + continue; + } + + Q_strncpyz(pak->pakPathname, curpath, sizeof(pak->pakPathname)); + // store the game name for downloading + Q_strncpyz(pak->pakGamename, dir, sizeof(pak->pakGamename)); + + fs_packFiles += pak->numfiles; + + search = (searchpath_t*)Z_Malloc(sizeof(searchpath_t)); + search->pack = pak; + search->next = fs_searchpaths; + fs_searchpaths = search; + + pakfilesi++; + } + else { + // The next .pk3dir is before the next .pk3 file + // But wait, this could be any directory, we're filtering to only ending with ".pk3dir" here. + len = strlen(pakdirs[pakdirsi]); + if (!FS_IsExt(pakdirs[pakdirsi], ".pk3dir", len)) { + // This isn't a .pk3dir! Next! + pakdirsi++; + continue; + } + + pakfile = FS_BuildOSPath(path, dir, pakdirs[pakdirsi]); + + // add the directory to the search path + search = (searchpath_t*)Z_Malloc(sizeof(searchpath_t)); + search->dir = (directory_t*)Z_Malloc(sizeof(*search->dir)); + + Q_strncpyz(search->dir->path, curpath, sizeof(search->dir->path)); // c:\quake3\baseq3 + Q_strncpyz(search->dir->fullpath, pakfile, sizeof(search->dir->fullpath)); // c:\quake3\baseq3\mypak.pk3dir + Q_strncpyz(search->dir->gamedir, pakdirs[pakdirsi], sizeof(search->dir->gamedir)); // mypak.pk3dir + + search->next = fs_searchpaths; + fs_searchpaths = search; + + pakdirsi++; + } } // done Sys_FreeFileList( pakfiles ); + Sys_FreeFileList( pakdirs ); // // add the directory to the search path // - search = (searchpath_t*)Z_Malloc( sizeof( searchpath_t ) ); + search = (searchpath_t*)Z_Malloc (sizeof(searchpath_t)); search->dir = (directory_t*)Z_Malloc( sizeof( *search->dir ) ); - search->pack = NULL; - Q_strncpyz( search->dir->path, path, sizeof( search->dir->path ) ); - Q_strncpyz( search->dir->gamedir, dir, sizeof( search->dir->gamedir ) ); + Q_strncpyz(search->dir->path, path, sizeof(search->dir->path)); + Q_strncpyz(search->dir->fullpath, curpath, sizeof(search->dir->fullpath)); + Q_strncpyz(search->dir->gamedir, dir, sizeof(search->dir->gamedir)); + search->next = fs_searchpaths; fs_searchpaths = search; } +/* +================ +FS_AddGameDirectories +================ +*/ +static void FS_AddGameDirectories(const char *dir) +{ + // add search path elements in reverse priority order + for(int i = ARRAY_LEN(fs_pathVars) - 1; i >= 0; i--) { + const cvar_t *pathVar = *fs_pathVars[i]; + + if (!pathVar || !pathVar->string[0]) { + continue; + } + + FS_AddGameDirectory(pathVar->string, dir); + } +} + /* ================ FS_idPak @@ -3290,7 +3300,7 @@ qboolean FS_ComparePaks( char *neededpaks, int len, qboolean dlstring ) { // Local name Q_strcat( neededpaks, len, "@"); // Do we have one with the same name? - if ( FS_SV_FileExists( va( "%s.pk3", fs_serverReferencedPakNames[i] ) ) ) + if ( FS_BaseDir_FileExists( va( "%s.pk3", fs_serverReferencedPakNames[i] ) ) ) { char st[MAX_ZPATH]; // We already have one called this, we need to download it to another name @@ -3317,7 +3327,7 @@ qboolean FS_ComparePaks( char *neededpaks, int len, qboolean dlstring ) { Q_strcat( neededpaks, len, fs_serverReferencedPakNames[i] ); Q_strcat( neededpaks, len, ".pk3" ); // Do we have one with the same name? - if ( FS_SV_FileExists( va( "%s.pk3", fs_serverReferencedPakNames[i] ) ) ) + if ( FS_BaseDir_FileExists( va( "%s.pk3", fs_serverReferencedPakNames[i] ) ) ) { Q_strcat( neededpaks, len, " (local file exists with wrong checksum)"); } @@ -3450,6 +3460,13 @@ static void FS_Startup(const char* gameName) fs_homepath = Cvar_Get ("fs_homepath", homePath, CVAR_INIT|CVAR_PROTECTED ); fs_gamedirvar = Cvar_Get ("fs_game", "", CVAR_INIT|CVAR_SYSTEMINFO ); fs_restrict = Cvar_Get( "fs_restrict", "", CVAR_INIT ); + fs_steampath = Cvar_Get ("fs_steampath", Sys_SteamPath(), CVAR_INIT|CVAR_PROTECTED ); + fs_gogpath = Cvar_Get ("fs_gogpath", Sys_GogPath(), CVAR_INIT|CVAR_PROTECTED ); + fs_microsoftstorepath = Cvar_Get ("fs_microsoftstorepath", Sys_MicrosoftStorePath(), CVAR_INIT|CVAR_PROTECTED ); + +#ifdef __APPLE__ + fs_apppath = Cvar_Get ("fs_apppath", Sys_DefaultAppPath(), CVAR_INIT|CVAR_PROTECTED ); +#endif if (!gameName[0]) { Cvar_ForceReset( "com_basegame" ); @@ -3473,66 +3490,19 @@ static void FS_Startup(const char* gameName) Com_Error( ERR_DROP, "Invalid fs_game '%s'", fs_gamedirvar->string ); } - // add search path elements in reverse priority order - fs_microsoftstorepath = Cvar_Get("fs_microsoftstorepath", Sys_MicrosoftStorePath(), CVAR_INIT | CVAR_PROTECTED); - if (fs_microsoftstorepath->string[0]) { - FS_AddGameDirectory(fs_microsoftstorepath->string, gameName); - } - fs_gogpath = Cvar_Get ("fs_gogpath", Sys_GogPath(), CVAR_INIT|CVAR_PROTECTED ); - if (fs_gogpath->string[0]) { - FS_AddGameDirectory( fs_gogpath->string, gameName ); - } - fs_steampath = Cvar_Get ("fs_steampath", Sys_SteamPath(), CVAR_INIT|CVAR_PROTECTED ); - if (fs_steampath->string[0]) { - FS_AddGameDirectory( fs_steampath->string, gameName ); - } - if (fs_basepath->string[0]) { - FS_AddGameDirectory( fs_basepath->string, gameName ); - } - // fs_homepath is somewhat particular to *nix systems, only add if relevant -#ifdef __APPLE__ - fs_apppath = Cvar_Get ("fs_apppath", Sys_DefaultAppPath(), CVAR_INIT|CVAR_PROTECTED ); - // Make MacOSX also include the base path included with the .app bundle - if (fs_apppath->string[0]) - FS_AddGameDirectory(fs_apppath->string, gameName); -#endif - - // NOTE: same filtering below for mods and basegame - if (fs_homepath->string[0] && Q_stricmp(fs_homepath->string,fs_basepath->string)) { + if (fs_homepath->string[0] && Q_stricmp(fs_homepath->string, fs_basepath->string)) { FS_CreatePath ( fs_homepath->string ); - FS_AddGameDirectory ( fs_homepath->string, gameName ); } + FS_AddGameDirectories(gameName); // check for additional base game so mods can be based upon other mods if ( fs_basegame->string[0] && Q_stricmp( fs_basegame->string, gameName ) ) { - if (fs_gogpath->string[0]) { - FS_AddGameDirectory(fs_gogpath->string, fs_basegame->string); - } - if (fs_steampath->string[0]) { - FS_AddGameDirectory(fs_steampath->string, fs_basegame->string); - } - if (fs_basepath->string[0]) { - FS_AddGameDirectory(fs_basepath->string, fs_basegame->string); - } - if (fs_homepath->string[0] && Q_stricmp(fs_homepath->string,fs_basepath->string)) { - FS_AddGameDirectory(fs_homepath->string, fs_basegame->string); - } + FS_AddGameDirectories(fs_basegame->string); } // check for additional game folder for mods if ( fs_gamedirvar->string[0] && Q_stricmp( fs_gamedirvar->string, gameName ) ) { - if (fs_gogpath->string[0]) { - FS_AddGameDirectory(fs_gogpath->string, fs_gamedirvar->string); - } - if (fs_steampath->string[0]) { - FS_AddGameDirectory(fs_steampath->string, fs_gamedirvar->string); - } - if (fs_basepath->string[0]) { - FS_AddGameDirectory(fs_basepath->string, fs_gamedirvar->string); - } - if (fs_homepath->string[0] && Q_stricmp(fs_homepath->string,fs_basepath->string)) { - FS_AddGameDirectory(fs_homepath->string, fs_gamedirvar->string); - } + FS_AddGameDirectories(fs_gamedirvar->string); } #ifndef STANDALONE diff --git a/code/qcommon/md5.c b/code/qcommon/md5.c index cee93a32..2dd4e93c 100644 --- a/code/qcommon/md5.c +++ b/code/qcommon/md5.c @@ -271,7 +271,7 @@ char *Com_MD5File( const char *fn, int length, const char *prefix, int prefix_le Q_strncpyz( final, "", sizeof( final ) ); - filelen = FS_SV_FOpenFileRead( fn, &f ); + filelen = FS_BaseDir_FOpenFileRead( fn, &f ); if( !f ) { return final; diff --git a/code/qcommon/qcommon.h b/code/qcommon/qcommon.h index 229413dc..f7a7d6f2 100644 --- a/code/qcommon/qcommon.h +++ b/code/qcommon/qcommon.h @@ -748,9 +748,6 @@ qboolean FS_ConditionalRestart( int checksumFeed, qboolean disconnect ); void FS_Restart( int checksumFeed ); // shutdown and restart the filesystem so changes to fs_gamedir can take effect -void FS_AddGameDirectory(const char *path, const char *dir); -void FS_AddGameDirectory2(const char *path, const char *dir, qboolean original_paks_priority); - char **FS_ListFilteredFiles( const char *path, const char *extension, const char *filter, qboolean wantSubs, int *numfiles, qboolean allowNonPureFilesOnDisk ); char **FS_ListFiles( const char *directory, const char *extension, qboolean wantSubs, int *numfiles ); // directory should not have either a leading or trailing / @@ -762,10 +759,10 @@ void FS_FreeFileList( char **list ); qboolean FS_FileExists( const char *file ); void FS_CorrectCase(char* path); +qboolean FS_CreatePath (const char *OSPath); -char *FS_BuildOSPath( const char *base, const char *game, const char *qpath ); - -qboolean FS_CreatePath(char *OSPath); +char *FS_BaseDir_BuildOSPath( const char *base, const char *qpath ); +char *FS_BuildOSPath( const char *base, const char *game, const char *qpath ); int FS_LoadStack( void ); @@ -780,11 +777,12 @@ fileHandle_t FS_FCreateOpenPipeFile( const char *filename ); fileHandle_t FS_FOpenTextFileWrite(const char* qpath); // will properly create any needed paths and deal with seperater character issues +fileHandle_t FS_BaseDir_FOpenFileWrite( const char *filename ); +long FS_BaseDir_FOpenFileRead( const char *filename, fileHandle_t *fp ); +void FS_BaseDir_Rename( const char *from, const char *to, qboolean safe ); void FS_DeleteFile( const char *filename ); void FS_CanonicalFilename( char *filename ); -fileHandle_t FS_SV_FOpenFileWrite( const char *filename ); -long FS_SV_FOpenFileRead( const char *filename, fileHandle_t *fp ); -void FS_SV_Rename( const char *from, const char *to, qboolean safe ); + long FS_FOpenFileRead(const char* filename, fileHandle_t* file, qboolean uniqueFILE, qboolean quiet); // if uniqueFILE is true, then a new FILE will be fopened even if the file // is found in an already open pak file. If uniqueFILE is false, you must call @@ -879,8 +877,6 @@ qboolean FS_CheckDirTraversal(const char *checkdir); qboolean FS_idPak(const char *pak, const char *base); qboolean FS_ComparePaks( char *neededpaks, int len, qboolean dlstring ); -void FS_Rename( const char *from, const char *to ); - void FS_Remove( const char *osPath ); void FS_FilenameCompletion( const char *dir, const char *ext, @@ -891,6 +887,8 @@ void FS_GetRelativeFilename( const char *currentDirectory, const char *absoluteF void FS_FileTime(const char* filename, char* date, char* size); +void FS_CorrectCase(char* path); + extern cvar_t* fs_debug; extern cvar_t* fs_mapdir; @@ -1408,7 +1406,6 @@ char *Sys_MicrosoftStorePath(void); char *Sys_DefaultAppPath(void); #endif -void Sys_SetDefaultHomePath(const char *path); char *Sys_DefaultHomePath(void); const char *Sys_Dirname( char *path ); const char *Sys_Basename( char *path ); diff --git a/code/server/sv_ccmds.c b/code/server/sv_ccmds.c index 3447e485..75ddf709 100644 --- a/code/server/sv_ccmds.c +++ b/code/server/sv_ccmds.c @@ -609,7 +609,7 @@ static void SV_RehashBans_f(void) Com_sprintf(filepath, sizeof(filepath), "%s/%s", FS_GetCurrentGameDir(), sv_banFile->string); - if((filelen = FS_SV_FOpenFileRead(filepath, &readfrom)) >= 0) + if((filelen = FS_BaseDir_FOpenFileRead(filepath, &readfrom)) >= 0) { if(filelen < 2) { @@ -705,7 +705,7 @@ static void SV_WriteBans(void) Com_sprintf(filepath, sizeof(filepath), "%s/%s", FS_GetCurrentGameDir(), sv_banFile->string); - if((writeto = FS_SV_FOpenFileWrite(filepath))) + if((writeto = FS_BaseDir_FOpenFileWrite(filepath))) { char writebuf[128 + MAX_REASON_LENGTH]; serverBan_t *curban; diff --git a/code/server/sv_client.c b/code/server/sv_client.c index 8db698a9..f05203fb 100644 --- a/code/server/sv_client.c +++ b/code/server/sv_client.c @@ -1088,7 +1088,7 @@ int SV_WriteDownloadToClient(client_t *cl, msg_t *msg) if ( !(sv_allowDownload->integer & DLF_ENABLE) || (sv_allowDownload->integer & DLF_NO_UDP) || idPack || unreferenced || - ( cl->downloadSize = FS_SV_FOpenFileRead( cl->downloadName, &cl->download ) ) < 0 ) { + ( cl->downloadSize = FS_BaseDir_FOpenFileRead( cl->downloadName, &cl->download ) ) < 0 ) { // cannot auto-download file if(unreferenced) { diff --git a/code/sys/sys_unix.c b/code/sys/sys_unix.c index 70ea1e5b..16eaed59 100644 --- a/code/sys/sys_unix.c +++ b/code/sys/sys_unix.c @@ -45,18 +45,6 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA qboolean stdinIsATTY; -// Used to determine where to store user-specific files -static char homePath[ MAX_OSPATH ] = { 0 }; - -// Used to store the Steam Quake 3 installation path -static char steamPath[ MAX_OSPATH ] = { 0 }; - -// Used to store the GOG Quake 3 installation path -static char gogPath[ MAX_OSPATH ] = { 0 }; - -// Used to store the Microsoft Store Quake 3 installation path -static char microsoftStorePath[MAX_OSPATH] = { 0 }; - /* ================== Sys_DefaultHomePath @@ -64,6 +52,7 @@ Sys_DefaultHomePath */ char *Sys_DefaultHomePath(void) { + static char homePath[ MAX_OSPATH ] = { 0 }; char *p; if( !*homePath && com_homepath != NULL ) @@ -130,22 +119,8 @@ Sys_SteamPath */ char *Sys_SteamPath( void ) { - // Disabled since Steam doesn't let you install Quake 3 on Mac/Linux -#if 0 //#ifdef STEAMPATH_NAME - char *p; - - if( ( p = getenv( "HOME" ) ) != NULL ) - { -#ifdef __APPLE__ - char *steamPathEnd = "/Library/Application Support/Steam/SteamApps/common/" STEAMPATH_NAME; -#else - char *steamPathEnd = "/.steam/steam/SteamApps/common/" STEAMPATH_NAME; -#endif - Com_sprintf(steamPath, sizeof(steamPath), "%s%s", p, steamPathEnd); - } -#endif - - return steamPath; + // Steam doesn't let you install Quake 3 on Mac/Linux + return ""; } /* @@ -155,8 +130,8 @@ Sys_GogPath */ char *Sys_GogPath( void ) { - // GOG also doesn't let you install Quake 3 on Mac/Linux - return gogPath; + // GOG doesn't let you install Quake 3 on Mac/Linux + return ""; } /* @@ -167,7 +142,7 @@ Sys_MicrosoftStorePath char* Sys_MicrosoftStorePath(void) { // Microsoft Store doesn't exist on Mac/Linux - return microsoftStorePath; + return ""; } diff --git a/code/sys/sys_win32.c b/code/sys/sys_win32.c index 421300d7..5ed0cee0 100644 --- a/code/sys/sys_win32.c +++ b/code/sys/sys_win32.c @@ -48,18 +48,6 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #define KEY_WOW64_32KEY 0x0200 #endif -// Used to determine where to store user-specific files -static char homePath[ MAX_OSPATH ] = { 0 }; - -// Used to store the Steam Quake 3 installation path -static char steamPath[ MAX_OSPATH ] = { 0 }; - -// Used to store the GOG Quake 3 installation path -static char gogPath[ MAX_OSPATH ] = { 0 }; - -// Used to store the Microsoft Store Quake 3 installation path -static char microsoftStorePath[MAX_OSPATH] = { 0 }; - #ifndef DEDICATED static UINT timerResolution = 0; #endif @@ -104,10 +92,11 @@ Sys_DefaultHomePath */ char *Sys_DefaultHomePath( void ) { - TCHAR szPath[MAX_PATH]; + static char homePath[ MAX_OSPATH ] = { 0 }; if(!*homePath && com_homepath) { + TCHAR szPath[MAX_PATH]; if( !SUCCEEDED( SHGetFolderPathA( NULL, CSIDL_APPDATA, NULL, 0, szPath ) ) ) @@ -134,14 +123,20 @@ Sys_SteamPath */ char *Sys_SteamPath( void ) { -#if defined(STEAMPATH_NAME) || defined(STEAMPATH_APPID) +#ifndef STANDALONE + +#define STEAMPATH_NAME "Quake 3 Arena" +#define STEAMPATH_APPID "2200" + + static char steamPath[ MAX_OSPATH ] = { 0 }; + HKEY steamRegKey; DWORD pathLen = MAX_OSPATH; qboolean finishPath = qfalse; -#ifdef STEAMPATH_APPID // Assuming Steam is a 32-bit app - if (!steamPath[0] && !RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\Steam App " STEAMPATH_APPID, 0, KEY_QUERY_VALUE | KEY_WOW64_32KEY, &steamRegKey)) + if (!steamPath[0] && !RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\Steam App " + STEAMPATH_APPID, 0, KEY_QUERY_VALUE | KEY_WOW64_32KEY, &steamRegKey)) { pathLen = MAX_OSPATH; if (RegQueryValueEx(steamRegKey, "InstallLocation", NULL, NULL, (LPBYTE)steamPath, &pathLen)) @@ -149,9 +144,7 @@ char *Sys_SteamPath( void ) RegCloseKey(steamRegKey); } -#endif -#ifdef STEAMPATH_NAME if (!steamPath[0] && !RegOpenKeyEx(HKEY_CURRENT_USER, "Software\\Valve\\Steam", 0, KEY_QUERY_VALUE, &steamRegKey)) { pathLen = MAX_OSPATH; @@ -164,7 +157,6 @@ char *Sys_SteamPath( void ) RegCloseKey(steamRegKey); } -#endif if (steamPath[0]) { @@ -176,9 +168,11 @@ char *Sys_SteamPath( void ) if (finishPath) Q_strcat(steamPath, MAX_OSPATH, "\\SteamApps\\common\\" STEAMPATH_NAME ); } -#endif return steamPath; +#else + return ""; +#endif } /* @@ -188,7 +182,12 @@ Sys_GogPath */ char *Sys_GogPath( void ) { -#ifdef GOGPATH_ID +#ifndef STANDALONE + +#define GOGPATH_ID "1441704920" + + static char gogPath[ MAX_OSPATH ] = { 0 }; + HKEY gogRegKey; DWORD pathLen = MAX_OSPATH; @@ -208,9 +207,11 @@ char *Sys_GogPath( void ) gogPath[pathLen] = '\0'; } -#endif return gogPath; +#else + return ""; +#endif } /* @@ -220,7 +221,12 @@ Sys_MicrosoftStorePath */ char* Sys_MicrosoftStorePath(void) { -#ifdef MSSTORE_PATH +#ifndef STANDALONE + +#define MSSTORE_PATH "Quake 3" + + static char microsoftStorePath[MAX_OSPATH] = { 0 }; + if (!microsoftStorePath[0]) { TCHAR szPath[MAX_PATH]; @@ -235,8 +241,11 @@ char* Sys_MicrosoftStorePath(void) // default: C:\Program Files\ModifiableWindowsApps\Quake 3\EN Com_sprintf(microsoftStorePath, sizeof(microsoftStorePath), "%s%cModifiableWindowsApps%c%s%cEN", szPath, PATH_SEP, PATH_SEP, MSSTORE_PATH, PATH_SEP); } -#endif + return microsoftStorePath; +#else + return ""; +#endif } /*