From 99a6d49b09ca8af9cad901bda2fdc165c4dc3aba Mon Sep 17 00:00:00 2001 From: bones_was_here Date: Sun, 28 Apr 2024 09:23:56 +1000 Subject: [PATCH] physics: add a workaround cvar for mods relying on the id1 fiends bug Also checks for teleport by QC in both code paths (forgot to do that in e62e6f563b475060fca315b875aa672c692ad052). Signed-off-by: bones_was_here --- server.h | 1 + sv_main.c | 2 ++ sv_phys.c | 68 +++++++++++++++++++++++++++++++------------------------ 3 files changed, 42 insertions(+), 29 deletions(-) diff --git a/server.h b/server.h index 20637517..1ad3158e 100644 --- a/server.h +++ b/server.h @@ -446,6 +446,7 @@ extern cvar_t sv_gameplayfix_easierwaterjump; extern cvar_t sv_gameplayfix_findradiusdistancetobox; extern cvar_t sv_gameplayfix_gravityunaffectedbyticrate; extern cvar_t sv_gameplayfix_grenadebouncedownslopes; +extern cvar_t sv_gameplayfix_impactbeforeonground; extern cvar_t sv_gameplayfix_multiplethinksperframe; extern cvar_t sv_gameplayfix_noairborncorpse; extern cvar_t sv_gameplayfix_noairborncorpse_allowsuspendeditems; diff --git a/sv_main.c b/sv_main.c index 1ba1b34e..21a2e8db 100644 --- a/sv_main.c +++ b/sv_main.c @@ -110,6 +110,7 @@ cvar_t sv_gameplayfix_easierwaterjump = {CF_SERVER, "sv_gameplayfix_easierwaterj cvar_t sv_gameplayfix_findradiusdistancetobox = {CF_SERVER, "sv_gameplayfix_findradiusdistancetobox", "1", "causes findradius to check the distance to the corner of a box rather than the center of the box, makes findradius detect bmodels such as very large doors that would otherwise be unaffected by splash damage"}; cvar_t sv_gameplayfix_gravityunaffectedbyticrate = {CF_SERVER, "sv_gameplayfix_gravityunaffectedbyticrate", "0", "fix some ticrate issues in physics."}; cvar_t sv_gameplayfix_grenadebouncedownslopes = {CF_SERVER, "sv_gameplayfix_grenadebouncedownslopes", "1", "prevents MOVETYPE_BOUNCE (grenades) from getting stuck when fired down a downward sloping surface"}; +cvar_t sv_gameplayfix_impactbeforeonground = {CF_SERVER, "sv_gameplayfix_impactbeforeonground", "0", "enables a bug from old DP versions in which entity .touch functions are called before FL_ONGROUND is set when a collision is detected in SV_FlyMove() (used by MOVETYPE_WALK and MOVETYPE_STEP), Quake 1.5 and Combat+ mods require this, it breaks id1 fiends"}; 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)"}; @@ -593,6 +594,7 @@ void SV_Init (void) Cvar_RegisterVariable (&sv_gameplayfix_findradiusdistancetobox); Cvar_RegisterVariable (&sv_gameplayfix_gravityunaffectedbyticrate); Cvar_RegisterVariable (&sv_gameplayfix_grenadebouncedownslopes); + Cvar_RegisterVariable (&sv_gameplayfix_impactbeforeonground); Cvar_RegisterVariable (&sv_gameplayfix_multiplethinksperframe); Cvar_RegisterVariable (&sv_gameplayfix_noairborncorpse); Cvar_RegisterVariable (&sv_gameplayfix_noairborncorpse_allowsuspendeditems); diff --git a/sv_phys.c b/sv_phys.c index 6d776f86..a61bc2f8 100644 --- a/sv_phys.c +++ b/sv_phys.c @@ -1112,15 +1112,18 @@ static qbool SV_RunThink (prvm_edict_t *ent) 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; @@ -1154,6 +1157,22 @@ static void SV_Impact (prvm_edict_t *e1, trace_t *trace) 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; + } } @@ -1194,7 +1213,7 @@ If stepnormal is not NULL, the plane normal of any vertical wall hit will be sto ============ */ static float SV_Gravity (prvm_edict_t *ent); -static qbool SV_PushEntity (trace_t *trace, prvm_edict_t *ent, vec3_t push, qbool dolink, qbool checkstuck); +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) { @@ -1237,7 +1256,7 @@ static int SV_FlyMove (prvm_edict_t *ent, float time, qbool applygravity, float break; VectorScale(PRVM_serveredictvector(ent, velocity), time_left, push); - if(!SV_PushEntity(&trace, ent, push, false, true)) + if(!SV_PushEntity(&trace, ent, push, sv_gameplayfix_impactbeforeonground.integer, true)) { // we got teleported by a touch function // let's abort the move @@ -1332,12 +1351,19 @@ static int SV_FlyMove (prvm_edict_t *ent, float time, qbool applygravity, float 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 (!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) { @@ -1559,7 +1585,7 @@ The trace struct is filled with the trace that has been done. 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, qbool checkstuck) +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; @@ -1603,8 +1629,6 @@ static qbool SV_PushEntity (trace_t *trace, prvm_edict_t *ent, vec3_t push, qboo 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 - SV_LinkEdict(ent); #if 0 @@ -1615,29 +1639,15 @@ static qbool SV_PushEntity (trace_t *trace, prvm_edict_t *ent, vec3_t push, qboo } #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); + return 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; - } + return true; } -- 2.39.2