diff --git a/engine/client/cl_main.c b/engine/client/cl_main.c index 03a8a8495..375afeb72 100644 --- a/engine/client/cl_main.c +++ b/engine/client/cl_main.c @@ -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))) diff --git a/engine/client/console.c b/engine/client/console.c index e128b4396..c17919aab 100644 --- a/engine/client/console.c +++ b/engine/client/console.c @@ -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 diff --git a/engine/client/image.c b/engine/client/image.c index 63c1d3062..d1f33518a 100644 --- a/engine/client/image.c +++ b/engine/client/image.c @@ -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]; diff --git a/engine/client/sys_linux.c b/engine/client/sys_linux.c index c517717ce..cb0eaa496 100644 --- a/engine/client/sys_linux.c +++ b/engine/client/sys_linux.c @@ -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; diff --git a/engine/client/sys_win.c b/engine/client/sys_win.c index 66d2ac305..825725bf5 100644 --- a/engine/client/sys_win.c +++ b/engine/client/sys_win.c @@ -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; } /* diff --git a/engine/client/textedit.c b/engine/client/textedit.c index 1ef13a7f1..de354583c 100644 --- a/engine/client/textedit.c +++ b/engine/client/textedit.c @@ -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) { diff --git a/engine/common/fs.c b/engine/common/fs.c index 2d0254308..41f0b6663 100644 --- a/engine/common/fs.c +++ b/engine/common/fs.c @@ -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= '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 } diff --git a/engine/common/fs_win32.c b/engine/common/fs_win32.c index a7cdce974..315a88043 100644 --- a/engine/common/fs_win32.c +++ b/engine/common/fs_win32.c @@ -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 diff --git a/engine/common/sys.h b/engine/common/sys.h index 534d48ca2..06a463a5b 100644 --- a/engine/common/sys.h +++ b/engine/common/sys.h @@ -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 diff --git a/engine/server/pr_cmds.c b/engine/server/pr_cmds.c index a82d23e09..d1929681c 100644 --- a/engine/server/pr_cmds.c +++ b/engine/server/pr_cmds.c @@ -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++) { diff --git a/engine/server/sv_ccmds.c b/engine/server/sv_ccmds.c index 10a472910..051a959a3 100644 --- a/engine/server/sv_ccmds.c +++ b/engine/server/sv_ccmds.c @@ -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++) diff --git a/engine/server/sv_init.c b/engine/server/sv_init.c index bf5babd4d..b2bfd1aa6 100644 --- a/engine/server/sv_init.c +++ b/engine/server/sv_init.c @@ -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))