From dbc428d618fb980cd4e4baba4706dd328b08847b Mon Sep 17 00:00:00 2001 From: havoc Date: Sun, 4 Oct 2009 12:35:50 +0000 Subject: [PATCH] added sv_gameplayfix_consistentplayerprethink which defaults on - this 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 | 3 +- sv_main.c | 2 + sv_phys.c | 132 +++++++++++++++++++++++++++++++++++------------------- 3 files changed, 91 insertions(+), 46 deletions(-) diff --git a/server.h b/server.h index d6cac81b..46c05053 100644 --- 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_gameplayfix_consistentplayerprethink; 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_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); diff --git a/sv_main.c b/sv_main.c index 6d2a6568..02c4690e 100644 --- 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_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"}; @@ -375,6 +376,7 @@ void SV_Init (void) 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); diff --git a/sv_phys.c b/sv_phys.c index 91fbbcca..6a2979ca 100644 --- 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) @@ -2672,12 +2678,6 @@ void SV_Physics_ClientMove(void) // 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); @@ -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) - { - memset(&host_client->cmd, 0, sizeof(host_client->cmd)); 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) @@ -2717,20 +2717,61 @@ void SV_Physics_ClientEntity(prvm_edict_t *ent) //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); - // 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); - 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) { @@ -2778,35 +2819,12 @@ void SV_Physics_ClientEntity(prvm_edict_t *ent) 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); - - // 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 - // 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); + 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) { -- 2.39.2