//
for (i=0 ; i<3 ; i++)
{
- if (PRVM_IS_NAN(PRVM_serveredictvector(ent, velocity)[i]))
+ if (isnan(PRVM_serveredictvector(ent, velocity)[i]))
{
Con_Printf("Got a NaN velocity on entity #%i (%s)\n", PRVM_NUM_FOR_EDICT(ent), PRVM_GetString(prog, PRVM_serveredictstring(ent, classname)));
PRVM_serveredictvector(ent, velocity)[i] = 0;
}
- if (PRVM_IS_NAN(PRVM_serveredictvector(ent, origin)[i]))
+ if (isnan(PRVM_serveredictvector(ent, origin)[i]))
{
Con_Printf("Got a NaN origin on entity #%i (%s)\n", PRVM_NUM_FOR_EDICT(ent), PRVM_GetString(prog, PRVM_serveredictstring(ent, classname)));
PRVM_serveredictvector(ent, origin)[i] = 0;
SV_Impact
Two entities have touched, so run their touch functions
+Returns true if the push did not result in the entity being teleported by QC code.
==================
*/
-static void SV_Impact (prvm_edict_t *e1, trace_t *trace)
+static qbool SV_Impact (prvm_edict_t *e1, trace_t *trace)
{
prvm_prog_t *prog = SVVM_prog;
int restorevm_tempstringsbuf_cursize;
int old_self, old_other;
prvm_edict_t *e2 = (prvm_edict_t *)trace->ent;
+ e1->priv.required->mark = PRVM_EDICT_MARK_WAIT_FOR_SETORIGIN; // -2: setorigin running
+
old_self = PRVM_serverglobaledict(self);
old_other = PRVM_serverglobaledict(other);
restorevm_tempstringsbuf_cursize = prog->tempstringsbuf.cursize;
PRVM_serverglobaledict(self) = old_self;
PRVM_serverglobaledict(other) = old_other;
prog->tempstringsbuf.cursize = restorevm_tempstringsbuf_cursize;
+
+ if(e1->priv.required->mark == PRVM_EDICT_MARK_SETORIGIN_CAUGHT)
+ {
+ e1->priv.required->mark = 0;
+ return false;
+ }
+ else if(e1->priv.required->mark == PRVM_EDICT_MARK_WAIT_FOR_SETORIGIN)
+ {
+ e1->priv.required->mark = 0;
+ return true;
+ }
+ else
+ {
+ Con_Printf(CON_ERROR "The edict mark had been overwritten! Please debug this.\n");
+ return true;
+ }
}
============
*/
static float SV_Gravity (prvm_edict_t *ent);
-static qbool SV_PushEntity (trace_t *trace, prvm_edict_t *ent, vec3_t push, qbool dolink);
+static qbool SV_PushEntity (trace_t *trace, prvm_edict_t *ent, vec3_t push, qbool dotouch, qbool checkstuck);
#define MAX_CLIP_PLANES 5
static int SV_FlyMove (prvm_edict_t *ent, float time, qbool applygravity, float *stepnormal, int hitsupercontentsmask, int skipsupercontentsmask, int skipmaterialflagsmask, float stepheight)
{
prvm_prog_t *prog = SVVM_prog;
- int blocked, bumpcount;
- int i, j, numplanes;
+ unsigned int i, j, numplanes, blocked, bumpcount;
float d, time_left, gravity;
vec3_t dir, push, planes[MAX_CLIP_PLANES];
prvm_vec3_t primal_velocity, original_velocity, new_velocity, restore_velocity;
break;
VectorScale(PRVM_serveredictvector(ent, velocity), time_left, push);
- if(!SV_PushEntity(&trace, ent, push, false))
+ if(!SV_PushEntity(&trace, ent, push, sv_gameplayfix_impactbeforeonground.integer, true))
{
// we got teleported by a touch function
// let's abort the move
VectorSet(steppush, 0, 0, stepheight);
VectorScale(PRVM_serveredictvector(ent, velocity), time_left, push);
VectorCopy(PRVM_serveredictvector(ent, origin), org);
- if(!SV_PushEntity(&steptrace, ent, steppush, false))
+ if(!SV_PushEntity(&steptrace, ent, steppush, false, true))
{
blocked |= 8;
break;
}
//Con_Printf("%f %f %f : ", PRVM_serveredictvector(ent, origin)[0], PRVM_serveredictvector(ent, origin)[1], PRVM_serveredictvector(ent, origin)[2]);
- if(!SV_PushEntity(&steptrace2, ent, push, false))
+ if(!SV_PushEntity(&steptrace2, ent, push, false, true))
{
blocked |= 8;
break;
}
//Con_Printf("%f %f %f : ", PRVM_serveredictvector(ent, origin)[0], PRVM_serveredictvector(ent, origin)[1], PRVM_serveredictvector(ent, origin)[2]);
VectorSet(steppush, 0, 0, org[2] - PRVM_serveredictvector(ent, origin)[2]);
- if(!SV_PushEntity(&steptrace3, ent, steppush, false))
+ if(!SV_PushEntity(&steptrace3, ent, steppush, false, true))
{
blocked |= 8;
break;
if (stepnormal)
VectorCopy(trace.plane.normal, stepnormal);
}
+
+ if (!sv_gameplayfix_impactbeforeonground.integer)
+ {
+ // Unlike some other movetypes Quake's SV_FlyMove calls SV_Impact only after setting ONGROUND which id1 fiends rely on.
+ // If we stepped up (sv_gameplayfix_stepmultipletimes) this will impact the steptrace2 plane instead of the original.
+ if (PRVM_serveredictfloat(ent, solid) >= SOLID_TRIGGER && trace.ent)
+ if (!SV_Impact(ent, &trace))
+ {
+ blocked |= 8;
+ break;
+ }
+ if (ent->free)
+ return blocked; // removed by the impact function
+ }
+
if (trace.fraction >= 0.001)
{
// actually covered some distance
Returns true if the push did not result in the entity being teleported by QC code.
============
*/
-static qbool SV_PushEntity (trace_t *trace, prvm_edict_t *ent, vec3_t push, qbool dolink)
+static qbool SV_PushEntity (trace_t *trace, prvm_edict_t *ent, vec3_t push, qbool dotouch, qbool checkstuck)
{
prvm_prog_t *prog = SVVM_prog;
int solid;
VectorCopy(PRVM_serveredictvector(ent, mins), mins);
VectorCopy(PRVM_serveredictvector(ent, maxs), maxs);
- // move start position out of solids
- if (sv_gameplayfix_nudgeoutofsolid.integer && sv_gameplayfix_nudgeoutofsolid_separation.value >= 0)
- {
- PHYS_NudgeOutOfSolid(prog, ent);
- }
-
VectorCopy(PRVM_serveredictvector(ent, origin), start);
VectorAdd(start, push, end);
type = MOVE_NORMAL;
*trace = SV_TraceBox(start, mins, maxs, end, type, ent, SV_GenericHitSuperContentsMask(ent), 0, 0, collision_extendmovelength.value);
- // fail the move if stuck in world
- if (trace->worldstartsolid)
- return true;
+ if (trace->allsolid && checkstuck)
+ {
+ if (SV_UnstickEntity(ent))
+ {
+ VectorCopy(PRVM_serveredictvector(ent, origin), start);
+ VectorAdd(start, push, end);
+ *trace = SV_TraceBox(start, mins, maxs, end, type, ent, SV_GenericHitSuperContentsMask(ent), 0, 0, collision_extendmovelength.value);
+ }
+ // abort move if we're stuck in the world (and didn't make it out)
+ else if (trace->worldstartsolid)
+ return true;
+ }
VectorCopy(trace->endpos, PRVM_serveredictvector(ent, origin));
-
- ent->priv.required->mark = PRVM_EDICT_MARK_WAIT_FOR_SETORIGIN; // -2: setorigin running
+ VectorCopy(trace->endpos, PRVM_serveredictvector(ent, oldorigin)); // for SV_UnstickEntity()
SV_LinkEdict(ent);
}
#endif
- if (dolink)
+ if (dotouch)
+ {
SV_LinkEdict_TouchAreaGrid(ent);
- if((PRVM_serveredictfloat(ent, solid) >= SOLID_TRIGGER && trace->ent && (!((int)PRVM_serveredictfloat(ent, flags) & FL_ONGROUND) || PRVM_serveredictedict(ent, groundentity) != PRVM_EDICT_TO_PROG(trace->ent))))
- SV_Impact (ent, trace);
-
- if(ent->priv.required->mark == PRVM_EDICT_MARK_SETORIGIN_CAUGHT)
- {
- ent->priv.required->mark = 0;
- return false;
- }
- else if(ent->priv.required->mark == PRVM_EDICT_MARK_WAIT_FOR_SETORIGIN)
- {
- ent->priv.required->mark = 0;
- return true;
- }
- else
- {
- Con_Printf("The edict mark had been overwritten! Please debug this.\n");
- return true;
+ if((PRVM_serveredictfloat(ent, solid) >= SOLID_TRIGGER && trace->ent && (!((int)PRVM_serveredictfloat(ent, flags) & FL_ONGROUND) || PRVM_serveredictedict(ent, groundentity) != PRVM_EDICT_TO_PROG(trace->ent))))
+ return SV_Impact (ent, trace);
}
+
+ return true;
}
// try moving the contacted entity
PRVM_serveredictfloat(pusher, solid) = SOLID_NOT;
- if(!SV_PushEntity (&trace, check, move, true))
+ if(!SV_PushEntity(&trace, check, move, true, true))
{
// entity "check" got teleported
PRVM_serveredictvector(check, angles)[1] += trace.fraction * moveangle[1];
{
// hack to invoke all necessary movement triggers
VectorClear(move2);
- if(!SV_PushEntity(&trace2, check, move2, true))
+ if(!SV_PushEntity(&trace2, check, move2, true, true))
{
// entity "check" got teleported
continue;
typedef enum unstickresult_e
{
+ // matching the DP_QC_NUDGEOUTOFSOLID return values
UNSTICK_STUCK = 0,
- UNSTICK_GOOD = 1,
- UNSTICK_UNSTUCK = 2
+ UNSTICK_GOOD = -1, ///< didn't need to be unstuck
+ UNSTICK_UNSTUCK = 1
}
unstickresult_t;
if (!SV_TestEntityPosition(ent, unstickoffsets + i))
{
VectorCopy(unstickoffsets + i, offset);
- SV_LinkEdict(ent);
- //SV_LinkEdict_TouchAreaGrid(ent);
return UNSTICK_UNSTUCK;
}
}
VectorClear(offset);
offset[2] = -i;
if (!SV_TestEntityPosition(ent, offset))
- {
- SV_LinkEdict(ent);
- //SV_LinkEdict_TouchAreaGrid(ent);
return UNSTICK_UNSTUCK;
- }
offset[2] = i;
if (!SV_TestEntityPosition(ent, offset))
- {
- SV_LinkEdict(ent);
- //SV_LinkEdict_TouchAreaGrid(ent);
return UNSTICK_UNSTUCK;
- }
}
return UNSTICK_STUCK;
}
-qbool SV_UnstickEntity (prvm_edict_t *ent)
-{
- prvm_prog_t *prog = SVVM_prog;
- vec3_t offset;
- switch(SV_UnstickEntityReturnOffset(ent, offset))
- {
- case UNSTICK_GOOD:
- return true;
- case UNSTICK_UNSTUCK:
- Con_DPrintf("Unstuck entity %i (classname \"%s\") with offset %f %f %f.\n", (int)PRVM_EDICT_TO_PROG(ent), PRVM_GetString(prog, PRVM_serveredictstring(ent, classname)), offset[0], offset[1], offset[2]);
- return true;
- case UNSTICK_STUCK:
- if (developer_extra.integer)
- Con_DPrintf("Stuck entity %i (classname \"%s\").\n", (int)PRVM_EDICT_TO_PROG(ent), PRVM_GetString(prog, PRVM_serveredictstring(ent, classname)));
- return false;
- default:
- Con_Printf("SV_UnstickEntityReturnOffset returned a value outside its enum.\n");
- return false;
- }
-}
-
/*
=============
SV_CheckStuck
clipping hull.
=============
*/
-static void SV_CheckStuck (prvm_edict_t *ent)
+qbool SV_UnstickEntity (prvm_edict_t *ent)
{
prvm_prog_t *prog = SVVM_prog;
vec3_t offset;
+ if (sv_gameplayfix_nudgeoutofsolid.integer && sv_gameplayfix_nudgeoutofsolid_separation.value >= 0
+ && sv.worldmodel->TraceBox == Mod_CollisionBIH_TraceBox) // Mod_Q1BSP_TraceBox doesn't support startdepth
+ {
+ VectorCopy(PRVM_serveredictvector(ent, origin), offset);
+ switch (PHYS_NudgeOutOfSolid(prog, ent))
+ {
+ case UNSTICK_GOOD:
+ return true;
+ case UNSTICK_UNSTUCK:
+ VectorSubtract(PRVM_serveredictvector(ent, origin), offset, offset);
+ Con_DPrintf("NudgeOutOfSolid fixed stuck entity %i (classname \"%s\") with offset %f %f %f.\n", (int)PRVM_EDICT_TO_PROG(ent), PRVM_GetString(prog, PRVM_serveredictstring(ent, classname)), offset[0], offset[1], offset[2]);
+ return true;
+ case UNSTICK_STUCK:
+ Con_DPrintf(CON_WARN "NudgeOutOfSolid couldn't fix stuck entity %i (classname \"%s\").\n", (int)PRVM_EDICT_TO_PROG(ent), PRVM_GetString(prog, PRVM_serveredictstring(ent, classname)));
+ return false;
+ default:
+ Con_Printf("NudgeOutOfSolid returned a value outside its enum.\n");
+ return false;
+ }
+ }
+
+ if (!(PRVM_NUM_FOR_EDICT(ent) <= svs.maxclients ? sv_gameplayfix_unstickplayers : sv_gameplayfix_unstickentities).integer)
+ return false;
+
switch(SV_UnstickEntityReturnOffset(ent, offset))
{
case UNSTICK_GOOD:
- VectorCopy (PRVM_serveredictvector(ent, origin), PRVM_serveredictvector(ent, oldorigin));
- break;
+ return true;
case UNSTICK_UNSTUCK:
- Con_DPrintf("Unstuck player entity %i (classname \"%s\") with offset %f %f %f.\n", (int)PRVM_EDICT_TO_PROG(ent), PRVM_GetString(prog, PRVM_serveredictstring(ent, classname)), offset[0], offset[1], offset[2]);
- break;
+ Con_DPrintf("Unstuck entity %i (classname \"%s\") with offset %f %f %f.\n", (int)PRVM_EDICT_TO_PROG(ent), PRVM_GetString(prog, PRVM_serveredictstring(ent, classname)), offset[0], offset[1], offset[2]);
+ return true;
case UNSTICK_STUCK:
VectorSubtract(PRVM_serveredictvector(ent, oldorigin), PRVM_serveredictvector(ent, origin), offset);
if (!SV_TestEntityPosition(ent, offset))
{
- Con_DPrintf("Unstuck player entity %i (classname \"%s\") by restoring oldorigin.\n", (int)PRVM_EDICT_TO_PROG(ent), PRVM_GetString(prog, PRVM_serveredictstring(ent, classname)));
- SV_LinkEdict(ent);
- //SV_LinkEdict_TouchAreaGrid(ent);
+ Con_DPrintf("Unstuck entity %i (classname \"%s\") by restoring oldorigin.\n", (int)PRVM_EDICT_TO_PROG(ent), PRVM_GetString(prog, PRVM_serveredictstring(ent, classname)));
+ return true;
}
- else
- Con_DPrintf("Stuck player entity %i (classname \"%s\").\n", (int)PRVM_EDICT_TO_PROG(ent), PRVM_GetString(prog, PRVM_serveredictstring(ent, classname)));
- break;
+ Con_DPrintf(CON_WARN "Stuck entity %i (classname \"%s\").\n", (int)PRVM_EDICT_TO_PROG(ent), PRVM_GetString(prog, PRVM_serveredictstring(ent, classname)));
+ return false;
default:
Con_Printf("SV_UnstickEntityReturnOffset returned a value outside its enum.\n");
+ return false;
}
}
if (sv.frametime <= 0)
return;
- if (sv_gameplayfix_unstickplayers.integer)
- SV_CheckStuck (ent);
-
applygravity = !SV_CheckWater (ent) && PRVM_serveredictfloat(ent, movetype) == MOVETYPE_WALK && ! ((int)PRVM_serveredictfloat(ent, flags) & FL_WATERJUMP);
SV_CheckVelocity(ent);
// move up
VectorClear (upmove);
upmove[2] = sv_stepheight.value;
- if(!SV_PushEntity(&trace, ent, upmove, true))
+ if(!SV_PushEntity(&trace, ent, upmove, true, true))
{
// we got teleported when upstepping... must abort the move
return;
// move down
VectorClear (downmove);
downmove[2] = -sv_stepheight.value + start_velocity[2]*sv.frametime;
- if(!SV_PushEntity (&downtrace, ent, downmove, true))
+ if(!SV_PushEntity(&downtrace, ent, downmove, true, true))
{
// we got teleported when downstepping... must abort the move
return;
{
// move origin
VectorScale(PRVM_serveredictvector(ent, velocity), movetime, move);
- if(!SV_PushEntity(&trace, ent, move, true))
+ // The buzzsaw traps in r2m6 and r2m7 use MOVETYPE_FLY and rely on moving while stuck in the world.
+ // Quake movetypes checked allsolid only in SV_FlyMove().
+ if(!SV_PushEntity(&trace, ent, move, true, PRVM_serveredictfloat(ent, movetype) != MOVETYPE_FLY))
return; // teleported
if (ent->free)
return;
- if (trace.bmodelstartsolid && sv_gameplayfix_unstickentities.integer)
- {
- // try to unstick the entity
- SV_UnstickEntity(ent);
- if(!SV_PushEntity(&trace, ent, move, true))
- return; // teleported
- if (ent->free)
- return;
- }
if (trace.fraction == 1)
break;
movetime *= 1 - min(1, trace.fraction);
}
}
+// asynchronous path
void SV_Physics_ClientMove(void)
{
prvm_prog_t *prog = SVVM_prog;