mirror of
https://github.com/KartKrewDev/RingRacers.git
synced 2025-10-30 08:01:28 +00:00
Merge branch 'file-fixes' into 'master'
Filesearch fixes See merge request kart-krew-dev/ring-racers-internal!2770
This commit is contained in:
commit
1da803c736
15 changed files with 243 additions and 167 deletions
|
|
@ -853,7 +853,7 @@ static void COM_Exec_f(void)
|
||||||
// Now try by searching the file path
|
// Now try by searching the file path
|
||||||
// filename is modified with the full found path
|
// filename is modified with the full found path
|
||||||
strcpy(filename, COM_Argv(1));
|
strcpy(filename, COM_Argv(1));
|
||||||
if (findfile(filename, NULL, true) != FS_NOTFOUND)
|
if (findfile(filename, NULL, NULL, true) != FS_NOTFOUND)
|
||||||
FIL_ReadFile(filename, &buf);
|
FIL_ReadFile(filename, &buf);
|
||||||
|
|
||||||
if (!buf)
|
if (!buf)
|
||||||
|
|
|
||||||
|
|
@ -1395,19 +1395,25 @@ static void IdentifyVersion(void)
|
||||||
srb2waddir = I_LocateWad();
|
srb2waddir = I_LocateWad();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
char tempsrb2path[256] = ".";
|
||||||
|
getcwd(tempsrb2path, 256);
|
||||||
|
|
||||||
// get the current directory (possible problem on NT with "." as current dir)
|
// get the current directory (possible problem on NT with "." as current dir)
|
||||||
if (srb2waddir)
|
if (!srb2waddir)
|
||||||
{
|
{
|
||||||
strlcpy(srb2path,srb2waddir,sizeof (srb2path));
|
if (tempsrb2path[0])
|
||||||
}
|
srb2waddir = tempsrb2path;
|
||||||
else
|
|
||||||
{
|
|
||||||
if (getcwd(srb2path, 256) != NULL)
|
|
||||||
srb2waddir = srb2path;
|
|
||||||
else
|
else
|
||||||
srb2waddir = ".";
|
srb2waddir = ".";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if (1) // reduce the amount of findfile by only using full cwd in this func
|
||||||
|
if (strcmp(tempsrb2path, srb2waddir))
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
strlcpy(srb2path, srb2waddir, sizeof (srb2path));
|
||||||
|
}
|
||||||
|
|
||||||
// Load the IWAD
|
// Load the IWAD
|
||||||
if (! AddIWAD())
|
if (! AddIWAD())
|
||||||
{
|
{
|
||||||
|
|
@ -1433,21 +1439,29 @@ static void IdentifyVersion(void)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define MUSICTEST(str) \
|
#define MUSICTEST(str) \
|
||||||
{\
|
musicpath = va(spandf,srb2waddir,"data",str);\
|
||||||
const char *musicpath = va(spandf,srb2waddir,"data",str);\
|
handle = W_OpenWadFile(&musicpath, NULL, false); \
|
||||||
int ms = W_VerifyNMUSlumps(musicpath, false); \
|
if (handle) \
|
||||||
if (ms == 1) \
|
|
||||||
{ \
|
{ \
|
||||||
D_AddFile(startupiwads, num_startupiwads++, musicpath, NULL); \
|
int ms = W_VerifyNMUSlumps(musicpath, handle, false); \
|
||||||
musicwads++; \
|
fclose(handle); \
|
||||||
} \
|
if (ms == 0) \
|
||||||
else if (ms == 0) \
|
I_Error("File " str " has been modified with non-music/sound lumps"); \
|
||||||
I_Error("File " str " has been modified with non-music/sound lumps"); \
|
if (ms == 1) \
|
||||||
}
|
{ \
|
||||||
|
D_AddFile(startupiwads, num_startupiwads++, musicpath, NULL); \
|
||||||
|
musicwads++; \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
|
||||||
MUSICTEST("sounds.pk3")
|
{
|
||||||
MUSICTEST("music.pk3")
|
const char *musicpath;
|
||||||
MUSICTEST("altmusic.pk3")
|
FILE *handle;
|
||||||
|
|
||||||
|
MUSICTEST("sounds.pk3")
|
||||||
|
MUSICTEST("music.pk3")
|
||||||
|
MUSICTEST("altmusic.pk3")
|
||||||
|
}
|
||||||
|
|
||||||
#undef MUSICTEST
|
#undef MUSICTEST
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4311,7 +4311,7 @@ static void Got_RunSOCcmd(const UINT8 **cp, INT32 playernum)
|
||||||
// Maybe add md5 support?
|
// Maybe add md5 support?
|
||||||
if (strstr(filename, ".soc") != NULL)
|
if (strstr(filename, ".soc") != NULL)
|
||||||
{
|
{
|
||||||
ncs = findfile(filename,NULL,true);
|
ncs = findfile(filename, "addons", NULL, true);
|
||||||
|
|
||||||
if (ncs != FS_FOUND)
|
if (ncs != FS_FOUND)
|
||||||
{
|
{
|
||||||
|
|
@ -4352,6 +4352,8 @@ static void Command_Addfile(void)
|
||||||
const char **addedfiles = Z_Calloc(sizeof(const char*) * argc, PU_STATIC, NULL);
|
const char **addedfiles = Z_Calloc(sizeof(const char*) * argc, PU_STATIC, NULL);
|
||||||
size_t numfilesadded = 0; // the amount of filenames processed
|
size_t numfilesadded = 0; // the amount of filenames processed
|
||||||
|
|
||||||
|
FILE *fhandle = NULL;
|
||||||
|
|
||||||
// start at one to skip command name
|
// start at one to skip command name
|
||||||
for (curarg = 1; curarg < argc; curarg++)
|
for (curarg = 1; curarg < argc; curarg++)
|
||||||
{
|
{
|
||||||
|
|
@ -4360,24 +4362,22 @@ static void Command_Addfile(void)
|
||||||
char *buf_p = buf;
|
char *buf_p = buf;
|
||||||
INT32 i;
|
INT32 i;
|
||||||
size_t ii;
|
size_t ii;
|
||||||
int musiconly; // W_VerifyNMUSlumps isn't boolean
|
int musiconly = -1; // W_VerifyNMUSlumps isn't boolean
|
||||||
boolean fileadded = false;
|
|
||||||
|
|
||||||
fn = COM_Argv(curarg);
|
fn = COM_Argv(curarg);
|
||||||
|
|
||||||
// For the amount of filenames previously processed...
|
// For the amount of filenames previously processed...
|
||||||
for (ii = 0; ii < numfilesadded; ii++)
|
for (ii = 0; ii < numfilesadded; ii++)
|
||||||
{
|
{
|
||||||
|
if (strcmp(fn, addedfiles[ii]))
|
||||||
|
continue;
|
||||||
|
|
||||||
// If this is one of them, don't try to add it.
|
// If this is one of them, don't try to add it.
|
||||||
if (!strcmp(fn, addedfiles[ii]))
|
break;
|
||||||
{
|
|
||||||
fileadded = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we've added this one, skip to the next one.
|
// If we've added this one, skip to the next one.
|
||||||
if (fileadded)
|
if (ii < numfilesadded)
|
||||||
{
|
{
|
||||||
CONS_Alert(CONS_WARNING, M_GetText("Already processed %s, skipping\n"), fn);
|
CONS_Alert(CONS_WARNING, M_GetText("Already processed %s, skipping\n"), fn);
|
||||||
continue;
|
continue;
|
||||||
|
|
@ -4385,13 +4385,22 @@ static void Command_Addfile(void)
|
||||||
|
|
||||||
// Disallow non-printing characters and semicolons.
|
// Disallow non-printing characters and semicolons.
|
||||||
for (i = 0; fn[i] != '\0'; i++)
|
for (i = 0; fn[i] != '\0'; i++)
|
||||||
if (!isprint(fn[i]) || fn[i] == ';')
|
{
|
||||||
{
|
if (isprint(fn[i]) && fn[i] != ';')
|
||||||
Z_Free(addedfiles);
|
continue;
|
||||||
return;
|
goto addfile_finally;
|
||||||
}
|
}
|
||||||
|
|
||||||
musiconly = W_VerifyNMUSlumps(fn, false);
|
if (fhandle)
|
||||||
|
{
|
||||||
|
fclose(fhandle);
|
||||||
|
fhandle = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((fhandle = W_OpenWadFile(&fn, "addons", true)) != NULL)
|
||||||
|
{
|
||||||
|
musiconly = W_VerifyNMUSlumps(fn, fhandle, false);
|
||||||
|
}
|
||||||
|
|
||||||
if (musiconly == -1)
|
if (musiconly == -1)
|
||||||
{
|
{
|
||||||
|
|
@ -4429,47 +4438,40 @@ static void Command_Addfile(void)
|
||||||
if (numwadfiles >= MAX_WADFILES)
|
if (numwadfiles >= MAX_WADFILES)
|
||||||
{
|
{
|
||||||
CONS_Alert(CONS_ERROR, M_GetText("Too many files loaded to add %s\n"), fn);
|
CONS_Alert(CONS_ERROR, M_GetText("Too many files loaded to add %s\n"), fn);
|
||||||
Z_Free(addedfiles);
|
goto addfile_finally;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
WRITESTRINGN(buf_p,p,240);
|
|
||||||
|
|
||||||
// calculate and check md5
|
// calculate and check md5
|
||||||
{
|
{
|
||||||
UINT8 md5sum[16];
|
UINT8 md5sum[16];
|
||||||
#ifdef NOMD5
|
#ifdef NOMD5
|
||||||
memset(md5sum,0,16);
|
memset(md5sum,0,16);
|
||||||
#else
|
#else
|
||||||
FILE *fhandle;
|
|
||||||
boolean valid = true;
|
|
||||||
|
|
||||||
if ((fhandle = W_OpenWadFile(&fn, true)) != NULL)
|
|
||||||
{
|
{
|
||||||
tic_t t = I_GetTime();
|
tic_t t = I_GetTime();
|
||||||
CONS_Debug(DBG_SETUP, "Making MD5 for %s\n",fn);
|
CONS_Debug(DBG_SETUP, "Making MD5 for %s\n",fn);
|
||||||
md5_stream(fhandle, md5sum);
|
md5_stream(fhandle, md5sum);
|
||||||
CONS_Debug(DBG_SETUP, "MD5 calc for %s took %f second\n", fn, (float)(I_GetTime() - t)/TICRATE);
|
CONS_Debug(DBG_SETUP, "MD5 calc for %s took %f second\n", fn, (float)(I_GetTime() - t)/TICRATE);
|
||||||
fclose(fhandle);
|
|
||||||
}
|
}
|
||||||
else // file not found
|
|
||||||
continue;
|
|
||||||
|
|
||||||
for (i = 0; i < numwadfiles; i++)
|
for (i = 0; i < numwadfiles; i++)
|
||||||
{
|
{
|
||||||
if (!memcmp(wadfiles[i]->md5sum, md5sum, 16))
|
if (memcmp(wadfiles[i]->md5sum, md5sum, 16))
|
||||||
{
|
continue;
|
||||||
CONS_Alert(CONS_ERROR, M_GetText("%s is already loaded\n"), fn);
|
|
||||||
valid = false;
|
CONS_Alert(CONS_ERROR, M_GetText("%s is already loaded\n"), fn);
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (valid == false)
|
if (i < numwadfiles)
|
||||||
{
|
{
|
||||||
|
// Already loaded, try next
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Finally okay to write this important data
|
||||||
|
WRITESTRINGN(buf_p,p,240);
|
||||||
WRITEMEM(buf_p, md5sum, 16);
|
WRITEMEM(buf_p, md5sum, 16);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -4481,6 +4483,10 @@ static void Command_Addfile(void)
|
||||||
SendNetXCmd(XD_ADDFILE, buf, buf_p - buf);
|
SendNetXCmd(XD_ADDFILE, buf, buf_p - buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
addfile_finally:
|
||||||
|
|
||||||
|
if (fhandle)
|
||||||
|
fclose(fhandle);
|
||||||
Z_Free(addedfiles);
|
Z_Free(addedfiles);
|
||||||
#endif/*TESTERS*/
|
#endif/*TESTERS*/
|
||||||
}
|
}
|
||||||
|
|
@ -4517,7 +4523,7 @@ static void Got_RequestAddfilecmd(const UINT8 **cp, INT32 playernum)
|
||||||
if (numwadfiles >= MAX_WADFILES)
|
if (numwadfiles >= MAX_WADFILES)
|
||||||
toomany = true;
|
toomany = true;
|
||||||
else
|
else
|
||||||
ncs = findfile(filename,md5sum,true);
|
ncs = findfile(filename, "addons", md5sum, true);
|
||||||
|
|
||||||
if (ncs != FS_FOUND || toomany)
|
if (ncs != FS_FOUND || toomany)
|
||||||
{
|
{
|
||||||
|
|
@ -4561,7 +4567,7 @@ static void Got_Addfilecmd(const UINT8 **cp, INT32 playernum)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ncs = findfile(filename,md5sum,true);
|
ncs = findfile(filename, "addons", md5sum, true);
|
||||||
|
|
||||||
if (ncs != FS_FOUND || !P_AddWadFile(filename))
|
if (ncs != FS_FOUND || !P_AddWadFile(filename))
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -636,7 +636,7 @@ INT32 CL_CheckFiles(void)
|
||||||
|
|
||||||
packetsize += nameonlylength(fileneeded[i].filename) + 22;
|
packetsize += nameonlylength(fileneeded[i].filename) + 22;
|
||||||
|
|
||||||
fileneeded[i].status = findfile(fileneeded[i].filename, fileneeded[i].md5sum, true);
|
fileneeded[i].status = findfile(fileneeded[i].filename, "addons", fileneeded[i].md5sum, true);
|
||||||
CONS_Debug(DBG_NETPLAY, "found %d\n", fileneeded[i].status);
|
CONS_Debug(DBG_NETPLAY, "found %d\n", fileneeded[i].status);
|
||||||
return 4;
|
return 4;
|
||||||
}
|
}
|
||||||
|
|
@ -1759,31 +1759,37 @@ filestatus_t checkfilemd5(char *filename, const UINT8 *wantedmd5sum)
|
||||||
// Rewritten by Monster Iestyn to be less stupid
|
// Rewritten by Monster Iestyn to be less stupid
|
||||||
// Note: if completepath is true, "filename" is modified, but only if FS_FOUND is going to be returned
|
// Note: if completepath is true, "filename" is modified, but only if FS_FOUND is going to be returned
|
||||||
// (Don't worry about WinCE's version of filesearch, nobody cares about that OS anymore)
|
// (Don't worry about WinCE's version of filesearch, nobody cares about that OS anymore)
|
||||||
filestatus_t findfile(char *filename, const UINT8 *wantedmd5sum, boolean completepath)
|
filestatus_t findfile(char *filename, const char *priorityfolder, const UINT8 *wantedmd5sum, boolean completepath)
|
||||||
{
|
{
|
||||||
filestatus_t homecheck; // store result of last file search
|
filestatus_t homecheck; // store result of last file search
|
||||||
boolean badmd5 = false; // store whether md5 was bad from either of the first two searches (if nothing was found in the third)
|
boolean badmd5 = false; // store whether md5 was bad from either of the first two searches (if nothing was found in the third)
|
||||||
|
|
||||||
// first, check SRB2's "home" directory
|
// first, check SRB2's "home" directory (if non-'.')
|
||||||
homecheck = filesearch(filename, srb2home, wantedmd5sum, completepath, 10);
|
if (strcmp(srb2home, "."))
|
||||||
|
{
|
||||||
|
homecheck = filesearch(filename, srb2home, priorityfolder, wantedmd5sum, completepath, 10);
|
||||||
|
|
||||||
if (homecheck == FS_FOUND) // we found the file, so return that we have :)
|
if (homecheck == FS_FOUND) // we found the file, so return that we have :)
|
||||||
return FS_FOUND;
|
return FS_FOUND;
|
||||||
else if (homecheck == FS_MD5SUMBAD) // file has a bad md5; move on and look for a file with the right md5
|
else if (homecheck == FS_MD5SUMBAD) // file has a bad md5; move on and look for a file with the right md5
|
||||||
badmd5 = true;
|
badmd5 = true;
|
||||||
// if not found at all, just move on without doing anything
|
// if not found at all, just move on without doing anything
|
||||||
|
}
|
||||||
|
|
||||||
// next, check SRB2's "path" directory
|
// next, check SRB2's "path" directory (also if non-'.')
|
||||||
homecheck = filesearch(filename, srb2path, wantedmd5sum, completepath, 10);
|
if (strcmp(srb2path, "."))
|
||||||
|
{
|
||||||
|
homecheck = filesearch(filename, srb2path, priorityfolder, wantedmd5sum, completepath, 10);
|
||||||
|
|
||||||
if (homecheck == FS_FOUND) // we found the file, so return that we have :)
|
if (homecheck == FS_FOUND) // we found the file, so return that we have :)
|
||||||
return FS_FOUND;
|
return FS_FOUND;
|
||||||
else if (homecheck == FS_MD5SUMBAD) // file has a bad md5; move on and look for a file with the right md5
|
else if (homecheck == FS_MD5SUMBAD) // file has a bad md5; move on and look for a file with the right md5
|
||||||
badmd5 = true;
|
badmd5 = true;
|
||||||
// if not found at all, just move on without doing anything
|
// if not found at all, just move on without doing anything
|
||||||
|
}
|
||||||
|
|
||||||
// finally check "." directory
|
// finally check "." directory
|
||||||
homecheck = filesearch(filename, ".", wantedmd5sum, completepath, 10);
|
homecheck = filesearch(filename, ".", priorityfolder, wantedmd5sum, completepath, 10);
|
||||||
|
|
||||||
if (homecheck != FS_NOTFOUND) // if not found this time, fall back on the below return statement
|
if (homecheck != FS_NOTFOUND) // if not found this time, fall back on the below return statement
|
||||||
return homecheck; // otherwise return the result we got
|
return homecheck; // otherwise return the result we got
|
||||||
|
|
|
||||||
|
|
@ -157,7 +157,7 @@ void Command_Downloads_f(void);
|
||||||
boolean fileexist(char *filename, time_t ptime);
|
boolean fileexist(char *filename, time_t ptime);
|
||||||
|
|
||||||
// Search a file in the wadpath, return FS_FOUND when found
|
// Search a file in the wadpath, return FS_FOUND when found
|
||||||
filestatus_t findfile(char *filename, const UINT8 *wantedmd5sum,
|
filestatus_t findfile(char *filename, const char *suggestedfolder, const UINT8 *wantedmd5sum,
|
||||||
boolean completepath);
|
boolean completepath);
|
||||||
filestatus_t checkfilemd5(char *filename, const UINT8 *wantedmd5sum);
|
filestatus_t checkfilemd5(char *filename, const UINT8 *wantedmd5sum);
|
||||||
|
|
||||||
|
|
|
||||||
136
src/filesrch.c
136
src/filesrch.c
|
|
@ -333,7 +333,8 @@ char *refreshdirname = NULL;
|
||||||
|
|
||||||
|
|
||||||
#if defined (_XBOX) && defined (_MSC_VER)
|
#if defined (_XBOX) && defined (_MSC_VER)
|
||||||
filestatus_t filesearch(char *filename, const char *startpath, const UINT8 *wantedmd5sum,
|
filestatus_t filesearch(char *filename, const char *startpath,
|
||||||
|
const char *priorityfolder, const UINT8 *wantedmd5sum,
|
||||||
boolean completepath, int maxsearchdepth)
|
boolean completepath, int maxsearchdepth)
|
||||||
{
|
{
|
||||||
//NONE?
|
//NONE?
|
||||||
|
|
@ -364,7 +365,8 @@ boolean preparefilemenu(boolean samedepth, boolean replayhut)
|
||||||
}
|
}
|
||||||
|
|
||||||
#elif defined (_WIN32_WCE)
|
#elif defined (_WIN32_WCE)
|
||||||
filestatus_t filesearch(char *filename, const char *startpath, const UINT8 *wantedmd5sum,
|
filestatus_t filesearch(char *filename, const char *startpath,
|
||||||
|
const char *priorityfolder, const UINT8 *wantedmd5sum,
|
||||||
boolean completepath, int maxsearchdepth)
|
boolean completepath, int maxsearchdepth)
|
||||||
{
|
{
|
||||||
#ifdef __GNUC__
|
#ifdef __GNUC__
|
||||||
|
|
@ -378,6 +380,8 @@ filestatus_t filesearch(char *filename, const char *startpath, const UINT8 *want
|
||||||
HANDLE searchhandle = INVALID_HANDLE_VALUE;
|
HANDLE searchhandle = INVALID_HANDLE_VALUE;
|
||||||
const wchar_t wm[4] = L"*.*";
|
const wchar_t wm[4] = L"*.*";
|
||||||
|
|
||||||
|
(void)priorityfolder;
|
||||||
|
|
||||||
//if (startpath) SetCurrentDirectory(startpath);
|
//if (startpath) SetCurrentDirectory(startpath);
|
||||||
if (FIL_ReadFileOK(filename))
|
if (FIL_ReadFileOK(filename))
|
||||||
{
|
{
|
||||||
|
|
@ -396,7 +400,7 @@ filestatus_t filesearch(char *filename, const char *startpath, const UINT8 *want
|
||||||
//if (SetCurrentDirectory(dta.cFileName))
|
//if (SetCurrentDirectory(dta.cFileName))
|
||||||
{ // can fail if we haven't the right
|
{ // can fail if we haven't the right
|
||||||
filestatus_t found;
|
filestatus_t found;
|
||||||
found = filesearch(filename,NULL,wantedmd5sum,completepath,maxsearchdepth-1);
|
found = filesearch(filename,NULL,NULL,wantedmd5sum,completepath,maxsearchdepth-1);
|
||||||
//SetCurrentDirectory("..");
|
//SetCurrentDirectory("..");
|
||||||
if (found == FS_FOUND || found == FS_MD5SUMBAD)
|
if (found == FS_FOUND || found == FS_MD5SUMBAD)
|
||||||
{
|
{
|
||||||
|
|
@ -435,14 +439,23 @@ boolean preparefilemenu(boolean samedepth, boolean replayhut)
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
filestatus_t filesearch(char *filename, const char *startpath, const UINT8 *wantedmd5sum, boolean completepath, int maxsearchdepth)
|
static const char *filesearch_exclude[] = {
|
||||||
|
"media",
|
||||||
|
"logs",
|
||||||
|
"luafiles",
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
filestatus_t filesearch(char *filename, const char *startpath,
|
||||||
|
const char *priorityfolder, const UINT8 *wantedmd5sum,
|
||||||
|
boolean completepath, int maxsearchdepth)
|
||||||
{
|
{
|
||||||
filestatus_t retval = FS_NOTFOUND;
|
filestatus_t retval = FS_NOTFOUND;
|
||||||
DIR **dirhandle;
|
DIR **dirhandle;
|
||||||
struct dirent *dent;
|
struct dirent *dent;
|
||||||
struct stat fsstat = {0};
|
struct stat fsstat = {0};
|
||||||
int found = 0;
|
int found = 0;
|
||||||
char *searchname = strdup(filename);
|
char *searchname;
|
||||||
int depthleft = maxsearchdepth;
|
int depthleft = maxsearchdepth;
|
||||||
char searchpath[1024];
|
char searchpath[1024];
|
||||||
size_t *searchpathindex;
|
size_t *searchpathindex;
|
||||||
|
|
@ -457,12 +470,13 @@ filestatus_t filesearch(char *filename, const char *startpath, const UINT8 *want
|
||||||
|
|
||||||
if (dirhandle[depthleft] == NULL)
|
if (dirhandle[depthleft] == NULL)
|
||||||
{
|
{
|
||||||
free(searchname);
|
|
||||||
free(dirhandle);
|
free(dirhandle);
|
||||||
free(searchpathindex);
|
free(searchpathindex);
|
||||||
return FS_NOTFOUND;
|
return FS_NOTFOUND;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
searchname = strdup(filename);
|
||||||
|
|
||||||
if (searchpath[searchpathindex[depthleft]-2] != PATHSEP[0])
|
if (searchpath[searchpathindex[depthleft]-2] != PATHSEP[0])
|
||||||
{
|
{
|
||||||
searchpath[searchpathindex[depthleft]-1] = PATHSEP[0];
|
searchpath[searchpathindex[depthleft]-1] = PATHSEP[0];
|
||||||
|
|
@ -471,6 +485,27 @@ filestatus_t filesearch(char *filename, const char *startpath, const UINT8 *want
|
||||||
else
|
else
|
||||||
searchpathindex[depthleft]--;
|
searchpathindex[depthleft]--;
|
||||||
|
|
||||||
|
if (priorityfolder != NULL)
|
||||||
|
{
|
||||||
|
// Start the search at [startpath]/priorityfolder
|
||||||
|
|
||||||
|
strcpy(&searchpath[searchpathindex[depthleft]], priorityfolder);
|
||||||
|
|
||||||
|
if (stat(searchpath,&fsstat) < 0) // do we want to follow symlinks? if not: change it to lstat
|
||||||
|
; // was the file (re)moved? can't stat it
|
||||||
|
else if (S_ISDIR(fsstat.st_mode) && depthleft)
|
||||||
|
{
|
||||||
|
if ((dirhandle[depthleft-1] = opendir(searchpath)) != NULL)
|
||||||
|
{
|
||||||
|
// Got read permissions!
|
||||||
|
searchpathindex[--depthleft] = strlen(searchpath) + 1;
|
||||||
|
|
||||||
|
searchpath[searchpathindex[depthleft]-1] = PATHSEP[0];
|
||||||
|
searchpath[searchpathindex[depthleft]] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
while ((!found) && (depthleft < maxsearchdepth))
|
while ((!found) && (depthleft < maxsearchdepth))
|
||||||
{
|
{
|
||||||
searchpath[searchpathindex[depthleft]]=0;
|
searchpath[searchpathindex[depthleft]]=0;
|
||||||
|
|
@ -492,42 +527,75 @@ filestatus_t filesearch(char *filename, const char *startpath, const UINT8 *want
|
||||||
}
|
}
|
||||||
|
|
||||||
// okay, now we actually want searchpath to incorporate d_name
|
// okay, now we actually want searchpath to incorporate d_name
|
||||||
strcpy(&searchpath[searchpathindex[depthleft]],dent->d_name);
|
strcpy(&searchpath[searchpathindex[depthleft]], dent->d_name);
|
||||||
|
|
||||||
if (stat(searchpath,&fsstat) < 0) // do we want to follow symlinks? if not: change it to lstat
|
if (stat(searchpath,&fsstat) < 0) // do we want to follow symlinks? if not: change it to lstat
|
||||||
; // was the file (re)moved? can't stat it
|
continue; // was the file (re)moved? can't stat it
|
||||||
else if (S_ISDIR(fsstat.st_mode) && depthleft)
|
|
||||||
|
if (S_ISDIR(fsstat.st_mode))
|
||||||
{
|
{
|
||||||
searchpathindex[--depthleft] = strlen(searchpath) + 1;
|
// I am a folder!
|
||||||
dirhandle[depthleft] = opendir(searchpath);
|
|
||||||
if (!dirhandle[depthleft])
|
if (!depthleft)
|
||||||
|
continue; // No additional folder delving permitted...
|
||||||
|
|
||||||
|
const char **path = filesearch_exclude;
|
||||||
|
|
||||||
|
if (depthleft == maxsearchdepth-1)
|
||||||
{
|
{
|
||||||
// can't open it... maybe no read-permissions
|
// When we're at the root of the search, we exclude certain folders.
|
||||||
// go back to previous dir
|
|
||||||
depthleft++;
|
if (priorityfolder != NULL
|
||||||
|
&& strcasecmp(priorityfolder, dent->d_name))
|
||||||
|
{
|
||||||
|
// We skip revisiting the priority by pretending
|
||||||
|
// it matched the first exclude directory instead
|
||||||
|
}
|
||||||
|
else for (; *path; path++)
|
||||||
|
{
|
||||||
|
if (strcasecmp(*path, dent->d_name))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*path)
|
||||||
|
continue; // This folder is excluded
|
||||||
}
|
}
|
||||||
|
|
||||||
searchpath[searchpathindex[depthleft]-1] = PATHSEP[0];
|
if (strcasecmp(".git", dent->d_name) // sanity if you're weird like me
|
||||||
searchpath[searchpathindex[depthleft]] = 0;
|
&& (dirhandle[depthleft-1] = opendir(searchpath)) != NULL)
|
||||||
}
|
|
||||||
else if (!strcasecmp(searchname, dent->d_name))
|
|
||||||
{
|
|
||||||
switch (checkfilemd5(searchpath, wantedmd5sum))
|
|
||||||
{
|
{
|
||||||
case FS_FOUND:
|
// Got read permissions!
|
||||||
if (completepath)
|
searchpathindex[--depthleft] = strlen(searchpath) + 1;
|
||||||
strcpy(filename,searchpath);
|
|
||||||
else
|
searchpath[searchpathindex[depthleft]-1] = PATHSEP[0];
|
||||||
strcpy(filename,dent->d_name);
|
searchpath[searchpathindex[depthleft]] = 0;
|
||||||
retval = FS_FOUND;
|
|
||||||
found = 1;
|
|
||||||
break;
|
|
||||||
case FS_MD5SUMBAD:
|
|
||||||
retval = FS_MD5SUMBAD;
|
|
||||||
break;
|
|
||||||
default: // prevent some compiler warnings
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// I am a file!
|
||||||
|
|
||||||
|
if (strcasecmp(searchname, dent->d_name))
|
||||||
|
continue; // Not what we're looking for!
|
||||||
|
|
||||||
|
switch (checkfilemd5(searchpath, wantedmd5sum))
|
||||||
|
{
|
||||||
|
case FS_FOUND:
|
||||||
|
if (completepath)
|
||||||
|
strcpy(filename,searchpath);
|
||||||
|
else
|
||||||
|
strcpy(filename,dent->d_name);
|
||||||
|
retval = FS_FOUND;
|
||||||
|
found = 1;
|
||||||
|
break;
|
||||||
|
case FS_MD5SUMBAD:
|
||||||
|
retval = FS_MD5SUMBAD;
|
||||||
|
break;
|
||||||
|
default: // prevent some compiler warnings
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,7 @@ extern consvar_t cv_addons_md5, cv_addons_showall, cv_addons_search_case, cv_add
|
||||||
|
|
||||||
\param filename the file to look for
|
\param filename the file to look for
|
||||||
\param startpath where to start look from
|
\param startpath where to start look from
|
||||||
|
\param priorityfolder priority for starting checking, then go back up?
|
||||||
\param wantedmd5sum want to check with MD5
|
\param wantedmd5sum want to check with MD5
|
||||||
\param completepath want to return the complete path of the file?
|
\param completepath want to return the complete path of the file?
|
||||||
\param maxsearchdepth the max depth to search for the file
|
\param maxsearchdepth the max depth to search for the file
|
||||||
|
|
@ -40,7 +41,7 @@ extern consvar_t cv_addons_md5, cv_addons_showall, cv_addons_search_case, cv_add
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
filestatus_t filesearch(char *filename, const char *startpath, const UINT8 *wantedmd5sum,
|
filestatus_t filesearch(char *filename, const char *startpath, const char *priorityfolder, const UINT8 *wantedmd5sum,
|
||||||
boolean completepath, int maxsearchdepth);
|
boolean completepath, int maxsearchdepth);
|
||||||
|
|
||||||
#define menudepth 20
|
#define menudepth 20
|
||||||
|
|
|
||||||
|
|
@ -1785,7 +1785,7 @@ static void G_LoadDemoExtraFiles(UINT8 **pp)
|
||||||
if (numwadfiles >= MAX_WADFILES)
|
if (numwadfiles >= MAX_WADFILES)
|
||||||
toomany = true;
|
toomany = true;
|
||||||
else
|
else
|
||||||
ncs = findfile(filename, md5sum, false);
|
ncs = findfile(filename, "addons", md5sum, false);
|
||||||
|
|
||||||
if (toomany)
|
if (toomany)
|
||||||
{
|
{
|
||||||
|
|
@ -1894,7 +1894,7 @@ static UINT8 G_CheckDemoExtraFiles(savebuffer_t *info, boolean quick)
|
||||||
|
|
||||||
if (numwadfiles >= MAX_WADFILES)
|
if (numwadfiles >= MAX_WADFILES)
|
||||||
error = DFILE_ERROR_CANNOTLOAD;
|
error = DFILE_ERROR_CANNOTLOAD;
|
||||||
else if (!quick && findfile(filename, md5sum, false) != FS_FOUND)
|
else if (!quick && findfile(filename, "addons", md5sum, false) != FS_FOUND)
|
||||||
error = DFILE_ERROR_CANNOTLOAD;
|
error = DFILE_ERROR_CANNOTLOAD;
|
||||||
else if (error < DFILE_ERROR_INCOMPLETEOUTOFORDER)
|
else if (error < DFILE_ERROR_INCOMPLETEOUTOFORDER)
|
||||||
error |= DFILE_ERROR_NOTLOADED;
|
error |= DFILE_ERROR_NOTLOADED;
|
||||||
|
|
|
||||||
|
|
@ -6739,7 +6739,7 @@ void M_DrawAddons(void)
|
||||||
if (modifiedgame)
|
if (modifiedgame)
|
||||||
V_DrawSmallScaledPatch(x, y, 0, addonsp[NUM_EXT+2]);
|
V_DrawSmallScaledPatch(x, y, 0, addonsp[NUM_EXT+2]);
|
||||||
|
|
||||||
m = numwadfiles-(mainwads+musicwads+1);
|
m = numwadfiles-(mainwads+musicwads);
|
||||||
|
|
||||||
V_DrawCenteredMenuString(BASEVIDWIDTH/2, y+4, (majormods ? highlightflags : V_TRANSLUCENT), va("%ld ADD-ON%s LOADED", (long)m, (m == 1) ? "" : "S")); //+2 for music, sounds, +1 for bios.pk3
|
V_DrawCenteredMenuString(BASEVIDWIDTH/2, y+4, (majormods ? highlightflags : V_TRANSLUCENT), va("%ld ADD-ON%s LOADED", (long)m, (m == 1) ? "" : "S")); //+2 for music, sounds, +1 for bios.pk3
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -628,7 +628,7 @@ void LUA_DumpFile(const char *filename)
|
||||||
|
|
||||||
// If findfile finds the file, the full path will be returned
|
// If findfile finds the file, the full path will be returned
|
||||||
// in filenamebuf == filename.
|
// in filenamebuf == filename.
|
||||||
if (findfile(filenamebuf, NULL, true))
|
if (findfile(filenamebuf, NULL, NULL, true))
|
||||||
{
|
{
|
||||||
if ((handle = fopen(filename, "rb")) == NULL)
|
if ((handle = fopen(filename, "rb")) == NULL)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -2160,7 +2160,7 @@ static const char *searchWad(const char *searchDir)
|
||||||
filestatus_t fstemp;
|
filestatus_t fstemp;
|
||||||
|
|
||||||
strcpy(tempsw, WADKEYWORD);
|
strcpy(tempsw, WADKEYWORD);
|
||||||
fstemp = filesearch(tempsw,searchDir,NULL,true,20);
|
fstemp = filesearch(tempsw, searchDir, NULL, NULL, true, 20);
|
||||||
if (fstemp == FS_FOUND)
|
if (fstemp == FS_FOUND)
|
||||||
{
|
{
|
||||||
pathonly(tempsw);
|
pathonly(tempsw);
|
||||||
|
|
|
||||||
|
|
@ -53,7 +53,7 @@ static char *searchFont(const char *fontsearchDir)
|
||||||
filestatus_t fstemp;
|
filestatus_t fstemp;
|
||||||
|
|
||||||
strcpy(tempsw, FONTFILE);
|
strcpy(tempsw, FONTFILE);
|
||||||
fstemp = filesearch(tempsw, fontsearchDir, NULL, true, 20);
|
fstemp = filesearch(tempsw, fontsearchDir, NULL, NULL, true, 20);
|
||||||
if (fstemp == FS_FOUND)
|
if (fstemp == FS_FOUND)
|
||||||
{
|
{
|
||||||
return tempsw;
|
return tempsw;
|
||||||
|
|
|
||||||
|
|
@ -3432,7 +3432,7 @@ static const char *searchWad(const char *searchDir)
|
||||||
filestatus_t fstemp;
|
filestatus_t fstemp;
|
||||||
|
|
||||||
strcpy(tempsw, WADKEYWORD);
|
strcpy(tempsw, WADKEYWORD);
|
||||||
fstemp = filesearch(tempsw,searchDir,NULL,true,20);
|
fstemp = filesearch(tempsw, searchDir, NULL, NULL, true, 20);
|
||||||
if (fstemp == FS_FOUND)
|
if (fstemp == FS_FOUND)
|
||||||
{
|
{
|
||||||
pathonly(tempsw);
|
pathonly(tempsw);
|
||||||
|
|
|
||||||
|
|
@ -186,7 +186,7 @@ static char filenamebuf[MAX_WADPATH];
|
||||||
// Returns the FILE * handle for the file, or NULL if not found or could not be opened
|
// Returns the FILE * handle for the file, or NULL if not found or could not be opened
|
||||||
// If "useerrors" is true then print errors in the console, else just don't bother
|
// If "useerrors" is true then print errors in the console, else just don't bother
|
||||||
// "filename" may be modified to have the correct path the actual file is located in, if necessary
|
// "filename" may be modified to have the correct path the actual file is located in, if necessary
|
||||||
FILE *W_OpenWadFile(const char **filename, boolean useerrors)
|
FILE *W_OpenWadFile(const char **filename, const char *priorityfolder, boolean useerrors)
|
||||||
{
|
{
|
||||||
FILE *handle;
|
FILE *handle;
|
||||||
|
|
||||||
|
|
@ -209,7 +209,7 @@ FILE *W_OpenWadFile(const char **filename, boolean useerrors)
|
||||||
|
|
||||||
// If findfile finds the file, the full path will be returned
|
// If findfile finds the file, the full path will be returned
|
||||||
// in filenamebuf == *filename.
|
// in filenamebuf == *filename.
|
||||||
if (findfile(filenamebuf, NULL, true))
|
if (findfile(filenamebuf, priorityfolder, NULL, true))
|
||||||
{
|
{
|
||||||
if ((handle = fopen(*filename, "rb")) == NULL)
|
if ((handle = fopen(*filename, "rb")) == NULL)
|
||||||
{
|
{
|
||||||
|
|
@ -845,10 +845,10 @@ UINT16 W_InitFile(const char *filename, boolean mainfile, boolean startup, const
|
||||||
}
|
}
|
||||||
|
|
||||||
// open wad file
|
// open wad file
|
||||||
if ((handle = W_OpenWadFile(&filename, true)) == NULL)
|
if ((handle = W_OpenWadFile(&filename, (mainfile ? NULL : "addons"), true)) == NULL)
|
||||||
return W_InitFileError(filename, startup);
|
return W_InitFileError(filename, startup);
|
||||||
|
|
||||||
important = W_VerifyNMUSlumps(filename, startup);
|
important = W_VerifyNMUSlumps(filename, handle, startup);
|
||||||
|
|
||||||
if (important == -1)
|
if (important == -1)
|
||||||
{
|
{
|
||||||
|
|
@ -959,8 +959,7 @@ UINT16 W_InitFile(const char *filename, boolean mainfile, boolean startup, const
|
||||||
|
|
||||||
if (important && !mainfile)
|
if (important && !mainfile)
|
||||||
{
|
{
|
||||||
//G_SetGameModified(true);
|
G_SetGameModified(true, false);
|
||||||
modifiedgame = true; // avoid savemoddata being set to false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|
@ -1072,8 +1071,8 @@ INT32 W_InitMultipleFiles(const initmultiplefilesentry_t *entries, INT32 count,
|
||||||
{
|
{
|
||||||
const initmultiplefilesentry_t *entry = &entries[i];
|
const initmultiplefilesentry_t *entry = &entries[i];
|
||||||
|
|
||||||
if (addons && !W_VerifyNMUSlumps(entry->filename, !addons))
|
// Previously, W_VerifyNMUSlumps was called to mark game modified
|
||||||
G_SetGameModified(true, false);
|
// for addons... but W_InitFile already does exactly that!
|
||||||
|
|
||||||
//CONS_Debug(DBG_SETUP, "Loading %s\n", *filenames);
|
//CONS_Debug(DBG_SETUP, "Loading %s\n", *filenames);
|
||||||
rc = W_InitFile(entry->filename, !addons, true, entry->md5sum);
|
rc = W_InitFile(entry->filename, !addons, true, entry->md5sum);
|
||||||
|
|
@ -2369,35 +2368,6 @@ W_VerifyPK3 (FILE *fp, lumpchecklist_t *checklist, boolean status)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Note: This never opens lumps themselves and therefore doesn't have to
|
|
||||||
// deal with compressed lumps.
|
|
||||||
static int W_VerifyFile(const char *filename, lumpchecklist_t *checklist,
|
|
||||||
boolean status)
|
|
||||||
{
|
|
||||||
FILE *handle;
|
|
||||||
int goodfile = false;
|
|
||||||
|
|
||||||
if (!checklist)
|
|
||||||
I_Error("No checklist for %s\n", filename);
|
|
||||||
// open wad file
|
|
||||||
if ((handle = W_OpenWadFile(&filename, false)) == NULL)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
if (stricmp(&filename[strlen(filename) - 4], ".pk3") == 0)
|
|
||||||
goodfile = W_VerifyPK3(handle, checklist, status);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// detect wad file by the absence of the other supported extensions
|
|
||||||
if (stricmp(&filename[strlen(filename) - 4], ".soc")
|
|
||||||
&& stricmp(&filename[strlen(filename) - 4], ".lua"))
|
|
||||||
{
|
|
||||||
goodfile = W_VerifyWAD(handle, checklist, status);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fclose(handle);
|
|
||||||
return goodfile;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/** Checks a wad for lumps other than music and sound.
|
/** Checks a wad for lumps other than music and sound.
|
||||||
* Used during game load to verify music.dta is a good file and during a
|
* Used during game load to verify music.dta is a good file and during a
|
||||||
|
|
@ -2411,7 +2381,7 @@ static int W_VerifyFile(const char *filename, lumpchecklist_t *checklist,
|
||||||
* file exists with that filename
|
* file exists with that filename
|
||||||
* \author Alam Arias
|
* \author Alam Arias
|
||||||
*/
|
*/
|
||||||
int W_VerifyNMUSlumps(const char *filename, boolean exit_on_error)
|
int W_VerifyNMUSlumps(const char *filename, FILE *handle, boolean exit_on_error)
|
||||||
{
|
{
|
||||||
lumpchecklist_t NMUSlist[] =
|
lumpchecklist_t NMUSlist[] =
|
||||||
{
|
{
|
||||||
|
|
@ -2464,7 +2434,24 @@ int W_VerifyNMUSlumps(const char *filename, boolean exit_on_error)
|
||||||
{NULL, 0},
|
{NULL, 0},
|
||||||
};
|
};
|
||||||
|
|
||||||
int status = W_VerifyFile(filename, NMUSlist, false);
|
int status = 0;
|
||||||
|
|
||||||
|
if (stricmp(&filename[strlen(filename) - 4], ".pk3") == 0)
|
||||||
|
{
|
||||||
|
status = W_VerifyPK3(handle, NMUSlist, false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// detect wad file by the absence of the other supported extensions
|
||||||
|
if (stricmp(&filename[strlen(filename) - 4], ".soc")
|
||||||
|
&& stricmp(&filename[strlen(filename) - 4], ".lua"))
|
||||||
|
{
|
||||||
|
status = W_VerifyWAD(handle, NMUSlist, false);
|
||||||
|
|
||||||
|
// repair file handle in this specific case
|
||||||
|
fseek(handle, 0, SEEK_SET);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (status == -1)
|
if (status == -1)
|
||||||
W_InitFileError(filename, exit_on_error);
|
W_InitFileError(filename, exit_on_error);
|
||||||
|
|
@ -2490,17 +2477,11 @@ void W_InitShaderLookup(const char *filename)
|
||||||
{
|
{
|
||||||
nameonly(filename_buf);
|
nameonly(filename_buf);
|
||||||
|
|
||||||
if (findfile(filename_buf, NULL, true))
|
if (!findfile(filename_buf, "data", NULL, true))
|
||||||
{
|
return;
|
||||||
if ((handle = fopen(filename_buf, "rb")) == NULL)
|
|
||||||
{
|
if ((handle = fopen(filename_buf, "rb")) == NULL)
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// It is acceptable to fail opening the pk3 lookup.
|
// It is acceptable to fail opening the pk3 lookup.
|
||||||
|
|
|
||||||
|
|
@ -147,7 +147,7 @@ extern wadfile_t *wadfiles[MAX_WADFILES];
|
||||||
void W_Shutdown(void);
|
void W_Shutdown(void);
|
||||||
|
|
||||||
// Opens a WAD file. Returns the FILE * handle for the file, or NULL if not found or could not be opened
|
// Opens a WAD file. Returns the FILE * handle for the file, or NULL if not found or could not be opened
|
||||||
FILE *W_OpenWadFile(const char **filename, boolean useerrors);
|
FILE *W_OpenWadFile(const char **filename, const char *priorityfolder, boolean useerrors);
|
||||||
// Load and add a wadfile to the active wad files, returns numbers of lumps, INT16_MAX on error
|
// Load and add a wadfile to the active wad files, returns numbers of lumps, INT16_MAX on error
|
||||||
UINT16 W_InitFile(const char *filename, boolean mainfile, boolean startup, const char *md5expected);
|
UINT16 W_InitFile(const char *filename, boolean mainfile, boolean startup, const char *md5expected);
|
||||||
|
|
||||||
|
|
@ -226,7 +226,7 @@ void *W_CacheSoftwarePatchNum(lumpnum_t lumpnum, INT32 tag);
|
||||||
|
|
||||||
void W_UnlockCachedPatch(void *patch);
|
void W_UnlockCachedPatch(void *patch);
|
||||||
|
|
||||||
int W_VerifyNMUSlumps(const char *filename, boolean exit_on_error);
|
int W_VerifyNMUSlumps(const char *filename, FILE *handle, boolean exit_on_error);
|
||||||
|
|
||||||
/// Initialize non-legacy GL shader lookup, which lives outside the lump management system.
|
/// Initialize non-legacy GL shader lookup, which lives outside the lump management system.
|
||||||
void W_InitShaderLookup(const char *filename);
|
void W_InitShaderLookup(const char *filename);
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue