]> git.xonotic.org Git - xonotic/darkplaces.git/commitdiff
added sv_gameplayfix_consistentplayerprethink which defaults on - this
authorhavoc <havoc@d7cf8633-e32d-0410-b094-e92efae38249>
Sun, 4 Oct 2009 12:35:50 +0000 (12:35 +0000)
committerhavoc <havoc@d7cf8633-e32d-0410-b094-e92efae38249>
Sun, 4 Oct 2009 12:35:50 +0000 (12:35 +0000)
cvar causes SV_Physics to call all PlayerPreThink functions, then move
all players, then call PlayerPostThink functions, then move all
entities, to improve consistency of firing/moving in multiplayer
in singleplayer this has no effect at all (because there is only one
client)

git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@9302 d7cf8633-e32d-0410-b094-e92efae38249

server.h
sv_main.c
sv_phys.c

index d6cac81be0d366159602a35c0f51b17aa6f8ea1a..46c05053aff53440254219685becbd8f7549353b 100644 (file)
--- a/server.h
+++ b/server.h
@@ -409,6 +409,7 @@ extern cvar_t sv_fixedframeratesingleplayer;
 extern cvar_t sv_freezenonclients;
 extern cvar_t sv_friction;
 extern cvar_t sv_gameplayfix_blowupfallenzombies;
 extern cvar_t sv_freezenonclients;
 extern cvar_t sv_friction;
 extern cvar_t sv_gameplayfix_blowupfallenzombies;
+extern cvar_t sv_gameplayfix_consistentplayerprethink;
 extern cvar_t sv_gameplayfix_delayprojectiles;
 extern cvar_t sv_gameplayfix_droptofloorstartsolid;
 extern cvar_t sv_gameplayfix_droptofloorstartsolid_nudgetocorrect;
 extern cvar_t sv_gameplayfix_delayprojectiles;
 extern cvar_t sv_gameplayfix_droptofloorstartsolid;
 extern cvar_t sv_gameplayfix_droptofloorstartsolid_nudgetocorrect;
@@ -499,7 +500,7 @@ void SV_BroadcastPrintf(const char *fmt, ...) DP_FUNC_PRINTF(1);
 
 void SV_Physics (void);
 void SV_Physics_ClientMove (void);
 
 void SV_Physics (void);
 void SV_Physics_ClientMove (void);
-void SV_Physics_ClientEntity (prvm_edict_t *ent);
+//void SV_Physics_ClientEntity (prvm_edict_t *ent);
 
 qboolean SV_PlayerCheckGround (prvm_edict_t *ent);
 qboolean SV_CheckBottom (prvm_edict_t *ent);
 
 qboolean SV_PlayerCheckGround (prvm_edict_t *ent);
 qboolean SV_CheckBottom (prvm_edict_t *ent);
