tweaks to try to get a more sane gui debug protocol.

gui debugging works with -dedicated. actual dedicated servers still not tested.
preliminary hack to support directly loading .map files without compiling. stable but buggy, not really yet worth using. attempted to rework entity lump parsing to work properly with threads.
reworked colour clears. gl_clear now clears *BEFORE* csqc is called. also, now also supports a range of colours. use 8 for black.

git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@4818 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
Spoike 2015-01-07 13:34:05 +00:00
parent 6ba09e4cce
commit 775f6abc0f
34 changed files with 1166 additions and 274 deletions

View File

@ -1226,6 +1226,10 @@ int CL_LoadModels(int stage, qboolean dontactuallyload)
if (atstage())
{
SCR_SetLoadingFile("wads");
if (cl.worldmodel && cl.worldmodel->loadstate == MLS_LOADING)
return stage;
Mod_ParseInfoFromEntityLump(cl.worldmodel);
Wad_NextDownload();
endstage();

View File

@ -281,8 +281,8 @@ struct pendingtextureinfo
PTI_DEPTH16,
PTI_DEPTH24,
PTI_DEPTH32,
PTI_DEPTH24_8
#define PTI_MAX PTI_DEPTH24_8+1
PTI_DEPTH24_8,
PTI_MAX
} encoding; //0
int mipcount;
struct
@ -415,9 +415,9 @@ typedef struct rendererinfo_s {
void (*BE_Scissor)(srect_t *rect);
/*check to see if an ent should be drawn for the selected light*/
qboolean (*BE_LightCullModel)(vec3_t org, struct model_s *model);
void (*BE_VBO_Begin)(vbobctx_t *ctx, unsigned int maxsize);
void (*BE_VBO_Data)(vbobctx_t *ctx, void *data, unsigned int size, vboarray_t *varray);
void (*BE_VBO_Finish)(vbobctx_t *ctx, void *edata, unsigned int esize, vboarray_t *earray);
void (*BE_VBO_Begin)(vbobctx_t *ctx, size_t maxsize);
void (*BE_VBO_Data)(vbobctx_t *ctx, void *data, size_t size, vboarray_t *varray);
void (*BE_VBO_Finish)(vbobctx_t *ctx, void *edata, size_t esize, vboarray_t *earray);
void (*BE_VBO_Destroy)(vboarray_t *vearray);
void (*BE_RenderToTextureUpdate2d)(qboolean destchanged);
char *alignment;

View File

@ -1602,6 +1602,13 @@ void QCBUILTIN PF_R_SetViewFlag(pubprogfuncs_t *prinst, struct globalvars_s *pr_
break;
case VF_RT_DESTCOLOUR0:
case VF_RT_DESTCOLOUR1:
case VF_RT_DESTCOLOUR2:
case VF_RT_DESTCOLOUR3:
case VF_RT_DESTCOLOUR4:
case VF_RT_DESTCOLOUR5:
case VF_RT_DESTCOLOUR6:
case VF_RT_DESTCOLOUR7:
{
int i = parametertype - VF_RT_DESTCOLOUR0;
Q_strncpyz(r_refdef.rt_destcolour[i].texname, PR_GetStringOfs(prinst, OFS_PARM1), sizeof(r_refdef.rt_destcolour[i].texname));
@ -6173,8 +6180,8 @@ void CSQC_WatchPoint_f(void)
void PR_CSProfile_f(void)
{
if (csqcprogs && csqcprogs->DumpProfile)
if (!csqcprogs->DumpProfile(csqcprogs))
Con_Printf("Please set pr_enable_profiling and restart the map first\n");
if (!csqcprogs->DumpProfile(csqcprogs, !atof(Cmd_Argv(1))))
Con_Printf("Enabled csqc Profiling.\n");
}
static void CSQC_GameCommand_f(void);

View File

@ -2913,7 +2913,7 @@ void Surf_NewMap (void)
{
if (cl.worldmodel->loadstate == MLS_LOADING)
COM_WorkerPartialSync(cl.worldmodel, &cl.worldmodel->loadstate, MLS_LOADING);
Mod_ParseInfoFromEntityLump(cl.worldmodel, cl.worldmodel->entities, cl.worldmodel->name);
Mod_ParseInfoFromEntityLump(cl.worldmodel);
}
if (!pe)
@ -2944,8 +2944,16 @@ TRACE(("dbg: Surf_NewMap: tp\n"));
{
vec3_t mins, maxs;
//fixme: no rotation
VectorAdd(cl_static_entities[i].ent.origin, cl_static_entities[i].ent.model->mins, mins);
VectorAdd(cl_static_entities[i].ent.origin, cl_static_entities[i].ent.model->maxs, maxs);
if (cl_static_entities[i].ent.model)
{
VectorAdd(cl_static_entities[i].ent.origin, cl_static_entities[i].ent.model->mins, mins);
VectorAdd(cl_static_entities[i].ent.origin, cl_static_entities[i].ent.model->maxs, maxs);
}
else
{
VectorCopy(mins, cl_static_entities[i].ent.origin);
VectorCopy(maxs, cl_static_entities[i].ent.origin);
}
cl.worldmodel->funcs.FindTouchedLeafs(cl.worldmodel, &cl_static_entities[i].pvscache, mins, maxs);
cl_static_entities[i].emit = NULL;
}

View File

@ -1967,8 +1967,16 @@ qboolean Sys_InitTerminal (void)
SetConsoleCP(CP_UTF8);
SetConsoleOutputCP(CP_UTF8);
SetConsoleTitle (FULLENGINENAME " dedicated server");
hinput = GetStdHandle (STD_INPUT_HANDLE);
houtput = GetStdHandle (STD_OUTPUT_HANDLE);
if (isPlugin)
{
hinput = CreateFile("CONIN$",GENERIC_READ|GENERIC_WRITE,FILE_SHARE_READ,0,OPEN_EXISTING,0,0);
houtput = CreateFile("CONOUT$",GENERIC_READ|GENERIC_WRITE,FILE_SHARE_READ,0,OPEN_EXISTING,0,0);
}
else
{
hinput = GetStdHandle (STD_INPUT_HANDLE);
houtput = GetStdHandle (STD_OUTPUT_HANDLE);
}
GetConsoleMode(hinput, &m);
SetConsoleMode(hinput, m | 0x40 | 0x80);
@ -2023,7 +2031,7 @@ void Sys_SendKeyEvents (void)
if (nl)
{
*nl++ = 0;
if (!qrenderer && !strncmp(text, "vid_recenter ", 13))
if (qrenderer <= QR_NONE && !strncmp(text, "vid_recenter ", 13))
{
Cmd_TokenizeString(text, false, false);
sys_parentleft = strtoul(Cmd_Argv(1), NULL, 0);
@ -2051,7 +2059,7 @@ void Sys_SendKeyEvents (void)
}
}
else if (isDedicated)
if (isDedicated)
{
#ifndef CLIENTONLY
SV_GetConsoleCommands ();
@ -2475,6 +2483,8 @@ void Win7_TaskListInit(void)
#define UPD_BUILDTYPE "rel"
#else
#define UPD_BUILDTYPE "test"
//WARNING: Security comes from the fact that the triptohell.info certificate is hardcoded in the tls code.
//this will correctly detect insecure tls proxies also.
#define UPDATE_URL "https://triptohell.info/moodles/"
#define UPDATE_URL_VERSION UPDATE_URL "version.txt"
#ifdef _WIN64
@ -3124,16 +3134,22 @@ int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLin
host_parms.binarydir = bindir;
COM_InitArgv (parms.argc, parms.argv);
c = COM_CheckParm("-plugin");
c = COM_CheckParm("-qcdebug");
if (c)
{
if (c < com_argc && !strcmp(com_argv[c+1], "qcdebug"))
isPlugin = 2;
else
isPlugin = 1;
}
isPlugin = 3;
else
isPlugin = 0;
{
c = COM_CheckParm("-plugin");
if (c)
{
if (c < com_argc && !strcmp(com_argv[c+1], "qcdebug"))
isPlugin = 2;
else
isPlugin = 1;
}
else
isPlugin = 0;
}
if (Sys_CheckUpdated())
return true;
@ -3161,7 +3177,7 @@ int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLin
Sys_CreateThread("watchdog", watchdogthread, NULL, 0, 0);
#endif
if (isPlugin)
if (isPlugin==1)
{
printf("status Starting up!\n");
fflush(stdout);
@ -3325,7 +3341,7 @@ int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLin
#endif
#endif
if (isPlugin)
if (isPlugin==1)
{
printf("status Running!\n");
fflush(stdout);

View File

@ -310,7 +310,7 @@ void W_LoadTextureWadFile (char *filename, int complain)
if (VFS_READ(file, &header, sizeof(wadinfo_t)) != sizeof(wadinfo_t))
{Con_Printf ("W_LoadTextureWadFile: unable to read wad header");return;}
if(memcmp(header.identification, "WAD3", 4))
if (memcmp(header.identification, "WAD3", 4) && memcmp(header.identification, "WAD2", 4))
{Con_Printf ("W_LoadTextureWadFile: Wad file %s doesn't have WAD3 id\n",filename);return;}
numlumps = LittleLong(header.numlumps);
@ -372,7 +372,7 @@ void W_ApplyGamma (qbyte *data, int len, int skipalpha)
}
}
*/
qbyte *W_ConvertWAD3Texture(miptex_t *tex, int *width, int *height, qboolean *usesalpha) //returns rgba
qbyte *W_ConvertWAD3Texture(miptex_t *tex, size_t lumpsize, int *width, int *height, qboolean *usesalpha) //returns rgba
{
qbyte *in, *data, *out, *pal;
int d, p;
@ -396,6 +396,8 @@ qbyte *W_ConvertWAD3Texture(miptex_t *tex, int *width, int *height, qboolean *us
*height = tex->height;
pal = in + (((tex->width * tex->height) * 85) >> 6);
pal += 2;
if (pal+768 - (qbyte*)tex > lumpsize)
pal = host_basepal;
for (d = 0;d < tex->width * tex->height;d++)
{
p = *in++;
@ -472,7 +474,7 @@ qbyte *W_GetTexture(const char *name, int *width, int *height, qboolean *usesalp
for (j = 0;j < MIPLEVELS;j++)
tex->offsets[j] = LittleLong(tex->offsets[j]);
data = W_ConvertWAD3Texture(tex, width, height, usesalpha);
data = W_ConvertWAD3Texture(tex, texwadlump[i].size, width, height, usesalpha);
BZ_Free(tex);
return data;
}
@ -578,10 +580,11 @@ void CL_Skygroup_f(void)
}
char wads[4096];
void Mod_ParseInfoFromEntityLump(model_t *wmodel, char *data, char *mapname) //actually, this should be in the model code.
void Mod_ParseInfoFromEntityLump(model_t *wmodel) //actually, this should be in the model code.
{
char token[4096];
char key[128];
char *data = wmodel->entities;
mapskys_t *msky;
cl.skyrotate = 0;
@ -617,7 +620,7 @@ void Mod_ParseInfoFromEntityLump(model_t *wmodel, char *data, char *mapname) //a
break; // error
if (!strcmp("wad", key)) // for HalfLife maps
{
if (wmodel->fromgame == fg_halflife)
if (wmodel->fromgame == fg_halflife || wmodel->type == mod_heightmap)
{
Q_strncatz(wads, ";", sizeof(wads)); //cache it for later (so that we don't play with any temp memory yet)
Q_strncatz(wads, token, sizeof(wads)); //cache it for later (so that we don't play with any temp memory yet)
@ -691,11 +694,12 @@ void Mod_ParseInfoFromEntityLump(model_t *wmodel, char *data, char *mapname) //a
}
}
COM_FileBase (wmodel->name, token, sizeof(token));
//map-specific sky override feature
for (msky = mapskies; msky; msky = msky->next)
{
if (!strcmp(msky->mapname, mapname))
if (!strcmp(msky->mapname, token))
{
Q_strncpyz(cl.skyname, msky->skyname, sizeof(cl.skyname));
break;
@ -733,10 +737,10 @@ qboolean Wad_NextDownload (void)
{
k = wads[i];
wads[i] = 0;
strcpy(wadname, &wads[j]);
strcpy(wadname+9, &wads[j]);
if (wadname[9])
{
if (COM_FCheckExists(wadname+9)) //wad is in root dir, so we don't need to try textures.
if (!COM_FCheckExists(wadname+9)) //wad is in root dir, so we don't need to try textures.
CL_CheckOrEnqueDownloadFile(wadname, wadname, DLLF_REQUIRED); //don't skip this one, or the world is white.
}
wads[i] = k;

View File

@ -112,7 +112,7 @@ void SwapPic (qpic_t *pic);
struct model_s;
void Mod_ParseWadsFromEntityLump(char *data);
qbyte *W_ConvertWAD3Texture(miptex_t *tex, int *width, int *height, qboolean *usesalpha);
void Mod_ParseInfoFromEntityLump(struct model_s *wmodel, char *data, char *mapname);
qbyte *W_ConvertWAD3Texture(miptex_t *tex, size_t lumpsize, int *width, int *height, qboolean *usesalpha);
void Mod_ParseInfoFromEntityLump(struct model_s *wmodel);
qboolean Wad_NextDownload (void);
qbyte *W_GetTexture(const char *name, int *width, int *height, qboolean *usesalpha);

View File

@ -1168,7 +1168,7 @@ static dllfunction_t odefuncs[] =
};
// Handle for ODE DLL
dllhandle_t ode_dll = NULL;
dllhandle_t *ode_dll = NULL;
#endif
static void World_ODE_RunCmd(world_t *world, odecommandqueue_t *cmd);
@ -1258,7 +1258,7 @@ void World_ODE_Shutdown(void)
{
dCloseODE();
#ifdef ODE_DYNAMIC
Sys_CloseLibrary(&ode_dll);
Sys_CloseLibrary(ode_dll);
ode_dll = NULL;
#endif
}

View File

@ -3529,7 +3529,7 @@ char *COM_ParseStringSet (const char *data, char *out, size_t outsize)
}
char *COM_ParseOut (const char *data, char *out, int outlen)
char *COM_ParseType (const char *data, char *out, int outlen, com_tokentype_t *toktype)
{
int c;
int len;
@ -3539,6 +3539,8 @@ char *COM_ParseOut (const char *data, char *out, int outlen)
len = 0;
out[0] = 0;
if (toktype)
*toktype = TTP_EOF;
if (!data)
return NULL;
@ -3582,6 +3584,9 @@ skipwhite:
// handle quoted strings specially
if (c == '\"')
{
if (toktype)
*toktype = TTP_STRING;
data++;
while (1)
{
@ -3603,6 +3608,8 @@ skipwhite:
}
// parse a regular word
if (toktype)
*toktype = TTP_RAWTOKEN;
do
{
if (len >= outlen-1)

View File

@ -266,7 +266,7 @@ void deleetstring(char *result, const char *leet);
extern char com_token[65536];
typedef enum {TTP_UNKNOWN, TTP_STRING, TTP_LINEENDING} com_tokentype_t;
typedef enum {TTP_UNKNOWN, TTP_STRING, TTP_LINEENDING, TTP_RAWTOKEN, TTP_EOF} com_tokentype_t;
extern com_tokentype_t com_tokentype;
extern qboolean com_eof;
@ -274,7 +274,8 @@ extern qboolean com_eof;
//these cast away the const for the return value.
//char *COM_Parse (const char *data);
#define COM_Parse(d) COM_ParseOut(d,com_token, sizeof(com_token))
char *COM_ParseOut (const char *data, char *out, int outlen);
#define COM_ParseOut(d,o,l) COM_ParseType(d,o,l,NULL)
char *COM_ParseType (const char *data, char *out, int outlen, com_tokentype_t *toktype);
char *COM_ParseStringSet (const char *data, char *out, size_t outlen);
char *COM_ParseCString (const char *data, char *out, size_t maxoutlen, size_t *writtenlen);
char *COM_StringParse (const char *data, char *token, unsigned int tokenlen, qboolean expandmacros, qboolean qctokenize);

View File

@ -4154,10 +4154,6 @@ static cmodel_t *CM_LoadMap (model_t *mod, qbyte *filein, size_t filelen, qboole
}
}
#ifndef SERVERONLY
Mod_ParseInfoFromEntityLump(mod, mod->entities, loadname); //only done for client's world model (or server if the server is loading it for client)
#endif
CM_InitBoxHull ();
if (map_autoopenportals.value)

View File

@ -11,7 +11,7 @@ cvar_t *tls_ignorecertificateerrors;
//hungarian ensures we hit no macros.
static struct
{
void *lib;
dllhandle_t *lib;
SECURITY_STATUS (WINAPI *pDecryptMessage) (PCtxtHandle,PSecBufferDesc,ULONG,PULONG);
SECURITY_STATUS (WINAPI *pEncryptMessage) (PCtxtHandle,ULONG,PSecBufferDesc,ULONG);
SECURITY_STATUS (WINAPI *pAcquireCredentialsHandleA) (SEC_CHAR*,SEC_CHAR*,ULONG,PLUID,PVOID,SEC_GET_KEY_FN,PVOID,PCredHandle,PTimeStamp);
@ -24,7 +24,7 @@ static struct
} secur;
static struct
{
void *lib;
dllhandle_t *lib;
BOOL (WINAPI *pCertGetCertificateChain) (HCERTCHAINENGINE,PCCERT_CONTEXT,LPFILETIME,HCERTSTORE,PCERT_CHAIN_PARA,DWORD,LPVOID,PCCERT_CHAIN_CONTEXT*);
BOOL (WINAPI *pCertVerifyCertificateChainPolicy) (LPCSTR,PCCERT_CHAIN_CONTEXT,PCERT_CHAIN_POLICY_PARA,PCERT_CHAIN_POLICY_STATUS);
void (WINAPI *pCertFreeCertificateChain) (PCCERT_CHAIN_CONTEXT);

View File

@ -103,7 +103,7 @@ void QCLoadBreakpoints(const char *vmname, const char *progsname)
{ //this asks the gui to reapply any active breakpoints and waits for them so that any spawn functions can be breakpointed properly.
#if defined(_WIN32) && !defined(SERVERONLY) && !defined(FTE_SDL)
extern int isPlugin;
if (isPlugin == 2)
if (isPlugin >= 2)
{
Sys_SendKeyEvents();
debuggerresume = false;
@ -120,6 +120,7 @@ void QCLoadBreakpoints(const char *vmname, const char *progsname)
}
extern cvar_t pr_sourcedir;
pubprogfuncs_t *debuggerinstance;
size_t debuggerwnd;
qboolean QCExternalDebuggerCommand(char *text)
{
@ -139,6 +140,11 @@ qboolean QCExternalDebuggerCommand(char *text)
if (l)
debuggerresumeline = l;
}
else if (!strncmp(text, "debuggerwnd ", 11))
{
//send focus to this window when debugging
debuggerwnd = strtoul(text+12, NULL, 0);
}
else if (!strncmp(text, "qcinspect ", 10))
{
//called on mouse-over events in the gui
@ -193,10 +199,19 @@ qboolean QCExternalDebuggerCommand(char *text)
Q_strncatz(resultbuffer, COM_QuotedString(values[i], tmpbuffer, sizeof(tmpbuffer), true), sizeof(resultbuffer));
}
Con_Printf("lookup %s\n", variable);
printf("qcvalue \"%s\" %s\n", variable, COM_QuotedString(resultbuffer, tmpbuffer, sizeof(tmpbuffer), false));
fflush(stdout);
}
else if (!strncmp(text, "qcreload", 8))
{
#ifdef MENU_DAT
Cbuf_AddText("menu_restart\n", RESTRICT_LOCAL);
#endif
#ifndef CLIENTONLY
if (sv.state)
Cbuf_AddText("restart\n", RESTRICT_LOCAL);
#endif
}
else if (!strncmp(text, "qcbreakpoint ", 13))
{
extern world_t csqc_world, menu_world;
@ -231,13 +246,15 @@ qboolean QCExternalDebuggerCommand(char *text)
int QDECL QCEditor (pubprogfuncs_t *prinst, char *filename, int line, int statement, int nump, char **parms)
{
#if defined(_WIN32) && !defined(SERVERONLY) && !defined(FTE_SDL)
if (isPlugin == 2)
if (isPlugin >= 2)
{
if (!*filename) //don't try editing an empty line, it won't work
return line;
Sys_SendKeyEvents();
debuggerresume = false;
debuggerresumeline = line;
if (debuggerwnd)
SetForegroundWindow((HWND)debuggerwnd);
printf("qcstep \"%s\":%i\n", filename, line);
fflush(stdout);
INS_UpdateGrabs(false, false);
@ -247,15 +264,18 @@ int QDECL QCEditor (pubprogfuncs_t *prinst, char *filename, int line, int statem
Sleep(10);
Sys_SendKeyEvents();
//FIXME: display a stack trace and locals instead
R2D_ImageColours((sin(Sys_DoubleTime())+1)*0.5,0, 0, 1);
R2D_FillBlock(0, 0, vid.width, vid.height);
Con_DrawConsole(vid.height/2, true); //draw console at half-height
debuggerstacky = vid.height/2;
if (debuggerstacky)
PR_StackTrace(prinst, 2);
debuggerstacky = 0;
VID_SwapBuffers();
if (qrenderer)
{
//FIXME: display a stack trace and locals instead
R2D_ImageColours((sin(Sys_DoubleTime())+1)*0.5,0, 0, 1);
R2D_FillBlock(0, 0, vid.width, vid.height);
Con_DrawConsole(vid.height/2, true); //draw console at half-height
debuggerstacky = vid.height/2;
if (debuggerstacky)
PR_StackTrace(prinst, 2);
debuggerstacky = 0;
VID_SwapBuffers();
}
}
debuggerinstance = NULL;
if (debuggerresume == 2)

View File

@ -1,3 +1,6 @@
#ifdef __cplusplus
extern "C" {
#endif
#include "progtype.h"
#include "progslib.h"
@ -716,3 +719,6 @@ enum
GE_ABSMAX = 15,
GE_LIGHT = 16
};
#ifdef __cplusplus
};
#endif

View File

@ -1217,7 +1217,7 @@ static void Fragment_ClipTriangle(fragmentdecal_t *dec, float *a, float *b, floa
#else
#define MAXFRAGMENTVERTS 360
static int Fragment_ClipPolyToPlane(float *inverts, float *outverts, int incount, float *plane, float planedist)
int Fragment_ClipPolyToPlane(float *inverts, float *outverts, int incount, float *plane, float planedist)
{
#define C 4
float dotv[MAXFRAGMENTVERTS+1];

View File

@ -54,7 +54,7 @@ typedef struct {
void **funcptr;
char *name;
} dllfunction_t;
typedef void *dllhandle_t;
typedef struct { int unused; } dllhandle_t; //typically recast to void*
dllhandle_t *Sys_LoadLibrary(const char *name, dllfunction_t *funcs);
void Sys_CloseLibrary(dllhandle_t *lib);
void *Sys_GetAddressForName(dllhandle_t *module, const char *exportname);

View File

@ -2445,6 +2445,7 @@ void BE_GenModelBatches(batch_t **batches, const dlight_t *dl, unsigned int bemo
{
int i;
entity_t *ent;
model_t *emodel;
unsigned int orig_numstris = cl_numstris;
unsigned int orig_numvisedicts = cl_numvisedicts;
unsigned int orig_numstrisidx = cl_numstrisidx;
@ -2495,14 +2496,15 @@ void BE_GenModelBatches(batch_t **batches, const dlight_t *dl, unsigned int bemo
{
case RT_MODEL:
default:
if (!ent->model)
emodel = ent->model;
if (!emodel)
continue;
if (ent->model->loadstate == MLS_NOTLOADED)
if (emodel->loadstate == MLS_NOTLOADED)
{
if (!Mod_LoadModel(ent->model, MLV_WARN))
if (!Mod_LoadModel(emodel, MLV_WARN))
continue;
}
if (ent->model->loadstate != MLS_LOADED)
if (emodel->loadstate != MLS_LOADED)
continue;
if (cl.lerpents && (cls.allow_anyparticles)) //allowed or static
@ -2514,14 +2516,14 @@ void BE_GenModelBatches(batch_t **batches, const dlight_t *dl, unsigned int bemo
}
}
if (ent->model->engineflags & MDLF_NOTREPLACEMENTS)
if (emodel->engineflags & MDLF_NOTREPLACEMENTS)
{
if (ent->model->fromgame != fg_quake || ent->model->type != mod_alias)
if (emodel->fromgame != fg_quake || emodel->type != mod_alias)
if (!ruleset_allow_sensitive_texture_replacements.value)
continue;
}
switch(ent->model->type)
switch(emodel->type)
{
case mod_brush:
if (r_drawentities.ival == 2)
@ -2544,6 +2546,10 @@ void BE_GenModelBatches(batch_t **batches, const dlight_t *dl, unsigned int bemo
// warning: enumeration value mod_* not handled in switch
case mod_dummy:
case mod_heightmap:
#if defined(TERRAIN)
if (emodel->terrain && !(r_refdef.flags & RDF_NOWORLDMODEL))
Terr_DrawTerrainModel(batches, ent);
#endif
break;
}
break;

View File

@ -219,6 +219,34 @@ typedef struct
{
hmsection_t *section[MAXSECTIONS*MAXSECTIONS];
} hmcluster_t;
typedef struct brushtex_s
{
char shadername[MAX_QPATH];
shader_t *shader;
vbo_t vbo;
mesh_t mesh;
mesh_t *pmesh;
qboolean rebuild;
// struct
// {
// unsigned int brush;
// unsigned short face;
// } *faces;
// int numfaces;
struct brushtex_s *next;
} brushtex_t;
typedef struct
{
unsigned int contents;
size_t numplanes;
vec4_t *planes;
struct brushface_s
{
brushtex_t *tex;
vec4_t sdir;
vec4_t tdir;
} *faces;
} brushes_t;
typedef struct heightmap_s
{
char path[MAX_QPATH];
@ -286,6 +314,14 @@ typedef struct heightmap_s
unsigned int relightidx;
vec2_t relightmin;
#endif
brushtex_t *brushtextures;
brushes_t *wbrushes;
int numbrushes;
} heightmap_t;
#ifndef SERVERONLY
@ -298,6 +334,8 @@ static void Terr_WorkerLoadedSectionLightmap(void *ctx, void *data, size_t a, si
static void Terr_WorkerLoadedSection(void *ctx, void *data, size_t a, size_t b);
static void Terr_WorkerFailedSection(void *ctx, void *data, size_t a, size_t b);
void Terr_Brush_Draw(heightmap_t *hm, batch_t **batches, entity_t *e);
#ifndef SERVERONLY
static texid_t Terr_LoadTexture(char *name)
{
@ -2971,6 +3009,7 @@ void Terr_DrawTerrainModel (batch_t **batches, entity_t *e)
}
}
Terr_Brush_Draw(hm, batches, e);
if (r_refdef.globalfog.density || gl_maxdist.value>0)
{
@ -3378,9 +3417,9 @@ static void Heightmap_Trace_Square(hmtrace_t *tr, int tx, int ty)
sx = tx/(SECTHEIGHTSIZE-1);
sy = ty/(SECTHEIGHTSIZE-1);
if (sx < tr->hm->firstsegx || sx >= tr->hm->maxsegx)
s = NULL;
return;//s = NULL;
else if (sy < tr->hm->firstsegy || sy >= tr->hm->maxsegy)
s = NULL;
return;//s = NULL;
else
s = Terr_GetSection(tr->hm, sx, sy, TGS_TRYLOAD|TGS_WAITLOAD);
@ -3717,6 +3756,17 @@ qboolean Heightmap_Trace(struct model_s *model, int hulloverride, int frame, vec
pos[!axis] = ((hmtrace.end[!axis] * frac[axis]) + (hmtrace.start[!axis] * (1-frac[axis])) + CHUNKBIAS*hmtrace.hm->sectionsize)/hmtrace.htilesize;
}
{
brushes_t *brushes = hmtrace.hm->wbrushes;
int count = hmtrace.hm->numbrushes;
while(count-->0)
{
if (brushes->contents & against)
Heightmap_Trace_Brush(&hmtrace, brushes->planes, brushes->numplanes);
brushes++;
}
}
trace->plane.dist = hmtrace.plane[3];
trace->plane.normal[0] = hmtrace.plane[0];
trace->plane.normal[1] = hmtrace.plane[1];
@ -4668,15 +4718,509 @@ void Terr_FinishTerrain(model_t *mod)
#endif
}
int Fragment_ClipPolyToPlane(float *inverts, float *outverts, int incount, float *plane, float planedist);
size_t Terr_GenerateBrushFace(vecV_t *points, size_t maxpoints, vec4_t *planes, size_t numplanes, vec4_t face)
{
int p;
vec4_t verts[128];
vec4_t verts2[128];
vec4_t *cverts;
int flip;
vec3_t d1, d2, n;
size_t numverts;
//generate some huge quad/poly aligned with the plane
vec3_t tmp = {0.1,0.04,0.96};
vec3_t right, forward;
// if (face[2] != 1)
// return 0;
CrossProduct(face, tmp, right);
VectorNormalize(right);
CrossProduct(face, right, forward);
VectorNormalize(forward);
VectorScale(face, face[3], verts[0]);
VectorMA(verts[0], 8192, right, verts[0]);
VectorMA(verts[0], 8192, forward, verts[0]);
VectorScale(face, face[3], verts[1]);
VectorMA(verts[1], 8192, right, verts[1]);
VectorMA(verts[1], -8192, forward, verts[1]);
VectorScale(face, face[3], verts[2]);
VectorMA(verts[2], -8192, right, verts[2]);
VectorMA(verts[2], -8192, forward, verts[2]);
VectorScale(face, face[3], verts[3]);
VectorMA(verts[3], -8192, right, verts[3]);
VectorMA(verts[3], 8192, forward, verts[3]);
numverts = 4;
//clip the quad to the various other planes
flip = 0;
for (p = 0; p < numplanes; p++)
{
if (planes[p] != face)
{
vec3_t norm;
flip^=1;
VectorNegate(planes[p], norm);
if (flip)
numverts = Fragment_ClipPolyToPlane((float*)verts, (float*)verts2, numverts, norm, -planes[p][3]);
else
numverts = Fragment_ClipPolyToPlane((float*)verts2, (float*)verts, numverts, norm, -planes[p][3]);
if (numverts < 3) //totally clipped.
return 0;
}
}
if (numverts > maxpoints)
return 0;
if (flip)
cverts = verts2;
else
cverts = verts;
for (p = 0; p < numverts; p++)
{
VectorCopy(cverts[p], points[p]);
}
return numverts;
}
void Terr_Brush_Draw(heightmap_t *hm, batch_t **batches, entity_t *e)
{
#ifndef _DEBUG
return;
#else
batch_t *b;
size_t i, j;
vbobctx_t ctx;
brushtex_t *bt;
brushes_t *br;
static vecV_t coord[65536];
static vec2_t texcoord[65536];
static vec3_t normal[65536];
static vec3_t svector[65536];
static vec3_t tvector[65536];
static index_t index[65535];
size_t numverts = 0;
size_t numindicies = 0;
int w, h;
float scale[2];
for (bt = hm->brushtextures; bt; bt = bt->next)
{
if (!bt->shader)
{
if (!strcmp(bt->shadername, "clip"))
bt->shader = R_RegisterShader(bt->shadername, SUF_LIGHTMAP, "{\nsurfaceparm nodraw\n}");
else
bt->shader = R_RegisterShader_Lightmap(bt->shadername);
R_BuildDefaultTexnums(NULL, bt->shader);
}
if (bt->rebuild)
{
//FIXME: don't block.
if (R_GetShaderSizes(bt->shader, &w, &h, false) < 0)
continue;
bt->rebuild = false;
if (w<1) w = 64;
if (h<1) h = 64;
scale[0] = 1.0/w; //I hate needing this.
scale[1] = 1.0/h;
BE_VBO_Destroy(&bt->vbo.coord);
BE_VBO_Destroy(&bt->vbo.indicies);
for (i = 0, br = hm->wbrushes; i < hm->numbrushes; i++, br++)
{
for (j = 0; j < br->numplanes; j++)
{
if (br->faces[j].tex == bt)
{
size_t add, k, o;
//this face needs to be built
add = Terr_GenerateBrushFace(&coord[numverts], 64, br->planes, br->numplanes, br->planes[j]);
for (k = 0, o = numverts; k < add; k++, o++)
{
// VectorCopy(points[k], coord[o]);
VectorCopy(br->planes[j], normal[o]);
VectorCopy(br->faces[j].sdir, svector[o]);
VectorCopy(br->faces[j].tdir, tvector[o]);
//compute the texcoord plane
texcoord[o][0] = (DotProduct(svector[o], coord[o]) + br->faces[j].sdir[3]) * scale[0];
texcoord[o][1] = (DotProduct(tvector[o], coord[o]) + br->faces[j].tdir[3]) * scale[1];
}
for (k = 2; k < add; k++)
{ //triangle fans
index[numindicies++] = numverts + 0;
index[numindicies++] = numverts + k-1;
index[numindicies++] = numverts + k-0;
}
numverts += add;
}
}
}
BE_VBO_Begin(&ctx, (sizeof(coord[0])+sizeof(texcoord[0])+sizeof(normal[0])+sizeof(svector[0])+sizeof(tvector[0])) * numverts);
BE_VBO_Data(&ctx, coord, sizeof(coord[0])*numverts, &bt->vbo.coord);
BE_VBO_Data(&ctx, texcoord, sizeof(texcoord[0])*numverts, &bt->vbo.texcoord);
BE_VBO_Data(&ctx, normal, sizeof(normal[0])*numverts, &bt->vbo.normals);
BE_VBO_Data(&ctx, svector, sizeof(svector[0])*numverts, &bt->vbo.svector);
BE_VBO_Data(&ctx, tvector, sizeof(tvector[0])*numverts, &bt->vbo.tvector);
BE_VBO_Finish(&ctx, index, sizeof(index[0])*numindicies, &bt->vbo.indicies);
bt->pmesh = &bt->mesh;
bt->mesh.numindexes = numindicies;
bt->mesh.numvertexes = numverts;
}
if (!bt->mesh.numindexes)
continue; //o.O
b = BE_GetTempBatch();
if (b)
{
for (j = 0; j < MAXRLIGHTMAPS; j++)
b->lightmap[j] = -1;
b->ent = e;
b->shader = bt->shader;
b->flags = 0;
b->mesh = &bt->pmesh;
b->meshes = 1;
b->buildmeshes = NULL;
b->skin = &b->shader->defaulttextures;
b->texture = NULL;
b->vbo = &bt->vbo;
b->next = batches[b->shader->sort];
batches[b->shader->sort] = b;
}
}
#endif
}
brushtex_t *Terr_Brush_FindTexture(heightmap_t *hm, char *texname)
{
brushtex_t *bt;
if (!hm)
return NULL;
for (bt = hm->brushtextures; bt; bt = bt->next)
{
if (!strcmp(bt->shadername, texname))
return bt;
}
bt = Z_Malloc(sizeof(*bt));
bt->next = hm->brushtextures;
hm->brushtextures = bt;
Q_strncpyz(bt->shadername, texname, sizeof(bt->shadername));
return bt;
}
void Terr_Brush_Insert(heightmap_t *hm, brushes_t *brush)
{
int i;
brushes_t *out;
if (!hm)
return;
hm->wbrushes = BZ_Realloc(hm->wbrushes, sizeof(*hm->wbrushes) * (hm->numbrushes+1));
out = &hm->wbrushes[hm->numbrushes];
out->contents = brush->contents;
out->numplanes = brush->numplanes;
out->planes = BZ_Malloc((sizeof(*out->planes)+sizeof(*out->faces)) * out->numplanes);
out->faces = (void*)(out->planes+out->numplanes);
for (i = 0; i < out->numplanes; i++)
{
Vector4Copy(brush->planes[i], out->planes[i]);
out->faces[i].tex = brush->faces[i].tex;
Vector4Copy(brush->faces[i].sdir, out->faces[i].sdir);
Vector4Copy(brush->faces[i].tdir, out->faces[i].tdir);
//make sure this stuff is rebuilt properly.
out->faces[i].tex->rebuild = true;
}
hm->numbrushes+=1;
}
void Terr_ReformEntitiesLump(model_t *mod, heightmap_t *hm, char *entities)
{
char token[8192];
int nest = 0;
int buflen = strlen(entities);
char *out, *start;
int i;
int submodelnum = 0;
qboolean foundsubmodel = false;
qboolean inbrush = false;
int numplanes = 0;
vec4_t planes[64];
struct brushface_s faces[64];
int brushcontents = FTECONTENTS_SOLID;
heightmap_t *subhm = NULL;
model_t *submod = NULL;
/*FIXME: we need to re-form the entities lump to insert model fields as appropriate*/
mod->entities = out = ZG_Malloc(&mod->memgroup, buflen+1);
while(entities)
{
start = entities;
entities = COM_ParseOut(entities, token, sizeof(token));
if (token[0] == '}' && token[1] == 0)
{
nest--;
if (inbrush)
{
brushes_t brush;
//finish the brush
brush.contents = brushcontents;
brush.numplanes = numplanes;
brush.planes = planes;
brush.faces = faces;
if (numplanes)
Terr_Brush_Insert(subhm, &brush);
numplanes = 0;
inbrush = false;
continue;
}
}
else if (token[0] == '{' && token[1] == 0)
{
nest++;
if (nest == 1)
foundsubmodel = false;
if (nest == 2)
{
if (!foundsubmodel)
{
foundsubmodel = true;
if (submodelnum)
{
Q_snprintfz(token, sizeof(token), "*%i:%s", submodelnum, mod->name);
*out++ = 'm';
*out++ = 'o';
*out++ = 'd';
*out++ = 'e';
*out++ = 'l';
*out++ = ' ';
*out++ = '\"';
for (i = 0; token[i]; i++)
*out++ = token[i];
*out++ = '\"';
*out++ = ' ';
submod = Mod_FindName (token);
if (submod->loadstate == MLS_NOTLOADED)
{
submod->type = mod_heightmap;
submod->entities = "";
subhm = submod->terrain = Mod_LoadTerrainInfo(submod, submod->name, true);
subhm->exteriorcontents = FTECONTENTS_EMPTY;
ClearBounds(submod->mins, submod->maxs);
submod->funcs.NativeTrace = Heightmap_Trace;
submod->funcs.PointContents = Heightmap_PointContents;
submod->funcs.NativeContents = Heightmap_NativeBoxContents;
submod->funcs.LightPointValues = Heightmap_LightPointValues;
submod->funcs.StainNode = Heightmap_StainNode;
submod->funcs.MarkLights = Heightmap_MarkLights;
submod->funcs.ClusterForPoint = Heightmap_ClusterForPoint;
submod->funcs.ClusterPVS = Heightmap_ClusterPVS;
#ifndef CLIENTONLY
submod->funcs.FindTouchedLeafs = Heightmap_FindTouchedLeafs;
submod->funcs.EdictInFatPVS = Heightmap_EdictInFatPVS;
submod->funcs.FatPVS = Heightmap_FatPVS;
#endif
submod->loadstate = MLS_LOADED;
}
else
subhm = NULL;
}
else
{
submod = mod;
subhm = hm;
}
submodelnum++;
}
inbrush = true;
continue;
}
}
else if (inbrush)
{
//parse a plane
//( -0 -0 16 ) ( -0 -0 32 ) ( 64 -0 16 ) texname 0 -32 rotation sscale tscale
//( -0 -0 16 ) ( -0 -0 32 ) ( 64 -0 16 ) texname [x y z d] [x y z d] rotation sscale tscale
brushtex_t *bt;
vec3_t d1,d2;
vec3_t points[3];
vec4_t texplane[2];
float scale[2], rot;
int p, a;
memset(points, 0, sizeof(points));
for (p = 0; p < 3; p++)
{
if (token[0] != '(' || token[1] != 0)
break;
entities = COM_ParseOut(entities, token, sizeof(token));
points[p][0] = atof(token);
entities = COM_ParseOut(entities, token, sizeof(token));
points[p][1] = atof(token);
entities = COM_ParseOut(entities, token, sizeof(token));
points[p][2] = atof(token);
entities = COM_ParseOut(entities, token, sizeof(token));
if (token[0] != ')' || token[1] != 0)
break;
entities = COM_ParseOut(entities, token, sizeof(token));
for (a = 0; a < 3; a++)
{
if (submod->mins[a] > points[p][a])
submod->mins[a] = points[p][a];
if (submod->maxs[a] < points[p][a])
submod->maxs[a] = points[p][a];
}
}
bt = Terr_Brush_FindTexture(subhm, token);
if (*token == '*')
{
if (!strncmp(token, "*lava", 5))
brushcontents = FTECONTENTS_LAVA;
else if (!strncmp(token, "*slime", 5))
brushcontents = FTECONTENTS_SLIME;
else
brushcontents = FTECONTENTS_WATER;
}
else
brushcontents = FTECONTENTS_SOLID;
//FIXME: halflife format has the entire [x y z dist] plane specified.
entities = COM_ParseOut(entities, token, sizeof(token));
if (*token == '[')
{
texplane[0][0] = atof(token);
entities = COM_ParseOut(entities, token, sizeof(token));
texplane[0][1] = atof(token);
entities = COM_ParseOut(entities, token, sizeof(token));
texplane[0][2] = atof(token);
entities = COM_ParseOut(entities, token, sizeof(token));
texplane[0][3] = atof(token);
entities = COM_ParseOut(entities, token, sizeof(token));
//]
entities = COM_ParseOut(entities, token, sizeof(token));
//[
entities = COM_ParseOut(entities, token, sizeof(token));
texplane[1][0] = atof(token);
entities = COM_ParseOut(entities, token, sizeof(token));
texplane[1][1] = atof(token);
entities = COM_ParseOut(entities, token, sizeof(token));
texplane[1][2] = atof(token);
entities = COM_ParseOut(entities, token, sizeof(token));
texplane[1][3] = atof(token);
entities = COM_ParseOut(entities, token, sizeof(token));
//]
}
else
{
texplane[0][3] = atof(token);
entities = COM_ParseOut(entities, token, sizeof(token));
texplane[1][3] = atof(token);
}
entities = COM_ParseOut(entities, token, sizeof(token));
rot = atof(token);
entities = COM_ParseOut(entities, token, sizeof(token));
scale[0] = atof(token);
entities = COM_ParseOut(entities, token, sizeof(token));
scale[1] = atof(token);
VectorSubtract(points[0], points[1], d1);
VectorSubtract(points[2], points[1], d2);
CrossProduct(d1, d2, planes[numplanes]);
VectorNormalize(planes[numplanes]);
planes[numplanes][3] = DotProduct(points[1], planes[numplanes]);
faces[numplanes].tex = bt;
//quake's .maps use the normal to decide which texture directions to use in some lame axially-aligned way.
{
float a=fabs(planes[numplanes][0]),b=fabs(planes[numplanes][1]),c=fabs(planes[numplanes][2]);
VectorClear(texplane[0]);
VectorClear(texplane[1]);
if (a>b&&a>c)
texplane[0][1] = 1;
else
texplane[0][0] = 1;
if (c>a&&c>b)
texplane[1][1] = -1;
else
texplane[1][2] = -1;
}
if (rot)
{
int mas, mat;
float s,t;
float a = rot*(M_PI/180);
float cosa = cos(a), sina=sin(a);
for (mas=0; mas<2&&!texplane[0][mas]; mas++);
for (mat=0; mat<2&&!texplane[1][mat]; mat++);
for (i = 0; i < 2; i++)
{
s = cosa*texplane[i][mas] - sina*texplane[i][mat];
t = sina*texplane[i][mas] + cosa*texplane[i][mat];
texplane[i][mas] = s;
texplane[i][mat] = t;
}
}
if (!scale[0]) scale[0] = 1;
if (!scale[1]) scale[1] = 1;
VectorScale(texplane[0], 1.0/scale[0], faces[numplanes].sdir);
VectorScale(texplane[1], 1.0/scale[1], faces[numplanes].tdir);
faces[numplanes].sdir[3] = -texplane[0][3];
faces[numplanes].tdir[3] = -texplane[1][3];
numplanes++;
continue;
}
while(start < entities)
*out++ = *start++;
}
*out++ = 0;
}
qboolean QDECL Terr_LoadTerrainModel (model_t *mod, void *buffer, size_t bufsize)
{
int exterior = FTECONTENTS_SOLID;
heightmap_t *hm;
char token[MAX_QPATH];
int sectsize = 0;
char *src;
buffer = COM_ParseOut(buffer, token, sizeof(token));
if (strcmp(token, "terrain"))
src = COM_ParseOut(buffer, token, sizeof(token));
if (!strcmp(token, "terrain"))
buffer = src;
else if (!strcmp(token, "{"))
exterior = FTECONTENTS_EMPTY;
else
{
Con_Printf(CON_ERROR "%s wasn't terrain map\n", mod->name); //shouldn't happen
return false;
@ -4689,19 +5233,28 @@ qboolean QDECL Terr_LoadTerrainModel (model_t *mod, void *buffer, size_t bufsize
// ClearLink(&hm->collected);
COM_FileBase(mod->name, hm->path, sizeof(hm->path));
mod->entities = ZG_Malloc(&mod->memgroup, strlen(buffer)+1);
strcpy(mod->entities, buffer);
Terr_ReformEntitiesLump(mod, hm, buffer);
strcpy(hm->groundshadername, "terrainshader");
strcpy(hm->skyname, "sky1");
hm->entitylock = Sys_CreateMutex();
hm->sectionsize = sectsize;
hm->firstsegx = -1;
hm->firstsegy = -1;
hm->maxsegx = +1;
hm->maxsegy = +1;
hm->exteriorcontents = FTECONTENTS_SOLID; //sky outside the map
if (exterior)
{
hm->firstsegx = -1;
hm->firstsegy = -1;
hm->maxsegx = +1;
hm->maxsegy = +1;
}
else
{
hm->firstsegx = 0;
hm->firstsegy = 0;
hm->maxsegx = 0;
hm->maxsegy = 0;
}
hm->exteriorcontents = exterior; //sky outside the map
Terr_ParseEntityLump(mod->entities, hm);
@ -4757,11 +5310,20 @@ void *Mod_LoadTerrainInfo(model_t *mod, char *loadname, qboolean force)
potential.firstsegy = floor(mod->mins[1] / potential.sectionsize) + CHUNKBIAS;
potential.maxsegx = ceil(mod->maxs[0] / potential.sectionsize) + CHUNKBIAS;
potential.maxsegy = ceil(mod->maxs[1] / potential.sectionsize) + CHUNKBIAS;
//bound it, such that 0 0 will always be loaded.
potential.firstsegx = bound(0, potential.firstsegx, CHUNKBIAS);
potential.firstsegy = bound(0, potential.firstsegy, CHUNKBIAS);
potential.maxsegx = bound(CHUNKBIAS+1, potential.maxsegx, CHUNKLIMIT);
potential.maxsegy = bound(CHUNKBIAS+1, potential.maxsegy, CHUNKLIMIT);
if (*loadname=='*')
{
potential.firstsegx = bound(0, potential.firstsegx, CHUNKLIMIT);
potential.firstsegy = bound(0, potential.firstsegy, CHUNKLIMIT);
potential.maxsegx = bound(potential.firstsegx, potential.maxsegx, CHUNKLIMIT);
potential.maxsegy = bound(potential.firstsegx, potential.maxsegy, CHUNKLIMIT);
}
else
{//bound it, such that 0 0 will always be loaded.
potential.firstsegx = bound(0, potential.firstsegx, CHUNKBIAS);
potential.firstsegy = bound(0, potential.firstsegy, CHUNKBIAS);
potential.maxsegx = bound(CHUNKBIAS+1, potential.maxsegx, CHUNKLIMIT);
potential.maxsegy = bound(CHUNKBIAS+1, potential.maxsegy, CHUNKLIMIT);
}
if (!force)
{
@ -4942,5 +5504,6 @@ void Terr_Init(void)
#endif
Mod_RegisterModelFormatText(NULL, "FTE Heightmap Map (hmp)", "terrain", Terr_LoadTerrainModel);
Mod_RegisterModelFormatText(NULL, "Quake Map Format (map)", "{", Terr_LoadTerrainModel);
}
#endif

View File

@ -1427,7 +1427,9 @@ static void Mod_LoadMiptex(model_t *loadmodel, char *loadname, texture_t *tx, mi
{//external textures have already been filtered.
if (maps & LMT_DIFFUSE)
{
base = W_ConvertWAD3Texture(mt, &mt->width, &mt->height, &alphaed); //convert texture to 32 bit.
//size is not directly known.
//we might be able to infer based upon neighbours, but that seems like too much hassle
base = W_ConvertWAD3Texture(mt, 0xffffffff, &mt->width, &mt->height, &alphaed); //convert texture to 32 bit.
tx->alphaed = alphaed;
tx->texnums.base = R_LoadReplacementTexture(mt->name, loadname, alphaed?0:IF_NOALPHA, base, tx->width, tx->height, alphaed?TF_RGBA32:TF_RGBX32);
BZ_Free(base);
@ -4507,12 +4509,6 @@ qboolean QDECL Mod_LoadBrushModel (model_t *mod, void *buffer, size_t fsize)
Mod_FindVisPatch(&vispatch, mod, header->lumps[LUMP_LEAFS].filelen);
TRACE(("Loading info\n"));
#ifndef SERVERONLY
if (!isnotmap)
Mod_ParseInfoFromEntityLump(mod, mod_base + header->lumps[LUMP_ENTITIES].fileofs, loadname);
#endif
// load into heap
if (!isDedicated || ode)
{

View File

@ -1229,19 +1229,23 @@ qboolean R_GameRectIsFullscreen(void)
}
int gldepthfunc = GL_LEQUAL;
void R_Clear (void)
qboolean depthcleared;
void R_Clear (qboolean fbo)
{
/*tbh, this entire function should be in the backend*/
GL_ForceDepthWritable();
{
qglColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
if (r_clear.ival && R_GameRectIsFullscreen() && !(r_refdef.flags & RDF_NOWORLDMODEL))
if (!depthcleared || fbo)
{
qglClearColor(1, 0, 0, 0);
qglClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
}
else
GL_ForceDepthWritable();
//we no longer clear colour here. we only ever (need to) do that at the start of the frame, and this point can be called multiple times per frame.
//for performance, we clear the depth at the same time we clear colour, so we can skip clearing depth here the first time around each frame.
//but for multiple scenes, we do need to clear depth still.
//fbos always get cleared depth, just in case (colour fbos may contain junk, but hey).
qglClear (GL_DEPTH_BUFFER_BIT);
}
if (!fbo)
depthcleared = false;
gldepthmin = 0;
gldepthmax = 1;
gldepthfunc=GL_LEQUAL;
@ -1495,7 +1499,7 @@ qboolean R_RenderScene_Cubemap(void)
r_refdef.viewangles[1] = saveang[1]+ang[i][1];
r_refdef.viewangles[2] = saveang[2]+ang[i][2];
R_Clear ();
R_Clear (false);
GL_SetShaderState2D(false);
@ -1734,7 +1738,7 @@ void GLR_RenderView (void)
{
GL_SetShaderState2D(false);
R_Clear ();
R_Clear (dofbo);
// GLR_SetupFog ();

View File

@ -44,6 +44,7 @@ extern int scr_chatmode;
extern cvar_t scr_chatmodecvar;
extern cvar_t vid_conautoscale;
extern qboolean scr_con_forcedraw;
extern qboolean depthcleared;
/*
==================
@ -152,6 +153,26 @@ void GLSCR_UpdateScreen (void)
noworld = false;
nohud = false;
if (r_clear.ival)
{
int i = r_clear.ival&7;
vec3_t cleartab[] =
{
{0,0,0}, //black
{1,0,0}, //red
{0,1,0}, //green
{1,1,0}, //
{0,0,1}, //blue
{1,0,1}, //
{0,1,1}, //
{1,1,1} //white
};
GL_ForceDepthWritable();
qglClearColor((r_clear.ival&1)?1:0, (r_clear.ival&2)?1:0, (r_clear.ival&4)?1:0, 1);
qglClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
depthcleared = true;
}
#ifdef VM_CG
if (CG_Refresh())
nohud = true;

View File

@ -1311,7 +1311,7 @@ qboolean VID_AttachGL (rendererstate_t *info)
}
if (developer.ival)
Con_SafePrintf("WGL extensions: %s\n", wgl_extensions?"NONE":wgl_extensions);
Con_SafePrintf("WGL_EXTENSIONS: %s\n", wgl_extensions?wgl_extensions:"NONE");
qwglCreateContextAttribsARB = getglfunc("wglCreateContextAttribsARB");
#if 1//def _DEBUG
@ -2357,6 +2357,7 @@ VID_Init
*/
qboolean GLVID_Init (rendererstate_t *info, unsigned char *palette)
{
extern int isPlugin;
// qbyte *ptmp;
DEVMODE devmode;
WNDCLASS wc;
@ -2404,6 +2405,12 @@ qboolean GLVID_Init (rendererstate_t *info, unsigned char *palette)
Cmd_AddCommand("vid_recenter", GLVID_Recenter_f);
if (isPlugin >= 2)
{
fprintf(stdout, "refocuswindow %#p\n", mainwindow);
fflush(stdout);
}
vid_initialized = true;
vid_initializing = false;

View File

@ -64,7 +64,7 @@ iwboolean IWebAllowUpLoad(char *fname, char *uname);
vfsfile_t *IWebGenerateFile(char *name, char *content, int contentlength);
char *COM_ParseOut (const char *data, char *out, int outlen);
//char *COM_ParseOut (const char *data, char *out, int outlen);
//struct searchpath_s;
//void COM_EnumerateFiles (const char *match, int (*func)(const char *, int, void *, struct searchpath_s *), void *parm);

View File

@ -1036,7 +1036,7 @@ void PR_FreeTemps (progfuncs_t *progfuncs, int depth)
prinst.numtempstrings = depth;
}
pbool PDECL PR_DumpProfiles (pubprogfuncs_t *ppf)
pbool PDECL PR_DumpProfiles (pubprogfuncs_t *ppf, pbool resetprofiles)
{
progfuncs_t *progfuncs = (progfuncs_t*)ppf;
struct progstate_s *ps;
@ -1051,9 +1051,8 @@ pbool PDECL PR_DumpProfiles (pubprogfuncs_t *ppf)
} *sorted, t;
if (!prinst.profiling)
{
printf("Enabling profiling\n");
prinst.profiling = true;
return true;
return false;
}
cpufrequency = Sys_GetClockRate();
@ -1075,8 +1074,12 @@ pbool PDECL PR_DumpProfiles (pubprogfuncs_t *ppf)
sorted[s].profile = ps->functions[f].profile;
sorted[s].profiletime = ps->functions[f].profiletime - ps->functions[f].profilechildtime;
sorted[s].totaltime = ps->functions[f].profiletime;
ps->functions[f].profile = 0;
ps->functions[f].profiletime = 0;
if (resetprofiles)
{
ps->functions[f].profile = 0;
ps->functions[f].profiletime = 0;
ps->functions[f].profilechildtime = 0;
}
s++;
}
@ -1093,9 +1096,9 @@ pbool PDECL PR_DumpProfiles (pubprogfuncs_t *ppf)
}
//print it out
printf("%5s %5s %5s: %s\n", "ops", "self-time", "total-time", "function");
printf("%8s %9s %10s: %s\n", "ops", "self-time", "total-time", "function");
for (f = 0; f < s; f++)
printf("%5u %5g %5g: %s\n", sorted[f].profile, (float)(((double)sorted[f].profiletime) / cpufrequency), (float)(((double)sorted[f].totaltime) / cpufrequency), sorted[f].fname);
printf("%8u %9f %10f: %s\n", sorted[f].profile, (float)(((double)sorted[f].profiletime) / cpufrequency), (float)(((double)sorted[f].totaltime) / cpufrequency), sorted[f].fname);
free(sorted);
}
return true;

View File

@ -171,7 +171,7 @@ struct pubprogfuncs_s
char *(PDECL *UglyValueString) (pubprogfuncs_t *progfuncs, etype_t type, union eval_s *val);
pbool (PDECL *ParseEval) (pubprogfuncs_t *progfuncs, union eval_s *eval, int type, const char *s);
void (PDECL *SetStringField) (pubprogfuncs_t *progfuncs, struct edict_s *ed, string_t *fld, const char *str, pbool str_is_static); //if ed is null, fld points to a global. if str_is_static, then s doesn't need its own memory allocated.
pbool (PDECL *DumpProfile) (pubprogfuncs_t *progfuncs);
pbool (PDECL *DumpProfile) (pubprogfuncs_t *progfuncs, pbool resetprofiles);
};
typedef struct progexterns_s {

View File

@ -70,6 +70,8 @@ void GUI_RevealOptions(void);
#define SCI_CALLTIPCANCEL 2201
#define SCI_SETMARGINSENSITIVEN 2246
#define SCI_SETMOUSEDWELLTIME 2264
#define SCI_SEARCHANCHOR 2366
#define SCI_SEARCHNEXT 2367
#define SCI_BRACEHIGHLIGHTINDICATOR 2498
#define SCI_BRACEBADLIGHTINDICATOR 2499
#define SCI_LINELENGTH 2350
@ -173,11 +175,14 @@ typedef struct
int pipeclosed;
DWORD tid;
HWND window;
HWND refocuswindow;
HANDLE thread;
HANDLE pipefromengine;
HANDLE pipetoengine;
int embedtype; //0 = not. 1 = separate. 2 = mdi child
} enginewindow_t;
static pbool EngineCommandf(char *message, ...);
static void EngineGiveFocus(void);
static pbool QCC_RegGetStringValue(HKEY base, char *keyname, char *valuename, void *data, int datalen)
{
@ -526,6 +531,20 @@ void GUI_DialogPrint(char *title, char *text)
MessageBox(mainwindow, text, title, 0);
}
static void FindNextScintilla(editor_t *editor, char *findtext)
{
int pos = SendMessage(editor->editpane, SCI_GETCURRENTPOS, 0, 0);
Edit_SetSel(editor->editpane, pos+1, pos+1);
SendMessage(editor->editpane, SCI_SEARCHANCHOR, 0, 0);
if (SendMessage(editor->editpane, SCI_SEARCHNEXT, 0, (LPARAM)findtext) != -1)
Edit_ScrollCaret(editor->editpane); //make sure its focused
else
{
Edit_SetSel(editor->editpane, pos, pos); //revert the selection change as nothing was found
MessageBox(editor->editpane, "No more occurences found", "FTE Editor", 0);
}
}
//available in xp+
typedef LRESULT (CALLBACK *SUBCLASSPROC)(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData);
BOOL (WINAPI * pSetWindowSubclass)(HWND hWnd, SUBCLASSPROC pfnSubclass, UINT_PTR uIdSubclass, DWORD_PTR dwRefData);
@ -536,11 +555,28 @@ LRESULT CALLBACK MySubclassWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM l
{
if (wParam == VK_F3)
{
SetFocus(search_name);
char buffer[128];
GetWindowText(search_name, buffer, sizeof(buffer));
if (*buffer == 0)
SetFocus(search_name);
else
{
editor_t *editor;
for (editor = editors; editor; editor = editor->next)
{
if (editor->editpane == hWnd)
break;
}
if (editor->scintilla)
{
FindNextScintilla(editor, buffer);
}
}
return 0;
}
if (wParam == VK_F5)
{
EngineGiveFocus();
if (!EngineCommandf("qcresume\n"))
RunEngine();
return 0;
@ -864,6 +900,9 @@ void EditorMenu(editor_t *editor, WPARAM wParam)
case IDM_SAVE:
EditorSave(editor);
break;
case IDM_FIND:
SetFocus(search_name);
break;
case IDM_GREP:
{
char buffer[1024];
@ -1064,6 +1103,15 @@ char *GetTooltipText(editor_t *editor, int pos, pbool dwell)
funcname = ""; //FIXME
if (dwell)
{
tooltip_editor = NULL;
*tooltip_variable = 0;
tooltip_position = 0;
*tooltip_type = 0;
*tooltip_comment = 0;
}
def = QCC_PR_GetDef(NULL, defname, NULL, false, 0, GDF_SILENT);
if (def)
{
@ -1083,18 +1131,19 @@ char *GetTooltipText(editor_t *editor, int pos, pbool dwell)
text = buffer;
}
else
text = NULL;
if (dwell)
{
tooltip_editor = editor;
strncpy(tooltip_variable, term, sizeof(tooltip_variable)-1);
tooltip_position = pos;
*tooltip_type = 0;
*tooltip_comment = 0;
tooltip_editor = editor;
EngineCommandf("qcinspect \"%s\" \"%s\"\n", term, funcname);
SendMessage(editor->editpane, SCI_CALLTIPSHOW, (WPARAM)pos, (LPARAM)text);
if (text)
SendMessage(editor->editpane, SCI_CALLTIPSHOW, (WPARAM)pos, (LPARAM)text);
}
return text;
@ -1765,6 +1814,7 @@ void EditorReload(editor_t *editor)
editor->modified = false;
}
//line is 0-based. use -1 for no reselection
void EditFile(char *name, int line)
{
char title[1024];
@ -1778,7 +1828,7 @@ void EditFile(char *name, int line)
{
if (line >= 0)
{
Edit_SetSel(neweditor->editpane, Edit_LineIndex(neweditor->editpane, line), Edit_LineIndex(neweditor->editpane, line+1));
Edit_SetSel(neweditor->editpane, Edit_LineIndex(neweditor->editpane, line), Edit_LineIndex(neweditor->editpane, line+1)-1);
Edit_ScrollCaret(neweditor->editpane);
}
if (mdibox)
@ -2168,6 +2218,28 @@ skipwhite:
return (char*)data;
}
static void EngineGiveFocus(void)
{
HWND game;
if (gamewindow)
{
enginewindow_t *ctx = (enginewindow_t*)(LONG_PTR)GetWindowLongPtr(gamewindow, GWLP_USERDATA);
if (ctx)
{
if (ctx->refocuswindow)
{
SetForegroundWindow(ctx->refocuswindow);
return;
}
}
SetFocus(gamewindow);
game = GetWindow(gamewindow, GW_CHILD);
if (game)
SetForegroundWindow(game); //make sure the game itself has focus
}
}
static pbool EngineCommandWnd(HWND wnd, char *message)
{
//qcresume - resume running
@ -2214,14 +2286,13 @@ static pbool EngineCommandWndf(HWND wnd, char *message, ...)
unsigned int WINAPI threadwrapper(void *args)
{
static char filenamebuffer[256];
enginewindow_t *ctx = args;
{
PROCESS_INFORMATION childinfo;
STARTUPINFO startinfo;
SECURITY_ATTRIBUTES pipesec = {sizeof(pipesec), NULL, TRUE};
char cmdline[8192];
_snprintf(cmdline, sizeof(cmdline), "\"%s\" %s -plugin qcdebug", enginebinary, enginecommandline);
_snprintf(cmdline, sizeof(cmdline), "\"%s\" %s -qcdebug", enginebinary, enginecommandline);
memset(&startinfo, 0, sizeof(startinfo));
startinfo.cb = sizeof(startinfo);
@ -2237,7 +2308,24 @@ unsigned int WINAPI threadwrapper(void *args)
SetHandleInformation(ctx->pipefromengine, HANDLE_FLAG_INHERIT, 0);
SetHandleInformation(ctx->pipetoengine, HANDLE_FLAG_INHERIT, 0);
// EngineCommand(ctx, "vid_recenter %i %i %i %i %#p\n", 0, 0, 640, 480, (void*)ctx->window);
//let the engine know who to give focus to
{
char message[256];
DWORD written;
_snprintf(message, sizeof(message)-1, "debuggerwnd %#p\n", (void*)mainwindow);
WriteFile(ctx->pipetoengine, message, strlen(message), &written, NULL);
}
//let the engine know which window to embed itself in
if (ctx->embedtype)
{
char message[256];
DWORD written;
RECT rect;
GetClientRect(ctx->window, &rect);
_snprintf(message, sizeof(message)-1, "vid_recenter %i %i %i %i %#p\n", 0, 0, rect.right - rect.left, rect.bottom-rect.top, (void*)ctx->window);
WriteFile(ctx->pipetoengine, message, strlen(message), &written, NULL);
}
CreateProcess(NULL, cmdline, NULL, NULL, TRUE, 0, NULL, enginebasedir, &startinfo, &childinfo);
@ -2291,15 +2379,22 @@ unsigned int WINAPI threadwrapper(void *args)
//stack "$func" "$loc"
//local $depth
}
else if (!strncmp(buffer, "qcstep ", 7))
else if (!strncmp(buffer, "qcstep ", 7) || !strncmp(buffer, "qcfault ", 8))
{
//post it, because of thread ownership issues.
static char filenamebuffer[256];
char line[16];
char error[256];
char *l = COM_ParseOut(buffer+7, filenamebuffer, sizeof(filenamebuffer));
while (*l == ' ')
l++;
if (*l == ':')
l++;
while(*l == ' ')
l++;
PostMessage(ctx->window, WM_USER, atoi(l), (LPARAM)filenamebuffer); //and tell the owning window to try to close it again
l = COM_ParseOut(l, line, sizeof(line));
l = COM_ParseOut(l, error, sizeof(error));
PostMessage(ctx->window, WM_USER, atoi(line), (LPARAM)filenamebuffer); //and tell the owning window to try to close it again
if (*error)
PostMessage(ctx->window, WM_USER+3, 0, (LPARAM)strdup(error)); //and tell the owning window to try to close it again
}
else if (!strncmp(buffer, "qcvalue ", 8))
{
@ -2311,8 +2406,23 @@ unsigned int WINAPI threadwrapper(void *args)
{
//so we can resend any breakpoint commands
//qcreloaded "$vmname" "$progsname"
char caption[256];
HWND gw = GetWindow(ctx->window, GW_CHILD);
if (gw)
{
GetWindowText(gw, caption, sizeof(caption));
SetWindowText(ctx->window, caption);
}
PostMessage(ctx->window, WM_USER+1, 0, 0); //and tell the owning window to try to close it again
}
else if (!strncmp(buffer, "refocuswindow", 13) && (buffer[13] == ' ' || !buffer[13]))
{
char *l = buffer+13;
while(*l == ' ')
l++;
ctx->refocuswindow = (HWND)strtoul(l, &l, 0);
ShowWindow(ctx->window, SW_HIDE);
}
else
{
//handle anything else we need to handle here
@ -2349,11 +2459,12 @@ static LRESULT CALLBACK EngineWndProc(HWND hWnd,UINT message,
memset(ctx, 0, sizeof(*ctx));
SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR)ctx);
ctx->window = hWnd;
ctx->embedtype = (int)((CREATESTRUCT*)lParam)->lpCreateParams;
ctx->thread = (HANDLE)CreateThread(NULL, 0, threadwrapper, ctx, 0, &ctx->tid);
break;
case WM_SIZE:
ctx = (enginewindow_t*)(LONG_PTR)GetWindowLongPtr(gamewindow, GWLP_USERDATA);
if (ctx)
if (ctx && ctx->embedtype)
{
RECT r;
GetClientRect(hWnd, &r);
@ -2383,6 +2494,7 @@ static LRESULT CALLBACK EngineWndProc(HWND hWnd,UINT message,
break;
case WM_USER:
//engine broke. show code.
SetForegroundWindow(mainwindow);
EditFile((char*)lParam, wParam-1);
break;
case WM_USER+1:
@ -2404,6 +2516,7 @@ static LRESULT CALLBACK EngineWndProc(HWND hWnd,UINT message,
}
}
//and now let the engine continue
SetFocus(hWnd);
EngineCommandWnd(hWnd, "qcresume\n");
break;
case WM_USER+2:
@ -2426,6 +2539,13 @@ static LRESULT CALLBACK EngineWndProc(HWND hWnd,UINT message,
free((char*)lParam);
}
break;
case WM_USER+3:
{
char *msg = (char*)lParam;
MessageBox(mainwindow, msg, "QC Fault", 0);
free(msg);
}
break;
default:
gdefault:
@ -2435,6 +2555,7 @@ static LRESULT CALLBACK EngineWndProc(HWND hWnd,UINT message,
}
void RunEngine(void)
{
int embedtype = 0; //0 has focus issues.
if (!gamewindow)
{
WNDCLASS wndclass;
@ -2453,19 +2574,27 @@ void RunEngine(void)
wndclass.lpszClassName = ENGINE_WINDOW_CLASS_NAME;
RegisterClass(&wndclass);
memset(&mcs, 0, sizeof(mcs));
mcs.szClass = ENGINE_WINDOW_CLASS_NAME;
mcs.szTitle = "Debug";
mcs.hOwner = ghInstance;
mcs.x = CW_USEDEFAULT;
mcs.y = CW_USEDEFAULT;
mcs.cx = 640;
mcs.cy = 480;
mcs.style = WS_OVERLAPPEDWINDOW;
mcs.lParam = 0;
if (embedtype != 2)
{
gamewindow = CreateWindowA(ENGINE_WINDOW_CLASS_NAME, "Debug", WS_OVERLAPPEDWINDOW, 0, 0, 640, 480, NULL, NULL, ghInstance, (void*)embedtype);
if (embedtype)
ShowWindow(gamewindow, SW_SHOW);
}
else
{
memset(&mcs, 0, sizeof(mcs));
mcs.szClass = ENGINE_WINDOW_CLASS_NAME;
mcs.szTitle = "Debug";
mcs.hOwner = ghInstance;
mcs.x = CW_USEDEFAULT;
mcs.y = CW_USEDEFAULT;
mcs.cx = 640;
mcs.cy = 480;
mcs.style = WS_OVERLAPPEDWINDOW;
mcs.lParam = embedtype;
gamewindow = (HWND) SendMessage (mdibox, WM_MDICREATE, 0, (LONG_PTR) (LPMDICREATESTRUCT) &mcs);
// ShowWindow(gamewindow, SW_SHOW);
gamewindow = (HWND) SendMessage (mdibox, WM_MDICREATE, 0, (LONG_PTR) (LPMDICREATESTRUCT) &mcs);
}
}
else
{
@ -3010,7 +3139,44 @@ void OptionsDialog(void)
#undef printf
WNDPROC combosubclassproc;
static LRESULT CALLBACK SearchComboSubClass(HWND hWnd,UINT message,
WPARAM wParam,LPARAM lParam)
{
switch (message)
{
case WM_KEYDOWN:
switch (wParam)
{
case VK_RETURN:
PostMessage(mainwindow, WM_COMMAND, 0x4404, (LPARAM)search_gotodef);
return true;
case VK_F3:
{
char buffer[128];
GetWindowText(search_name, buffer, sizeof(buffer));
if (*buffer != 0)
{
HWND ew = (HWND)SendMessage(mdibox, WM_MDIGETACTIVE, 0, 0);
editor_t *editor;
for (editor = editors; editor; editor = editor->next)
{
if (editor->window == ew)
break;
}
if (editor && editor->scintilla)
{
FindNextScintilla(editor, buffer);
SetFocus(editor->window);
SetFocus(editor->editpane);
}
}
}
}
break;
}
return CallWindowProc(combosubclassproc, hWnd, message, wParam, lParam);
}
static LRESULT CALLBACK MainWndProc(HWND hWnd,UINT message,
WPARAM wParam,LPARAM lParam)
@ -3031,11 +3197,11 @@ static LRESULT CALLBACK MainWndProc(HWND hWnd,UINT message,
AppendMenu(rootmenu, MF_POPUP, (UINT_PTR)(m = CreateMenu()), "&File");
AppendMenu(m, 0, IDM_OPENNEW, "Open new file ");
AppendMenu(m, 0, IDM_SAVE, "&Save Ctrl+S ");
AppendMenu(m, 0, IDM_RECOMPILE, "&Recompile Ctrl+R ");
AppendMenu(m, 0, IDM_SAVE, "&Save Ctrl+S ");
AppendMenu(m, 0, IDM_RECOMPILE, "&Recompile Ctrl+R ");
// AppendMenu(m, 0, IDM_FIND, "&Find");
AppendMenu(m, 0, IDM_UNDO, "Undo Ctrl+Z");
AppendMenu(m, 0, IDM_REDO, "Redo Ctrl+Y");
AppendMenu(m, 0, IDM_UNDO, "Undo Ctrl+Z");
AppendMenu(m, 0, IDM_REDO, "Redo Ctrl+Y");
AppendMenu(rootmenu, MF_POPUP, (UINT_PTR)(m = CreateMenu()), "&Navigation");
AppendMenu(m, 0, IDM_GOTODEF, "Go to definition");
AppendMenu(m, 0, IDM_OPENDOCU, "Open selected file");
@ -3070,17 +3236,23 @@ static LRESULT CALLBACK MainWndProc(HWND hWnd,UINT message,
if (projecttree)
{
search_name = CreateWindowEx(WS_EX_CLIENTEDGE, "EDIT", (LPCTSTR) NULL,
WS_CHILD | WS_CLIPCHILDREN,
0, 0, 320, 200, hWnd, (HMENU) 0xCAC, ghInstance, (LPSTR) NULL);
search_name = CreateWindowEx(WS_EX_CLIENTEDGE, "COMBOBOX", (LPCTSTR) NULL,
WS_CHILD | WS_CLIPCHILDREN|CBS_DROPDOWN|CBS_SORT,
0, 0, 320, 200, hWnd, (HMENU) 0x4403, ghInstance, (LPSTR) NULL);
{
//microsoft suck big hairy donkey balls.
//this tries to get the edit box of the combo control.
HWND comboedit = GetWindow(search_name, GW_CHILD);
combosubclassproc = (WNDPROC) SetWindowLongPtr(comboedit, GWL_WNDPROC, (DWORD_PTR) SearchComboSubClass);
}
ShowWindow(search_name, SW_SHOW);
search_gotodef = CreateWindowEx(WS_EX_CLIENTEDGE, "BUTTON", "Def",
WS_CHILD | WS_CLIPCHILDREN | BS_DEFPUSHBUTTON,
WS_CHILD | WS_CLIPCHILDREN/* | BS_DEFPUSHBUTTON*/,
0, 0, 320, 200, hWnd, (HMENU) 0x4404, ghInstance, (LPSTR) NULL);
ShowWindow(search_gotodef, SW_SHOW);
search_grep = CreateWindowEx(WS_EX_CLIENTEDGE, "BUTTON", "Grep",
WS_CHILD | WS_CLIPCHILDREN | BS_DEFPUSHBUTTON,
WS_CHILD | WS_CLIPCHILDREN/* | BS_DEFPUSHBUTTON*/,
0, 0, 320, 200, hWnd, (HMENU) 0x4405, ghInstance, (LPSTR) NULL);
ShowWindow(search_grep, SW_SHOW);
}
@ -3120,23 +3292,52 @@ static LRESULT CALLBACK MainWndProc(HWND hWnd,UINT message,
return TRUE;
break;
case WM_COMMAND:
if (wParam == 0x4404)
i = LOWORD(wParam);
if (i == 0x4403)
{
char buffer[65536];
char text[128];
switch(HIWORD(wParam))
{
case CBN_EDITUPDATE:
GetWindowText(search_name, text, sizeof(text)-1);
if (GenAutoCompleteList(text, buffer, sizeof(buffer)))
{
char token[128];
char *list;
DWORD start=0,end=0;
SendMessage(search_name, CB_GETEDITSEL, (WPARAM)&start, (LPARAM)&end);
ComboBox_ResetContent(search_name); //windows is shit. this clears the text too.
SetWindowText(search_name, text);
ComboBox_SetEditSel(search_name, start, end);
for (list = buffer; ; )
{
list = COM_ParseOut(list, token, sizeof(token));
if (!*token)
break;
ComboBox_AddString(search_name, token);
}
}
return true;
}
goto gdefault;
}
if (i == 0x4404)
{
GetWindowText(search_name, finddef, sizeof(finddef)-1);
return true;
}
if (wParam == 0x4405)
if (i == 0x4405)
{
GetWindowText(search_name, greptext, sizeof(greptext)-1);
return true;
}
if (LOWORD(wParam)>0 && LOWORD(wParam) <= NUMBUTTONS)
if (i>0 && i <= NUMBUTTONS)
{
if (LOWORD(wParam))
buttons[LOWORD(wParam)-1].washit = 1;
buttons[i-1].washit = 1;
break;
}
if (LOWORD(wParam) < IDM_FIRSTCHILD)
if (i < IDM_FIRSTCHILD)
{
HWND ew;
editor_t *editor;
@ -3474,6 +3675,7 @@ void RunCompiler(char *args)
if (CompileParams(&funcs, true, argc, argv))
{
EngineGiveFocus();
EngineCommandf("qcresume\nmenu_restart\nrestart\n");
}
@ -3692,6 +3894,7 @@ int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLin
ACCEL acceleratorlist[] =
{
{FCONTROL|FVIRTKEY, 'S', IDM_SAVE},
{FCONTROL|FVIRTKEY, 'F', IDM_FIND},
{FCONTROL|FVIRTKEY, 'R', IDM_RECOMPILE}
};
ghInstance= hInstance;

View File

@ -87,12 +87,14 @@ void GoToDefinition(char *name)
if (def)
{
//with functions, the def is the prototype.
//we want the body, so zoom to the first statement of the function instead
if (def->type->type == ev_function && def->constant)
{
fnc = &functions[((int *)qcc_pr_globals)[def->ofs]];
if (fnc->first_statement>=0 && fnc->s_file)
{
EditFile(fnc->s_file+strings, statements[fnc->first_statement].linenum);
EditFile(fnc->s_file+strings, statements[fnc->first_statement].linenum-1);
return;
}
}

View File

@ -1093,84 +1093,89 @@ strofs = (strofs+3)&~3;
{
case PST_KKQWSV:
case PST_FTE32:
#define statements32 ((QCC_dstatement32_t*) statements)
for (i=0 ; i<numstatements ; i++)
{
statements32[i].op = PRLittleLong/*PRLittleShort*/(statements[i].op);
statements32[i].a = PRLittleLong/*PRLittleShort*/(statements[i].a);
statements32[i].b = PRLittleLong/*PRLittleShort*/(statements[i].b);
statements32[i].c = PRLittleLong/*PRLittleShort*/(statements[i].c);
}
QCC_dstatement32_t *statements32 = qccHunkAlloc(sizeof(*statements32) * numstatements);
for (i=0 ; i<numstatements ; i++)
{
statements32[i].op = PRLittleLong/*PRLittleShort*/(statements[i].op);
statements32[i].a = PRLittleLong/*PRLittleShort*/(statements[i].a);
statements32[i].b = PRLittleLong/*PRLittleShort*/(statements[i].b);
statements32[i].c = PRLittleLong/*PRLittleShort*/(statements[i].c);
}
if (progs.blockscompressed&1)
{
SafeWrite (h, &len, sizeof(int)); //save for later
len = QC_encode(progfuncs, numstatements*sizeof(QCC_dstatement32_t), 2, (char *)statements, h); //write
i = SafeSeek (h, 0, SEEK_CUR);
SafeSeek(h, progs.ofs_statements, SEEK_SET);//seek back
len = PRLittleLong(len);
SafeWrite (h, &len, sizeof(int)); //write size.
SafeSeek(h, i, SEEK_SET);
if (progs.blockscompressed&1)
{
SafeWrite (h, &len, sizeof(int)); //save for later
len = QC_encode(progfuncs, numstatements*sizeof(QCC_dstatement32_t), 2, (char *)statements, h); //write
i = SafeSeek (h, 0, SEEK_CUR);
SafeSeek(h, progs.ofs_statements, SEEK_SET);//seek back
len = PRLittleLong(len);
SafeWrite (h, &len, sizeof(int)); //write size.
SafeSeek(h, i, SEEK_SET);
}
else
SafeWrite (h, statements32, numstatements*sizeof(QCC_dstatement32_t));
}
else
SafeWrite (h, statements32, numstatements*sizeof(QCC_dstatement32_t));
break;
case PST_QTEST:
#define qtst ((qtest_statement_t*) statements)
for (i=0 ; i<numstatements ; i++) // scale down from 16-byte internal to 12-byte qtest
{
QCC_statement_t stmt = statements[i];
qtst[i].line = 0; // no line support
qtst[i].op = PRLittleShort((unsigned short)stmt.op);
if (stmt.a < 0)
qtst[i].a = PRLittleShort((short)stmt.a);
else
qtst[i].a = (unsigned short)PRLittleShort((unsigned short)stmt.a);
if (stmt.b < 0)
qtst[i].b = PRLittleShort((short)stmt.b);
else
qtst[i].b = (unsigned short)PRLittleShort((unsigned short)stmt.b);
if (stmt.c < 0)
qtst[i].c = PRLittleShort((short)stmt.c);
else
qtst[i].c = (unsigned short)PRLittleShort((unsigned short)stmt.c);
}
qtest_statement_t *qtst = qccHunkAlloc(sizeof(*qtst) * numstatements);
for (i=0 ; i<numstatements ; i++) // scale down from 16-byte internal to 12-byte qtest
{
QCC_statement_t stmt = statements[i];
qtst[i].line = 0; // no line support
qtst[i].op = PRLittleShort((unsigned short)stmt.op);
if (stmt.a < 0)
qtst[i].a = PRLittleShort((short)stmt.a);
else
qtst[i].a = (unsigned short)PRLittleShort((unsigned short)stmt.a);
if (stmt.b < 0)
qtst[i].b = PRLittleShort((short)stmt.b);
else
qtst[i].b = (unsigned short)PRLittleShort((unsigned short)stmt.b);
if (stmt.c < 0)
qtst[i].c = PRLittleShort((short)stmt.c);
else
qtst[i].c = (unsigned short)PRLittleShort((unsigned short)stmt.c);
}
// no compression
SafeWrite (h, qtst, numstatements*sizeof(qtest_statement_t));
#undef qtst
// no compression
SafeWrite (h, qtst, numstatements*sizeof(qtest_statement_t));
}
break;
case PST_DEFAULT:
#define statements16 ((QCC_dstatement16_t*) statements)
for (i=0 ; i<numstatements ; i++) //resize as we go - scaling down
{
statements16[i].op = PRLittleShort((unsigned short)statements[i].op);
if (statements[i].a < 0)
statements16[i].a = PRLittleShort((short)statements[i].a);
else
statements16[i].a = (unsigned short)PRLittleShort((unsigned short)statements[i].a);
if (statements[i].b < 0)
statements16[i].b = PRLittleShort((short)statements[i].b);
else
statements16[i].b = (unsigned short)PRLittleShort((unsigned short)statements[i].b);
if (statements[i].c < 0)
statements16[i].c = PRLittleShort((short)statements[i].c);
else
statements16[i].c = (unsigned short)PRLittleShort((unsigned short)statements[i].c);
}
QCC_dstatement16_t *statements16 = qccHunkAlloc(sizeof(*statements16) * numstatements);
for (i=0 ; i<numstatements ; i++) //resize as we go - scaling down
{
statements16[i].op = PRLittleShort((unsigned short)statements[i].op);
if (statements[i].a < 0)
statements16[i].a = PRLittleShort((short)statements[i].a);
else
statements16[i].a = (unsigned short)PRLittleShort((unsigned short)statements[i].a);
if (statements[i].b < 0)
statements16[i].b = PRLittleShort((short)statements[i].b);
else
statements16[i].b = (unsigned short)PRLittleShort((unsigned short)statements[i].b);
if (statements[i].c < 0)
statements16[i].c = PRLittleShort((short)statements[i].c);
else
statements16[i].c = (unsigned short)PRLittleShort((unsigned short)statements[i].c);
}
if (progs.blockscompressed&1)
{
SafeWrite (h, &len, sizeof(int)); //save for later
len = QC_encode(progfuncs, numstatements*sizeof(QCC_dstatement16_t), 2, (char *)statements16, h); //write
i = SafeSeek (h, 0, SEEK_CUR);
SafeSeek(h, progs.ofs_statements, SEEK_SET);//seek back
len = PRLittleLong(len);
SafeWrite (h, &len, sizeof(int)); //write size.
SafeSeek(h, i, SEEK_SET);
if (progs.blockscompressed&1)
{
SafeWrite (h, &len, sizeof(int)); //save for later
len = QC_encode(progfuncs, numstatements*sizeof(QCC_dstatement16_t), 2, (char *)statements16, h); //write
i = SafeSeek (h, 0, SEEK_CUR);
SafeSeek(h, progs.ofs_statements, SEEK_SET);//seek back
len = PRLittleLong(len);
SafeWrite (h, &len, sizeof(int)); //write size.
SafeSeek(h, i, SEEK_SET);
}
else
SafeWrite (h, statements16, numstatements*sizeof(QCC_dstatement16_t));
}
else
SafeWrite (h, statements16, numstatements*sizeof(QCC_dstatement16_t));
break;
default:
Sys_Error("structtype error");

View File

@ -1193,8 +1193,8 @@ void PR_WatchPoint_f(void)
static void PR_SSProfile_f(void)
{
if (svprogfuncs && svprogfuncs->DumpProfile)
if (!svprogfuncs->DumpProfile(svprogfuncs))
Con_Printf("Please set pr_enable_profiling and restart the map first\n");
if (!svprogfuncs->DumpProfile(svprogfuncs, !atof(Cmd_Argv(1))))
Con_Printf("Enabled ssqc profiling. Re-execute %s to see the results.\n", Cmd_Argv(0));
}
static void PR_SSPoke_f(void)
@ -1253,7 +1253,7 @@ void PR_Init(void)
Cmd_AddCommand ("applycompile", PR_ApplyCompilation_f);
Cmd_AddCommand ("coredump_ssqc", PR_SSCoreDump_f);
Cmd_AddCommand ("poke_ssqc", PR_SSPoke_f);
Cmd_AddCommand ("profile_ssqc", PR_SSProfile_f);
Cmd_AddCommandD ("profile_ssqc", PR_SSProfile_f, "Displays how much time has been spent in various QC functions since this command was last used.\nIf pr_enable_profiling is set, profiling will be enabled automatically, and can be used to list spawn functions.\nAdd an arg with value 1 if you wish to avoid purging timing information.");
Cmd_AddCommand ("extensionlist_ssqc", PR_SVExtensionList_f);
Cmd_AddCommand ("pr_dumpplatform", PR_DumpPlatform_f);
@ -9177,7 +9177,7 @@ BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs
#endif
//nq qw h2 ebfs
{"ignore", PF_Ignore, 0, 0, 0, 0, D("void()","Ignored by the engine. Returns 0.")},
{"makevectors", PF_makevectors, 1, 1, 1, 0, D("void(vector vang)","Takes an angle vector (pitch,yaw,roll). Writes its results into v_forward, v_right, v_up vectors.")},
{"makevectors", PF_makevectors, 1, 1, 1, 0, D("void(vector vang)","Takes an angle vector (pitch,yaw,roll) (+x=DOWN). Writes its results into v_forward, v_right, v_up vectors.")},
{"setorigin", PF_setorigin, 2, 2, 2, 0, D("void(entity e, vector o)","Changes e's origin to be equal to o. Also relinks collision state (as well as setting absmin+absmax), which is required after changing .solid")},
{"setmodel", PF_setmodel, 3, 3, 3, 0, D("void(entity e, string m)","Looks up m in the model precache list, and sets both e.model and e.modelindex to match. BSP models will set e.mins and e.maxs accordingly, other models depend upon the value of sv_gameplayfix_setmodelrealbox - for compatibility you should always call setsize after all pickups or non-bsp models. Also relinks collision state.")},
{"setsize", PF_setsize, 4, 4, 4, 0, D("void(entity e, vector min, vector max)", "Sets the e's mins and maxs fields. Also relinks collision state, which sets absmin and absmax too.")},
@ -9233,7 +9233,7 @@ BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs
{"particle", PF_particle, 48, 0, 48, 48, D("void(vector pos, vector dir, float colour, float count)", "Spawn 'count' particles around 'pos' moving in the direction 'dir', with a palette colour index between 'colour' and 'colour+8'.")}, //48 nq readded. This isn't present in QW protocol (fte added it back).
{"changeyaw", PF_changeyaw, 49, 49, 49, 0, D("#define ChangeYaw changeyaw\nvoid()", "Changes the self.angles_y field towards self.ideal_yaw by up to self.yawspeed.")},
// {"qtest_precacheitem", NULL, 50}, // defined QTest builtin that is never called
{"vectoangles", PF_vectoangles, 51, 51, 51, 0, D("vector(vector fwd, optional vector up)", "Returns the angles required to orient an entity to look in the given direction. The 'up' argument is required if you wish to set a roll angle, otherwise it will be limited to just monster-style turning.")},
{"vectoangles", PF_vectoangles, 51, 51, 51, 0, D("vector(vector fwd, optional vector up)", "Returns the angles (+x=UP) required to orient an entity to look in the given direction. The 'up' argument is required if you wish to set a roll angle, otherwise it will be limited to just monster-style turning.")},
{"WriteByte", PF_WriteByte, 52, 52, 52, 0, D("void(float to, float val)", "Writes a single byte into a network message buffer. Typically you will find a more correct alternative to writing arbitary data. 'to' should be one of the MSG_* constants. MSG_ONE must have msg_entity set first.")}, //52
{"WriteChar", PF_WriteChar, 53, 53, 53, 0, "void(float to, float val)"}, //53
@ -10330,7 +10330,7 @@ void PR_DumpPlatform_f(void)
{"parm1, parm2, parm3, parm4, parm5, parm6, parm7, parm8, parm9, parm10, parm11, parm12, parm13, parm14, parm15, parm16", "float", QW|NQ},
{"intermission", "float", CS},
{"v_forward, v_up, v_right", "vector", QW|NQ|CS},
{"view_angles", "vector", CS},
{"view_angles", "vector", CS, "+x=DOWN"},
{"trace_allsolid, trace_startsolid, trace_fraction", "float", QW|NQ|CS},
{"trace_endpos, trace_plane_normal", "vector", QW|NQ|CS},
{"trace_plane_dist", "float", QW|NQ|CS},
@ -10338,7 +10338,7 @@ void PR_DumpPlatform_f(void)
{"trace_inopen", "float", QW|NQ|CS},
{"trace_inwater", "float", QW|NQ|CS},
{"input_timelength", "float", CS},
{"input_angles", "vector", CS},
{"input_angles", "vector", CS, "+x=DOWN"},
{"input_movevalues", "vector", CS},
{"input_buttons", "float", CS},
{"input_impulse", "float", CS},
@ -10355,41 +10355,42 @@ void PR_DumpPlatform_f(void)
{"SetChangeParms", "void()", QW|NQ},
{"end_sys_globals", "void", QW|NQ|CS|MENU},
{"modelindex", ".float", QW|NQ|CS},
{"absmin", ".vector", QW|NQ|CS},
{"absmax", ".vector", QW|NQ|CS},
{"ltime", ".float", QW|NQ},
{"entnum", ".float", CS, "The entity number as its known on the server."},
{"drawmask", ".float", CS, "Acts as a filter in the addentities call."},
{"predraw", ".float()", CS, "Called by addentities after the filter and before the entity is actually drawn. Do your interpolation and animation in here. Should return one of the PREDRAW_* constants."},
{"lastruntime", ".float", QW},
{"movetype", ".float", QW|NQ|CS},
{"solid", ".float", QW|NQ|CS},
{"origin", ".vector", QW|NQ|CS},
{"oldorigin", ".vector", QW|NQ|CS},
{"velocity", ".vector", QW|NQ|CS},
{"angles", ".vector", QW|NQ|CS},
{"avelocity", ".vector", QW|NQ|CS},
{"modelindex", ".float", QW|NQ|CS, "This is the model precache index for the model that was set on the entity, instead of having to look up the model according to the .model field. Use setmodel to change it."},
{"absmin", ".vector", QW|NQ|CS, "Set by the engine when the entity is relinked (by setorigin, setsize, or setmodel). This is in world coordinates."},
{"absmax", ".vector", QW|NQ|CS, "Set by the engine when the entity is relinked (by setorigin, setsize, or setmodel). This is in world coordinates."},
{"ltime", ".float", QW|NQ, "On MOVETYPE_PUSH entities, this is used as an alternative to the 'time' global, and .nextthink is synced to this instead of time. This allows time to effectively freeze if the entity is blocked, ensuring the think happens when the entity reaches the target point instead of randomly."},
{"entnum", ".float", CS, "The entity number as its known on the server."},
{"drawmask", ".float", CS, "Acts as a filter in the addentities call."},
{"predraw", ".float()", CS, "Called by addentities after the filter and before the entity is actually drawn. Do your interpolation and animation in here. Should return one of the PREDRAW_* constants."},
{"lastruntime", ".float", QW, "This field used to be used to avoid running an entity multiple times in a single frame due to quakeworld's out-of-order thinks. It is no longer used by FTE due to precision issues, but may still be updated for compatibility reasons."},
{"movetype", ".float", QW|NQ|CS, "Describes how the entity moves. One of the MOVETYPE_ constants."},
{"solid", ".float", QW|NQ|CS, "Describes whether the entity is solid or not, and any special properties infered by that. Must be one of the SOLID_ constants"},
{"origin", ".vector", QW|NQ|CS, "The current location of the entity in world space. Inline bsp entities (ie: ones placed by a mapper) will typically have a value of '0 0 0' in their neutral pose, as the geometry is offset from that. It is the reference point of the entity rather than the center of its geometry, for non-bsp models, this is often not a significant distinction."},
{"oldorigin", ".vector", QW|NQ|CS, "This is often used on players to reset the player back to where they were last frame if they somehow got stuck inside something due to fpu precision. Never change a player's oldorigin field to inside a solid, because that might cause them to become pemanently stuck."},
{"velocity", ".vector", QW|NQ|CS, "The direction and speed that the entity is moving in world space."},
{"angles", ".vector", QW|NQ|CS, "The eular angles the entity is facing in, in pitch, yaw, roll order. Due to a legacy bug, mdl/iqm/etc formats use +x=UP, bsp/spr/etc formats use +x=DOWN."},
{"avelocity", ".vector", QW|NQ|CS, "The amount the entity's angles change by each frame. Note that this is direct eular angles, and thus the angular change is non-linear and often just looks buggy."},
{"pmove_flags", ".float", CS},
{"punchangle", ".vector", NQ},
{"classname", ".string", QW|NQ|CS},
{"classname", ".string", QW|NQ|CS, "Identifies the class/type of the entity. Useful for debugging, also used for loading, but its value is not otherwise significant to the engine, this leaves the mod free to set it to whatever it wants and randomly test strings for values in whatever inefficient way it chooses fit."},
{"renderflags", ".float", CS},
{"model", ".string", QW|NQ|CS},
{"frame", ".float", QW|NQ|CS},
{"frame1time", ".float", CS, "The absolute time into the animation/framegroup specified by .frame."},
{"frame2", ".float", CS},
{"frame2time", ".float", CS, "The absolute time into the animation/framegroup specified by .frame2."},
{"lerpfrac", ".float", CS, "If 0, use frame1 only. If 1, use frame2 only. Mix them together for values between."},
{"skin", ".float", QW|NQ|CS},
{"effects", ".float", QW|NQ|CS},
{"mins", ".vector", QW|NQ|CS},
{"maxs", ".vector", QW|NQ|CS},
{"size", ".vector", QW|NQ|CS},
{"model", ".string", QW|NQ|CS, "The model name that was set via setmodel, in theory. Often, this is cleared to null to prevent the engine from being seen by clients while not changing modelindex. This behaviour allows inline models to remain solid yet be invisible."},
{"frame", ".float", QW|NQ|CS, "The current frame the entity is meant to be displayed in. In CSQC, note the lerpfrac and frame2 fields as well. if it specifies a framegroup, the framegroup will autoanimate in ssqc, but not in csqc."},
{"frame1time", ".float", CS, "The absolute time into the animation/framegroup specified by .frame."},
{"frame2", ".float", CS, "The alternative frame. Visible only when lerpfrac is set to 1."},
{"frame2time", ".float", CS, "The absolute time into the animation/framegroup specified by .frame2."},
{"lerpfrac", ".float", CS, "If 0, use frame1 only. If 1, use frame2 only. Mix them together for values between."},
{"skin", ".float", QW|NQ|CS, "The skin index to use. on a bsp entity, setting this to 1 will switch to the 'activated' texture instead. A negative value will be understood as a replacement contents value, so setting it to CONTENTS_WATER will make a movable pool of water."},
{"effects", ".float", QW|NQ|CS, "Lots of random flags that change random effects. See EF_* constants."},
{"mins", ".vector", QW|NQ|CS, "The minimum extent of the model (ie: the bottom-left coordinate relative to the entity's origin). Change via setsize. May also be changed by setmodel."},
{"maxs", ".vector", QW|NQ|CS, "like mins, but in the other direction."},
{"size", ".vector", QW|NQ|CS, "maxs-mins. Updated when the entity is relinked (by setorigin, setsize, setmodel)"},
{"touch", ".void()", QW|NQ|CS},
{"use", ".void()", QW|NQ},
{"think", ".void()", QW|NQ|CS},
{"blocked", ".void()", QW|NQ|CS},
{"nextthink", ".float", QW|NQ|CS},
{"nextthink", ".float", QW|NQ|CS, "The time at which the entity is next scheduled to fire its think event. For MOVETYPE_PUSH entities, this is relative to that entity's ltime field, for all other entities it is relative to the time gloal."},
{"groundentity", ".entity", QW|NQ},
{"health", ".float", QW|NQ},
@ -10413,7 +10414,7 @@ void PR_DumpPlatform_f(void)
{"button2", ".float", QW|NQ},
{"impulse", ".float", QW|NQ},
{"fixangle", ".float", QW|NQ},
{"v_angle", ".vector", QW|NQ},
{"v_angle", ".vector", QW|NQ, "The angles a player is viewing. +x is DOWN (pitch, yaw, roll)"},
{"idealpitch", ".float", NQ},
{"netname", ".string", QW|NQ},
{"enemy", ".entity", QW|NQ|CS},
@ -10421,7 +10422,7 @@ void PR_DumpPlatform_f(void)
{"colormap", ".float", QW|NQ|CS},
{"team", ".float", QW|NQ},
{"max_health", ".float", QW|NQ},
{"teleport_time", ".float", QW|NQ},
{"teleport_time", ".float", QW|NQ, "While active, prevents the player from using the +back command, also blocks waterjumping."},
{"armortype", ".float", QW|NQ},
{"armorvalue", ".float", QW|NQ},
{"waterlevel", ".float", QW|NQ},
@ -10448,7 +10449,7 @@ void PR_DumpPlatform_f(void)
{"time", "float", MENU, "The current local time. Increases while paused."},
{"input_timelength", "float", QW|NQ},
{"input_angles", "vector", QW|NQ},
{"input_angles", "vector", QW|NQ, "+x=DOWN"},
{"input_movevalues", "vector", QW|NQ},
{"input_buttons", "float", QW|NQ},
{"input_impulse", "float", QW|NQ},

View File

@ -119,7 +119,7 @@ and the extension fields are added on the end and can have extra vm-specific stu
comfieldvector(origin,"The current location of the entity in world space. Inline bsp entities (ie: ones placed by a mapper) will typically have a value of '0 0 0' in their neutral pose, as the geometry is offset from that. It is the reference point of the entity rather than the center of its geometry, for non-bsp models, this is often not a significant distinction.")\
comfieldvector(oldorigin,"This is often used on players to reset the player back to where they were last frame if they somehow got stuck inside something due to fpu precision. Never change a player's oldorigin field to inside a solid, because that might cause them to become pemanently stuck.")\
comfieldvector(velocity,"The direction and speed that the entity is moving in world space.")\
comfieldvector(angles,"The eular angles the entity is facing in, in pitch, yaw, roll order. Note that non-bsp models use a negated pitch due to a widely-proliferated-and-thus-unfixable legacy bug.")\
comfieldvector(angles,"The eular angles the entity is facing in, in pitch, yaw, roll order. Due to a legacy bug, mdl/iqm/etc formats use +x=UP, bsp/spr/etc formats use +x=DOWN.")\
comfieldvector(avelocity,"The amount the entity's angles change by each frame. Note that this is direct eular angles, and thus the angular change is non-linear and often just looks buggy.")\
comfieldstring(classname,"Identifies the class/type of the entity. Useful for debugging, also used for loading, but its value is not otherwise significant to the engine, this leaves the mod free to set it to whatever it wants and randomly test strings for values in whatever inefficient way it chooses fit.")\
comfieldstring(model,"The model name that was set via setmodel, in theory. Often, this is cleared to null to prevent the engine from being seen by clients while not changing modelindex. This behaviour allows inline models to remain solid yet be invisible.")\
@ -155,7 +155,7 @@ and the extension fields are added on the end and can have extra vm-specific stu
comfieldfloat(button2,NULL)\
comfieldfloat(impulse,NULL)\
comfieldfloat(fixangle,NULL)\
comfieldvector(v_angle,NULL)\
comfieldvector(v_angle,"The angles a player is viewing. +x is DOWN (pitch, yaw, roll)")\
comfieldstring(netname,NULL)\
comfieldentity(enemy,NULL)\
comfieldfloat(flags,NULL)\
@ -414,16 +414,18 @@ typedef struct
vec3_t axis, axis2;
} odejointinfo_t;
enum odecommands_e
{
ODECMD_ENABLE,
ODECMD_DISABLE,
ODECMD_FORCE,
ODECMD_TORQUE,
};
typedef struct odecommandqueue_s
{
struct odecommandqueue_s *next;
enum
{
ODECMD_ENABLE,
ODECMD_DISABLE,
ODECMD_FORCE,
ODECMD_TORQUE,
} command;
enum odecommands_e command;
struct wedict_s *edict;
vec3_t v1;
vec3_t v2;

View File

@ -505,7 +505,7 @@ void SV_Map_f (void)
}
else
{
char *exts[] = {"maps/%s.bsp", "maps/%s.cm", "maps/%s.hmp", NULL};
char *exts[] = {"maps/%s.bsp", "maps/%s.cm", "maps/%s.hmp", "maps/%s.map", NULL};
int i, j;
for (i = 0; exts[i]; i++)

View File

@ -936,7 +936,7 @@ void SV_SpawnServer (char *server, char *startspot, qboolean noents, qboolean us
else
#endif
{
char *exts[] = {"maps/%s.bsp", "maps/%s.cm", "maps/%s.hmp", NULL};
char *exts[] = {"maps/%s.bsp", "maps/%s.cm", "maps/%s.hmp", "maps/%s.map", NULL};
int depth, bestdepth;
Q_strncpyz (sv.name, server, sizeof(sv.name));
Q_snprintfz (sv.modelname, sizeof(sv.modelname), exts[0], server);

View File

@ -4303,7 +4303,13 @@ void SV_MVDStream_Poll(void);
NET_Tick();
if (sv.framenum != 1)
{
#ifndef SERVERONLY
Sys_SendKeyEvents();
#else
SV_GetConsoleCommands ();
#endif
}
// process console commands
if (!pr_imitatemvdsv.value)

View File

@ -48,8 +48,8 @@ cvar_t sv_mapcheck = SCVAR("sv_mapcheck", "1");
cvar_t sv_fullredirect = CVARD("sv_fullredirect", "", "This is the ip:port to redirect players to when the server is full");
cvar_t sv_antilag = CVARFD("sv_antilag", "1", CVAR_SERVERINFO, "Attempt to backdate impacts to compensate for lag. 0=completely off. 1=mod-controlled. 2=forced, which might break certain uses of traceline.");
cvar_t sv_antilag_frac = CVARF("sv_antilag_frac", "1", CVAR_SERVERINFO);
cvar_t sv_cheatpc = CVAR("sv_cheatpc", "125");
cvar_t sv_cheatspeedchecktime = CVAR("sv_cheatspeedchecktime", "30");
cvar_t sv_cheatpc = CVARD("sv_cheatpc", "125", "If the client tried to claim more than this percentage of time within any speed-cheat period, the client will be deemed to have cheated.");
cvar_t sv_cheatspeedchecktime = CVARD("sv_cheatspeedchecktime", "30", "The interval between each speed-cheat check.");
cvar_t sv_playermodelchecks = CVAR("sv_playermodelchecks", "0");
cvar_t sv_ping_ignorepl = CVARD("sv_ping_ignorepl", "0", "If 1, ping times reported for players will ignore the effects of packetloss on ping times. 0 is slightly more honest, but less useful for connection diagnosis.");
cvar_t sv_protocol_nq = CVARD("sv_protocol_nq", "0", "Specifies the default protocol to use for new NQ clients. Supported values are\n0 = autodetect\n15 = vanilla\n666 = fitzquake\n999 = rmq protocol\nThe sv_bigcoords cvar forces upgrades as required.");
@ -5856,6 +5856,7 @@ SV_RunCmd
*/
void SV_RunCmd (usercmd_t *ucmd, qboolean recurse)
{
extern int isPlugin;
edict_t *ent;
int i, n;
int oldmsec;
@ -5871,21 +5872,24 @@ void SV_RunCmd (usercmd_t *ucmd, qboolean recurse)
// To prevent a infinite loop
if (!recurse)
{
//FIXME: update protocol to use server's timestamps instead of msecs over the wire, obsoleting speed cheat checks (by allowing the server to clamp sanely).
if (!host_client->last_check)
{
host_client->msecs = 0;
host_client->last_check = realtime;
host_client->last_check = realtime;
}
host_client->msecs += ucmd->msec;
if ((tmp_time = realtime - host_client->last_check) >= sv_cheatspeedchecktime.value)
{
tmp_time = tmp_time * 1000.0 * sv_cheatpc.value/100.0;
if (host_client->msecs > tmp_time)
if (host_client->msecs > tmp_time &&
isPlugin < 2) //debugging can result in WEIRD timings, so don't warn about weird timings if we're likely to get blocked out for long periods
{
host_client->msec_cheating++;
SV_BroadcastTPrintf(PRINT_HIGH,
"Speed cheat possibility, analyzing:\n %d %.1f %d for: %s\n",
"Speed cheat possibility, analyzing:\n %d>%.1f %d for: %s\n",
host_client->msecs, tmp_time,
host_client->msec_cheating, host_client->name);
@ -5896,10 +5900,10 @@ void SV_RunCmd (usercmd_t *ucmd, qboolean recurse)
host_client->name, NET_AdrToString(adr, sizeof(adr), &host_client->netchan.remote_address));
host_client->drop = true; //drop later
}
}
}
host_client->msecs = 0;
host_client->last_check = realtime;
host_client->msecs = 0;
host_client->last_check = realtime;
}
}
// end KK hack copied from QuakeForge anti-cheat