diff --git a/engine/client/cl_input.c b/engine/client/cl_input.c index a55f72541..e2de0e55e 100644 --- a/engine/client/cl_input.c +++ b/engine/client/cl_input.c @@ -155,6 +155,26 @@ static kbutton_t in_button[19+1]; static int in_impulse[MAX_SPLITS][IN_IMPULSECACHE]; static int in_nextimpulse[MAX_SPLITS]; static int in_impulsespending[MAX_SPLITS]; +static void CL_QueueImpulse (int pnum, int newimp) +{ + if (cl_queueimpulses.ival) + { + if (in_impulsespending[pnum]>=IN_IMPULSECACHE) + { + Con_Printf("Too many impulses, ignoring %i\n", newimp); + return; + } + in_impulse[pnum][(in_nextimpulse[pnum]+in_impulsespending[pnum])%IN_IMPULSECACHE] = newimp; + in_impulsespending[pnum]++; + } + else + { + if (in_impulsespending[pnum]) + Con_DPrintf("Too many impulses, forgetting %i\n", in_impulse[pnum][(in_nextimpulse[pnum])%IN_IMPULSECACHE]); + in_impulse[pnum][(in_nextimpulse[pnum])%IN_IMPULSECACHE] = newimp; + in_impulsespending[pnum]=1; + } +} qboolean cursor_active; @@ -349,10 +369,7 @@ static void IN_DoPostSelect(void) int pnum = CL_TargettedSplit(false); int best = IN_BestWeapon_Pre(pnum); if (best) - { - in_impulse[pnum][(in_nextimpulse[pnum])%IN_IMPULSECACHE] = best; - in_impulsespending[pnum]=1; - } + CL_QueueImpulse(pnum, best); } } //The weapon command autoselects a prioritised weapon like multi-arg impulse does. @@ -391,21 +408,7 @@ void IN_Weapon (void) if (mode == 2 && !(in_attack.state[pnum]&3)) return; //2 changes instantly only when already firing. - if (cl_queueimpulses.ival) - { - if (in_impulsespending[pnum]>=IN_IMPULSECACHE) - { - Con_Printf("Too many impulses, ignoring %i\n", newimp); - return; - } - in_impulse[pnum][(in_nextimpulse[pnum]+in_impulsespending[pnum])%IN_IMPULSECACHE] = newimp; - in_impulsespending[pnum]++; - } - else - { - in_impulse[pnum][(in_nextimpulse[pnum])%IN_IMPULSECACHE] = newimp; - in_impulsespending[pnum]=1; - } + CL_QueueImpulse(pnum, newimp); } //+fire 8 7 [keycode] @@ -425,10 +428,7 @@ void IN_FireDown(void) impulse = IN_BestWeapon_Args(pnum, 1, impulse); if (impulse) - { - in_impulse[pnum][(in_nextimpulse[pnum])%IN_IMPULSECACHE] = impulse; - in_impulsespending[pnum]=1; - } + CL_QueueImpulse(pnum, impulse); else IN_DoPostSelect(); @@ -452,8 +452,7 @@ static void IN_DoWeaponHide(void) } if (best) { //looks like we're switching away - in_impulse[pnum][(in_nextimpulse[pnum])%IN_IMPULSECACHE] = best; - in_impulsespending[pnum]=1; + CL_QueueImpulse(pnum, best); } } } @@ -656,22 +655,7 @@ void IN_Impulse (void) } #endif - if (in_impulsespending[pnum]>=IN_IMPULSECACHE) - { - Con_Printf("Too many impulses, ignoring %i\n", newimp); - return; - } - - if (cl_queueimpulses.ival) - { - in_impulse[pnum][(in_nextimpulse[pnum]+in_impulsespending[pnum])%IN_IMPULSECACHE] = newimp; - in_impulsespending[pnum]++; - } - else - { - in_impulse[pnum][(in_nextimpulse[pnum])%IN_IMPULSECACHE] = newimp; - in_impulsespending[pnum]=1; - } + CL_QueueImpulse(pnum, newimp); } void IN_Restart (void) @@ -1182,9 +1166,9 @@ static void CL_FinishMove (usercmd_t *cmd, int pnum) if (in_impulsespending[pnum] && !cl.paused) { + cmd->impulse = in_impulse[pnum][(in_nextimpulse[pnum])%IN_IMPULSECACHE]; in_nextimpulse[pnum]++; in_impulsespending[pnum]--; - cmd->impulse = in_impulse[pnum][(in_nextimpulse[pnum]-1)%IN_IMPULSECACHE]; } else cmd->impulse = 0; @@ -2286,7 +2270,7 @@ void CL_SendCmd (double frametime, qboolean mainloop) cl_pendingcmd[plnum].angles[i] = ((int)(cl.playerview[plnum].viewangles[i]*65536.0/360)&65535); CL_BaseMove (&cl_pendingcmd[plnum], plnum, cl_pendingcmd[plnum].msec, framemsecs); - if (!cl_pendingcmd[plnum].msec) + if (!cl_pendingcmd[plnum].msec && framemsecs) { CL_FinishMove(&cl_pendingcmd[plnum], plnum); Cbuf_Waited(); //its okay to stop waiting now diff --git a/engine/client/cl_main.c b/engine/client/cl_main.c index 73c986732..510fdfd74 100644 --- a/engine/client/cl_main.c +++ b/engine/client/cl_main.c @@ -1199,6 +1199,9 @@ void CL_CheckForResend (void) void CL_BeginServerConnect(const char *host, int port, qboolean noproxy) { + if (!strncmp(host, "localhost", 9)) + noproxy = true; //FIXME: resolve the address here or something so that we don't end up using a proxy for lan addresses. + if (strstr(host, "://") || !*cl_proxyaddr.string || noproxy) Q_strncpyz (cls.servername, host, sizeof(cls.servername)); else diff --git a/engine/client/net_master.c b/engine/client/net_master.c index 02d8b678b..6343c4285 100644 --- a/engine/client/net_master.c +++ b/engine/client/net_master.c @@ -1433,7 +1433,7 @@ serverinfo_t *Master_FindRoute(netadr_t target) return NULL; //never flood into a peer if its just going to be more expensive than a direct connection - if (*cl_proxyaddr.string) + if (*cl_proxyaddr.string && NET_ClassifyAddress(&target, NULL) >= ASCOPE_NET) { //fixme: we don't handle chained proxies properly, as we assume we can directly hop to the named final proxy. //fixme: we'll find the same route, we just won't display the correct expected ping. diff --git a/engine/client/pr_csqc.c b/engine/client/pr_csqc.c index 6e325dbf4..19fd02453 100644 --- a/engine/client/pr_csqc.c +++ b/engine/client/pr_csqc.c @@ -7168,6 +7168,8 @@ static struct { {"search_getfilename", PF_search_getfilename,447}, // #447 string search_getfilename(float handle, float num) (DP_QC_FS_SEARCH) {"search_getfilesize", PF_search_getfilesize, 0}, {"search_getfilemtime", PF_search_getfilemtime, 0}, + {"search_getpackagename", PF_search_getpackagename, 0}, + {"search_fopen", PF_search_fopen, 0}, {"cvar_string", PF_cvar_string, 448}, // #448 string(float n) cvar_string (DP_QC_CVAR_STRING) {"findflags", PF_FindFlags, 449}, // #449 entity(entity start, .entity fld, float match) findflags (DP_QC_FINDFLAGS) diff --git a/engine/client/pr_menu.c b/engine/client/pr_menu.c index 0096324d9..bb2a66c6d 100644 --- a/engine/client/pr_menu.c +++ b/engine/client/pr_menu.c @@ -2389,6 +2389,8 @@ static struct { {"search_getfilename", PF_search_getfilename, 77}, {"search_getfilesize", PF_search_getfilesize, 0}, {"search_getfilemtime", PF_search_getfilemtime, 0}, + {"search_getpackagename", PF_search_getpackagename, 0}, + {"search_fopen", PF_search_fopen, 0}, {"chr2str", PF_chr2str, 78}, {"etof", PF_etof, 79}, {"ftoe", PF_ftoe, 80}, @@ -2797,16 +2799,18 @@ static qboolean MP_KeyEvent(menu_t *menu, qboolean isdown, unsigned int devid, i if (isdown) { #ifndef NOBUILTINMENUS +#ifdef _DEBUG if (key == 'c') { extern qboolean keydown[K_MAX]; - if (keydown[K_LCTRL] || keydown[K_RCTRL]) + if ((keydown[K_LCTRL] || keydown[K_RCTRL]) && (keydown[K_LSHIFT] || keydown[K_RSHIFT])) { MP_Shutdown(); M_Init_Internal(); return true; } } +#endif #endif mpkeysdown[key>>3] |= (1<<(key&7)); diff --git a/engine/client/renderer.c b/engine/client/renderer.c index a75860168..763f5fb99 100644 --- a/engine/client/renderer.c +++ b/engine/client/renderer.c @@ -476,7 +476,7 @@ cvar_t gl_mipcap = CVARAFCD("d_mipcap", "0 1000", "gl_miptexLevel", cvar_t gl_texturemode2d = CVARFCD("gl_texturemode2d", "GL_LINEAR", CVAR_ARCHIVE | CVAR_RENDERERCALLBACK, Image_TextureMode_Callback, "Specifies how 2d images are sampled. format is a 3-tupple "); -cvar_t r_font_linear = CVARF("r_font_linear", "1", 0); +cvar_t r_font_linear = CVARF("r_font_linear", "1", CVAR_ARCHIVE); cvar_t r_font_postprocess_outline = CVARFD("r_font_postprocess_outline", "0", 0, "Controls the number of pixels of dark borders to use around fonts."); #if defined(HAVE_LEGACY) && defined(AVAIL_FREETYPE) diff --git a/engine/client/snd_al.c b/engine/client/snd_al.c index 844c389fa..1e597c60a 100644 --- a/engine/client/snd_al.c +++ b/engine/client/snd_al.c @@ -1489,8 +1489,11 @@ static qboolean QDECL OpenAL_InitCard(soundcardinfo_t *sc, const char *devname) return false; oali = sc->handle; - Con_DPrintf(SDRVNAME" AL Extension : %s\n",palGetString(AL_EXTENSIONS)); - Con_DPrintf(SDRVNAME" ALC Extension : %s\n",palcGetString(oali->OpenAL_Device,ALC_EXTENSIONS)); + Con_Printf( SDRVNAME" AL_VERSION: %s\n",palGetString(AL_VERSION)); + Con_Printf( SDRVNAME" AL_RENDERER: %s\n",palGetString(AL_RENDERER)); + Con_Printf( SDRVNAME" AL_VENDOR: %s\n",palGetString(AL_VENDOR)); + Con_DPrintf(SDRVNAME" AL_EXTENSIONS: %s\n",palGetString(AL_EXTENSIONS)); + Con_DPrintf(SDRVNAME" ALC_EXTENSIONS: %s\n",palcGetString(oali->OpenAL_Device,ALC_EXTENSIONS)); sc->Shutdown = OpenAL_Shutdown; #ifdef USEEFX diff --git a/engine/common/common.h b/engine/common/common.h index 3d8d5fd67..ff4c19848 100644 --- a/engine/common/common.h +++ b/engine/common/common.h @@ -534,7 +534,11 @@ struct vfsfile_s; //standard return value is 0 on failure, or depth on success. int FS_FLocateFile(const char *filename, unsigned int flags, flocation_t *loc); struct vfsfile_s *FS_OpenReadLocation(flocation_t *location); -const char *FS_WhichPackForLocation(flocation_t *loc, qboolean makereferenced); +#define WP_REFERENCE 1 +#define WP_FULLPATH 2 +#define WP_FORCE 4 +const char *FS_WhichPackForLocation(flocation_t *loc, unsigned int flags); +qboolean FS_GetLocationForPackageHandle(flocation_t *loc, searchpathfuncs_t *spath, const char *fname); qboolean FS_GetLocMTime(flocation_t *location, time_t *modtime); const char *FS_GetPackageDownloadFilename(flocation_t *loc); //returns only packages (or null) const char *FS_GetRootPackagePath(flocation_t *loc); //favours packages, but falls back on gamedirs. diff --git a/engine/common/fs.c b/engine/common/fs.c index e9aabe3fb..78479494b 100644 --- a/engine/common/fs.c +++ b/engine/common/fs.c @@ -37,6 +37,7 @@ int fs_finds; void COM_CheckRegistered (void); void Mods_FlushModList(void); static qboolean Sys_SteamHasFile(char *basepath, int basepathlen, char *steamdir, char *fname); +static searchpathfuncs_t *FS_OpenPackByExtension(vfsfile_t *f, searchpathfuncs_t *parent, const char *filename, const char *pakname); static void QDECL fs_game_callback(cvar_t *var, char *oldvalue) { @@ -1695,21 +1696,43 @@ const char *FS_GetPackageDownloadFilename(flocation_t *loc) return sp->purepath; return NULL; } -const char *FS_WhichPackForLocation(flocation_t *loc, qboolean makereferenced) +qboolean FS_GetLocationForPackageHandle(flocation_t *loc, searchpathfuncs_t *spath, const char *fname) +{ + searchpath_t *search; + for (search = com_searchpaths; search; search = search->next) + { + if (search->handle == spath) + { + loc->search = search; + return spath->FindFile(spath, loc, fname, NULL); + } + } + return false; +} +const char *FS_WhichPackForLocation(flocation_t *loc, unsigned int flags) { char *ret; if (!loc->search) return NULL; //huh? not a valid location. - ret = strchr(loc->search->purepath, '/'); - if (ret) + if (flags & WP_FULLPATH) { - ret++; - if (!strchr(ret, '/')) + if (flags & WP_REFERENCE) + loc->search->flags |= SPF_REFERENCED; + return loc->search->purepath; + } + else + { + ret = strchr(loc->search->purepath, '/'); + if (ret) { - if (makereferenced) - loc->search->flags |= SPF_REFERENCED; - return ret; + ret++; + if (!strchr(ret, '/')) + { + if (flags & WP_REFERENCE) + loc->search->flags |= SPF_REFERENCED; + return ret; + } } } return NULL; @@ -2645,7 +2668,87 @@ void FS_FreeFile(void *file) } +searchpathfuncs_t *COM_EnumerateFilesPackage (const char *match, const char *package, unsigned int flags, int (QDECL *func)(const char *, qofs_t, time_t mtime, void *, searchpathfuncs_t*), void *parm) +{ //special version that takes an explicit package name to search inside. + searchpathfuncs_t *handle; + searchpath_t *search; + const char *sp; + qboolean foundpackage = false; + for (search = com_searchpaths; search ; search = search->next) + { + if (package) + { + if (flags & WP_FULLPATH) + sp = search->purepath; + else + { + sp = strchr(search->purepath, '/'); + if (sp && !strchr(++sp, '/')) + ; + else + continue; //ignore packages inside other packages. they're just too weird. + } + if (strcmp(package, sp)) + continue; //ignore this package + } + foundpackage = true; + // is the element a pak file? + if (!search->handle->EnumerateFiles(search->handle, match, func, parm)) + break; + } + if (!foundpackage && package && (flags&WP_FORCE) && (flags & WP_FULLPATH)) + { //if we're forcing the package search then be prepared to open the gamedir or gamedir/package that was specified. + char cleanname[MAX_OSPATH]; + char syspath[MAX_OSPATH]; + char *sl; + + package = FS_GetCleanPath(package, false, cleanname, sizeof(cleanname)); + if (!package) + return NULL; + + sl = strchr(package, '/'); + if (sl) + { //try to open the named package. + *sl = 0; + if (strchr(sl+1, '/') || !FS_GamedirIsOkay(package)) + return NULL; + *sl = '/'; + + if (com_homepathenabled) + { //try the homedir + Q_snprintfz(syspath, sizeof(syspath), "%s%s", com_homepath, package); + handle = FS_OpenPackByExtension(VFSOS_Open(package, "rb"), NULL, package, package); + } + else + handle = NULL; + if (!handle) + { //now go for the basedir to see if ther. + Q_snprintfz(syspath, sizeof(syspath), "%s%s", com_gamepath, package); + handle = FS_OpenPackByExtension(VFSOS_Open(package, "rb"), NULL, package, package); + } + + if (handle) + handle->EnumerateFiles(handle, match, func, parm); + return handle; //caller can use this for context, but is expected to tidy it up too. + } + else + { //we use NULLs for spath context here. caller will need to figure out which basedir to read it from. + if (!FS_GamedirIsOkay(package)) + return NULL; + + if (com_homepathenabled) + { + Q_snprintfz(syspath, sizeof(syspath), "%s%s", com_homepath, package); + Sys_EnumerateFiles(syspath, match, func, parm, NULL); + } + + Q_snprintfz(syspath, sizeof(syspath), "%s%s", com_gamepath, package); + Sys_EnumerateFiles(syspath, match, func, parm, NULL); + } + } + return NULL; +} void COM_EnumerateFiles (const char *match, int (QDECL *func)(const char *, qofs_t, time_t mtime, void *, searchpathfuncs_t*), void *parm) { searchpath_t *search; diff --git a/engine/common/pr_bgcmd.c b/engine/common/pr_bgcmd.c index d14ad75eb..b301f6f64 100644 --- a/engine/common/pr_bgcmd.c +++ b/engine/common/pr_bgcmd.c @@ -8,6 +8,7 @@ #ifdef SQL #include "sv_sql.h" #endif +#include "fs.h" #include @@ -2354,6 +2355,50 @@ void QCBUILTIN PF_fopen (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals G_FLOAT(OFS_RETURN) = -1; break; } + } + +//internal function used by search_begin +static int PF_fopen_search (pubprogfuncs_t *prinst, const char *name, flocation_t *loc) +{ + const char *fallbackread; + int i; + + Con_DPrintf("qcfopen(\"%s\") called\n", name); + + for (i = 0; i < MAX_QC_FILES; i++) + if (!pf_fopen_files[i].prinst) + break; + + if (i == MAX_QC_FILES) //too many already open + { + Con_Printf("qcfopen(\"%s\"): too many files open\n", name); + return -1; + } + + if (!QC_FixFileName(name, &name, &fallbackread) || !fallbackread) + { //we're ignoring the data/ dir so using only the fallback, but still blocking it if its a nasty path. + Con_Printf("qcfopen(\"%s\"): Access denied\n", name); + return -1; + } + + pf_fopen_files[i].accessmode = FRIK_FILE_READ_DELAY; + + Q_strncpyz(pf_fopen_files[i].name, fallbackread, sizeof(pf_fopen_files[i].name)); + if (loc->search->handle) + pf_fopen_files[i].file = FS_OpenReadLocation(loc); + else + pf_fopen_files[i].file = FS_OpenVFS(loc->rawname, "rb", FS_ROOT); + + pf_fopen_files[i].ofs = 0; + if (pf_fopen_files[i].file) + { + pf_fopen_files[i].len = VFS_GETLEN(pf_fopen_files[i].file); + + pf_fopen_files[i].prinst = prinst; + return i + FIRST_QC_FILE_INDEX; + } + else + return -1; } void PF_fclose_i (int fnum) @@ -2895,12 +2940,12 @@ void QCBUILTIN PF_rmtree (pubprogfuncs_t *prinst, struct globalvars_s *pr_global void QCBUILTIN PF_whichpack (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) { const char *srcname = PR_GetStringOfs(prinst, OFS_PARM0); - qboolean makereferenced = prinst->callargc>1?G_FLOAT(OFS_PARM1):true; + unsigned int flags = prinst->callargc>1?G_FLOAT(OFS_PARM1):WP_REFERENCE; flocation_t loc; if (FS_FLocateFile(srcname, FSLF_IFFOUND, &loc)) { - srcname = FS_WhichPackForLocation(&loc, makereferenced); + srcname = FS_WhichPackForLocation(&loc, flags); if (srcname == NULL) srcname = ""; RETURN_TSTRING(srcname); @@ -2913,19 +2958,33 @@ void QCBUILTIN PF_whichpack (pubprogfuncs_t *prinst, struct globalvars_s *pr_glo } +enum +{ + QCSEARCH_INSENSITIVE = 1u<<0, //for dp, we're always insensitive you prick. + QCSEARCH_FULLPACKAGE = 1u<<1, //package names include gamedir prefix etc. + QCSEARCH_ALLOWDUPES = 1u<<2, //don't filter out dupes, allowing entries hidden by later packages to be shown. + QCSEARCH_FORCESEARCH = 1u<<3, //force the search to succeed even if the gamedir/package is not active. +}; +searchpathfuncs_t *COM_EnumerateFilesPackage (const char *match, const char *package, unsigned int flags, int (QDECL *func)(const char *, qofs_t, time_t mtime, void *, searchpathfuncs_t*), void *parm); typedef struct prvmsearch_s { pubprogfuncs_t *fromprogs; //share across menu/server + + searchpath_t searchinfo; + int entries; struct { char *name; qofs_t size; time_t mtime; + searchpathfuncs_t *package; } *entry; char *pattern; + unsigned int flags; + unsigned int fsflags; } prvmsearch_t; -prvmsearch_t *pr_searches; //realloced to extend -size_t numpr_searches; +static prvmsearch_t *pr_searches; //realloced to extend +static size_t numpr_searches; void search_close (pubprogfuncs_t *prinst, int handle) { @@ -2943,6 +3002,8 @@ void search_close (pubprogfuncs_t *prinst, int handle) BZ_Free(s->entry[i].name); Z_Free(s->pattern); BZ_Free(s->entry); + if (s->searchinfo.handle) + s->searchinfo.handle->ClosePath(s->searchinfo.handle); memset(s, 0, sizeof(*s)); } //a progs was closed... hunt down it's searches, and warn about any searches left open. @@ -2984,10 +3045,13 @@ static int QDECL search_enumerate(const char *name, qofs_t fsize, time_t mtime, prvmsearch_t *s = parm; size_t i; - for (i = 0; i < s->entries; i++) + if (!(s->flags & QCSEARCH_ALLOWDUPES)) { - if (!Q_strcasecmp(name, s->entry[i].name)) - return true; //already in the list, apparently. try to avoid dupes. + for (i = 0; i < s->entries; i++) + { + if (!Q_strcasecmp(name, s->entry[i].name)) + return true; //already in the list, apparently. try to avoid dupes. + } } s->entry = BZ_Realloc(s->entry, ((s->entries+64)&~63) * sizeof(*s->entry)); @@ -2995,6 +3059,7 @@ static int QDECL search_enumerate(const char *name, qofs_t fsize, time_t mtime, strcpy(s->entry[s->entries].name, name); s->entry[s->entries].size = fsize; s->entry[s->entries].mtime = mtime; + s->entry[s->entries].package = spath; s->entries++; return true; @@ -3005,8 +3070,9 @@ void QCBUILTIN PF_search_begin (pubprogfuncs_t *prinst, struct globalvars_s *pr_ { //< 0 for error, >= 0 for handle. //error includes bad search patterns, but not no files const char *pattern = PR_GetStringOfs(prinst, OFS_PARM0); -// qboolean caseinsensitive = G_FLOAT(OFS_PARM1); -// qboolean quiet = G_FLOAT(OFS_PARM2); + unsigned int flags = G_FLOAT(OFS_PARM1); +// qboolean quiet = G_FLOAT(OFS_PARM2); //fte is not noisy + const char *package = (prinst->callargc>3)?PR_GetStringOfs(prinst, OFS_PARM3):NULL; prvmsearch_t *s; size_t j; @@ -3032,7 +3098,15 @@ void QCBUILTIN PF_search_begin (pubprogfuncs_t *prinst, struct globalvars_s *pr_ s->pattern = Z_StrDup(pattern); s->fromprogs = prinst; - COM_EnumerateFiles(pattern, search_enumerate, s); + s->flags = flags; + s->fsflags = 0; + if (flags&QCSEARCH_FULLPACKAGE) + s->fsflags |= WP_FULLPATH; + if (flags&QCSEARCH_FORCESEARCH) + s->fsflags |= WP_FORCE; + + Q_strncpyz(s->searchinfo.purepath, package?package:"", sizeof(s->searchinfo.purepath)); + s->searchinfo.handle = COM_EnumerateFilesPackage(pattern, package?s->searchinfo.purepath:NULL, s->fsflags, search_enumerate, s); G_FLOAT(OFS_RETURN) = j; } @@ -3118,6 +3192,69 @@ void QCBUILTIN PF_search_getfilemtime (pubprogfuncs_t *prinst, struct globalvars RETURN_TSTRING(timestr); } } +static qboolean PF_search_getloc(flocation_t *loc, prvmsearch_t *s, int num) +{ + const char *fname = s->entry[num].name; + if (s->searchinfo.handle) //we were only searching a single package... + { + loc->search = &s->searchinfo; + return loc->search->handle->FindFile(loc->search->handle, loc, fname, NULL); + } + else if (!s->entry[num].package) + { + loc->search = &s->searchinfo; + + Q_snprintfz(loc->rawname, sizeof(loc->rawname), "%s/%s", s->searchinfo.purepath, fname); + return true; + } + else + return FS_GetLocationForPackageHandle(loc, s->entry[num].package, fname); +} +void QCBUILTIN PF_search_getpackagename (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) +{ + int handle = G_FLOAT(OFS_PARM0); + int num = G_FLOAT(OFS_PARM1); + prvmsearch_t *s; + flocation_t loc; + const char *pkgname; + G_INT(OFS_RETURN) = 0; + + if (handle < 0 || handle >= numpr_searches || pr_searches[handle].fromprogs != prinst) + { + PF_Warningf(prinst, "PF_search_getpackagename: Invalid search handle %i\n", handle); + return; + } + s = &pr_searches[handle]; + + if (num < 0 || num >= s->entries) + return; + if (PF_search_getloc(&loc, s, num)) + { + pkgname = FS_WhichPackForLocation(&loc, s->fsflags); + if (pkgname) + RETURN_TSTRING(pkgname); + } +} +void QCBUILTIN PF_search_fopen (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) +{ + int handle = G_FLOAT(OFS_PARM0); + int num = G_FLOAT(OFS_PARM1); + prvmsearch_t *s; + flocation_t loc; + G_FLOAT(OFS_RETURN) = -1; + + if (handle < 0 || handle >= numpr_searches || pr_searches[handle].fromprogs != prinst) + { + PF_Warningf(prinst, "PF_search_getpackagename: Invalid search handle %i\n", handle); + return; + } + s = &pr_searches[handle]; + + if (num < 0 || num >= s->entries) + return; + if (PF_search_getloc(&loc, s, num)) + G_FLOAT(OFS_RETURN) = PF_fopen_search (prinst, s->entry[num].name, &loc); +} //closes filesystem type stuff for when a progs has stopped needing it. void PR_fclose_progs (pubprogfuncs_t *prinst) @@ -6609,6 +6746,8 @@ nolength: *f++ = 'x'; else if (*s == 'P') *f++ = 'X'; + else if (*s == 'S') + *f++ = 's'; else *f++ = *s; *f++ = 0; @@ -7288,6 +7427,7 @@ lh_extension_t QSG_Extensions[] = { {"DP_QC_FINDCHAINFLAGS", 1, NULL, {"findchainflags"}}, {"DP_QC_FINDFLOAT", 1, NULL, {"findfloat"}}, {"DP_QC_FS_SEARCH", 4, NULL, {"search_begin", "search_end", "search_getsize", "search_getfilename"}}, + {"DP_QC_FS_SEARCH_PACKFILE", 4, NULL, {"search_begin", "search_end", "search_getsize", "search_getfilename"}}, {"DP_QC_GETSURFACE", 6, NULL, {"getsurfacenumpoints", "getsurfacepoint", "getsurfacenormal", "getsurfacetexture", "getsurfacenearpoint", "getsurfaceclippedpoint"}}, {"DP_QC_GETSURFACEPOINTATTRIBUTE", 1, NULL, {"getsurfacepointattribute"}}, {"DP_QC_GETTAGINFO", 2, NULL, {"gettagindex", "gettaginfo"}}, diff --git a/engine/common/pr_common.h b/engine/common/pr_common.h index 4d9c9a63b..052df6883 100644 --- a/engine/common/pr_common.h +++ b/engine/common/pr_common.h @@ -193,6 +193,8 @@ void QCBUILTIN PF_search_getsize (pubprogfuncs_t *prinst, struct globalvars_s *p void QCBUILTIN PF_search_getfilename (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); void QCBUILTIN PF_search_getfilesize (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); void QCBUILTIN PF_search_getfilemtime (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); +void QCBUILTIN PF_search_getpackagename (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); +void QCBUILTIN PF_search_fopen (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); void QCBUILTIN PF_isfunction (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); void QCBUILTIN PF_callfunction (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); void QCBUILTIN PF_writetofile(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); diff --git a/engine/common/protocol.h b/engine/common/protocol.h index d7a005520..402ffc06a 100644 --- a/engine/common/protocol.h +++ b/engine/common/protocol.h @@ -1193,8 +1193,8 @@ typedef struct usercmd_s short forwardmove, sidemove, upmove; qbyte impulse; qbyte lightlevel; + //end q2 compat - //freestyle float msec; //replace msec, but with more precision int buttons; //replaces buttons, but with more bits. int weapon; //q3 has a separate weapon field to supplement impulse. diff --git a/engine/gl/gl_model.c b/engine/gl/gl_model.c index a9bbae252..a91a8df9d 100644 --- a/engine/gl/gl_model.c +++ b/engine/gl/gl_model.c @@ -3618,7 +3618,7 @@ TRACE(("dbg: Mod_LoadTextures: inittexturedescs\n")); mt->offsets[j] = LittleLong (mt->offsets[j]); if ( (mt->width & 15) || (mt->height & 15) ) - Con_Printf (CON_WARNING "Warning: Texture %s is not 16 aligned", mt->name); + Con_DPrintf (CON_WARNING "Warning: Texture %s is not 16 aligned", mt->name); if (mt->width < 1 || mt->height < 1) Con_Printf (CON_WARNING "Warning: Texture %s has no size", mt->name); tx = ZG_Malloc(&loadmodel->memgroup, sizeof(texture_t)); diff --git a/engine/gl/r_bishaders.h b/engine/gl/r_bishaders.h index ae2ef9ec8..3aa926815 100644 --- a/engine/gl/r_bishaders.h +++ b/engine/gl/r_bishaders.h @@ -4654,7 +4654,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND //Fun question: should sky be fogged as if infinite, or as if an actual surface? "#ifdef FOG\n" "#if 1\n" -"skybox.rgb = mix(skybox.rgb, w_fogcolour_ float(r_skyfog)*w_fogalpha); //flat fog ignoring actual geometry\n" +"skybox.rgb = mix(skybox.rgb, w_fogcolour, float(r_skyfog)*w_fogalpha); //flat fog ignoring actual geometry\n" "#else\n" "skybox.rgb = mix(skybox.rgb, fog3(skybox.rgb), float(r_skyfog)); //fog in terms of actual geometry distance\n" "#endif\n" diff --git a/engine/server/pr_cmds.c b/engine/server/pr_cmds.c index 5a712daa1..325717c45 100644 --- a/engine/server/pr_cmds.c +++ b/engine/server/pr_cmds.c @@ -10478,7 +10478,7 @@ static BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs {"cvar_string", PF_Fixme, 0, 0, 0, 71, D("string(string name)", "Returns the value of a cvar, as a string.")}, {"crash", PF_Fixme, 0, 0, 0, 72, D("void()", "Demonstrates that no program is bug free.")}, {"stackdump", PF_Fixme, 0, 0, 0, 73, D("void()", "Prints out the QC's stack, for console-based error reports.")}, - {"search_begin", PF_Fixme, 0, 0, 0, 74, "searchhandle(string pattern, float caseinsensitive, float quiet)"}, + {"search_begin", PF_Fixme, 0, 0, 0, 74, "searchhandle(string pattern, enumflags:float{SB_CASEINSENSITIVE=1<<0,SB_FULLPACKAGEPATH=1<<1,SB_ALLOWDUPES=1<<2,SB_FORCESEARCH=1<<3} flags, float quiet, optional string package)"}, {"search_end", PF_Fixme, 0, 0, 0, 75, "void(searchhandle handle)"}, {"search_getsize", PF_Fixme, 0, 0, 0, 76, "float(searchhandle handle)"}, {"search_getfilename",PF_Fixme, 0, 0, 0, 77, "string(searchhandle handle, float num)"}, @@ -11253,12 +11253,14 @@ static BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs {"tokenize", PF_Tokenize, 0, 0, 0, 441, "float(string s)"},// (KRIMZON_SV_PARSECLIENTCOMMAND) {"argv", PF_ArgV, 0, 0, 0, 442, "string(float n)"},// (KRIMZON_SV_PARSECLIENTCOMMAND {"setattachment", PF_setattachment, 0, 0, 0, 443, "void(entity e, entity tagentity, string tagname)"},// (DP_GFX_QUAKE3MODELTAGS) - {"search_begin", PF_search_begin, 0, 0, 0, 444, D("searchhandle(string pattern, float caseinsensitive, float quiet)", "initiate a filesystem scan based upon filenames. Be sure to call search_end on the returned handle.")}, + {"search_begin", PF_search_begin, 0, 0, 0, 444, D("searchhandle(string pattern, enumflags:float{SB_CASEINSENSITIVE=1<<0,SB_FULLPACKAGEPATH=1<<1,SB_ALLOWDUPES=1<<2,SB_FORCESEARCH=1<<3} flags, float quiet, optional string filterpackage)", "initiate a filesystem scan based upon filenames. Be sure to call search_end on the returned handle. SB_FULLPACKAGEPATH interprets the filterpackage arg as a full package path to avoid gamedir ambiguity, equivelent to whichpack's WP_FULLPACKAGEPATH flag. SB_ALLOWDUPES allows returning multiple entries with the same name (but different package, useful with search_fopen). SB_FORCESEARCH requires use of the filterpackage and SB_FULLPACKAGEPATH flag, initiating searches from gamedirs/packages which are not currently active.")}, {"search_end", PF_search_end, 0, 0, 0, 445, "void(searchhandle handle)"}, {"search_getsize", PF_search_getsize, 0, 0, 0, 446, D("float(searchhandle handle)", "Retrieves the number of files that were found.")}, {"search_getfilename", PF_search_getfilename,0, 0, 0, 447, D("string(searchhandle handle, float num)", "Retrieves name of one of the files that was found by the initial search.")}, {"search_getfilesize", PF_search_getfilesize,0, 0, 0, 0, D("float(searchhandle handle, float num)", "Retrieves the size of one of the files that was found by the initial search.")}, {"search_getfilemtime", PF_search_getfilemtime,0,0, 0, 0, D("string(searchhandle handle, float num)", "Retrieves modification time of one of the files.")}, + {"search_getpackagename", PF_search_getpackagename,0,0, 0, 0, D("string(searchhandle handle, float num)", "Retrieves the name of the package containing the file. Search with SB_FULLPACKAGEPATH to see gamedir/package info")}, + {"search_fopen", PF_search_fopen, 0, 0, 0, 0, D("filestream(searchhandle handle, float num)", "Opens the file directly, without getting confused about entries from other packages. Read access only.")}, {"cvar_string", PF_cvar_string, 0, 0, 0, 448, "string(string cvarname)"},//DP_QC_CVAR_STRING {"findflags", PF_FindFlags, 0, 0, 0, 449, "entity(entity start, .float fld, float match)"},//DP_QC_FINDFLAGS {"findchainflags", PF_findchainflags,0, 0, 0, 450, "entity(.float fld, float match, optional .entity chainfield)"},//DP_QC_FINDCHAINFLAGS @@ -11327,7 +11329,7 @@ static BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs {"WritePicture", PF_WritePicture, 0, 0, 0, 501, D("void(float to, string s, float sz)", "Encodes the named image across the network as-is adhering to some size limit. In FTE, this simply writes the string and is equivelent to writestring and sz is ignored. WritePicture should be paired with ReadPicture in csqc.")},//DP_SV_WRITEPICTURE {"ReadPicture", PF_Fixme, 0, 0, 0, 501, D("string()", "Reads a picture that was written by ReadPicture, and returns a name that can be used in drawpic and other 2d drawing functions. In FTE, this acts as a readstring-with-downloadcheck - the image will appear normally once it has been downloaded, but its size may be incorrect until then.")},//DP_SV_WRITEPICTURE {"boxparticles", PF_Fixme, 0, 0, 0, 502, "void(float effectindex, entity own, vector org_from, vector org_to, vector dir_from, vector dir_to, float countmultiplier, optional float flags)"}, - {"whichpack", PF_whichpack, 0, 0, 0, 503, D("string(string filename, optional float makereferenced)", "Returns the pak file name that contains the file specified. progs/player.mdl will generally return something like 'pak0.pak'. If makereferenced is true, clients will automatically be told that the returned package should be pre-downloaded and used, even if allow_download_refpackages is not set.")},//DP_QC_WHICHPACK + {"whichpack", PF_whichpack, 0, 0, 0, 503, D("string(string filename, optional enumflags:float{WP_REFERENCEPACKAGE,WP_FULLPACKAGEPATH} flags)", "Returns the pak file name that contains the file specified. progs/player.mdl will generally return something like 'pak0.pak'. If WP_REFERENCE, clients will automatically be told that the returned package should be pre-downloaded and used, even if allow_download_refpackages is not set.")},//DP_QC_WHICHPACK {"getentity", PF_Fixme, 0, 0, 0, 504, D("__variant(float entnum, float fieldnum)", "Looks up fields from non-csqc-visible entities. The entity will need to be within the player's pvs. fieldnum should be one of the GE_ constants.")},//DP_CSQC_QUERYRENDERENTITY // {"undefined", PF_Fixme, 0, 0, 0, 505, ""}, // {"undefined", PF_Fixme, 0, 0, 0, 506, ""}, @@ -12596,17 +12598,17 @@ void PR_DumpPlatform_f(void) {"PFLAGS_CORONA", "const float", QW|NQ|CS, D("Enables support of coronas on the associated rtlights."), PFLAGS_CORONA}, {"PFLAGS_FULLDYNAMIC", "const float", QW|NQ, D("When set in self.pflags, enables fully-customised dynamic lights. Custom rtlight information is not otherwise used."), PFLAGS_FULLDYNAMIC}, - //including these for csqc stat types. + //including these for csqc stat types, hash tables, etc. // {"EV_VOID", "const float", QW|NQ|CS, NULL, ev_void}, - {"EV_STRING", "const float", QW|NQ|CS, NULL, ev_string}, - {"EV_FLOAT", "const float", QW|NQ|CS, NULL, ev_float}, - {"EV_VECTOR", "const float", QW|NQ|CS, NULL, ev_vector}, - {"EV_ENTITY", "const float", QW|NQ|CS, NULL, ev_entity}, - {"EV_FIELD", "const float", QW|NQ|CS, NULL, ev_field}, - {"EV_FUNCTION", "const float", QW|NQ|CS, NULL, ev_function}, - {"EV_POINTER", "const float", QW|NQ|CS, NULL, ev_pointer}, - {"EV_INTEGER", "const float", QW|NQ|CS, NULL, ev_integer}, - {"EV_VARIANT", "const float", QW|NQ|CS, NULL, ev_variant}, + {"EV_STRING", "const float", ALL, NULL, ev_string}, + {"EV_FLOAT", "const float", ALL, NULL, ev_float}, + {"EV_VECTOR", "const float", ALL, NULL, ev_vector}, + {"EV_ENTITY", "const float", ALL, NULL, ev_entity}, + {"EV_FIELD", "const float", ALL, NULL, ev_field}, + {"EV_FUNCTION", "const float", ALL, NULL, ev_function}, + {"EV_POINTER", "const float", ALL, NULL, ev_pointer}, + {"EV_INTEGER", "const float", ALL, NULL, ev_integer}, + {"EV_VARIANT", "const float", ALL, NULL, ev_variant}, // {"EV_STRUCT", "const float", QW|NQ|CS, NULL, ev_struct}, // {"EV_UNION", "const float", QW|NQ|CS, NULL, ev_union}, diff --git a/engine/shaders/glsl/defaultskybox.glsl b/engine/shaders/glsl/defaultskybox.glsl index a15a5d342..5db1ac0ff 100644 --- a/engine/shaders/glsl/defaultskybox.glsl +++ b/engine/shaders/glsl/defaultskybox.glsl @@ -39,7 +39,7 @@ void main () //Fun question: should sky be fogged as if infinite, or as if an actual surface? #ifdef FOG #if 1 - skybox.rgb = mix(skybox.rgb, w_fogcolour_ float(r_skyfog)*w_fogalpha); //flat fog ignoring actual geometry + skybox.rgb = mix(skybox.rgb, w_fogcolour, float(r_skyfog)*w_fogalpha); //flat fog ignoring actual geometry #else skybox.rgb = mix(skybox.rgb, fog3(skybox.rgb), float(r_skyfog)); //fog in terms of actual geometry distance #endif