index 6d2a65689f9a82171b83b4ad1c0a4ed2b803e5ee..02c4690e83e5335b0e984ea4359186810b592ff9 100644 (file)
--- a/sv_main.c
+++ b/sv_main.c
@@ -84,6 +84,7 @@ cvar_t sv_fixedframeratesingleplayer = {0, "sv_fixedframeratesingleplayer", "1",
 cvar_t sv_freezenonclients = {CVAR_NOTIFY, "sv_freezenonclients", "0", "freezes time, except for players, allowing you to walk around and take screenshots of explosions"};
 cvar_t sv_friction = {CVAR_NOTIFY, "sv_friction","4", "how fast you slow down"};
 cvar_t sv_gameplayfix_blowupfallenzombies = {0, "sv_gameplayfix_blowupfallenzombies", "1", "causes findradius to detect SOLID_NOT entities such as zombies and corpses on the floor, allowing splash damage to apply to them"};
 cvar_t sv_freezenonclients = {CVAR_NOTIFY, "sv_freezenonclients", "0", "freezes time, except for players, allowing you to walk around and take screenshots of explosions"};
 cvar_t sv_friction = {CVAR_NOTIFY, "sv_friction","4", "how fast you slow down"};
 cvar_t sv_gameplayfix_blowupfallenzombies = {0, "sv_gameplayfix_blowupfallenzombies", "1", "causes findradius to detect SOLID_NOT entities such as zombies and corpses on the floor, allowing splash damage to apply to them"};
+cvar_t sv_gameplayfix_consistentplayerprethink = {0, "sv_gameplayfix_consistentplayerprethink", "1", "improves fairness in multiplayer by running all PlayerPreThink functions (which fire weapons) before performing physics, then runing all PlayerPostThink functions"};
 cvar_t sv_gameplayfix_delayprojectiles = {0, "sv_gameplayfix_delayprojectiles", "1", "causes entities to not move on the same frame they are spawned, meaning that projectiles wait until the next frame to perform their first move, giving proper interpolation and rocket trails, but making weapons harder to use at low framerates"};
 cvar_t sv_gameplayfix_droptofloorstartsolid = {0, "sv_gameplayfix_droptofloorstartsolid", "1", "prevents items and monsters that start in a solid area from falling out of the level (makes droptofloor treat trace_startsolid as an acceptable outcome)"};
 cvar_t sv_gameplayfix_droptofloorstartsolid_nudgetocorrect = {0, "sv_gameplayfix_droptofloorstartsolid_nudgetocorrect", "1", "tries to nudge stuck items and monsters out of walls before droptofloor is performed"};
 cvar_t sv_gameplayfix_delayprojectiles = {0, "sv_gameplayfix_delayprojectiles", "1", "causes entities to not move on the same frame they are spawned, meaning that projectiles wait until the next frame to perform their first move, giving proper interpolation and rocket trails, but making weapons harder to use at low framerates"};
 cvar_t sv_gameplayfix_droptofloorstartsolid = {0, "sv_gameplayfix_droptofloorstartsolid", "1", "prevents items and monsters that start in a solid area from falling out of the level (makes droptofloor treat trace_startsolid as an acceptable outcome)"};
 cvar_t sv_gameplayfix_droptofloorstartsolid_nudgetocorrect = {0, "sv_gameplayfix_droptofloorstartsolid_nudgetocorrect", "1", "tries to nudge stuck items and monsters out of walls before droptofloor is performed"};
@@ -375,6 +376,7 @@ void SV_Init (void)
        Cvar_RegisterVariable (&sv_freezenonclients);
        Cvar_RegisterVariable (&sv_friction);
        Cvar_RegisterVariable (&sv_gameplayfix_blowupfallenzombies);
        Cvar_RegisterVariable (&sv_freezenonclients);
        Cvar_RegisterVariable (&sv_friction);
        Cvar_RegisterVariable (&sv_gameplayfix_blowupfallenzombies);
+       Cvar_RegisterVariable (&sv_gameplayfix_consistentplayerprethink);
        Cvar_RegisterVariable (&sv_gameplayfix_delayprojectiles);
        Cvar_RegisterVariable (&sv_gameplayfix_droptofloorstartsolid);
        Cvar_RegisterVariable (&sv_gameplayfix_droptofloorstartsolid_nudgetocorrect);
        Cvar_RegisterVariable (&sv_gameplayfix_delayprojectiles);
        Cvar_RegisterVariable (&sv_gameplayfix_droptofloorstartsolid);
        Cvar_RegisterVariable (&sv_gameplayfix_droptofloorstartsolid_nudgetocorrect);
index 91fbbccad2e85c15bc27ef2fb4bfff384dd437eb..6a2979cac23ea64486b92f5da968027c597e3ef3 100644 (file)
--- a/sv_phys.c
+++ b/sv_phys.c
@@ -1025,6 +1025,12 @@ void SV_CheckVelocity (prvm_edict_t *ent)
                }
        }
 
                }
        }
 
+       // LordHavoc: a hack to ensure that the (rather silly) id1 quakec
+       // player_run/player_stand1 does not horribly malfunction if the
+       // velocity becomes a denormalized float
+       if (VectorLength2(ent->fields.server->velocity) < 0.0001)
+               VectorClear(ent->fields.server->velocity);
+
        // LordHavoc: max velocity fix, inspired by Maddes's source fixes, but this is faster
        wishspeed = DotProduct(ent->fields.server->velocity, ent->fields.server->velocity);
        if (wishspeed > sv_maxvelocity.value * sv_maxvelocity.value)
        // LordHavoc: max velocity fix, inspired by Maddes's source fixes, but this is faster
        wishspeed = DotProduct(ent->fields.server->velocity, ent->fields.server->velocity);
        if (wishspeed > sv_maxvelocity.value * sv_maxvelocity.value)
@@ -2672,12 +2678,6 @@ void SV_Physics_ClientMove(void)
 
        // make sure the velocity is sane (not a NaN)
        SV_CheckVelocity(ent);
 
        // make sure the velocity is sane (not a NaN)
        SV_CheckVelocity(ent);
