From 5fbf1b000aeab4cc583f562a35cf0dddef63aa52 Mon Sep 17 00:00:00 2001 From: havoc Date: Thu, 15 Feb 2007 00:13:49 +0000 Subject: [PATCH] cleaned up client qc, menu qc, and server qc VM initialization a bit so they have shared field/global/function lookup code, changed world.c to not be server specific, moved server-specific functions to sv_phys.c git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@6843 d7cf8633-e32d-0410-b094-e92efae38249 --- cl_main.c | 7 + client.h | 5 + clvm_cmds.c | 142 ++-------- csprogs.c | 325 ++++++++++++++--------- csprogs.h | 5 - host.c | 5 +- host_cmd.c | 43 ++- menu.c | 62 ++--- mvm_cmds.c | 2 +- netconn.c | 2 +- progs.h | 147 +---------- progsvm.h | 324 ++++++++++++----------- protocol.c | 14 +- prvm_cmds.c | 230 +++++++++------- prvm_cmds.h | 3 + prvm_edict.c | 187 +++++++++++-- prvm_exec.c | 6 +- prvm_execprogram.h | 8 +- quakedef.h | 2 +- server.h | 27 +- sv_main.c | 266 ++++--------------- sv_move.c | 8 +- sv_phys.c | 527 +++++++++++++++++++++++++++++++++++-- sv_user.c | 52 ++-- svvm_cmds.c | 163 ++---------- todo | 4 + world.c | 643 ++++++--------------------------------------- world.h | 62 +++-- 28 files changed, 1523 insertions(+), 1748 deletions(-) diff --git a/cl_main.c b/cl_main.c index 3b4949b3..05a36f55 100644 --- a/cl_main.c +++ b/cl_main.c @@ -1729,6 +1729,11 @@ static void CL_TimeRefresh_f (void) Con_Printf("%f seconds (%f fps)\n", timedelta, 128/timedelta); } +void CL_AreaStats_f(void) +{ + World_PrintAreaStats(&cl.world, "client"); +} + /* =========== CL_Shutdown @@ -1803,6 +1808,8 @@ void CL_Init (void) // LordHavoc: added pausedemo Cmd_AddCommand ("pausedemo", CL_PauseDemo_f, "pause demo playback (can also safely pause demo recording if using QUAKE, QUAKEDP or NEHAHRAMOVIE protocol, useful for making movies)"); + Cmd_AddCommand ("cl_areastats", CL_AreaStats_f, "prints statistics on entity culling during collision traces"); + Cvar_RegisterVariable(&r_draweffects); Cvar_RegisterVariable(&cl_explosions_alpha_start); Cvar_RegisterVariable(&cl_explosions_alpha_end); diff --git a/client.h b/client.h index 83dcffaa..5bba6b51 100644 --- a/client.h +++ b/client.h @@ -927,6 +927,11 @@ typedef struct client_state_s int qw_validsequence; int qw_deltasequence[QW_UPDATE_BACKUP]; + + // csqc stuff: + + // collision culling data + world_t world; } client_state_t; diff --git a/clvm_cmds.c b/clvm_cmds.c index dfa53575..5148c569 100644 --- a/clvm_cmds.c +++ b/clvm_cmds.c @@ -127,6 +127,7 @@ void CSQC_RelinkCSQCEntities (void); char *Key_GetBind (int key); model_t *CSQC_GetModelByIndex(int modelindex); model_t *CSQC_GetModelFromEntity(prvm_edict_t *ed); +void CL_LinkEdict(prvm_edict_t *ed); @@ -159,6 +160,7 @@ void VM_CL_setorigin (void) } org = PRVM_G_VECTOR(OFS_PARM1); VectorCopy (org, e->fields.client->origin); + CL_LinkEdict(e); } // #3 void(entity e, string m) setmodel @@ -222,6 +224,8 @@ void VM_CL_setsize (void) VectorCopy (min, e->fields.client->mins); VectorCopy (max, e->fields.client->maxs); VectorSubtract (max, min, e->fields.client->size); + + CL_LinkEdict(e); } // #8 void(entity e, float chan, string samp) sound @@ -568,104 +572,6 @@ void VM_CL_particle (void) CL_ParticleEffect(EFFECT_SVC_PARTICLE, count, org, org, dir, dir, NULL, color); } -// #49 void(entity ent, float ideal_yaw, float speed_yaw) ChangeYaw -void VM_CL_changeyaw (void) -{ - prvm_edict_t *ent; - float ideal, current, move, speed; - VM_SAFEPARMCOUNT(3, VM_CL_changeyaw); - - ent = PRVM_G_EDICT(OFS_PARM0); - if (ent == prog->edicts) - { - VM_Warning("changeyaw: can not modify world entity\n"); - return; - } - if (ent->priv.server->free) - { - VM_Warning("changeyaw: can not modify free entity\n"); - return; - } - current = ANGLEMOD(ent->fields.client->angles[1]); - ideal = PRVM_G_FLOAT(OFS_PARM1); - speed = PRVM_G_FLOAT(OFS_PARM2); - - if (current == ideal) - return; - move = ideal - current; - if (ideal > current) - { - if (move >= 180) - move = move - 360; - } - else - { - if (move <= -180) - move = move + 360; - } - if (move > 0) - { - if (move > speed) - move = speed; - } - else - { - if (move < -speed) - move = -speed; - } - - ent->fields.client->angles[1] = ANGLEMOD (current + move); -} - -// #63 void(entity ent, float ideal_pitch, float speed_pitch) changepitch (DP_QC_CHANGEPITCH) -void VM_CL_changepitch (void) -{ - prvm_edict_t *ent; - float ideal, current, move, speed; - VM_SAFEPARMCOUNT(3, VM_CL_changepitch); - - ent = PRVM_G_EDICT(OFS_PARM0); - if (ent == prog->edicts) - { - VM_Warning("changepitch: can not modify world entity\n"); - return; - } - if (ent->priv.server->free) - { - VM_Warning("changepitch: can not modify free entity\n"); - return; - } - current = ANGLEMOD( ent->fields.client->angles[0] ); - ideal = PRVM_G_FLOAT(OFS_PARM1); - speed = PRVM_G_FLOAT(OFS_PARM2); - - if (current == ideal) - return; - move = ideal - current; - if (ideal > current) - { - if (move >= 180) - move = move - 360; - } - else - { - if (move <= -180) - move = move + 360; - } - if (move > 0) - { - if (move > speed) - move = speed; - } - else - { - if (move < -speed) - move = -speed; - } - - ent->fields.client->angles[0] = ANGLEMOD (current + move); -} - // #64 void(entity e, entity ignore) tracetoss (DP_QC_TRACETOSS) void VM_CL_tracetoss (void) { @@ -792,7 +698,7 @@ void VM_R_AddEntities (void) CSQC_RelinkAllEntities(drawmask); CL_RelinkLightFlashes(); - *prog->time = cl.time; + prog->globals.client->time = cl.time; for(i=1;inum_edicts;i++) { ed = &prog->edicts[i]; @@ -1855,11 +1761,11 @@ void VM_CL_setattachment (void) if (tagentity == NULL) tagentity = prog->edicts; - v = PRVM_GETEDICTFIELDVALUE(e, csqc_fieldoff_tag_entity); + v = PRVM_GETEDICTFIELDVALUE(e, prog->fieldoffsets.tag_entity); if (v) v->edict = PRVM_EDICT_TO_PROG(tagentity); - v = PRVM_GETEDICTFIELDVALUE(e, csqc_fieldoff_tag_index); + v = PRVM_GETEDICTFIELDVALUE(e, prog->fieldoffsets.tag_index); if (v) v->_float = 0; if (tagentity != NULL && tagentity != prog->edicts && tagname && tagname[0]) @@ -1934,13 +1840,13 @@ int CL_GetTagMatrix (matrix4x4_t *out, prvm_edict_t *ent, int tagindex) else tagmatrix = identitymatrix; - if ((val = PRVM_GETEDICTFIELDVALUE(ent, csqc_fieldoff_tag_entity)) && val->edict) + if ((val = PRVM_GETEDICTFIELDVALUE(ent, prog->fieldoffsets.tag_entity)) && val->edict) { // DP_GFX_QUAKE3MODELTAGS, scan all chain and stop on unattached entity attachloop = 0; do { attachent = PRVM_EDICT_NUM(val->edict); // to this it entity our entity is attached - val = PRVM_GETEDICTFIELDVALUE(ent, csqc_fieldoff_tag_index); + val = PRVM_GETEDICTFIELDVALUE(ent, prog->fieldoffsets.tag_index); model = CSQC_GetModelFromEntity(attachent); @@ -1950,7 +1856,7 @@ int CL_GetTagMatrix (matrix4x4_t *out, prvm_edict_t *ent, int tagindex) attachmatrix = identitymatrix; // apply transformation by child entity matrix - val = PRVM_GETEDICTFIELDVALUE(ent, csqc_fieldoff_scale); + val = PRVM_GETEDICTFIELDVALUE(ent, prog->fieldoffsets.scale); if (val->_float == 0) val->_float = 1; Matrix4x4_CreateFromQuakeEntity(&entitymatrix, ent->fields.client->origin[0], ent->fields.client->origin[1], ent->fields.client->origin[2], -ent->fields.client->angles[0], ent->fields.client->angles[1], ent->fields.client->angles[2], val->_float); @@ -1966,22 +1872,22 @@ int CL_GetTagMatrix (matrix4x4_t *out, prvm_edict_t *ent, int tagindex) if (attachloop > 255) // prevent runaway looping return 5; } - while ((val = PRVM_GETEDICTFIELDVALUE(ent, csqc_fieldoff_tag_entity)) && val->edict); + while ((val = PRVM_GETEDICTFIELDVALUE(ent, prog->fieldoffsets.tag_entity)) && val->edict); } // normal or RENDER_VIEWMODEL entity (or main parent entity on attach chain) - val = PRVM_GETEDICTFIELDVALUE(ent, csqc_fieldoff_scale); + val = PRVM_GETEDICTFIELDVALUE(ent, prog->fieldoffsets.scale); if (val->_float == 0) val->_float = 1; // Alias models have inverse pitch, bmodels can't have tags, so don't check for modeltype... Matrix4x4_CreateFromQuakeEntity(&entitymatrix, ent->fields.client->origin[0], ent->fields.client->origin[1], ent->fields.client->origin[2], -ent->fields.client->angles[0], ent->fields.client->angles[1], ent->fields.client->angles[2], val->_float); Matrix4x4_Concat(out, &entitymatrix, &tagmatrix); - if ((val = PRVM_GETEDICTFIELDVALUE(ent, csqc_fieldoff_renderflags)) && (RF_VIEWMODEL & (int)val->_float)) + if ((val = PRVM_GETEDICTFIELDVALUE(ent, prog->fieldoffsets.renderflags)) && (RF_VIEWMODEL & (int)val->_float)) {// RENDER_VIEWMODEL magic Matrix4x4_Copy(&tagmatrix, out); - val = PRVM_GETEDICTFIELDVALUE(ent, csqc_fieldoff_scale); + val = PRVM_GETEDICTFIELDVALUE(ent, prog->fieldoffsets.scale); if (val->_float == 0) val->_float = 1; @@ -2088,7 +1994,7 @@ void VM_WasFreed (void) VM_SAFEPARMCOUNT(1, VM_WasFreed); e = PRVM_G_EDICT(OFS_PARM0); - if (!e->priv.required->free || (e->priv.required->free && (e->priv.required->freetime < 2 || (*prog->time - e->priv.required->freetime) > 0.5 ))) + if (!e->priv.required->free || (e->priv.required->free && (e->priv.required->freetime < 2 || (prog->globals.client->time - e->priv.required->freetime) > 0.5 ))) PRVM_G_FLOAT(OFS_RETURN) = false; else PRVM_G_FLOAT(OFS_RETURN) = true; @@ -2097,18 +2003,15 @@ void VM_WasFreed (void) void VM_CL_select_cube (void) { int i; - int chain_of; float *mins2, *maxs2; prvm_edict_t *ent, *chain; vec3_t mins1, maxs1; VM_SAFEPARMCOUNT(2, VM_CL_select_cube); - // is the same like !(prog->flag & PRVM_FE_CHAIN) - even if the operator precedence is another - if(!prog->flag & PRVM_FE_CHAIN) + if (prog->fieldoffsets.chain < 0) PRVM_ERROR("VM_findchain: %s doesnt have a chain field !\n", PRVM_NAME); - chain_of = PRVM_ED_FindField("chain")->ofs; chain = prog->edicts; mins2 = PRVM_G_VECTOR(OFS_PARM0); @@ -2126,7 +2029,7 @@ void VM_CL_select_cube (void) continue; if (maxs1[0] < mins2[0] || maxs1[1] < mins2[1] || maxs1[2] < mins2[2]) continue; - PRVM_E_INT(ent,chain_of) = PRVM_NUM_FOR_EDICT(chain); + PRVM_E_INT(ent,prog->fieldoffsets.chain) = PRVM_NUM_FOR_EDICT(chain); chain = ent; } @@ -2136,7 +2039,6 @@ void VM_CL_select_cube (void) void VM_CL_select_super (void) { /* int i; - int chain_of; float *v[8]; prvm_edict_t *ent, *chain; vec3_t mins1, maxs1; @@ -2145,11 +2047,9 @@ void VM_CL_select_super (void) for(i=0;i<8;i++) v[i] = PRVM_G_VECTOR(OFS_PARM0+i*3); - // is the same like !(prog->flag & PRVM_FE_CHAIN) - even if the operator precedence is another - if(!prog->flag & PRVM_FE_CHAIN) + if (prog->fieldoffsets.chain < 0) PRVM_ERROR("VM_findchain: %s doesnt have a chain field !\n", PRVM_NAME); - chain_of = PRVM_ED_FindField("chain")->ofs; chain = prog->edicts; mins2 = PRVM_G_VECTOR(OFS_PARM0); @@ -2167,7 +2067,7 @@ void VM_CL_select_super (void) continue; if (maxs1[0] < mins2[0] || maxs1[1] < mins2[1] || maxs1[2] < mins2[2]) continue; - PRVM_E_INT(ent,chain_of) = PRVM_NUM_FOR_EDICT(chain); + PRVM_E_INT(ent,prog->fieldoffsets.chain) = PRVM_NUM_FOR_EDICT(chain); chain = ent; } @@ -2322,7 +2222,7 @@ VM_cvar, // #45 float(string s) cvar VM_localcmd, // #46 void(string s) localcmd VM_nextent, // #47 entity(entity e) nextent VM_CL_particle, // #48 void(vector o, vector d, float color, float count) particle -VM_CL_changeyaw, // #49 void(entity ent, float ideal_yaw, float speed_yaw) ChangeYaw +VM_changeyaw, // #49 void(entity ent) ChangeYaw NULL, // #50 VM_vectoangles, // #51 vector(vector v) vectoangles 0, // #52 void(float to, float f) WriteByte @@ -2336,7 +2236,7 @@ VM_vectoangles, // #51 vector(vector v) vectoangles VM_sin, // #60 float(float f) sin (DP_QC_SINCOSSQRTPOW) VM_cos, // #61 float(float f) cos (DP_QC_SINCOSSQRTPOW) VM_sqrt, // #62 float(float f) sqrt (DP_QC_SINCOSSQRTPOW) -VM_CL_changepitch, // #63 void(entity ent, float ideal_pitch, float speed_pitch) changepitch (DP_QC_CHANGEPITCH) +VM_changepitch, // #63 void(entity ent) changepitch (DP_QC_CHANGEPITCH) VM_CL_tracetoss, // #64 void(entity e, entity ignore) tracetoss (DP_QC_TRACETOSS) VM_etos, // #65 string(entity ent) etos (DP_QC_ETOS) NULL, // #66 diff --git a/csprogs.c b/csprogs.c index 54684f95..c4b5e479 100644 --- a/csprogs.c +++ b/csprogs.c @@ -13,32 +13,13 @@ static prvm_prog_t *csqc_tmpprog; //[515]: these are required funcs -#define CL_F_INIT "CSQC_Init" -#define CL_F_INPUTEVENT "CSQC_InputEvent" -#define CL_F_UPDATEVIEW "CSQC_UpdateView" -#define CL_F_CONSOLECOMMAND "CSQC_ConsoleCommand" -#define CL_F_SHUTDOWN "CSQC_Shutdown" - -//[515]: these are optional -#define CL_F_PARSE_TEMPENTITY "CSQC_Parse_TempEntity" //[515]: very helpfull when you want to create your own particles/decals/etc for effects that already exist -#define CL_F_PARSE_STUFFCMD "CSQC_Parse_StuffCmd" -#define CL_F_PARSE_PRINT "CSQC_Parse_Print" -#define CL_F_PARSE_CENTERPRINT "CSQC_Parse_CenterPrint" -#define CL_F_ENT_UPDATE "CSQC_Ent_Update" -#define CL_F_ENT_REMOVE "CSQC_Ent_Remove" -#define CL_F_EVENT "CSQC_Event" //[515]: engine call this for its own needs - //so csqc can do some things according to what engine it's running on - //example: to say about edicts increase, whatever... - -#define CSQC_PRINTBUFFERLEN 8192 //[515]: enough ? - static char *cl_required_func[] = { - CL_F_INIT, - CL_F_INPUTEVENT, - CL_F_UPDATEVIEW, - CL_F_CONSOLECOMMAND, - CL_F_SHUTDOWN + "CSQC_Init", + "CSQC_InputEvent", + "CSQC_UpdateView", + "CSQC_ConsoleCommand", + "CSQC_Shutdown" }; static int cl_numrequiredfunc = sizeof(cl_required_func) / sizeof(char*); @@ -46,23 +27,6 @@ static int cl_numrequiredfunc = sizeof(cl_required_func) / sizeof(char*); static char *csqc_printtextbuf = NULL; static unsigned short *csqc_sv2csqcents; //[515]: server entities numbers on client side. FIXME : make pointers instead of numbers ? -static mfunction_t *CSQC_Parse_TempEntity; -static mfunction_t *CSQC_Parse_StuffCmd; -static mfunction_t *CSQC_Parse_Print; -static mfunction_t *CSQC_Parse_CenterPrint; -static mfunction_t *CSQC_Ent_Update; -static mfunction_t *CSQC_Ent_Remove; -static mfunction_t *CSQC_Event; - -static int csqc_fieldoff_alpha; -static int csqc_fieldoff_colormod; -static int csqc_fieldoff_effects; -int csqc_fieldoff_scale; -int csqc_fieldoff_renderflags; -int csqc_fieldoff_tag_entity; -int csqc_fieldoff_tag_index; -int csqc_fieldoff_dphitcontentsmask; - qboolean csqc_loaded = false; vec3_t csqc_origin, csqc_angles; @@ -70,31 +34,6 @@ static double csqc_frametime = 0; static mempool_t *csqc_mempool; -static void CL_VM_FindEdictFieldOffsets (void) -{ - csqc_fieldoff_alpha = PRVM_ED_FindFieldOffset("alpha"); - csqc_fieldoff_scale = PRVM_ED_FindFieldOffset("scale"); - csqc_fieldoff_colormod = PRVM_ED_FindFieldOffset("colormod"); - csqc_fieldoff_renderflags = PRVM_ED_FindFieldOffset("renderflags"); - csqc_fieldoff_effects = PRVM_ED_FindFieldOffset("effects"); - csqc_fieldoff_tag_entity = PRVM_ED_FindFieldOffset("tag_entity"); - csqc_fieldoff_tag_index = PRVM_ED_FindFieldOffset("tag_index"); - - CSQC_Parse_TempEntity = PRVM_ED_FindFunction (CL_F_PARSE_TEMPENTITY); - CSQC_Parse_StuffCmd = PRVM_ED_FindFunction (CL_F_PARSE_STUFFCMD); - CSQC_Parse_Print = PRVM_ED_FindFunction (CL_F_PARSE_PRINT); - CSQC_Parse_CenterPrint = PRVM_ED_FindFunction (CL_F_PARSE_CENTERPRINT); - CSQC_Ent_Update = PRVM_ED_FindFunction (CL_F_ENT_UPDATE); - CSQC_Ent_Remove = PRVM_ED_FindFunction (CL_F_ENT_REMOVE); - CSQC_Event = PRVM_ED_FindFunction (CL_F_EVENT); - - if(CSQC_Parse_Print) - { - csqc_printtextbuf = (char *)Mem_Alloc(csqc_mempool, CSQC_PRINTBUFFERLEN); - csqc_printtextbuf[0] = 0; - } -} - void CL_VM_Error (const char *format, ...) DP_FUNC_PRINTF(1); void CL_VM_Error (const char *format, ...) //[515]: hope it will be never executed =) { @@ -148,7 +87,7 @@ static void CSQC_SetGlobals (void) //extern cvar_t sv_accelerate, sv_friction, sv_gravity, sv_stopspeed, sv_maxspeed; CSQC_BEGIN - *prog->time = cl.time; + prog->globals.client->time = cl.time; prog->globals.client->frametime = cl.time - csqc_frametime; csqc_frametime = cl.time; prog->globals.client->servercommandframe = cl.servermovesequence; @@ -181,7 +120,7 @@ void CSQC_Think (prvm_edict_t *ed) { int b; if(ed->fields.client->think) - if(ed->fields.client->nextthink && ed->fields.client->nextthink <= *prog->time) + if(ed->fields.client->nextthink && ed->fields.client->nextthink <= prog->globals.client->time) { ed->fields.client->nextthink = 0; b = prog->globals.client->self; @@ -218,21 +157,21 @@ qboolean CSQC_AddRenderEdict(prvm_edict_t *ed) // FIXME: renderflags should be in the cl_entvars_t #if 1 renderflags = 0; - if((val = PRVM_GETEDICTFIELDVALUE(ed, csqc_fieldoff_renderflags)) && val->_float) renderflags = (int)val->_float; + if((val = PRVM_GETEDICTFIELDVALUE(ed, prog->fieldoffsets.renderflags)) && val->_float) renderflags = (int)val->_float; #else renderflags = (int)ed->fields.client->renderflags; #endif - if((val = PRVM_GETEDICTFIELDVALUE(ed, csqc_fieldoff_alpha)) && val->_float) e->render.alpha = val->_float; - if((val = PRVM_GETEDICTFIELDVALUE(ed, csqc_fieldoff_scale)) && val->_float) e->render.scale = scale = val->_float; - if((val = PRVM_GETEDICTFIELDVALUE(ed, csqc_fieldoff_colormod)) && VectorLength2(val->vector)) VectorCopy(val->vector, e->render.colormod); - if((val = PRVM_GETEDICTFIELDVALUE(ed, csqc_fieldoff_effects)) && val->_float) e->render.effects = (int)val->_float; - if((val = PRVM_GETEDICTFIELDVALUE(ed, csqc_fieldoff_tag_entity)) && val->edict) + if((val = PRVM_GETEDICTFIELDVALUE(ed, prog->fieldoffsets.alpha)) && val->_float) e->render.alpha = val->_float; + if((val = PRVM_GETEDICTFIELDVALUE(ed, prog->fieldoffsets.scale)) && val->_float) e->render.scale = scale = val->_float; + if((val = PRVM_GETEDICTFIELDVALUE(ed, prog->fieldoffsets.colormod)) && VectorLength2(val->vector)) VectorCopy(val->vector, e->render.colormod); + if((val = PRVM_GETEDICTFIELDVALUE(ed, prog->fieldoffsets.effects)) && val->_float) e->render.effects = (int)val->_float; + if((val = PRVM_GETEDICTFIELDVALUE(ed, prog->fieldoffsets.tag_entity)) && val->edict) { int tagentity; int tagindex = 0; tagentity = val->edict; - if((val = PRVM_GETEDICTFIELDVALUE(ed, csqc_fieldoff_tag_index)) && val->_float) + if((val = PRVM_GETEDICTFIELDVALUE(ed, prog->fieldoffsets.tag_index)) && val->_float) tagindex = (int)val->_float; // FIXME: calculate tag matrix Matrix4x4_CreateIdentity(&tagmatrix); @@ -269,7 +208,7 @@ qboolean CSQC_AddRenderEdict(prvm_edict_t *ed) CL_UpdateRenderEntity(&e->render); i = 0; - if((val = PRVM_GETEDICTFIELDVALUE(ed, csqc_fieldoff_renderflags)) && val->_float) + if((val = PRVM_GETEDICTFIELDVALUE(ed, prog->fieldoffsets.renderflags)) && val->_float) { i = (int)val->_float; if(i & RF_VIEWMODEL) e->render.flags |= RENDER_VIEWMODEL; @@ -303,10 +242,10 @@ qboolean CL_VM_InputEvent (qboolean pressed, int key) if(!csqc_loaded) return false; CSQC_BEGIN - *prog->time = cl.time; + prog->globals.client->time = cl.time; PRVM_G_FLOAT(OFS_PARM0) = pressed; PRVM_G_FLOAT(OFS_PARM1) = key; - PRVM_ExecuteProgram (prog->globals.client->CSQC_InputEvent, CL_F_INPUTEVENT); + PRVM_ExecuteProgram(prog->funcoffsets.CSQC_InputEvent, "QC function CSQC_InputEvent is missing"); r = CSQC_RETURNVAL; CSQC_END return r; @@ -319,13 +258,13 @@ qboolean CL_VM_UpdateView (void) return false; CSQC_BEGIN //VectorCopy(cl.viewangles, oldangles); - *prog->time = cl.time; + prog->globals.client->time = cl.time; CSQC_SetGlobals(); // clear renderable entity and light lists to prevent crashes if the // CSQC_UpdateView function does not call R_ClearScene as it should r_refdef.numentities = 0; r_refdef.numlights = 0; - PRVM_ExecuteProgram (prog->globals.client->CSQC_UpdateView, CL_F_UPDATEVIEW); + PRVM_ExecuteProgram(prog->funcoffsets.CSQC_UpdateView, "QC function CSQC_UpdateView is missing"); //VectorCopy(oldangles, cl.viewangles); CSQC_END return true; @@ -339,10 +278,10 @@ qboolean CL_VM_ConsoleCommand (const char *cmd) if(!csqc_loaded) return false; CSQC_BEGIN - *prog->time = cl.time; + prog->globals.client->time = cl.time; restorevm_tempstringsbuf_cursize = vm_tempstringsbuf.cursize; PRVM_G_INT(OFS_PARM0) = PRVM_SetTempString(cmd); - PRVM_ExecuteProgram (prog->globals.client->CSQC_ConsoleCommand, CL_F_CONSOLECOMMAND); + PRVM_ExecuteProgram(prog->funcoffsets.CSQC_ConsoleCommand, "QC function CSQC_ConsoleCommand is missing"); vm_tempstringsbuf.cursize = restorevm_tempstringsbuf_cursize; r = CSQC_RETURNVAL; CSQC_END @@ -352,20 +291,23 @@ qboolean CL_VM_ConsoleCommand (const char *cmd) qboolean CL_VM_Parse_TempEntity (void) { int t; - qboolean r; - if(!csqc_loaded || !CSQC_Parse_TempEntity) + qboolean r = false; + if(!csqc_loaded) return false; - t = msg_readcount; CSQC_BEGIN - *prog->time = cl.time; - PRVM_ExecuteProgram ((func_t)(CSQC_Parse_TempEntity - prog->functions), CL_F_PARSE_TEMPENTITY); - r = CSQC_RETURNVAL; - CSQC_END - if(!r) + if(prog->funcoffsets.CSQC_Parse_TempEntity) { - msg_readcount = t; - msg_badread = false; + t = msg_readcount; + prog->globals.client->time = cl.time; + PRVM_ExecuteProgram(prog->funcoffsets.CSQC_Parse_TempEntity, "QC function CSQC_Parse_TempEntity is missing"); + r = CSQC_RETURNVAL; + if(!r) + { + msg_readcount = t; + msg_badread = false; + } } + CSQC_END return r; } @@ -389,85 +331,103 @@ void CL_VM_Parse_StuffCmd (const char *msg) csqc_progsize.flags = sizeflags; return; } - if(!csqc_loaded || !CSQC_Parse_StuffCmd) + if(!csqc_loaded) { Cbuf_AddText(msg); return; } CSQC_BEGIN - *prog->time = cl.time; + if(prog->funcoffsets.CSQC_Parse_StuffCmd) + { + prog->globals.client->time = cl.time; restorevm_tempstringsbuf_cursize = vm_tempstringsbuf.cursize; PRVM_G_INT(OFS_PARM0) = PRVM_SetTempString(msg); - PRVM_ExecuteProgram ((func_t)(CSQC_Parse_StuffCmd - prog->functions), CL_F_PARSE_STUFFCMD); + PRVM_ExecuteProgram(prog->funcoffsets.CSQC_Parse_StuffCmd, "QC function CSQC_Parse_StuffCmd is missing"); vm_tempstringsbuf.cursize = restorevm_tempstringsbuf_cursize; + } + else + Cbuf_AddText(msg); CSQC_END } static void CL_VM_Parse_Print (const char *msg) { int restorevm_tempstringsbuf_cursize; - CSQC_BEGIN - *prog->time = cl.time; - restorevm_tempstringsbuf_cursize = vm_tempstringsbuf.cursize; - PRVM_G_INT(OFS_PARM0) = PRVM_SetTempString(msg); - PRVM_ExecuteProgram ((func_t)(CSQC_Parse_Print - prog->functions), CL_F_PARSE_PRINT); - vm_tempstringsbuf.cursize = restorevm_tempstringsbuf_cursize; - CSQC_END + prog->globals.client->time = cl.time; + restorevm_tempstringsbuf_cursize = vm_tempstringsbuf.cursize; + PRVM_G_INT(OFS_PARM0) = PRVM_SetTempString(msg); + PRVM_ExecuteProgram(prog->funcoffsets.CSQC_Parse_Print, "QC function CSQC_Parse_Print is missing"); + vm_tempstringsbuf.cursize = restorevm_tempstringsbuf_cursize; } void CSQC_AddPrintText (const char *msg) { size_t i; - if(!csqc_loaded || !CSQC_Parse_Print) + if(!csqc_loaded) { Con_Print(msg); return; } - // FIXME: is this bugged? - i = strlen(msg)-1; - if(msg[i] != '\n' && msg[i] != '\r') + CSQC_BEGIN + if(prog->funcoffsets.CSQC_Parse_Print) { - if(strlen(csqc_printtextbuf)+i >= CSQC_PRINTBUFFERLEN) + // FIXME: is this bugged? + i = strlen(msg)-1; + if(msg[i] != '\n' && msg[i] != '\r') { - CL_VM_Parse_Print(csqc_printtextbuf); - csqc_printtextbuf[0] = 0; + if(strlen(csqc_printtextbuf)+i >= MAX_INPUTLINE) + { + CL_VM_Parse_Print(csqc_printtextbuf); + csqc_printtextbuf[0] = 0; + } + else + strlcat(csqc_printtextbuf, msg, MAX_INPUTLINE); + return; } - else - strlcat(csqc_printtextbuf, msg, CSQC_PRINTBUFFERLEN); - return; + strlcat(csqc_printtextbuf, msg, MAX_INPUTLINE); + CL_VM_Parse_Print(csqc_printtextbuf); + csqc_printtextbuf[0] = 0; } - strlcat(csqc_printtextbuf, msg, CSQC_PRINTBUFFERLEN); - CL_VM_Parse_Print(csqc_printtextbuf); - csqc_printtextbuf[0] = 0; + else + Con_Print(msg); + CSQC_END } void CL_VM_Parse_CenterPrint (const char *msg) { int restorevm_tempstringsbuf_cursize; - if(!csqc_loaded || !CSQC_Parse_CenterPrint) + if(!csqc_loaded) { SCR_CenterPrint((char*)msg); return; } CSQC_BEGIN - *prog->time = cl.time; + if(prog->funcoffsets.CSQC_Parse_CenterPrint) + { + prog->globals.client->time = cl.time; restorevm_tempstringsbuf_cursize = vm_tempstringsbuf.cursize; PRVM_G_INT(OFS_PARM0) = PRVM_SetTempString(msg); - PRVM_ExecuteProgram ((func_t)(CSQC_Parse_CenterPrint - prog->functions), CL_F_PARSE_CENTERPRINT); + PRVM_ExecuteProgram(prog->funcoffsets.CSQC_Parse_CenterPrint, "QC function CSQC_Parse_CenterPrint is missing"); vm_tempstringsbuf.cursize = restorevm_tempstringsbuf_cursize; + } + else + SCR_CenterPrint((char*)msg); CSQC_END } float CL_VM_Event (float event) //[515]: needed ? I'd say "YES", but don't know for what :D { float r; - if(!csqc_loaded || !CSQC_Event) + if(!csqc_loaded) return 0; CSQC_BEGIN - *prog->time = cl.time; + if(prog->funcoffsets.CSQC_Event) + { + prog->globals.client->time = cl.time; PRVM_G_FLOAT(OFS_PARM0) = event; - PRVM_ExecuteProgram ((func_t)(CSQC_Event - prog->functions), CL_F_EVENT); + PRVM_ExecuteProgram(prog->funcoffsets.CSQC_Event, "QC function CSQC_Event is missing"); r = CSQC_RETURNVAL; + } CSQC_END return r; } @@ -476,7 +436,7 @@ void CSQC_ReadEntities (void) { unsigned short entnum, oldself, realentnum; CSQC_BEGIN - *prog->time = cl.time; + prog->globals.client->time = cl.time; oldself = prog->globals.client->self; while(1) { @@ -489,7 +449,7 @@ void CSQC_ReadEntities (void) { if(prog->globals.client->self) { - PRVM_ExecuteProgram((func_t)(CSQC_Ent_Remove - prog->functions), CL_F_ENT_REMOVE); + PRVM_ExecuteProgram(prog->funcoffsets.CSQC_Ent_Remove, "QC function CSQC_Ent_Remove is missing"); csqc_sv2csqcents[realentnum] = 0; } else @@ -507,13 +467,93 @@ void CSQC_ReadEntities (void) } else PRVM_G_FLOAT(OFS_PARM0) = 0; - PRVM_ExecuteProgram((func_t)(CSQC_Ent_Update - prog->functions), CL_F_ENT_UPDATE); + PRVM_ExecuteProgram(prog->funcoffsets.CSQC_Ent_Update, "QC function CSQC_Ent_Update is missing"); } } prog->globals.client->self = oldself; CSQC_END } +void CL_LinkEdict(prvm_edict_t *ent) +{ + if (ent == prog->edicts) + return; // don't add the world + + if (ent->priv.server->free) + return; + + VectorAdd(ent->fields.client->origin, ent->fields.client->mins, ent->fields.client->absmin); + VectorAdd(ent->fields.client->origin, ent->fields.client->maxs, ent->fields.client->absmax); + + World_LinkEdict(&cl.world, ent, ent->fields.client->absmin, ent->fields.client->absmax); +} + +void CL_VM_CB_BeginIncreaseEdicts(void) +{ + int i; + prvm_edict_t *ent; + + // links don't survive the transition, so unlink everything + for (i = 0, ent = prog->edicts;i < prog->max_edicts;i++, ent++) + { + if (!ent->priv.server->free) + World_UnlinkEdict(prog->edicts + i); + memset(&ent->priv.server->areagrid, 0, sizeof(ent->priv.server->areagrid)); + } + World_Clear(&cl.world); +} + +void CL_VM_CB_EndIncreaseEdicts(void) +{ + int i; + prvm_edict_t *ent; + + // link every entity except world + for (i = 1, ent = prog->edicts;i < prog->max_edicts;i++, ent++) + if (!ent->priv.server->free) + CL_LinkEdict(ent); +} + +void CL_VM_CB_InitEdict(prvm_edict_t *e) +{ + e->priv.server->move = false; // don't move on first frame +} + +void CL_VM_CB_FreeEdict(prvm_edict_t *ed) +{ + World_UnlinkEdict(ed); + memset(ed->fields.client, 0, sizeof(*ed->fields.client)); +} + +void CL_VM_CB_CountEdicts(void) +{ + int i; + prvm_edict_t *ent; + int active = 0, models = 0, solid = 0; + + for (i=0 ; inum_edicts ; i++) + { + ent = PRVM_EDICT_NUM(i); + if (ent->priv.server->free) + continue; + active++; + if (ent->fields.client->solid) + solid++; + if (ent->fields.client->model) + models++; + } + + Con_Printf("num_edicts:%3i\n", prog->num_edicts); + Con_Printf("active :%3i\n", active); + Con_Printf("view :%3i\n", models); + Con_Printf("touch :%3i\n", solid); +} + +qboolean CL_VM_CB_LoadEdict(prvm_edict_t *ent) +{ + return true; +} + void Cmd_ClearCsqcFuncs (void); void CL_VM_Init (void) @@ -586,15 +626,24 @@ void CL_VM_Init (void) prog->edictprivate_size = 0; // no private struct used prog->name = CL_NAME; prog->num_edicts = 1; + prog->max_edicts = 512; prog->limit_edicts = CL_MAX_EDICTS; + prog->reserved_edicts = 0; + prog->edictprivate_size = sizeof(edict_engineprivate_t); prog->extensionstring = vm_cl_extensions; prog->builtins = vm_cl_builtins; prog->numbuiltins = vm_cl_numbuiltins; + prog->begin_increase_edicts = CL_VM_CB_BeginIncreaseEdicts; + prog->end_increase_edicts = CL_VM_CB_EndIncreaseEdicts; + prog->init_edict = CL_VM_CB_InitEdict; + prog->free_edict = CL_VM_CB_FreeEdict; + prog->count_edicts = CL_VM_CB_CountEdicts; + prog->load_edict = CL_VM_CB_LoadEdict; prog->init_cmd = VM_CL_Cmd_Init; prog->reset_cmd = VM_CL_Cmd_Reset; prog->error_cmd = CL_VM_Error; - PRVM_LoadProgs(csqc_progname.string, cl_numrequiredfunc, cl_required_func, 0, NULL); + PRVM_LoadProgs(csqc_progname.string, cl_numrequiredfunc, cl_required_func, 0, NULL, 0, NULL); if(prog->loaded) Con_Printf("CSQC ^5loaded (crc=%i, size=%i)\n", csprogsdatacrc, (int)csprogsdatasize); @@ -607,17 +656,33 @@ void CL_VM_Init (void) } //[515]: optional fields & funcs - CL_VM_FindEdictFieldOffsets(); + if(prog->funcoffsets.CSQC_Parse_Print) + { + csqc_printtextbuf = (char *)Mem_Alloc(csqc_mempool, MAX_INPUTLINE); + csqc_printtextbuf[0] = 0; + } + + if (cl.worldmodel) + { + VectorCopy(cl.worldmodel->normalmins, cl.world.areagrid_mins); + VectorCopy(cl.worldmodel->normalmaxs, cl.world.areagrid_maxs); + } + else + { + VectorSet(cl.world.areagrid_mins, -4096, -4096, -4096); + VectorSet(cl.world.areagrid_maxs, 4096, 4096, 4096); + } + World_Clear(&cl.world); // set time - *prog->time = cl.time; + prog->globals.client->time = cl.time; csqc_frametime = 0; prog->globals.client->mapname = PRVM_SetEngineString(cl.worldmodel->name); prog->globals.client->player_localentnum = cl.playerentity; // call the prog init - PRVM_ExecuteProgram((func_t) (PRVM_ED_FindFunction(CL_F_INIT) - prog->functions), CL_F_INIT); + PRVM_ExecuteProgram(prog->funcoffsets.CSQC_Init, "QC function CSQC_Init is missing"); PRVM_End; csqc_loaded = true; @@ -637,8 +702,8 @@ void CL_VM_ShutDown (void) if(!csqc_loaded) return; CSQC_BEGIN - *prog->time = cl.time; - PRVM_ExecuteProgram((func_t) (PRVM_ED_FindFunction(CL_F_SHUTDOWN) - prog->functions), CL_F_SHUTDOWN); + prog->globals.client->time = cl.time; + PRVM_ExecuteProgram(prog->funcoffsets.CSQC_Shutdown, "QC function CSQC_Shutdown is missing"); PRVM_ResetProg(); CSQC_END Con_Print("CSQC ^1unloaded\n"); diff --git a/csprogs.h b/csprogs.h index 1a9cfe1c..45b91a34 100644 --- a/csprogs.h +++ b/csprogs.h @@ -50,11 +50,6 @@ extern qboolean csqc_loaded; extern vec3_t csqc_origin, csqc_angles; -extern int csqc_fieldoff_scale; -extern int csqc_fieldoff_renderflags; -extern int csqc_fieldoff_tag_entity; -extern int csqc_fieldoff_tag_index; -extern int csqc_fieldoff_dphitcontentsmask; extern cvar_t csqc_progname; //[515]: csqc crc check and right csprogs name according to progs.dat extern cvar_t csqc_progcrc; extern cvar_t csqc_progsize; diff --git a/host.c b/host.c index 0e2f91e1..6a8c0352 100644 --- a/host.c +++ b/host.c @@ -466,10 +466,6 @@ void SV_DropClient(qboolean crash) } // remove leaving player from scoreboard - //host_client->edict->fields.server->netname = PRVM_SetEngineString(host_client->name); - //if ((val = PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_clientcolors))) - // val->_float = 0; - //host_client->edict->fields.server->frags = 0; host_client->name[0] = 0; host_client->colors = 0; host_client->frags = 0; @@ -974,6 +970,7 @@ static void Host_Init (void) //PR_Cmd_Init(); PRVM_Init(); Mod_Init(); + World_Init(); SV_Init(); Host_InitCommands(); Host_InitLocal(); diff --git a/host_cmd.c b/host_cmd.c index 38a041bf..a4529feb 100644 --- a/host_cmd.c +++ b/host_cmd.c @@ -92,7 +92,7 @@ void Host_Status_f (void) } else hours = 0; - print ("#%-3u %-16.16s %3i %2i:%02i:%02i\n", j+1, client->name, (int)client->edict->fields.server->frags, hours, minutes, seconds); + print ("#%-3u %-16.16s %3i %2i:%02i:%02i\n", j+1, client->name, client->frags, hours, minutes, seconds); print (" %s\n", client->netconnection ? client->netconnection->address : "botclient"); } } @@ -853,8 +853,8 @@ void Host_Playermodel_f (void) // point the string back at updateclient->name to keep it safe strlcpy (host_client->playermodel, newPath, sizeof (host_client->playermodel)); - if( eval_playermodel ) - PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_playermodel)->string = PRVM_SetEngineString(host_client->playermodel); + if( prog->fieldoffsets.playermodel >= 0 ) + PRVM_GETEDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.playermodel)->string = PRVM_SetEngineString(host_client->playermodel); if (strcmp(host_client->old_model, host_client->playermodel)) { strlcpy(host_client->old_model, host_client->playermodel, sizeof(host_client->old_model)); @@ -911,8 +911,8 @@ void Host_Playerskin_f (void) // point the string back at updateclient->name to keep it safe strlcpy (host_client->playerskin, newPath, sizeof (host_client->playerskin)); - if( eval_playerskin ) - PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_playerskin)->string = PRVM_SetEngineString(host_client->playerskin); + if( prog->fieldoffsets.playerskin >= 0 ) + PRVM_GETEDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.playerskin)->string = PRVM_SetEngineString(host_client->playerskin); if (strcmp(host_client->old_skin, host_client->playerskin)) { //if (host_client->spawned) @@ -1146,8 +1146,6 @@ cvar_t cl_color = {CVAR_SAVE, "_cl_color", "0", "internal storage cvar for curre void Host_Color(int changetop, int changebottom) { int top, bottom, playercolor; - mfunction_t *f; - func_t SV_ChangeTeam; // get top and bottom either from the provided values or the current values // (allows changing only top or bottom, or both at once) @@ -1182,20 +1180,20 @@ void Host_Color(int changetop, int changebottom) if (cls.protocol == PROTOCOL_QUAKEWORLD) return; - if (host_client->edict && (f = PRVM_ED_FindFunction ("SV_ChangeTeam")) && (SV_ChangeTeam = (func_t)(f - prog->functions))) + if (host_client->edict && prog->funcoffsets.SV_ChangeTeam) { Con_DPrint("Calling SV_ChangeTeam\n"); prog->globals.server->time = sv.time; prog->globals.generic[OFS_PARM0] = playercolor; prog->globals.server->self = PRVM_EDICT_TO_PROG(host_client->edict); - PRVM_ExecuteProgram (SV_ChangeTeam, "QC function SV_ChangeTeam is missing"); + PRVM_ExecuteProgram(prog->funcoffsets.SV_ChangeTeam, "QC function SV_ChangeTeam is missing"); } else { prvm_eval_t *val; if (host_client->edict) { - if ((val = PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_clientcolors))) + if ((val = PRVM_GETEDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.clientcolors))) val->_float = playercolor; host_client->edict->fields.server->team = bottom + 1; } @@ -1348,7 +1346,7 @@ static void Host_PModel_f (void) return; } - if (host_client->edict && (val = PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_pmodel))) + if (host_client->edict && (val = PRVM_GETEDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.pmodel))) val->_float = i; } @@ -1388,8 +1386,6 @@ void Host_Spawn_f (void) { int i; client_t *client; - func_t RestoreGame; - mfunction_t *f; int stats[MAX_CL_STATS]; if (host_client->spawned) @@ -1414,13 +1410,12 @@ void Host_Spawn_f (void) // if this is the last client to be connected, unpause sv.paused = false; - if ((f = PRVM_ED_FindFunction ("RestoreGame"))) - if ((RestoreGame = (func_t)(f - prog->functions))) + if (prog->funcoffsets.RestoreGame) { Con_DPrint("Calling RestoreGame\n"); prog->globals.server->time = sv.time; prog->globals.server->self = PRVM_EDICT_TO_PROG(host_client->edict); - PRVM_ExecuteProgram (RestoreGame, "QC function RestoreGame is missing"); + PRVM_ExecuteProgram(prog->funcoffsets.RestoreGame, "QC function RestoreGame is missing"); } } else @@ -1679,7 +1674,7 @@ void Host_Give_f (void) break; case 's': - if (gamemode == GAME_ROGUE && (val = PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_ammo_shells1))) + if (gamemode == GAME_ROGUE && (val = PRVM_GETEDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.ammo_shells1))) val->_float = v; host_client->edict->fields.server->ammo_shells = v; @@ -1687,7 +1682,7 @@ void Host_Give_f (void) case 'n': if (gamemode == GAME_ROGUE) { - if ((val = PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_ammo_nails1))) + if ((val = PRVM_GETEDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.ammo_nails1))) { val->_float = v; if (host_client->edict->fields.server->weapon <= IT_LIGHTNING) @@ -1702,7 +1697,7 @@ void Host_Give_f (void) case 'l': if (gamemode == GAME_ROGUE) { - val = PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_ammo_lava_nails); + val = PRVM_GETEDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.ammo_lava_nails); if (val) { val->_float = v; @@ -1714,7 +1709,7 @@ void Host_Give_f (void) case 'r': if (gamemode == GAME_ROGUE) { - val = PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_ammo_rockets1); + val = PRVM_GETEDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.ammo_rockets1); if (val) { val->_float = v; @@ -1730,7 +1725,7 @@ void Host_Give_f (void) case 'm': if (gamemode == GAME_ROGUE) { - val = PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_ammo_multi_rockets); + val = PRVM_GETEDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.ammo_multi_rockets); if (val) { val->_float = v; @@ -1745,7 +1740,7 @@ void Host_Give_f (void) case 'c': if (gamemode == GAME_ROGUE) { - val = PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_ammo_cells1); + val = PRVM_GETEDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.ammo_cells1); if (val) { val->_float = v; @@ -1761,7 +1756,7 @@ void Host_Give_f (void) case 'p': if (gamemode == GAME_ROGUE) { - val = PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_ammo_plasma); + val = PRVM_GETEDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.ammo_plasma); if (val) { val->_float = v; @@ -2000,7 +1995,7 @@ void Host_SendCvar_f (void) return; if (cls.state != ca_dedicated) Cmd_ForwardStringToServer(va("sentcvar %s \"%s\"\n", c->name, c->string)); - if(!sv.active)// || !SV_ParseClientCommandQC) + if(!sv.active)// || !prog->funcoffsets.SV_ParseClientCommand) return; old = host_client; diff --git a/menu.c b/menu.c index df499d72..e9597350 100644 --- a/menu.c +++ b/menu.c @@ -4816,22 +4816,13 @@ void M_Restart(void) //============================================================================ // Menu prog handling -mfunction_t *PRVM_ED_FindFunction(const char *); - -#define M_F_INIT "m_init" -#define M_F_KEYDOWN "m_keydown" -#define M_F_KEYUP "m_keyup" -#define M_F_DRAW "m_draw" -// normal menu names (rest) -#define M_F_TOGGLE "m_toggle" -#define M_F_SHUTDOWN "m_shutdown" static char *m_required_func[] = { -M_F_INIT, -M_F_KEYDOWN, -M_F_DRAW, -M_F_TOGGLE, -M_F_SHUTDOWN, +"m_init", +"m_keydown", +"m_draw", +"m_toggle", +"m_shutdown", }; #ifdef NG_MENU @@ -4840,9 +4831,6 @@ static qboolean m_displayed; static int m_numrequiredfunc = sizeof(m_required_func) / sizeof(char*); -static func_t m_draw, m_keydown; -static mfunction_t *m_keyup; - void MR_SetRouting (qboolean forceold); void MP_Error(const char *format, ...) DP_FUNC_PRINTF(1); @@ -4883,16 +4871,13 @@ void MP_KeyEvent (int key, char ascii, qboolean downevent) PRVM_Begin; PRVM_SetProg(PRVM_MENUPROG); - // set time - *prog->time = realtime; - // pass key prog->globals.generic[OFS_PARM0] = (float) key; prog->globals.generic[OFS_PARM1] = (float) ascii; if (downevent) - PRVM_ExecuteProgram(m_keydown, M_F_KEYDOWN"(float key, float ascii) required\n"); - else if (m_keyup) - PRVM_ExecuteProgram((func_t)(m_keyup - prog->functions), M_F_KEYUP"(float key, float ascii) required\n"); + PRVM_ExecuteProgram(prog->funcoffsets.m_keydown,"m_keydown(float key, float ascii) required"); + else if (prog->funcoffsets.m_keyup) + PRVM_ExecuteProgram(prog->funcoffsets.m_keyup,"m_keyup(float key, float ascii) required"); PRVM_End; } @@ -4902,10 +4887,7 @@ void MP_Draw (void) PRVM_Begin; PRVM_SetProg(PRVM_MENUPROG); - // set time - *prog->time = realtime; - - PRVM_ExecuteProgram(m_draw,""); + PRVM_ExecuteProgram(prog->funcoffsets.m_draw,"m_draw() required"); PRVM_End; } @@ -4915,17 +4897,14 @@ void MP_ToggleMenu_f (void) PRVM_Begin; PRVM_SetProg(PRVM_MENUPROG); - // set time - *prog->time = realtime; - #ifdef NG_MENU m_displayed = !m_displayed; if( m_displayed ) - PRVM_ExecuteProgram((func_t) (PRVM_ED_FindFunction(M_F_DISPLAY) - prog->functions),""); + PRVM_ExecuteProgram(prog->funcoffsets.m_display,"m_display() required"); else - PRVM_ExecuteProgram((func_t) (PRVM_ED_FindFunction(M_F_HIDE) - prog->functions),""); + PRVM_ExecuteProgram(prog->funcoffsets.m_hide,"m_hide() required"); #else - PRVM_ExecuteProgram((func_t) (PRVM_ED_FindFunction(M_F_TOGGLE) - prog->functions),""); + PRVM_ExecuteProgram(prog->funcoffsets.m_toggle,"m_toggle() required"); #endif PRVM_End; @@ -4936,10 +4915,7 @@ void MP_Shutdown (void) PRVM_Begin; PRVM_SetProg(PRVM_MENUPROG); - // set time - *prog->time = realtime; - - PRVM_ExecuteProgram((func_t) (PRVM_ED_FindFunction(M_F_SHUTDOWN) - prog->functions),""); + PRVM_ExecuteProgram(prog->funcoffsets.m_shutdown,"m_shutdown() required"); // reset key_dest key_dest = key_game; @@ -4980,22 +4956,14 @@ void MP_Init (void) // allocate the mempools prog->progs_mempool = Mem_AllocPool(M_PROG_FILENAME, 0, NULL); - PRVM_LoadProgs(M_PROG_FILENAME, m_numrequiredfunc, m_required_func, 0, NULL); - - // set m_draw and m_keydown - m_draw = (func_t) (PRVM_ED_FindFunction(M_F_DRAW) - prog->functions); - m_keydown = (func_t) (PRVM_ED_FindFunction(M_F_KEYDOWN) - prog->functions); - m_keyup = PRVM_ED_FindFunction(M_F_KEYUP); + PRVM_LoadProgs(M_PROG_FILENAME, m_numrequiredfunc, m_required_func, 0, NULL, 0, NULL); #ifdef NG_MENU m_displayed = false; #endif - // set time - *prog->time = realtime; - // call the prog init - PRVM_ExecuteProgram((func_t) (PRVM_ED_FindFunction(M_F_INIT) - prog->functions),""); + PRVM_ExecuteProgram(prog->funcoffsets.m_init,"m_init() required"); PRVM_End; } diff --git a/mvm_cmds.c b/mvm_cmds.c index 138dfc46..b53f5282 100644 --- a/mvm_cmds.c +++ b/mvm_cmds.c @@ -200,7 +200,7 @@ void VM_M_callfunction(void) else PRVM_ERROR("No such builtin #%i in %s", builtinnumber, PRVM_NAME); } - else if(func > 0) + else if(func - prog->functions > 0) { prog->argc--; PRVM_ExecuteProgram(func - prog->functions,""); diff --git a/netconn.c b/netconn.c index 1ade12c3..eec93bcc 100755 --- a/netconn.c +++ b/netconn.c @@ -2209,7 +2209,7 @@ static int NetConn_ServerParsePacket(lhnetsocket_t *mysocket, unsigned char *dat MSG_WriteByte(&net_message, playerNumber); MSG_WriteString(&net_message, client->name); MSG_WriteLong(&net_message, client->colors); - MSG_WriteLong(&net_message, (int)client->edict->fields.server->frags); + MSG_WriteLong(&net_message, client->frags); MSG_WriteLong(&net_message, (int)(realtime - client->connecttime)); MSG_WriteString(&net_message, client->netconnection ? client->netconnection->address : "botclient"); *((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK)); diff --git a/progs.h b/progs.h index 6a96837e..1ef4f55d 100644 --- a/progs.h +++ b/progs.h @@ -22,12 +22,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define PROGS_H #include "pr_comp.h" // defs shared with qcc -typedef struct link_s -{ - int entitynumber; - struct link_s *prev, *next; -} link_t; - #define ENTITYGRIDAREAS 16 #define MAX_ENTITYCLUSTERS 16 @@ -52,6 +46,8 @@ typedef struct edict_engineprivate_s // since the areagrid can have multiple references to one entity, // we should avoid extensive checking on entities already encountered int areagridmarknumber; + // mins/maxs passed to World_LinkEdict + vec3_t areamins, areamaxs; // PROTOCOL_QUAKE, PROTOCOL_QUAKEDP, PROTOCOL_NEHAHRAMOVIE, PROTOCOL_QUAKEWORLD // baseline values @@ -66,85 +62,6 @@ typedef struct edict_engineprivate_s } edict_engineprivate_t; -// LordHavoc: in an effort to eliminate time wasted on GetEdictFieldValue... see pr_edict.c for the functions which use these. -extern int eval_gravity; -extern int eval_button3; -extern int eval_button4; -extern int eval_button5; -extern int eval_button6; -extern int eval_button7; -extern int eval_button8; -extern int eval_button9; -extern int eval_button10; -extern int eval_button11; -extern int eval_button12; -extern int eval_button13; -extern int eval_button14; -extern int eval_button15; -extern int eval_button16; -extern int eval_buttonuse; -extern int eval_buttonchat; -extern int eval_glow_size; -extern int eval_glow_trail; -extern int eval_glow_color; -extern int eval_items2; -extern int eval_scale; -extern int eval_alpha; -extern int eval_renderamt; // HalfLife support -extern int eval_rendermode; // HalfLife support -extern int eval_fullbright; -extern int eval_ammo_shells1; -extern int eval_ammo_nails1; -extern int eval_ammo_lava_nails; -extern int eval_ammo_rockets1; -extern int eval_ammo_multi_rockets; -extern int eval_ammo_cells1; -extern int eval_ammo_plasma; -extern int eval_idealpitch; -extern int eval_pitch_speed; -extern int eval_viewmodelforclient; -extern int eval_nodrawtoclient; -extern int eval_exteriormodeltoclient; -extern int eval_drawonlytoclient; -extern int eval_ping; -extern int eval_movement; -extern int eval_pmodel; -extern int eval_punchvector; -extern int eval_viewzoom; -extern int eval_clientcolors; -extern int eval_tag_entity; -extern int eval_tag_index; -extern int eval_light_lev; -extern int eval_color; -extern int eval_style; -extern int eval_pflags; -extern int eval_cursor_active; -extern int eval_cursor_screen; -extern int eval_cursor_trace_start; -extern int eval_cursor_trace_endpos; -extern int eval_cursor_trace_ent; -extern int eval_colormod; -extern int eval_playermodel; -extern int eval_playerskin; -extern int eval_SendEntity; -extern int eval_Version; -extern int eval_customizeentityforclient; -extern int eval_dphitcontentsmask; -// DRESK - Support for Entity Contents Transition Event -extern int eval_contentstransition; - -extern int gval_trace_dpstartcontents; -extern int gval_trace_dphitcontents; -extern int gval_trace_dphitq3surfaceflags; -extern int gval_trace_dphittexturename; - - - -extern mfunction_t *SV_PlayerPhysicsQC; -extern mfunction_t *EndFrameQC; -//KrimZon - SERVER COMMANDS IN QUAKEC -extern mfunction_t *SV_ParseClientCommandQC; - #endif @@ -220,70 +137,12 @@ typedef struct edict_s } prvm_edict_t; -// LordHavoc: in an effort to eliminate time wasted on GetEdictFieldValue... see pr_edict.c for the functions which use these. -extern int eval_gravity; -extern int eval_button3; -extern int eval_button4; -extern int eval_button5; -extern int eval_button6; -extern int eval_button7; -extern int eval_button8; -extern int eval_buttonuse; -extern int eval_buttonchat; -extern int eval_glow_size; -extern int eval_glow_trail; -extern int eval_glow_color; -extern int eval_items2; -extern int eval_scale; -extern int eval_alpha; -extern int eval_renderamt; // HalfLife support -extern int eval_rendermode; // HalfLife support -extern int eval_fullbright; -extern int eval_ammo_shells1; -extern int eval_ammo_nails1; -extern int eval_ammo_lava_nails; -extern int eval_ammo_rockets1; -extern int eval_ammo_multi_rockets; -extern int eval_ammo_cells1; -extern int eval_ammo_plasma; -extern int eval_idealpitch; -extern int eval_pitch_speed; -extern int eval_viewmodelforclient; -extern int eval_nodrawtoclient; -extern int eval_exteriormodeltoclient; -extern int eval_drawonlytoclient; -extern int eval_ping; -extern int eval_movement; -extern int eval_pmodel; -extern int eval_punchvector; -extern int eval_viewzoom; -extern int eval_clientcolors; -extern int eval_tag_entity; -extern int eval_tag_index; -extern int eval_light_lev; -extern int eval_color; -extern int eval_style; -extern int eval_pflags; -extern int eval_cursor_active; -extern int eval_cursor_screen; -extern int eval_cursor_trace_start; -extern int eval_cursor_trace_endpos; -extern int eval_cursor_trace_ent; -extern int eval_colormod; -extern int eval_playermodel; -extern int eval_playerskin; - #define PRVM_GETEDICTFIELDVALUE(ed, fieldoffset) (fieldoffset ? (prvm_eval_t *)((unsigned char *)ed->v + fieldoffset) : NULL) -extern mfunction_t *SV_PlayerPhysicsQC; -extern mfunction_t *EndFrameQC; -//KrimZon - SERVER COMMANDS IN QUAKEC -extern mfunction_t *SV_ParseClientCommandQC; - //============================================================================ extern dprograms_t *progs; -extern mfunction_t *prog->functions; +extern mfunction_t *pr_functions; extern char *pr_strings; extern int pr_stringssize; extern ddef_t *pr_globaldefs; diff --git a/progsvm.h b/progsvm.h index 673d366f..eb516065 100644 --- a/progsvm.h +++ b/progsvm.h @@ -33,108 +33,6 @@ The code uses void pointers instead. #include "progdefs.h" // generated by program cdefs #include "clprogdefs.h" // generated by program cdefs -/* -typedef union vm_eval_s -{ - string_t string; - float _float; - float vector[3]; - func_t function; - int ivector[3]; - int _int; - int edict; -} vm_eval_t; - -typedef struct vm_link_s -{ - int entitynumber; - struct link_s *prev, *next; -} vm_link_t; - -#define ENTITYGRIDAREAS 16 - -typedef struct vm_edict_engineprivate_s -{ - // true if this edict is unused - qboolean free; - // sv.time when the object was freed (to prevent early reuse which could - // mess up client interpolation or obscure severe QuakeC bugs) - float freetime; - - // physics grid areas this edict is linked into - link_t areagrid[ENTITYGRIDAREAS]; - // since the areagrid can have multiple references to one entity, - // we should avoid extensive checking on entities already encountered - int areagridmarknumber; - - // old entity protocol, not used -#ifdef QUAKEENTITIES - // baseline values - entity_state_t baseline; - // LordHavoc: previous frame - entity_state_t deltabaseline; -#endif - - // LordHavoc: gross hack to make floating items still work - int suspendedinairflag; - // used by PushMove to keep track of where objects were before they were - // moved, in case they need to be moved back - vec3_t moved_from; - vec3_t moved_fromangles; -} -vm_edict_engineprivate_t; - -// the entire server entity structure -// NOTE: keep this small! priv and v are dynamic but this struct is not! -typedef struct vm_edict_s -{ - // engine-private fields (stored in dynamically resized array) - edict_engineprivate_t *e; - // QuakeC fields (stored in dynamically resized array) - entvars_t *v; -} -vm_edict_t; -*/ - -/*// LordHavoc: in an effort to eliminate time wasted on GetEdictFieldValue... see pr_edict.c for the functions which use these. -extern int eval_gravity; -extern int eval_button3; -extern int eval_button4; -extern int eval_button5; -extern int eval_button6; -extern int eval_button7; -extern int eval_button8; -extern int eval_glow_size; -extern int eval_glow_trail; -extern int eval_glow_color; -extern int eval_items2; -extern int eval_scale; -extern int eval_alpha; -extern int eval_renderamt; // HalfLife support -extern int eval_rendermode; // HalfLife support -extern int eval_fullbright; -extern int eval_ammo_shells1; -extern int eval_ammo_nails1; -extern int eval_ammo_lava_nails; -extern int eval_ammo_rockets1; -extern int eval_ammo_multi_rockets; -extern int eval_ammo_cells1; -extern int eval_ammo_plasma; -extern int eval_idealpitch; -extern int eval_pitch_speed; -extern int eval_viewmodelforclient; -extern int eval_nodrawtoclient; -extern int eval_exteriormodeltoclient; -extern int eval_drawonlytoclient; -extern int eval_ping; -extern int eval_movement; -extern int eval_pmodel; -extern int eval_punchvector; -extern int eval_viewzoom; -extern int eval_clientcolors; -extern int eval_tag_entity; -extern int eval_tag_index;*/ - typedef struct prvm_stack_s { int s; @@ -160,12 +58,6 @@ typedef struct prvm_required_field_s } prvm_required_field_t; -/*typedef struct prvm_link_s -{ - int entitynumber; - struct link_s *prev, *next; -} prvm_link_t;*/ - // AK: I dont call it engine private cause it doesnt really belongs to the engine // it belongs to prvm. typedef struct prvm_edict_private_s @@ -182,6 +74,8 @@ typedef struct prvm_edict_s { prvm_edict_private_t *required; void *vp; + // FIXME: this server pointer really means world, not server + // (it is used by both server qc and client qc, but not menu qc) edict_engineprivate_t *server; // add other private structs as you desire // new structs have to start with the elements of prvm_edit_private_t @@ -209,40 +103,10 @@ typedef struct prvm_edict_s } fields; } prvm_edict_t; -#define PRVM_GETEDICTFIELDVALUE(ed, fieldoffset) (fieldoffset ? (prvm_eval_t *)((unsigned char *)ed->fields.vp + fieldoffset) : NULL) -#define PRVM_GETGLOBALFIELDVALUE(fieldoffset) (fieldoffset ? (prvm_eval_t *)((unsigned char *)prog->globals.generic + fieldoffset) : NULL) - -/*// this struct is the basic requirement for a qc prog -typedef struct prvm_pr_globalvars_s -{ - int pad[28]; -} prvm_pr_globalvars_t; -*/ -/* -extern mfunction_t *SV_PlayerPhysicsQC; -extern mfunction_t *EndFrameQC; -//KrimZon - SERVER COMMANDS IN QUAKEC -extern mfunction_t *SV_ParseClientCommandQC; -*/ -//============================================================================ -/* -typedef struct prvm_builtin_mem_s -{ - void (*init)(void); - void (*deinit)(void); - - void *mem; -} prvm_builtin_mem_t; -*/ +#define PRVM_GETEDICTFIELDVALUE(ed, fieldoffset) (fieldoffset >= 0 ? (prvm_eval_t *)((unsigned char *)ed->fields.vp + fieldoffset) : NULL) +#define PRVM_GETGLOBALFIELDVALUE(fieldoffset) (fieldoffset >= 0 ? (prvm_eval_t *)((unsigned char *)prog->globals.generic + fieldoffset) : NULL) //============================================================================ -/* -#define PRVM_FE_NEXTHINK 2 -#define PRVM_FE_THINK 4 -#define PRVM_FE_FRAME 8 -*/ -#define PRVM_FE_CLASSNAME 8 -#define PRVM_FE_CHAIN 4 #define PRVM_OP_STATE 1 #define PRVM_MAX_STACK_DEPTH 1024 @@ -253,6 +117,165 @@ typedef struct prvm_builtin_mem_s typedef void (*prvm_builtin_t) (void); +// NOTE: field offsets use -1 for NULL +typedef struct prvm_prog_fieldoffsets_s +{ + int classname; // common + int chain; // common - used by find builtins + int think; // common - used by OP_STATE + int nextthink; // common - used by OP_STATE + int frame; // common - used by OP_STATE + int angles; // common - used by changeyaw/changepitch + + int gravity; // ssqc + int button3; // ssqc + int button4; // ssqc + int button5; // ssqc + int button6; // ssqc + int button7; // ssqc + int button8; // ssqc + int button9; // ssqc + int button10; // ssqc + int button11; // ssqc + int button12; // ssqc + int button13; // ssqc + int button14; // ssqc + int button15; // ssqc + int button16; // ssqc + int buttonuse; // ssqc + int buttonchat; // ssqc + int glow_size; // ssqc + int glow_trail; // ssqc + int glow_color; // ssqc + int items2; // ssqc + int scale; // ssqc / csqc + int alpha; // ssqc / csqc + int renderamt; // ssqc - HalfLife support + int rendermode; // ssqc - HalfLife support + int fullbright; // ssqc - Nehahra support + int ammo_shells1; // ssqc - Dissolution of Eternity mission pack + int ammo_nails1; // ssqc - Dissolution of Eternity mission pack + int ammo_lava_nails; // ssqc - Dissolution of Eternity mission pack + int ammo_rockets1; // ssqc - Dissolution of Eternity mission pack + int ammo_multi_rockets; // ssqc - Dissolution of Eternity mission pack + int ammo_cells1; // ssqc - Dissolution of Eternity mission pack + int ammo_plasma; // ssqc - Dissolution of Eternity mission pack + int ideal_yaw; // ssqc / csqc + int yaw_speed; // ssqc / csqc + int idealpitch; // ssqc / csqc + int pitch_speed; // ssqc / csqc + int viewmodelforclient; // ssqc + int nodrawtoclient; // ssqc + int exteriormodeltoclient; // ssqc + int drawonlytoclient; // ssqc + int ping; // ssqc + int movement; // ssqc + int pmodel; // ssqc + int punchvector; // ssqc + int viewzoom; // ssqc + int clientcolors; // ssqc + int tag_entity; // ssqc + int tag_index; // ssqc + int light_lev; // ssqc + int color; // ssqc + int style; // ssqc + int pflags; // ssqc + int cursor_active; // ssqc + int cursor_screen; // ssqc + int cursor_trace_start; // ssqc + int cursor_trace_endpos; // ssqc + int cursor_trace_ent; // ssqc + int colormod; // ssqc / csqc + int playermodel; // ssqc + int playerskin; // ssqc + int SendEntity; // ssqc + int Version; // ssqc + int customizeentityforclient; // ssqc + int dphitcontentsmask; // ssqc + int contentstransition; // ssqc + //int fatness; // ssqc / csqc + //int dimension_hit; // ssqc / csqc + //int dimension_solid; // ssqc / csqc + + // csqc + int frame2; + int frame1time; + int frame2time; + int lerpfrac; + int renderflags; + //int forceshader; + int groundentity; + //int hull; + int effects; + //int tag_entity; + //int tag_index; + //int dphitcontentsmask; + + // mqc +} +prvm_prog_fieldoffsets_t; + +// NOTE: global offsets use -1 for NULL +typedef struct prvm_prog_globaloffsets_s +{ + // common + int self; + int time; + + // ssqc + int trace_dpstartcontents; + int trace_dphitcontents; + int trace_dphitq3surfaceflags; + int trace_dphittexturename; + int SV_InitCmd; + + // csqc + + // mqc +} +prvm_prog_globaloffsets_t; + +// these are initialized using PRVM_ED_FindFunction +// NOTE: function offsets use 0 for NULL +typedef struct prvm_prog_funcoffsets_s +{ + // common + + // ssqc + func_t SV_PlayerPhysics; + func_t SV_ParseClientCommand; + func_t SV_ChangeTeam; + func_t EndFrame; + func_t RestoreGame; + + // csqc + func_t CSQC_Init; + func_t CSQC_InputEvent; + func_t CSQC_UpdateView; + func_t CSQC_ConsoleCommand; + func_t CSQC_Shutdown; + func_t CSQC_Parse_TempEntity; //[515]: very helpfull when you want to create your own particles/decals/etc for effects that already exist + func_t CSQC_Parse_StuffCmd; + func_t CSQC_Parse_Print; + func_t CSQC_Parse_CenterPrint; + func_t CSQC_Ent_Update; + func_t CSQC_Ent_Remove; + func_t CSQC_Event; //[515]: engine call this for its own needs so csqc can do some things according to what engine it's running on. example: to say about edicts increase, whatever... + + // mqc + func_t m_init; +#ifdef NG_MENU + func_t m_display; + func_t m_hide; +#endif + func_t m_keydown; + func_t m_keyup; + func_t m_draw; + func_t m_toggle; + func_t m_shutdown; +} +prvm_prog_funcoffsets_t; + // [INIT] variables flagged with this token can be initialized by 'you' // NOTE: external code has to create and free the mempools but everything else is done by prvm ! typedef struct prvm_prog_s @@ -333,11 +356,9 @@ typedef struct prvm_prog_s // size of the engine private struct int edictprivate_size; // [INIT] - // has to be updated every frame - so the vm time is up-to-date - // AK changed so time will point to the time field (if there is one) else it points to _time - // actually should be double, but qc doesnt support it - float *time; - float _time; + prvm_prog_fieldoffsets_t fieldoffsets; + prvm_prog_globaloffsets_t globaloffsets; + prvm_prog_funcoffsets_t funcoffsets; // allow writing to world entity fields, this is set by server init and // cleared before first server frame @@ -442,10 +463,13 @@ void PRVM_PrintState(void); void PRVM_CrashAll (void); void PRVM_Crash (void); -int PRVM_ED_FindFieldOffset(const char *field); -int PRVM_ED_FindGlobalOffset(const char *global); -ddef_t *PRVM_ED_FindField (const char *name); -mfunction_t *PRVM_ED_FindFunction (const char *name); +ddef_t *PRVM_ED_FindField(const char *name); +ddef_t *PRVM_ED_FindGlobal(const char *name); +mfunction_t *PRVM_ED_FindFunction(const char *name); + +int PRVM_ED_FindFieldOffset(const char *name); +int PRVM_ED_FindGlobalOffset(const char *name); +func_t PRVM_ED_FindFunctionOffset(const char *name); void PRVM_MEM_IncreaseEdicts(void); @@ -545,7 +569,7 @@ Load a program with LoadProgs */ void PRVM_InitProg(int prognr); // LoadProgs expects to be called right after InitProg -void PRVM_LoadProgs (const char *filename, int numrequiredfunc, char **required_func, int numrequiredfields, prvm_required_field_t *required_field); +void PRVM_LoadProgs (const char *filename, int numrequiredfunc, char **required_func, int numrequiredfields, prvm_required_field_t *required_field, int numrequiredglobals, char **required_global); void PRVM_ResetProg(void); qboolean PRVM_ProgLoaded(int prognr); diff --git a/protocol.c b/protocol.c index 46408a59..5ceeed35 100644 --- a/protocol.c +++ b/protocol.c @@ -282,7 +282,7 @@ void EntityFrameCSQC_WriteFrame (sizebuf_t *msg, int numstates, const entity_sta prvm_eval_t *val, *val2; int csqcents = 0; - if(!eval_SendEntity || !eval_Version) + if(prog->fieldoffsets.SendEntity < 0 || prog->fieldoffsets.Version < 0) return; --csqc_clent; if(!sv2csqcents_version[csqc_clent]) @@ -323,10 +323,10 @@ void EntityFrameCSQC_WriteFrame (sizebuf_t *msg, int numstates, const entity_sta // if(!s->active) // continue; - val = PRVM_GETEDICTFIELDVALUE((&prog->edicts[s->number]), eval_SendEntity); + val = PRVM_GETEDICTFIELDVALUE((&prog->edicts[s->number]), prog->fieldoffsets.SendEntity); if(val->function) { - val2 = PRVM_GETEDICTFIELDVALUE((&prog->edicts[s->number]), eval_Version); + val2 = PRVM_GETEDICTFIELDVALUE((&prog->edicts[s->number]), prog->fieldoffsets.Version); if(sv2csqcents_version[csqc_clent][s->number] == (unsigned char)val2->_float) continue; if(!csqcents) @@ -391,7 +391,7 @@ void EntityFrameQuake_WriteFrame(sizebuf_t *msg, int numstates, const entity_sta for (i = 0, s = states;i < numstates;i++, s++) { - val = PRVM_GETEDICTFIELDVALUE((&prog->edicts[s->number]), eval_SendEntity); + val = PRVM_GETEDICTFIELDVALUE((&prog->edicts[s->number]), prog->fieldoffsets.SendEntity); if(val && val->function) continue; @@ -1048,7 +1048,7 @@ void EntityFrame_WriteFrame(sizebuf_t *msg, entityframe_database_t *d, int numst ent = states + i; number = ent->number; - val = PRVM_GETEDICTFIELDVALUE((&prog->edicts[number]), eval_SendEntity); + val = PRVM_GETEDICTFIELDVALUE((&prog->edicts[number]), prog->fieldoffsets.SendEntity); if(val && val->function) continue; for (;onum < o->numentities && o->entitydata[onum].number < number;onum++) @@ -1537,7 +1537,7 @@ void EntityFrame4_WriteFrame(sizebuf_t *msg, entityframe4_database_t *d, int num d->currententitynumber = 1; for (i = 0, n = startnumber;n < prog->max_edicts;n++) { - val = PRVM_GETEDICTFIELDVALUE((&prog->edicts[n]), eval_SendEntity); + val = PRVM_GETEDICTFIELDVALUE((&prog->edicts[n]), prog->fieldoffsets.SendEntity); if(val && val->function) continue; // find the old state to delta from @@ -1691,7 +1691,7 @@ void EntityState5_WriteUpdate(int number, const entity_state_t *s, int changedbi unsigned int bits = 0; prvm_eval_t *val; - val = PRVM_GETEDICTFIELDVALUE((&prog->edicts[s->number]), eval_SendEntity); + val = PRVM_GETEDICTFIELDVALUE((&prog->edicts[s->number]), prog->fieldoffsets.SendEntity); if(val && val->function) return; diff --git a/prvm_cmds.c b/prvm_cmds.c index 4a5bcd0b..8f15a2d5 100644 --- a/prvm_cmds.c +++ b/prvm_cmds.c @@ -112,9 +112,9 @@ void VM_error (void) VM_VarString(0, string, sizeof(string)); Con_Printf("======%s ERROR in %s:\n%s\n", PRVM_NAME, PRVM_GetString(prog->xfunction->s_name), string); - if(prog->self) + if (prog->globaloffsets.self >= 0) { - ed = PRVM_G_EDICT(prog->self->ofs); + ed = PRVM_PROG_TO_EDICT(PRVM_GETGLOBALFIELDVALUE(prog->globaloffsets.self)->edict); PRVM_ED_Print(ed); } @@ -138,9 +138,9 @@ void VM_objerror (void) VM_VarString(0, string, sizeof(string)); Con_Printf("======OBJECT ERROR======\n"); // , PRVM_NAME, PRVM_GetString(prog->xfunction->s_name), string); // or include them? FIXME - if(prog->self) + if (prog->globaloffsets.self >= 0) { - ed = PRVM_G_EDICT (prog->self->ofs); + ed = PRVM_PROG_TO_EDICT(PRVM_GETGLOBALFIELDVALUE(prog->globaloffsets.self)->edict); PRVM_ED_Print(ed); PRVM_ED_Free (ed); @@ -860,18 +860,14 @@ void VM_findchain (void) { int i; int f; - int chain_of; const char *s, *t; prvm_edict_t *ent, *chain; VM_SAFEPARMCOUNT(2,VM_findchain); - // is the same like !(prog->flag & PRVM_FE_CHAIN) - even if the operator precedence is another - if(!prog->flag & PRVM_FE_CHAIN) + if (prog->fieldoffsets.chain < 0) PRVM_ERROR("VM_findchain: %s doesnt have a chain field !", PRVM_NAME); - chain_of = PRVM_ED_FindField("chain")->ofs; - chain = prog->edicts; f = PRVM_G_INT(OFS_PARM0); @@ -893,7 +889,7 @@ void VM_findchain (void) if (strcmp(t,s)) continue; - PRVM_E_INT(ent,chain_of) = PRVM_NUM_FOR_EDICT(chain); + PRVM_E_INT(ent,prog->fieldoffsets.chain) = PRVM_NUM_FOR_EDICT(chain); chain = ent; } @@ -914,17 +910,14 @@ void VM_findchainfloat (void) { int i; int f; - int chain_of; float s; prvm_edict_t *ent, *chain; VM_SAFEPARMCOUNT(2, VM_findchainfloat); - if(!prog->flag & PRVM_FE_CHAIN) + if (prog->fieldoffsets.chain < 0) PRVM_ERROR("VM_findchainfloat: %s doesnt have a chain field !", PRVM_NAME); - chain_of = PRVM_ED_FindField("chain")->ofs; - chain = (prvm_edict_t *)prog->edicts; f = PRVM_G_INT(OFS_PARM0); @@ -939,7 +932,7 @@ void VM_findchainfloat (void) if (PRVM_E_FLOAT(ent,f) != s) continue; - PRVM_E_INT(ent,chain_of) = PRVM_EDICT_TO_PROG(chain); + PRVM_E_INT(ent,prog->fieldoffsets.chain) = PRVM_EDICT_TO_PROG(chain); chain = ent; } @@ -999,16 +992,13 @@ void VM_findchainflags (void) int i; int f; int s; - int chain_of; prvm_edict_t *ent, *chain; VM_SAFEPARMCOUNT(2, VM_findchainflags); - if(!prog->flag & PRVM_FE_CHAIN) + if (prog->fieldoffsets.chain < 0) PRVM_ERROR("VM_findchainflags: %s doesnt have a chain field !", PRVM_NAME); - chain_of = PRVM_ED_FindField("chain")->ofs; - chain = (prvm_edict_t *)prog->edicts; f = PRVM_G_INT(OFS_PARM0); @@ -1025,7 +1015,7 @@ void VM_findchainflags (void) if (!((int)PRVM_E_FLOAT(ent,f) & s)) continue; - PRVM_E_INT(ent,chain_of) = PRVM_EDICT_TO_PROG(chain); + PRVM_E_INT(ent,prog->fieldoffsets.chain) = PRVM_EDICT_TO_PROG(chain); chain = ent; } @@ -1504,42 +1494,6 @@ void VM_copyentity (void) memcpy(out->fields.vp, in->fields.vp, prog->progs->entityfields * 4); } -/* -================= -VM_setcolor - -sets the color of a client and broadcasts the update to all connected clients - -setcolor(clientent, value) -================= -*/ -/*void PF_setcolor (void) -{ - client_t *client; - int entnum, i; - prvm_eval_t *val; - - entnum = PRVM_G_EDICTNUM(OFS_PARM0); - i = PRVM_G_FLOAT(OFS_PARM1); - - if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active) - { - Con_Print("tried to setcolor a non-client\n"); - return; - } - - client = svs.clients + entnum-1; - if ((val = PRVM_GETEDICTFIELDVALUE(client->edict, eval_clientcolors))) - val->_float = i; - client->colors = i; - client->old_colors = i; - client->edict->fields.server->team = (i & 15) + 1; - - MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors); - MSG_WriteByte (&sv.reliable_datagram, entnum - 1); - MSG_WriteByte (&sv.reliable_datagram, i); -}*/ - void VM_Files_Init(void) { int i; @@ -2088,50 +2042,6 @@ void VM_argv (void) PRVM_G_INT(OFS_RETURN) = OFS_NULL; } -/* -//void(entity e, entity tagentity, string tagname) setattachment = #443; // attachs e to a tag on tagentity (note: use "" to attach to entity origin/angles instead of a tag) -void PF_setattachment (void) -{ - prvm_edict_t *e = PRVM_G_EDICT(OFS_PARM0); - prvm_edict_t *tagentity = PRVM_G_EDICT(OFS_PARM1); - char *tagname = PRVM_G_STRING(OFS_PARM2); - prvm_eval_t *v; - int i, modelindex; - model_t *model; - - if (tagentity == NULL) - tagentity = prog->edicts; - - v = PRVM_GETEDICTFIELDVALUE(e, eval_tag_entity); - if (v) - fields.server->edict = PRVM_EDICT_TO_PROG(tagentity); - - v = PRVM_GETEDICTFIELDVALUE(e, eval_tag_index); - if (v) - fields.server->_float = 0; - if (tagentity != NULL && tagentity != prog->edicts && tagname && tagname[0]) - { - modelindex = (int)tagentity->fields.server->modelindex; - if (modelindex >= 0 && modelindex < MAX_MODELS) - { - model = sv.models[modelindex]; - if (model->data_overridetagnamesforskin && (unsigned int)tagentity->fields.server->skin < (unsigned int)model->numskins && model->data_overridetagnamesforskin[(unsigned int)tagentity->fields.server->skin].num_overridetagnames) - for (i = 0;i < model->data_overridetagnamesforskin[(unsigned int)tagentity->fields.server->skin].num_overridetagnames;i++) - if (!strcmp(tagname, model->data_overridetagnamesforskin[(unsigned int)tagentity->fields.server->skin].data_overridetagnames[i].name)) - fields.server->_float = i + 1; - // FIXME: use a model function to get tag info (need to handle skeletal) - if (fields.server->_float == 0 && model->num_tags) - for (i = 0;i < model->num_tags;i++) - if (!strcmp(tagname, model->data_tags[i].name)) - fields.server->_float = i + 1; - if (fields.server->_float == 0) - Con_DPrintf("setattachment(edict %i, edict %i, string \"%s\"): tried to find tag named \"%s\" on entity %i (model \"%s\") but could not find it\n", PRVM_NUM_FOR_EDICT(e), PRVM_NUM_FOR_EDICT(tagentity), tagname, tagname, PRVM_NUM_FOR_EDICT(tagentity), model->name); - } - else - Con_DPrintf("setattachment(edict %i, edict %i, string \"%s\"): tried to find tag named \"%s\" on entity %i but it has no model\n", PRVM_NUM_FOR_EDICT(e), PRVM_NUM_FOR_EDICT(tagentity), tagname, tagname, PRVM_NUM_FOR_EDICT(tagentity)); - } -}*/ - /* ========= VM_isserver @@ -2228,7 +2138,7 @@ void VM_gettime(void) { VM_SAFEPARMCOUNT(0,VM_gettime); - PRVM_G_FLOAT(OFS_RETURN) = (float) *prog->time; + PRVM_G_FLOAT(OFS_RETURN) = (float) realtime; } /* @@ -3994,6 +3904,124 @@ void VM_bufstr_free (void) //============= +/* +============== +VM_changeyaw + +This was a major timewaster in progs, so it was converted to C +============== +*/ +void VM_changeyaw (void) +{ + prvm_edict_t *ent; + float ideal, current, move, speed; + + ent = PRVM_PROG_TO_EDICT(PRVM_GETGLOBALFIELDVALUE(prog->globaloffsets.self)->edict); + if (ent == prog->edicts) + { + VM_Warning("changeyaw: can not modify world entity\n"); + return; + } + if (ent->priv.server->free) + { + VM_Warning("changeyaw: can not modify free entity\n"); + return; + } + if (prog->fieldoffsets.angles < 0 || prog->fieldoffsets.ideal_yaw < 0 || prog->fieldoffsets.yaw_speed < 0) + { + VM_Warning("changeyaw: angles, ideal_yaw, or yaw_speed field(s) not found\n"); + return; + } + current = ANGLEMOD(PRVM_GETEDICTFIELDVALUE(ent, prog->fieldoffsets.angles)->vector[1]); + ideal = PRVM_GETEDICTFIELDVALUE(ent, prog->fieldoffsets.ideal_yaw)->_float; + speed = PRVM_GETEDICTFIELDVALUE(ent, prog->fieldoffsets.yaw_speed)->_float; + + if (current == ideal) + return; + move = ideal - current; + if (ideal > current) + { + if (move >= 180) + move = move - 360; + } + else + { + if (move <= -180) + move = move + 360; + } + if (move > 0) + { + if (move > speed) + move = speed; + } + else + { + if (move < -speed) + move = -speed; + } + + PRVM_GETEDICTFIELDVALUE(ent, prog->fieldoffsets.angles)->vector[1] = ANGLEMOD (current + move); +} + +/* +============== +VM_changepitch +============== +*/ +void VM_changepitch (void) +{ + prvm_edict_t *ent; + float ideal, current, move, speed; + + ent = PRVM_G_EDICT(OFS_PARM0); + if (ent == prog->edicts) + { + VM_Warning("changepitch: can not modify world entity\n"); + return; + } + if (ent->priv.server->free) + { + VM_Warning("changepitch: can not modify free entity\n"); + return; + } + if (prog->fieldoffsets.angles < 0 || prog->fieldoffsets.idealpitch < 0 || prog->fieldoffsets.pitch_speed < 0) + { + VM_Warning("changepitch: angles, idealpitch, or pitch_speed field(s) not found\n"); + return; + } + current = ANGLEMOD(PRVM_GETEDICTFIELDVALUE(ent, prog->fieldoffsets.angles)->vector[0]); + ideal = PRVM_GETEDICTFIELDVALUE(ent, prog->fieldoffsets.idealpitch)->_float; + speed = PRVM_GETEDICTFIELDVALUE(ent, prog->fieldoffsets.pitch_speed)->_float; + + if (current == ideal) + return; + move = ideal - current; + if (ideal > current) + { + if (move >= 180) + move = move - 360; + } + else + { + if (move <= -180) + move = move + 360; + } + if (move > 0) + { + if (move > speed) + move = speed; + } + else + { + if (move < -speed) + move = -speed; + } + + PRVM_GETEDICTFIELDVALUE(ent, prog->fieldoffsets.angles)->vector[0] = ANGLEMOD (current + move); +} + +//============= + void VM_Cmd_Init(void) { // only init the stuff for the current prog diff --git a/prvm_cmds.h b/prvm_cmds.h index 8f9fd6dc..98645894 100644 --- a/prvm_cmds.h +++ b/prvm_cmds.h @@ -367,5 +367,8 @@ void VM_bufstr_set (void); void VM_bufstr_add (void); void VM_bufstr_free (void); +void VM_changeyaw (void); +void VM_changepitch (void); + void VM_Cmd_Init(void); void VM_Cmd_Reset(void); diff --git a/prvm_edict.c b/prvm_edict.c index c7c6e61f..7226f0d7 100644 --- a/prvm_edict.c +++ b/prvm_edict.c @@ -122,20 +122,28 @@ int PRVM_ED_FindFieldOffset(const char *field) ddef_t *d; d = PRVM_ED_FindField(field); if (!d) - return 0; + return -1; return d->ofs*4; } -ddef_t* PRVM_ED_FindGlobal(const char *name); int PRVM_ED_FindGlobalOffset(const char *global) { ddef_t *d; d = PRVM_ED_FindGlobal(global); if (!d) - return 0; + return -1; return d->ofs*4; } +func_t PRVM_ED_FindFunctionOffset(const char *function) +{ + mfunction_t *f; + f = PRVM_ED_FindFunction(function); + if (!f) + return 0; + return (func_t)(f - prog->functions); +} + qboolean PRVM_ProgLoaded(int prognr) { if(prognr < 0 || prognr >= PRVM_MAXPROGS) @@ -232,7 +240,7 @@ prvm_edict_t *PRVM_ED_Alloc (void) e = PRVM_EDICT_NUM(i); // the first couple seconds of server time can involve a lot of // freeing and allocating, so relax the replacement policy - if (e->priv.required->free && ( e->priv.required->freetime < 2 || (*prog->time - e->priv.required->freetime) > 0.5 ) ) + if (e->priv.required->free && ( e->priv.required->freetime < 2 || prog->globaloffsets.time < 0 || (PRVM_GETGLOBALFIELDVALUE(prog->globaloffsets.time)->_float - e->priv.required->freetime) > 0.5 ) ) { PRVM_ED_ClearEdict (e); return e; @@ -269,7 +277,7 @@ void PRVM_ED_Free (prvm_edict_t *ed) PRVM_GCALL(free_edict)(ed); ed->priv.required->free = true; - ed->priv.required->freetime = *prog->time; + ed->priv.required->freetime = prog->globaloffsets.time >= 0 ? PRVM_GETGLOBALFIELDVALUE(prog->globaloffsets.time)->_float : 0; } //=========================================================================== @@ -1175,9 +1183,9 @@ void PRVM_ED_LoadFromFile (const char *data) // // immediately call spawn function, but only if there is a self global and a classname // - if(prog->self && prog->flag & PRVM_FE_CLASSNAME) + if(prog->globaloffsets.self >= 0 && prog->fieldoffsets.classname >= 0) { - string_t handle = *(string_t*)&((unsigned char*)ent->fields.vp)[PRVM_ED_FindFieldOffset("classname")]; + string_t handle = *(string_t*)&((unsigned char*)ent->fields.vp)[prog->fieldoffsets.classname]; if (!handle) { Con_Print("No classname for:\n"); @@ -1201,7 +1209,7 @@ void PRVM_ED_LoadFromFile (const char *data) } // self = ent - PRVM_G_INT(prog->self->ofs) = PRVM_EDICT_TO_PROG(ent); + PRVM_GETGLOBALFIELDVALUE(prog->globaloffsets.self)->edict = PRVM_EDICT_TO_PROG(ent); PRVM_ExecuteProgram (func - prog->functions, ""); } @@ -1213,6 +1221,146 @@ void PRVM_ED_LoadFromFile (const char *data) Con_DPrintf("%s: %i new entities parsed, %i new inhibited, %i (%i new) spawned (whereas %i removed self, %i stayed)\n", PRVM_NAME, parsed, inhibited, prog->num_edicts, spawned, died, spawned - died); } +void PRVM_FindOffsets(void) +{ + // field and global searches use -1 for NULL + memset(&prog->fieldoffsets, -1, sizeof(prog->fieldoffsets)); + memset(&prog->globaloffsets, -1, sizeof(prog->globaloffsets)); + // functions use 0 for NULL + memset(&prog->funcoffsets, 0, sizeof(prog->funcoffsets)); + + // common + prog->fieldoffsets.classname = PRVM_ED_FindFieldOffset("classname"); + prog->fieldoffsets.chain = PRVM_ED_FindFieldOffset("chain"); + prog->fieldoffsets.think = PRVM_ED_FindFieldOffset("think"); + prog->fieldoffsets.nextthink = PRVM_ED_FindFieldOffset("nextthink"); + prog->fieldoffsets.frame = PRVM_ED_FindFieldOffset("frame"); + prog->fieldoffsets.angles = PRVM_ED_FindFieldOffset("angles"); + prog->globaloffsets.self = PRVM_ED_FindGlobalOffset("self"); + prog->globaloffsets.time = PRVM_ED_FindGlobalOffset("time"); + + // ssqc + prog->fieldoffsets.gravity = PRVM_ED_FindFieldOffset("gravity"); + prog->fieldoffsets.button3 = PRVM_ED_FindFieldOffset("button3"); + prog->fieldoffsets.button4 = PRVM_ED_FindFieldOffset("button4"); + prog->fieldoffsets.button5 = PRVM_ED_FindFieldOffset("button5"); + prog->fieldoffsets.button6 = PRVM_ED_FindFieldOffset("button6"); + prog->fieldoffsets.button7 = PRVM_ED_FindFieldOffset("button7"); + prog->fieldoffsets.button8 = PRVM_ED_FindFieldOffset("button8"); + prog->fieldoffsets.button9 = PRVM_ED_FindFieldOffset("button9"); + prog->fieldoffsets.button10 = PRVM_ED_FindFieldOffset("button10"); + prog->fieldoffsets.button11 = PRVM_ED_FindFieldOffset("button11"); + prog->fieldoffsets.button12 = PRVM_ED_FindFieldOffset("button12"); + prog->fieldoffsets.button13 = PRVM_ED_FindFieldOffset("button13"); + prog->fieldoffsets.button14 = PRVM_ED_FindFieldOffset("button14"); + prog->fieldoffsets.button15 = PRVM_ED_FindFieldOffset("button15"); + prog->fieldoffsets.button16 = PRVM_ED_FindFieldOffset("button16"); + prog->fieldoffsets.buttonuse = PRVM_ED_FindFieldOffset("buttonuse"); + prog->fieldoffsets.buttonchat = PRVM_ED_FindFieldOffset("buttonchat"); + prog->fieldoffsets.glow_size = PRVM_ED_FindFieldOffset("glow_size"); + prog->fieldoffsets.glow_trail = PRVM_ED_FindFieldOffset("glow_trail"); + prog->fieldoffsets.glow_color = PRVM_ED_FindFieldOffset("glow_color"); + prog->fieldoffsets.items2 = PRVM_ED_FindFieldOffset("items2"); + prog->fieldoffsets.scale = PRVM_ED_FindFieldOffset("scale"); + prog->fieldoffsets.alpha = PRVM_ED_FindFieldOffset("alpha"); + prog->fieldoffsets.renderamt = PRVM_ED_FindFieldOffset("renderamt"); // HalfLife support + prog->fieldoffsets.rendermode = PRVM_ED_FindFieldOffset("rendermode"); // HalfLife support + prog->fieldoffsets.fullbright = PRVM_ED_FindFieldOffset("fullbright"); + prog->fieldoffsets.ammo_shells1 = PRVM_ED_FindFieldOffset("ammo_shells1"); + prog->fieldoffsets.ammo_nails1 = PRVM_ED_FindFieldOffset("ammo_nails1"); + prog->fieldoffsets.ammo_lava_nails = PRVM_ED_FindFieldOffset("ammo_lava_nails"); + prog->fieldoffsets.ammo_rockets1 = PRVM_ED_FindFieldOffset("ammo_rockets1"); + prog->fieldoffsets.ammo_multi_rockets = PRVM_ED_FindFieldOffset("ammo_multi_rockets"); + prog->fieldoffsets.ammo_cells1 = PRVM_ED_FindFieldOffset("ammo_cells1"); + prog->fieldoffsets.ammo_plasma = PRVM_ED_FindFieldOffset("ammo_plasma"); + prog->fieldoffsets.ideal_yaw = PRVM_ED_FindFieldOffset("ideal_yaw"); + prog->fieldoffsets.yaw_speed = PRVM_ED_FindFieldOffset("yaw_speed"); + prog->fieldoffsets.idealpitch = PRVM_ED_FindFieldOffset("idealpitch"); + prog->fieldoffsets.pitch_speed = PRVM_ED_FindFieldOffset("pitch_speed"); + prog->fieldoffsets.viewmodelforclient = PRVM_ED_FindFieldOffset("viewmodelforclient"); + prog->fieldoffsets.nodrawtoclient = PRVM_ED_FindFieldOffset("nodrawtoclient"); + prog->fieldoffsets.exteriormodeltoclient = PRVM_ED_FindFieldOffset("exteriormodeltoclient"); + prog->fieldoffsets.drawonlytoclient = PRVM_ED_FindFieldOffset("drawonlytoclient"); + prog->fieldoffsets.ping = PRVM_ED_FindFieldOffset("ping"); + prog->fieldoffsets.movement = PRVM_ED_FindFieldOffset("movement"); + prog->fieldoffsets.pmodel = PRVM_ED_FindFieldOffset("pmodel"); + prog->fieldoffsets.punchvector = PRVM_ED_FindFieldOffset("punchvector"); + prog->fieldoffsets.viewzoom = PRVM_ED_FindFieldOffset("viewzoom"); + prog->fieldoffsets.clientcolors = PRVM_ED_FindFieldOffset("clientcolors"); + prog->fieldoffsets.tag_entity = PRVM_ED_FindFieldOffset("tag_entity"); + prog->fieldoffsets.tag_index = PRVM_ED_FindFieldOffset("tag_index"); + prog->fieldoffsets.light_lev = PRVM_ED_FindFieldOffset("light_lev"); + prog->fieldoffsets.color = PRVM_ED_FindFieldOffset("color"); + prog->fieldoffsets.style = PRVM_ED_FindFieldOffset("style"); + prog->fieldoffsets.pflags = PRVM_ED_FindFieldOffset("pflags"); + prog->fieldoffsets.cursor_active = PRVM_ED_FindFieldOffset("cursor_active"); + prog->fieldoffsets.cursor_screen = PRVM_ED_FindFieldOffset("cursor_screen"); + prog->fieldoffsets.cursor_trace_start = PRVM_ED_FindFieldOffset("cursor_trace_start"); + prog->fieldoffsets.cursor_trace_endpos = PRVM_ED_FindFieldOffset("cursor_trace_endpos"); + prog->fieldoffsets.cursor_trace_ent = PRVM_ED_FindFieldOffset("cursor_trace_ent"); + prog->fieldoffsets.colormod = PRVM_ED_FindFieldOffset("colormod"); + prog->fieldoffsets.playermodel = PRVM_ED_FindFieldOffset("playermodel"); + prog->fieldoffsets.playerskin = PRVM_ED_FindFieldOffset("playerskin"); + prog->fieldoffsets.SendEntity = PRVM_ED_FindFieldOffset("SendEntity"); + prog->fieldoffsets.Version = PRVM_ED_FindFieldOffset("Version"); + prog->fieldoffsets.customizeentityforclient = PRVM_ED_FindFieldOffset("customizeentityforclient"); + prog->fieldoffsets.dphitcontentsmask = PRVM_ED_FindFieldOffset("dphitcontentsmask"); + prog->fieldoffsets.contentstransition = PRVM_ED_FindFieldOffset("contentstransition"); + prog->globaloffsets.trace_dpstartcontents = PRVM_ED_FindGlobalOffset("trace_dpstartcontents"); + prog->globaloffsets.trace_dphitcontents = PRVM_ED_FindGlobalOffset("trace_dphitcontents"); + prog->globaloffsets.trace_dphitq3surfaceflags = PRVM_ED_FindGlobalOffset("trace_dphitq3surfaceflags"); + prog->globaloffsets.trace_dphittexturename = PRVM_ED_FindGlobalOffset("trace_dphittexturename"); + prog->globaloffsets.SV_InitCmd = PRVM_ED_FindGlobalOffset("SV_InitCmd"); + prog->funcoffsets.SV_ParseClientCommand = PRVM_ED_FindFunctionOffset("SV_ParseClientCommand"); + prog->funcoffsets.SV_PlayerPhysics = PRVM_ED_FindFunctionOffset("SV_PlayerPhysics"); + prog->funcoffsets.SV_ChangeTeam = PRVM_ED_FindFunctionOffset("SV_ChangeTeam"); + prog->funcoffsets.EndFrame = PRVM_ED_FindFunctionOffset("EndFrame"); + prog->funcoffsets.RestoreGame = PRVM_ED_FindFunctionOffset("RestoreGame"); + + // csqc + prog->fieldoffsets.alpha = PRVM_ED_FindFieldOffset("alpha"); + prog->fieldoffsets.scale = PRVM_ED_FindFieldOffset("scale"); + //prog->fieldoffsets.fatness = PRVM_ED_FindFieldOffset("fatness"); + prog->fieldoffsets.frame2 = PRVM_ED_FindFieldOffset("frame2"); + prog->fieldoffsets.frame1time = PRVM_ED_FindFieldOffset("frame1time"); + prog->fieldoffsets.frame2time = PRVM_ED_FindFieldOffset("frame2time"); + prog->fieldoffsets.lerpfrac = PRVM_ED_FindFieldOffset("lerpfrac"); + prog->fieldoffsets.renderflags = PRVM_ED_FindFieldOffset("renderflags"); + //prog->fieldoffsets.forceshader = PRVM_ED_FindFieldOffset("forceshader"); + //prog->fieldoffsets.dimension_hit = PRVM_ED_FindFieldOffset("dimension_hit"); + //prog->fieldoffsets.dimension_solid = PRVM_ED_FindFieldOffset("dimension_solid"); + //prog->fieldoffsets.groundentity = PRVM_ED_FindFieldOffset("groundentity"); + //prog->fieldoffsets.hull = PRVM_ED_FindFieldOffset("hull"); + prog->fieldoffsets.colormod = PRVM_ED_FindFieldOffset("colormod"); + prog->fieldoffsets.effects = PRVM_ED_FindFieldOffset("effects"); + prog->fieldoffsets.tag_entity = PRVM_ED_FindFieldOffset("tag_entity"); + prog->fieldoffsets.tag_index = PRVM_ED_FindFieldOffset("tag_index"); + prog->funcoffsets.CSQC_Init = PRVM_ED_FindFunctionOffset("CSQC_Init"); + prog->funcoffsets.CSQC_InputEvent = PRVM_ED_FindFunctionOffset("CSQC_InputEvent"); + prog->funcoffsets.CSQC_UpdateView = PRVM_ED_FindFunctionOffset("CSQC_UpdateView"); + prog->funcoffsets.CSQC_ConsoleCommand = PRVM_ED_FindFunctionOffset("CSQC_ConsoleCommand"); + prog->funcoffsets.CSQC_Shutdown = PRVM_ED_FindFunctionOffset("CSQC_Shutdown"); + prog->funcoffsets.CSQC_Parse_TempEntity = PRVM_ED_FindFunctionOffset("CSQC_Parse_TempEntity"); + prog->funcoffsets.CSQC_Parse_StuffCmd = PRVM_ED_FindFunctionOffset("CSQC_Parse_StuffCmd"); + prog->funcoffsets.CSQC_Parse_Print = PRVM_ED_FindFunctionOffset("CSQC_Parse_Print"); + prog->funcoffsets.CSQC_Parse_CenterPrint = PRVM_ED_FindFunctionOffset("CSQC_Parse_CenterPrint"); + prog->funcoffsets.CSQC_Ent_Update = PRVM_ED_FindFunctionOffset("CSQC_Ent_Update"); + prog->funcoffsets.CSQC_Ent_Remove = PRVM_ED_FindFunctionOffset("CSQC_Ent_Remove"); + prog->funcoffsets.CSQC_Event = PRVM_ED_FindFunctionOffset("CSQC_Event"); + + // mqc + prog->funcoffsets.m_init = PRVM_ED_FindFunctionOffset("m_init"); +#ifdef NG_MENU + prog->funcoffsets.m_display = PRVM_ED_FindFunctionOffset("m_display"); + prog->funcoffsets.m_hide = PRVM_ED_FindFunctionOffset("m_hide"); +#endif + prog->funcoffsets.m_keydown = PRVM_ED_FindFunctionOffset("m_keydown"); + prog->funcoffsets.m_keyup = PRVM_ED_FindFunctionOffset("m_keyup"); + prog->funcoffsets.m_draw = PRVM_ED_FindFunctionOffset("m_draw"); + prog->funcoffsets.m_toggle = PRVM_ED_FindFunctionOffset("m_toggle"); + prog->funcoffsets.m_shutdown = PRVM_ED_FindFunctionOffset("m_shutdown"); +} + // not used /* typedef struct dpfield_s @@ -1294,7 +1442,7 @@ void PRVM_LoadLNO( const char *progname ) { PRVM_LoadProgs =============== */ -void PRVM_LoadProgs (const char * filename, int numrequiredfunc, char **required_func, int numrequiredfields, prvm_required_field_t *required_field) +void PRVM_LoadProgs (const char * filename, int numrequiredfunc, char **required_func, int numrequiredfields, prvm_required_field_t *required_field, int numrequiredglobals, char **required_global) { int i; dstatement_t *st; @@ -1412,6 +1560,11 @@ void PRVM_LoadProgs (const char * filename, int numrequiredfunc, char **required if(PRVM_ED_FindFunction(required_func[i]) == 0) PRVM_ERROR("%s: %s not found in %s",PRVM_NAME, required_func[i], filename); + // check required globals + for(i=0 ; i < numrequiredglobals ; i++) + if(PRVM_ED_FindGlobal(required_global[i]) == 0) + PRVM_ERROR("%s: %s not found in %s",PRVM_NAME, required_global[i], filename); + for (i=0 ; iprogs->numglobals ; i++) ((int *)prog->globals.generic)[i] = LittleLong (((int *)prog->globals.generic)[i]); @@ -1529,19 +1682,10 @@ void PRVM_LoadProgs (const char * filename, int numrequiredfunc, char **required prog->flag = 0; - prog->self = PRVM_ED_FindGlobal("self"); - - if( PRVM_ED_FindGlobal("time") && PRVM_ED_FindGlobal("time")->type & ev_float ) - prog->time = &PRVM_G_FLOAT(PRVM_ED_FindGlobal("time")->ofs); - - if(PRVM_ED_FindField ("chain")) - prog->flag |= PRVM_FE_CHAIN; - - if(PRVM_ED_FindField ("classname")) - prog->flag |= PRVM_FE_CLASSNAME; + PRVM_FindOffsets(); - if(PRVM_ED_FindField ("nextthink") && PRVM_ED_FindField ("frame") && PRVM_ED_FindField ("think") - && prog->flag && prog->self) + // check if OP_STATE animation is possible in this dat file + if (prog->fieldoffsets.nextthink >= 0 && prog->fieldoffsets.frame >= 0 && prog->fieldoffsets.think >= 0 && prog->globaloffsets.self >= 0) prog->flag |= PRVM_OP_STATE; PRVM_GCALL(init_cmd)(); @@ -1794,7 +1938,6 @@ void PRVM_InitProg(int prognr) memset(prog, 0, sizeof(prvm_prog_t)); - prog->time = &prog->_time; prog->error_cmd = Host_Error; } diff --git a/prvm_exec.c b/prvm_exec.c index 1d05c082..8a04550e 100644 --- a/prvm_exec.c +++ b/prvm_exec.c @@ -488,8 +488,6 @@ PRVM_ExecuteProgram extern cvar_t prvm_boundscheck; extern cvar_t prvm_traceqc; extern cvar_t prvm_statementprofiling; -extern int PRVM_ED_FindFieldOffset (const char *field); -extern ddef_t* PRVM_ED_FindGlobal(const char *name); extern sizebuf_t vm_tempstringsbuf; void PRVM_ExecuteProgram (func_t fnum, const char *errormessage) { @@ -502,8 +500,8 @@ void PRVM_ExecuteProgram (func_t fnum, const char *errormessage) if (!fnum || fnum >= (unsigned int)prog->progs->numfunctions) { - if (prog->self && PRVM_G_INT(prog->self->ofs)) - PRVM_ED_Print(PRVM_PROG_TO_EDICT(PRVM_G_INT(prog->self->ofs))); + if (prog->globaloffsets.self >= 0 && PRVM_GETGLOBALFIELDVALUE(prog->globaloffsets.self)->edict) + PRVM_ED_Print(PRVM_PROG_TO_EDICT(PRVM_GETGLOBALFIELDVALUE(prog->globaloffsets.self)->edict)); PRVM_ERROR ("PRVM_ExecuteProgram: %s", errormessage); } diff --git a/prvm_execprogram.h b/prvm_execprogram.h index 26fafb81..10549bcf 100644 --- a/prvm_execprogram.h +++ b/prvm_execprogram.h @@ -333,10 +333,10 @@ case OP_STATE: if(prog->flag & PRVM_OP_STATE) { - ed = PRVM_PROG_TO_EDICT(PRVM_G_INT(prog->self->ofs)); - PRVM_E_FLOAT(ed,PRVM_ED_FindField ("nextthink")->ofs) = *prog->time + 0.1; - PRVM_E_FLOAT(ed,PRVM_ED_FindField ("frame")->ofs) = OPA->_float; - *(func_t *)((float*)ed->fields.vp + PRVM_ED_FindField ("think")->ofs) = OPB->function; + ed = PRVM_PROG_TO_EDICT(PRVM_GETGLOBALFIELDVALUE(prog->globaloffsets.self)->edict); + PRVM_GETEDICTFIELDVALUE(ed,prog->fieldoffsets.nextthink)->_float = PRVM_GETGLOBALFIELDVALUE(prog->globaloffsets.time)->_float + 0.1; + PRVM_GETEDICTFIELDVALUE(ed,prog->fieldoffsets.frame)->_float = OPA->_float; + PRVM_GETEDICTFIELDVALUE(ed,prog->fieldoffsets.think)->function = OPB->function; } else { diff --git a/quakedef.h b/quakedef.h index f0738de0..aeae68fc 100644 --- a/quakedef.h +++ b/quakedef.h @@ -213,6 +213,7 @@ extern char engineversion[128]; #include "sbar.h" #include "sound.h" #include "model_shared.h" +#include "world.h" #include "client.h" #include "render.h" #include "progs.h" @@ -220,7 +221,6 @@ extern char engineversion[128]; #include "server.h" #include "input.h" -#include "world.h" #include "keys.h" #include "console.h" #include "menu.h" diff --git a/server.h b/server.h index d835aeef..ba73d8f2 100644 --- a/server.h +++ b/server.h @@ -73,6 +73,9 @@ typedef struct server_s int csqc_progsize; // -1 = no progs char csqc_progname[MAX_QPATH]; // copied from csqc_progname at level start + // collision culling data + world_t world; + // map name char name[64]; // maps/.bsp, for model_precache[0] @@ -355,7 +358,29 @@ qboolean SV_PlayerCheckGround (prvm_edict_t *ent); qboolean SV_CheckBottom (prvm_edict_t *ent); qboolean SV_movestep (prvm_edict_t *ent, vec3_t move, qboolean relink); -struct trace_s SV_ClipMoveToEntity(prvm_edict_t *ent, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int movetype, int hitsupercontents); +// Needs to be called any time an entity changes origin, mins, maxs, or solid +// sets ent->v.absmin and ent->v.absmax +// if touchtriggers, calls prog functions for the intersected triggers +void SV_LinkEdict (prvm_edict_t *ent, qboolean touch_triggers); + +// traces a box move against a single entity +// mins and maxs are relative +// +// if the entire move stays in a single solid brush, trace.allsolid will be set +// +// if the starting point is in a solid, it will be allowed to move out to an +// open area, and trace.startsolid will be set +// +// type is one of the MOVE_ values such as MOVE_NOMONSTERS which skips box +// entities, only colliding with SOLID_BSP entities (doors, lifts) +// +// passedict is excluded from clipping checks +struct trace_s SV_Move_ClipToEntity(prvm_edict_t *ent, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int movetype, int hitsupercontents); + +// traces a box move against worldmodel and all entities in the specified area +trace_t SV_Move(const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int type, prvm_edict_t *passedict); + +#define SV_PointSuperContents(point) (SV_Move((point), vec3_origin, vec3_origin, (point), sv_gameplayfix_swiminbmodels.integer ? MOVE_NOMONSTERS : MOVE_WORLDONLY, NULL).startsupercontents) void SV_WriteClientdataToMessage (client_t *client, prvm_edict_t *ent, sizebuf_t *msg, int *stats); diff --git a/sv_main.c b/sv_main.c index 94957da3..271928e6 100644 --- a/sv_main.c +++ b/sv_main.c @@ -77,11 +77,15 @@ mempool_t *sv_mempool = NULL; //============================================================================ extern void SV_Phys_Init (void); -extern void SV_World_Init (void); static void SV_SaveEntFile_f(void); static void SV_StartDownload_f(void); static void SV_Download_f(void); +void SV_AreaStats_f(void) +{ + World_PrintAreaStats(&sv.world, "server"); +} + /* =============== SV_Init @@ -99,6 +103,7 @@ void SV_Init (void) Cvar_RegisterVariable (&csqc_progsize); Cmd_AddCommand("sv_saveentfile", SV_SaveEntFile_f, "save map entities to .ent file (to allow external editing)"); + Cmd_AddCommand("sv_areastats", SV_AreaStats_f, "prints statistics on entity culling during collision traces"); Cmd_AddCommand_WithClientCommand("sv_startdownload", NULL, SV_StartDownload_f, "begins sending a file to the client (network protocol use only)"); Cmd_AddCommand_WithClientCommand("download", NULL, SV_Download_f, "downloads a specified file from the server"); Cvar_RegisterVariable (&sv_maxvelocity); @@ -146,7 +151,6 @@ void SV_Init (void) SV_VM_Init(); SV_Phys_Init(); - SV_World_Init(); sv_mempool = Mem_AllocPool("server", 0, NULL); } @@ -371,14 +375,14 @@ void SV_SendServerinfo (client_t *client) { prvm_eval_t *val; Con_DPrintf("sending csqc info to client (\"%s\" with size %i and crc %i)\n", sv.csqc_progname, sv.csqc_progsize, sv.csqc_progcrc); - //[515]: init stufftext string (it is sent before svc_serverinfo) - val = PRVM_GETGLOBALFIELDVALUE(PRVM_ED_FindGlobalOffset("SV_InitCmd")); MSG_WriteByte (&client->netconnection->message, svc_stufftext); MSG_WriteString (&client->netconnection->message, va("csqc_progname %s\n", sv.csqc_progname)); MSG_WriteByte (&client->netconnection->message, svc_stufftext); MSG_WriteString (&client->netconnection->message, va("csqc_progsize %i\n", sv.csqc_progsize)); MSG_WriteByte (&client->netconnection->message, svc_stufftext); MSG_WriteString (&client->netconnection->message, va("csqc_progcrc %i\n", sv.csqc_progcrc)); + //[515]: init stufftext string (it is sent before svc_serverinfo) + val = PRVM_GETGLOBALFIELDVALUE(prog->globaloffsets.SV_InitCmd); if (val) { MSG_WriteByte (&client->netconnection->message, svc_stufftext); @@ -557,21 +561,21 @@ qboolean SV_PrepareEntityForSending (prvm_edict_t *ent, entity_state_t *cs, int modelindex = (i >= 1 && i < MAX_MODELS && *PRVM_GetString(ent->fields.server->model)) ? i : 0; flags = 0; - i = (int)(PRVM_GETEDICTFIELDVALUE(ent, eval_glow_size)->_float * 0.25f); + i = (int)(PRVM_GETEDICTFIELDVALUE(ent, prog->fieldoffsets.glow_size)->_float * 0.25f); glowsize = (unsigned char)bound(0, i, 255); - if (PRVM_GETEDICTFIELDVALUE(ent, eval_glow_trail)->_float) + if (PRVM_GETEDICTFIELDVALUE(ent, prog->fieldoffsets.glow_trail)->_float) flags |= RENDER_GLOWTRAIL; - f = PRVM_GETEDICTFIELDVALUE(ent, eval_color)->vector[0]*256; + f = PRVM_GETEDICTFIELDVALUE(ent, prog->fieldoffsets.color)->vector[0]*256; light[0] = (unsigned short)bound(0, f, 65535); - f = PRVM_GETEDICTFIELDVALUE(ent, eval_color)->vector[1]*256; + f = PRVM_GETEDICTFIELDVALUE(ent, prog->fieldoffsets.color)->vector[1]*256; light[1] = (unsigned short)bound(0, f, 65535); - f = PRVM_GETEDICTFIELDVALUE(ent, eval_color)->vector[2]*256; + f = PRVM_GETEDICTFIELDVALUE(ent, prog->fieldoffsets.color)->vector[2]*256; light[2] = (unsigned short)bound(0, f, 65535); - f = PRVM_GETEDICTFIELDVALUE(ent, eval_light_lev)->_float; + f = PRVM_GETEDICTFIELDVALUE(ent, prog->fieldoffsets.light_lev)->_float; light[3] = (unsigned short)bound(0, f, 65535); - lightstyle = (unsigned char)PRVM_GETEDICTFIELDVALUE(ent, eval_style)->_float; - lightpflags = (unsigned char)PRVM_GETEDICTFIELDVALUE(ent, eval_pflags)->_float; + lightstyle = (unsigned char)PRVM_GETEDICTFIELDVALUE(ent, prog->fieldoffsets.style)->_float; + lightpflags = (unsigned char)PRVM_GETEDICTFIELDVALUE(ent, prog->fieldoffsets.pflags)->_float; if (gamemode == GAME_TENEBRAE) { @@ -622,7 +626,7 @@ qboolean SV_PrepareEntityForSending (prvm_edict_t *ent, entity_state_t *cs, int // early culling checks // (final culling is done by SV_MarkWriteEntityStateToClient) - customizeentityforclient = PRVM_GETEDICTFIELDVALUE(ent, eval_customizeentityforclient)->function; + customizeentityforclient = PRVM_GETEDICTFIELDVALUE(ent, prog->fieldoffsets.customizeentityforclient)->function; if (!customizeentityforclient) { if (e > svs.maxclients && (!modelindex && !specialvisibilityradius)) @@ -645,18 +649,18 @@ qboolean SV_PrepareEntityForSending (prvm_edict_t *ent, entity_state_t *cs, int cs->modelindex = modelindex; cs->skin = (unsigned)ent->fields.server->skin; cs->frame = (unsigned)ent->fields.server->frame; - cs->viewmodelforclient = PRVM_GETEDICTFIELDVALUE(ent, eval_viewmodelforclient)->edict; - cs->exteriormodelforclient = PRVM_GETEDICTFIELDVALUE(ent, eval_exteriormodeltoclient)->edict; - cs->nodrawtoclient = PRVM_GETEDICTFIELDVALUE(ent, eval_nodrawtoclient)->edict; - cs->drawonlytoclient = PRVM_GETEDICTFIELDVALUE(ent, eval_drawonlytoclient)->edict; + cs->viewmodelforclient = PRVM_GETEDICTFIELDVALUE(ent, prog->fieldoffsets.viewmodelforclient)->edict; + cs->exteriormodelforclient = PRVM_GETEDICTFIELDVALUE(ent, prog->fieldoffsets.exteriormodeltoclient)->edict; + cs->nodrawtoclient = PRVM_GETEDICTFIELDVALUE(ent, prog->fieldoffsets.nodrawtoclient)->edict; + cs->drawonlytoclient = PRVM_GETEDICTFIELDVALUE(ent, prog->fieldoffsets.drawonlytoclient)->edict; cs->customizeentityforclient = customizeentityforclient; - cs->tagentity = PRVM_GETEDICTFIELDVALUE(ent, eval_tag_entity)->edict; - cs->tagindex = (unsigned char)PRVM_GETEDICTFIELDVALUE(ent, eval_tag_index)->_float; + cs->tagentity = PRVM_GETEDICTFIELDVALUE(ent, prog->fieldoffsets.tag_entity)->edict; + cs->tagindex = (unsigned char)PRVM_GETEDICTFIELDVALUE(ent, prog->fieldoffsets.tag_index)->_float; cs->glowsize = glowsize; // don't need to init cs->colormod because the defaultstate did that for us //cs->colormod[0] = cs->colormod[1] = cs->colormod[2] = 32; - val = PRVM_GETEDICTFIELDVALUE(ent, eval_colormod); + val = PRVM_GETEDICTFIELDVALUE(ent, prog->fieldoffsets.colormod); if (val->vector[0] || val->vector[1] || val->vector[2]) { i = (int)(val->vector[0] * 32.0f);cs->colormod[0] = bound(0, i, 255); @@ -667,14 +671,14 @@ qboolean SV_PrepareEntityForSending (prvm_edict_t *ent, entity_state_t *cs, int cs->modelindex = modelindex; cs->alpha = 255; - f = (PRVM_GETEDICTFIELDVALUE(ent, eval_alpha)->_float * 255.0f); + f = (PRVM_GETEDICTFIELDVALUE(ent, prog->fieldoffsets.alpha)->_float * 255.0f); if (f) { i = (int)f; cs->alpha = (unsigned char)bound(0, i, 255); } // halflife - f = (PRVM_GETEDICTFIELDVALUE(ent, eval_renderamt)->_float); + f = (PRVM_GETEDICTFIELDVALUE(ent, prog->fieldoffsets.renderamt)->_float); if (f) { i = (int)f; @@ -682,7 +686,7 @@ qboolean SV_PrepareEntityForSending (prvm_edict_t *ent, entity_state_t *cs, int } cs->scale = 16; - f = (PRVM_GETEDICTFIELDVALUE(ent, eval_scale)->_float * 16.0f); + f = (PRVM_GETEDICTFIELDVALUE(ent, prog->fieldoffsets.scale)->_float * 16.0f); if (f) { i = (int)f; @@ -690,11 +694,11 @@ qboolean SV_PrepareEntityForSending (prvm_edict_t *ent, entity_state_t *cs, int } cs->glowcolor = 254; - f = (PRVM_GETEDICTFIELDVALUE(ent, eval_glow_color)->_float); + f = (PRVM_GETEDICTFIELDVALUE(ent, prog->fieldoffsets.glow_color)->_float); if (f) cs->glowcolor = (int)f; - if (PRVM_GETEDICTFIELDVALUE(ent, eval_fullbright)->_float) + if (PRVM_GETEDICTFIELDVALUE(ent, prog->fieldoffsets.fullbright)->_float) cs->effects |= EF_FULLBRIGHT; if (ent->fields.server->movetype == MOVETYPE_STEP) @@ -1056,14 +1060,14 @@ void SV_WriteClientdataToMessage (client_t *client, prvm_edict_t *ent, sizebuf_t // stuff the sigil bits into the high bits of items for sbar, or else // mix in items2 - val = PRVM_GETEDICTFIELDVALUE(ent, eval_items2); + val = PRVM_GETEDICTFIELDVALUE(ent, prog->fieldoffsets.items2); if (gamemode == GAME_HIPNOTIC || gamemode == GAME_ROGUE) items = (int)ent->fields.server->items | ((int)val->_float << 23); else items = (int)ent->fields.server->items | ((int)prog->globals.server->serverflags << 28); VectorClear(punchvector); - if ((val = PRVM_GETEDICTFIELDVALUE(ent, eval_punchvector))) + if ((val = PRVM_GETEDICTFIELDVALUE(ent, prog->fieldoffsets.punchvector))) VectorCopy(val->vector, punchvector); // cache weapon model name and index in client struct to save time @@ -1076,7 +1080,7 @@ void SV_WriteClientdataToMessage (client_t *client, prvm_edict_t *ent, sizebuf_t } viewzoom = 255; - if ((val = PRVM_GETEDICTFIELDVALUE(ent, eval_viewzoom))) + if ((val = PRVM_GETEDICTFIELDVALUE(ent, prog->fieldoffsets.viewzoom))) viewzoom = (int)(val->_float * 255.0f); if (viewzoom == 0) viewzoom = 255; @@ -1380,7 +1384,7 @@ void SV_UpdateToReliableMessages (void) // DP_SV_CLIENTCOLORS // this is always found (since it's added by the progs loader) - if ((val = PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_clientcolors))) + if ((val = PRVM_GETEDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.clientcolors))) host_client->colors = (int)val->_float; if (host_client->old_colors != host_client->colors) { @@ -1392,23 +1396,23 @@ void SV_UpdateToReliableMessages (void) } // NEXUIZ_PLAYERMODEL - if( eval_playermodel ) { - model = PRVM_GetString(PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_playermodel)->string); + if( prog->fieldoffsets.playermodel >= 0 ) { + model = PRVM_GetString(PRVM_GETEDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.playermodel)->string); if (model == NULL) model = ""; // always point the string back at host_client->name to keep it safe strlcpy (host_client->playermodel, model, sizeof (host_client->playermodel)); - PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_playermodel)->string = PRVM_SetEngineString(host_client->playermodel); + PRVM_GETEDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.playermodel)->string = PRVM_SetEngineString(host_client->playermodel); } // NEXUIZ_PLAYERSKIN - if( eval_playerskin ) { - skin = PRVM_GetString(PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_playerskin)->string); + if( prog->fieldoffsets.playerskin >= 0 ) { + skin = PRVM_GetString(PRVM_GETEDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.playerskin)->string); if (skin == NULL) skin = ""; // always point the string back at host_client->name to keep it safe strlcpy (host_client->playerskin, skin, sizeof (host_client->playerskin)); - PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_playerskin)->string = PRVM_SetEngineString(host_client->playerskin); + PRVM_GETEDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.playerskin)->string = PRVM_SetEngineString(host_client->playerskin); } // frags @@ -1837,7 +1841,7 @@ void SV_IncreaseEdicts(void) SV_UnlinkEdict(prog->edicts + i); memset(&ent->priv.server->areagrid, 0, sizeof(ent->priv.server->areagrid)); } - SV_ClearWorld(); + World_Clear(&sv.world); prog->max_edicts = min(prog->max_edicts + 256, MAX_EDICTS); prog->edictprivate = PR_Alloc(prog->max_edicts * sizeof(edict_engineprivate_t)); @@ -2010,7 +2014,7 @@ void SV_SpawnServer (const char *server) prog->allowworldwrites = true; sv.paused = false; - *prog->time = sv.time = 1.0; + prog->globals.server->time = sv.time = 1.0; Mod_ClearUsed(); worldmodel->used = true; @@ -2023,7 +2027,9 @@ void SV_SpawnServer (const char *server) // // clear world interaction links // - SV_ClearWorld (); + VectorCopy(sv.worldmodel->normalmins, sv.world.areagrid_mins); + VectorCopy(sv.worldmodel->normalmaxs, sv.world.areagrid_maxs); + World_Clear(&sv.world); strlcpy(sv.sound_precache[0], "", sizeof(sv.sound_precache[0])); @@ -2151,10 +2157,10 @@ void SV_VM_CB_BeginIncreaseEdicts(void) for (i = 0, ent = prog->edicts;i < prog->max_edicts;i++, ent++) { if (!ent->priv.server->free) - SV_UnlinkEdict(prog->edicts + i); + World_UnlinkEdict(prog->edicts + i); memset(&ent->priv.server->areagrid, 0, sizeof(ent->priv.server->areagrid)); } - SV_ClearWorld(); + World_Clear(&sv.world); } void SV_VM_CB_EndIncreaseEdicts(void) @@ -2162,12 +2168,10 @@ void SV_VM_CB_EndIncreaseEdicts(void) int i; prvm_edict_t *ent; - for (i = 0, ent = prog->edicts;i < prog->max_edicts;i++, ent++) - { - // link every entity except world + // link every entity except world + for (i = 1, ent = prog->edicts;i < prog->max_edicts;i++, ent++) if (!ent->priv.server->free) SV_LinkEdict(ent, false); - } } void SV_VM_CB_InitEdict(prvm_edict_t *e) @@ -2187,19 +2191,19 @@ void SV_VM_CB_InitEdict(prvm_edict_t *e) // DP_SV_CLIENTNAME and DP_SV_CLIENTCOLORS will not immediately // reset them e->fields.server->netname = PRVM_SetEngineString(svs.clients[num].name); - if ((val = PRVM_GETEDICTFIELDVALUE(e, eval_clientcolors))) + if ((val = PRVM_GETEDICTFIELDVALUE(e, prog->fieldoffsets.clientcolors))) val->_float = svs.clients[num].colors; // NEXUIZ_PLAYERMODEL and NEXUIZ_PLAYERSKIN - if( eval_playermodel ) - PRVM_GETEDICTFIELDVALUE(e, eval_playermodel)->string = PRVM_SetEngineString(svs.clients[num].playermodel); - if( eval_playerskin ) - PRVM_GETEDICTFIELDVALUE(e, eval_playerskin)->string = PRVM_SetEngineString(svs.clients[num].playerskin); + if( prog->fieldoffsets.playermodel >= 0 ) + PRVM_GETEDICTFIELDVALUE(e, prog->fieldoffsets.playermodel)->string = PRVM_SetEngineString(svs.clients[num].playermodel); + if( prog->fieldoffsets.playerskin >= 0 ) + PRVM_GETEDICTFIELDVALUE(e, prog->fieldoffsets.playerskin)->string = PRVM_SetEngineString(svs.clients[num].playerskin); } } void SV_VM_CB_FreeEdict(prvm_edict_t *ed) { - SV_UnlinkEdict (ed); // unlink from world bsp + World_UnlinkEdict(ed); // unlink from world bsp ed->fields.server->model = 0; ed->fields.server->takedamage = 0; @@ -2338,163 +2342,6 @@ void SV_VM_Init(void) Cvar_RegisterVariable (&cutscene); // for Nehahra but useful to other mods as well } -// LordHavoc: in an effort to eliminate time wasted on GetEdictFieldValue... these are defined as externs in progs.h -int eval_gravity; -int eval_button3; -int eval_button4; -int eval_button5; -int eval_button6; -int eval_button7; -int eval_button8; -int eval_button9; -int eval_button10; -int eval_button11; -int eval_button12; -int eval_button13; -int eval_button14; -int eval_button15; -int eval_button16; -int eval_buttonuse; -int eval_buttonchat; -int eval_glow_size; -int eval_glow_trail; -int eval_glow_color; -int eval_items2; -int eval_scale; -int eval_alpha; -int eval_renderamt; // HalfLife support -int eval_rendermode; // HalfLife support -int eval_fullbright; -int eval_ammo_shells1; -int eval_ammo_nails1; -int eval_ammo_lava_nails; -int eval_ammo_rockets1; -int eval_ammo_multi_rockets; -int eval_ammo_cells1; -int eval_ammo_plasma; -int eval_idealpitch; -int eval_pitch_speed; -int eval_viewmodelforclient; -int eval_nodrawtoclient; -int eval_exteriormodeltoclient; -int eval_drawonlytoclient; -int eval_ping; -int eval_movement; -int eval_pmodel; -int eval_punchvector; -int eval_viewzoom; -int eval_clientcolors; -int eval_tag_entity; -int eval_tag_index; -int eval_light_lev; -int eval_color; -int eval_style; -int eval_pflags; -int eval_cursor_active; -int eval_cursor_screen; -int eval_cursor_trace_start; -int eval_cursor_trace_endpos; -int eval_cursor_trace_ent; -int eval_colormod; -int eval_playermodel; -int eval_playerskin; -int eval_SendEntity; -int eval_Version; -int eval_customizeentityforclient; -int eval_dphitcontentsmask; -// DRESK - Support for Entity Contents Transition Event -int eval_contentstransition; - -int gval_trace_dpstartcontents; -int gval_trace_dphitcontents; -int gval_trace_dphitq3surfaceflags; -int gval_trace_dphittexturename; - -mfunction_t *SV_PlayerPhysicsQC; -mfunction_t *EndFrameQC; -//KrimZon - SERVER COMMANDS IN QUAKEC -mfunction_t *SV_ParseClientCommandQC; - -void SV_VM_FindEdictFieldOffsets(void) -{ - eval_gravity = PRVM_ED_FindFieldOffset("gravity"); - eval_button3 = PRVM_ED_FindFieldOffset("button3"); - eval_button4 = PRVM_ED_FindFieldOffset("button4"); - eval_button5 = PRVM_ED_FindFieldOffset("button5"); - eval_button6 = PRVM_ED_FindFieldOffset("button6"); - eval_button7 = PRVM_ED_FindFieldOffset("button7"); - eval_button8 = PRVM_ED_FindFieldOffset("button8"); - eval_button9 = PRVM_ED_FindFieldOffset("button9"); - eval_button10 = PRVM_ED_FindFieldOffset("button10"); - eval_button11 = PRVM_ED_FindFieldOffset("button11"); - eval_button12 = PRVM_ED_FindFieldOffset("button12"); - eval_button13 = PRVM_ED_FindFieldOffset("button13"); - eval_button14 = PRVM_ED_FindFieldOffset("button14"); - eval_button15 = PRVM_ED_FindFieldOffset("button15"); - eval_button16 = PRVM_ED_FindFieldOffset("button16"); - eval_buttonuse = PRVM_ED_FindFieldOffset("buttonuse"); - eval_buttonchat = PRVM_ED_FindFieldOffset("buttonchat"); - eval_glow_size = PRVM_ED_FindFieldOffset("glow_size"); - eval_glow_trail = PRVM_ED_FindFieldOffset("glow_trail"); - eval_glow_color = PRVM_ED_FindFieldOffset("glow_color"); - eval_items2 = PRVM_ED_FindFieldOffset("items2"); - eval_scale = PRVM_ED_FindFieldOffset("scale"); - eval_alpha = PRVM_ED_FindFieldOffset("alpha"); - eval_renderamt = PRVM_ED_FindFieldOffset("renderamt"); // HalfLife support - eval_rendermode = PRVM_ED_FindFieldOffset("rendermode"); // HalfLife support - eval_fullbright = PRVM_ED_FindFieldOffset("fullbright"); - eval_ammo_shells1 = PRVM_ED_FindFieldOffset("ammo_shells1"); - eval_ammo_nails1 = PRVM_ED_FindFieldOffset("ammo_nails1"); - eval_ammo_lava_nails = PRVM_ED_FindFieldOffset("ammo_lava_nails"); - eval_ammo_rockets1 = PRVM_ED_FindFieldOffset("ammo_rockets1"); - eval_ammo_multi_rockets = PRVM_ED_FindFieldOffset("ammo_multi_rockets"); - eval_ammo_cells1 = PRVM_ED_FindFieldOffset("ammo_cells1"); - eval_ammo_plasma = PRVM_ED_FindFieldOffset("ammo_plasma"); - eval_idealpitch = PRVM_ED_FindFieldOffset("idealpitch"); - eval_pitch_speed = PRVM_ED_FindFieldOffset("pitch_speed"); - eval_viewmodelforclient = PRVM_ED_FindFieldOffset("viewmodelforclient"); - eval_nodrawtoclient = PRVM_ED_FindFieldOffset("nodrawtoclient"); - eval_exteriormodeltoclient = PRVM_ED_FindFieldOffset("exteriormodeltoclient"); - eval_drawonlytoclient = PRVM_ED_FindFieldOffset("drawonlytoclient"); - eval_ping = PRVM_ED_FindFieldOffset("ping"); - eval_movement = PRVM_ED_FindFieldOffset("movement"); - eval_pmodel = PRVM_ED_FindFieldOffset("pmodel"); - eval_punchvector = PRVM_ED_FindFieldOffset("punchvector"); - eval_viewzoom = PRVM_ED_FindFieldOffset("viewzoom"); - eval_clientcolors = PRVM_ED_FindFieldOffset("clientcolors"); - eval_tag_entity = PRVM_ED_FindFieldOffset("tag_entity"); - eval_tag_index = PRVM_ED_FindFieldOffset("tag_index"); - eval_light_lev = PRVM_ED_FindFieldOffset("light_lev"); - eval_color = PRVM_ED_FindFieldOffset("color"); - eval_style = PRVM_ED_FindFieldOffset("style"); - eval_pflags = PRVM_ED_FindFieldOffset("pflags"); - eval_cursor_active = PRVM_ED_FindFieldOffset("cursor_active"); - eval_cursor_screen = PRVM_ED_FindFieldOffset("cursor_screen"); - eval_cursor_trace_start = PRVM_ED_FindFieldOffset("cursor_trace_start"); - eval_cursor_trace_endpos = PRVM_ED_FindFieldOffset("cursor_trace_endpos"); - eval_cursor_trace_ent = PRVM_ED_FindFieldOffset("cursor_trace_ent"); - eval_colormod = PRVM_ED_FindFieldOffset("colormod"); - eval_playermodel = PRVM_ED_FindFieldOffset("playermodel"); - eval_playerskin = PRVM_ED_FindFieldOffset("playerskin"); - eval_SendEntity = PRVM_ED_FindFieldOffset("SendEntity"); - eval_Version = PRVM_ED_FindFieldOffset("Version"); - eval_customizeentityforclient = PRVM_ED_FindFieldOffset("customizeentityforclient"); - eval_dphitcontentsmask = PRVM_ED_FindFieldOffset("dphitcontentsmask"); - // DRESK - Support for Entity Contents Transition Event - eval_contentstransition = PRVM_ED_FindFieldOffset("contentstransition"); - - // LordHavoc: allowing QuakeC to override the player movement code - SV_PlayerPhysicsQC = PRVM_ED_FindFunction ("SV_PlayerPhysics"); - // LordHavoc: support for endframe - EndFrameQC = PRVM_ED_FindFunction ("EndFrame"); - //KrimZon - SERVER COMMANDS IN QUAKEC - SV_ParseClientCommandQC = PRVM_ED_FindFunction ("SV_ParseClientCommand"); - gval_trace_dpstartcontents = PRVM_ED_FindGlobalOffset("trace_dpstartcontents"); - gval_trace_dphitcontents = PRVM_ED_FindGlobalOffset("trace_dphitcontents"); - gval_trace_dphitq3surfaceflags = PRVM_ED_FindGlobalOffset("trace_dphitq3surfaceflags"); - gval_trace_dphittexturename = PRVM_ED_FindGlobalOffset("trace_dphittexturename"); -} - #define REQFIELDS (sizeof(reqfields) / sizeof(prvm_required_field_t)) prvm_required_field_t reqfields[] = @@ -2599,8 +2446,7 @@ void SV_VM_Setup(void) prog->error_cmd = Host_Error; // TODO: add a requiredfuncs list (ask LH if this is necessary at all) - PRVM_LoadProgs( sv_progs.string, 0, NULL, REQFIELDS, reqfields ); - SV_VM_FindEdictFieldOffsets(); + PRVM_LoadProgs( sv_progs.string, 0, NULL, REQFIELDS, reqfields, 0, NULL ); VM_AutoSentStats_Clear();//[515]: csqc EntityFrameCSQC_ClearVersions();//[515]: csqc @@ -2623,7 +2469,7 @@ void SV_VM_Begin(void) PRVM_Begin; PRVM_SetProg( PRVM_SERVERPROG ); - *prog->time = (float) sv.time; + prog->globals.server->time = (float) sv.time; } void SV_VM_End(void) diff --git a/sv_move.c b/sv_move.c index e89415fe..bd7404c1 100644 --- a/sv_move.c +++ b/sv_move.c @@ -222,14 +222,14 @@ facing it. ====================== */ -void PF_changeyaw (void); +void VM_changeyaw (void); qboolean SV_StepDirection (prvm_edict_t *ent, float yaw, float dist) { vec3_t move, oldorigin; float delta; ent->fields.server->ideal_yaw = yaw; - PF_changeyaw(); + VM_changeyaw(); yaw = yaw*M_PI*2 / 360; move[0] = cos(yaw)*dist; @@ -367,9 +367,9 @@ qboolean SV_CloseEnough (prvm_edict_t *ent, prvm_edict_t *goal, float dist) for (i=0 ; i<3 ; i++) { - if (goal->fields.server->absmin[i] > ent->fields.server->absmax[i] + dist) + if (goal->priv.server->areamins[i] > ent->priv.server->areamaxs[i] + dist) return false; - if (goal->fields.server->absmax[i] < ent->fields.server->absmin[i] - dist) + if (goal->priv.server->areamaxs[i] < ent->priv.server->areamins[i] - dist) return false; } return true; diff --git a/sv_phys.c b/sv_phys.c index f44932f2..9cf79ae4 100644 --- a/sv_phys.c +++ b/sv_phys.c @@ -51,6 +51,7 @@ cvar_t sv_wallfriction = {CVAR_NOTIFY, "sv_wallfriction", "1", "how much you slo cvar_t sv_newflymove = {CVAR_NOTIFY, "sv_newflymove", "0", "enables simpler/buggier player physics (not recommended)"}; cvar_t sv_freezenonclients = {CVAR_NOTIFY, "sv_freezenonclients", "0", "freezes time, except for players, allowing you to walk around and take screenshots of explosions"}; cvar_t sv_playerphysicsqc = {CVAR_NOTIFY, "sv_playerphysicsqc", "1", "enables QuakeC function to override player physics"}; +cvar_t sv_debugmove = {CVAR_NOTIFY, "sv_debugmove", "0", "disables collision detection optimizations for debugging purposes"}; cvar_t sv_sound_watersplash = {0, "sv_sound_watersplash", "misc/h2ohit1.wav", "sound to play when MOVETYPE_FLY/TOSS/BOUNCE/STEP entity enters or leaves water (empty cvar disables the sound)"}; cvar_t sv_sound_land = {0, "sv_sound_land", "demon/dland2.wav", "sound to play when MOVETYPE_STEP entity hits the ground at high speed (empty cvar disables the sound)"}; @@ -69,13 +70,497 @@ void SV_Phys_Init (void) Cvar_RegisterVariable(&sv_wallfriction); Cvar_RegisterVariable(&sv_newflymove); Cvar_RegisterVariable(&sv_freezenonclients); - Cvar_RegisterVariable(&sv_playerphysicsqc); + Cvar_RegisterVariable(&sv_debugmove); Cvar_RegisterVariable(&sv_sound_watersplash); Cvar_RegisterVariable(&sv_sound_land); } +/* +=============================================================================== + +LINE TESTING IN HULLS + +=============================================================================== +*/ + +/* +================== +SV_Move_ClipToEntity + +Handles selection or creation of a clipping hull, and offseting (and +eventually rotation) of the end points +================== +*/ +trace_t SV_Move_ClipToEntity(prvm_edict_t *ent, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int movetype, int hitsupercontents) +{ + trace_t trace; + model_t *model = NULL; + matrix4x4_t matrix, imatrix; + float tempnormal[3], starttransformed[3], endtransformed[3]; + + memset(&trace, 0, sizeof(trace)); + trace.fraction = trace.realfraction = 1; + VectorCopy(end, trace.endpos); + + if ((int) ent->fields.server->solid == SOLID_BSP || movetype == MOVE_HITMODEL) + { + unsigned int modelindex = (unsigned int)ent->fields.server->modelindex; + // if the modelindex is 0, it shouldn't be SOLID_BSP! + if (modelindex == 0) + { + Con_Printf("SV_Move_ClipToEntity: edict %i: SOLID_BSP with no model\n", PRVM_NUM_FOR_EDICT(ent)); + return trace; + } + if (modelindex >= MAX_MODELS) + { + Con_Printf("SV_Move_ClipToEntity: edict %i: SOLID_BSP with invalid modelindex\n", PRVM_NUM_FOR_EDICT(ent)); + return trace; + } + model = sv.models[modelindex]; + if (modelindex != 0 && model == NULL) + { + Con_Printf("SV_Move_ClipToEntity: edict %i: SOLID_BSP with invalid modelindex\n", PRVM_NUM_FOR_EDICT(ent)); + return trace; + } + + if ((int) ent->fields.server->solid == SOLID_BSP) + { + if (!model->TraceBox) + { + Con_Printf("SV_Move_ClipToEntity: edict %i: SOLID_BSP with a non-collidable model\n", PRVM_NUM_FOR_EDICT(ent)); + return trace; + } + //if ((int) ent->fields.server->movetype != MOVETYPE_PUSH) + //{ + // Con_Printf("SV_Move_ClipToEntity: edict %i: SOLID_BSP without MOVETYPE_PUSH\n", PRVM_NUM_FOR_EDICT(ent)); + // return trace; + //} + } + Matrix4x4_CreateFromQuakeEntity(&matrix, ent->fields.server->origin[0], ent->fields.server->origin[1], ent->fields.server->origin[2], ent->fields.server->angles[0], ent->fields.server->angles[1], ent->fields.server->angles[2], 1); + } + else + Matrix4x4_CreateTranslate(&matrix, ent->fields.server->origin[0], ent->fields.server->origin[1], ent->fields.server->origin[2]); + + Matrix4x4_Invert_Simple(&imatrix, &matrix); + Matrix4x4_Transform(&imatrix, start, starttransformed); + Matrix4x4_Transform(&imatrix, end, endtransformed); +#if COLLISIONPARANOID >= 3 + Con_Printf("trans(%f %f %f -> %f %f %f, %f %f %f -> %f %f %f)", start[0], start[1], start[2], starttransformed[0], starttransformed[1], starttransformed[2], end[0], end[1], end[2], endtransformed[0], endtransformed[1], endtransformed[2]); +#endif + + if (model && model->TraceBox) + { + int frame; + frame = (int)ent->fields.server->frame; + frame = bound(0, frame, (model->numframes - 1)); + model->TraceBox(model, frame, &trace, starttransformed, mins, maxs, endtransformed, hitsupercontents); + } + else + Collision_ClipTrace_Box(&trace, ent->fields.server->mins, ent->fields.server->maxs, starttransformed, mins, maxs, endtransformed, hitsupercontents, ent->fields.server->solid == SOLID_CORPSE ? SUPERCONTENTS_CORPSE : SUPERCONTENTS_BODY, 0, NULL); + trace.fraction = bound(0, trace.fraction, 1); + trace.realfraction = bound(0, trace.realfraction, 1); + + if (trace.fraction < 1) + { + VectorLerp(start, trace.fraction, end, trace.endpos); + VectorCopy(trace.plane.normal, tempnormal); + Matrix4x4_Transform3x3(&matrix, tempnormal, trace.plane.normal); + // FIXME: should recalc trace.plane.dist + } + else + VectorCopy(end, trace.endpos); + + return trace; +} + +/* +================== +SV_Move_ClipToWorld +================== +*/ +trace_t SV_Move_ClipToWorld(const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int movetype, int hitsupercontents) +{ + trace_t trace; + memset(&trace, 0, sizeof(trace)); + trace.fraction = trace.realfraction = 1; + sv.worldmodel->TraceBox(sv.worldmodel, 0, &trace, start, mins, maxs, end, hitsupercontents); + trace.fraction = bound(0, trace.fraction, 1); + trace.realfraction = bound(0, trace.realfraction, 1); + VectorLerp(start, trace.fraction, end, trace.endpos); + return trace; +} + +/* +================== +SV_Move +================== +*/ +#if COLLISIONPARANOID >= 1 +trace_t SV_Move_(const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int type, prvm_edict_t *passedict) +#else +trace_t SV_Move(const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int type, prvm_edict_t *passedict) +#endif +{ + vec3_t hullmins, hullmaxs; + int i; + int hitsupercontentsmask; + int passedictprog; + qboolean pointtrace; + prvm_edict_t *traceowner, *touch; + prvm_eval_t *val; + trace_t trace; + // bounding box of entire move area + vec3_t clipboxmins, clipboxmaxs; + // size of the moving object + vec3_t clipmins, clipmaxs; + // size when clipping against monsters + vec3_t clipmins2, clipmaxs2; + // start and end origin of move + vec3_t clipstart, clipend; + // trace results + trace_t cliptrace; + int numtouchedicts; + prvm_edict_t *touchedicts[MAX_EDICTS]; + + VectorCopy(start, clipstart); + VectorCopy(end, clipend); + VectorCopy(mins, clipmins); + VectorCopy(maxs, clipmaxs); + VectorCopy(mins, clipmins2); + VectorCopy(maxs, clipmaxs2); +#if COLLISIONPARANOID >= 3 + Con_Printf("move(%f %f %f,%f %f %f)", clipstart[0], clipstart[1], clipstart[2], clipend[0], clipend[1], clipend[2]); +#endif + + if (passedict) + { + val = PRVM_GETEDICTFIELDVALUE(passedict, prog->fieldoffsets.dphitcontentsmask); + if (val && val->_float) + hitsupercontentsmask = (int)val->_float; + else if (passedict->fields.server->solid == SOLID_SLIDEBOX) + { + if ((int)passedict->fields.server->flags & FL_MONSTER) + hitsupercontentsmask = SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_MONSTERCLIP; + else + hitsupercontentsmask = SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_PLAYERCLIP; + } + else if (passedict->fields.server->solid == SOLID_CORPSE) + hitsupercontentsmask = SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY; + else + hitsupercontentsmask = SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_CORPSE; + } + else + hitsupercontentsmask = SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_CORPSE; + + // clip to world + cliptrace = SV_Move_ClipToWorld(clipstart, clipmins, clipmaxs, clipend, type, hitsupercontentsmask); + cliptrace.bmodelstartsolid = cliptrace.startsolid; + if (cliptrace.startsolid || cliptrace.fraction < 1) + cliptrace.ent = prog->edicts; + if (type == MOVE_WORLDONLY) + return cliptrace; + + if (type == MOVE_MISSILE) + { + // LordHavoc: modified this, was = -15, now -= 15 + for (i = 0;i < 3;i++) + { + clipmins2[i] -= 15; + clipmaxs2[i] += 15; + } + } + + // get adjusted box for bmodel collisions if the world is q1bsp or hlbsp + if (sv.worldmodel && sv.worldmodel->brush.RoundUpToHullSize) + sv.worldmodel->brush.RoundUpToHullSize(sv.worldmodel, clipmins, clipmaxs, hullmins, hullmaxs); + else + { + VectorCopy(clipmins, hullmins); + VectorCopy(clipmaxs, hullmaxs); + } + + // create the bounding box of the entire move + for (i = 0;i < 3;i++) + { + clipboxmins[i] = min(clipstart[i], cliptrace.endpos[i]) + min(hullmins[i], clipmins2[i]) - 1; + clipboxmaxs[i] = max(clipstart[i], cliptrace.endpos[i]) + max(hullmaxs[i], clipmaxs2[i]) + 1; + } + + // debug override to test against everything + if (sv_debugmove.integer) + { + clipboxmins[0] = clipboxmins[1] = clipboxmins[2] = -999999999; + clipboxmaxs[0] = clipboxmaxs[1] = clipboxmaxs[2] = 999999999; + } + + // if the passedict is world, make it NULL (to avoid two checks each time) + if (passedict == prog->edicts) + passedict = NULL; + // precalculate prog value for passedict for comparisons + passedictprog = PRVM_EDICT_TO_PROG(passedict); + // figure out whether this is a point trace for comparisons + pointtrace = VectorCompare(clipmins, clipmaxs); + // precalculate passedict's owner edict pointer for comparisons + traceowner = passedict ? PRVM_PROG_TO_EDICT(passedict->fields.server->owner) : 0; + + // clip to entities + numtouchedicts = World_EntitiesInBox(&sv.world, clipboxmins, clipboxmaxs, MAX_EDICTS, touchedicts); + if (numtouchedicts > MAX_EDICTS) + { + // this never happens + Con_Printf("SV_EntitiesInBox returned %i edicts, max was %i\n", numtouchedicts, MAX_EDICTS); + numtouchedicts = MAX_EDICTS; + } + for (i = 0;i < numtouchedicts;i++) + { + touch = touchedicts[i]; + + if (touch->fields.server->solid < SOLID_BBOX) + continue; + if (type == MOVE_NOMONSTERS && touch->fields.server->solid != SOLID_BSP) + continue; + + if (passedict) + { + // don't clip against self + if (passedict == touch) + continue; + // don't clip owned entities against owner + if (traceowner == touch) + continue; + // don't clip owner against owned entities + if (passedictprog == touch->fields.server->owner) + continue; + // don't clip points against points (they can't collide) + if (pointtrace && VectorCompare(touch->fields.server->mins, touch->fields.server->maxs) && (type != MOVE_MISSILE || !((int)touch->fields.server->flags & FL_MONSTER))) + continue; + } + + // might interact, so do an exact clip + if ((int)touch->fields.server->flags & FL_MONSTER) + trace = SV_Move_ClipToEntity(touch, clipstart, clipmins2, clipmaxs2, clipend, type, hitsupercontentsmask); + else + trace = SV_Move_ClipToEntity(touch, clipstart, clipmins, clipmaxs, clipend, type, hitsupercontentsmask); + // LordHavoc: take the 'best' answers from the new trace and combine with existing data + if (trace.allsolid) + cliptrace.allsolid = true; + if (trace.startsolid) + { + if (touch->fields.server->solid == SOLID_BSP) + cliptrace.bmodelstartsolid = true; + cliptrace.startsolid = true; + if (cliptrace.realfraction == 1) + cliptrace.ent = touch; + } + // don't set this except on the world, because it can easily confuse + // monsters underwater if there's a bmodel involved in the trace + // (inopen && inwater is how they check water visibility) + //if (trace.inopen) + // cliptrace.inopen = true; + if (trace.inwater) + cliptrace.inwater = true; + if (trace.realfraction < cliptrace.realfraction) + { + cliptrace.fraction = trace.fraction; + cliptrace.realfraction = trace.realfraction; + VectorCopy(trace.endpos, cliptrace.endpos); + cliptrace.plane = trace.plane; + cliptrace.ent = touch; + cliptrace.hitsupercontents = trace.hitsupercontents; + cliptrace.hitq3surfaceflags = trace.hitq3surfaceflags; + cliptrace.hittexture = trace.hittexture; + } + cliptrace.startsupercontents |= trace.startsupercontents; + } + + return cliptrace; +} + +#if COLLISIONPARANOID >= 1 +trace_t SV_Move(const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int type, prvm_edict_t *passedict) +{ + int endstuck; + trace_t trace; + vec3_t temp; + trace = SV_Move_(start, mins, maxs, end, type, passedict); + if (passedict) + { + VectorCopy(trace.endpos, temp); + endstuck = SV_Move_(temp, mins, maxs, temp, type, passedict).startsolid; +#if COLLISIONPARANOID < 3 + if (trace.startsolid || endstuck) +#endif + Con_Printf("%s{e%i:%f %f %f:%f %f %f:%f:%f %f %f%s%s}\n", (trace.startsolid || endstuck) ? "^3" : "", passedict ? (int)(passedict - prog->edicts) : -1, passedict->fields.server->origin[0], passedict->fields.server->origin[1], passedict->fields.server->origin[2], end[0] - passedict->fields.server->origin[0], end[1] - passedict->fields.server->origin[1], end[2] - passedict->fields.server->origin[2], trace.fraction, trace.endpos[0] - passedict->fields.server->origin[0], trace.endpos[1] - passedict->fields.server->origin[1], trace.endpos[2] - passedict->fields.server->origin[2], trace.startsolid ? " startstuck" : "", endstuck ? " endstuck" : ""); + } + return trace; +} +#endif + +/* +=============================================================================== + +Linking entities into the world culling system + +=============================================================================== +*/ + +void SV_LinkEdict_TouchAreaGrid(prvm_edict_t *ent) +{ + int i, numtouchedicts, old_self, old_other; + prvm_edict_t *touch, *touchedicts[MAX_EDICTS]; + + // build a list of edicts to touch, because the link loop can be corrupted + // by SV_IncreaseEdicts called during touch functions + numtouchedicts = World_EntitiesInBox(&sv.world, ent->priv.server->areamins, ent->priv.server->areamaxs, MAX_EDICTS, touchedicts); + if (numtouchedicts > MAX_EDICTS) + { + // this never happens + Con_Printf("SV_EntitiesInBox returned %i edicts, max was %i\n", numtouchedicts, MAX_EDICTS); + numtouchedicts = MAX_EDICTS; + } + + old_self = prog->globals.server->self; + old_other = prog->globals.server->other; + for (i = 0;i < numtouchedicts;i++) + { + touch = touchedicts[i]; + if (touch != ent && (int)touch->fields.server->solid == SOLID_TRIGGER && touch->fields.server->touch) + { + prvm_eval_t *val; + prog->globals.server->self = PRVM_EDICT_TO_PROG(touch); + prog->globals.server->other = PRVM_EDICT_TO_PROG(ent); + prog->globals.server->time = sv.time; + prog->globals.server->trace_allsolid = false; + prog->globals.server->trace_startsolid = false; + prog->globals.server->trace_fraction = 1; + prog->globals.server->trace_inwater = false; + prog->globals.server->trace_inopen = true; + VectorCopy (touch->fields.server->origin, prog->globals.server->trace_endpos); + VectorSet (prog->globals.server->trace_plane_normal, 0, 0, 1); + prog->globals.server->trace_plane_dist = 0; + prog->globals.server->trace_ent = PRVM_EDICT_TO_PROG(ent); + if ((val = PRVM_GETGLOBALFIELDVALUE(prog->globaloffsets.trace_dpstartcontents))) + val->_float = 0; + if ((val = PRVM_GETGLOBALFIELDVALUE(prog->globaloffsets.trace_dphitcontents))) + val->_float = 0; + if ((val = PRVM_GETGLOBALFIELDVALUE(prog->globaloffsets.trace_dphitq3surfaceflags))) + val->_float = 0; + if ((val = PRVM_GETGLOBALFIELDVALUE(prog->globaloffsets.trace_dphittexturename))) + val->string = 0; + PRVM_ExecuteProgram (touch->fields.server->touch, "QC function self.touch is missing"); + } + } + prog->globals.server->self = old_self; + prog->globals.server->other = old_other; +} + +/* +=============== +SV_LinkEdict + +=============== +*/ +void SV_LinkEdict (prvm_edict_t *ent, qboolean touch_triggers) +{ + model_t *model; + vec3_t mins, maxs; + + if (ent == prog->edicts) + return; // don't add the world + + if (ent->priv.server->free) + return; + +// set the abs box + + if (ent->fields.server->solid == SOLID_BSP) + { + int modelindex = (int)ent->fields.server->modelindex; + if (modelindex < 0 || modelindex > MAX_MODELS) + { + Con_Printf("edict %i: SOLID_BSP with invalid modelindex!\n", PRVM_NUM_FOR_EDICT(ent)); + modelindex = 0; + } + model = sv.models[modelindex]; + if (model != NULL) + { + if (!model->TraceBox) + Con_Printf("edict %i: SOLID_BSP with non-collidable model\n", PRVM_NUM_FOR_EDICT(ent)); + + if (ent->fields.server->angles[0] || ent->fields.server->angles[2] || ent->fields.server->avelocity[0] || ent->fields.server->avelocity[2]) + { + VectorAdd(ent->fields.server->origin, model->rotatedmins, mins); + VectorAdd(ent->fields.server->origin, model->rotatedmaxs, maxs); + } + else if (ent->fields.server->angles[1] || ent->fields.server->avelocity[1]) + { + VectorAdd(ent->fields.server->origin, model->yawmins, mins); + VectorAdd(ent->fields.server->origin, model->yawmaxs, maxs); + } + else + { + VectorAdd(ent->fields.server->origin, model->normalmins, mins); + VectorAdd(ent->fields.server->origin, model->normalmaxs, maxs); + } + } + else + { + // SOLID_BSP with no model is valid, mainly because some QC setup code does so temporarily + VectorAdd(ent->fields.server->origin, ent->fields.server->mins, mins); + VectorAdd(ent->fields.server->origin, ent->fields.server->maxs, maxs); + } + } + else + { + VectorAdd(ent->fields.server->origin, ent->fields.server->mins, mins); + VectorAdd(ent->fields.server->origin, ent->fields.server->maxs, maxs); + } + +// +// to make items easier to pick up and allow them to be grabbed off +// of shelves, the abs sizes are expanded +// + if ((int)ent->fields.server->flags & FL_ITEM) + { + mins[0] -= 15; + mins[1] -= 15; + mins[2] -= 1; + maxs[0] += 15; + maxs[1] += 15; + maxs[2] += 1; + } + else + { + // because movement is clipped an epsilon away from an actual edge, + // we must fully check even when bounding boxes don't quite touch + mins[0] -= 1; + mins[1] -= 1; + mins[2] -= 1; + maxs[0] += 1; + maxs[1] += 1; + maxs[2] += 1; + } + + VectorCopy(mins, ent->fields.server->absmin); + VectorCopy(maxs, ent->fields.server->absmax); + + World_LinkEdict(&sv.world, ent, mins, maxs); + + // if touch_triggers, call touch on all entities overlapping this box + if (touch_triggers && ent->fields.server->solid != SOLID_NOT) + SV_LinkEdict_TouchAreaGrid(ent); +} + +/* +=============================================================================== + +Utility functions + +=============================================================================== +*/ + /* ============ SV_TestEntityPosition @@ -163,7 +648,7 @@ int SV_CheckContentsTransition(prvm_edict_t *ent, const int nContents) if(ent->fields.server->watertype != nContents) { // Changed Contents // Acquire Contents Transition Function from QC - contentstransition = PRVM_GETEDICTFIELDVALUE(ent, eval_contentstransition); + contentstransition = PRVM_GETEDICTFIELDVALUE(ent, prog->fieldoffsets.contentstransition); if(contentstransition->function) { // Valid Function; Execute @@ -286,13 +771,13 @@ void SV_Impact (prvm_edict_t *e1, trace_t *trace) prog->globals.server->trace_ent = PRVM_EDICT_TO_PROG(trace->ent); else prog->globals.server->trace_ent = PRVM_EDICT_TO_PROG(prog->edicts); - if ((val = PRVM_GETGLOBALFIELDVALUE(gval_trace_dpstartcontents))) + if ((val = PRVM_GETGLOBALFIELDVALUE(prog->globaloffsets.trace_dpstartcontents))) val->_float = trace->startsupercontents; - if ((val = PRVM_GETGLOBALFIELDVALUE(gval_trace_dphitcontents))) + if ((val = PRVM_GETGLOBALFIELDVALUE(prog->globaloffsets.trace_dphitcontents))) val->_float = trace->hitsupercontents; - if ((val = PRVM_GETGLOBALFIELDVALUE(gval_trace_dphitq3surfaceflags))) + if ((val = PRVM_GETGLOBALFIELDVALUE(prog->globaloffsets.trace_dphitq3surfaceflags))) val->_float = trace->hitq3surfaceflags; - if ((val = PRVM_GETGLOBALFIELDVALUE(gval_trace_dphittexturename))) + if ((val = PRVM_GETGLOBALFIELDVALUE(prog->globaloffsets.trace_dphittexturename))) { if (trace->hittexture) val->string = PRVM_SetTempString(trace->hittexture->name); @@ -315,13 +800,13 @@ void SV_Impact (prvm_edict_t *e1, trace_t *trace) VectorSet (prog->globals.server->trace_plane_normal, 0, 0, 1); prog->globals.server->trace_plane_dist = 0; prog->globals.server->trace_ent = PRVM_EDICT_TO_PROG(e1); - if ((val = PRVM_GETGLOBALFIELDVALUE(gval_trace_dpstartcontents))) + if ((val = PRVM_GETGLOBALFIELDVALUE(prog->globaloffsets.trace_dpstartcontents))) val->_float = 0; - if ((val = PRVM_GETGLOBALFIELDVALUE(gval_trace_dphitcontents))) + if ((val = PRVM_GETGLOBALFIELDVALUE(prog->globaloffsets.trace_dphitcontents))) val->_float = 0; - if ((val = PRVM_GETGLOBALFIELDVALUE(gval_trace_dphitq3surfaceflags))) + if ((val = PRVM_GETGLOBALFIELDVALUE(prog->globaloffsets.trace_dphitq3surfaceflags))) val->_float = 0; - if ((val = PRVM_GETGLOBALFIELDVALUE(gval_trace_dphittexturename))) + if ((val = PRVM_GETGLOBALFIELDVALUE(prog->globaloffsets.trace_dphittexturename))) val->string = 0; PRVM_ExecuteProgram (e2->fields.server->touch, "QC function self.touch is missing"); } @@ -610,7 +1095,7 @@ void SV_AddGravity (prvm_edict_t *ent) float ent_gravity; prvm_eval_t *val; - val = PRVM_GETEDICTFIELDVALUE(ent, eval_gravity); + val = PRVM_GETEDICTFIELDVALUE(ent, prog->fieldoffsets.gravity); if (val!=0 && val->_float) ent_gravity = val->_float; else @@ -787,7 +1272,7 @@ void SV_PushMove (prvm_edict_t *pusher, float movetime) // see if any solid entities are inside the final position num_moved = 0; - numcheckentities = SV_EntitiesInBox(mins, maxs, MAX_EDICTS, checkentities); + numcheckentities = World_EntitiesInBox(&sv.world, mins, maxs, MAX_EDICTS, checkentities); for (e = 0;e < numcheckentities;e++) { prvm_edict_t *check = checkentities[e]; @@ -808,7 +1293,7 @@ void SV_PushMove (prvm_edict_t *pusher, float movetime) else { // if the entity is not inside the pusher's final position, leave it alone - if (!SV_ClipMoveToEntity(pusher, check->fields.server->origin, check->fields.server->mins, check->fields.server->maxs, check->fields.server->origin, 0, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY).startsolid) + if (!SV_Move_ClipToEntity(pusher, check->fields.server->origin, check->fields.server->mins, check->fields.server->maxs, check->fields.server->origin, 0, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY).startsolid) continue; } @@ -839,7 +1324,7 @@ void SV_PushMove (prvm_edict_t *pusher, float movetime) //Con_Printf("%s:%d frac %f startsolid %d bmodelstartsolid %d allsolid %d\n", __FILE__, __LINE__, trace.fraction, trace.startsolid, trace.bmodelstartsolid, trace.allsolid); // if it is still inside the pusher, block - if (SV_ClipMoveToEntity(pusher, check->fields.server->origin, check->fields.server->mins, check->fields.server->maxs, check->fields.server->origin, 0, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY).startsolid) + if (SV_Move_ClipToEntity(pusher, check->fields.server->origin, check->fields.server->mins, check->fields.server->maxs, check->fields.server->origin, 0, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY).startsolid) { // try moving the contacted entity a tiny bit further to account for precision errors vec3_t move2; @@ -849,7 +1334,7 @@ void SV_PushMove (prvm_edict_t *pusher, float movetime) VectorCopy (check->priv.server->moved_fromangles, check->fields.server->angles); SV_PushEntity (check, move2, true); pusher->fields.server->solid = savesolid; - if (SV_ClipMoveToEntity(pusher, check->fields.server->origin, check->fields.server->mins, check->fields.server->maxs, check->fields.server->origin, 0, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY).startsolid) + if (SV_Move_ClipToEntity(pusher, check->fields.server->origin, check->fields.server->mins, check->fields.server->maxs, check->fields.server->origin, 0, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY).startsolid) { // try moving the contacted entity a tiny bit less to account for precision errors pusher->fields.server->solid = SOLID_NOT; @@ -858,7 +1343,7 @@ void SV_PushMove (prvm_edict_t *pusher, float movetime) VectorCopy (check->priv.server->moved_fromangles, check->fields.server->angles); SV_PushEntity (check, move2, true); pusher->fields.server->solid = savesolid; - if (SV_ClipMoveToEntity(pusher, check->fields.server->origin, check->fields.server->mins, check->fields.server->maxs, check->fields.server->origin, 0, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY).startsolid) + if (SV_Move_ClipToEntity(pusher, check->fields.server->origin, check->fields.server->mins, check->fields.server->maxs, check->fields.server->origin, 0, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY).startsolid) { // still inside pusher, so it's really blocked @@ -1646,11 +2131,11 @@ void SV_Physics_ClientEntity (prvm_edict_t *ent) // make sure the velocity is sane (not a NaN) SV_CheckVelocity(ent); // LordHavoc: QuakeC replacement for SV_ClientThink (player movement) - if (SV_PlayerPhysicsQC && sv_playerphysicsqc.integer) + if (prog->funcoffsets.SV_PlayerPhysics && sv_playerphysicsqc.integer) { prog->globals.server->time = sv.time; prog->globals.server->self = PRVM_EDICT_TO_PROG(ent); - PRVM_ExecuteProgram ((func_t)(SV_PlayerPhysicsQC - prog->functions), "QC function SV_PlayerPhysics is missing"); + PRVM_ExecuteProgram (prog->funcoffsets.SV_PlayerPhysics, "QC function SV_PlayerPhysics is missing"); } else SV_ClientThink (); @@ -1788,12 +2273,12 @@ void SV_Physics (void) prog->globals.server->force_retouch = max(0, prog->globals.server->force_retouch - 1); // LordHavoc: endframe support - if (EndFrameQC) + if (prog->funcoffsets.EndFrame) { prog->globals.server->self = PRVM_EDICT_TO_PROG(prog->edicts); prog->globals.server->other = PRVM_EDICT_TO_PROG(prog->edicts); prog->globals.server->time = sv.time; - PRVM_ExecuteProgram ((func_t)(EndFrameQC - prog->functions), "QC function EndFrame is missing"); + PRVM_ExecuteProgram (prog->funcoffsets.EndFrame, "QC function EndFrame is missing"); } // decrement prog->num_edicts if the highest number entities died @@ -1821,7 +2306,7 @@ trace_t SV_Trace_Toss (prvm_edict_t *tossent, prvm_edict_t *ignore) VectorCopy(tossent->fields.server->angles , original_angles ); VectorCopy(tossent->fields.server->avelocity, original_avelocity); - val = PRVM_GETEDICTFIELDVALUE(tossent, eval_gravity); + val = PRVM_GETEDICTFIELDVALUE(tossent, prog->fieldoffsets.gravity); if (val != NULL && val->_float != 0) gravity = val->_float; else diff --git a/sv_user.c b/sv_user.c index dd5ed4f7..73cba767 100644 --- a/sv_user.c +++ b/sv_user.c @@ -208,7 +208,7 @@ void DropPunchAngle (void) len = 0; VectorScale (host_client->edict->fields.server->punchangle, len, host_client->edict->fields.server->punchangle); - if ((val = PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_punchvector))) + if ((val = PRVM_GETEDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.punchvector))) { len = VectorNormalizeLength (val->vector); @@ -660,29 +660,29 @@ void SV_ApplyClientMove (void) // only send the impulse to qc once move->impulse = 0; VectorCopy(move->viewangles, host_client->edict->fields.server->v_angle); - if ((val = PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_button3))) val->_float = ((move->buttons >> 2) & 1); - if ((val = PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_button4))) val->_float = ((move->buttons >> 3) & 1); - if ((val = PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_button5))) val->_float = ((move->buttons >> 4) & 1); - if ((val = PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_button6))) val->_float = ((move->buttons >> 5) & 1); - if ((val = PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_button7))) val->_float = ((move->buttons >> 6) & 1); - if ((val = PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_button8))) val->_float = ((move->buttons >> 7) & 1); - if ((val = PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_button9))) val->_float = ((move->buttons >> 11) & 1); - if ((val = PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_button10))) val->_float = ((move->buttons >> 12) & 1); - if ((val = PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_button11))) val->_float = ((move->buttons >> 13) & 1); - if ((val = PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_button12))) val->_float = ((move->buttons >> 14) & 1); - if ((val = PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_button13))) val->_float = ((move->buttons >> 15) & 1); - if ((val = PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_button14))) val->_float = ((move->buttons >> 16) & 1); - if ((val = PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_button15))) val->_float = ((move->buttons >> 17) & 1); - if ((val = PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_button16))) val->_float = ((move->buttons >> 18) & 1); - if ((val = PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_buttonuse))) val->_float = ((move->buttons >> 8) & 1); - if ((val = PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_buttonchat))) val->_float = ((move->buttons >> 9) & 1); - if ((val = PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_cursor_active))) val->_float = ((move->buttons >> 10) & 1); - if ((val = PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_movement))) VectorSet(val->vector, move->forwardmove, move->sidemove, move->upmove); - if ((val = PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_cursor_screen))) VectorCopy(move->cursor_screen, val->vector); - if ((val = PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_cursor_trace_start))) VectorCopy(move->cursor_start, val->vector); - if ((val = PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_cursor_trace_endpos))) VectorCopy(move->cursor_impact, val->vector); - if ((val = PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_cursor_trace_ent))) val->edict = PRVM_EDICT_TO_PROG(PRVM_EDICT_NUM(move->cursor_entitynumber)); - if ((val = PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_ping))) val->_float = host_client->ping * 1000.0; + if ((val = PRVM_GETEDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.button3))) val->_float = ((move->buttons >> 2) & 1); + if ((val = PRVM_GETEDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.button4))) val->_float = ((move->buttons >> 3) & 1); + if ((val = PRVM_GETEDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.button5))) val->_float = ((move->buttons >> 4) & 1); + if ((val = PRVM_GETEDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.button6))) val->_float = ((move->buttons >> 5) & 1); + if ((val = PRVM_GETEDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.button7))) val->_float = ((move->buttons >> 6) & 1); + if ((val = PRVM_GETEDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.button8))) val->_float = ((move->buttons >> 7) & 1); + if ((val = PRVM_GETEDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.button9))) val->_float = ((move->buttons >> 11) & 1); + if ((val = PRVM_GETEDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.button10))) val->_float = ((move->buttons >> 12) & 1); + if ((val = PRVM_GETEDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.button11))) val->_float = ((move->buttons >> 13) & 1); + if ((val = PRVM_GETEDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.button12))) val->_float = ((move->buttons >> 14) & 1); + if ((val = PRVM_GETEDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.button13))) val->_float = ((move->buttons >> 15) & 1); + if ((val = PRVM_GETEDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.button14))) val->_float = ((move->buttons >> 16) & 1); + if ((val = PRVM_GETEDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.button15))) val->_float = ((move->buttons >> 17) & 1); + if ((val = PRVM_GETEDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.button16))) val->_float = ((move->buttons >> 18) & 1); + if ((val = PRVM_GETEDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.buttonuse))) val->_float = ((move->buttons >> 8) & 1); + if ((val = PRVM_GETEDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.buttonchat))) val->_float = ((move->buttons >> 9) & 1); + if ((val = PRVM_GETEDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.cursor_active))) val->_float = ((move->buttons >> 10) & 1); + if ((val = PRVM_GETEDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.movement))) VectorSet(val->vector, move->forwardmove, move->sidemove, move->upmove); + if ((val = PRVM_GETEDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.cursor_screen))) VectorCopy(move->cursor_screen, val->vector); + if ((val = PRVM_GETEDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.cursor_trace_start))) VectorCopy(move->cursor_start, val->vector); + if ((val = PRVM_GETEDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.cursor_trace_endpos))) VectorCopy(move->cursor_impact, val->vector); + if ((val = PRVM_GETEDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.cursor_trace_ent))) val->edict = PRVM_EDICT_TO_PROG(PRVM_EDICT_NUM(move->cursor_entitynumber)); + if ((val = PRVM_GETEDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.ping))) val->_float = host_client->ping * 1000.0; } void SV_FrameLost(int framenum) @@ -757,13 +757,13 @@ void SV_ReadClientMessage(void) || strncasecmp(s, "begin", 5) == 0 || strncasecmp(s, "prespawn", 8) == 0) Cmd_ExecuteString (s, src_client); - else if (SV_ParseClientCommandQC) + else if (prog->funcoffsets.SV_ParseClientCommand) { int restorevm_tempstringsbuf_cursize; restorevm_tempstringsbuf_cursize = vm_tempstringsbuf.cursize; PRVM_G_INT(OFS_PARM0) = PRVM_SetTempString(s); prog->globals.server->self = PRVM_EDICT_TO_PROG(host_client->edict); - PRVM_ExecuteProgram ((func_t)(SV_ParseClientCommandQC - prog->functions), "QC function SV_ParseClientCommand is missing"); + PRVM_ExecuteProgram (prog->funcoffsets.SV_ParseClientCommand, "QC function SV_ParseClientCommand is missing"); vm_tempstringsbuf.cursize = restorevm_tempstringsbuf_cursize; } else diff --git a/svvm_cmds.c b/svvm_cmds.c index 7f33f9c1..f70afaac 100644 --- a/svvm_cmds.c +++ b/svvm_cmds.c @@ -492,13 +492,13 @@ void PF_traceline (void) prog->globals.server->trace_ent = PRVM_EDICT_TO_PROG(trace.ent); else prog->globals.server->trace_ent = PRVM_EDICT_TO_PROG(prog->edicts); - if ((val = PRVM_GETGLOBALFIELDVALUE(gval_trace_dpstartcontents))) + if ((val = PRVM_GETGLOBALFIELDVALUE(prog->globaloffsets.trace_dpstartcontents))) val->_float = trace.startsupercontents; - if ((val = PRVM_GETGLOBALFIELDVALUE(gval_trace_dphitcontents))) + if ((val = PRVM_GETGLOBALFIELDVALUE(prog->globaloffsets.trace_dphitcontents))) val->_float = trace.hitsupercontents; - if ((val = PRVM_GETGLOBALFIELDVALUE(gval_trace_dphitq3surfaceflags))) + if ((val = PRVM_GETGLOBALFIELDVALUE(prog->globaloffsets.trace_dphitq3surfaceflags))) val->_float = trace.hitq3surfaceflags; - if ((val = PRVM_GETGLOBALFIELDVALUE(gval_trace_dphittexturename))) + if ((val = PRVM_GETGLOBALFIELDVALUE(prog->globaloffsets.trace_dphittexturename))) { if (trace.hittexture) val->string = PRVM_SetTempString(trace.hittexture->name); @@ -554,13 +554,13 @@ void PF_tracebox (void) prog->globals.server->trace_ent = PRVM_EDICT_TO_PROG(trace.ent); else prog->globals.server->trace_ent = PRVM_EDICT_TO_PROG(prog->edicts); - if ((val = PRVM_GETGLOBALFIELDVALUE(gval_trace_dpstartcontents))) + if ((val = PRVM_GETGLOBALFIELDVALUE(prog->globaloffsets.trace_dpstartcontents))) val->_float = trace.startsupercontents; - if ((val = PRVM_GETGLOBALFIELDVALUE(gval_trace_dphitcontents))) + if ((val = PRVM_GETGLOBALFIELDVALUE(prog->globaloffsets.trace_dphitcontents))) val->_float = trace.hitsupercontents; - if ((val = PRVM_GETGLOBALFIELDVALUE(gval_trace_dphitq3surfaceflags))) + if ((val = PRVM_GETGLOBALFIELDVALUE(prog->globaloffsets.trace_dphitq3surfaceflags))) val->_float = trace.hitq3surfaceflags; - if ((val = PRVM_GETGLOBALFIELDVALUE(gval_trace_dphittexturename))) + if ((val = PRVM_GETGLOBALFIELDVALUE(prog->globaloffsets.trace_dphittexturename))) { if (trace.hittexture) val->string = PRVM_SetTempString(trace.hittexture->name); @@ -601,13 +601,13 @@ void PF_tracetoss (void) prog->globals.server->trace_ent = PRVM_EDICT_TO_PROG(trace.ent); else prog->globals.server->trace_ent = PRVM_EDICT_TO_PROG(prog->edicts); - if ((val = PRVM_GETGLOBALFIELDVALUE(gval_trace_dpstartcontents))) + if ((val = PRVM_GETGLOBALFIELDVALUE(prog->globaloffsets.trace_dpstartcontents))) val->_float = trace.startsupercontents; - if ((val = PRVM_GETGLOBALFIELDVALUE(gval_trace_dphitcontents))) + if ((val = PRVM_GETGLOBALFIELDVALUE(prog->globaloffsets.trace_dphitcontents))) val->_float = trace.hitsupercontents; - if ((val = PRVM_GETGLOBALFIELDVALUE(gval_trace_dphitq3surfaceflags))) + if ((val = PRVM_GETGLOBALFIELDVALUE(prog->globaloffsets.trace_dphitq3surfaceflags))) val->_float = trace.hitq3surfaceflags; - if ((val = PRVM_GETGLOBALFIELDVALUE(gval_trace_dphittexturename))) + if ((val = PRVM_GETGLOBALFIELDVALUE(prog->globaloffsets.trace_dphittexturename))) { if (trace.hittexture) val->string = PRVM_SetTempString(trace.hittexture->name); @@ -789,7 +789,7 @@ void PF_findradius (void) maxs[0] = org[0] + (radius + 1); maxs[1] = org[1] + (radius + 1); maxs[2] = org[2] + (radius + 1); - numtouchedicts = SV_EntitiesInBox(mins, maxs, MAX_EDICTS, touchedicts); + numtouchedicts = World_EntitiesInBox(&sv.world, mins, maxs, MAX_EDICTS, touchedicts); if (numtouchedicts > MAX_EDICTS) { // this never happens @@ -1099,125 +1099,6 @@ void PF_aim (void) } } -/* -============== -PF_changeyaw - -This was a major timewaster in progs, so it was converted to C -============== -*/ -void PF_changeyaw (void) -{ - prvm_edict_t *ent; - float ideal, current, move, speed; - - ent = PRVM_PROG_TO_EDICT(prog->globals.server->self); - if (ent == prog->edicts) - { - VM_Warning("changeyaw: can not modify world entity\n"); - return; - } - if (ent->priv.server->free) - { - VM_Warning("changeyaw: can not modify free entity\n"); - return; - } - current = ANGLEMOD(ent->fields.server->angles[1]); - ideal = ent->fields.server->ideal_yaw; - speed = ent->fields.server->yaw_speed; - - if (current == ideal) - return; - move = ideal - current; - if (ideal > current) - { - if (move >= 180) - move = move - 360; - } - else - { - if (move <= -180) - move = move + 360; - } - if (move > 0) - { - if (move > speed) - move = speed; - } - else - { - if (move < -speed) - move = -speed; - } - - ent->fields.server->angles[1] = ANGLEMOD (current + move); -} - -/* -============== -PF_changepitch -============== -*/ -void PF_changepitch (void) -{ - prvm_edict_t *ent; - float ideal, current, move, speed; - prvm_eval_t *val; - - ent = PRVM_G_EDICT(OFS_PARM0); - if (ent == prog->edicts) - { - VM_Warning("changepitch: can not modify world entity\n"); - return; - } - if (ent->priv.server->free) - { - VM_Warning("changepitch: can not modify free entity\n"); - return; - } - current = ANGLEMOD( ent->fields.server->angles[0] ); - if ((val = PRVM_GETEDICTFIELDVALUE(ent, eval_idealpitch))) - ideal = val->_float; - else - { - VM_Warning("PF_changepitch: .float idealpitch and .float pitch_speed must be defined to use changepitch\n"); - return; - } - if ((val = PRVM_GETEDICTFIELDVALUE(ent, eval_pitch_speed))) - speed = val->_float; - else - { - VM_Warning("PF_changepitch: .float idealpitch and .float pitch_speed must be defined to use changepitch\n"); - return; - } - - if (current == ideal) - return; - move = ideal - current; - if (ideal > current) - { - if (move >= 180) - move = move - 360; - } - else - { - if (move <= -180) - move = move + 360; - } - if (move > 0) - { - if (move > speed) - move = speed; - } - else - { - if (move < -speed) - move = -speed; - } - - ent->fields.server->angles[0] = ANGLEMOD (current + move); -} - /* =============================================================================== @@ -1659,7 +1540,7 @@ void PF_setcolor (void) client = svs.clients + entnum-1; if (client->edict) { - if ((val = PRVM_GETEDICTFIELDVALUE(client->edict, eval_clientcolors))) + if ((val = PRVM_GETEDICTFIELDVALUE(client->edict, prog->fieldoffsets.clientcolors))) val->_float = i; client->edict->fields.server->team = (i & 15) + 1; } @@ -2348,11 +2229,11 @@ void PF_setattachment (void) if (tagentity == NULL) tagentity = prog->edicts; - v = PRVM_GETEDICTFIELDVALUE(e, eval_tag_entity); + v = PRVM_GETEDICTFIELDVALUE(e, prog->fieldoffsets.tag_entity); if (v) v->edict = PRVM_EDICT_TO_PROG(tagentity); - v = PRVM_GETEDICTFIELDVALUE(e, eval_tag_index); + v = PRVM_GETEDICTFIELDVALUE(e, prog->fieldoffsets.tag_index); if (v) v->_float = 0; if (tagentity != NULL && tagentity != prog->edicts && tagname && tagname[0]) @@ -2387,7 +2268,7 @@ int SV_GetTagIndex (prvm_edict_t *e, const char *tagname) void SV_GetEntityMatrix (prvm_edict_t *ent, matrix4x4_t *out, qboolean viewmatrix) { - float scale = PRVM_GETEDICTFIELDVALUE(ent, eval_scale)->_float; + float scale = PRVM_GETEDICTFIELDVALUE(ent, prog->fieldoffsets.scale)->_float; if (scale == 0) scale = 1; if (viewmatrix) @@ -2463,9 +2344,9 @@ int SV_GetTagMatrix (matrix4x4_t *out, prvm_edict_t *ent, int tagindex) SV_GetEntityMatrix(ent, &entitymatrix, false); Matrix4x4_Concat(&tagmatrix, &entitymatrix, out); // next iteration we process the parent entity - if ((val = PRVM_GETEDICTFIELDVALUE(ent, eval_tag_entity)) && val->edict) + if ((val = PRVM_GETEDICTFIELDVALUE(ent, prog->fieldoffsets.tag_entity)) && val->edict) { - tagindex = (int)PRVM_GETEDICTFIELDVALUE(ent, eval_tag_index)->_float; + tagindex = (int)PRVM_GETEDICTFIELDVALUE(ent, prog->fieldoffsets.tag_index)->_float; ent = PRVM_EDICT_NUM(val->edict); } else @@ -2474,7 +2355,7 @@ int SV_GetTagMatrix (matrix4x4_t *out, prvm_edict_t *ent, int tagindex) } // RENDER_VIEWMODEL magic - if ((val = PRVM_GETEDICTFIELDVALUE(ent, eval_viewmodelforclient)) && val->edict) + if ((val = PRVM_GETEDICTFIELDVALUE(ent, prog->fieldoffsets.viewmodelforclient)) && val->edict) { Matrix4x4_Copy(&tagmatrix, out); ent = PRVM_EDICT_NUM(val->edict); @@ -2686,7 +2567,7 @@ VM_cvar, // #45 float(string s) cvar VM_localcmd, // #46 void(string s) localcmd VM_nextent, // #47 entity(entity e) nextent PF_particle, // #48 void(vector o, vector d, float color, float count) particle -PF_changeyaw, // #49 void() ChangeYaw +VM_changeyaw, // #49 void() ChangeYaw NULL, // #50 VM_vectoangles, // #51 vector(vector v) vectoangles PF_WriteByte, // #52 void(float to, float f) WriteByte @@ -2700,7 +2581,7 @@ PF_WriteEntity, // #59 void(float to, entity e) WriteEntity VM_sin, // #60 float(float f) sin (DP_QC_SINCOSSQRTPOW) VM_cos, // #61 float(float f) cos (DP_QC_SINCOSSQRTPOW) VM_sqrt, // #62 float(float f) sqrt (DP_QC_SINCOSSQRTPOW) -PF_changepitch, // #63 void(entity ent) changepitch (DP_QC_CHANGEPITCH) +VM_changepitch, // #63 void(entity ent) changepitch (DP_QC_CHANGEPITCH) PF_tracetoss, // #64 void(entity e, entity ignore) tracetoss (DP_QC_TRACETOSS) VM_etos, // #65 string(entity ent) etos (DP_QC_ETOS) NULL, // #66 diff --git a/todo b/todo index 4ec5dc4b..fb17e375 100644 --- a/todo +++ b/todo @@ -81,6 +81,7 @@ 0 bug dpmod: identify what could cause huge angles values (1187488512.0000) on a dog entity, may be related to anglemod, FacingIdeal, ai_run, or dog_run2 (Zombie13) 0 bug dpmod: impulse 102 isn't removing the bots 0 bug dpmod: in dpmod_qcphysics_casings the two main particles have the same mass, realistically speaking the rear one should have more mass than the front one +0 bug dpmod: it is (rarely) possible to die and be unable to respawn 0 bug dpmod: monsters don't properly chase you around corners, this is not an engine bug because they work fine in id1 but not dpmod, the knight at the start of e2m2 makes for good testing by shooting him and then hiding behind the crates (StrangerThanYou) 0 bug dpmod: monsters falling out of level? 0 bug dpmod: monsters shouldn't constantly do sightsounds on a slain player, it's annoying and silly @@ -115,6 +116,7 @@ 0 change darkplaces renderer: rename r_drawportals to r_showportals, and move its declaration to gl_rmain.c, and make it work with r_showdisabledepthtest 0 change darkplaces server: make "viewmodel" command code precache a new model and set it, rather than changing the meaning of the player model 0 change darkplaces server: support sys_ticrate 0 as variable framerate mode +0 change darkplaces: make vid_mouse 0 mouse movement work with menu.dat 0 change dpmod: add a ghostly cvar and change skill 5 code to check it 0 change dpmod: make shamblers be worth 5 frags, shalrath be worth 3 frags, and fiends be worth 2 frags (Zenex) 0 change dpmod: stop using playernogun/playergun models, go back to ordinary player.mdl, this saves a bit of memory @@ -194,9 +196,11 @@ 0 feature darkplaces windows: include P3, P4, Xeon, AthlonXP, and Athlon64-32bit optimized windows dedicated server binaries for windows server admins to use, http://www.alientrap.org/forum/viewtopic.php?t=522 (PoWaZ) 0 feature darkplaces: .vis files - like .lit but replacement vis data, note this also requires .leaf files (knghtbrd) 0 feature darkplaces: add DP_GFX_EFFECTINFO extension to indicate that effectinfo.txt is supported, and thoroughly document its syntax (Morphed) +0 feature darkplaces: add a progress bar to the loading screen, this would be updated by the model/sound loading process 0 feature dpmaster: don't filter by protocol version if query is for protocol version 0, this way server browsers can see multiple versions of a single game, should probably also add a 'any' gamename that disables gamename filtering (Angst, Elric) 0 feature dpmaster: release an example /etc/init.d/dpdmasterd script based on the one LordHavoc is using 0 feature dpmod: add a g_spawnprotectiontime cvar which would default to 1 (invulnerable for 1 second after spawn) to prevent mining the spawn points +0 feature dpmod: add a gravity gun weapon, able to grab and launch monsters 0 feature dpmod: add a summon command using KRIMZON_SV_PARSECLIENTCOMMAND which would summon the specified monster infront of you (Kedhrin) 0 feature dpmod: add higher quality replacement sbar images 0 feature dpmod: add knight/hell knight swords as player weapons (TimeServ) diff --git a/world.c b/world.c index 0ff5a6fc..7f95e28e 100644 --- a/world.c +++ b/world.c @@ -29,35 +29,30 @@ line of sight checks trace->inopen and trace->inwater, but bullets don't */ -cvar_t sv_debugmove = {CVAR_NOTIFY, "sv_debugmove", "0", "disables collision detection optimizations for debugging purposes"}; cvar_t sv_areagrid_mingridsize = {CVAR_NOTIFY, "sv_areagrid_mingridsize", "64", "minimum areagrid cell size, smaller values work better for lots of small objects, higher values for large objects"}; -void SV_AreaStats_f(void); - -void SV_World_Init(void) +void World_Init(void) { - Cvar_RegisterVariable(&sv_debugmove); Cvar_RegisterVariable(&sv_areagrid_mingridsize); - Cmd_AddCommand("sv_areastats", SV_AreaStats_f, "prints information on culling grid system"); Collision_Init(); } //============================================================================ -// ClearLink is used for new headnodes -static void ClearLink (link_t *l) +// World_ClearLink is used for new headnodes +void World_ClearLink (link_t *l) { l->entitynumber = 0; l->prev = l->next = l; } -static void RemoveLink (link_t *l) +void World_RemoveLink (link_t *l) { l->next->prev = l->prev; l->prev->next = l->next; } -static void InsertLinkBefore (link_t *l, link_t *before, int entitynumber) +void World_InsertLinkBefore (link_t *l, link_t *before, int entitynumber) { l->entitynumber = entitynumber; l->next = before; @@ -66,7 +61,6 @@ static void InsertLinkBefore (link_t *l, link_t *before, int entitynumber) l->next->prev = l; } - /* =============================================================================== @@ -75,105 +69,85 @@ ENTITY AREA CHECKING =============================================================================== */ -int sv_areagrid_stats_calls = 0; -int sv_areagrid_stats_nodechecks = 0; -int sv_areagrid_stats_entitychecks = 0; - -void SV_AreaStats_f(void) -{ - Con_Printf("areagrid check stats: %d calls %d nodes (%f per call) %d entities (%f per call)\n", sv_areagrid_stats_calls, sv_areagrid_stats_nodechecks, (double) sv_areagrid_stats_nodechecks / (double) sv_areagrid_stats_calls, sv_areagrid_stats_entitychecks, (double) sv_areagrid_stats_entitychecks / (double) sv_areagrid_stats_calls); - sv_areagrid_stats_calls = 0; - sv_areagrid_stats_nodechecks = 0; - sv_areagrid_stats_entitychecks = 0; -} - -typedef struct areagrid_s +void World_PrintAreaStats(world_t *world, const char *worldname) { - link_t edicts; + Con_Printf("%s areagrid check stats: %d calls %d nodes (%f per call) %d entities (%f per call)\n", worldname, world->areagrid_stats_calls, world->areagrid_stats_nodechecks, (double) world->areagrid_stats_nodechecks / (double) world->areagrid_stats_calls, world->areagrid_stats_entitychecks, (double) world->areagrid_stats_entitychecks / (double) world->areagrid_stats_calls); + world->areagrid_stats_calls = 0; + world->areagrid_stats_nodechecks = 0; + world->areagrid_stats_entitychecks = 0; } -areagrid_t; - -#define AREA_GRID 512 -#define AREA_GRIDNODES (AREA_GRID * AREA_GRID) -static areagrid_t sv_areagrid[AREA_GRIDNODES], sv_areagrid_outside; -static vec3_t sv_areagrid_bias, sv_areagrid_scale, sv_areagrid_mins, sv_areagrid_maxs, sv_areagrid_size; -static int sv_areagrid_marknumber = 1; +/* +=============== +World_Clear -void SV_CreateAreaGrid (vec3_t mins, vec3_t maxs) +=============== +*/ +void World_Clear(world_t *world) { int i; - ClearLink (&sv_areagrid_outside.edicts); + // the areagrid_marknumber is not allowed to be 0 + if (world->areagrid_marknumber < 1) + world->areagrid_marknumber = 1; // choose either the world box size, or a larger box to ensure the grid isn't too fine - sv_areagrid_size[0] = max(maxs[0] - mins[0], AREA_GRID * sv_areagrid_mingridsize.value); - sv_areagrid_size[1] = max(maxs[1] - mins[1], AREA_GRID * sv_areagrid_mingridsize.value); - sv_areagrid_size[2] = max(maxs[2] - mins[2], AREA_GRID * sv_areagrid_mingridsize.value); + world->areagrid_size[0] = max(world->areagrid_maxs[0] - world->areagrid_mins[0], AREA_GRID * sv_areagrid_mingridsize.value); + world->areagrid_size[1] = max(world->areagrid_maxs[1] - world->areagrid_mins[1], AREA_GRID * sv_areagrid_mingridsize.value); + world->areagrid_size[2] = max(world->areagrid_maxs[2] - world->areagrid_mins[2], AREA_GRID * sv_areagrid_mingridsize.value); // figure out the corners of such a box, centered at the center of the world box - sv_areagrid_mins[0] = (mins[0] + maxs[0] - sv_areagrid_size[0]) * 0.5f; - sv_areagrid_mins[1] = (mins[1] + maxs[1] - sv_areagrid_size[1]) * 0.5f; - sv_areagrid_mins[2] = (mins[2] + maxs[2] - sv_areagrid_size[2]) * 0.5f; - sv_areagrid_maxs[0] = (mins[0] + maxs[0] + sv_areagrid_size[0]) * 0.5f; - sv_areagrid_maxs[1] = (mins[1] + maxs[1] + sv_areagrid_size[1]) * 0.5f; - sv_areagrid_maxs[2] = (mins[2] + maxs[2] + sv_areagrid_size[2]) * 0.5f; + world->areagrid_mins[0] = (world->areagrid_mins[0] + world->areagrid_maxs[0] - world->areagrid_size[0]) * 0.5f; + world->areagrid_mins[1] = (world->areagrid_mins[1] + world->areagrid_maxs[1] - world->areagrid_size[1]) * 0.5f; + world->areagrid_mins[2] = (world->areagrid_mins[2] + world->areagrid_maxs[2] - world->areagrid_size[2]) * 0.5f; + world->areagrid_maxs[0] = (world->areagrid_mins[0] + world->areagrid_maxs[0] + world->areagrid_size[0]) * 0.5f; + world->areagrid_maxs[1] = (world->areagrid_mins[1] + world->areagrid_maxs[1] + world->areagrid_size[1]) * 0.5f; + world->areagrid_maxs[2] = (world->areagrid_mins[2] + world->areagrid_maxs[2] + world->areagrid_size[2]) * 0.5f; // now calculate the actual useful info from that - VectorNegate(sv_areagrid_mins, sv_areagrid_bias); - sv_areagrid_scale[0] = AREA_GRID / sv_areagrid_size[0]; - sv_areagrid_scale[1] = AREA_GRID / sv_areagrid_size[1]; - sv_areagrid_scale[2] = AREA_GRID / sv_areagrid_size[2]; + VectorNegate(world->areagrid_mins, world->areagrid_bias); + world->areagrid_scale[0] = AREA_GRID / world->areagrid_size[0]; + world->areagrid_scale[1] = AREA_GRID / world->areagrid_size[1]; + world->areagrid_scale[2] = AREA_GRID / world->areagrid_size[2]; + World_ClearLink(&world->areagrid_outside); for (i = 0;i < AREA_GRIDNODES;i++) - { - ClearLink (&sv_areagrid[i].edicts); - } - Con_DPrintf("sv_areagrid settings: divisions %ix%ix1 : box %f %f %f : %f %f %f size %f %f %f grid %f %f %f (mingrid %f)\n", AREA_GRID, AREA_GRID, sv_areagrid_mins[0], sv_areagrid_mins[1], sv_areagrid_mins[2], sv_areagrid_maxs[0], sv_areagrid_maxs[1], sv_areagrid_maxs[2], sv_areagrid_size[0], sv_areagrid_size[1], sv_areagrid_size[2], 1.0f / sv_areagrid_scale[0], 1.0f / sv_areagrid_scale[1], 1.0f / sv_areagrid_scale[2], sv_areagrid_mingridsize.value); -} - -/* -=============== -SV_ClearWorld - -=============== -*/ -void SV_ClearWorld (void) -{ - SV_CreateAreaGrid(sv.worldmodel->normalmins, sv.worldmodel->normalmaxs); + World_ClearLink(&world->areagrid[i]); + Con_DPrintf("areagrid settings: divisions %ix%ix1 : box %f %f %f : %f %f %f size %f %f %f grid %f %f %f (mingrid %f)\n", AREA_GRID, AREA_GRID, world->areagrid_mins[0], world->areagrid_mins[1], world->areagrid_mins[2], world->areagrid_maxs[0], world->areagrid_maxs[1], world->areagrid_maxs[2], world->areagrid_size[0], world->areagrid_size[1], world->areagrid_size[2], 1.0f / world->areagrid_scale[0], 1.0f / world->areagrid_scale[1], 1.0f / world->areagrid_scale[2], sv_areagrid_mingridsize.value); } /* =============== -SV_UnlinkEdict =============== */ -void SV_UnlinkEdict (prvm_edict_t *ent) +void World_UnlinkEdict(prvm_edict_t *ent) { int i; for (i = 0;i < ENTITYGRIDAREAS;i++) { if (ent->priv.server->areagrid[i].prev) { - RemoveLink (&ent->priv.server->areagrid[i]); + World_RemoveLink (&ent->priv.server->areagrid[i]); ent->priv.server->areagrid[i].prev = ent->priv.server->areagrid[i].next = NULL; } } } -int SV_EntitiesInBox(vec3_t mins, vec3_t maxs, int maxlist, prvm_edict_t **list) +int World_EntitiesInBox(world_t *world, vec3_t mins, vec3_t maxs, int maxlist, prvm_edict_t **list) { int numlist; - areagrid_t *grid; + link_t *grid; link_t *l; prvm_edict_t *ent; int igrid[3], igridmins[3], igridmaxs[3]; - sv_areagrid_stats_calls++; - sv_areagrid_marknumber++; - igridmins[0] = (int) floor((mins[0] + sv_areagrid_bias[0]) * sv_areagrid_scale[0]); - igridmins[1] = (int) floor((mins[1] + sv_areagrid_bias[1]) * sv_areagrid_scale[1]); - //igridmins[2] = (int) ((mins[2] + sv_areagrid_bias[2]) * sv_areagrid_scale[2]); - igridmaxs[0] = (int) floor((maxs[0] + sv_areagrid_bias[0]) * sv_areagrid_scale[0]) + 1; - igridmaxs[1] = (int) floor((maxs[1] + sv_areagrid_bias[1]) * sv_areagrid_scale[1]) + 1; - //igridmaxs[2] = (int) ((maxs[2] + sv_areagrid_bias[2]) * sv_areagrid_scale[2]) + 1; + // FIXME: if areagrid_marknumber wraps, all entities need their + // ent->priv.server->areagridmarknumber reset + world->areagrid_stats_calls++; + world->areagrid_marknumber++; + igridmins[0] = (int) floor((mins[0] + world->areagrid_bias[0]) * world->areagrid_scale[0]); + igridmins[1] = (int) floor((mins[1] + world->areagrid_bias[1]) * world->areagrid_scale[1]); + //igridmins[2] = (int) ((mins[2] + world->areagrid_bias[2]) * world->areagrid_scale[2]); + igridmaxs[0] = (int) floor((maxs[0] + world->areagrid_bias[0]) * world->areagrid_scale[0]) + 1; + igridmaxs[1] = (int) floor((maxs[1] + world->areagrid_bias[1]) * world->areagrid_scale[1]) + 1; + //igridmaxs[2] = (int) ((maxs[2] + world->areagrid_bias[2]) * world->areagrid_scale[2]) + 1; igridmins[0] = max(0, igridmins[0]); igridmins[1] = max(0, igridmins[1]); //igridmins[2] = max(0, igridmins[2]); @@ -184,47 +158,48 @@ int SV_EntitiesInBox(vec3_t mins, vec3_t maxs, int maxlist, prvm_edict_t **list) numlist = 0; // add entities not linked into areagrid because they are too big or // outside the grid bounds - if (sv_areagrid_outside.edicts.next != &sv_areagrid_outside.edicts) + if (world->areagrid_outside.next != &world->areagrid_outside) { - for (l = sv_areagrid_outside.edicts.next;l != &sv_areagrid_outside.edicts;l = l->next) + grid = &world->areagrid_outside; + for (l = grid->next;l != grid;l = l->next) { ent = PRVM_EDICT_NUM_UNSIGNED(l->entitynumber); - if (ent->priv.server->areagridmarknumber != sv_areagrid_marknumber) + if (ent->priv.server->areagridmarknumber != world->areagrid_marknumber) { - ent->priv.server->areagridmarknumber = sv_areagrid_marknumber; - if (!ent->priv.server->free && BoxesOverlap(mins, maxs, ent->fields.server->absmin, ent->fields.server->absmax)) + ent->priv.server->areagridmarknumber = world->areagrid_marknumber; + if (!ent->priv.server->free && BoxesOverlap(mins, maxs, ent->priv.server->areamins, ent->priv.server->areamaxs)) { if (numlist < maxlist) list[numlist] = ent; numlist++; } - sv_areagrid_stats_entitychecks++; + world->areagrid_stats_entitychecks++; } } } // add grid linked entities for (igrid[1] = igridmins[1];igrid[1] < igridmaxs[1];igrid[1]++) { - grid = sv_areagrid + igrid[1] * AREA_GRID + igridmins[0]; + grid = world->areagrid + igrid[1] * AREA_GRID + igridmins[0]; for (igrid[0] = igridmins[0];igrid[0] < igridmaxs[0];igrid[0]++, grid++) { - if (grid->edicts.next != &grid->edicts) + if (grid->next != grid) { - for (l = grid->edicts.next;l != &grid->edicts;l = l->next) + for (l = grid->next;l != grid;l = l->next) { ent = PRVM_EDICT_NUM_UNSIGNED(l->entitynumber); - if (ent->priv.server->areagridmarknumber != sv_areagrid_marknumber) + if (ent->priv.server->areagridmarknumber != world->areagrid_marknumber) { - ent->priv.server->areagridmarknumber = sv_areagrid_marknumber; - if (!ent->priv.server->free && BoxesOverlap(mins, maxs, ent->fields.server->absmin, ent->fields.server->absmax)) + ent->priv.server->areagridmarknumber = world->areagrid_marknumber; + if (!ent->priv.server->free && BoxesOverlap(mins, maxs, ent->priv.server->areamins, ent->priv.server->areamaxs)) { if (numlist < maxlist) list[numlist] = ent; numlist++; } - // Con_Printf("%d %f %f %f %f %f %f : %d : %f %f %f %f %f %f\n", BoxesOverlap(mins, maxs, ent->fields.server->absmin, ent->fields.server->absmax), ent->fields.server->absmin[0], ent->fields.server->absmin[1], ent->fields.server->absmin[2], ent->fields.server->absmax[0], ent->fields.server->absmax[1], ent->fields.server->absmax[2], PRVM_NUM_FOR_EDICT(ent), mins[0], mins[1], mins[2], maxs[0], maxs[1], maxs[2]); + //Con_Printf("%d %f %f %f %f %f %f : %d : %f %f %f %f %f %f\n", BoxesOverlap(mins, maxs, ent->priv.server->areamins, ent->priv.server->areamaxs), ent->priv.server->areamins[0], ent->priv.server->areamins[1], ent->priv.server->areamins[2], ent->priv.server->areamaxs[0], ent->priv.server->areamaxs[1], ent->priv.server->areamaxs[2], PRVM_NUM_FOR_EDICT(ent), mins[0], mins[1], mins[2], maxs[0], maxs[1], maxs[2]); } - sv_areagrid_stats_entitychecks++; + world->areagrid_stats_entitychecks++; } } } @@ -232,59 +207,9 @@ int SV_EntitiesInBox(vec3_t mins, vec3_t maxs, int maxlist, prvm_edict_t **list) return numlist; } -void SV_TouchAreaGrid(prvm_edict_t *ent) -{ - int i, numtouchedicts, old_self, old_other; - prvm_edict_t *touch, *touchedicts[MAX_EDICTS]; - - // build a list of edicts to touch, because the link loop can be corrupted - // by SV_IncreaseEdicts called during touch functions - numtouchedicts = SV_EntitiesInBox(ent->fields.server->absmin, ent->fields.server->absmax, MAX_EDICTS, touchedicts); - if (numtouchedicts > MAX_EDICTS) - { - // this never happens - Con_Printf("SV_EntitiesInBox returned %i edicts, max was %i\n", numtouchedicts, MAX_EDICTS); - numtouchedicts = MAX_EDICTS; - } - - old_self = prog->globals.server->self; - old_other = prog->globals.server->other; - for (i = 0;i < numtouchedicts;i++) - { - touch = touchedicts[i]; - if (touch != ent && (int)touch->fields.server->solid == SOLID_TRIGGER && touch->fields.server->touch) - { - prvm_eval_t *val; - prog->globals.server->self = PRVM_EDICT_TO_PROG(touch); - prog->globals.server->other = PRVM_EDICT_TO_PROG(ent); - prog->globals.server->time = sv.time; - prog->globals.server->trace_allsolid = false; - prog->globals.server->trace_startsolid = false; - prog->globals.server->trace_fraction = 1; - prog->globals.server->trace_inwater = false; - prog->globals.server->trace_inopen = true; - VectorCopy (touch->fields.server->origin, prog->globals.server->trace_endpos); - VectorSet (prog->globals.server->trace_plane_normal, 0, 0, 1); - prog->globals.server->trace_plane_dist = 0; - prog->globals.server->trace_ent = PRVM_EDICT_TO_PROG(ent); - if ((val = PRVM_GETGLOBALFIELDVALUE(gval_trace_dpstartcontents))) - val->_float = 0; - if ((val = PRVM_GETGLOBALFIELDVALUE(gval_trace_dphitcontents))) - val->_float = 0; - if ((val = PRVM_GETGLOBALFIELDVALUE(gval_trace_dphitq3surfaceflags))) - val->_float = 0; - if ((val = PRVM_GETGLOBALFIELDVALUE(gval_trace_dphittexturename))) - val->string = 0; - PRVM_ExecuteProgram (touch->fields.server->touch, "QC function self.touch is missing"); - } - } - prog->globals.server->self = old_self; - prog->globals.server->other = old_other; -} - -void SV_LinkEdict_AreaGrid(prvm_edict_t *ent) +void World_LinkEdict_AreaGrid(world_t *world, prvm_edict_t *ent) { - areagrid_t *grid; + link_t *grid; int igrid[3], igridmins[3], igridmaxs[3], gridnum, entitynumber = PRVM_NUM_FOR_EDICT(ent); if (entitynumber <= 0 || entitynumber >= prog->max_edicts || PRVM_EDICT_NUM(entitynumber) != ent) @@ -293,447 +218,49 @@ void SV_LinkEdict_AreaGrid(prvm_edict_t *ent) return; } - igridmins[0] = (int) floor((ent->fields.server->absmin[0] + sv_areagrid_bias[0]) * sv_areagrid_scale[0]); - igridmins[1] = (int) floor((ent->fields.server->absmin[1] + sv_areagrid_bias[1]) * sv_areagrid_scale[1]); - //igridmins[2] = (int) ((ent->fields.server->absmin[2] + sv_areagrid_bias[2]) * sv_areagrid_scale[2]); - igridmaxs[0] = (int) floor((ent->fields.server->absmax[0] + sv_areagrid_bias[0]) * sv_areagrid_scale[0]) + 1; - igridmaxs[1] = (int) floor((ent->fields.server->absmax[1] + sv_areagrid_bias[1]) * sv_areagrid_scale[1]) + 1; - //igridmaxs[2] = (int) ((ent->fields.server->absmax[2] + sv_areagrid_bias[2]) * sv_areagrid_scale[2]) + 1; + igridmins[0] = (int) floor((ent->priv.server->areamins[0] + sv.world.areagrid_bias[0]) * sv.world.areagrid_scale[0]); + igridmins[1] = (int) floor((ent->priv.server->areamins[1] + sv.world.areagrid_bias[1]) * sv.world.areagrid_scale[1]); + //igridmins[2] = (int) floor((ent->priv.server->areamins[2] + sv.world.areagrid_bias[2]) * sv.world.areagrid_scale[2]); + igridmaxs[0] = (int) floor((ent->priv.server->areamaxs[0] + sv.world.areagrid_bias[0]) * sv.world.areagrid_scale[0]) + 1; + igridmaxs[1] = (int) floor((ent->priv.server->areamaxs[1] + sv.world.areagrid_bias[1]) * sv.world.areagrid_scale[1]) + 1; + //igridmaxs[2] = (int) floor((ent->priv.server->areamaxs[2] + sv.world.areagrid_bias[2]) * sv.world.areagrid_scale[2]) + 1; if (igridmins[0] < 0 || igridmaxs[0] > AREA_GRID || igridmins[1] < 0 || igridmaxs[1] > AREA_GRID || ((igridmaxs[0] - igridmins[0]) * (igridmaxs[1] - igridmins[1])) > ENTITYGRIDAREAS) { // wow, something outside the grid, store it as such - InsertLinkBefore (&ent->priv.server->areagrid[0], &sv_areagrid_outside.edicts, entitynumber); + World_InsertLinkBefore (&ent->priv.server->areagrid[0], &sv.world.areagrid_outside, entitynumber); return; } gridnum = 0; for (igrid[1] = igridmins[1];igrid[1] < igridmaxs[1];igrid[1]++) { - grid = sv_areagrid + igrid[1] * AREA_GRID + igridmins[0]; + grid = sv.world.areagrid + igrid[1] * AREA_GRID + igridmins[0]; for (igrid[0] = igridmins[0];igrid[0] < igridmaxs[0];igrid[0]++, grid++, gridnum++) - InsertLinkBefore (&ent->priv.server->areagrid[gridnum], &grid->edicts, entitynumber); + World_InsertLinkBefore (&ent->priv.server->areagrid[gridnum], grid, entitynumber); } } /* =============== -SV_LinkEdict +World_LinkEdict =============== */ -void SV_LinkEdict (prvm_edict_t *ent, qboolean touch_triggers) +void World_LinkEdict(world_t *world, prvm_edict_t *ent, const vec3_t mins, const vec3_t maxs) { - model_t *model; - + // unlink from old position first if (ent->priv.server->areagrid[0].prev) - SV_UnlinkEdict (ent); // unlink from old position + World_UnlinkEdict(ent); + // don't add the world if (ent == prog->edicts) - return; // don't add the world + return; + // don't add free entities if (ent->priv.server->free) return; -// set the abs box - - if (ent->fields.server->solid == SOLID_BSP) - { - int modelindex = (int)ent->fields.server->modelindex; - if (modelindex < 0 || modelindex > MAX_MODELS) - { - Con_Printf("edict %i: SOLID_BSP with invalid modelindex!\n", PRVM_NUM_FOR_EDICT(ent)); - modelindex = 0; - } - model = sv.models[modelindex]; - if (model != NULL) - { - if (!model->TraceBox) - Con_Printf("edict %i: SOLID_BSP with non-collidable model\n", PRVM_NUM_FOR_EDICT(ent)); - - if (ent->fields.server->angles[0] || ent->fields.server->angles[2] || ent->fields.server->avelocity[0] || ent->fields.server->avelocity[2]) - { - VectorAdd(ent->fields.server->origin, model->rotatedmins, ent->fields.server->absmin); - VectorAdd(ent->fields.server->origin, model->rotatedmaxs, ent->fields.server->absmax); - } - else if (ent->fields.server->angles[1] || ent->fields.server->avelocity[1]) - { - VectorAdd(ent->fields.server->origin, model->yawmins, ent->fields.server->absmin); - VectorAdd(ent->fields.server->origin, model->yawmaxs, ent->fields.server->absmax); - } - else - { - VectorAdd(ent->fields.server->origin, model->normalmins, ent->fields.server->absmin); - VectorAdd(ent->fields.server->origin, model->normalmaxs, ent->fields.server->absmax); - } - } - else - { - // SOLID_BSP with no model is valid, mainly because some QC setup code does so temporarily - VectorAdd(ent->fields.server->origin, ent->fields.server->mins, ent->fields.server->absmin); - VectorAdd(ent->fields.server->origin, ent->fields.server->maxs, ent->fields.server->absmax); - } - } - else - { - VectorAdd(ent->fields.server->origin, ent->fields.server->mins, ent->fields.server->absmin); - VectorAdd(ent->fields.server->origin, ent->fields.server->maxs, ent->fields.server->absmax); - } - -// -// to make items easier to pick up and allow them to be grabbed off -// of shelves, the abs sizes are expanded -// - if ((int)ent->fields.server->flags & FL_ITEM) - { - ent->fields.server->absmin[0] -= 15; - ent->fields.server->absmin[1] -= 15; - ent->fields.server->absmin[2] -= 1; - ent->fields.server->absmax[0] += 15; - ent->fields.server->absmax[1] += 15; - ent->fields.server->absmax[2] += 1; - } - else - { - // because movement is clipped an epsilon away from an actual edge, - // we must fully check even when bounding boxes don't quite touch - ent->fields.server->absmin[0] -= 1; - ent->fields.server->absmin[1] -= 1; - ent->fields.server->absmin[2] -= 1; - ent->fields.server->absmax[0] += 1; - ent->fields.server->absmax[1] += 1; - ent->fields.server->absmax[2] += 1; - } - - SV_LinkEdict_AreaGrid(ent); - -// if touch_triggers, touch all entities at this node and descend for more - if (touch_triggers && ent->fields.server->solid != SOLID_NOT) - SV_TouchAreaGrid(ent); -} - - - -/* -=============================================================================== - -LINE TESTING IN HULLS - -=============================================================================== -*/ - -/* -================== -SV_ClipMoveToEntity - -Handles selection or creation of a clipping hull, and offseting (and -eventually rotation) of the end points -================== -*/ -trace_t SV_ClipMoveToEntity(prvm_edict_t *ent, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int movetype, int hitsupercontents) -{ - trace_t trace; - model_t *model = NULL; - matrix4x4_t matrix, imatrix; - float tempnormal[3], starttransformed[3], endtransformed[3]; - - memset(&trace, 0, sizeof(trace)); - trace.fraction = trace.realfraction = 1; - VectorCopy(end, trace.endpos); - - if ((int) ent->fields.server->solid == SOLID_BSP || movetype == MOVE_HITMODEL) - { - unsigned int modelindex = (unsigned int)ent->fields.server->modelindex; - // if the modelindex is 0, it shouldn't be SOLID_BSP! - if (modelindex == 0) - { - Con_Printf("SV_ClipMoveToEntity: edict %i: SOLID_BSP with no model\n", PRVM_NUM_FOR_EDICT(ent)); - return trace; - } - if (modelindex >= MAX_MODELS) - { - Con_Printf("SV_ClipMoveToEntity: edict %i: SOLID_BSP with invalid modelindex\n", PRVM_NUM_FOR_EDICT(ent)); - return trace; - } - model = sv.models[modelindex]; - if (modelindex != 0 && model == NULL) - { - Con_Printf("SV_ClipMoveToEntity: edict %i: SOLID_BSP with invalid modelindex\n", PRVM_NUM_FOR_EDICT(ent)); - return trace; - } - - if ((int) ent->fields.server->solid == SOLID_BSP) - { - if (!model->TraceBox) - { - Con_Printf("SV_ClipMoveToEntity: edict %i: SOLID_BSP with a non-collidable model\n", PRVM_NUM_FOR_EDICT(ent)); - return trace; - } - //if ((int) ent->fields.server->movetype != MOVETYPE_PUSH) - //{ - // Con_Printf("SV_ClipMoveToEntity: edict %i: SOLID_BSP without MOVETYPE_PUSH\n", PRVM_NUM_FOR_EDICT(ent)); - // return trace; - //} - } - Matrix4x4_CreateFromQuakeEntity(&matrix, ent->fields.server->origin[0], ent->fields.server->origin[1], ent->fields.server->origin[2], ent->fields.server->angles[0], ent->fields.server->angles[1], ent->fields.server->angles[2], 1); - } - else - Matrix4x4_CreateTranslate(&matrix, ent->fields.server->origin[0], ent->fields.server->origin[1], ent->fields.server->origin[2]); - - Matrix4x4_Invert_Simple(&imatrix, &matrix); - Matrix4x4_Transform(&imatrix, start, starttransformed); - Matrix4x4_Transform(&imatrix, end, endtransformed); -#if COLLISIONPARANOID >= 3 - Con_Printf("trans(%f %f %f -> %f %f %f, %f %f %f -> %f %f %f)", start[0], start[1], start[2], starttransformed[0], starttransformed[1], starttransformed[2], end[0], end[1], end[2], endtransformed[0], endtransformed[1], endtransformed[2]); -#endif - - if (model && model->TraceBox) - { - int frame; - frame = (int)ent->fields.server->frame; - frame = bound(0, frame, (model->numframes - 1)); - model->TraceBox(model, frame, &trace, starttransformed, mins, maxs, endtransformed, hitsupercontents); - } - else - Collision_ClipTrace_Box(&trace, ent->fields.server->mins, ent->fields.server->maxs, starttransformed, mins, maxs, endtransformed, hitsupercontents, ent->fields.server->solid == SOLID_CORPSE ? SUPERCONTENTS_CORPSE : SUPERCONTENTS_BODY, 0, NULL); - trace.fraction = bound(0, trace.fraction, 1); - trace.realfraction = bound(0, trace.realfraction, 1); - - if (trace.fraction < 1) - { - VectorLerp(start, trace.fraction, end, trace.endpos); - VectorCopy(trace.plane.normal, tempnormal); - Matrix4x4_Transform3x3(&matrix, tempnormal, trace.plane.normal); - // FIXME: should recalc trace.plane.dist - } - else - VectorCopy(end, trace.endpos); - - return trace; -} - -/* -================== -SV_ClipMoveToWorld -================== -*/ -trace_t SV_ClipMoveToWorld(const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int movetype, int hitsupercontents) -{ - trace_t trace; - memset(&trace, 0, sizeof(trace)); - trace.fraction = trace.realfraction = 1; - sv.worldmodel->TraceBox(sv.worldmodel, 0, &trace, start, mins, maxs, end, hitsupercontents); - trace.fraction = bound(0, trace.fraction, 1); - trace.realfraction = bound(0, trace.realfraction, 1); - VectorLerp(start, trace.fraction, end, trace.endpos); - return trace; -} - -//=========================================================================== - -/* -================== -SV_Move -================== -*/ -#if COLLISIONPARANOID >= 1 -trace_t SV_Move_(const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int type, prvm_edict_t *passedict) -#else -trace_t SV_Move(const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int type, prvm_edict_t *passedict) -#endif -{ - vec3_t hullmins, hullmaxs; - int i; - int hitsupercontentsmask; - int passedictprog; - qboolean pointtrace; - prvm_edict_t *traceowner, *touch; - prvm_eval_t *val; - trace_t trace; - // bounding box of entire move area - vec3_t clipboxmins, clipboxmaxs; - // size of the moving object - vec3_t clipmins, clipmaxs; - // size when clipping against monsters - vec3_t clipmins2, clipmaxs2; - // start and end origin of move - vec3_t clipstart, clipend; - // trace results - trace_t cliptrace; - int numtouchedicts; - prvm_edict_t *touchedicts[MAX_EDICTS]; - - VectorCopy(start, clipstart); - VectorCopy(end, clipend); - VectorCopy(mins, clipmins); - VectorCopy(maxs, clipmaxs); - VectorCopy(mins, clipmins2); - VectorCopy(maxs, clipmaxs2); -#if COLLISIONPARANOID >= 3 - Con_Printf("move(%f %f %f,%f %f %f)", clipstart[0], clipstart[1], clipstart[2], clipend[0], clipend[1], clipend[2]); -#endif - - if (passedict) - { - val = PRVM_GETEDICTFIELDVALUE(passedict, eval_dphitcontentsmask); - if (val && val->_float) - hitsupercontentsmask = (int)val->_float; - else if (passedict->fields.server->solid == SOLID_SLIDEBOX) - { - if ((int)passedict->fields.server->flags & FL_MONSTER) - hitsupercontentsmask = SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_MONSTERCLIP; - else - hitsupercontentsmask = SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_PLAYERCLIP; - } - else if (passedict->fields.server->solid == SOLID_CORPSE) - hitsupercontentsmask = SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY; - else - hitsupercontentsmask = SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_CORPSE; - } - else - hitsupercontentsmask = SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_CORPSE; - - // clip to world - cliptrace = SV_ClipMoveToWorld(clipstart, clipmins, clipmaxs, clipend, type, hitsupercontentsmask); - cliptrace.bmodelstartsolid = cliptrace.startsolid; - if (cliptrace.startsolid || cliptrace.fraction < 1) - cliptrace.ent = prog->edicts; - if (type == MOVE_WORLDONLY) - return cliptrace; - - if (type == MOVE_MISSILE) - { - // LordHavoc: modified this, was = -15, now -= 15 - for (i = 0;i < 3;i++) - { - clipmins2[i] -= 15; - clipmaxs2[i] += 15; - } - } - - // get adjusted box for bmodel collisions if the world is q1bsp or hlbsp - if (sv.worldmodel && sv.worldmodel->brush.RoundUpToHullSize) - sv.worldmodel->brush.RoundUpToHullSize(sv.worldmodel, clipmins, clipmaxs, hullmins, hullmaxs); - else - { - VectorCopy(clipmins, hullmins); - VectorCopy(clipmaxs, hullmaxs); - } - - // create the bounding box of the entire move - for (i = 0;i < 3;i++) - { - clipboxmins[i] = min(clipstart[i], cliptrace.endpos[i]) + min(hullmins[i], clipmins2[i]) - 1; - clipboxmaxs[i] = max(clipstart[i], cliptrace.endpos[i]) + max(hullmaxs[i], clipmaxs2[i]) + 1; - } - - // debug override to test against everything - if (sv_debugmove.integer) - { - clipboxmins[0] = clipboxmins[1] = clipboxmins[2] = -999999999; - clipboxmaxs[0] = clipboxmaxs[1] = clipboxmaxs[2] = 999999999; - } - - // if the passedict is world, make it NULL (to avoid two checks each time) - if (passedict == prog->edicts) - passedict = NULL; - // precalculate prog value for passedict for comparisons - passedictprog = PRVM_EDICT_TO_PROG(passedict); - // figure out whether this is a point trace for comparisons - pointtrace = VectorCompare(clipmins, clipmaxs); - // precalculate passedict's owner edict pointer for comparisons - traceowner = passedict ? PRVM_PROG_TO_EDICT(passedict->fields.server->owner) : 0; - - // clip to entities - numtouchedicts = SV_EntitiesInBox(clipboxmins, clipboxmaxs, MAX_EDICTS, touchedicts); - if (numtouchedicts > MAX_EDICTS) - { - // this never happens - Con_Printf("SV_EntitiesInBox returned %i edicts, max was %i\n", numtouchedicts, MAX_EDICTS); - numtouchedicts = MAX_EDICTS; - } - for (i = 0;i < numtouchedicts;i++) - { - touch = touchedicts[i]; - - if (touch->fields.server->solid < SOLID_BBOX) - continue; - if (type == MOVE_NOMONSTERS && touch->fields.server->solid != SOLID_BSP) - continue; - - if (passedict) - { - // don't clip against self - if (passedict == touch) - continue; - // don't clip owned entities against owner - if (traceowner == touch) - continue; - // don't clip owner against owned entities - if (passedictprog == touch->fields.server->owner) - continue; - // don't clip points against points (they can't collide) - if (pointtrace && VectorCompare(touch->fields.server->mins, touch->fields.server->maxs) && (type != MOVE_MISSILE || !((int)touch->fields.server->flags & FL_MONSTER))) - continue; - } - - // might interact, so do an exact clip - if ((int)touch->fields.server->flags & FL_MONSTER) - trace = SV_ClipMoveToEntity(touch, clipstart, clipmins2, clipmaxs2, clipend, type, hitsupercontentsmask); - else - trace = SV_ClipMoveToEntity(touch, clipstart, clipmins, clipmaxs, clipend, type, hitsupercontentsmask); - // LordHavoc: take the 'best' answers from the new trace and combine with existing data - if (trace.allsolid) - cliptrace.allsolid = true; - if (trace.startsolid) - { - if (touch->fields.server->solid == SOLID_BSP) - cliptrace.bmodelstartsolid = true; - cliptrace.startsolid = true; - if (cliptrace.realfraction == 1) - cliptrace.ent = touch; - } - // don't set this except on the world, because it can easily confuse - // monsters underwater if there's a bmodel involved in the trace - // (inopen && inwater is how they check water visibility) - //if (trace.inopen) - // cliptrace.inopen = true; - if (trace.inwater) - cliptrace.inwater = true; - if (trace.realfraction < cliptrace.realfraction) - { - cliptrace.fraction = trace.fraction; - cliptrace.realfraction = trace.realfraction; - VectorCopy(trace.endpos, cliptrace.endpos); - cliptrace.plane = trace.plane; - cliptrace.ent = touch; - cliptrace.hitsupercontents = trace.hitsupercontents; - cliptrace.hitq3surfaceflags = trace.hitq3surfaceflags; - cliptrace.hittexture = trace.hittexture; - } - cliptrace.startsupercontents |= trace.startsupercontents; - } - - return cliptrace; + VectorCopy(mins, ent->priv.server->areamins); + VectorCopy(maxs, ent->priv.server->areamaxs); + World_LinkEdict_AreaGrid(world, ent); } - -#if COLLISIONPARANOID >= 1 -trace_t SV_Move(const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int type, prvm_edict_t *passedict) -{ - int endstuck; - trace_t trace; - vec3_t temp; - trace = SV_Move_(start, mins, maxs, end, type, passedict); - if (passedict) - { - VectorCopy(trace.endpos, temp); - endstuck = SV_Move_(temp, mins, maxs, temp, type, passedict).startsolid; -#if COLLISIONPARANOID < 3 - if (trace.startsolid || endstuck) -#endif - Con_Printf("%s{e%i:%f %f %f:%f %f %f:%f:%f %f %f%s%s}\n", (trace.startsolid || endstuck) ? "^3" : "", passedict ? (int)(passedict - prog->edicts) : -1, passedict->fields.server->origin[0], passedict->fields.server->origin[1], passedict->fields.server->origin[2], end[0] - passedict->fields.server->origin[0], end[1] - passedict->fields.server->origin[1], end[2] - passedict->fields.server->origin[2], trace.fraction, trace.endpos[0] - passedict->fields.server->origin[0], trace.endpos[1] - passedict->fields.server->origin[1], trace.endpos[2] - passedict->fields.server->origin[2], trace.startsolid ? " startstuck" : "", endstuck ? " endstuck" : ""); - } - return trace; -} -#endif - - diff --git a/world.h b/world.h index e01b831c..f591cbac 100644 --- a/world.h +++ b/world.h @@ -30,35 +30,55 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define MOVE_WORLDONLY 3 #define MOVE_HITMODEL 4 +#define AREA_GRID 512 +#define AREA_GRIDNODES (AREA_GRID * AREA_GRID) + +typedef struct link_s +{ + int entitynumber; + struct link_s *prev, *next; +} link_t; + +typedef struct world_s +{ + int areagrid_stats_calls; + int areagrid_stats_nodechecks; + int areagrid_stats_entitychecks; + + link_t areagrid[AREA_GRIDNODES]; + link_t areagrid_outside; + vec3_t areagrid_bias; + vec3_t areagrid_scale; + vec3_t areagrid_mins; + vec3_t areagrid_maxs; + vec3_t areagrid_size; + int areagrid_marknumber; +} +world_t; + +struct prvm_edict_s; + +// cyclic doubly-linked list functions +void World_ClearLink(link_t *l); +void World_RemoveLink(link_t *l); +void World_InsertLinkBefore(link_t *l, link_t *before, int entitynumber); + +void World_Init(void); // called after the world model has been loaded, before linking any entities -void SV_ClearWorld (void); +void World_Clear(world_t *world); + +void World_PrintAreaStats(world_t *world, const char *worldname); // call before removing an entity, and before trying to move one, // so it doesn't clip against itself -void SV_UnlinkEdict (prvm_edict_t *ent); +void World_UnlinkEdict(struct prvm_edict_s *ent); -// Needs to be called any time an entity changes origin, mins, maxs, or solid -// sets ent->v.absmin and ent->v.absmax -// if touchtriggers, calls prog functions for the intersected triggers -void SV_LinkEdict (prvm_edict_t *ent, qboolean touch_triggers); +// Needs to be called any time an entity changes origin, mins, maxs +void World_LinkEdict(world_t *world, struct prvm_edict_s *ent, const vec3_t mins, const vec3_t maxs); // returns list of entities touching a box -int SV_EntitiesInBox(vec3_t mins, vec3_t maxs, int maxlist, prvm_edict_t **list); - -// mins and maxs are relative -// if the entire move stays in a solid volume, trace.allsolid will be set - -// if the starting point is in a solid, it will be allowed to move out -// to an open area - -// nomonsters is used for line of sight or edge testing, where mosnters -// shouldn't be considered solid objects - -// passedict is explicitly excluded from clipping checks (normally NULL) -trace_t SV_Move(const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int type, prvm_edict_t *passedict); - -#define SV_PointSuperContents(point) (SV_Move((point), vec3_origin, vec3_origin, (point), sv_gameplayfix_swiminbmodels.integer ? MOVE_NOMONSTERS : MOVE_WORLDONLY, NULL).startsupercontents) +int World_EntitiesInBox(world_t *world, vec3_t mins, vec3_t maxs, int maxlist, struct prvm_edict_s **list); #endif -- 2.39.2