fix some search_begin to not fail just because no files were found, fixing a crash reported by eukara.
fix Sys_EnumerateFiles on linux to enumerate more loosely, so "*/*/*/*.tga" or whatever can now be searched for, instead of giving no hits. be slightly more promiscuous when loading audio files. try to deal with denormals-are-zero without bugging out. be slightly more verbose about nan origins/velocities. parse custom cvar descriptions specified via the set command. git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@5023 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
parent
018aed2c19
commit
f7d7a1a9fb
8 changed files with 318 additions and 136 deletions
|
@ -851,6 +851,11 @@ static void S_LoadSoundWorker (void *ctx, void *ctxdata, size_t a, size_t b)
|
|||
{
|
||||
//Con_Printf ("S_LoadSound: %x\n", (int)stackbuf);
|
||||
// load it in
|
||||
const char *prefixes[] = {"sound/", ""};
|
||||
const char *extensions[] = {".wav", ".ogg"};
|
||||
char altname[sizeof(namebuffer)];
|
||||
char orig[16];
|
||||
size_t pre, ex;
|
||||
|
||||
data = NULL;
|
||||
filesize = 0;
|
||||
|
@ -860,38 +865,46 @@ static void S_LoadSoundWorker (void *ctx, void *ctxdata, size_t a, size_t b)
|
|||
s->loadstate = SLS_FAILED;
|
||||
return;
|
||||
}
|
||||
else if (name[0] == '.' && name[1] == '.' && name[2] == '/')
|
||||
|
||||
for (pre = 0; !data && pre < countof(prefixes); pre++)
|
||||
{
|
||||
//not relative to sound/
|
||||
Q_strcpy(namebuffer, name+3);
|
||||
}
|
||||
else
|
||||
{
|
||||
//q1 behaviour, relative to sound/
|
||||
Q_strcpy(namebuffer, "sound/");
|
||||
Q_strcat(namebuffer, name);
|
||||
if (name[0] == '.' && name[1] == '.' && name[2] == '/')
|
||||
{ //someone's being specific. disable prefixes entirely.
|
||||
if (pre)
|
||||
break;
|
||||
//not relative to sound/
|
||||
Q_snprintfz(namebuffer, sizeof(namebuffer), "%s", name+3);
|
||||
}
|
||||
else
|
||||
Q_snprintfz(namebuffer, sizeof(namebuffer), "%s%s", prefixes[pre], name);
|
||||
|
||||
data = COM_LoadFile(namebuffer, 5, &filesize);
|
||||
}
|
||||
|
||||
// Con_Printf ("loading %s\n",namebuffer);
|
||||
|
||||
if (!data)
|
||||
data = COM_LoadFile(name, 5, &filesize);
|
||||
if (!data)
|
||||
{
|
||||
char altname[sizeof(namebuffer)];
|
||||
COM_StripExtension(namebuffer, altname, sizeof(altname));
|
||||
COM_DefaultExtension(altname, ".ogg", sizeof(altname));
|
||||
data = COM_LoadFile(altname, 5, &filesize);
|
||||
if (data)
|
||||
Con_DPrintf("found a mangled name\n");
|
||||
break;
|
||||
COM_FileExtension(namebuffer, orig, sizeof(orig));
|
||||
COM_StripExtension(namebuffer, altname, sizeof(altname));
|
||||
for (ex = 0; ex < countof(extensions); ex++)
|
||||
{
|
||||
if (!strcmp(orig, extensions[ex]+1))
|
||||
continue;
|
||||
Q_snprintfz(namebuffer, sizeof(namebuffer), "%s%s", altname, extensions[ex]);
|
||||
data = COM_LoadFile(namebuffer, 5, &filesize);
|
||||
if (data)
|
||||
{
|
||||
Con_DPrintf("found a mangled name: %s\n", namebuffer);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!data)
|
||||
{
|
||||
//FIXME: check to see if queued for download.
|
||||
Con_DPrintf ("Couldn't load %s\n", namebuffer);
|
||||
if (name[0] == '.' && name[1] == '.' && name[2] == '/')
|
||||
Con_DPrintf ("Couldn't load %s\n", name+3);
|
||||
else
|
||||
Con_DPrintf ("Couldn't load sound/%s\n", name);
|
||||
COM_AddWork(WG_MAIN, S_LoadedOrFailed, s, NULL, SLS_FAILED, 0);
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -415,43 +415,65 @@ int Sys_DebugLog(char *file, char *fmt, ...)
|
|||
return 1;
|
||||
}
|
||||
|
||||
int Sys_EnumerateFiles (const char *gpath, const char *match, int (*func)(const char *, qofs_t, time_t modtime, void *, searchpathfuncs_t *), void *parm, searchpathfuncs_t *spath)
|
||||
int Sys_EnumerateFiles2 (const char *truepath, int apathofs, const char *match, int (*func)(const char *, qofs_t, time_t modtime, void *, searchpathfuncs_t *), void *parm, searchpathfuncs_t *spath)
|
||||
{
|
||||
DIR *dir;
|
||||
char apath[MAX_OSPATH];
|
||||
char file[MAX_OSPATH];
|
||||
char truepath[MAX_OSPATH];
|
||||
char *s;
|
||||
const char *s;
|
||||
struct dirent *ent;
|
||||
struct stat st;
|
||||
const char *wild;
|
||||
const char *apath = truepath+apathofs;
|
||||
|
||||
//printf("path = %s\n", gpath);
|
||||
//printf("match = %s\n", match);
|
||||
|
||||
if (!gpath)
|
||||
gpath = "";
|
||||
*apath = '\0';
|
||||
|
||||
Q_strncpyz(apath, match, sizeof(apath));
|
||||
for (s = apath+strlen(apath)-1; s >= apath; s--)
|
||||
//if there's a * in a system path, then we need to scan its parent directory to figure out what the * expands to.
|
||||
//we can just recurse quicklyish to try to handle it.
|
||||
wild = strchr(apath, '*');
|
||||
if (!wild)
|
||||
wild = strchr(apath, '?');
|
||||
if (wild)
|
||||
{
|
||||
if (*s == '/')
|
||||
char subdir[MAX_OSPATH];
|
||||
for (s = wild+1; *s && *s != '/'; s++)
|
||||
;
|
||||
while (wild > truepath)
|
||||
{
|
||||
s[1] = '\0';
|
||||
match += s - apath+1;
|
||||
break;
|
||||
if (*(wild-1) == '/')
|
||||
break;
|
||||
wild--;
|
||||
}
|
||||
memcpy(file, truepath, wild-truepath);
|
||||
file[wild-truepath] = 0;
|
||||
|
||||
dir = opendir(file);
|
||||
memcpy(subdir, wild, s-wild);
|
||||
subdir[s-wild] = 0;
|
||||
if (dir)
|
||||
{
|
||||
do
|
||||
{
|
||||
ent = readdir(dir);
|
||||
if (!ent)
|
||||
break;
|
||||
if (*ent->d_name != '.')
|
||||
{
|
||||
if (wildcmp(subdir, ent->d_name))
|
||||
{
|
||||
memcpy(file, truepath, wild-truepath);
|
||||
Q_snprintfz(file+(wild-truepath), sizeof(file)-(wild-truepath), "%s%s", ent->d_name, s);
|
||||
if (!Sys_EnumerateFiles2(file, apathofs, match, func, parm, spath))
|
||||
{
|
||||
closedir(dir);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
} while(1);
|
||||
closedir(dir);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (s < apath) //didn't find a '/'
|
||||
*apath = '\0';
|
||||
|
||||
Q_snprintfz(truepath, sizeof(truepath), "%s/%s", gpath, apath);
|
||||
|
||||
|
||||
//printf("truepath = %s\n", truepath);
|
||||
//printf("gamepath = %s\n", gpath);
|
||||
//printf("apppath = %s\n", apath);
|
||||
//printf("match = %s\n", match);
|
||||
dir = opendir(truepath);
|
||||
if (!dir)
|
||||
{
|
||||
|
@ -486,10 +508,34 @@ int Sys_EnumerateFiles (const char *gpath, const char *match, int (*func)(const
|
|||
}
|
||||
} while(1);
|
||||
closedir(dir);
|
||||
|
||||
return true;
|
||||
}
|
||||
int Sys_EnumerateFiles (const char *gpath, const char *match, int (*func)(const char *, qofs_t, time_t modtime, void *, searchpathfuncs_t *), void *parm, searchpathfuncs_t *spath)
|
||||
{
|
||||
char apath[MAX_OSPATH];
|
||||
char truepath[MAX_OSPATH];
|
||||
char *s;
|
||||
|
||||
if (!gpath)
|
||||
gpath = "";
|
||||
*apath = '\0';
|
||||
|
||||
Q_strncpyz(apath, match, sizeof(apath));
|
||||
for (s = apath+strlen(apath)-1; s >= apath; s--)
|
||||
{
|
||||
if (*s == '/')
|
||||
{
|
||||
s[1] = '\0';
|
||||
match += s - apath+1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (s < apath) //didn't find a '/'
|
||||
*apath = '\0';
|
||||
|
||||
Q_snprintfz(truepath, sizeof(truepath), "%s/%s", gpath, apath);
|
||||
return Sys_EnumerateFiles2(truepath, strlen(gpath)+1, match, func, parm, spath);
|
||||
}
|
||||
|
||||
int secbase;
|
||||
|
||||
|
|
|
@ -3130,6 +3130,7 @@ void Cmd_set_f(void)
|
|||
int forceflags = 0;
|
||||
qboolean docalc;
|
||||
char name[256];
|
||||
const char *desc = NULL;
|
||||
|
||||
if (Cmd_Argc()<3)
|
||||
{
|
||||
|
@ -3147,7 +3148,7 @@ void Cmd_set_f(void)
|
|||
|
||||
Q_strncpyz(name, Cmd_Argv(1), sizeof(name));
|
||||
|
||||
if (!strcmp(Cmd_Argv(0), "setfl") || Cmd_FromGamecode()) //AAHHHH!!! Q2 set command is different
|
||||
if (!strcmp(Cmd_Argv(0), "setfl") || Cmd_FromGamecode()) //AARGHHHH!!! Q2 set command is different
|
||||
{
|
||||
text = Cmd_Argv(3);
|
||||
while(*text)
|
||||
|
@ -3169,41 +3170,81 @@ void Cmd_set_f(void)
|
|||
}
|
||||
text = Cmd_Argv(2);
|
||||
|
||||
/*desc = Cmd_Argv(4)*/
|
||||
if (Cmd_Argc()>=5)
|
||||
desc = Cmd_Argv(4);
|
||||
}
|
||||
else if (dpcompat_set.ival && !docalc)
|
||||
{
|
||||
text = Cmd_Argv(2);
|
||||
/*desc = Cmd_Argv(3)*/
|
||||
if (Cmd_Argc()>=4)
|
||||
desc = Cmd_Argv(3);
|
||||
}
|
||||
else
|
||||
{
|
||||
Cmd_ShiftArgs(1, false);
|
||||
text = Cmd_Args();
|
||||
if (!docalc && (*text == '\"' || (*text == '\\' && text[1] == '\"'))) //if it's already quoted, dequote it, and ignore trailing stuff, for q2/q3 compatability
|
||||
text = Cmd_Argv(1);
|
||||
else
|
||||
if (!docalc && Cmd_Argc()==2 && (*text == '\"' || (*text == '\\' && text[1] == '\"'))) //if it's already quoted, dequote it, and ignore trailing stuff, for q2/q3 compatability
|
||||
{
|
||||
end = strstr(text, "//");
|
||||
if (end)
|
||||
desc = COM_StringParse (text, com_token, sizeof(com_token), false, false);
|
||||
while (*desc == ' ' || *desc == '\t')
|
||||
desc++;
|
||||
if (desc[0] == '/' && desc[1] == '/')
|
||||
{
|
||||
end--;
|
||||
while (end >= text)
|
||||
desc+=2;
|
||||
while (*desc == ' ' || *desc == '\t')
|
||||
desc++;
|
||||
end = desc + strlen(desc);
|
||||
while (end > desc)
|
||||
{
|
||||
end--;
|
||||
if (*end == ' ' || *end == '\t' || *end == '\r')
|
||||
end--;
|
||||
*(char*)end = 0;
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
desc = NULL;
|
||||
text = Cmd_Argv(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
desc = strstr(text, "//");
|
||||
if (desc)
|
||||
end = desc;
|
||||
else
|
||||
end = text+strlen(text);
|
||||
end--;
|
||||
while (end >= text)
|
||||
{
|
||||
if (*end == ' ' || *end == '\t' || *end == '\r')
|
||||
end--;
|
||||
else
|
||||
break;
|
||||
}
|
||||
end++;
|
||||
*(char*)end = 0;
|
||||
if (desc)
|
||||
{
|
||||
desc+=2;
|
||||
while(*desc == ' ' || *desc == '\t')
|
||||
desc++;
|
||||
end = desc + strlen(desc);
|
||||
while (end > desc)
|
||||
{
|
||||
end--;
|
||||
if (*end == ' ' || *end == '\t' || *end == '\r')
|
||||
*(char*)end = 0;
|
||||
else
|
||||
break;
|
||||
}
|
||||
end++;
|
||||
*(char*)end = 0;
|
||||
|
||||
}
|
||||
}
|
||||
//fixme: should peek onto the next line to see if that's an indented // too, or something.
|
||||
forceflags |= 0;
|
||||
}
|
||||
|
||||
var = Cvar_Get (name, text, CVAR_TEAMPLAYTAINT, "Custom variables");
|
||||
var = Cvar_Get2 (name, text, CVAR_TEAMPLAYTAINT, desc, "Custom variables");
|
||||
|
||||
mark = If_Token_GetMark();
|
||||
|
||||
|
|
|
@ -3,7 +3,10 @@
|
|||
//named functions, this makes it *really* easy to port plugins from one engine to annother.
|
||||
|
||||
#include "quakedef.h"
|
||||
|
||||
|
||||
#define GNUTLS_DYNAMIC //statically linking is bad, because that just dynamically links to a .so that probably won't exist.
|
||||
//on the other hand, it does validate that the function types are correct.
|
||||
|
||||
#ifdef HAVE_GNUTLS
|
||||
|
||||
#if defined(_WIN32) && !defined(MINGW)
|
||||
|
@ -116,12 +119,13 @@ typedef int (VARGS gnutls_certificate_verify_function)(gnutls_session_t session)
|
|||
#endif
|
||||
|
||||
#if GNUTLS_VERSION_MAJOR >= 3
|
||||
#define GNUTLS_VERSION_3_0_0_PLUS
|
||||
#define GNUTLS_HAVE_SYSTEMTRUST
|
||||
#endif
|
||||
#if GNUTLS_VERSION_MAJOR >= 4 || (GNUTLS_VERSION_MAJOR == 3 && (GNUTLS_VERSION_MINOR > 1 || (GNUTLS_VERSION_MINOR == 1 && GNUTLS_VERSION_PATCH >= 1)))
|
||||
#define GNUTLS_VERSION_3_1_4_PLUS
|
||||
#define GNUTLS_HAVE_VERIFY3
|
||||
#endif
|
||||
|
||||
|
||||
static int (VARGS *qgnutls_bye)(gnutls_session_t session, gnutls_close_request_t how);
|
||||
static void (VARGS *qgnutls_perror)(int error);
|
||||
static int (VARGS *qgnutls_handshake)(gnutls_session_t session);
|
||||
|
@ -138,18 +142,18 @@ static int (VARGS *qgnutls_certificate_allocate_credentials)(gnutls_certificate_
|
|||
static int (VARGS *qgnutls_certificate_type_set_priority)(gnutls_session_t session, const int*);
|
||||
static int (VARGS *qgnutls_anon_allocate_client_credentials)(gnutls_anon_client_credentials_t *sc);
|
||||
static int (VARGS *qgnutls_global_init)(void);
|
||||
static int (VARGS *qgnutls_record_send)(gnutls_session_t session, const void *data, size_t sizeofdata);
|
||||
static int (VARGS *qgnutls_record_recv)(gnutls_session_t session, void *data, size_t sizeofdata);
|
||||
static ssize_t (VARGS *qgnutls_record_send)(gnutls_session_t session, const void *data, size_t sizeofdata);
|
||||
static ssize_t (VARGS *qgnutls_record_recv)(gnutls_session_t session, void *data, size_t sizeofdata);
|
||||
|
||||
static int (VARGS *qgnutls_certificate_set_verify_function)(gnutls_certificate_credentials_t cred, gnutls_certificate_verify_function *func);
|
||||
static void (VARGS *qgnutls_certificate_set_verify_function)(gnutls_certificate_credentials_t cred, gnutls_certificate_verify_function *func);
|
||||
static void *(VARGS *qgnutls_session_get_ptr)(gnutls_session_t session);
|
||||
static void (VARGS *qgnutls_session_set_ptr)(gnutls_session_t session, void *ptr);
|
||||
#ifdef GNUTLS_VERSION_3_0_0_PLUS
|
||||
#ifdef GNUTLS_HAVE_SYSTEMTRUST
|
||||
static int (VARGS *qgnutls_certificate_set_x509_system_trust)(gnutls_certificate_credentials_t cred);
|
||||
#else
|
||||
static int (VARGS *qgnutls_certificate_set_x509_trust_file)(gnutls_certificate_credentials_t cred, const char * cafile, gnutls_x509_crt_fmt_t type);
|
||||
#endif
|
||||
#ifdef GNUTLS_VERSION_3_1_4_PLUS
|
||||
#ifdef GNUTLS_HAVE_VERIFY3
|
||||
static int (VARGS *qgnutls_certificate_verify_peers3)(gnutls_session_t session, const char* hostname, unsigned int * status);
|
||||
static int (VARGS *qgnutls_certificate_verification_status_print)(unsigned int status, gnutls_certificate_type_t type, gnutls_datum_t * out, unsigned int flags);
|
||||
#else
|
||||
|
@ -165,12 +169,12 @@ static int (VARGS *qgnutls_server_name_set)(gnutls_session_t session, gnutls_ser
|
|||
|
||||
static qboolean Init_GNUTLS(void)
|
||||
{
|
||||
#ifdef GNUTLS_VERSION_3_0_0_PLUS
|
||||
#ifdef GNUTLS_HAVE_SYSTEMTRUST
|
||||
#define GNUTLS_TRUSTFUNCS GNUTLS_FUNC(gnutls_certificate_set_x509_system_trust)
|
||||
#else
|
||||
#define GNUTLS_TRUSTFUNCS GNUTLS_FUNC(gnutls_certificate_set_x509_trust_file)
|
||||
#endif
|
||||
#ifdef GNUTLS_VERSION_3_1_4_PLUS
|
||||
#ifdef GNUTLS_HAVE_VERIFY3
|
||||
#define GNUTLS_VERIFYFUNCS \
|
||||
GNUTLS_FUNC(gnutls_certificate_verify_peers3) \
|
||||
GNUTLS_FUNC(gnutls_certificate_verification_status_print)
|
||||
|
@ -212,7 +216,7 @@ static qboolean Init_GNUTLS(void)
|
|||
GNUTLS_FUNC(gnutls_free) \
|
||||
GNUTLS_FUNC(gnutls_server_name_set) \
|
||||
|
||||
#if 1 //GNUTLS_DYNAMIC
|
||||
#ifdef GNUTLS_DYNAMIC
|
||||
dllhandle_t *hmod;
|
||||
|
||||
dllfunction_t functable[] =
|
||||
|
@ -242,12 +246,12 @@ static qboolean Init_GNUTLS(void)
|
|||
{(void**)&qgnutls_certificate_set_verify_function, "gnutls_certificate_set_verify_function"},
|
||||
{(void**)&qgnutls_session_get_ptr, "gnutls_session_get_ptr"},
|
||||
{(void**)&qgnutls_session_set_ptr, "gnutls_session_set_ptr"},
|
||||
#ifdef GNUTLS_VERSION_3_0_0_PLUS
|
||||
#ifdef GNUTLS_HAVE_SYSTEMTRUST
|
||||
{(void**)&qgnutls_certificate_set_x509_system_trust, "gnutls_certificate_set_x509_system_trust"},
|
||||
#else
|
||||
{(void**)&qgnutls_certificate_set_x509_trust_file, "gnutls_certificate_set_x509_trust_file"},
|
||||
#endif
|
||||
#ifdef GNUTLS_VERSION_3_1_4_PLUS
|
||||
#ifdef GNUTLS_HAVE_VERIFY3
|
||||
{(void**)&qgnutls_certificate_verify_peers3, "gnutls_certificate_verify_peers3"},
|
||||
{(void**)&qgnutls_certificate_verification_status_print, "gnutls_certificate_verification_status_print"},
|
||||
#else
|
||||
|
@ -326,7 +330,7 @@ static int QDECL SSL_CheckCert(gnutls_session_t session)
|
|||
unsigned int certstatus;
|
||||
cvar_t *tls_ignorecertificateerrors;
|
||||
|
||||
#ifdef GNUTLS_VERSION_3_1_4_PLUS
|
||||
#ifdef GNUTLS_HAVE_VERIFY3
|
||||
if (qgnutls_certificate_verify_peers3(session, file->certname, &certstatus) >= 0)
|
||||
{
|
||||
{
|
||||
|
@ -339,7 +343,7 @@ static int QDECL SSL_CheckCert(gnutls_session_t session)
|
|||
if (qgnutls_certificate_verification_status_print(certstatus, type, &out, 0) >= 0)
|
||||
{
|
||||
Con_Printf("%s: %s\n", file->certname, out.data);
|
||||
qgnutls_free(out.data);
|
||||
//looks like its static anyway. qgnutls_free(out.data);
|
||||
|
||||
#else
|
||||
if (qgnutls_certificate_verify_peers2(session, &certstatus) >= 0)
|
||||
|
@ -591,7 +595,7 @@ vfsfile_t *FS_OpenSSL(const char *hostname, vfsfile_t *source, qboolean server,
|
|||
qgnutls_anon_allocate_client_credentials (&anoncred);
|
||||
qgnutls_certificate_allocate_credentials (&xcred);
|
||||
|
||||
#ifdef GNUTLS_VERSION_3_0_0_PLUS
|
||||
#ifdef GNUTLS_HAVE_SYSTEMTRUST
|
||||
qgnutls_certificate_set_x509_system_trust (xcred);
|
||||
#else
|
||||
qgnutls_certificate_set_x509_trust_file (xcred, CAFILE, GNUTLS_X509_FMT_PEM);
|
||||
|
|
|
@ -30,6 +30,17 @@ void skel_info_f(void);
|
|||
void skel_generateragdoll_f(void);
|
||||
void PF_Common_RegisterCvars(void)
|
||||
{
|
||||
volatile union
|
||||
{
|
||||
int i;
|
||||
float f;
|
||||
} a, b;
|
||||
a.i = 1;
|
||||
b.i = 1;
|
||||
if (!(a.f && b.f))
|
||||
Con_Printf("WARNING: denormalised floats are disabled. Mods may malfunction\n");
|
||||
|
||||
|
||||
Cvar_Register (&sv_gameplayfix_blowupfallenzombies, cvargroup_progs);
|
||||
Cvar_Register (&pr_droptofloorunits, cvargroup_progs);
|
||||
Cvar_Register (&pr_brokenfloatconvert, cvargroup_progs);
|
||||
|
@ -1429,7 +1440,11 @@ void QCBUILTIN PF_registercvar (pubprogfuncs_t *prinst, struct globalvars_s *pr_
|
|||
void QCBUILTIN PF_memalloc (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
||||
{
|
||||
int size = G_INT(OFS_PARM0);
|
||||
void *ptr = prinst->AddressableAlloc(prinst, size);
|
||||
void *ptr;
|
||||
if (size <= 0 || size > 0x01000000)
|
||||
ptr = NULL; //don't let them abuse things too much. values that are too large might overflow.
|
||||
else
|
||||
ptr = prinst->AddressableAlloc(prinst, size);
|
||||
if (ptr)
|
||||
{
|
||||
memset(ptr, 0, size);
|
||||
|
@ -2411,24 +2426,26 @@ int QDECL search_enumerate(const char *name, qofs_t fsize, time_t mtime, void *p
|
|||
|
||||
//float search_begin(string pattern, float caseinsensitive, float quiet) = #74;
|
||||
void QCBUILTIN PF_search_begin (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
||||
{ //< 0 for error, > 0 for handle.
|
||||
{ //< 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);
|
||||
prvmsearch_t *s;
|
||||
|
||||
if (!*pattern || (*pattern == '.' && pattern[1] == '.') || *pattern == '/' || *pattern == '\\' || strchr(pattern, ':'))
|
||||
{
|
||||
PF_Warningf(prinst, "PF_search_begin: bad search pattern \"%s\"\n", pattern);
|
||||
G_FLOAT(OFS_RETURN) = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
s = Z_Malloc(sizeof(*s));
|
||||
s->fromprogs = prinst;
|
||||
s->handle = prvm_nextsearchhandle++;
|
||||
|
||||
COM_EnumerateFiles(pattern, search_enumerate, s);
|
||||
|
||||
if (s->entries==0)
|
||||
{
|
||||
BZ_Free(s);
|
||||
G_FLOAT(OFS_RETURN) = -1;
|
||||
return;
|
||||
}
|
||||
s->next = prvmsearches;
|
||||
prvmsearches = s;
|
||||
G_FLOAT(OFS_RETURN) = s->handle;
|
||||
|
@ -2444,7 +2461,7 @@ void QCBUILTIN PF_search_getsize (pubprogfuncs_t *prinst, struct globalvars_s *p
|
|||
{
|
||||
int handle = G_FLOAT(OFS_PARM0);
|
||||
prvmsearch_t *s;
|
||||
G_FLOAT(OFS_RETURN) = -1;
|
||||
G_FLOAT(OFS_RETURN) = 0;
|
||||
for (s = prvmsearches; s; s = s->next)
|
||||
{
|
||||
if (s->handle == handle)
|
||||
|
@ -6022,6 +6039,7 @@ lh_extension_t QSG_Extensions[] = {
|
|||
// {"DP_ENT_COLORMOD"},
|
||||
{"DP_ENT_CUSTOMCOLORMAP"},
|
||||
{"DP_ENT_EXTERIORMODELTOCLIENT"},
|
||||
{"DP_ENT_SCALE"},
|
||||
{"DP_ENT_TRAILEFFECTNUM", 1, NULL, {"particleeffectnum"}, "self.traileffectnum=particleeffectnum(\"myeffectname\"); can be used to attach a particle trail to the given server entity. This is equivelent to calling trailparticles each frame."},
|
||||
//only in dp6 currently {"DP_ENT_GLOW"},
|
||||
{"DP_ENT_VIEWMODEL"},
|
||||
|
@ -6111,8 +6129,8 @@ lh_extension_t QSG_Extensions[] = {
|
|||
{"DP_TE_EXPLOSIONRGB", 1, NULL, {"te_explosionrgb"}},
|
||||
{"_DP_TE_FLAMEJET", 1, NULL, {"te_flamejet"}},
|
||||
{"DP_TE_PARTICLECUBE", 1, NULL, {"te_particlecube"}},
|
||||
{"_DP_TE_PARTICLERAIN", 1, NULL, {"te_particlerain"}},
|
||||
{"_DP_TE_PARTICLESNOW", 1, NULL, {"te_particlesnow"}},
|
||||
{"DP_TE_PARTICLERAIN", 1, NULL, {"te_particlerain"}},
|
||||
{"DP_TE_PARTICLESNOW", 1, NULL, {"te_particlesnow"}},
|
||||
{"_DP_TE_PLASMABURN", 1, NULL, {"te_plasmaburn"}},
|
||||
{"_DP_TE_QUADEFFECTS1", 4, NULL, {"te_gunshotquad", "te_spikequad", "te_superspikequad", "te_explosionquad"}},
|
||||
{"DP_TE_SMALLFLASH", 1, NULL, {"te_smallflash"}},
|
||||
|
@ -6128,7 +6146,6 @@ lh_extension_t QSG_Extensions[] = {
|
|||
{"FTE_CALLTIMEOFDAY", 1, NULL, {"calltimeofday"}, "Replication of mvdsv functionality (call calltimeofday to cause 'timeofday' to be called, with arguments that can be saved off to a global). Generally strftime is simpler to use."},
|
||||
{"FTE_CSQC_ALTCONSOLES", 4, NULL, {"con_getset", "con_printf", "con_draw", "con_input"}, "The engine tracks multiple consoles. These may or may not be directly visible to the user."},
|
||||
{"FTE_CSQC_BASEFRAME", 0, NULL, {NULL}, "Specifies that .basebone, .baseframe2, .baselerpfrac, baseframe1time, etc exist in csqc. These fields affect all bones in the entity's model with a lower index than the .basebone field, allowing you to give separate control to the legs of a skeletal model, without affecting the torso animations."},
|
||||
{"FTE_QC_BASEFRAME", 0, NULL, {NULL}, "Specifies that .basebone and .baseframe exist in ssqc. These fields affect all bones in the entity's model with a lower index than the .basebone field, allowing you to give separate control to the legs of a skeletal model, without affecting the torso animations, from ssqc."},
|
||||
#ifdef HALFLIFEMODELS
|
||||
{"FTE_CSQC_HALFLIFE_MODELS"}, //hl-specific skeletal model control
|
||||
#endif
|
||||
|
@ -6138,7 +6155,10 @@ lh_extension_t QSG_Extensions[] = {
|
|||
{"FTE_CSQC_SKELETONOBJECTS", 15, NULL, { "skel_create", "skel_build", "skel_get_numbones", "skel_get_bonename", "skel_get_boneparent", "skel_find_bone",
|
||||
"skel_get_bonerel", "skel_get_boneabs", "skel_set_bone", "skel_mul_bone", "skel_mul_bones", "skel_copybones",
|
||||
"skel_delete", "frameforname", "frameduration"}, "Provides container objects for skeletal bone data, which can be modified on a per bone basis if needed. This allows you to dynamically generate animations (or just blend them with greater customisation) instead of being limited to a single animation or two."},
|
||||
{"FTE_CSQC_RAWIMAGES", 2, NULL, {"r_uploadimage","r_readimage"}, "Provides raw rgba image access to csqc. With this, the csprogs can read textures into qc-accessible memory, modify it, and then upload it to the renderer."},
|
||||
{"FTE_CSQC_RENDERTARGETS", 0, NULL, {NULL}, "VF_RT_DESTCOLOUR exists and can be used to redirect any rendering to a texture instead of the screen."},
|
||||
{"FTE_CSQC_REVERB", 1, NULL, {"setup_reverb"}, "Specifies that the mod can create custom reverb effects. Whether they will actually be used or not depends upon the sound driver."},
|
||||
{"FTE_CSQC_WINDOWCAPTION", 1, NULL, {"setwindowcaption"}, "Provides csqc with the ability to change the window caption as displayed when running windowed or in the task bar when switched out."},
|
||||
{"FTE_ENT_SKIN_CONTENTS", 0, NULL, {NULL}, "self.skin = CONTENTS_WATER; makes a brush entity into water. use -16 for a ladder."},
|
||||
{"FTE_ENT_UNIQUESPAWNID"},
|
||||
{"FTE_EXTENDEDTEXTCODES"},
|
||||
|
@ -6175,18 +6195,25 @@ lh_extension_t QSG_Extensions[] = {
|
|||
{"FTE_PART_NAMESPACE_EFFECTINFO", 0, NULL, {NULL}, "Specifies that effectinfo.bar can load effects from effectinfo.txt for DP compatibility."},
|
||||
#endif
|
||||
#endif
|
||||
{"FTE_QC_BASEFRAME", 0, NULL, {NULL}, "Specifies that .basebone and .baseframe exist in ssqc. These fields affect all bones in the entity's model with a lower index than the .basebone field, allowing you to give separate control to the legs of a skeletal model, without affecting the torso animations, from ssqc."},
|
||||
{"FTE_QC_FILE_BINARY", 4, NULL, {"fread","fwrite","fseek","fsize"}, "Extends FRIK_FILE with binary read+write, as well as allowing seeking. Requires pointers."},
|
||||
{"FTE_QC_CHANGELEVEL_HUB", 0, NULL, {NULL}, "Adds an extra argument to changelevel which is carried over to the next map in the 'spawnspot' global. Maps will be saved+reloaded until the extra argument is omitted again, purging all saved maps. Saved games will contain a copy of each preserved map. parm1-parm64 globals can be used, giving more space to transfer more player data."},
|
||||
{"FTE_QC_CHECKCOMMAND", 1, NULL, {"checkcommand"}, "Provides a way to test if a console command exists, and whether its a command/alias/cvar. Does not say anything about the expected meanings of any arguments or values."},
|
||||
{"FTE_QC_CHECKPVS", 1, NULL, {"checkpvs"}},
|
||||
{"FTE_QC_HARDWARECURSORS", 0, NULL, {NULL}, "setcursormode exists in both csqc+menuqc, and accepts additional arguments to specify a cursor image to use when this module has focus. If the image exceeds hardware limits, it will be emulated using regular draws - this at least still avoids conflicting cursors."},
|
||||
{"FTE_QC_CROSSPRODUCT", 1, NULL, {"crossproduct"}},
|
||||
{"FTE_QC_FS_SEARCH_SIZEMTIME", 2, NULL, {"search_getfilesize", "search_getfilemtime"}},
|
||||
{"FTE_QC_HARDWARECURSORS", 0, NULL, {NULL}, "setcursormode exists in both csqc+menuqc, and accepts additional arguments to specify a cursor image to use when this module has focus. If the image exceeds hardware limits (or hardware cursors are unsupported), it will be emulated using regular draws - this at least still avoids conflicting cursors as only one will ever be used, even if console+menu+csqc are all overlayed."},
|
||||
{"FTE_QC_HASHTABLES", 6, NULL, {"hash_createtab", "hash_destroytab", "hash_add", "hash_get", "hash_delete", "hash_getkey"}, "Provides efficient string-based lookups."},
|
||||
{"FTE_QC_INTCONV", 4, NULL, {"stoi", "itos", "stoh", "htos"}, "Provides string<>int conversions, including hex representations."},
|
||||
{"FTE_QC_INTCONV", 6, NULL, {"stoi", "itos", "stoh", "htos", "itof", "ftoi"}, "Provides string<>int conversions, including hex representations."},
|
||||
{"FTE_QC_MATCHCLIENTNAME", 1, NULL, {"matchclientname"}},
|
||||
// {"FTE_QC_MESHOBJECTS", 0, NULL, {"mesh_create", "mesh_build", "mesh_getvertex", "mesh_getindex", "mesh_setvertex", "mesh_setindex", "mesh_destroy"}, "Provides qc with the ability to create its own meshes."},
|
||||
{"FTE_QC_PAUSED"},
|
||||
#ifdef QCGC
|
||||
{"FTE_QC_PERSISTENTTEMPSTRINGS", NOBI "Supersedes DP_QC_MULTIPLETEMPSTRINGS. Temp strings are garbage collected automatically, and do not expire while they're still in use. This makes strzone redundant."},
|
||||
#endif
|
||||
{"FTE_QC_RAGDOLL_WIP", 1, NULL, {"ragupdate", "skel_set_bone_world", "skel_mmap"}},
|
||||
{"FTE_QC_SENDPACKET", 1, NULL, {"sendpacket"}, "Allows the use of out-of-band udp packets to/from other hosts. Includes the SV_ParseConnectionlessPacket event."},
|
||||
{"FTE_QC_STUFFCMDFLAGS", 1, NULL, {"stuffcmdflags"}, "Variation on regular stuffcmd that gives control over how spectators/mvds should be treated."},
|
||||
{"FTE_QC_TRACETRIGGER"},
|
||||
#ifdef Q2CLIENT
|
||||
{"FTE_QUAKE2_CLIENT", 0, NULL, {NULL}, "This engine is able to act as a quake2 client"},
|
||||
|
@ -6223,10 +6250,11 @@ lh_extension_t QSG_Extensions[] = {
|
|||
{"FTE_TE_STANDARDEFFECTBUILTINS", 14, NULL, {"te_gunshot", "te_spike", "te_superspike", "te_explosion", "te_tarexplosion", "te_wizspike", "te_knightspike", "te_lavasplash",
|
||||
"te_teleport", "te_lightning1", "te_lightning2", "te_lightning3", "te_lightningblood", "te_bloodqw"}, "Provides builtins to replace writebytes, with a QW compatible twist."},
|
||||
#ifdef TERRAIN
|
||||
{"FTE_TERRAIN_MAP", 0, NULL, {NULL}, "This engine supports .hmp files, as well as terrain embedded within bsp files."},
|
||||
{"FTE_RAW_MAP", 0, NULL, {NULL}, "This engine supports directly loading .map files, as well as realtime editing of the various brushes."},
|
||||
{"FTE_TERRAIN_MAP", 1, NULL, {"terrain_edit"}, "This engine supports .hmp files, as well as terrain embedded within bsp files."},
|
||||
{"FTE_RAW_MAP", 7, NULL, {"brush_get","brush_create","brush_delete","brush_selected","brush_getfacepoints","brush_calcfacepoints","brush_findinvolume"}, "This engine supports directly loading .map files, as well as realtime editing of the various brushes."},
|
||||
#endif
|
||||
|
||||
|
||||
{"KRIMZON_SV_PARSECLIENTCOMMAND", 3, NULL, {"clientcommand", "tokenize", "argv"}, "SSQC's SV_ParseClientCommand function is able to handle client 'cmd' commands. The tokenizing parts also work in csqc."}, //very very similar to the mvdsv system.
|
||||
{"NEH_CMD_PLAY2"},
|
||||
{"NEH_RESTOREGAME"},
|
||||
|
|
|
@ -38,6 +38,7 @@
|
|||
|
||||
|
||||
#define QCFAULT return (pr_xstatement=(st-pr_statements)-1),PR_HandleFault
|
||||
#define EVAL_FLOATISTRUE(ev) ((ev)->_int & 0x7fffffff) //mask away sign bit. This avoids using denormalized floats.
|
||||
|
||||
#ifdef __GNUC__
|
||||
#define errorif(x) if(__builtin_expect(x,0))
|
||||
|
@ -223,14 +224,18 @@ reeval:
|
|||
break;
|
||||
|
||||
case OP_AND_F:
|
||||
OPC->_float = (float)(OPA->_float && OPB->_float);
|
||||
//original logic
|
||||
//OPC->_float = (float)(OPA->_float && OPB->_float);
|
||||
//deal with denormalized floats by ensuring that they're not 0 (ignoring sign bit).
|
||||
//this avoids issues where the fpu treats denormalised floats as 0, or fpus that don't support denormals.
|
||||
OPC->_float = (float)(EVAL_FLOATISTRUE(OPA) && EVAL_FLOATISTRUE(OPB));
|
||||
break;
|
||||
case OP_OR_F:
|
||||
OPC->_float = (float)(OPA->_float || OPB->_float);
|
||||
OPC->_float = (float)(EVAL_FLOATISTRUE(OPA) || EVAL_FLOATISTRUE(OPB));
|
||||
break;
|
||||
|
||||
case OP_NOT_F:
|
||||
OPC->_float = (float)(!OPA->_float);
|
||||
OPC->_float = (float)(!EVAL_FLOATISTRUE(OPA));
|
||||
break;
|
||||
case OP_NOT_V:
|
||||
OPC->_float = (float)(!OPA->_vector[0] && !OPA->_vector[1] && !OPA->_vector[2]);
|
||||
|
@ -549,7 +554,7 @@ reeval:
|
|||
OPC->_vector[2] = ptr->_vector[2];
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
//==================
|
||||
|
||||
case OP_IFNOT_S:
|
||||
|
@ -560,10 +565,11 @@ reeval:
|
|||
|
||||
case OP_IFNOT_F:
|
||||
RUNAWAYCHECK();
|
||||
if (!OPA->_float)
|
||||
if (!EVAL_FLOATISTRUE(OPA))
|
||||
st += (sofs)st->b - 1; // offset the s++
|
||||
break;
|
||||
|
||||
//WARNING: vanilla uses this for floats too, which results in a discrepancy with -0
|
||||
case OP_IFNOT_I:
|
||||
RUNAWAYCHECK();
|
||||
if (!OPA->_int)
|
||||
|
@ -578,16 +584,17 @@ reeval:
|
|||
|
||||
case OP_IF_F:
|
||||
RUNAWAYCHECK();
|
||||
if (OPA->_float)
|
||||
if (EVAL_FLOATISTRUE(OPA))
|
||||
st += (sofs)st->b - 1; // offset the s++
|
||||
break;
|
||||
|
||||
//WARNING: vanilla uses this for floats too, which results in a discrepancy with -0
|
||||
case OP_IF_I:
|
||||
RUNAWAYCHECK();
|
||||
if (OPA->_int)
|
||||
st += (sofs)st->b - 1; // offset the s++
|
||||
break;
|
||||
|
||||
|
||||
case OP_GOTO:
|
||||
RUNAWAYCHECK();
|
||||
st += (sofs)st->a - 1; // offset the s++
|
||||
|
|
|
@ -148,12 +148,12 @@ void WPhys_CheckVelocity (world_t *w, wedict_t *ent)
|
|||
{
|
||||
if (IS_NAN(ent->v->velocity[i]))
|
||||
{
|
||||
Con_DPrintf ("Got a NaN velocity on %s\n", PR_GetString(w->progs, ent->v->classname));
|
||||
Con_DPrintf ("Got a NaN velocity on entity %i (%s)\n", ent->entnum, PR_GetString(w->progs, ent->v->classname));
|
||||
ent->v->velocity[i] = 0;
|
||||
}
|
||||
if (IS_NAN(ent->v->origin[i]))
|
||||
{
|
||||
Con_Printf ("Got a NaN origin on %s\n", PR_GetString(w->progs, ent->v->classname));
|
||||
Con_Printf ("Got a NaN origin on entity %i (%s)\n", ent->entnum, PR_GetString(w->progs, ent->v->classname));
|
||||
ent->v->origin[i] = 0;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -769,48 +769,65 @@ int main(int argc, char *argv[])
|
|||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
int Sys_EnumerateFiles (const char *gpath, const char *match, int (*func)(const char *, qofs_t, time_t mtime, void *, searchpathfuncs_t *), void *parm, searchpathfuncs_t *spath)
|
||||
int Sys_EnumerateFiles2 (const char *truepath, int apathofs, const char *match, int (*func)(const char *, qofs_t, time_t modtime, void *, searchpathfuncs_t *), void *parm, searchpathfuncs_t *spath)
|
||||
{
|
||||
DIR *dir;
|
||||
char apath[MAX_OSPATH];
|
||||
char file[MAX_OSPATH];
|
||||
char truepath[MAX_OSPATH];
|
||||
char *s;
|
||||
const char *s;
|
||||
struct dirent *ent;
|
||||
struct stat st;
|
||||
const char *wild;
|
||||
const char *apath = truepath+apathofs;
|
||||
|
||||
//printf("path = %s\n", gpath);
|
||||
//printf("match = %s\n", match);
|
||||
|
||||
if (!gpath)
|
||||
gpath = "";
|
||||
*apath = '\0';
|
||||
|
||||
Q_strncpyz(apath, match, sizeof(apath));
|
||||
for (s = apath+strlen(apath)-1; s >= apath; s--)
|
||||
//if there's a * in a system path, then we need to scan its parent directory to figure out what the * expands to.
|
||||
//we can just recurse quicklyish to try to handle it.
|
||||
wild = strchr(apath, '*');
|
||||
if (!wild)
|
||||
wild = strchr(apath, '?');
|
||||
if (wild)
|
||||
{
|
||||
if (*s == '/')
|
||||
char subdir[MAX_OSPATH];
|
||||
for (s = wild+1; *s && *s != '/'; s++)
|
||||
;
|
||||
while (wild > truepath)
|
||||
{
|
||||
s[1] = '\0';
|
||||
match += s - apath+1;
|
||||
break;
|
||||
if (*(wild-1) == '/')
|
||||
break;
|
||||
wild--;
|
||||
}
|
||||
memcpy(file, truepath, wild-truepath);
|
||||
file[wild-truepath] = 0;
|
||||
|
||||
dir = opendir(file);
|
||||
memcpy(subdir, wild, s-wild);
|
||||
subdir[s-wild] = 0;
|
||||
if (dir)
|
||||
{
|
||||
do
|
||||
{
|
||||
ent = readdir(dir);
|
||||
if (!ent)
|
||||
break;
|
||||
if (*ent->d_name != '.')
|
||||
{
|
||||
if (wildcmp(subdir, ent->d_name))
|
||||
{
|
||||
memcpy(file, truepath, wild-truepath);
|
||||
Q_snprintfz(file+(wild-truepath), sizeof(file)-(wild-truepath), "%s%s", ent->d_name, s);
|
||||
if (!Sys_EnumerateFiles2(file, apathofs, match, func, parm, spath))
|
||||
{
|
||||
closedir(dir);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
} while(1);
|
||||
closedir(dir);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (s < apath) //didn't find a '/'
|
||||
*apath = '\0';
|
||||
|
||||
Q_snprintfz(truepath, sizeof(truepath), "%s/%s", gpath, apath);
|
||||
|
||||
|
||||
//printf("truepath = %s\n", truepath);
|
||||
//printf("gamepath = %s\n", gpath);
|
||||
//printf("apppath = %s\n", apath);
|
||||
//printf("match = %s\n", match);
|
||||
dir = opendir(truepath);
|
||||
if (!dir)
|
||||
{
|
||||
|
@ -834,6 +851,7 @@ int Sys_EnumerateFiles (const char *gpath, const char *match, int (*func)(const
|
|||
|
||||
if (!func(file, st.st_size, st.st_mtime, parm, spath))
|
||||
{
|
||||
Con_DPrintf("giving up on search after finding %s\n", file);
|
||||
closedir(dir);
|
||||
return false;
|
||||
}
|
||||
|
@ -844,9 +862,34 @@ int Sys_EnumerateFiles (const char *gpath, const char *match, int (*func)(const
|
|||
}
|
||||
} while(1);
|
||||
closedir(dir);
|
||||
|
||||
return true;
|
||||
}
|
||||
int Sys_EnumerateFiles (const char *gpath, const char *match, int (*func)(const char *, qofs_t, time_t modtime, void *, searchpathfuncs_t *), void *parm, searchpathfuncs_t *spath)
|
||||
{
|
||||
char apath[MAX_OSPATH];
|
||||
char truepath[MAX_OSPATH];
|
||||
char *s;
|
||||
|
||||
if (!gpath)
|
||||
gpath = "";
|
||||
*apath = '\0';
|
||||
|
||||
Q_strncpyz(apath, match, sizeof(apath));
|
||||
for (s = apath+strlen(apath)-1; s >= apath; s--)
|
||||
{
|
||||
if (*s == '/')
|
||||
{
|
||||
s[1] = '\0';
|
||||
match += s - apath+1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (s < apath) //didn't find a '/'
|
||||
*apath = '\0';
|
||||
|
||||
Q_snprintfz(truepath, sizeof(truepath), "%s/%s", gpath, apath);
|
||||
return Sys_EnumerateFiles2(truepath, strlen(gpath)+1, match, func, parm, spath);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
Loading…
Reference in a new issue