-       // LordHavoc: a hack to ensure that the (rather silly) id1 quakec
-       // player_run/player_stand1 does not horribly malfunction if the
-       // velocity becomes a number that is both == 0 and != 0
-       // (sounds to me like NaN but to be absolutely safe...)
-       if (DotProduct(ent->fields.server->velocity, ent->fields.server->velocity) < 0.0001)
-               VectorClear(ent->fields.server->velocity);
 
        // perform MOVETYPE_WALK behavior
        SV_WalkMove (ent);
 
        // perform MOVETYPE_WALK behavior
        SV_WalkMove (ent);
@@ -2701,14 +2701,14 @@ void SV_Physics_ClientMove(void)
        }
 }
 
        }
 }
 
-void SV_Physics_ClientEntity(prvm_edict_t *ent)
+static void SV_Physics_ClientEntity_PreThink(prvm_edict_t *ent)
 {
        // don't do physics on disconnected clients, FrikBot relies on this
        if (!host_client->spawned)
 {
        // don't do physics on disconnected clients, FrikBot relies on this
        if (!host_client->spawned)
-       {
-               memset(&host_client->cmd, 0, sizeof(host_client->cmd));
                return;
                return;
-       }
+
+       // make sure the velocity is sane (not a NaN)
+       SV_CheckVelocity(ent);
 
        // don't run physics here if running asynchronously
        if (host_client->clmovement_inputtimeout <= 0)
 
        // don't run physics here if running asynchronously
        if (host_client->clmovement_inputtimeout <= 0)
@@ -2717,20 +2717,61 @@ void SV_Physics_ClientEntity(prvm_edict_t *ent)
                //host_client->cmd.time = max(host_client->cmd.time, sv.time);
        }
 
                //host_client->cmd.time = max(host_client->cmd.time, sv.time);
        }
 
-       // make sure the velocity is sane (not a NaN)
+       // make sure the velocity is still sane (not a NaN)
        SV_CheckVelocity(ent);
        SV_CheckVelocity(ent);
-       // LordHavoc: a hack to ensure that the (rather silly) id1 quakec
-       // player_run/player_stand1 does not horribly malfunction if the
-       // velocity becomes a number that is both == 0 and != 0
-       // (sounds to me like NaN but to be absolutely safe...)
-       if (DotProduct(ent->fields.server->velocity, ent->fields.server->velocity) < 0.0001)
-               VectorClear(ent->fields.server->velocity);
 
        // call standard client pre-think
        prog->globals.server->time = sv.time;
        prog->globals.server->self = PRVM_EDICT_TO_PROG(ent);
 
        // call standard client pre-think
        prog->globals.server->time = sv.time;
        prog->globals.server->self = PRVM_EDICT_TO_PROG(ent);
