From 51ed961630495503ab48aa2f1a0b2758f1ebe301 Mon Sep 17 00:00:00 2001 From: Daggolin Date: Sun, 19 Mar 2023 05:32:09 +0100 Subject: [PATCH 01/10] Add support for loading JKA assets: - new cvar fs_assetsPathJKA; works similar to fs_assetsPath, but automatically tries to detect jka rather than jk2 (using registry keys on Windows and known paths on Mac) - new cvar fs_noJKA; disables loading of jka assets - jka assets are loaded before jk2 assets, thus jk2 files take precedence in case of conflicts - .shader files from jka assets are virtually renamed to .shader_jka and .shader_jka files are loaded with lower priority than .shader files - when trying to load an image the renderer tries to load all extensions without considering the jka assets and only includes jka assets if all extensions failed; this avoids cases of a higher priority extension images from the jka assets overriding jk2 images --- CVARS.rst | 17 ++++++++ src/client/cl_main.cpp | 1 + src/qcommon/files.cpp | 81 ++++++++++++++++++++++++++++++++------ src/qcommon/qcommon.h | 5 ++- src/renderer/tr_image.cpp | 51 ++++++++++++++++++------ src/renderer/tr_public.h | 1 + src/renderer/tr_shader.cpp | 21 ++++++---- src/sys/sys_public.h | 1 + src/sys/sys_unix.cpp | 47 ++++++++++++++++++++++ src/sys/sys_win32.cpp | 29 ++++++++++++++ 10 files changed, 222 insertions(+), 32 deletions(-) diff --git a/CVARS.rst b/CVARS.rst index 765dc57e..44d28fd9 100644 --- a/CVARS.rst +++ b/CVARS.rst @@ -45,6 +45,23 @@ New and Modified Cvars | ``fs_game cvar`` | ``fs_forcegame cvar`` +.. + +:Name: fs_assetsPathJKA +:Values: Foldername +:Default: "" (Not set on portable); autodetected for non-portable +:Description: + Sets the path to load JKA assets from. + +.. + +:Name: fs_noJKA +:Values: "0", "1" +:Default: "0" +:Description: + Disables loading of JKA assets even when fs_assetsPathJKA point to a valid + JKA folder. + ----------- Client-Side ----------- diff --git a/src/client/cl_main.cpp b/src/client/cl_main.cpp index 244f20c0..e2c2fe0e 100644 --- a/src/client/cl_main.cpp +++ b/src/client/cl_main.cpp @@ -2701,6 +2701,7 @@ void CL_InitRef( void ) { ri.Hunk_FreeTempMemory = Hunk_FreeTempMemory; ri.CM_DrawDebugSurface = CM_DrawDebugSurface; ri.FS_ReadFile = FS_ReadFile; + ri.FS_ReadFileSkipJKA = FS_ReadFileSkipJKA; ri.FS_FreeFile = FS_FreeFile; ri.FS_WriteFile = FS_WriteFile; ri.FS_FreeFileList = FS_FreeFileList; diff --git a/src/qcommon/files.cpp b/src/qcommon/files.cpp index cdc64c54..10bd60c4 100644 --- a/src/qcommon/files.cpp +++ b/src/qcommon/files.cpp @@ -216,6 +216,7 @@ typedef struct { fileInPack_t* *hashTable; // hash table fileInPack_t* buildBuffer; // buffer with the filenames etc. int gvc; // game-version compatibility + qboolean isJKA; // jka assets } pack_t; typedef struct { @@ -235,6 +236,8 @@ static cvar_t *fs_debug; static cvar_t *fs_homepath; static cvar_t *fs_basepath; static cvar_t *fs_assetspath; +static cvar_t *fs_assetspathJKA; +static cvar_t *fs_noJKA; static cvar_t *fs_basegame; static cvar_t *fs_copyfiles; static cvar_t *fs_gamedirvar; @@ -1222,11 +1225,11 @@ separate file or a ZIP file. */ extern qboolean com_fullyInitialized; -int FS_FOpenFileRead(const char *filename, fileHandle_t *file, qboolean uniqueFILE, module_t module) { - return FS_FOpenFileReadHash(filename, file, uniqueFILE, NULL, module); +int FS_FOpenFileRead(const char *filename, fileHandle_t *file, qboolean uniqueFILE, module_t module, qboolean skipJKA) { + return FS_FOpenFileReadHash(filename, file, uniqueFILE, NULL, module, skipJKA); } -int FS_FOpenFileReadHash(const char *filename, fileHandle_t *file, qboolean uniqueFILE, unsigned long *filehash, module_t module) { +int FS_FOpenFileReadHash(const char *filename, fileHandle_t *file, qboolean uniqueFILE, unsigned long *filehash, module_t module, qboolean skipJKA) { bool isLocalConfig; searchpath_t *search; char *netpath; @@ -1283,6 +1286,10 @@ int FS_FOpenFileReadHash(const char *filename, fileHandle_t *file, qboolean uniq if ( isLocalConfig && search->pack ) { continue; } + // Skip JKA assets if desired + if ( search->pack && search->pack->isJKA && skipJKA ) { + continue; + } // if ( search->pack ) { hash = FS_HashFileName(filename, search->pack->hashSize); @@ -1732,7 +1739,7 @@ Filename are relative to the quake search path a null buffer will just return the file length without loading ============ */ -int FS_ReadFile( const char *qpath, void **buffer ) { +int FS_ReadFile_real( const char *qpath, void **buffer, qboolean skipJKA ) { fileHandle_t h; byte* buf; qboolean isConfig; @@ -1794,7 +1801,7 @@ int FS_ReadFile( const char *qpath, void **buffer ) { } // look for it in the filesystem or pack files - len = FS_FOpenFileRead( qpath, &h, qfalse ); + len = FS_FOpenFileRead( qpath, &h, qfalse, MODULE_MAIN, skipJKA ); if ( h == 0 ) { if ( buffer ) { *buffer = NULL; @@ -1847,6 +1854,14 @@ int FS_ReadFile( const char *qpath, void **buffer ) { return len; } +int FS_ReadFile( const char *qpath, void **buffer ) { + return FS_ReadFile_real( qpath, buffer, qfalse ); +} + +int FS_ReadFileSkipJKA( const char *qpath, void **buffer ) { + return FS_ReadFile_real( qpath, buffer, qtrue ); +} + /* ============= FS_FreeFile @@ -1927,7 +1942,7 @@ Creates a new pak_t in the search chain for the contents of a zip file. ================= */ -static pack_t *FS_LoadZipFile( char *zipfile, const char *basename ) +static pack_t *FS_LoadZipFile( char *zipfile, const char *basename, qboolean assetsJKA ) { fileInPack_t *buildBuffer; pack_t *pack; @@ -1942,6 +1957,7 @@ static pack_t *FS_LoadZipFile( char *zipfile, const char *basename ) int fs_numHeaderLongs; int *fs_headerLongs; char *namePtr; + int strLength; fs_numHeaderLongs = 0; @@ -1961,7 +1977,17 @@ static pack_t *FS_LoadZipFile( char *zipfile, const char *basename ) if (err != UNZ_OK) { break; } - len += strlen(filename_inzip) + 1; + strLength = strlen(filename_inzip); + if ( assetsJKA ) { + // Ugly workaround: rename academy shader files to avoid collisions + if ( strLength > 7 && !Q_stricmp(filename_inzip + strLength - 7, ".shader") ) { + len += strLength + 5; // "_jka" + 1 + } else { + len += strlen(filename_inzip) + 1; + } + } else { + len += strlen(filename_inzip) + 1; + } unzGoToNextFile(uf); } @@ -2005,6 +2031,13 @@ static pack_t *FS_LoadZipFile( char *zipfile, const char *basename ) if (file_info.uncompressed_size > 0) { fs_headerLongs[fs_numHeaderLongs++] = LittleLong(file_info.crc); } + if ( assetsJKA ) { + // Ugly workaround: rename academy shader files to avoid collisions + strLength = strlen( filename_inzip ); + if ( strLength > 7 && !Q_stricmp(filename_inzip + strLength - 7, ".shader") ) { + Q_strcat( filename_inzip, sizeof(filename_inzip), "_jka" ); + } + } Q_strlwr( filename_inzip ); hash = FS_HashFileName(filename_inzip, pack->hashSize); buildBuffer[i].name = namePtr; @@ -2911,7 +2944,7 @@ const char *get_filename(const char *path) { return slash + 1; } -static void FS_AddGameDirectory( const char *path, const char *dir, qboolean assetsOnly ) { +static void FS_AddGameDirectory2( const char *path, const char *dir, qboolean assetsOnly, qboolean assetsJKA ) { searchpath_t *sp; int i; searchpath_t *search; @@ -2940,7 +2973,7 @@ static void FS_AddGameDirectory( const char *path, const char *dir, qboolean ass // // add the directory to the search path // - if (!assetsOnly) { + if (!assetsOnly && !assetsJKA) { search = (struct searchpath_s *)Z_Malloc(sizeof(searchpath_t), TAG_FILESYS, qtrue); search->dir = (directory_t *)Z_Malloc(sizeof(*search->dir), TAG_FILESYS, qtrue); @@ -2971,9 +3004,14 @@ static void FS_AddGameDirectory( const char *path, const char *dir, qboolean ass strcmp(filename, "assets2.pk3") && strcmp(filename, "assets5.pk3")) { continue; } + } else if ( assetsJKA ) { + if (strcmp(filename, "assets0.pk3") && strcmp(filename, "assets1.pk3") && + strcmp(filename, "assets2.pk3") && strcmp(filename, "assets3.pk3")) { + continue; + } } - if ( ( pak = FS_LoadZipFile( pakfile, pakfiles[i] ) ) == 0 ) + if ( ( pak = FS_LoadZipFile( pakfile, pakfiles[i], assetsJKA ) ) == 0 ) continue; #ifndef DEDICATED @@ -3008,6 +3046,9 @@ static void FS_AddGameDirectory( const char *path, const char *dir, qboolean ass pak->referenced |= FS_GENERAL_REF; } + // Mark jka assets as such + pak->isJKA = assetsJKA; + search = (searchpath_s *)Z_Malloc (sizeof(searchpath_t), TAG_FILESYS, qtrue); search->pack = pak; search->next = fs_searchpaths; @@ -3018,6 +3059,10 @@ static void FS_AddGameDirectory( const char *path, const char *dir, qboolean ass Sys_FreeFileList( pakfiles ); } +static void FS_AddGameDirectory( const char *path, const char *dir, qboolean assetsOnly ) { + FS_AddGameDirectory2( path, dir, assetsOnly, qfalse ); +} + /* ================ FS_idPak @@ -3261,6 +3306,7 @@ FS_Startup */ static void FS_Startup( const char *gameName ) { const char *assetsPath; + const char *assetsPathJKA; // Silence clang, they do get initialized char *mv_whitelist = NULL, *mv_blacklist = NULL, *mv_forcelist = NULL; fileHandle_t f_w, f_b, f_f; @@ -3281,6 +3327,10 @@ static void FS_Startup( const char *gameName ) { assetsPath = Sys_DefaultAssetsPath(); fs_assetspath = Cvar_Get("fs_assetspath", assetsPath ? assetsPath : "", CVAR_INIT | CVAR_VM_NOWRITE); + assetsPathJKA = Sys_DefaultAssetsPathJKA(); + fs_assetspathJKA = Cvar_Get("fs_assetspathJKA", assetsPathJKA ? assetsPathJKA : "", CVAR_INIT | CVAR_VM_NOWRITE); + fs_noJKA = Cvar_Get("fs_noJKA", "0", CVAR_ARCHIVE); + if (!FS_AllPath_Base_FileExists("assets5.pk3")) { // assets files found in none of the paths #if defined(INSTALLED) @@ -3297,9 +3347,14 @@ static void FS_Startup( const char *gameName ) { return; } + // Try to load JKA assets if a path has been specified + if (fs_assetspathJKA->string[0] && !fs_noJKA->integer) { + FS_AddGameDirectory2(fs_assetspathJKA->string, BASEGAME, qfalse, qtrue); + } + // don't use the assetspath if assets files already found in fs_basepath or fs_homepath - if (assetsPath && !FS_BaseHome_Base_FileExists("assets5.pk3")) { - FS_AddGameDirectory(assetsPath, BASEGAME, qtrue); + if (fs_assetspath->string[0] && !FS_BaseHome_Base_FileExists("assets5.pk3")) { + FS_AddGameDirectory(fs_assetspath->string, BASEGAME, qtrue); } // add search path elements in reverse priority order @@ -3787,6 +3842,8 @@ void FS_InitFilesystem( void ) { // has already been initialized Com_StartupVariable( "fs_basepath" ); Com_StartupVariable( "fs_homepath" ); + Com_StartupVariable( "fs_assetspathJKA" ); + Com_StartupVariable( "fs_noJKA" ); #if !defined(PORTABLE) Com_StartupVariable( "fs_assetspath" ); #endif diff --git a/src/qcommon/qcommon.h b/src/qcommon/qcommon.h index e702be21..a0c468d2 100644 --- a/src/qcommon/qcommon.h +++ b/src/qcommon/qcommon.h @@ -640,8 +640,8 @@ fileHandle_t FS_SV_FOpenFileWrite( const char *filename, module_t module = MODUL fileHandle_t FS_SV_FOpenFileAppend( const char *filename, module_t module = MODULE_MAIN ); int FS_SV_FOpenFileRead( const char *filename, fileHandle_t *fp, module_t module = MODULE_MAIN ); void FS_SV_Rename( const char *from, const char *to ); -int FS_FOpenFileRead( const char *qpath, fileHandle_t *file, qboolean uniqueFILE, module_t module = MODULE_MAIN ); -int FS_FOpenFileReadHash( const char *filename, fileHandle_t *file, qboolean uniqueFILE, unsigned long *filehash, module_t module = MODULE_MAIN ); +int FS_FOpenFileRead( const char *qpath, fileHandle_t *file, qboolean uniqueFILE, module_t module = MODULE_MAIN, qboolean skipJKA = qfalse ); +int FS_FOpenFileReadHash( const char *filename, fileHandle_t *file, qboolean uniqueFILE, unsigned long *filehash, module_t module = MODULE_MAIN, qboolean skipJKA = qfalse ); // 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 // FS_FCloseFile instead of fclose, otherwise the pak FILE would be improperly closed @@ -667,6 +667,7 @@ int FS_ReadFile( const char *qpath, void **buffer ); // A 0 byte will always be appended at the end, so string ops are safe. // the buffer should be considered read-only, because it may be cached // for other uses. +int FS_ReadFileSkipJKA( const char *qpath, void **buffer ); void FS_ForceFlush( fileHandle_t f, module_t module = MODULE_MAIN ); // forces flush on files we're writing to. diff --git a/src/renderer/tr_image.cpp b/src/renderer/tr_image.cpp index 392762d9..d6ef0b22 100644 --- a/src/renderer/tr_image.cpp +++ b/src/renderer/tr_image.cpp @@ -22,8 +22,8 @@ using namespace std; #include #include -static void LoadTGA( const char *name, byte **pic, int *width, int *height ); -static void LoadJPG( const char *name, byte **pic, int *width, int *height ); +static void LoadTGA( const char *name, byte **pic, int *width, int *height, qboolean skipJKA ); +static void LoadJPG( const char *name, byte **pic, int *width, int *height, qboolean skipJKA ); static byte s_intensitytable[256]; static unsigned char s_gammatable[256]; @@ -1205,7 +1205,7 @@ typedef struct // returns false if found but had a format error, else true for either OK or not-found (there's a reason for this) // -void LoadTGA ( const char *name, byte **pic, int *width, int *height) +void LoadTGA ( const char *name, byte **pic, int *width, int *height, qboolean skipJKA) { char sErrorString[1024]; bool bFormatErrors = false; @@ -1226,7 +1226,8 @@ void LoadTGA ( const char *name, byte **pic, int *width, int *height) // load the file // byte *pTempLoadedBuffer = 0; - ri.FS_ReadFile ( name, (void **)&pTempLoadedBuffer); + if ( skipJKA ) ri.FS_ReadFileSkipJKA( name, (void**)&pTempLoadedBuffer ); + else ri.FS_ReadFile ( name, (void **)&pTempLoadedBuffer); if (!pTempLoadedBuffer) { return; } @@ -1556,7 +1557,7 @@ static void R_JPGOutputMessage( j_common_ptr cinfo ) Com_Printf("%s\n", buffer); } -void LoadJPG( const char *filename, unsigned char **pic, int *width, int *height ) { +void LoadJPG( const char *filename, unsigned char **pic, int *width, int *height, qboolean skipJKA ) { /* This struct contains the JPEG decompression parameters and pointers to * working space (which is allocated as needed by the JPEG library). */ @@ -1591,7 +1592,9 @@ void LoadJPG( const char *filename, unsigned char **pic, int *width, int *height * requires it in order to read binary files. */ - int len = ri.FS_ReadFile ( filename, &fbuffer.v); + int len; + if ( skipJKA ) len = ri.FS_ReadFileSkipJKA ( filename, &fbuffer.v ); + else len = ri.FS_ReadFile ( filename, &fbuffer.v); if (!fbuffer.b || len < 0) { return; } @@ -2093,10 +2096,12 @@ void user_read_data(png_structp png_ptr, png_bytep data, png_size_t length) { } // Loads a PNG image from file. -void LoadPNG(const char *filename, byte **data, int *width, int *height) +void LoadPNG(const char *filename, byte **data, int *width, int *height, qboolean skipJKA) { char *buf = NULL; - int len = ri.FS_ReadFile(filename, (void **)&buf); + int len; + if ( skipJKA ) len = ri.FS_ReadFileSkipJKA(filename, (void**)&buf); + else len = ri.FS_ReadFile(filename, (void **)&buf); if (len < 0 || buf == NULL) { return; @@ -2125,23 +2130,47 @@ void R_LoadImage( const char *shortname, byte **pic, int *width, int *height ) *width = 0; *height = 0; + // First try without JKA assets COM_StripExtension(shortname,name,sizeof(name)); COM_DefaultExtension(name, sizeof(name), ".jpg"); - LoadJPG( name, pic, width, height ); + LoadJPG( name, pic, width, height, qtrue ); if (*pic) { return; } COM_StripExtension(shortname,name,sizeof(name)); COM_DefaultExtension(name, sizeof(name), ".png"); - LoadPNG( name, pic, width, height ); // try png first + LoadPNG( name, pic, width, height, qtrue ); // try png first if (*pic){ return; } COM_StripExtension(shortname,name,sizeof(name)); COM_DefaultExtension(name, sizeof(name), ".tga"); - LoadTGA( name, pic, width, height ); // try tga first + LoadTGA( name, pic, width, height, qtrue ); // try tga first + if (*pic){ + return; + } + + + // Retry with JKA assets + COM_StripExtension(shortname,name,sizeof(name)); + COM_DefaultExtension(name, sizeof(name), ".jpg"); + LoadJPG( name, pic, width, height, qfalse ); + if (*pic) { + return; + } + + COM_StripExtension(shortname,name,sizeof(name)); + COM_DefaultExtension(name, sizeof(name), ".png"); + LoadPNG( name, pic, width, height, qfalse ); // try png first + if (*pic){ + return; + } + + COM_StripExtension(shortname,name,sizeof(name)); + COM_DefaultExtension(name, sizeof(name), ".tga"); + LoadTGA( name, pic, width, height, qfalse ); // try tga first if (*pic){ return; } diff --git a/src/renderer/tr_public.h b/src/renderer/tr_public.h index a683530d..1da17de7 100644 --- a/src/renderer/tr_public.h +++ b/src/renderer/tr_public.h @@ -150,6 +150,7 @@ typedef struct { // NULL can be passed for buf to just determine existance int (*FS_FileIsInPAK)( const char *name, int *pCheckSum ); int (*FS_ReadFile)( const char *name, void **buf ); + int (*FS_ReadFileSkipJKA)( const char *name, void **buf ); void (*FS_FreeFile)( void *buf ); const char ** (*FS_ListFiles)( const char *name, const char *extension, int *numfilesfound ); void (*FS_FreeFileList)( const char **filelist ); diff --git a/src/renderer/tr_shader.cpp b/src/renderer/tr_shader.cpp index cb2ae94c..7db0667f 100644 --- a/src/renderer/tr_shader.cpp +++ b/src/renderer/tr_shader.cpp @@ -3888,12 +3888,12 @@ a single large text block that can be scanned for shader names #define MAX_SHADER_FILES 4096 static void ScanAndLoadShaderFiles( const char *path ) { - const char **shaderFiles[2]; + const char **shaderFiles[3]; char *buffers[MAX_SHADER_FILES]; const char *p; char *pw; int numShaderFiles; - int numShaderFilesType[2]; + int numShaderFilesType[3]; int i, j, type; const char *oldp, *token; char *hashMem; @@ -3903,6 +3903,7 @@ static void ScanAndLoadShaderFiles( const char *path ) // scan for shader files shaderFiles[0] = ri.FS_ListFiles( path, ".shader_mv", &numShaderFilesType[0] ); shaderFiles[1] = ri.FS_ListFiles( path, ".shader", &numShaderFilesType[1] ); + shaderFiles[2] = ri.FS_ListFiles( path, ".shader_jka", &numShaderFilesType[2] ); if ( !shaderFiles[0] ) { @@ -3912,23 +3913,28 @@ static void ScanAndLoadShaderFiles( const char *path ) { numShaderFilesType[1] = 0; } + if ( !shaderFiles[2] ) + { + numShaderFilesType[2] = 0; + } - if ( numShaderFilesType[0] + numShaderFilesType[1] > MAX_SHADER_FILES ) { + if ( numShaderFilesType[0] + numShaderFilesType[1] + numShaderFilesType[2] > MAX_SHADER_FILES ) { ri.Printf( PRINT_WARNING, "WARNING: too many shader files, truncating...\n" ); numShaderFilesType[0] = MIN(numShaderFilesType[0], MAX_SHADER_FILES); - numShaderFilesType[1] = MAX_SHADER_FILES - numShaderFilesType[0]; + numShaderFilesType[1] = MIN(numShaderFilesType[1], MAX_SHADER_FILES - numShaderFilesType[0]); + numShaderFilesType[2] = MIN(numShaderFilesType[2], MAX_SHADER_FILES - numShaderFilesType[0] - numShaderFilesType[1]); } - numShaderFiles = numShaderFilesType[0] + numShaderFilesType[1]; + numShaderFiles = numShaderFilesType[0] + numShaderFilesType[1] + numShaderFilesType[2]; if (numShaderFiles == 0) { ri.Error( ERR_FATAL, "ERROR: no shader files found" ); } - assert(numShaderFilesType[0] > 0 || numShaderFilesType[1] > 0); + assert(numShaderFilesType[0] > 0 || numShaderFilesType[1] > 0 || numShaderFilesType[2] > 0); sum = 0; // load and parse shader files - for ( type = 0, j = 0; type < 2; type++ ) { + for ( type = 0, j = 0; type < 3; type++ ) { for ( i = 0; i < numShaderFilesType[type]; i++, j++ ) { char filename[MAX_QPATH]; @@ -3957,6 +3963,7 @@ static void ScanAndLoadShaderFiles( const char *path ) // free up memory ri.FS_FreeFileList( shaderFiles[0] ); ri.FS_FreeFileList( shaderFiles[1] ); + ri.FS_FreeFileList( shaderFiles[2] ); Com_Memset(shaderTextHashTableSizes, 0, sizeof(shaderTextHashTableSizes)); size = 0; diff --git a/src/sys/sys_public.h b/src/sys/sys_public.h index 9debe13c..3c5da3e7 100644 --- a/src/sys/sys_public.h +++ b/src/sys/sys_public.h @@ -116,6 +116,7 @@ int Sys_PID( void ); char *Sys_DefaultInstallPath(void); char *Sys_DefaultAssetsPath(); +char *Sys_DefaultAssetsPathJKA(); char *Sys_DefaultHomePath(void); #ifdef MACOS_X diff --git a/src/sys/sys_unix.cpp b/src/sys/sys_unix.cpp index e10f9cb3..e98eb6ad 100644 --- a/src/sys/sys_unix.cpp +++ b/src/sys/sys_unix.cpp @@ -453,6 +453,53 @@ char *Sys_DefaultAssetsPath() { #endif } +// Try to find assets from /Applications (Appstore JKA) or Steam. +// If neither worked try to find them in the same directory the jk2mv app is in. +char *Sys_DefaultAssetsPathJKA() { +#if defined(MACOS_X) && defined(INSTALLED) + static char path[MAX_OSPATH]; + char *ptr; + + // AppStore version (App name not verified, because the AppStore version + // doesn't support 32-bit and can't easily be obtained from the AppStore + // on modern Mac anymore; name guessed based on Steam version) + if (access("/Applications/SWJKJA.app/Contents/base/assets0.pk3", F_OK) != -1) { + return "/Applications/SWJKJA.app/Contents"; + } + + // Steam version + if (access(va("%s/Library/Application Support/Steam/steamapps/common/Jedi Academy/SWJKJA.app/Contents/base/assets0.pk3", getenv("HOME")), F_OK) != -1) { + Q_strncpyz(path, va("%s/Library/Application Support/Steam/steamapps/common/Jedi Academy/SWJKJA.app/Contents", getenv("HOME")), sizeof(path)); + return path; + } + + uint32_t size = sizeof(path); + if (_NSGetExecutablePath(path, &size)) { + return NULL; + } + + ptr = last_strstr(path, ".app/"); + if (!ptr) { + return NULL; + } + *ptr = 0; + + ptr = last_strstr(path, "/"); + if (!ptr) { + return NULL; + } + + strcpy(ptr, "/SWJKA.app/Contents"); + if (access(va("%s/base/assets0.pk3", path), F_OK) == -1) { + return NULL; + } + + return path; +#else + return NULL; +#endif +} + qboolean stdin_active = qtrue; qboolean stdinIsATTY = qfalse; int crashlogfd; diff --git a/src/sys/sys_win32.cpp b/src/sys/sys_win32.cpp index 989bc621..79d59b26 100644 --- a/src/sys/sys_win32.cpp +++ b/src/sys/sys_win32.cpp @@ -80,6 +80,35 @@ char *Sys_DefaultAssetsPath() { #endif } +// read the path from the registry on windows... apply the same workaround for the InstallPath as for jk2 +char *Sys_DefaultAssetsPathJKA() { +#ifdef INSTALLED + HKEY hKey; + static char installPath[MAX_OSPATH]; + DWORD installPathSize; + + // force 32bit registry + if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, "SOFTWARE\\LucasArts\\Star Wars Jedi Knight Jedi Academy\\1.0", + 0, KEY_WOW64_32KEY|KEY_QUERY_VALUE, &hKey) != ERROR_SUCCESS) { + return NULL; + } + + installPathSize = sizeof(installPath); + if (RegQueryValueExA(hKey, "Install Path", NULL, NULL, (LPBYTE)installPath, &installPathSize) != ERROR_SUCCESS) { + if (RegQueryValueExA(hKey, "InstallPath", NULL, NULL, (LPBYTE)installPath, &installPathSize) != ERROR_SUCCESS) { + RegCloseKey(hKey); + return NULL; + } + } + + RegCloseKey(hKey); + Q_strcat(installPath, sizeof(installPath), "\\GameData"); + return installPath; +#else + return NULL; +#endif +} + char *Sys_DefaultInstallPath(void) { return Sys_Cwd(); From 0614c82286a48d6b1cd8bdc701f0aeef1041709d Mon Sep 17 00:00:00 2001 From: Daggolin Date: Sun, 30 Apr 2023 00:15:38 +0200 Subject: [PATCH 02/10] Simplify shader workaround in FS_LoadZipFile. --- src/qcommon/files.cpp | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/qcommon/files.cpp b/src/qcommon/files.cpp index 10bd60c4..40f1e364 100644 --- a/src/qcommon/files.cpp +++ b/src/qcommon/files.cpp @@ -1981,13 +1981,10 @@ static pack_t *FS_LoadZipFile( char *zipfile, const char *basename, qboolean ass if ( assetsJKA ) { // Ugly workaround: rename academy shader files to avoid collisions if ( strLength > 7 && !Q_stricmp(filename_inzip + strLength - 7, ".shader") ) { - len += strLength + 5; // "_jka" + 1 - } else { - len += strlen(filename_inzip) + 1; + len += 4; // "_jka" } - } else { - len += strlen(filename_inzip) + 1; } + len += strLength + 1; unzGoToNextFile(uf); } From 2e4166da3aaafa21bd756741bb6beaf772cd8489 Mon Sep 17 00:00:00 2001 From: Daggolin Date: Sun, 30 Apr 2023 00:26:40 +0200 Subject: [PATCH 03/10] Replace FS_AddGameDirectory2 with FS_AddAssetsDirectoryJK2 and FS_AddAssetsDirectoryJKA. --- src/qcommon/files.cpp | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/src/qcommon/files.cpp b/src/qcommon/files.cpp index 40f1e364..a8dc0efb 100644 --- a/src/qcommon/files.cpp +++ b/src/qcommon/files.cpp @@ -2941,7 +2941,7 @@ const char *get_filename(const char *path) { return slash + 1; } -static void FS_AddGameDirectory2( const char *path, const char *dir, qboolean assetsOnly, qboolean assetsJKA ) { +static void FS_AddGameDirectory( const char *path, const char *dir, qboolean assetsJK2 = qfalse, qboolean assetsJKA = qfalse ) { searchpath_t *sp; int i; searchpath_t *search; @@ -2970,7 +2970,7 @@ static void FS_AddGameDirectory2( const char *path, const char *dir, qboolean as // // add the directory to the search path // - if (!assetsOnly && !assetsJKA) { + if (!assetsJK2 && !assetsJKA) { search = (struct searchpath_s *)Z_Malloc(sizeof(searchpath_t), TAG_FILESYS, qtrue); search->dir = (directory_t *)Z_Malloc(sizeof(*search->dir), TAG_FILESYS, qtrue); @@ -2996,7 +2996,7 @@ static void FS_AddGameDirectory2( const char *path, const char *dir, qboolean as pakfile = FS_BuildOSPath( path, dir, pakfiles[i] ); filename = get_filename(pakfile); - if (assetsOnly) { + if (assetsJK2) { if (strcmp(filename, "assets0.pk3") && strcmp(filename, "assets1.pk3") && strcmp(filename, "assets2.pk3") && strcmp(filename, "assets5.pk3")) { continue; @@ -3056,8 +3056,12 @@ static void FS_AddGameDirectory2( const char *path, const char *dir, qboolean as Sys_FreeFileList( pakfiles ); } -static void FS_AddGameDirectory( const char *path, const char *dir, qboolean assetsOnly ) { - FS_AddGameDirectory2( path, dir, assetsOnly, qfalse ); +static void FS_AddAssetsDirectoryJK2( const char *path, const char *dir ) { + FS_AddGameDirectory( path, dir, qtrue, qfalse ); +} + +static void FS_AddAssetsDirectoryJKA( const char *path, const char *dir ) { + FS_AddGameDirectory( path, dir, qfalse, qtrue ); } /* @@ -3346,41 +3350,41 @@ static void FS_Startup( const char *gameName ) { // Try to load JKA assets if a path has been specified if (fs_assetspathJKA->string[0] && !fs_noJKA->integer) { - FS_AddGameDirectory2(fs_assetspathJKA->string, BASEGAME, qfalse, qtrue); + FS_AddAssetsDirectoryJKA(fs_assetspathJKA->string, BASEGAME); } // don't use the assetspath if assets files already found in fs_basepath or fs_homepath if (fs_assetspath->string[0] && !FS_BaseHome_Base_FileExists("assets5.pk3")) { - FS_AddGameDirectory(fs_assetspath->string, BASEGAME, qtrue); + FS_AddAssetsDirectoryJK2(fs_assetspath->string, BASEGAME); } // add search path elements in reverse priority order if (fs_basepath->string[0]) { - FS_AddGameDirectory(fs_basepath->string, gameName, qfalse); + FS_AddGameDirectory(fs_basepath->string, gameName); } // fs_homepath is somewhat particular to *nix systems, only add if relevant // NOTE: same filtering below for mods and basegame if (fs_basepath->string[0] && Q_stricmp(fs_homepath->string,fs_basepath->string)) { - FS_AddGameDirectory(fs_homepath->string, gameName, qfalse); + FS_AddGameDirectory(fs_homepath->string, gameName); } // check for additional base game so mods can be based upon other mods if ( fs_basegame->string[0] && !Q_stricmp( gameName, BASEGAME ) && Q_stricmp( fs_basegame->string, gameName ) ) { if (fs_basepath->string[0]) { - FS_AddGameDirectory(fs_basepath->string, fs_basegame->string, qfalse); + 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, qfalse); + FS_AddGameDirectory(fs_homepath->string, fs_basegame->string); } } // check for additional game folder for mods if ( fs_gamedirvar->string[0] && !Q_stricmp( gameName, BASEGAME ) && Q_stricmp( fs_gamedirvar->string, gameName ) ) { if (fs_basepath->string[0]) { - FS_AddGameDirectory(fs_basepath->string, fs_gamedirvar->string, qfalse); + 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, qfalse); + FS_AddGameDirectory(fs_homepath->string, fs_gamedirvar->string); } } @@ -3388,10 +3392,10 @@ static void FS_Startup( const char *gameName ) { if ( fs_forcegame->string[0] && Q_stricmp(fs_forcegame->string, fs_gamedir) ) { if ( !fs_basegame->string[0] || Q_stricmp(fs_forcegame->string, fs_basegame->string) ) { if (fs_basepath->string[0]) { - FS_AddGameDirectory(fs_basepath->string, fs_forcegame->string, qfalse); + FS_AddGameDirectory(fs_basepath->string, fs_forcegame->string); } if (fs_homepath->string[0] && Q_stricmp(fs_homepath->string,fs_basepath->string)) { - FS_AddGameDirectory(fs_homepath->string, fs_forcegame->string, qfalse); + FS_AddGameDirectory(fs_homepath->string, fs_forcegame->string); } } Q_strncpyz( fs_gamedir, fs_forcegame->string, sizeof( fs_gamedir ) ); From ecd871d18d980705b2ca812aa23f4b69c1f21048 Mon Sep 17 00:00:00 2001 From: Daggolin Date: Sun, 30 Apr 2023 00:49:42 +0200 Subject: [PATCH 04/10] Fix jka assets getting incorrect gvc values. --- src/qcommon/files.cpp | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/qcommon/files.cpp b/src/qcommon/files.cpp index a8dc0efb..cbd57aaa 100644 --- a/src/qcommon/files.cpp +++ b/src/qcommon/files.cpp @@ -2093,14 +2093,16 @@ static pack_t *FS_LoadZipFile( char *zipfile, const char *basename, qboolean ass } // assets are hardcoded - if (!Q_stricmp(pack->pakBasename, "assets0")) { - pack->gvc = PACKGVC_1_02 | PACKGVC_1_03 | PACKGVC_1_04; - } else if (!Q_stricmp(pack->pakBasename, "assets1")) { - pack->gvc = PACKGVC_1_02 | PACKGVC_1_03 | PACKGVC_1_04; - } else if (!Q_stricmp(pack->pakBasename, "assets2")) { - pack->gvc = PACKGVC_1_03 | PACKGVC_1_04; - } else if (!Q_stricmp(pack->pakBasename, "assets5")) { - pack->gvc = PACKGVC_1_04; + if ( !assetsJKA ) { + if (!Q_stricmp(pack->pakBasename, "assets0")) { + pack->gvc = PACKGVC_1_02 | PACKGVC_1_03 | PACKGVC_1_04; + } else if (!Q_stricmp(pack->pakBasename, "assets1")) { + pack->gvc = PACKGVC_1_02 | PACKGVC_1_03 | PACKGVC_1_04; + } else if (!Q_stricmp(pack->pakBasename, "assets2")) { + pack->gvc = PACKGVC_1_03 | PACKGVC_1_04; + } else if (!Q_stricmp(pack->pakBasename, "assets5")) { + pack->gvc = PACKGVC_1_04; + } } return pack; From b4bc09fe549f8ba4beb52421241b6180b043929d Mon Sep 17 00:00:00 2001 From: Daggolin Date: Sun, 30 Apr 2023 00:52:33 +0200 Subject: [PATCH 05/10] Rename fs_noJKA cvar to fs_loadJKA. --- CVARS.rst | 8 ++++---- src/qcommon/files.cpp | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/CVARS.rst b/CVARS.rst index 44d28fd9..d99ed8a3 100644 --- a/CVARS.rst +++ b/CVARS.rst @@ -55,12 +55,12 @@ New and Modified Cvars .. -:Name: fs_noJKA +:Name: fs_loadJKA :Values: "0", "1" -:Default: "0" +:Default: "1" :Description: - Disables loading of JKA assets even when fs_assetsPathJKA point to a valid - JKA folder. + Enables loading of JKA assets when fs_assetsPathJKA point to a valid JKA + folder. ----------- Client-Side diff --git a/src/qcommon/files.cpp b/src/qcommon/files.cpp index cbd57aaa..8c94a0e9 100644 --- a/src/qcommon/files.cpp +++ b/src/qcommon/files.cpp @@ -237,7 +237,7 @@ static cvar_t *fs_homepath; static cvar_t *fs_basepath; static cvar_t *fs_assetspath; static cvar_t *fs_assetspathJKA; -static cvar_t *fs_noJKA; +static cvar_t *fs_loadJKA; static cvar_t *fs_basegame; static cvar_t *fs_copyfiles; static cvar_t *fs_gamedirvar; @@ -3332,7 +3332,7 @@ static void FS_Startup( const char *gameName ) { assetsPathJKA = Sys_DefaultAssetsPathJKA(); fs_assetspathJKA = Cvar_Get("fs_assetspathJKA", assetsPathJKA ? assetsPathJKA : "", CVAR_INIT | CVAR_VM_NOWRITE); - fs_noJKA = Cvar_Get("fs_noJKA", "0", CVAR_ARCHIVE); + fs_loadJKA = Cvar_Get("fs_loadJKA", "1", CVAR_ARCHIVE); if (!FS_AllPath_Base_FileExists("assets5.pk3")) { // assets files found in none of the paths @@ -3351,7 +3351,7 @@ static void FS_Startup( const char *gameName ) { } // Try to load JKA assets if a path has been specified - if (fs_assetspathJKA->string[0] && !fs_noJKA->integer) { + if (fs_assetspathJKA->string[0] && !fs_loadJKA->integer) { FS_AddAssetsDirectoryJKA(fs_assetspathJKA->string, BASEGAME); } @@ -3846,7 +3846,7 @@ void FS_InitFilesystem( void ) { Com_StartupVariable( "fs_basepath" ); Com_StartupVariable( "fs_homepath" ); Com_StartupVariable( "fs_assetspathJKA" ); - Com_StartupVariable( "fs_noJKA" ); + Com_StartupVariable( "fs_loadJKA" ); #if !defined(PORTABLE) Com_StartupVariable( "fs_assetspath" ); #endif From 0d68927807597aabad81e061d54c36d07a1e8fd9 Mon Sep 17 00:00:00 2001 From: Daggolin Date: Sun, 30 Apr 2023 01:02:25 +0200 Subject: [PATCH 06/10] Make fs_assetspathjka and fs_loadjka cvars lowercase to be more consistent with existing cvars. --- CVARS.rst | 6 +++--- src/qcommon/files.cpp | 16 ++++++++-------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/CVARS.rst b/CVARS.rst index d99ed8a3..da0576ab 100644 --- a/CVARS.rst +++ b/CVARS.rst @@ -47,7 +47,7 @@ New and Modified Cvars .. -:Name: fs_assetsPathJKA +:Name: fs_assetspathjka :Values: Foldername :Default: "" (Not set on portable); autodetected for non-portable :Description: @@ -55,11 +55,11 @@ New and Modified Cvars .. -:Name: fs_loadJKA +:Name: fs_loadjka :Values: "0", "1" :Default: "1" :Description: - Enables loading of JKA assets when fs_assetsPathJKA point to a valid JKA + Enables loading of JKA assets when fs_assetspathjka point to a valid JKA folder. ----------- diff --git a/src/qcommon/files.cpp b/src/qcommon/files.cpp index 8c94a0e9..f8206c0f 100644 --- a/src/qcommon/files.cpp +++ b/src/qcommon/files.cpp @@ -236,8 +236,8 @@ static cvar_t *fs_debug; static cvar_t *fs_homepath; static cvar_t *fs_basepath; static cvar_t *fs_assetspath; -static cvar_t *fs_assetspathJKA; -static cvar_t *fs_loadJKA; +static cvar_t *fs_assetspathjka; +static cvar_t *fs_loadjka; static cvar_t *fs_basegame; static cvar_t *fs_copyfiles; static cvar_t *fs_gamedirvar; @@ -3331,8 +3331,8 @@ static void FS_Startup( const char *gameName ) { fs_assetspath = Cvar_Get("fs_assetspath", assetsPath ? assetsPath : "", CVAR_INIT | CVAR_VM_NOWRITE); assetsPathJKA = Sys_DefaultAssetsPathJKA(); - fs_assetspathJKA = Cvar_Get("fs_assetspathJKA", assetsPathJKA ? assetsPathJKA : "", CVAR_INIT | CVAR_VM_NOWRITE); - fs_loadJKA = Cvar_Get("fs_loadJKA", "1", CVAR_ARCHIVE); + fs_assetspathjka = Cvar_Get("fs_assetspathjka", assetsPathJKA ? assetsPathJKA : "", CVAR_INIT | CVAR_VM_NOWRITE); + fs_loadjka = Cvar_Get("fs_loadjka", "1", CVAR_ARCHIVE); if (!FS_AllPath_Base_FileExists("assets5.pk3")) { // assets files found in none of the paths @@ -3351,8 +3351,8 @@ static void FS_Startup( const char *gameName ) { } // Try to load JKA assets if a path has been specified - if (fs_assetspathJKA->string[0] && !fs_loadJKA->integer) { - FS_AddAssetsDirectoryJKA(fs_assetspathJKA->string, BASEGAME); + if (fs_assetspathjka->string[0] && !fs_loadjka->integer) { + FS_AddAssetsDirectoryJKA(fs_assetspathjka->string, BASEGAME); } // don't use the assetspath if assets files already found in fs_basepath or fs_homepath @@ -3845,8 +3845,8 @@ void FS_InitFilesystem( void ) { // has already been initialized Com_StartupVariable( "fs_basepath" ); Com_StartupVariable( "fs_homepath" ); - Com_StartupVariable( "fs_assetspathJKA" ); - Com_StartupVariable( "fs_loadJKA" ); + Com_StartupVariable( "fs_assetspathjka" ); + Com_StartupVariable( "fs_loadjka" ); #if !defined(PORTABLE) Com_StartupVariable( "fs_assetspath" ); #endif From de3d8b3aa7975acb5bd651766861c8de444c5c91 Mon Sep 17 00:00:00 2001 From: Daggolin Date: Sun, 30 Apr 2023 23:58:51 +0200 Subject: [PATCH 07/10] Fix fs_loadjka check being inverted (forgot to invert it when renaming the cvar from fs_noJKA to fs_loadJKA). --- src/qcommon/files.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qcommon/files.cpp b/src/qcommon/files.cpp index f8206c0f..0a112ad2 100644 --- a/src/qcommon/files.cpp +++ b/src/qcommon/files.cpp @@ -3351,7 +3351,7 @@ static void FS_Startup( const char *gameName ) { } // Try to load JKA assets if a path has been specified - if (fs_assetspathjka->string[0] && !fs_loadjka->integer) { + if (fs_assetspathjka->string[0] && fs_loadjka->integer) { FS_AddAssetsDirectoryJKA(fs_assetspathjka->string, BASEGAME); } From 775cd2fecb73a59843931577bc1960b8d2abcad4 Mon Sep 17 00:00:00 2001 From: Daggolin Date: Mon, 1 May 2023 00:23:00 +0200 Subject: [PATCH 08/10] Add CVAR_LATCH flag to fs_loadjka. --- src/qcommon/files.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qcommon/files.cpp b/src/qcommon/files.cpp index 0a112ad2..bdab931f 100644 --- a/src/qcommon/files.cpp +++ b/src/qcommon/files.cpp @@ -3332,7 +3332,7 @@ static void FS_Startup( const char *gameName ) { assetsPathJKA = Sys_DefaultAssetsPathJKA(); fs_assetspathjka = Cvar_Get("fs_assetspathjka", assetsPathJKA ? assetsPathJKA : "", CVAR_INIT | CVAR_VM_NOWRITE); - fs_loadjka = Cvar_Get("fs_loadjka", "1", CVAR_ARCHIVE); + fs_loadjka = Cvar_Get("fs_loadjka", "1", CVAR_ARCHIVE | CVAR_LATCH); if (!FS_AllPath_Base_FileExists("assets5.pk3")) { // assets files found in none of the paths From e6804b6badead53c2ee9765f5fdfea8021750bf7 Mon Sep 17 00:00:00 2001 From: Daggolin Date: Mon, 1 May 2023 01:09:58 +0200 Subject: [PATCH 09/10] Add fs_basejka cvar. If fs_basejka is not explicitly set as launch argument: - if fs_assetspathjka is set on launch (either manually or via detection for non-portable versions) the fs_basejka cvar is set to "base" - if fs_assetspathjka is not set on launch the fs_basejka cvar is set to "basejka" to make it easier to manually provide assets --- src/qcommon/files.cpp | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/src/qcommon/files.cpp b/src/qcommon/files.cpp index bdab931f..34ee60c7 100644 --- a/src/qcommon/files.cpp +++ b/src/qcommon/files.cpp @@ -237,6 +237,7 @@ static cvar_t *fs_homepath; static cvar_t *fs_basepath; static cvar_t *fs_assetspath; static cvar_t *fs_assetspathjka; +static cvar_t *fs_basejka; static cvar_t *fs_loadjka; static cvar_t *fs_basegame; static cvar_t *fs_copyfiles; @@ -708,6 +709,20 @@ qboolean FS_BaseHome_Base_FileExists(const char *file) { return qfalse; } +qboolean FS_FileExistsIn(const char *base, const char *game, const char *qpath) { + FILE *f; + char *testpath; + + testpath = FS_BuildOSPath(base, game, qpath); + f = fopen(testpath, "rb"); + if (f) { + fclose(f); + return qtrue; + } + + return qfalse; +} + /* ================ FS_SV_FileExists @@ -3332,6 +3347,8 @@ static void FS_Startup( const char *gameName ) { assetsPathJKA = Sys_DefaultAssetsPathJKA(); fs_assetspathjka = Cvar_Get("fs_assetspathjka", assetsPathJKA ? assetsPathJKA : "", CVAR_INIT | CVAR_VM_NOWRITE); + fs_basejka = Cvar_Get("fs_basejka", fs_assetspathjka->string[0] ? "base" : "basejka", CVAR_INIT | CVAR_VM_NOWRITE); + fs_loadjka = Cvar_Get("fs_loadjka", "1", CVAR_ARCHIVE | CVAR_LATCH); if (!FS_AllPath_Base_FileExists("assets5.pk3")) { @@ -3351,8 +3368,18 @@ static void FS_Startup( const char *gameName ) { } // Try to load JKA assets if a path has been specified - if (fs_assetspathjka->string[0] && fs_loadjka->integer) { - FS_AddAssetsDirectoryJKA(fs_assetspathjka->string, BASEGAME); + if ( fs_loadjka->integer && fs_basejka->string[0] ) { + if (fs_assetspathjka->string[0]) { + // Got a JKA GameData path + FS_AddAssetsDirectoryJKA(fs_assetspathjka->string, fs_basejka->string); + } else { + // Try to find assets inside of a fs_basejka folder in any of the other paths + if (fs_basepath->string[0] && FS_FileExistsIn(fs_basepath->string, fs_basejka->string, "assets0.pk3")) { + FS_AddAssetsDirectoryJKA(fs_basepath->string, fs_basejka->string); + } else if (fs_homepath->string[0] && FS_FileExistsIn(fs_homepath->string, fs_basejka->string, "assets0.pk3")) { + FS_AddAssetsDirectoryJKA(fs_homepath->string, fs_basejka->string); + } + } } // don't use the assetspath if assets files already found in fs_basepath or fs_homepath From a8ba86453c3d8e3237921cede0f7d89d4a25e132 Mon Sep 17 00:00:00 2001 From: Daggolin Date: Mon, 1 May 2023 16:12:09 +0200 Subject: [PATCH 10/10] Add fs_basejka cvar to CVARS.rst. --- CVARS.rst | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/CVARS.rst b/CVARS.rst index da0576ab..49bba1da 100644 --- a/CVARS.rst +++ b/CVARS.rst @@ -55,6 +55,16 @@ New and Modified Cvars .. +:Name: fs_basejka +:Values: Foldername +:Default: "basejka" (if fs_assetspathjka is empty); "base" (if fs_assetspathjka is set) +:Description: + Name of the folder containing the JKA assets within fs_assetspathjka. If + fs_assetspathjka is not set the game tries to load assets from the specified + folder in fs_basepath and fs_homepath. + +.. + :Name: fs_loadjka :Values: "0", "1" :Default: "1"