From: havoc Date: Sun, 28 May 2006 19:38:41 +0000 (+0000) Subject: further tweaks to prediction X-Git-Tag: xonotic-v0.1.0preview~3969 X-Git-Url: http://de.git.xonotic.org/?p=xonotic%2Fdarkplaces.git;a=commitdiff_plain;h=6162f7035eef9d1dc6a4913dba2e2023c0857c3a further tweaks to prediction git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@6401 d7cf8633-e32d-0410-b094-e92efae38249 --- diff --git a/cl_input.c b/cl_input.c index 7c6fec1a..83f688ab 100644 --- a/cl_input.c +++ b/cl_input.c @@ -527,7 +527,7 @@ void CL_ClientMovement_InputQW(qw_usercmd_t *cmd) if (cl.movement_queue[i].sequence > cls.netcon->qw.incoming_sequence) cl.movement_queue[cl.movement_numqueue++] = cl.movement_queue[i]; else if (i == 0) - cl.movement_replay_canjump = !cl.movement_queue[i].jump; + cl.movement_replay_canjump = !cl.movement_queue[i].jump; // FIXME: this logic is quite broken } // add to input queue if there is room if (cl.movement_numqueue < (int)(sizeof(cl.movement_queue)/sizeof(cl.movement_queue[0]))) @@ -551,7 +551,7 @@ void CL_ClientMovement_Input(qboolean buttonjump, qboolean buttoncrouch) { int i; int n; - double lasttime = cl.movement_numqueue >= 0 ? cl.movement_queue[cl.movement_numqueue - 1].time : 0; + double lasttime = (cls.protocol == PROTOCOL_DARKPLACES6 || cls.protocol == PROTOCOL_DARKPLACES7) ? cl.mtime[1] : (cl.movement_numqueue >= 0 ? cl.movement_queue[cl.movement_numqueue - 1].time : 0); // remove stale queue items n = cl.movement_numqueue; cl.movement_numqueue = 0; @@ -562,7 +562,7 @@ void CL_ClientMovement_Input(qboolean buttonjump, qboolean buttoncrouch) if (cl.movement_queue[i].sequence > cl.servermovesequence) cl.movement_queue[cl.movement_numqueue++] = cl.movement_queue[i]; else if (i == 0) - cl.movement_replay_canjump = !cl.movement_queue[i].jump; + cl.movement_replay_canjump = !cl.movement_queue[i].jump; // FIXME: this logic is quite broken } } else @@ -572,7 +572,7 @@ void CL_ClientMovement_Input(qboolean buttonjump, qboolean buttoncrouch) if (cl.movement_queue[i].time >= cl.mtime[0] - cl_movement_latency.value / 1000.0 && cl.movement_queue[i].time <= cl.mtime[0]) cl.movement_queue[cl.movement_numqueue++] = cl.movement_queue[i]; else if (i == 0) - cl.movement_replay_canjump = !cl.movement_queue[i].jump; + cl.movement_replay_canjump = !cl.movement_queue[i].jump; // FIXME: this logic is quite broken } } // add to input queue if there is room @@ -1072,7 +1072,8 @@ void CL_ClientMovement_Replay(void) s.movevars_stepheight = cl_movement_stepheight.value; } - if (cl.movement) + cl.movement_predicted = (cl_movement.integer && cls.signon == SIGNONS && cl.stats[STAT_HEALTH] > 0 && !cl.intermission) && ((cls.protocol != PROTOCOL_DARKPLACES6 && cls.protocol != PROTOCOL_DARKPLACES7) || cl.servermovesequence); + if (cl.movement_predicted) { //Con_Printf("%f: ", cl.mtime[0]); @@ -1182,7 +1183,6 @@ void CL_SendMove(void) accumtotal++; #endif - cl.movement = cl_movement.integer && cls.signon == SIGNONS && cl.stats[STAT_HEALTH] > 0 && !cl.intermission; if (cl_movement.integer && cls.signon == SIGNONS && cls.protocol != PROTOCOL_QUAKEWORLD) { if (!cl.movement_needupdate) diff --git a/cl_main.c b/cl_main.c index d2058952..e77ea64a 100644 --- a/cl_main.c +++ b/cl_main.c @@ -913,7 +913,7 @@ void CL_LinkNetworkEntity(entity_t *e) // movement lerp // if it's the player entity, update according to client movement - if (e == cl.entities + cl.playerentity && cl.movement)// && !e->csqc) + if (e == cl.entities + cl.playerentity && cl.movement_predicted)// && !e->csqc) { lerp = (cl.time - cl.movement_time[1]) / (cl.movement_time[0] - cl.movement_time[1]); lerp = bound(0, lerp, 1); diff --git a/client.h b/client.h index cfa3f3dc..6fa4b32e 100644 --- a/client.h +++ b/client.h @@ -657,7 +657,8 @@ typedef struct client_state_s // client movement simulation // these fields are only updated by CL_ClientMovement (called by CL_SendMove after parsing each network packet) - qboolean movement; + // set by CL_ClientMovement_Replay functions + qboolean movement_predicted; // this is set true by svc_time parsing and causes a new movement to be // queued for prediction purposes qboolean movement_needupdate; @@ -671,7 +672,7 @@ typedef struct client_state_s vec3_t movement_velocity; // queue of proposed moves int movement_numqueue; - client_movementqueue_t movement_queue[64]; + client_movementqueue_t movement_queue[256]; int movesequence; int servermovesequence; // whether the replay should allow a jump at the first sequence diff --git a/server.h b/server.h index d2e6c303..8371c750 100644 --- a/server.h +++ b/server.h @@ -137,7 +137,9 @@ typedef struct client_s float ping; // this is used by sv_clmovement_minping code - double clmovement_disable_minpingtimeout; + double clmovement_disabletimeout; + // this is used by sv_clmvoement_waitforinput code + int clmovement_skipphysicsframes; // spawn parms are carried from level to level float spawn_parms[NUM_SPAWN_PARMS]; diff --git a/sv_main.c b/sv_main.c index 5b8b7c4b..2efbb889 100644 --- a/sv_main.c +++ b/sv_main.c @@ -57,6 +57,7 @@ cvar_t sv_progs = {0, "sv_progs", "progs.dat", "selects which quakec progs.dat f extern cvar_t sv_clmovement_enable; extern cvar_t sv_clmovement_minping; extern cvar_t sv_clmovement_minping_disabletime; +extern cvar_t sv_clmovement_waitforinput; server_t sv; server_static_t svs; @@ -91,6 +92,7 @@ void SV_Init (void) Cvar_RegisterVariable (&sv_clmovement_enable); Cvar_RegisterVariable (&sv_clmovement_minping); Cvar_RegisterVariable (&sv_clmovement_minping_disabletime); + Cvar_RegisterVariable (&sv_clmovement_waitforinput); Cvar_RegisterVariable (&sv_idealpitchscale); Cvar_RegisterVariable (&sv_aim); Cvar_RegisterVariable (&sv_nostep); diff --git a/sv_phys.c b/sv_phys.c index 1f50232b..725aa884 100644 --- a/sv_phys.c +++ b/sv_phys.c @@ -57,6 +57,9 @@ cvar_t sv_playerphysicsqc = {CVAR_NOTIFY, "sv_playerphysicsqc", "1", "enables Qu cvar_t sv_sound_watersplash = {0, "sv_sound_watersplash", "misc/h2ohit1.wav", "sound to play when MOVETYPE_FLY/TOSS/BOUNCE/STEP entity enters or leaves water (empty cvar disables the sound)"}; cvar_t sv_sound_land = {0, "sv_sound_land", "demon/dland2.wav", "sound to play when MOVETYPE_STEP entity hits the ground at high speed (empty cvar disables the sound)"}; +// TODO: move this extern to server.h +extern cvar_t sv_clmovement_waitforinput; + #define MOVE_EPSILON 0.01 void SV_Physics_Toss (prvm_edict_t *ent); @@ -1668,7 +1671,9 @@ void SV_Physics (void) if (!host_client->spawned) memset(&host_client->cmd, 0, sizeof(host_client->cmd)); // don't run physics here if running asynchronously - else if (!host_client->movesequence) + else if (host_client->clmovement_skipphysicsframes > 0) + host_client->clmovement_skipphysicsframes--; + else SV_Physics_ClientEntity(ent); } } diff --git a/sv_user.c b/sv_user.c index d880a87c..480c46a6 100644 --- a/sv_user.c +++ b/sv_user.c @@ -31,6 +31,7 @@ cvar_t sv_wateraccelerate = {0, "sv_wateraccelerate", "-1", "rate at which a pla cvar_t sv_clmovement_enable = {0, "sv_clmovement_enable", "1", "whether to allow clients to use cl_movement prediction, which can cause choppy movement on the server which may annoy other players"}; cvar_t sv_clmovement_minping = {0, "sv_clmovement_minping", "100", "if client ping is below this time in milliseconds, then their ability to use cl_movement prediction is disabled for a while (as they don't need it)"}; cvar_t sv_clmovement_minping_disabletime = {0, "sv_clmovement_minping_disabletime", "1000", "when client falls below minping, disable their prediction for this many milliseconds (should be at least 1000 or else their prediction may turn on/off frequently)"}; +cvar_t sv_clmovement_waitforinput = {0, "sv_clmovement_waitforinput", "2", "when a client does not send input for this many frames, force them to move anyway (unlike QuakeWorld)"}; static usercmd_t cmd; @@ -533,8 +534,8 @@ qboolean SV_ReadClientMove (void) // disable clientside movement prediction in some cases if (ceil((move->receivetime - move->time) * 1000.0) < sv_clmovement_minping.integer) - host_client->clmovement_disable_minpingtimeout = realtime + sv_clmovement_minping_disabletime.value / 1000.0; - if (!sv_clmovement_enable.integer || host_client->clmovement_disable_minpingtimeout > realtime) + host_client->clmovement_disabletimeout = realtime + sv_clmovement_minping_disabletime.value / 1000.0; + if (!sv_clmovement_enable.integer || host_client->clmovement_disabletimeout > realtime) move->sequence = 0; if (!host_client->spawned) @@ -554,7 +555,7 @@ qboolean SV_ReadClientMove (void) { // apply the latest accepted move to the entity fields host_client->movesequence = move->sequence; - if (host_client->movesequence) + if (host_client->movesequence && sv_clmovement_waitforinput.integer > 0) { double frametime = bound(0, move->time - oldmovetime, 0.1); double oldframetime = prog->globals.server->frametime; @@ -563,6 +564,7 @@ qboolean SV_ReadClientMove (void) prog->globals.server->frametime = frametime; SV_Physics_ClientEntity(host_client->edict); prog->globals.server->frametime = oldframetime; + host_client->clmovement_skipphysicsframes = sv_clmovement_waitforinput.integer; } } return kickplayer;