-       PRVM_ExecuteProgram (prog->globals.server->PlayerPreThink, "QC function PlayerPreThink is missing");
-       SV_CheckVelocity (ent);
+       PRVM_ExecuteProgram(prog->globals.server->PlayerPreThink, "QC function PlayerPreThink is missing");
+
+       // make sure the velocity is still sane (not a NaN)
+       SV_CheckVelocity(ent);
+}
+
+static void SV_Physics_ClientEntity_PostThink(prvm_edict_t *ent)
+{
+       // make sure the velocity is sane (not a NaN)
+       SV_CheckVelocity(ent);
+
+       // call standard player post-think
+       prog->globals.server->time = sv.time;
+       prog->globals.server->self = PRVM_EDICT_TO_PROG(ent);
+       PRVM_ExecuteProgram(prog->globals.server->PlayerPostThink, "QC function PlayerPostThink is missing");
+
+       // make sure the velocity is still sane (not a NaN)
+       SV_CheckVelocity(ent);
+
+       if(ent->fields.server->fixangle)
+       {
+               // angle fixing was requested by physics code...
+               // so store the current angles for later use
+               memcpy(host_client->fixangle_angles, ent->fields.server->angles, sizeof(host_client->fixangle_angles));
+               host_client->fixangle_angles_set = TRUE;
+
+               // and clear fixangle for the next frame
+               ent->fields.server->fixangle = 0;
+       }
+
+       // decrement the countdown variable used to decide when to go back to
+       // synchronous physics
+       if (host_client->clmovement_inputtimeout > sv.frametime)
+               host_client->clmovement_inputtimeout -= sv.frametime;
+       else
+               host_client->clmovement_inputtimeout = 0;
+}
+
+static void SV_Physics_ClientEntity(prvm_edict_t *ent)
+{
+       // don't do physics on disconnected clients, FrikBot relies on this
+       if (!host_client->spawned)
+       {
+               memset(&host_client->cmd, 0, sizeof(host_client->cmd));
+               return;
+       }
+
+       // make sure the velocity is sane (not a NaN)
+       SV_CheckVelocity(ent);
 
        switch ((int) ent->fields.server->movetype)
        {
 
        switch ((int) ent->fields.server->movetype)
        {
@@ -2778,35 +2819,12 @@ void SV_Physics_ClientEntity(prvm_edict_t *ent)
                break;
        }
 
                break;
        }
 
-       // decrement the countdown variable used to decide when to go back to
-       // synchronous physics
-       if (host_client->clmovement_inputtimeout > sv.frametime)
-               host_client->clmovement_inputtimeout -= sv.frametime;
-       else
-               host_client->clmovement_inputtimeout = 0;
-
        SV_CheckVelocity (ent);
 
        SV_LinkEdict(ent);
        SV_LinkEdict_TouchAreaGrid(ent);
 
        SV_CheckVelocity (ent);
        SV_CheckVelocity (ent);
 
        SV_LinkEdict(ent);
        SV_LinkEdict_TouchAreaGrid(ent);
 
        SV_CheckVelocity (ent);
-
-       // call standard player post-think
-       prog->globals.server->time = sv.time;
-       prog->globals.server->self = PRVM_EDICT_TO_PROG(ent);
-       PRVM_ExecuteProgram (prog->globals.server->PlayerPostThink, "QC function PlayerPostThink is missing");
-
-       if(ent->fields.server->fixangle)
-       {
-               // angle fixing was requested by physics code...
-               // so store the current angles for later use
-               memcpy(host_client->fixangle_angles, ent->fields.server->angles, sizeof(host_client->fixangle_angles));
-               host_client->fixangle_angles_set = TRUE;
-
-               // and clear fixangle for the next frame
-               ent->fields.server->fixangle = 0;
-       }
 }
 
 /*
 }
 
 /*
@@ -2837,11 +2855,35 @@ void SV_Physics (void)
                        if (!ent->priv.server->free)
                                SV_LinkEdict_TouchAreaGrid(ent); // force retouch even for stationary
 
                        if (!ent->priv.server->free)
                                SV_LinkEdict_TouchAreaGrid(ent); // force retouch even for stationary
 
-       // run physics on the client entities
-       for (i = 1, ent = PRVM_EDICT_NUM(i), host_client = svs.clients;i <= svs.maxclients;i++, ent = PRVM_NEXT_EDICT(ent), host_client++)
-               if (!ent->priv.server->free)
+       if (sv_gameplayfix_consistentplayerprethink.integer)
+       {
+               // run physics on the client entities in 3 stages
+               for (i = 1, ent = PRVM_EDICT_NUM(i), host_client = svs.clients;i <= svs.maxclients;i++, ent = PRVM_NEXT_EDICT(ent), host_client++)
+                       if (!ent->priv.server->free)
+                               SV_Physics_ClientEntity_PreThink(ent);
+
+               for (i = 1, ent = PRVM_EDICT_NUM(i), host_client = svs.clients;i <= svs.maxclients;i++, ent = PRVM_NEXT_EDICT(ent), host_client++)
+                       if (!ent->priv.server->free)
                                SV_Physics_ClientEntity(ent);
 
                                SV_Physics_ClientEntity(ent);
 
+               for (i = 1, ent = PRVM_EDICT_NUM(i), host_client = svs.clients;i <= svs.maxclients;i++, ent = PRVM_NEXT_EDICT(ent), host_client++)
+                       if (!ent->priv.server->free)
+                               SV_Physics_ClientEntity_PostThink(ent);
+       }
+       else
+       {
+               // run physics on the client entities
+               for (i = 1, ent = PRVM_EDICT_NUM(i), host_client = svs.clients;i <= svs.maxclients;i++, ent = PRVM_NEXT_EDICT(ent), host_client++)
+               {
+                       if (!ent->priv.server->free)
+                       {
+                               SV_Physics_ClientEntity_PreThink(ent);
+                               SV_Physics_ClientEntity(ent);
+                               SV_Physics_ClientEntity_PostThink(ent);
+                       }
+               }
+       }
+
        // run physics on all the non-client entities
        if (!sv_freezenonclients.integer)
        {
        // run physics on all the non-client entities
        if (!sv_freezenonclients.integer)
        {