Port faster file finding from SRB2Kart Saturn

This commit is contained in:
NepDisk 2025-12-11 10:47:22 -05:00
parent f792afd288
commit 4208fdd197
6 changed files with 202 additions and 85 deletions

View file

@ -712,7 +712,10 @@ static inline void CL_DrawConnectionStatus(void)
// Loading progress
V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT-24-32, MENUCAPS|V_YELLOWMAP, "Checking server addons...");
totalfileslength = !fileneedednum ? 0 : ((checkednum/fileneedednum) * 256);
if (checkednum && fileneedednum)
totalfileslength = (INT32)((checkednum/(double)(fileneedednum)) * 256);
else
totalfileslength = 0;
M_DrawTextBox(BASEVIDWIDTH/2-128-8, BASEVIDHEIGHT-24-8, 32, 1);
V_DrawFill(BASEVIDWIDTH/2-128, BASEVIDHEIGHT-24, 256, 8, 111);
V_DrawFill(BASEVIDWIDTH/2-128, BASEVIDHEIGHT-24, totalfileslength, 8, 96);

View file

@ -1330,17 +1330,23 @@ static void IdentifyVersion(void)
srb2waddir = I_LocateWad();
#endif
char tempsrb2path[256] = ".";
getcwd(tempsrb2path, 256);
// get the current directory (possible problem on NT with "." as current dir)
if (srb2waddir)
if (!srb2waddir)
{
strlcpy(srb2path,srb2waddir,sizeof (srb2path));
}
else
{
if (getcwd(srb2path, 256) != NULL)
srb2waddir = srb2path;
if (tempsrb2path[0])
srb2waddir = tempsrb2path;
else
srb2waddir = ".";
srb2waddir = srb2path;
}
#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

View file

@ -52,6 +52,7 @@ typedef enum
} mainwad_t;
// make sure not to write back the config until it's been correctly loaded
extern boolean gameconfig_loaded;
extern tic_t rendergametic;
extern char srb2home[256]; //Alam: My Home

View file

@ -1763,23 +1763,63 @@ filestatus_t findfile(char *filename, UINT64 wantedhash, boolean completepath)
filestatus_t homecheck; // store result of last file search
boolean badhash = false; // store whether hash was bad from either of the first two searches (if nothing was found in the third)
// skip for startup, our mainwads wont be in there
if (gameconfig_loaded)
{
if (cv_addons_option.value == 3 && *cv_addons_folder.string != '\0')
{
// first, check any custom directory if specified
homecheck = filesearch(filename, cv_addons_folder.string, wantedhash, completepath, 10);
if (homecheck == FS_FOUND) // we found the file, so return that we have :)
return FS_FOUND;
else if (homecheck == FS_BADHASH) // file has a bad hash; move on and look for a file with the right md5
badhash = true;
// if not found at all, just move on without doing anything
}
// next, check "DOWNLOAD" directory
homecheck = filesearch(filename, "DOWNLOAD", wantedhash, completepath, 10);
if (homecheck == FS_FOUND) // we found the file, so return that we have :)
return FS_FOUND;
else if (homecheck == FS_BADHASH) // file has a bad md5; move on and look for a file with the right md5
badhash = true;
// if not found at all, just move on without doing anything
// next, check "addons" directory
homecheck = filesearch(filename, "addons", wantedhash, completepath, 10);
if (homecheck == FS_FOUND) // we found the file, so return that we have :)
return FS_FOUND;
else if (homecheck == FS_BADHASH) // file has a bad md5; move on and look for a file with the right md5
badhash = true;
// if not found at all, just move on without doing anything
}
// first, check SRB2's "home" directory
homecheck = filesearch(filename, srb2home, wantedhash, completepath, 10);
if (strcmp(srb2home, "."))
{
homecheck = filesearch(filename, srb2home, wantedhash, completepath, 10);
if (homecheck == FS_FOUND) // we found the file, so return that we have :)
return FS_FOUND;
else if (homecheck == FS_BADHASH) // file has a bad hash; move on and look for a file with the right hash
badhash = true;
// if not found at all, just move on without doing anything
if (homecheck == FS_FOUND) // we found the file, so return that we have :)
return FS_FOUND;
else if (homecheck == FS_BADHASH) // file has a bad hash; move on and look for a file with the right hash
badhash = true;
// if not found at all, just move on without doing anything
}
// next, check SRB2's "path" directory
homecheck = filesearch(filename, srb2path, wantedhash, completepath, 10);
if (strcmp(srb2home, "."))
{
// next, check SRB2's "path" directory
homecheck = filesearch(filename, srb2path, wantedhash, completepath, 10);
if (homecheck == FS_FOUND) // we found the file, so return that we have :)
return FS_FOUND;
else if (homecheck == FS_BADHASH) // file has a bad hash; move on and look for a file with the right hash
badhash = true;
// if not found at all, just move on without doing anything
if (homecheck == FS_FOUND) // we found the file, so return that we have :)
return FS_FOUND;
else if (homecheck == FS_BADHASH) // file has a bad hash; move on and look for a file with the right hash
badhash = true;
// if not found at all, just move on without doing anything
}
// finally check "." directory
homecheck = filesearch(filename, ".", wantedhash, completepath, 10);

