X-Git-Url: http://git.xonotic.org/?a=blobdiff_plain;f=sv_user.c;h=2b88821c6a1775f1c1b82851fa999b2bf61b1fbd;hb=906db963b5ddd7afa7305174993c1f22c182a870;hp=6566bf3e2bd5c16e05392d244ff437165653c908;hpb=c601878023c4b57a02391e30db730a200402bfe1;p=xonotic%2Fdarkplaces.git diff --git a/sv_user.c b/sv_user.c index 6566bf3e..2b88821c 100644 --- a/sv_user.c +++ b/sv_user.c @@ -21,11 +21,11 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "quakedef.h" -cvar_t sv_edgefriction = {0, "edgefriction", "2"}; -cvar_t sv_deltacompress = {0, "sv_deltacompress", "1"}; -cvar_t sv_idealpitchscale = {0, "sv_idealpitchscale","0.8"}; -cvar_t sv_maxspeed = {CVAR_NOTIFY, "sv_maxspeed", "320"}; -cvar_t sv_accelerate = {0, "sv_accelerate", "10"}; +cvar_t sv_edgefriction = {0, "edgefriction", "2", "how much you slow down when nearing a ledge you might fall off"}; +cvar_t sv_idealpitchscale = {0, "sv_idealpitchscale","0.8", "how much to look up/down slopes and stairs when not using freelook"}; +cvar_t sv_maxspeed = {CVAR_NOTIFY, "sv_maxspeed", "320", "maximum speed a player can accelerate to when on ground (can be exceeded by tricks)"}; +cvar_t sv_maxairspeed = {0, "sv_maxairspeed", "30", "maximum speed a player can accelerate to when airborn (note that it is possible to completely stop by moving the opposite direction)"}; +cvar_t sv_accelerate = {0, "sv_accelerate", "10", "rate at which a player accelerates to sv_maxspeed"}; static usercmd_t cmd; @@ -176,8 +176,8 @@ void SV_AirAccelerate (vec3_t wishveloc) float addspeed, wishspd, accelspeed, currentspeed; wishspd = VectorNormalizeLength (wishveloc); - if (wishspd > 30) - wishspd = 30; + if (wishspd > sv_maxairspeed.value) + wishspd = sv_maxairspeed.value; currentspeed = DotProduct (host_client->edict->fields.server->velocity, wishveloc); addspeed = wishspd - currentspeed; if (addspeed <= 0) @@ -602,15 +602,21 @@ void SV_ClientThink(void) SV_ReadClientMove =================== */ -extern void SV_Physics_Entity (prvm_edict_t *ent, qboolean runmove); -void SV_ReadClientMove (void) +qboolean SV_ReadClientMove (void) { + qboolean kickplayer = false; int i; double oldmovetime; +#ifdef NUM_PING_TIMES + double total; +#endif usercmd_t *move = &host_client->cmd; oldmovetime = move->time; - memset(move, 0, sizeof(usercmd_t)); + + // if this move has been applied, clear it, and start accumulating new data + if (move->applied) + memset(move, 0, sizeof(*move)); if (msg_badread) Con_Printf("SV_ReadClientMessage: badread at %s:%i\n", __FILE__, __LINE__); @@ -621,6 +627,16 @@ void SV_ReadClientMove (void) if (msg_badread) Con_Printf("SV_ReadClientMessage: badread at %s:%i\n", __FILE__, __LINE__); move->receivetime = sv.time; + // calculate average ping time + host_client->ping = move->receivetime - move->time; +#ifdef NUM_PING_TIMES + host_client->ping_times[host_client->num_pings % NUM_PING_TIMES] = move->receivetime - move->time; + host_client->num_pings++; + for (i=0, total = 0;i < NUM_PING_TIMES;i++) + total += host_client->ping_times[i]; + host_client->ping = total / NUM_PING_TIMES; +#endif + // read current angles for (i = 0;i < 3;i++) { @@ -642,14 +658,18 @@ void SV_ReadClientMove (void) if (msg_badread) Con_Printf("SV_ReadClientMessage: badread at %s:%i\n", __FILE__, __LINE__); // read buttons + // be sure to bitwise OR them into the move->buttons because we want to + // accumulate button presses from multiple packets per actual move if (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE || sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4 || sv.protocol == PROTOCOL_DARKPLACES5) - move->buttons = MSG_ReadByte (); + move->buttons |= MSG_ReadByte (); else - move->buttons = MSG_ReadLong (); + move->buttons |= MSG_ReadLong (); if (msg_badread) Con_Printf("SV_ReadClientMessage: badread at %s:%i\n", __FILE__, __LINE__); // read impulse - move->impulse = MSG_ReadByte (); + i = MSG_ReadByte (); + if (i) + move->impulse = i; if (msg_badread) Con_Printf("SV_ReadClientMessage: badread at %s:%i\n", __FILE__, __LINE__); // PRYDON_CLIENTCURSOR @@ -679,41 +699,57 @@ void SV_ReadClientMove (void) if (!host_client->spawned) memset(move, 0, sizeof(*move)); + else if (move->time > (float)sv.time + 0.001f) // add a little fuzz factor due to float precision issues + { + Con_DPrintf("client move->time %f > sv.time %f, kicking\n", move->time, sv.time); + // if the client is lying about time, we have definitively detected a + // speed cheat attempt of the worst sort, and we can immediately kick + // the offending player off. + // this fixes the timestamp to prevent a speed cheat from working + move->time = sv.time; + // but we kick the player for good measure + kickplayer = true; + } else { + // apply the latest accepted move to the entity fields host_client->movesequence = move->sequence; if (host_client->movesequence) { - double frametime = move->time - oldmovetime; + double frametime = bound(0, move->time - oldmovetime, 0.1); double oldframetime = prog->globals.server->frametime; - if (frametime > 0.1) - frametime = 0.1; + //if (move->time - oldmovetime >= 0.1001) + // Con_DPrintf("client move exceeds 100ms! (time %f -> time %f)\n", oldmovetime, move->time); prog->globals.server->frametime = frametime; - SV_Physics_Entity(host_client->edict, true); + SV_Physics_ClientEntity(host_client->edict); prog->globals.server->frametime = oldframetime; } } + return kickplayer; } void SV_ApplyClientMove (void) { - int i; prvm_eval_t *val; - float total; usercmd_t *move = &host_client->cmd; - // calculate average ping time - host_client->ping_times[host_client->num_pings % NUM_PING_TIMES] = move->receivetime - move->time; - host_client->num_pings++; - for (i=0, total = 0;i < NUM_PING_TIMES;i++) - total += host_client->ping_times[i]; - host_client->ping = total / NUM_PING_TIMES; + if (!move->receivetime) + return; + + // note: a move can be applied multiple times if the client packets are + // not coming as often as the physics is executed, and the move must be + // applied before running qc each time because the id1 qc had a bug where + // it clears self.button2 in PlayerJump, causing pogostick behavior if + // moves are not applied every time before calling qc + move->applied = true; // set the edict fields host_client->edict->fields.server->button0 = move->buttons & 1; host_client->edict->fields.server->button2 = (move->buttons & 2)>>1; if (move->impulse) host_client->edict->fields.server->impulse = move->impulse; + // only send the impulse to qc once + move->impulse = 0; VectorCopy(move->viewangles, host_client->edict->fields.server->v_angle); if ((val = PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_button3))) val->_float = ((move->buttons >> 2) & 1); if ((val = PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_button4))) val->_float = ((move->buttons >> 3) & 1); @@ -721,6 +757,14 @@ void SV_ApplyClientMove (void) if ((val = PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_button6))) val->_float = ((move->buttons >> 5) & 1); if ((val = PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_button7))) val->_float = ((move->buttons >> 6) & 1); if ((val = PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_button8))) val->_float = ((move->buttons >> 7) & 1); + if ((val = PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_button9))) val->_float = ((move->buttons >> 11) & 1); + if ((val = PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_button10))) val->_float = ((move->buttons >> 12) & 1); + if ((val = PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_button11))) val->_float = ((move->buttons >> 13) & 1); + if ((val = PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_button12))) val->_float = ((move->buttons >> 14) & 1); + if ((val = PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_button13))) val->_float = ((move->buttons >> 15) & 1); + if ((val = PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_button14))) val->_float = ((move->buttons >> 16) & 1); + if ((val = PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_button15))) val->_float = ((move->buttons >> 17) & 1); + if ((val = PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_button16))) val->_float = ((move->buttons >> 18) & 1); if ((val = PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_buttonuse))) val->_float = ((move->buttons >> 8) & 1); if ((val = PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_buttonchat))) val->_float = ((move->buttons >> 9) & 1); if ((val = PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_cursor_active))) val->_float = ((move->buttons >> 10) & 1); @@ -777,7 +821,7 @@ void SV_ReadClientMessage(void) return; } - cmd = MSG_ReadChar (); + cmd = MSG_ReadByte (); if (cmd == -1) { // end of message @@ -833,7 +877,9 @@ void SV_ReadClientMessage(void) return; case clc_move: - SV_ReadClientMove (); + // if ReadClientMove returns true, the client tried to speed cheat + if (SV_ReadClientMove ()) + SV_DropClient (false); break; case clc_ackframe: @@ -842,7 +888,10 @@ void SV_ReadClientMessage(void) if (msg_badread) Con_Printf("SV_ReadClientMessage: badread at %s:%i\n", __FILE__, __LINE__); if (developer_networkentities.integer >= 1) Con_Printf("recv clc_ackframe %i\n", num); - if (host_client->latestframenum < num) + // if the client hasn't progressed through signons yet, + // ignore any clc_ackframes we get (they're probably from the + // previous level) + if (host_client->spawned && host_client->latestframenum < num) { int i; for (i = host_client->latestframenum + 1;i < num;i++)