From 09a32a91ba4afb37350327625ff87da73a36a63b Mon Sep 17 00:00:00 2001 From: Shpoike Date: Tue, 25 Jul 2023 13:37:52 +0100 Subject: [PATCH] Add sv_nqplayerphysics cvar for mods that don't want to include SV_RunClientCommand for whatever reason. Set to 0 to force predictable player physics. --- Quake/pmove.h | 2 ++ Quake/pr_ext.c | 37 ++++++++++++++++++------------------- Quake/server.h | 1 + Quake/sv_main.c | 4 +++- Quake/sv_phys.c | 2 +- Quake/sv_user.c | 37 ++++++++++++++++++++++++++++++------- 6 files changed, 55 insertions(+), 28 deletions(-) diff --git a/Quake/pmove.h b/Quake/pmove.h index 550d7515..58201a57 100644 --- a/Quake/pmove.h +++ b/Quake/pmove.h @@ -164,6 +164,8 @@ void SV_Impact (edict_t *e1, edict_t *e2); void World_AddEntsToPmove(edict_t *ignore, vec3_t boxminmax[2]); void PMCL_ServerinfoUpdated(void); void PMSV_SetMoveStats(edict_t *plent, float *fstat, int *istat); //so client has the right movevars as stats. +void PMSV_UpdateMovevars(void); +void PF_sv_pmove(void); void PM_Register(void); #define VectorClear(v) ((v)[0] = (v)[1] = (v)[2] = 0) #define VectorSet(r,x,y,z) do{(r)[0] = x; (r)[1] = y;(r)[2] = z;}while(0) diff --git a/Quake/pr_ext.c b/Quake/pr_ext.c index 4e33871c..3c6f8661 100644 --- a/Quake/pr_ext.c +++ b/Quake/pr_ext.c @@ -1987,30 +1987,29 @@ static void PF_both_pmove(edict_t *e) } } -cvar_t pm_bunnyspeedcap = {"pm_bunnyspeedcap", "", CVAR_SERVERINFO}; //reduces strafejumps to maxspeed instead of endlessly accelerating -cvar_t pm_bunnyfriction = {"pm_bunnyfriction", "1", CVAR_SERVERINFO}; //forces nq's frame of friction -cvar_t pm_ktjump = {"pm_ktjump", "", CVAR_SERVERINFO}; -cvar_t pm_slidefix = {"pm_slidefix", "1", CVAR_SERVERINFO}; //don't bump when going down slopes. -cvar_t pm_airstep = {"pm_airstep", "", CVAR_SERVERINFO}; //allow stepping up stairs when eg jumping -cvar_t pm_pground = {"pm_pground", "", CVAR_SERVERINFO}; //persistent onground state, supposed to be more precise but has gamecode interaction issues. -cvar_t pm_stepdown = {"pm_stepdown", "", CVAR_SERVERINFO}; //glue the player to the ground when going down steps instead of just up. kinda weird. -cvar_t pm_walljump = {"pm_walljump", "", CVAR_SERVERINFO}; //bouncing off the walls. -cvar_t pm_slidyslopes = {"pm_slidyslopes", "", CVAR_SERVERINFO}; //gradually slide down slopes like vanilla nq -cvar_t pm_autobunny = {"pm_autobunny", "", CVAR_SERVERINFO}; //pogostick mode, for lazy noobs -cvar_t pm_watersinkspeed = {"pm_watersinkspeed", "", CVAR_SERVERINFO}; //speed you sink at when idle in water -cvar_t pm_flyfriction = {"pm_flyfriction", "", CVAR_SERVERINFO}; //friction in fly/noclip modes. -cvar_t pm_edgefriction = {"pm_edgefriction", "2",}; //should alias to edgefriction but be listed in the serverinfo as pm_... -cvar_t pm_stepheight = {"pm_stepheight", ""}; //should alias to edgefriction but be listed in the serverinfo as pm_... +static cvar_t pm_bunnyspeedcap = {"pm_bunnyspeedcap", "", CVAR_SERVERINFO}; //reduces strafejumps to maxspeed instead of endlessly accelerating +static cvar_t pm_bunnyfriction = {"pm_bunnyfriction", "1", CVAR_SERVERINFO}; //forces nq's frame of friction +static cvar_t pm_ktjump = {"pm_ktjump", "", CVAR_SERVERINFO}; +static cvar_t pm_slidefix = {"pm_slidefix", "1", CVAR_SERVERINFO}; //don't bump when going down slopes. +static cvar_t pm_airstep = {"pm_airstep", "", CVAR_SERVERINFO}; //allow stepping up stairs when eg jumping +static cvar_t pm_pground = {"pm_pground", "", CVAR_SERVERINFO}; //persistent onground state, supposed to be more precise but has gamecode interaction issues. +static cvar_t pm_stepdown = {"pm_stepdown", "", CVAR_SERVERINFO}; //glue the player to the ground when going down steps instead of just up. kinda weird. +static cvar_t pm_walljump = {"pm_walljump", "", CVAR_SERVERINFO}; //bouncing off the walls. +static cvar_t pm_slidyslopes = {"pm_slidyslopes", "", CVAR_SERVERINFO}; //gradually slide down slopes like vanilla nq +static cvar_t pm_autobunny = {"pm_autobunny", "", CVAR_SERVERINFO}; //pogostick mode, for lazy noobs +static cvar_t pm_watersinkspeed = {"pm_watersinkspeed", "", CVAR_SERVERINFO}; //speed you sink at when idle in water +static cvar_t pm_flyfriction = {"pm_flyfriction", "", CVAR_SERVERINFO}; //friction in fly/noclip modes. +static cvar_t pm_edgefriction = {"pm_edgefriction", "2",}; //should alias to edgefriction but be listed in the serverinfo as pm_... +static cvar_t pm_stepheight = {"pm_stepheight", ""}; //should alias to edgefriction but be listed in the serverinfo as pm_... extern cvar_t sv_maxspeed; -cvar_t sv_spectatormaxspeed = {"sv_spectatormaxspeed", "500"}; extern cvar_t sv_accelerate; -cvar_t sv_airaccelerate = {"sv_airaccelerate", "0.7"}; -cvar_t sv_wateraccelerate = {"sv_wateraccelerate", "10"}; -cvar_t sv_waterfriction = {"sv_waterfriction", "4"}; -extern cvar_t sv_waterfriction; extern cvar_t sv_friction; extern cvar_t sv_gravity; extern cvar_t sv_stopspeed; +static cvar_t sv_airaccelerate = {"sv_airaccelerate", "0.7"}; +static cvar_t sv_wateraccelerate = {"sv_wateraccelerate", "10"}; +static cvar_t sv_waterfriction = {"sv_waterfriction", "4"}; +static cvar_t sv_spectatormaxspeed = {"sv_spectatormaxspeed", "500"}; void PM_Register(void) { PM_Init(); diff --git a/Quake/server.h b/Quake/server.h index 9287f5b0..6e547832 100644 --- a/Quake/server.h +++ b/Quake/server.h @@ -206,6 +206,7 @@ typedef struct client_s int lastacksequence; int lastmovemessage; double lastmovetime; + qboolean usingpmove; //using the SV_RunClientCommand entrypoint, or getting pmove thrust upon them serverside (disables sv_user.c+movetype stuff, enables provides pmove hints to the client) char userinfo[1024]; //spike -- for csqc to (ab)use. client_voip_t voip; //spike -- for voip diff --git a/Quake/sv_main.c b/Quake/sv_main.c index 724851c1..39a02f0b 100644 --- a/Quake/sv_main.c +++ b/Quake/sv_main.c @@ -1312,7 +1312,7 @@ invisible: ents[numents].state.modelindex = 0; if (ent == clent) //add velocity, but we only care for the local player (should add prediction for other entities some time too). { - if (qcvm->extfuncs.SV_RunClientCommand) + if (client->usingpmove) ents[numents].state.pmovetype = ent->v.movetype; //looks like prediction is available. assuming SV_RunClientCommand just calls runstandardplayerphysics then we can predict it with matching clientside stuff. else ents[numents].state.pmovetype = 0; //fixme: we don't do prediction, so don't tell the client that it can try @@ -1539,6 +1539,7 @@ void SV_Init (void) extern cvar_t sv_idealpitchscale; extern cvar_t sv_aim; extern cvar_t sv_altnoclip; //johnfitz + extern cvar_t sv_nqplayerphysics; //spike extern cvar_t sv_public; //spike extern cvar_t sv_reportheartbeats; //spike extern cvar_t com_protocolname; //spike @@ -1567,6 +1568,7 @@ void SV_Init (void) Cvar_RegisterVariable (&sv_gameplayfix_setmodelrealbox); Cvar_RegisterVariable (&pr_checkextension); Cvar_RegisterVariable (&sv_altnoclip); //johnfitz + Cvar_RegisterVariable (&sv_nqplayerphysics); //spike Cvar_RegisterVariable (&sv_sound_watersplash); //spike Cvar_RegisterVariable (&sv_sound_land); //spike diff --git a/Quake/sv_phys.c b/Quake/sv_phys.c index d17ff868..69ec6846 100644 --- a/Quake/sv_phys.c +++ b/Quake/sv_phys.c @@ -1202,7 +1202,7 @@ void SV_Physics_Client (edict_t *ent, int num) if ( ! svs.clients[num-1].active ) return; // unconnected slot - if (qcvm->extfuncs.SV_RunClientCommand) + if (svs.clients[num-1].usingpmove) return; //we're doing independant player physics with this mod, so clientside prediction can do its thing. if (!svs.clients[num-1].knowntoqc && sv_gameplayfix_spawnbeforethinks.value) return; //don't spam prethinks before we called putclientinserver. diff --git a/Quake/sv_user.c b/Quake/sv_user.c index ac41bec3..34e5aba6 100644 --- a/Quake/sv_user.c +++ b/Quake/sv_user.c @@ -22,6 +22,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. // sv_user.c -- server code for moving users #include "quakedef.h" +#include "pmove.h" edict_t *sv_player; @@ -42,6 +43,7 @@ usercmd_t cmd; cvar_t sv_idealpitchscale = {"sv_idealpitchscale","0.8",CVAR_NONE}; cvar_t sv_altnoclip = {"sv_altnoclip","1",CVAR_ARCHIVE}; //johnfitz +cvar_t sv_nqplayerphysics = {"sv_nqplayerphysics", "1", CVAR_ARCHIVE}; //spike. set to 0 for prediction to work. name comes from fte. qboolean SV_RunThink (edict_t *ent); @@ -392,8 +394,6 @@ void SV_ClientThink (void) if (sv_player->v.movetype == MOVETYPE_NONE) return; - if (qcvm->extfuncs.SV_RunClientCommand) - return; //this stuff is handled on inputs. don't corrupt anything. onground = (int)sv_player->v.flags & FL_ONGROUND; @@ -402,6 +402,9 @@ void SV_ClientThink (void) DropPunchAngle (); + if (host_client->usingpmove) + return; //this stuff is handled on inputs. don't corrupt anything. + // // if dead, behave differently // @@ -462,6 +465,7 @@ void SV_ReadClientMove (usercmd_t *move) vec3_t movevalues; int sequence; eval_t *val; + vec3_t savedvel; if (host_client->protocol_pext2 & PEXT2_PREDINFO) { @@ -554,10 +558,11 @@ void SV_ReadClientMove (usercmd_t *move) eval->vector[2] = move->upmove; } - //FIXME: attempt to apply physics command now, if the mod has custom physics+csqc-prediction + //decide if we're going independant or not + host_client->usingpmove = !!qcvm->extfuncs.SV_RunClientCommand || (!sv_nqplayerphysics.value && (*sv_nqplayerphysics.string||deathmatch.value)); - - if (qcvm->extfuncs.SV_RunClientCommand && host_client->knowntoqc) + //and give them their independance here. + if (host_client->usingpmove && host_client->knowntoqc) { if (timestamp > qcvm->time) timestamp = qcvm->time; //don't let the client exceed the current time @@ -592,14 +597,32 @@ void SV_ReadClientMove (usercmd_t *move) if (qcvm->extglobals.input_cursor_entitynumber) *qcvm->extglobals.input_cursor_entitynumber = curs_entity; + VectorCopy(host_client->edict->v.velocity, savedvel); pr_global_struct->self = EDICT_TO_PROG(host_client->edict); PR_ExecuteProgram(pr_global_struct->PlayerPreThink); + if (!qcvm->extfuncs.SV_RunClientCommand) + { + //Undo damage caused by unaware mods... in vanilla this includes: + // PlayerJump has 4 velocity changes that might mess with prediction + // WaterMove imposes some additional drag that breaks things + // CheckWaterJump is entirely redundant. + //(it should be noted that the (cs)qc should still track jumps for sounds, and landings for fall damage, and water for drowning, just not any of the velocity changes) + VectorCopy(savedvel, host_client->edict->v.velocity); + } if (!SV_RunThink (host_client->edict)) return; //ent was removed? o.O - pr_global_struct->self = EDICT_TO_PROG(host_client->edict); - PR_ExecuteProgram(qcvm->extfuncs.SV_RunClientCommand); + if (qcvm->extfuncs.SV_RunClientCommand) + { + pr_global_struct->self = EDICT_TO_PROG(host_client->edict); + PR_ExecuteProgram(qcvm->extfuncs.SV_RunClientCommand); + } + else + { //the qc ain't helping us here. go direct to the runstandardplayerphysics builtin. + G_INT(OFS_PARM0) = EDICT_TO_PROG(host_client->edict); + PF_sv_pmove(); + } pr_global_struct->self = EDICT_TO_PROG(host_client->edict); PR_ExecuteProgram(pr_global_struct->PlayerPostThink);