Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for loading JKA assets. #159

Merged
merged 10 commits into from May 1, 2023
17 changes: 17 additions & 0 deletions CVARS.rst
Expand Up @@ -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_loadjka
:Values: "0", "1"
:Default: "1"
:Description:
Enables loading of JKA assets when fs_assetspathjka point to a valid JKA
folder.

-----------
Client-Side
-----------
Expand Down
1 change: 1 addition & 0 deletions src/client/cl_main.cpp
Expand Up @@ -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;
Expand Down
118 changes: 89 additions & 29 deletions src/qcommon/files.cpp
Expand Up @@ -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
aufau marked this conversation as resolved.
Show resolved Hide resolved
} pack_t;

typedef struct {
Expand All @@ -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_loadjka;
static cvar_t *fs_basegame;
static cvar_t *fs_copyfiles;
static cvar_t *fs_gamedirvar;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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;
Expand All @@ -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;

Expand All @@ -1961,7 +1977,14 @@ 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 += 4; // "_jka"
}
}
len += strLength + 1;
unzGoToNextFile(uf);
}

Expand Down Expand Up @@ -2005,6 +2028,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;
Expand Down Expand Up @@ -2063,14 +2093,16 @@ static pack_t *FS_LoadZipFile( char *zipfile, const char *basename )
}

// 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;
Expand Down Expand Up @@ -2911,7 +2943,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_AddGameDirectory( const char *path, const char *dir, qboolean assetsJK2 = qfalse, qboolean assetsJKA = qfalse ) {
searchpath_t *sp;
int i;
searchpath_t *search;
Expand Down Expand Up @@ -2940,7 +2972,7 @@ static void FS_AddGameDirectory( const char *path, const char *dir, qboolean ass
//
// add the directory to the search path
//
if (!assetsOnly) {
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);

Expand All @@ -2966,14 +2998,19 @@ static void FS_AddGameDirectory( const char *path, const char *dir, qboolean ass
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;
}
} 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
Expand Down Expand Up @@ -3008,6 +3045,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;
Expand All @@ -3018,6 +3058,14 @@ static void FS_AddGameDirectory( const char *path, const char *dir, qboolean ass
Sys_FreeFileList( pakfiles );
}

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 );
}

/*
================
FS_idPak
Expand Down Expand Up @@ -3261,6 +3309,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;
Expand All @@ -3281,6 +3330,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_loadjka = Cvar_Get("fs_loadjka", "1", CVAR_ARCHIVE);

if (!FS_AllPath_Base_FileExists("assets5.pk3")) {
// assets files found in none of the paths
#if defined(INSTALLED)
Expand All @@ -3297,49 +3350,54 @@ 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_loadjka->integer) {
FS_AddAssetsDirectoryJKA(fs_assetspathjka->string, BASEGAME);
}

// 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_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);
}
}

// forcegame allows users to override any fs_game settings
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 ) );
Expand Down Expand Up @@ -3787,6 +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" );
#if !defined(PORTABLE)
Com_StartupVariable( "fs_assetspath" );
#endif
Expand Down
5 changes: 3 additions & 2 deletions src/qcommon/qcommon.h
Expand Up @@ -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
Expand All @@ -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.
Expand Down