]> de.git.xonotic.org Git - xonotic/darkplaces.git/commitdiff
physics: add a workaround cvar for mods relying on the id1 fiends bug
authorbones_was_here <bones_was_here@xonotic.au>
Sat, 27 Apr 2024 23:23:56 +0000 (09:23 +1000)
committerbones_was_here <bones_was_here@xonotic.au>
Thu, 2 May 2024 22:21:23 +0000 (08:21 +1000)
Also checks for teleport by QC in both code paths (forgot to do that in
e62e6f563b475060fca315b875aa672c692ad052).

Signed-off-by: bones_was_here <bones_was_here@xonotic.au>
server.h
sv_main.c
sv_phys.c

index 20637517eaf873563fbb8d27cd6ce652717e9628..1ad3158eb7a33b79e8ab045c9c4bb975c631f8e3 100644 (file)
--- 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;
index 1ba1b34e3a591fe9f40e631fef57d3be63064429..21a2e8dbbcb431898eecf30251991b3634b9efb7 100644 (file)
--- 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);
index 6d776f86f45d4af27d120271495fc405d901bc38..a61bc2f893a999c25f0d8ce30d55b884ee9965c3 100644 (file)
--- 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;
 }