1
0
Fork 0
forked from fte/fteqw

Add file uri support, requires a '-allowfileurl' commandline argument.

git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@6318 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
Spoike 2023-01-09 05:12:39 +00:00
parent cdcb3c3950
commit 503162aefe
12 changed files with 250 additions and 67 deletions

View file

@ -6174,12 +6174,15 @@ done:
qboolean Host_RunFile(const char *fname, int nlen, vfsfile_t *file)
{
hrf_t *f;
#if defined(_WIN32) && !defined(FTE_SDL) && !defined(WINRT) && !defined(_XBOX)
//win32 file urls are basically fucked, so defer to the windows api.
#if defined(FTE_TARGET_WEB)
if (nlen >= 8 && !strncmp(fname, "file:///", 8))
{ //just here so we don't get confused by the arbitrary scheme check below.
}
#else
//file urls need special handling, if only for percent-encoding.
char utf8[MAX_OSPATH*3];
if (nlen >= 7 && !strncmp(fname, "file://", 7))
if (nlen >= 5 && !strncmp(fname, "file:", 5))
{
qboolean Sys_ResolveFileURL(const char *inurl, int inlen, char *out, int outlen);
if (!Sys_ResolveFileURL(fname, nlen, utf8, sizeof(utf8)))
{
Con_Printf("Cannot resolve file url\n");
@ -6188,17 +6191,6 @@ qboolean Host_RunFile(const char *fname, int nlen, vfsfile_t *file)
fname = utf8;
nlen = strlen(fname);
}
#elif defined(FTE_TARGET_WEB)
if (nlen >= 8 && !strncmp(fname, "file:///", 8))
{ //just here so we don't get confused by the arbitrary scheme check below.
}
#else
//unix file urls are fairly consistant - must be an absolute path.
if (nlen >= 8 && !strncmp(fname, "file:///", 8))
{
fname += 7;
nlen -= 7;
}
#endif
else if((nlen >= 7 && !strncmp(fname, "http://", 7)) ||
(nlen >= 8 && !strncmp(fname, "https://", 8)))

View file

@ -1313,7 +1313,7 @@ void VARGS Con_ThrottlePrintf (float *timer, int developerlevel, const char *fmt
if (*timer > now)
; //in the future? zomg
else if (*timer > now-1)
else if (*timer >= now-1)
return; //within the last second
*timer = now; //in the future? zomg

View file

@ -13706,6 +13706,7 @@ qboolean Image_LocateHighResTexture(image_t *tex, flocation_t *bestloc, char *be
char *altname;
char *nextalt;
qboolean exactext = !!(tex->flags & IF_EXACTEXTENSION);
qboolean exactpath = false;
int locflags = FSLF_DEPTH_INEXPLICIT|FSLF_DEEPONFAILURE;
int bestdepth = 0x7fffffff, depth;
@ -13716,7 +13717,13 @@ qboolean Image_LocateHighResTexture(image_t *tex, flocation_t *bestloc, char *be
if (strncmp(tex->ident, "http:", 5) && strncmp(tex->ident, "https:", 6))
for(altname = tex->ident;altname;altname = nextalt)
{
nextalt = strchr(altname, ':');
if (!strncmp(altname, "file:", 5))
{
nextalt = strchr(altname+5, ':');
exactpath = true;
}
else
nextalt = strchr(altname, ':');
if (nextalt)
{
nextalt++;
@ -13754,18 +13761,21 @@ qboolean Image_LocateHighResTexture(image_t *tex, flocation_t *bestloc, char *be
if (!tex->fallbackdata || (gl_load24bit.ival && !(tex->flags & IF_NOREPLACE)))
{
#ifdef IMAGEFMT_DDS
Q_snprintfz(fname, sizeof(fname), "dds/%s.dds", nicename);
depth = FS_FLocateFile(fname, locflags, &loc);
if (depth < bestdepth)
if (!exactpath)
{
Q_strncpyz(bestname, fname, bestnamesize);
bestdepth = depth;
*bestloc = loc;
*bestflags = 0;
Q_snprintfz(fname, sizeof(fname), "dds/%s.dds", nicename);
depth = FS_FLocateFile(fname, locflags, &loc);
if (depth < bestdepth)
{
Q_strncpyz(bestname, fname, bestnamesize);
bestdepth = depth;
*bestloc = loc;
*bestflags = 0;
}
}
#endif
if (strchr(nicename, '/') || strchr(nicename, '\\')) //never look in a root dir for the pic
if (exactpath || strchr(nicename, '/') || strchr(nicename, '\\')) //never look in a root dir for the pic
i = 0;
else
i = 1;
@ -13774,6 +13784,8 @@ qboolean Image_LocateHighResTexture(image_t *tex, flocation_t *bestloc, char *be
{
if (!tex_path[i].enabled)
continue;
if (exactpath && i)
break;
if (tex_path[i].args >= 3)
{ //this is a path that needs subpaths
char subpath[MAX_QPATH];

View file

@ -62,6 +62,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#define FTEENGINE
#include "../plugins/plugin.h"
#endif
#include "fs.h"
#undef malloc
@ -1077,7 +1078,7 @@ static void Friendly_Crash_Handler(int sig, siginfo_t *info, void *vcontext)
#endif
backtrace_symbols_fd(array+firstframe, size-firstframe, 2);
if (sig == SIGINT)
if (sig == SIGINT || fs_readonly)
fd = -1; //don't write out crash logs on ctrl+c
else
fd = open("crash.log", O_WRONLY|O_CREAT|O_APPEND, S_IRUSR | S_IWUSR | S_IRGRP);
@ -1181,7 +1182,6 @@ char *Sys_ConsoleInput(void)
}
//begin meta generation helper
#include "fs.h"
static int Crypto_GenerateSignature(qbyte *hashdata, size_t hashsize, qbyte *signdata, size_t signsizemax)
{
int i;

View file

@ -1474,6 +1474,12 @@ qboolean Sys_ResolveFileURL(const char *inurl, int inlen, char *out, int outlen)
if (FAILED(pPathCreateFromUrlW(wurl, local, &grr, 0)))
return false;
narrowen(out, outlen, local);
while(*out)
{
if (*out == '\\')
*out = '/';
out++;
}
return true;
}
/*

View file

@ -1046,7 +1046,8 @@ void Con_TextEditor_f(void)
{
char *fname = Cmd_Argv(1);
char *line = strrchr(fname, ':');
if (line)
char *lineend = NULL;
if (line && strtol(line+1, &lineend, 0) && !lineend)
*line++ = 0;
if (!*fname)
{

View file

@ -19,6 +19,7 @@ hashtable_t filesystemhash;
static qboolean com_fschanged = true, com_fsneedreload;
qboolean com_installer = false;
qboolean fs_readonly;
static searchpath_t *fs_allowfileuri;
int waitingformanifest;
static unsigned int fs_restarts;
void *fs_thread_mutex;
@ -170,6 +171,85 @@ void VARGS VFS_PRINTF(vfsfile_t *vf, const char *format, ...)
#if defined(_WIN32) && !defined(FTE_SDL) && !defined(WINRT) && !defined(_XBOX)
//windows has a special helper function to handle legacy URIs.
#else
qboolean Sys_ResolveFileURL(const char *inurl, int inlen, char *out, int outlen)
{
const unsigned char *i = inurl, *inend = inurl+inlen;
unsigned char *o = out, *outend = out+outlen;
unsigned char hex;
//make sure its a file url...
if (inlen < 5 || strncmp(inurl, "file:", 5))
return false;
i += 5;
if (i+1 < inend && i[0] == '/' && i[1] == '/')
{ //has an authority field...
i+=2;
//except we don't support authorities other than ourself...
if (i < inend || *i != '/')
return false; //must be an absolute path...
#ifdef _WIN32
i++; //on windows, (full)absolute paths start with a drive name...
#endif
}
else if (i < inend && i[0] == '/')
; // file:/foo (no authority)
else
return false;
//everything else must be percent-encoded
while (i < inend)
{
if (!*i || o == outend)
return false; //don't allow nulls...
else if (*i == '/' && i+1<inend && i[1] == '/')
return false; //two slashes is invalid (can be parent directory on some systems, or just buggy or weird)
else if (*i == '\\')
return false; //don't allow backslashes. they're meant to be percent-encoded anyway.
else if (*i == '%' && i+2<inend)
{
hex = 0;
if (i[1] >= 'A' && i[1] <= 'F')
hex += i[1]-'A'+10;
else if (i[1] >= 'a' && i[1] <= 'f')
hex += i[1]-'a'+10;
else if (i[1] >= '0' && i[1] <= '9')
hex += i[1]-'0';
else
{
*o++ = *i++;
continue;
}
hex <<= 4;
if (i[2] >= 'A' && i[2] <= 'F')
hex += i[2]-'A'+10;
else if (i[2] >= 'a' && i[2] <= 'f')
hex += i[2]-'a'+10;
else if (i[2] >= '0' && i[2] <= '9')
hex += i[2]-'0';
else
{
*o++ = *i++;
continue;
}
*o++ = hex;
i += 3;
}
else
*o++ = *i++;
}
if (o == outend)
return false;
*o = 0;
return true;
}
#endif
@ -1104,7 +1184,7 @@ static int QDECL COM_Dir_List(const char *name, qofs_t size, time_t mtime, void
colour = "^1"; //superseeded
Q_snprintfz(link, sizeof(link), "\\tip\\flocate error");
}
else if (loc.search->handle == spath)
else if (loc.search->handle == spath || (fs_allowfileuri&&loc.search == fs_allowfileuri))
{
colour = "^2";
@ -1657,6 +1737,19 @@ int FS_FLocateFile(const char *filename, unsigned int lflags, flocation_t *loc)
loc->search = NULL;
loc->len = -1;
if (!strncmp(filename, "file:", 5))
{
if (fs_allowfileuri && Sys_ResolveFileURL(filename, strlen(filename), cleanpath, sizeof(cleanpath)))
{
fs_finds++;
found = fs_allowfileuri->handle->FindFile(fs_allowfileuri->handle, loc, cleanpath, NULL);
if (found)
loc->search = fs_allowfileuri;
}
pf = NULL;
goto fail;
}
filename = FS_GetCleanPath(filename, (lflags&FSLF_QUIET), cleanpath, sizeof(cleanpath));
if (!filename)
{
@ -1864,7 +1957,7 @@ qboolean FS_GetLocationForPackageHandle(flocation_t *loc, searchpathfuncs_t *spa
if (search->handle == spath)
{
loc->search = search;
return spath->FindFile(spath, loc, fname, NULL);
return spath->FindFile(spath, loc, fname, NULL) == FF_FOUND;
}
}
return false;
@ -2033,27 +2126,28 @@ static const char *FS_GetCleanPath(const char *pattern, qboolean silent, char *o
char *o;
char *seg;
char *end = outbuf + outlen;
static float throttletimer;
s = pattern;
seg = o = outbuf;
if (!pattern || !*pattern)
{
Con_Printf("Error: Empty filename\n");
Con_ThrottlePrintf(&throttletimer, 0, "Error: Empty filename\n");
return NULL;
}
for(;;)
{
if (o == end)
{
Con_Printf("Error: filename too long\n");
Con_ThrottlePrintf(&throttletimer, 0, "Error: filename too long\n");
return NULL;
}
if (*s == ':')
{
if (s == pattern+1 && (s[1] == '/' || s[1] == '\\'))
Con_Printf("Error: absolute path in filename %s\n", pattern);
Con_ThrottlePrintf(&throttletimer, 0, "Error: absolute path in filename %s\n", pattern);
else
Con_Printf("Error: alternative data stream in filename %s\n", pattern);
Con_ThrottlePrintf(&throttletimer, 0, "Error: alternative data stream in filename %s\n", pattern);
return NULL;
}
else if (*s == '\\' || *s == '/' || !*s)
@ -2062,7 +2156,7 @@ static const char *FS_GetCleanPath(const char *pattern, qboolean silent, char *o
{
if (o == outbuf)
{
Con_Printf("Error: absolute path in filename %s\n", pattern);
Con_ThrottlePrintf(&throttletimer, 0, "Error: absolute path in filename %s\n", pattern);
return NULL;
}
if (!*s)
@ -2070,7 +2164,7 @@ static const char *FS_GetCleanPath(const char *pattern, qboolean silent, char *o
*o++ = '\0';
break;
}
Con_Printf("Error: empty directory name (%s)\n", pattern);
Con_ThrottlePrintf(&throttletimer, 0, "Error: empty directory name (%s)\n", pattern);
s++;
continue;
}
@ -2080,17 +2174,17 @@ static const char *FS_GetCleanPath(const char *pattern, qboolean silent, char *o
seg++;
if (!seg[0])
{
Con_Printf("Error: No filename (%s)\n", pattern);
Con_ThrottlePrintf(&throttletimer, 0, "Error: No filename (%s)\n", pattern);
return NULL;
}
if (seg[0] == '.')
{
if (o == seg+1)
Con_Printf("Error: source directory (%s)\n", pattern);
Con_ThrottlePrintf(&throttletimer, 0, "Error: source directory (%s)\n", pattern);
else if (seg[1] == '.')
Con_Printf("Error: parent directory (%s)\n", pattern);
Con_ThrottlePrintf(&throttletimer, 0, "Error: parent directory (%s)\n", pattern);
else
Con_Printf("Error: hidden name (%s)\n", pattern);
Con_ThrottlePrintf(&throttletimer, 0, "Error: hidden name (%s)\n", pattern);
return NULL;
}
#if defined(_WIN32) || defined(__CYGWIN__)
@ -2108,7 +2202,7 @@ static const char *FS_GetCleanPath(const char *pattern, qboolean silent, char *o
{
if (o == seg+4 || seg[4] == ' '|| seg[4] == '\t' || seg[4] == '.')
{
Con_Printf("Error: reserved name in path (%c%c%c%c in %s)\n", seg[0], seg[1], seg[2], seg[3], pattern);
Con_ThrottlePrintf(&throttletimer, 0, "Error: reserved name in path (%c%c%c%c in %s)\n", seg[0], seg[1], seg[2], seg[3], pattern);
return NULL;
}
}
@ -2125,7 +2219,7 @@ static const char *FS_GetCleanPath(const char *pattern, qboolean silent, char *o
{
if (o == seg+3 || seg[3] == ' '|| seg[3] == '\t' || seg[3] == '.')
{
Con_Printf("Error: reserved name in path (%c%c%c in %s)\n", seg[0], seg[1], seg[2], pattern);
Con_ThrottlePrintf(&throttletimer, 0, "Error: reserved name in path (%c%c%c in %s)\n", seg[0], seg[1], seg[2], pattern);
return NULL;
}
}
@ -2401,6 +2495,16 @@ vfsfile_t *QDECL FS_OpenVFS(const char *filename, const char *mode, enum fs_rela
if (fs_readonly && *mode == 'w')
return NULL;
if (!strncmp(filename, "file:", 5))
{
if (fs_allowfileuri || relativeto == FS_SYSTEM)
{
if (Sys_ResolveFileURL(filename, strlen(filename), fullname, sizeof(fullname)))
return VFSOS_Open(fullname, mode);
}
return NULL;
}
if (relativeto == FS_SYSTEM)
return VFSOS_Open(filename, mode);
@ -2869,6 +2973,11 @@ static qboolean FS_EnumerateFilesEach(searchpathfuncs_t *handle, char *matches,
char *sep;
for (; matches; matches = sep)
{
if (!strncmp(matches, "file:", 5))
{
sep = strchr(matches+5, ':');
continue;
}
sep = strchr(matches, ':');
if (sep)
{
@ -2892,6 +3001,11 @@ static int FS_EnumerateFilesEachSys (const char *syspath, char *matches, int (*f
char *sep;
for (; matches; matches = sep)
{
if (!strncmp(matches, "file:", 5))
{
sep = strchr(matches+5, ':');
continue;
}
sep = strchr(matches, ':');
if (sep)
{
@ -2989,9 +3103,42 @@ searchpathfuncs_t *COM_EnumerateFilesPackage (char *matches, const char *package
}
return NULL;
}
struct fs_enumerate_fileuri_s
{
int (QDECL *func)(const char *, qofs_t, time_t mtime, void *, searchpathfuncs_t*);
void *parm;
};
static int QDECL COM_EnumerateFiles_FileURI (const char *name, qofs_t flags, time_t mtime, void *parm, searchpathfuncs_t *spath)
{
char syspath[MAX_OSPATH];
struct fs_enumerate_fileuri_s *e = parm;
size_t nlen = strlen(name)+1;
if (7+nlen > sizeof(syspath))
return true;
memcpy(syspath, "file://", 7);
memcpy(syspath+7, name, nlen);
return e->func(syspath, flags, mtime, e->parm, spath);
}
void COM_EnumerateFiles (const char *match, int (QDECL *func)(const char *, qofs_t, time_t mtime, void *, searchpathfuncs_t*), void *parm)
{
searchpath_t *search;
if (!strncmp(match, "file:", 5))
{
if (fs_allowfileuri)
{
char syspath[MAX_OSPATH];
struct fs_enumerate_fileuri_s e;
e.func = func;
e.parm = parm;
if (Sys_ResolveFileURL(match, strlen(match), syspath, sizeof(syspath)))
Sys_EnumerateFiles(NULL, syspath, COM_EnumerateFiles_FileURI, &e, NULL);
}
return;
}
for (search = com_searchpaths; search ; search = search->next)
{
// is the element a pak file?
@ -7502,6 +7649,11 @@ void COM_InitFilesystem (void)
COM_InitHomedir(NULL);
fs_readonly = COM_CheckParm("-readonly");
if (COM_CheckParm("-allowfileuri") || COM_CheckParm("-allowfileurl"))
{
fs_allowfileuri = (searchpath_t*)Z_Malloc (sizeof(searchpath_t));
fs_allowfileuri->handle = VFSOS_OpenPath(NULL, NULL, "", "", "");
}
fs_thread_mutex = Sys_CreateMutex();
}
@ -7520,7 +7672,10 @@ extern searchpathfuncs_t *(QDECL FSPAK_LoadArchive) (vfsfile_t *packhandle, sear
extern searchpathfuncs_t *(QDECL FSDWD_LoadArchive) (vfsfile_t *packhandle, searchpathfuncs_t *parent, const char *filename, const char *desc, const char *prefix);
#endif*/
void FS_RegisterDefaultFileSystems(void)
{
{ //packages listed last will be scanned for last (and thus be favoured when searching for game files)
#ifdef PACKAGE_DOOMWAD
FS_RegisterFileSystemType(NULL, "wad", FSDWD_LoadArchive, true);
#endif
#ifdef PACKAGE_DZIP
FS_RegisterFileSystemType(NULL, "dz", FSDZ_LoadArchive, false);
#endif
@ -7531,7 +7686,6 @@ void FS_RegisterDefaultFileSystems(void)
FS_RegisterFileSystemType(NULL, "PAK", FSPAK_LoadArchive, true);
#endif
#endif
FS_RegisterFileSystemType(NULL, "pk3dir", VFSOS_OpenPath, true); //used for git repos or whatever, to make packaging easier
#ifdef PACKAGE_PK3
FS_RegisterFileSystemType(NULL, "pk3", FSZIP_LoadArchive, true); //quake3's extension for zips
FS_RegisterFileSystemType(NULL, "pk4", FSZIP_LoadArchive, true); //quake4's extension for zips...
@ -7545,7 +7699,5 @@ void FS_RegisterDefaultFileSystems(void)
FS_RegisterFileSystemType(NULL, "dll", FSZIP_LoadArchive, false); //for plugin metas / self-extracting zips.
FS_RegisterFileSystemType(NULL, "so", FSZIP_LoadArchive, false); //for plugin metas / self-extracting zips.
#endif
#ifdef PACKAGE_DOOMWAD
FS_RegisterFileSystemType(NULL, "wad", FSDWD_LoadArchive, true);
#endif
FS_RegisterFileSystemType(NULL, "pk3dir", VFSOS_OpenPath, true); //used for git repos or whatever, to make packaging easier
}

View file

@ -601,7 +601,7 @@ static qboolean QDECL VFSW32_CreateLoc(searchpathfuncs_t *handle, flocation_t *l
loc->offset = 0;
loc->fhandle = handle;
loc->rawname[sizeof(loc->rawname)-1] = 0;
if (Q_snprintfz (loc->rawname, sizeof(loc->rawname), "%s/%s", wp->rootpath, filename))
if (Q_snprintfz (loc->rawname, sizeof(loc->rawname), "%s%s", wp->rootpath, filename))
return FF_NOTFOUND;
for (ofs = loc->rawname+1 ; *ofs ; ofs++)
{
@ -639,7 +639,7 @@ static unsigned int QDECL VFSW32_FLocate(searchpathfuncs_t *handle, flocation_t
*/
// check a file in the directory tree
if (Q_snprintfz (netpath, sizeof(netpath), "%s/%s", wp->rootpath, filename))
if (Q_snprintfz (netpath, sizeof(netpath), "%s%s", wp->rootpath, filename))
return FF_NOTFOUND;
if (!WinNT)
@ -716,8 +716,8 @@ static qboolean QDECL VFSW32_RenameFile(searchpathfuncs_t *handle, const char *o
char newsyspath[MAX_OSPATH];
if (fs_readonly)
return false;
snprintf (oldsyspath, sizeof(oldsyspath)-1, "%s/%s", wp->rootpath, oldfname);
snprintf (newsyspath, sizeof(newsyspath)-1, "%s/%s", wp->rootpath, newfname);
snprintf (oldsyspath, sizeof(oldsyspath)-1, "%s%s", wp->rootpath, oldfname);
snprintf (newsyspath, sizeof(newsyspath)-1, "%s%s", wp->rootpath, newfname);
return Sys_Rename(oldsyspath, newsyspath);
}
static qboolean QDECL VFSW32_RemoveFile(searchpathfuncs_t *handle, const char *filename)
@ -726,7 +726,7 @@ static qboolean QDECL VFSW32_RemoveFile(searchpathfuncs_t *handle, const char *f
char syspath[MAX_OSPATH];
if (fs_readonly)
return false;
snprintf (syspath, sizeof(syspath)-1, "%s/%s", wp->rootpath, filename);
snprintf (syspath, sizeof(syspath)-1, "%s%s", wp->rootpath, filename);
if (*filename && filename[strlen(filename)-1] == '/')
return Sys_rmdir(syspath);
return Sys_remove(syspath);
@ -745,6 +745,8 @@ searchpathfuncs_t *QDECL VFSW32_OpenPath(vfsfile_t *mustbenull, searchpathfuncs_
{
wchar_t wide[MAX_OSPATH];
memcpy(np->rootpath, desc, dlen+1);
if (*np->rootpath)
Q_strncpy(np->rootpath+dlen, "/", 2);
if (!WinNT)
np->changenotification = FindFirstChangeNotificationA(np->rootpath, true, FILE_NOTIFY_CHANGE_FILE_NAME|FILE_NOTIFY_CHANGE_CREATION);
else

View file

@ -75,6 +75,8 @@ unsigned int Sys_Milliseconds (void);
double Sys_DoubleTime (void);
qboolean Sys_RandomBytes(qbyte *string, int len);
qboolean Sys_ResolveFileURL(const char *inurl, int inlen, char *out, int outlen);
char *Sys_ConsoleInput (void);
typedef enum

View file

@ -2220,8 +2220,8 @@ void Q_InitProgs(enum initprogs_e flags)
oldprnum=prnum;
}
//progs depended on by maps.
a = as = COM_LoadStackFile(va("maps/%s.inf", svs.name), addons, sizeof(addons), NULL);
/* //progs depended on by maps.
a = as = COM_LoadStackFile(va("%s.inf", sv.modelname), addons, sizeof(addons), NULL);
if (a)
{
if (progstype == PROG_QW)
@ -2284,7 +2284,7 @@ void Q_InitProgs(enum initprogs_e flags)
a++;
}
}
*/
//add any addons specified
for (i2 = 0; i2 < MAXADDONS; i2++)
{

View file

@ -698,7 +698,7 @@ void SV_Map_f (void)
{
char *mangled = Cmd_Argv(1);
char *sep = strchr(mangled, ':');
if (sep)
if (sep && strncmp(mangled, "file:", 5) && strncmp(mangled, "http:", 5) && strncmp(mangled, "https:", 5))
{
*sep++ = 0;
if (Cmd_FromGamecode())
@ -737,7 +737,7 @@ void SV_Map_f (void)
else
{
snprintf (expanded, sizeof(expanded), "maps/%s.bsp", level); // this function and the if statement below, is a quake bugfix which stopped a map called "dm6++.bsp" from loading because of the + sign, quake2 map syntax interprets + character as "intro.cin+base1.bsp", to play a cinematic then load a map after
if (!COM_FCheckExists (expanded))
if (!COM_FCheckExists (level) && !COM_FCheckExists (expanded))
{
nextserver = strchr(level, '+');
if (nextserver)
@ -841,7 +841,7 @@ void SV_Map_f (void)
else
#endif
{
char *exts[] = {"maps/%s", "maps/%s.bsp", "maps/%s.bsp.gz", "maps/%s.bsp.xz", "maps/%s.cm", "maps/%s.hmp", /*"maps/%s.map",*/ /*"maps/%s.ent",*/ NULL};
char *exts[] = {"%s", "maps/%s", "maps/%s.bsp", "maps/%s.bsp.gz", "maps/%s.bsp.xz", "maps/%s.cm", "maps/%s.hmp", /*"maps/%s.map",*/ /*"maps/%s.ent",*/ NULL};
int i, j;
for (i = 0; exts[i]; i++)

View file

@ -1016,22 +1016,38 @@ void SV_SpawnServer (const char *server, const char *startspot, qboolean noents,
{
//.map is commented out because quite frankly, they're a bit annoying when the engine loads the gpled start.map when really you wanted to just play the damn game intead of take it apart.
//if you want to load a .map, just use 'map foo.map' instead.
char *exts[] = {"maps/%s", "maps/%s.bsp", "maps/%s.cm", "maps/%s.hmp", /*"maps/%s.map",*/ "maps/%s.bsp.gz", "maps/%s.bsp.xz", NULL};
char *exts[] = {"maps/%s", "maps/%s.bsp", "maps/%s.cm", "maps/%s.hmp", /*"maps/%s.map",*/ "maps/%s.bsp.gz", "maps/%s.bsp.xz", NULL}, *e;
int depth, bestdepth;
flocation_t loc;
time_t filetime;
Q_strncpyz (svs.name, server, sizeof(svs.name));
Q_snprintfz (sv.modelname, sizeof(sv.modelname), exts[0], server);
Q_snprintfz (sv.modelname, sizeof(sv.modelname), "%s", server);
bestdepth = COM_FDepthFile(sv.modelname, false);
for (i = 1; exts[i]; i++)
{
depth = COM_FDepthFile(va(exts[i], server), false);
if (depth < bestdepth)
if (bestdepth == FDEPTH_MISSING)
{ //not an exact name, scan the maps subdir.
for (i = 0; exts[i]; i++)
{
bestdepth = depth;
Q_snprintfz (sv.modelname, sizeof(sv.modelname), exts[i], server);
depth = COM_FDepthFile(va(exts[i], server), false);
if (depth < bestdepth)
{
bestdepth = depth;
Q_snprintfz (sv.modelname, sizeof(sv.modelname), exts[i], server);
}
}
}
if (!strncmp(sv.modelname, "maps/", 5))
Q_strncpyz (svs.name, sv.modelname+5, sizeof(svs.name));
else
Q_strncpyz (svs.name, sv.modelname, sizeof(svs.name));
e = (char*)COM_GetFileExtension(svs.name, NULL);
if (!strcmp(e, ".gz") || !strcmp(e, ".xz"))
{
*e = 0;
e = (char*)COM_GetFileExtension(svs.name, NULL);
}
if (!strcmp(e, ".bsp"))
*e = 0;
sv.world.worldmodel = Mod_ForName (sv.modelname, MLV_ERROR);
if (FS_FLocateFile(sv.modelname,FSLF_IFFOUND, &loc) && FS_GetLocMTime(&loc, &filetime))