View file

@ -57,6 +57,14 @@ size_t dir_on[menudepth];
UINT8 refreshdirmenu = 0;
char *refreshdirname = NULL;
// skip those folders, they will not have any addons
static const char *exclude_paths[] = {
"logs",
"models",
"media",
NULL
};
filestatus_t filesearch(char *filename, const char *startpath, UINT64 wantedhash, boolean completepath, int maxsearchdepth)
{
filestatus_t retval = FS_NOTFOUND;
@ -66,27 +74,28 @@ filestatus_t filesearch(char *filename, const char *startpath, UINT64 wantedhash
struct stat fsstat;
#endif
int found = 0;
char *searchname = strdup(filename);
char *searchname;
int depthleft = maxsearchdepth;
char searchpath[MAXFILEPATH];
size_t *searchpathindex;
dirhandle = (DIR**) malloc(maxsearchdepth * sizeof (DIR*));
searchpathindex = (size_t *) malloc(maxsearchdepth * sizeof (size_t));
dirhandle = (DIR**)malloc(maxsearchdepth * sizeof(DIR*));
searchpathindex = (size_t *)malloc(maxsearchdepth * sizeof(size_t));
strcpy(searchpath,startpath);
strcpy(searchpath, startpath);
searchpathindex[--depthleft] = strlen(searchpath) + 1;
dirhandle[depthleft] = opendir(searchpath);
if (dirhandle[depthleft] == NULL)
{
free(searchname);
free(dirhandle);
free(searchpathindex);
return FS_NOTFOUND;
}
searchname = strdup(filename);
if (searchpath[searchpathindex[depthleft]-2] != PATHSEP[0])
{
searchpath[searchpathindex[depthleft]-1] = PATHSEP[0];
@ -118,63 +127,89 @@ filestatus_t filesearch(char *filename, const char *startpath, UINT64 wantedhash
// okay, now we actually want searchpath to incorporate d_name
strcpy(&searchpath[searchpathindex[depthleft]],dent->d_name);
#if defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__)
if (dent->d_type == DT_UNKNOWN && lstat(searchpath, &fsstat) == 0)
{
if (S_ISDIR(fsstat.st_mode))
#if defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__)
if (dent->d_type == DT_UNKNOWN || dent->d_type == DT_LNK)
if (stat(searchpath, &fsstat) == 0 && S_ISDIR(fsstat.st_mode))
dent->d_type = DT_DIR;
else if (S_ISLNK(fsstat.st_mode))
dent->d_type = DT_LNK;
}
// Symlinks aren't always directory symlinks. Dunno if this would resolve recursive
// symlinks, but i think stat already does that
if (dent->d_type == DT_LNK && stat(searchpath, &fsstat) == 0 && !S_ISDIR(fsstat.st_mode))
{
dent->d_type = DT_UNKNOWN;
}
// Linux and FreeBSD has a special field for file type on dirent, so use that to speed up lookups.
// FIXME: should we also follow symlinks?
if ((dent->d_type == DT_DIR && depthleft) || (dent->d_type == DT_LNK && depthleft))
#else
if (dent->d_type == DT_DIR)
#elif defined (_WIN32)
// if we wanna follow symlinks we can check with FILE_ATTRIBUTE_REPARSE_POINT
DWORD fileattr = GetFileAttributes(searchpath);
if (fileattr == INVALID_FILE_ATTRIBUTES)
; // was the file (re)moved? can't stat it
else if ((fileattr & FILE_ATTRIBUTE_DIRECTORY) && depthleft)
continue; // was the file (re)moved? can't stat it
if (fileattr & FILE_ATTRIBUTE_DIRECTORY)
#else
if (stat(searchpath,&fsstat) < 0) // do we want to follow symlinks? if not: change it to lstat
continue; // was the file (re)moved? can't stat it
if (S_ISDIR(fsstat.st_mode))
#endif
{
searchpathindex[--depthleft] = strlen(searchpath) + 1;
dirhandle[depthleft] = opendir(searchpath);
if (!dirhandle[depthleft])
{
// I am a folder!
if (!depthleft)
continue; // No additional folder delving permitted...
const char **path = exclude_paths;
if (depthleft == maxsearchdepth-1)
{
// can't open it... maybe no read-permissions
// go back to previous dir
depthleft++;
// When we're at the root of the search, we exclude certain folders.
boolean skipfolder = false;
for (; *path != NULL; path++)
{
if (strcasecmp(*path, dent->d_name) == 0)
{
skipfolder = true;
break;
}
}
// This folder is excluded
if (skipfolder)
{
continue;
}
}
searchpath[searchpathindex[depthleft]-1] = PATHSEP[0];
searchpath[searchpathindex[depthleft]] = 0;
}
else if (!strcasecmp(searchname, dent->d_name))
{
switch (checkfilehash(searchpath, wantedhash))
if (strcasecmp(".git", dent->d_name) // sanity if you're weird like me
&& (dirhandle[depthleft-1] = opendir(searchpath)) != NULL)
{
case FS_FOUND:
if (completepath)
strcpy(filename,searchpath);
else
strcpy(filename,dent->d_name);
retval = FS_FOUND;
found = 1;
break;
case FS_BADHASH:
retval = FS_BADHASH;
break;
default: // prevent some compiler warnings
break;
// Got read permissions!
searchpathindex[--depthleft] = strlen(searchpath) + 1;
searchpath[searchpathindex[depthleft]-1] = PATHSEP[0];
searchpath[searchpathindex[depthleft]] = 0;
}
continue;
}
// I am a file!
if (strcasecmp(searchname, dent->d_name))
continue; // Not what we're looking for!
switch (checkfilehash(searchpath, wantedhash))
{
case FS_FOUND:
if (completepath)
strcpy(filename, searchpath);
else
strcpy(filename, dent->d_name);
retval = FS_FOUND;
found = 1;
break;
case FS_BADHASH:
retval = FS_BADHASH;
break;
default: // prevent some compiler warnings
break;
}
}
@ -351,7 +386,9 @@ boolean preparefilemenu(boolean samedepth, boolean replayhut)
{
DIR *dirhandle;
struct dirent *dent;
#ifndef _WIN32
struct stat fsstat;
#endif
size_t pos = 0, folderpos = 0, numfolders = 0;
char *tempname = NULL;
@ -390,30 +427,43 @@ boolean preparefilemenu(boolean samedepth, boolean replayhut)
if (!dent)
break;
else if (dent->d_name[0]=='.' &&
(dent->d_name[1]=='\0' ||
(dent->d_name[1]=='.' &&
dent->d_name[2]=='\0')))
(dent->d_name[1]=='\0' ||
(dent->d_name[1]=='.' &&
dent->d_name[2]=='\0')))
continue; // we don't want to scan uptree
strcpy(&menupath[menupathindex[menudepthleft]],dent->d_name);
if (stat(menupath,&fsstat) < 0) // do we want to follow symlinks? if not: change it to lstat
#ifndef _WIN32
if (stat(menupath, &fsstat) < 0)
#else
// if we wanna follow symlinks we can check with FILE_ATTRIBUTE_REPARSE_POINT
DWORD fileattr = GetFileAttributes(menupath);
if (fileattr == INVALID_FILE_ATTRIBUTES)
#endif
; // was the file (re)moved? can't stat it
else // is a file or directory
{
#ifndef _WIN32
if (!S_ISDIR(fsstat.st_mode)) // file
#else
if (!(fileattr & FILE_ATTRIBUTE_DIRECTORY))
#endif
{
size_t len = strlen(dent->d_name)+1;
if (replayhut)
{
if (strcasecmp(".lmp", dent->d_name+len-5)) continue; // Not a replay
if (strcasecmp(".lmp", dent->d_name+len-5))
continue; // Not a replay
}
else if (!cv_addons_showall.value)
{
UINT8 ext;
for (ext = 0; ext < NUM_EXT_TABLE; ext++)
if (!strcasecmp(exttable[ext]+1, dent->d_name+len-(exttable[ext][0]))) break; // extension comparison
if (ext == NUM_EXT_TABLE) continue; // not an addfile-able (or exec-able) file
if (!strcasecmp(exttable[ext]+1, dent->d_name+len-(exttable[ext][0])))
break; // extension comparison
if (ext == NUM_EXT_TABLE)
continue; // not an addfile-able (or exec-able) file
}
}
else // directory
@ -465,7 +515,13 @@ boolean preparefilemenu(boolean samedepth, boolean replayhut)
strcpy(&menupath[menupathindex[menudepthleft]],dent->d_name);
if (stat(menupath,&fsstat) < 0) // do we want to follow symlinks? if not: change it to lstat
#ifndef _WIN32
if (stat(menupath, &fsstat) < 0)
#else
// if we wanna follow symlinks we can check with FILE_ATTRIBUTE_REPARSE_POINT
DWORD fileattr = GetFileAttributes(menupath);
if (fileattr == INVALID_FILE_ATTRIBUTES)
#endif
; // was the file (re)moved? can't stat it
else // is a file or directory
{
@ -474,20 +530,28 @@ boolean preparefilemenu(boolean samedepth, boolean replayhut)
UINT8 ext = EXT_FOLDER;
UINT8 folder;
#ifndef _WIN32
if (!S_ISDIR(fsstat.st_mode)) // file
#else
if (!(fileattr & FILE_ATTRIBUTE_DIRECTORY))
#endif
{
if (!((numfolders+pos) < sizecoredirmenu)) continue; // crash prevention
if (!((numfolders+pos) < sizecoredirmenu))
continue; // crash prevention
if (replayhut)
{
if (strcasecmp(".lmp", dent->d_name+len-5)) continue; // Not a replay
if (strcasecmp(".lmp", dent->d_name+len-5))
continue; // Not a replay
ext = EXT_TXT; // This isn't used anywhere but better safe than sorry for messing with this...
}
else
{
for (; ext < NUM_EXT_TABLE; ext++)
if (!strcasecmp(exttable[ext]+1, dent->d_name+len-(exttable[ext][0]))) break; // extension comparison
if (ext == NUM_EXT_TABLE && !cv_addons_showall.value) continue; // not an addfile-able (or exec-able) file
if (!strcasecmp(exttable[ext]+1, dent->d_name+len-(exttable[ext][0])))
break; // extension comparison
if (ext == NUM_EXT_TABLE && !cv_addons_showall.value)
continue; // not an addfile-able (or exec-able) file
ext += EXT_START; // moving to be appropriate position
if (ext >= EXT_LOADSTART)
@ -504,6 +568,7 @@ boolean preparefilemenu(boolean samedepth, boolean replayhut)
if (strcmp(dent->d_name, filenamebuf[i]))
continue;
if (cv_addons_md5.value && !checkfilehash(menupath, wadfiles[i]->hash))
continue;
@ -530,9 +595,11 @@ boolean preparefilemenu(boolean samedepth, boolean replayhut)
if (!(temp = Z_Malloc((len+DIR_STRING+folder) * sizeof (char), PU_STATIC, NULL)))
I_Error("preparefilemenu(): could not create file entry.");
temp[DIR_TYPE] = ext;
temp[DIR_LEN] = (UINT8)(len);
strlcpy(temp+DIR_STRING, dent->d_name, len);
if (folder)
{
strcpy(temp+len, PATHSEP);

View file

@ -465,7 +465,7 @@ char configfile[MAX_WADPATH];
// ==========================================================================
// CONFIGURATION
// ==========================================================================
static boolean gameconfig_loaded = false; // true once config.cfg loaded AND executed
boolean gameconfig_loaded = false; // true once config.cfg loaded AND executed
/** Saves a player's config, possibly to a particular file.
*