==================
*/
#if COLLISIONPARANOID >= 1
-trace_t SV_TraceBox_(const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int type, prvm_edict_t *passedict, int hitsupercontentsmask, int skipsupercontentsmask, int skipmaterialflagsmask, float extend)
+static trace_t SV_TraceBox_(const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int type, prvm_edict_t *passedict, int hitsupercontentsmask, int skipsupercontentsmask, int skipmaterialflagsmask, float extend)
#else
trace_t SV_TraceBox(const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int type, prvm_edict_t *passedict, int hitsupercontentsmask, int skipsupercontentsmask, int skipmaterialflagsmask, float extend)
#endif
}
#if COLLISIONPARANOID >= 1
-trace_t SV_TraceBox(const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int type, prvm_edict_t *passedict, int hitsupercontentsmask, int skipsupercontentsmask, int skipmaterialflagsmask)
+trace_t SV_TraceBox(const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int type, prvm_edict_t *passedict, int hitsupercontentsmask, int skipsupercontentsmask, int skipmaterialflagsmask, float extend)
{
prvm_prog_t *prog = SVVM_prog;
int endstuck;
trace_t trace;
vec3_t temp;
- trace = SV_TraceBox_(start, mins, maxs, end, type, passedict, hitsupercontentsmask, skipsupercontentsmask, skipmaterialflagsmask);
+ trace = SV_TraceBox_(start, mins, maxs, end, type, passedict, hitsupercontentsmask, skipsupercontentsmask, skipmaterialflagsmask, extend);
if (passedict)
{
VectorCopy(trace.endpos, temp);
- endstuck = SV_TraceBox_(temp, mins, maxs, temp, type, passedict, hitsupercontentsmask, skipsupercontentsmask, skipmaterialflagsmask).startsolid;
+ endstuck = SV_TraceBox_(temp, mins, maxs, temp, type, passedict, hitsupercontentsmask, skipsupercontentsmask, skipmaterialflagsmask, extend).startsolid;
#if COLLISIONPARANOID < 3
if (trace.startsolid || endstuck)
#endif
VectorAdd(PRVM_serveredictvector(ent, origin), PRVM_serveredictvector(ent, 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)PRVM_serveredictfloat(ent, flags) & FL_ITEM)
+ if (sv_legacy_bbox_expand.integer)
{
- 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;
+ if ((int)PRVM_serveredictfloat(ent, flags) & FL_ITEM)
+ {
+ // to make items easier to pick up and allow them to be grabbed off
+ // of shelves, the abs sizes are expanded
+ 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, PRVM_serveredictvector(ent, absmin));
VectorCopy(maxs, PRVM_serveredictvector(ent, absmax));
- World_LinkEdict(&sv.world, ent, mins, maxs);
+ World_LinkEdict(&sv.world, ent, mins, maxs, sv_areagrid_link_SOLID_NOT.integer);
}
/*
============
*/
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 dolink, 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)
{
break;
VectorScale(PRVM_serveredictvector(ent, velocity), time_left, push);
- if(!SV_PushEntity(&trace, ent, push, false))
+ if(!SV_PushEntity(&trace, ent, push, false, true))
{
// we got teleported by a touch function
// let's abort the move
// this code is used by MOVETYPE_WALK and MOVETYPE_STEP and SV_UnstickEntity
// abort move if we're stuck in the world (and didn't make it out)
- if (trace.worldstartsolid && trace.allsolid)
+ if (trace.worldstartsolid && trace.allsolid && trace.startdepth < 0)
{
VectorCopy(restore_velocity, PRVM_serveredictvector(ent, velocity));
return 3;
if (trace.fraction == 1)
break;
+
+ time_left *= 1 - trace.fraction;
+
if (trace.plane.normal[2])
{
if (trace.plane.normal[2] > 0.7)
trace_t steptrace3;
//Con_Printf("step %f %f %f : ", PRVM_serveredictvector(ent, origin)[0], PRVM_serveredictvector(ent, origin)[1], PRVM_serveredictvector(ent, origin)[2]);
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;
}
//Con_Printf("%f %f %f : ", PRVM_serveredictvector(ent, origin)[0], PRVM_serveredictvector(ent, origin)[1], PRVM_serveredictvector(ent, origin)[2]);
// accept the new position if it made some progress...
- if (fabs(PRVM_serveredictvector(ent, origin)[0] - org[0]) >= 0.03125 || fabs(PRVM_serveredictvector(ent, origin)[1] - org[1]) >= 0.03125)
+ // previously this checked if absolute distance >= 0.03125 which made stepping up unreliable
+ if (PRVM_serveredictvector(ent, origin)[0] - org[0] || PRVM_serveredictvector(ent, origin)[1] - org[1])
{
//Con_Printf("accepted (delta %f %f %f)\n", PRVM_serveredictvector(ent, origin)[0] - org[0], PRVM_serveredictvector(ent, origin)[1] - org[1], PRVM_serveredictvector(ent, origin)[2] - org[2]);
trace = steptrace2;
if (stepnormal)
VectorCopy(trace.plane.normal, stepnormal);
}
+
+ // 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)
+ SV_Impact(ent, &trace);
+ if (ent->free)
+ return blocked; // removed by the impact function
+
if (trace.fraction >= 0.001)
{
// actually covered some distance
numplanes = 0;
}
- time_left *= 1 - trace.fraction;
-
// clipped to another plane
if (numplanes >= MAX_CLIP_PLANES)
{
return true;
}
-qbool SV_NudgeOutOfSolid(prvm_edict_t *ent)
-{
- prvm_prog_t *prog = SVVM_prog;
- int bump, pass;
- trace_t stucktrace;
- vec3_t stuckorigin;
- vec3_t stuckmins, stuckmaxs;
- vec_t nudge;
- vec_t separation = sv_gameplayfix_nudgeoutofsolid_separation.value;
- if (sv.worldmodel && sv.worldmodel->brushq1.numclipnodes)
- separation = 0.0f; // when using hulls, it can not be enlarged
- VectorCopy(PRVM_serveredictvector(ent, mins), stuckmins);
- VectorCopy(PRVM_serveredictvector(ent, maxs), stuckmaxs);
- stuckmins[0] -= separation;
- stuckmins[1] -= separation;
- stuckmins[2] -= separation;
- stuckmaxs[0] += separation;
- stuckmaxs[1] += separation;
- stuckmaxs[2] += separation;
- // first pass we try to get it out of brush entities
- // second pass we try to get it out of world only (can't win them all)
- for (pass = 0;pass < 2;pass++)
- {
- VectorCopy(PRVM_serveredictvector(ent, origin), stuckorigin);
- for (bump = 0;bump < 10;bump++)
- {
- stucktrace = SV_TraceBox(stuckorigin, stuckmins, stuckmaxs, stuckorigin, pass ? MOVE_WORLDONLY : MOVE_NOMONSTERS, ent, SV_GenericHitSuperContentsMask(ent), 0, 0, collision_extendmovelength.value);
- if (!stucktrace.bmodelstartsolid || stucktrace.startdepth >= 0)
- {
- // found a good location, use it
- VectorCopy(stuckorigin, PRVM_serveredictvector(ent, origin));
- return true;
- }
- nudge = -stucktrace.startdepth;
- VectorMA(stuckorigin, nudge, stucktrace.startdepthnormal, stuckorigin);
- }
- }
- return false;
-}
-
/*
============
SV_PushEntity
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 dolink, 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)
- {
- SV_NudgeOutOfSolid(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;
+ // abort move if we're stuck in the world (and didn't make it out)
+ if (trace->worldstartsolid && trace->allsolid && trace->startdepth < 0 && checkstuck)
+ {
+ // checking startdepth eliminates many false positives on Q1BSP with mod_q1bsp_polygoncollisions 0
+ // but it's still not guaranteed that we're stuck in a bmodel at this point
+ if (sv_gameplayfix_nudgeoutofsolid.integer && sv_gameplayfix_nudgeoutofsolid_separation.value >= 0)
+ {
+ switch (PHYS_NudgeOutOfSolid(prog, ent))
+ {
+ case 0:
+ Con_Printf(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 true; // definitely stuck in a bmodel
+ case 1:
+ 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)), PRVM_serveredictvector(ent, origin)[0] - start[0], PRVM_serveredictvector(ent, origin)[1] - start[1], PRVM_serveredictvector(ent, origin)[2] - start[2]);
+ 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);
+
+ // definitely not stuck in a bmodel, move may proceed
+ }
+ }
+ else if (sv_gameplayfix_unstickentities.integer && SV_UnstickEntity(ent))
+ {
+ // bones_was_here: pretty sure we can deprecate sv_gameplayfix_unstickentities, sv_gameplayfix_nudgeoutofsolid is much nicer
+ 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);
+ }
+ else
+ return true; // assuming stuck, bones_was_here TODO: always use PHYS_NudgeOutOfSolid (remove sv_gameplayfix_nudgeoutofsolid)?
+ }
VectorCopy(trace->endpos, PRVM_serveredictvector(ent, origin));
#endif
if (dolink)
+ {
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((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)
{
// 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;
VectorCopy(PRVM_serveredictvector(ent, maxs), entmaxs);
trace = SV_TraceBox(upmove, entmins, entmaxs, downmove, type, ent, SV_GenericHitSuperContentsMask(ent), skipsupercontentsmask, skipmaterialflagsmask, collision_extendmovelength.value);
if(trace.fraction < 1 && trace.plane.normal[2] > 0.7)
+ {
clip |= 1; // but we HAVE found a floor
+ // set groundentity so we get carried when walking onto a mover with sv_gameplayfix_nogravityonground
+ PRVM_serveredictedict(ent, groundentity) = PRVM_EDICT_TO_PROG(trace.ent);
+ }
}
// if the move did not hit the ground at any point, we're not on ground
// 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;