From 93cb4701f3ca8e38849cd3fcb270be77b4aec331 Mon Sep 17 00:00:00 2001 From: Eugene Date: Wed, 31 Jan 2024 00:19:53 +0200 Subject: [PATCH] Filesystem: allow multiple basegames in fs_basegame cvar separated by '/' Makefile: use additive LDFLAGS --- Makefile | 10 +-- code/client/cl_main.c | 2 +- code/qcommon/common.c | 4 +- code/qcommon/files.c | 135 +++++++++++++++++++++++++++-------------- code/qcommon/qcommon.h | 2 - code/qcommon/vm.c | 6 +- 6 files changed, 97 insertions(+), 62 deletions(-) diff --git a/Makefile b/Makefile index d8eb7edf4..f11818a41 100644 --- a/Makefile +++ b/Makefile @@ -418,7 +418,7 @@ ifdef MINGW BINEXT = .exe - LDFLAGS = -mwindows -Wl,--dynamicbase -Wl,--nxcompat + LDFLAGS += -mwindows -Wl,--dynamicbase -Wl,--nxcompat LDFLAGS += -Wl,--gc-sections -fvisibility=hidden LDFLAGS += -lwsock32 -lgdi32 -lwinmm -lole32 -lws2_32 -lpsapi -lcomctl32 LDFLAGS += -flto @@ -479,15 +479,15 @@ ifeq ($(COMPILE_PLATFORM),darwin) ARCHEXT = .$(ARCH) - LDFLAGS = + LDFLAGS += ifeq ($(ARCH),x86_64) BASE_CFLAGS += -arch x86_64 - LDFLAGS = -arch x86_64 + LDFLAGS += -arch x86_64 endif ifeq ($(ARCH),aarch64) BASE_CFLAGS += -arch arm64 - LDFLAGS = -arch arm64 + LDFLAGS += -arch arm64 endif ifeq ($(USE_LOCAL_HEADERS),1) @@ -554,7 +554,7 @@ else SHLIBCFLAGS = -fPIC -fvisibility=hidden SHLIBLDFLAGS = -shared $(LDFLAGS) - LDFLAGS = -lm + LDFLAGS += -lm LDFLAGS += -Wl,--gc-sections -fvisibility=hidden ifeq ($(USE_SDL),1) diff --git a/code/client/cl_main.c b/code/client/cl_main.c index 3bb5470c5..b807a8d05 100644 --- a/code/client/cl_main.c +++ b/code/client/cl_main.c @@ -3967,7 +3967,7 @@ void CL_Init( void ) { Cvar_CheckRange( cl_dlDirectory, "0", "1", CV_INTEGER ); s = va( "Save downloads initiated by \\dlmap and \\download commands in:\n" " 0 - current game directory\n" - " 1 - fs_basegame (%s) directory\n", FS_GetBaseGameDir() ); + " 1 - basegame (%s) directory\n", FS_GetBaseGameDir() ); Cvar_SetDescription( cl_dlDirectory, s ); cl_reconnectArgs = Cvar_Get( "cl_reconnectArgs", "", CVAR_ARCHIVE_ND | CVAR_NOTABCOMPLETE ); diff --git a/code/qcommon/common.c b/code/qcommon/common.c index a200ccbfa..0e06e5e09 100644 --- a/code/qcommon/common.c +++ b/code/qcommon/common.c @@ -4074,8 +4074,8 @@ void Com_WriteConfiguration( void ) { Com_WriteConfigToFile( Q3CONFIG_CFG ); #ifndef DEDICATED - gamedir = Cvar_VariableString( "fs_game" ); - basegame = Cvar_VariableString( "fs_basegame" ); + gamedir = FS_GetCurrentGameDir(); + basegame = FS_GetBaseGameDir(); if ( UI_usesUniqueCDKey() && gamedir[0] && Q_stricmp( basegame, gamedir ) ) { Com_WriteCDKey( gamedir, &cl_cdkey[16] ); } else { diff --git a/code/qcommon/files.c b/code/qcommon/files.c index 523eeb4e9..837d7d1b2 100644 --- a/code/qcommon/files.c +++ b/code/qcommon/files.c @@ -290,6 +290,11 @@ typedef struct searchpath_s { dirPolicy_t policy; } searchpath_t; +#define MAX_BASEGAMES 4 +static char basegame_str[MAX_OSPATH], *basegames[MAX_BASEGAMES]; +static int basegame_cnt; +static const char *basegame = ""; /* last value in array */ + static char fs_gamedir[MAX_OSPATH]; // this will be a single file name with no separators static cvar_t *fs_debug; static cvar_t *fs_homepath; @@ -3642,6 +3647,29 @@ static void FS_GetModDescription( const char *modDir, char *description, int des } +/* +================ +FS_IsBaseGame +================ +*/ +static qboolean FS_IsBaseGame( const char *game ) +{ + int i; + + if ( game == NULL || *game == '\0' ) { + return qtrue; + } + + for ( i = 0; i < basegame_cnt; i++ ) { + if ( Q_stricmp( basegames[i], game ) == 0 ) { + return qtrue; + } + } + + return qfalse; +} + + /* ================ FS_GetModList @@ -3697,10 +3725,11 @@ static int FS_GetModList( char *listbuf, int bufsize ) { } // we also drop BASEGAME, "." and ".." - if ( bDrop || Q_stricmp( name, fs_basegame->string ) == 0 ) { + if ( bDrop || strcmp(name, "." ) == 0 || strcmp( name, ".." ) == 0 ) { continue; } - if ( strcmp( name, "." ) == 0 || strcmp( name, ".." ) == 0 ) { + + if ( FS_IsBaseGame( name ) ) { continue; } @@ -4639,7 +4668,7 @@ FS_Startup */ static void FS_Startup( void ) { const char *homePath; - int start, end; + int i, start, end; Com_Printf( "----- FS_Startup -----\n" ); @@ -4650,9 +4679,25 @@ static void FS_Startup( void ) { fs_basepath = Cvar_Get( "fs_basepath", Sys_DefaultBasePath(), CVAR_INIT | CVAR_PROTECTED | CVAR_PRIVATE ); Cvar_SetDescription( fs_basepath, "Write-protected CVAR specifying the path to the installation folder of the game." ); fs_basegame = Cvar_Get( "fs_basegame", BASEGAME, CVAR_INIT | CVAR_PROTECTED ); - Cvar_SetDescription( fs_basegame, "Write-protected CVAR specifying the path to the base game folder." ); + Cvar_SetDescription( fs_basegame, "Write-protected CVAR specifying the path to the base game(s) folder(s), separated by '/'." ); fs_steampath = Cvar_Get( "fs_steampath", Sys_SteamPath(), CVAR_INIT | CVAR_PROTECTED | CVAR_PRIVATE ); + /* parse fs_basegame cvar */ + Q_strncpyz( basegame_str, fs_basegame->string, sizeof( basegame_str ) ); + basegame_cnt = Com_Split( basegame_str, basegames, ARRAY_LEN( basegames ), '/' ); + /* set up basegame on last item from the list */ + basegame = basegames[0]; + for (i = 1; i < basegame_cnt; i++) { + if ( basegames[i] != '\0' ) { + basegame = basegames[i]; + } + } + + if ( fs_basegame->string[0] == '\0' || *basegame == '\0' || basegame_cnt == 0 ) + Com_Error( ERR_FATAL, "* fs_basegame is not set *" ); + + Com_Printf( S_COLOR_YELLOW "basegame set to '%s'\n", basegame ); + #ifndef USE_HANDLE_CACHE fs_locked = Cvar_Get( "fs_locked", "0", CVAR_INIT ); Cvar_SetDescription( fs_locked, "Set file handle policy for pk3 files:\n" @@ -4660,11 +4705,8 @@ static void FS_Startup( void ) { " 1 - keep file handle locked, more consistent, total pk3 files count limited to ~1k-4k\n" ); #endif - if ( !fs_basegame->string[0] ) - Com_Error( ERR_FATAL, "* fs_basegame is not set *" ); - homePath = Sys_DefaultHomePath(); - if ( !homePath || !homePath[0] ) { + if ( homePath == NULL || homePath[0] == '\0' ) { homePath = fs_basepath->string; } @@ -4675,7 +4717,7 @@ static void FS_Startup( void ) { Cvar_CheckRange( fs_gamedirvar, NULL, NULL, CV_FSPATH ); Cvar_SetDescription( fs_gamedirvar, "Specify an alternate mod directory and run the game with this mod." ); - if ( !Q_stricmp( fs_basegame->string, fs_gamedirvar->string ) ) { + if ( FS_IsBaseGame( fs_gamedirvar->string ) ) { Cvar_ForceReset( "fs_game" ); } @@ -4693,36 +4735,49 @@ static void FS_Startup( void ) { #endif // add search path elements in reverse priority order - if ( fs_steampath->string[0] ) { - FS_AddGameDirectory( fs_steampath->string, fs_basegame->string ); + if (fs_steampath->string[0]) { + // handle multiple basegames: + for (i = 0; i < basegame_cnt; i++) { + FS_AddGameDirectory( fs_steampath->string, basegames[i] ); + } } - if ( fs_basepath->string[0] ) { - FS_AddGameDirectory( fs_basepath->string, fs_basegame->string ); + if (fs_basepath->string[0]) { + // handle multiple basegames: + for (i = 0; i < basegame_cnt; i++) { + FS_AddGameDirectory( fs_basepath->string, basegames[i] ); + } } #ifdef __APPLE__ - fs_apppath = Cvar_Get ("fs_apppath", Sys_DefaultAppPath(), CVAR_INIT|CVAR_PROTECTED ); + 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, fs_basegame->string); + if ( fs_apppath->string[0] ) { + // handle multiple basegames: + for ( i = 0; i < basegame_cnt; i++ ) { + FS_AddGameDirectory( fs_apppath->string, basegames[i] ); + } + } #endif // fs_homepath is somewhat particular to *nix systems, only add if relevant // NOTE: same filtering below for mods and basegame if ( fs_homepath->string[0] && Q_stricmp( fs_homepath->string, fs_basepath->string ) ) { - FS_AddGameDirectory( fs_homepath->string, fs_basegame->string ); + // handle multiple basegames: + for ( i = 0; i < basegame_cnt; i++ ) { + FS_AddGameDirectory( fs_homepath->string, basegames[i] ); + } } // check for additional game folder for mods - if ( fs_gamedirvar->string[0] && Q_stricmp( fs_gamedirvar->string, fs_basegame->string ) ) { - if ( fs_steampath->string[0] ) { + if ( fs_gamedirvar->string[0] != '\0' && !FS_IsBaseGame( fs_gamedirvar->string ) ) { + if ( fs_steampath->string[0] != '\0' ) { FS_AddGameDirectory( fs_steampath->string, fs_gamedirvar->string ); } - if ( fs_basepath->string[0] ) { + if ( fs_basepath->string[0] != '\0' ) { FS_AddGameDirectory( fs_basepath->string, fs_gamedirvar->string ); } - if ( fs_homepath->string[0] && Q_stricmp( fs_homepath->string, fs_basepath->string ) ) { + if ( fs_homepath->string[0] != '\0' && Q_stricmp( fs_homepath->string, fs_basepath->string ) ) { FS_AddGameDirectory( fs_homepath->string, fs_gamedirvar->string ); } } @@ -4739,9 +4794,8 @@ static void FS_Startup( void ) { end = Sys_Milliseconds(); - Com_ReadCDKey( fs_basegame->string ); - - if ( fs_gamedirvar->string[0] && Q_stricmp( fs_gamedirvar->string, fs_basegame->string ) ) { + Com_ReadCDKey( basegame ); + if ( !FS_IsBaseGame( fs_gamedirvar->string ) ) { Com_AppendCDKey( fs_gamedirvar->string ); } @@ -4765,8 +4819,9 @@ static void FS_Startup( void ) { fs_gamedirvar->modified = qfalse; // We just loaded, it's not modified // check original q3a files - if ( !Q_stricmp( fs_basegame->string, BASEGAME ) || !Q_stricmp( fs_basegame->string, BASEDEMO ) ) + if ( FS_IsBaseGame( BASEGAME ) || FS_IsBaseGame( BASEDEMO ) ) { FS_CheckIdPaks(); + } #ifdef FS_MISSING if (missingFiles == NULL) { @@ -5014,7 +5069,7 @@ const char *FS_ReferencedPakChecksums( void ) { if ( search->pack->exclude ) { continue; } - if ( search->pack->referenced || Q_stricmp( search->pack->pakGamename, fs_basegame->string ) ) { + if ( search->pack->referenced || !FS_IsBaseGame( search->pack->pakGamename ) ) { Q_strcat( info, sizeof( info ), va( "%i ", search->pack->checksum ) ); } } @@ -5141,7 +5196,7 @@ const char *FS_ReferencedPakNames( void ) { if ( search->pack->exclude ) { continue; } - if ( search->pack->referenced || Q_stricmp( search->pack->pakGamename, fs_basegame->string ) ) { + if ( search->pack->referenced || !FS_IsBaseGame( search->pack->pakGamename ) ) { pakName = va( "%s/%s", search->pack->pakGamename, search->pack->pakBasename ); if ( *info != '\0' ) { Q_strcat( info, sizeof( info ), " " ); @@ -5624,22 +5679,22 @@ void FS_VM_CloseFiles( handleOwner_t owner ) const char *FS_GetCurrentGameDir( void ) { - if ( fs_gamedirvar->string[0] ) + if ( fs_gamedirvar->string[0] != '\0' ) return fs_gamedirvar->string; - return fs_basegame->string; + return basegame; // last basegame } const char *FS_GetBaseGameDir( void ) { - return fs_basegame->string; + return basegame; // last basegame } -const char *FS_GetBasePath( void ) +static const char *FS_GetBasePath( void ) { - if ( fs_basepath && fs_basepath->string[0] ) + if ( fs_basepath && fs_basepath->string[0] != '\0' ) return fs_basepath->string; else return ""; @@ -5648,27 +5703,13 @@ const char *FS_GetBasePath( void ) const char *FS_GetHomePath( void ) { - if ( fs_homepath && fs_homepath->string[0] ) + if ( fs_homepath && fs_homepath->string[0] != '\0' ) return fs_homepath->string; else return FS_GetBasePath(); } -const char *FS_GetGamePath( void ) -{ - static char buffer[ MAX_OSPATH + MAX_CVAR_VALUE_STRING + 1 ]; - if ( fs_gamedirvar && fs_gamedirvar->string[0] ) { - Com_sprintf( buffer, sizeof( buffer ), "%s%c%s", FS_GetHomePath(), - PATH_SEP, fs_gamedirvar->string ); - return buffer; - } else { - buffer[0] = '\0'; - return buffer; - } -} - - fileHandle_t FS_PipeOpenWrite( const char *cmd, const char *filename ) { fileHandleData_t *fd; fileHandle_t f; diff --git a/code/qcommon/qcommon.h b/code/qcommon/qcommon.h index f75e6273b..37954f22d 100644 --- a/code/qcommon/qcommon.h +++ b/code/qcommon/qcommon.h @@ -851,9 +851,7 @@ void FS_VM_CloseFiles( handleOwner_t owner ); const char *FS_GetCurrentGameDir( void ); const char *FS_GetBaseGameDir( void ); -const char *FS_GetBasePath( void ); const char *FS_GetHomePath( void ); -const char *FS_GetGamePath( void ); qboolean FS_StripExt( char *filename, const char *ext ); qboolean FS_AllowedExtension( const char *fileName, qboolean allowPk3s, const char **ext ); diff --git a/code/qcommon/vm.c b/code/qcommon/vm.c index fd1f8354e..8610fbc59 100644 --- a/code/qcommon/vm.c +++ b/code/qcommon/vm.c @@ -1689,15 +1689,11 @@ TTimo: added some verbosity in debug */ static void * QDECL VM_LoadDll( const char *name, vmMainFunc_t *entryPoint, dllSyscall_t systemcalls ) { - const char *gamedir = Cvar_VariableString( "fs_game" ); + const char *gamedir = FS_GetCurrentGameDir(); char filename[ MAX_QPATH ]; void *libHandle; dllEntry_t dllEntry; - if ( !*gamedir ) { - gamedir = Cvar_VariableString( "fs_basegame" ); - } - Com_sprintf( filename, sizeof( filename ), "%s%c%s" ARCH_STRING DLL_EXT, gamedir, PATH_SEP, name ); libHandle = FS_LoadLibrary( filename );