cvar_t sv_gameplayfix_multiplethinksperframe = {CF_SERVER, "sv_gameplayfix_multiplethinksperframe", "1", "allows entities to think more often than the server framerate, primarily useful for very high fire rate weapons"};
cvar_t sv_gameplayfix_noairborncorpse = {CF_SERVER, "sv_gameplayfix_noairborncorpse", "1", "causes entities (corpses, items, etc) sitting ontop of moving entities (players) to fall when the moving entity (player) is no longer supporting them"};
cvar_t sv_gameplayfix_noairborncorpse_allowsuspendeditems = {CF_SERVER, "sv_gameplayfix_noairborncorpse_allowsuspendeditems", "1", "causes entities sitting ontop of objects that are instantaneously remove to float in midair (special hack to allow a common level design trick for floating items)"};
-cvar_t sv_gameplayfix_nudgeoutofsolid = {CF_SERVER, "sv_gameplayfix_nudgeoutofsolid", "1", "attempts to fix physics errors where an object ended up in solid for some reason, supersedes sv_gameplayfix_unstickentities"};
+cvar_t sv_gameplayfix_nudgeoutofsolid = {CF_SERVER, "sv_gameplayfix_nudgeoutofsolid", "0", "attempts to fix physics errors where an object ended up in solid for some reason, better than sv_gameplayfix_unstick* but currently has no effect on Q1BSP (unless mod_q1bsp_polygoncollisions is enabled)"};
cvar_t sv_gameplayfix_nudgeoutofsolid_separation = {CF_SERVER, "sv_gameplayfix_nudgeoutofsolid_separation", "0.03125", "keep objects this distance apart to prevent collision issues on seams"};
cvar_t sv_gameplayfix_q2airaccelerate = {CF_SERVER, "sv_gameplayfix_q2airaccelerate", "0", "Quake2-style air acceleration"};
cvar_t sv_gameplayfix_nogravityonground = {CF_SERVER, "sv_gameplayfix_nogravityonground", "0", "turn off gravity when on ground (to get rid of sliding)"};
cvar_t sv_gameplayfix_upwardvelocityclearsongroundflag = {CF_SERVER, "sv_gameplayfix_upwardvelocityclearsongroundflag", "1", "prevents monsters, items, and most other objects from being stuck to the floor when pushed around by damage, and other situations in mods"};
cvar_t sv_gameplayfix_downtracesupportsongroundflag = {CF_SERVER, "sv_gameplayfix_downtracesupportsongroundflag", "1", "prevents very short moves from clearing onground (which may make the player stick to the floor at high netfps), fixes groundentity not being set when walking onto a mover with sv_gameplayfix_nogravityonground"};
cvar_t sv_gameplayfix_q1bsptracelinereportstexture = {CF_SERVER, "sv_gameplayfix_q1bsptracelinereportstexture", "1", "enables mods to get accurate trace_texture results on q1bsp by using a surface-hitting traceline implementation rather than the standard solidbsp method, q3bsp always reports texture accurately"};
-cvar_t sv_gameplayfix_unstickplayers = {CF_SERVER, "sv_gameplayfix_unstickplayers", "0", "big hack to try and fix the rare case of MOVETYPE_WALK entities getting stuck in the world clipping hull."};
-cvar_t sv_gameplayfix_unstickentities = {CF_SERVER, "sv_gameplayfix_unstickentities", "1", "hack to check if entities are crossing world collision hull and try to move them to the right position, superseded by sv_gameplayfix_nudgeoutofsolid"};
+cvar_t sv_gameplayfix_unstickplayers = {CF_SERVER, "sv_gameplayfix_unstickplayers", "1", "big hack to try and fix the rare case of MOVETYPE_WALK entities getting stuck in the world clipping hull. Quake did something similar."};
+cvar_t sv_gameplayfix_unstickentities = {CF_SERVER, "sv_gameplayfix_unstickentities", "0", "hack to check if entities are crossing world collision hull and try to move them to the right position. Quake didn't do this so maps shouldn't depend on it."};
cvar_t sv_gameplayfix_fixedcheckwatertransition = {CF_SERVER, "sv_gameplayfix_fixedcheckwatertransition", "1", "fix two very stupid bugs in SV_CheckWaterTransition when watertype is CONTENTS_EMPTY (the bugs causes waterlevel to be 1 on first frame, -1 on second frame - the fix makes it 0 on both frames)"};
cvar_t sv_gravity = {CF_SERVER | CF_NOTIFY, "sv_gravity","800", "how fast you fall (512 = roughly earth gravity)"};
cvar_t sv_init_frame_count = {CF_SERVER, "sv_init_frame_count", "2", "number of frames to run to allow everything to settle before letting clients connect"};
// 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 && trace.startdepth < 0)
+ if (trace.worldstartsolid && trace.allsolid)
{
VectorCopy(restore_velocity, PRVM_serveredictvector(ent, velocity));
return 3;
type = MOVE_NORMAL;
*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)
- if (trace->worldstartsolid && trace->allsolid && trace->startdepth < 0 && checkstuck)
+ if (trace->allsolid && 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)
+ if (SV_UnstickEntity(ent))
{
- 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)?
+ // 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));
+ VectorCopy(trace->endpos, PRVM_serveredictvector(ent, oldorigin)); // for SV_UnstickEntity()
ent->priv.required->mark = PRVM_EDICT_MARK_WAIT_FOR_SETORIGIN; // -2: setorigin running
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);