X-Git-Url: http://de.git.xonotic.org/?a=blobdiff_plain;f=cl_input.c;h=6ca50da589fd0c85efbe49abfde0697c3039fad5;hb=e3e9fa2d84758086c389fe943f54f230e777a7a3;hp=00c0bed932af9ad077853354c8fc1f34e0f9f5ff;hpb=841ae7e6b08293b76fddc8f6fc6aa42da24984f3;p=xonotic%2Fdarkplaces.git diff --git a/cl_input.c b/cl_input.c index 00c0bed9..6ca50da5 100644 --- a/cl_input.c +++ b/cl_input.c @@ -438,8 +438,8 @@ cvar_t cl_movement_accelerate = {0, "cl_movement_accelerate", "10", "how fast yo cvar_t cl_movement_airaccelerate = {0, "cl_movement_airaccelerate", "-1", "how fast you accelerate while in the air (should match sv_airaccelerate), if less than 0 the cl_movement_accelerate variable is used instead"}; cvar_t cl_movement_wateraccelerate = {0, "cl_movement_wateraccelerate", "-1", "how fast you accelerate while in water (should match sv_wateraccelerate), if less than 0 the cl_movement_accelerate variable is used instead"}; cvar_t cl_movement_jumpvelocity = {0, "cl_movement_jumpvelocity", "270", "how fast you move upward when you begin a jump (should match the quakec code)"}; -cvar_t cl_movement_airaccel_qw = {0, "cl_movement_airaccel_qw", "1", "ratio of QW-style air control as opposed to simple acceleration (should match sv_airaccel_qw)"}; -cvar_t cl_movement_airaccel_sideways_friction = {0, "cl_movement_airaccel_sideways_friction", "0", "anti-sideways movement stabilization (should match sv_airaccel_sideways_friction)"}; +cvar_t cl_movement_airaccel_qw = {0, "cl_movement_airaccel_qw", "1", "ratio of QW-style air control as opposed to simple acceleration (reduces speed gain when zigzagging) (should match sv_airaccel_qw); when < 0, the speed is clamped against the maximum allowed forward speed after the move"}; +cvar_t cl_movement_airaccel_sideways_friction = {0, "cl_movement_airaccel_sideways_friction", "0", "anti-sideways movement stabilization (should match sv_airaccel_sideways_friction); when < 0, only so much friction is applied that braking (by accelerating backwards) cannot be stronger"}; cvar_t in_pitch_min = {0, "in_pitch_min", "-90", "how far downward you can aim (quake used -70"}; cvar_t in_pitch_max = {0, "in_pitch_max", "90", "how far upward you can aim (quake used 80"}; @@ -846,7 +846,7 @@ qboolean CL_ClientMovement_Unstick(cl_clientmovement_state_t *s) for (i = 0;i < NUMOFFSETS;i++) { VectorAdd(offsets[i], s->origin, neworigin); - if (!CL_Move(neworigin, cl.playercrouchmins, cl.playercrouchmaxs, neworigin, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_PLAYERCLIP, true, true, NULL, false).startsolid) + if (!CL_TraceBox(neworigin, cl.playercrouchmins, cl.playercrouchmaxs, neworigin, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_PLAYERCLIP, true, true, NULL, false).startsolid) { VectorCopy(neworigin, s->origin); return true; @@ -877,7 +877,7 @@ void CL_ClientMovement_UpdateStatus(cl_clientmovement_state_t *s) // low ceiling first if (s->crouched) { - trace = CL_Move(s->origin, cl.playerstandmins, cl.playerstandmaxs, s->origin, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_PLAYERCLIP, true, true, NULL, false); + trace = CL_TraceBox(s->origin, cl.playerstandmins, cl.playerstandmaxs, s->origin, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_PLAYERCLIP, true, true, NULL, false); if (!trace.startsolid) s->crouched = false; } @@ -896,22 +896,22 @@ void CL_ClientMovement_UpdateStatus(cl_clientmovement_state_t *s) // set onground VectorSet(origin1, s->origin[0], s->origin[1], s->origin[2] + 1); VectorSet(origin2, s->origin[0], s->origin[1], s->origin[2] - 1); // -2 causes clientside doublejump bug at above 150fps, raising that to 300fps :) - trace = CL_Move(origin1, s->mins, s->maxs, origin2, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_PLAYERCLIP, true, true, NULL, false); + trace = CL_TraceBox(origin1, s->mins, s->maxs, origin2, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_PLAYERCLIP, true, true, NULL, false); s->onground = trace.fraction < 1 && trace.plane.normal[2] > 0.7; // set watertype/waterlevel VectorSet(origin1, s->origin[0], s->origin[1], s->origin[2] + s->mins[2] + 1); s->waterlevel = WATERLEVEL_NONE; - s->watertype = CL_Move(origin1, vec3_origin, vec3_origin, origin1, MOVE_NOMONSTERS, NULL, 0, true, false, NULL, false).startsupercontents & SUPERCONTENTS_LIQUIDSMASK; + s->watertype = CL_TracePoint(origin1, MOVE_NOMONSTERS, NULL, 0, true, false, NULL, false).startsupercontents & SUPERCONTENTS_LIQUIDSMASK; if (s->watertype) { s->waterlevel = WATERLEVEL_WETFEET; origin1[2] = s->origin[2] + (s->mins[2] + s->maxs[2]) * 0.5f; - if (CL_Move(origin1, vec3_origin, vec3_origin, origin1, MOVE_NOMONSTERS, NULL, 0, true, false, NULL, false).startsupercontents & SUPERCONTENTS_LIQUIDSMASK) + if (CL_TracePoint(origin1, MOVE_NOMONSTERS, NULL, 0, true, false, NULL, false).startsupercontents & SUPERCONTENTS_LIQUIDSMASK) { s->waterlevel = WATERLEVEL_SWIMMING; origin1[2] = s->origin[2] + 22; - if (CL_Move(origin1, vec3_origin, vec3_origin, origin1, MOVE_NOMONSTERS, NULL, 0, true, false, NULL, false).startsupercontents & SUPERCONTENTS_LIQUIDSMASK) + if (CL_TracePoint(origin1, MOVE_NOMONSTERS, NULL, 0, true, false, NULL, false).startsupercontents & SUPERCONTENTS_LIQUIDSMASK) s->waterlevel = WATERLEVEL_SUBMERGED; } } @@ -938,20 +938,20 @@ void CL_ClientMovement_Move(cl_clientmovement_state_t *s) for (bump = 0, t = s->cmd.frametime;bump < 8 && VectorLength2(s->velocity) > 0;bump++) { VectorMA(s->origin, t, s->velocity, neworigin); - trace = CL_Move(s->origin, s->mins, s->maxs, neworigin, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_PLAYERCLIP, true, true, NULL, false); + trace = CL_TraceBox(s->origin, s->mins, s->maxs, neworigin, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_PLAYERCLIP, true, true, NULL, false); if (trace.fraction < 1 && trace.plane.normal[2] == 0) { // may be a step or wall, try stepping up // first move forward at a higher level VectorSet(currentorigin2, s->origin[0], s->origin[1], s->origin[2] + cl.movevars_stepheight); VectorSet(neworigin2, neworigin[0], neworigin[1], s->origin[2] + cl.movevars_stepheight); - trace2 = CL_Move(currentorigin2, s->mins, s->maxs, neworigin2, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_PLAYERCLIP, true, true, NULL, false); + trace2 = CL_TraceBox(currentorigin2, s->mins, s->maxs, neworigin2, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_PLAYERCLIP, true, true, NULL, false); if (!trace2.startsolid) { // then move down from there VectorCopy(trace2.endpos, currentorigin2); VectorSet(neworigin2, trace2.endpos[0], trace2.endpos[1], s->origin[2]); - trace3 = CL_Move(currentorigin2, s->mins, s->maxs, neworigin2, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_PLAYERCLIP, true, true, NULL, false); + trace3 = CL_TraceBox(currentorigin2, s->mins, s->maxs, neworigin2, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_PLAYERCLIP, true, true, NULL, false); //Con_Printf("%f %f %f %f : %f %f %f %f : %f %f %f %f\n", trace.fraction, trace.endpos[0], trace.endpos[1], trace.endpos[2], trace2.fraction, trace2.endpos[0], trace2.endpos[1], trace2.endpos[2], trace3.fraction, trace3.endpos[0], trace3.endpos[1], trace3.endpos[2]); // accept the new trace if it made some progress if (fabs(trace3.endpos[0] - trace.endpos[0]) >= 0.03125 || fabs(trace3.endpos[1] - trace.endpos[1]) >= 0.03125) @@ -1001,10 +1001,10 @@ void CL_ClientMovement_Physics_Swim(cl_clientmovement_state_t *s) AngleVectors(yawangles, forward, NULL, NULL); VectorMA(s->origin, 24, forward, spot); spot[2] += 8; - if (CL_Move(spot, vec3_origin, vec3_origin, spot, MOVE_NOMONSTERS, NULL, 0, true, false, NULL, false).startsolid) + if (CL_TracePoint(spot, MOVE_NOMONSTERS, NULL, 0, true, false, NULL, false).startsolid) { spot[2] += 24; - if (!CL_Move(spot, vec3_origin, vec3_origin, spot, MOVE_NOMONSTERS, NULL, 0, true, false, NULL, false).startsolid) + if (!CL_TracePoint(spot, MOVE_NOMONSTERS, NULL, 0, true, false, NULL, false).startsolid) { VectorScale(forward, 50, s->velocity); s->velocity[2] = 310; @@ -1078,19 +1078,41 @@ void CL_ClientMovement_Physics_Swim(cl_clientmovement_state_t *s) CL_ClientMovement_Move(s); } +static vec_t CL_IsMoveInDirection(vec_t forward, vec_t side, vec_t angle) +{ + if(forward == 0 && side == 0) + return 0; // avoid division by zero + angle -= RAD2DEG(atan2(side, forward)); + angle = (ANGLEMOD(angle + 180) - 180) / 45; + if(angle > 1) + return 0; + if(angle < -1) + return 0; + return 1 - fabs(angle); +} + void CL_ClientMovement_Physics_CPM_PM_Aircontrol(cl_clientmovement_state_t *s, vec3_t wishdir, vec_t wishspeed) { vec_t zspeed, speed, dot, k; +#if 0 + // this doesn't play well with analog input if(s->cmd.forwardmove == 0 || s->cmd.sidemove != 0) return; - + k = 32; +#else + k = 32 * (2 * CL_IsMoveInDirection(s->cmd.forwardmove, s->cmd.sidemove, 0) - 1); + if(k <= 0) + return; +#endif + + k *= bound(0, wishspeed / cl.movevars_maxairspeed, 1); + zspeed = s->velocity[2]; s->velocity[2] = 0; speed = VectorNormalizeLength(s->velocity); dot = DotProduct(s->velocity, wishdir); - k = 32; k *= cl.movevars_aircontrol*dot*dot*s->cmd.frametime; if(dot > 0) { // we can't change direction while slowing down @@ -1102,39 +1124,68 @@ void CL_ClientMovement_Physics_CPM_PM_Aircontrol(cl_clientmovement_state_t *s, v s->velocity[2] = zspeed; } -void CL_ClientMovement_Physics_PM_Accelerate(cl_clientmovement_state_t *s, vec3_t wishdir, vec_t wishspeed, vec_t accel, vec_t accelqw, vec_t sidefric) +void CL_ClientMovement_Physics_PM_Accelerate(cl_clientmovement_state_t *s, vec3_t wishdir, vec_t wishspeed, vec_t wishspeed0, vec_t accel, vec_t accelqw, vec_t sidefric) { - vec_t vel_straight, vel_z; + vec_t vel_straight; + vec_t vel_z; vec3_t vel_perpend; - vec_t addspeed; - vec_t savespeed; + vec_t step; + vec3_t vel_xy; + vec_t vel_xy_current; + vec_t vel_xy_backward, vel_xy_forward; + qboolean speedclamp; + + speedclamp = (accelqw < 0); + if(speedclamp) + accelqw = -accelqw; - savespeed = VectorLength2(s->velocity); + if(cl.moveflags & MOVEFLAG_Q2AIRACCELERATE) + wishspeed0 = wishspeed; // don't need to emulate this Q1 bug vel_straight = DotProduct(s->velocity, wishdir); vel_z = s->velocity[2]; - VectorMA(s->velocity, -vel_straight, wishdir, vel_perpend); vel_perpend[2] -= vel_z; - - addspeed = wishspeed - vel_straight; - if(addspeed > 0) - vel_straight = vel_straight + min(addspeed, accel * s->cmd.frametime * wishspeed) * accelqw; - if(wishspeed > 0) - vel_straight = vel_straight + min(wishspeed, accel * s->cmd.frametime * wishspeed) * (1 - accelqw); - + VectorCopy(s->velocity, vel_xy); vel_xy[2] -= vel_z; + VectorMA(vel_xy, -vel_straight, wishdir, vel_perpend); + + step = accel * s->cmd.frametime * wishspeed0; + + vel_xy_current = VectorLength(vel_xy); + vel_xy_forward = vel_xy_current + bound(0, wishspeed - vel_xy_current, step) * accelqw + step * (1 - accelqw); + vel_xy_backward = vel_xy_current - bound(0, wishspeed + vel_xy_current, step) * accelqw - step * (1 - accelqw); + if(vel_xy_backward < 0) + vel_xy_backward = 0; // not that it REALLY occurs that this would cause wrong behaviour afterwards + + vel_straight = vel_straight + bound(0, wishspeed - vel_straight, step) * accelqw + step * (1 - accelqw); + if(sidefric < 0 && VectorLength2(vel_perpend)) + // negative: only apply so much sideways friction to stay below the speed you could get by "braking" { vec_t f, fmin; - f = 1 + s->cmd.frametime * wishspeed * sidefric; - fmin = (savespeed - vel_straight*vel_straight) / VectorLength2(vel_perpend); + f = 1 - s->cmd.frametime * wishspeed * sidefric; + fmin = (vel_xy_backward*vel_xy_backward - vel_straight*vel_straight) / VectorLength2(vel_perpend); if(fmin <= 0) VectorScale(vel_perpend, f, vel_perpend); else - VectorScale(vel_perpend, min(1.0f, max(fmin, f)), vel_perpend); + { + fmin = sqrt(fmin); + VectorScale(vel_perpend, bound(fmin, f, 1.0f), vel_perpend); + } } else VectorScale(vel_perpend, 1 - s->cmd.frametime * wishspeed * sidefric, vel_perpend); VectorMA(vel_perpend, vel_straight, wishdir, s->velocity); + + if(speedclamp) + { + vel_xy_current = min(VectorLength(s->velocity), vel_xy_forward); + if(vel_xy_current > 0) // prevent division by zero + { + VectorNormalize(s->velocity); + VectorScale(s->velocity, vel_xy_current, s->velocity); + } + } + s->velocity[2] += vel_z; } @@ -1251,9 +1302,9 @@ void CL_ClientMovement_Physics_Walk(cl_clientmovement_state_t *s) VectorSet(neworigin2, s->origin[0] + s->velocity[0]*(16/f), s->origin[1] + s->velocity[1]*(16/f), s->origin[2] + s->mins[2]); VectorSet(neworigin3, neworigin2[0], neworigin2[1], neworigin2[2] - 34); if (cls.protocol == PROTOCOL_QUAKEWORLD) - trace = CL_Move(neworigin2, s->mins, s->maxs, neworigin3, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_PLAYERCLIP, true, true, NULL, false); + trace = CL_TraceBox(neworigin2, s->mins, s->maxs, neworigin3, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_PLAYERCLIP, true, true, NULL, false); else - trace = CL_Move(neworigin2, vec3_origin, vec3_origin, neworigin3, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_PLAYERCLIP, true, true, NULL, false); + trace = CL_TraceLine(neworigin2, neworigin3, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_PLAYERCLIP, true, true, NULL, false); if (trace.fraction == 1 && !trace.startsolid) friction *= cl.movevars_edgefriction; } @@ -1279,10 +1330,11 @@ void CL_ClientMovement_Physics_Walk(cl_clientmovement_state_t *s) if (s->waterjumptime <= 0) { // apply air speed limit - vec_t accel, wishspeed2, accelqw; + vec_t accel, wishspeed0, wishspeed2, accelqw; qboolean accelerating; accelqw = cl.movevars_airaccel_qw; + wishspeed0 = wishspeed; wishspeed = min(wishspeed, cl.movevars_maxairspeed); if (s->crouched) wishspeed *= 0.5; @@ -1295,6 +1347,9 @@ void CL_ClientMovement_Physics_Walk(cl_clientmovement_state_t *s) if(cl.movevars_airstopaccelerate != 0) if(DotProduct(s->velocity, wishdir) < 0) accel = cl.movevars_airstopaccelerate; + // this doesn't play well with analog input, but can't really be + // fixed like the AirControl can. So, don't set the maxairstrafe* + // cvars when you want to support analog input. if(s->cmd.forwardmove == 0 && s->cmd.sidemove != 0) { if(cl.movevars_maxairstrafespeed) @@ -1322,7 +1377,7 @@ void CL_ClientMovement_Physics_Walk(cl_clientmovement_state_t *s) if(cl.movevars_warsowbunny_turnaccel && accelerating && s->cmd.sidemove == 0 && s->cmd.forwardmove != 0) CL_ClientMovement_Physics_PM_AirAccelerate(s, wishdir, wishspeed2); else - CL_ClientMovement_Physics_PM_Accelerate(s, wishdir, wishspeed, accel, accelqw, cl.movevars_airaccel_sideways_friction / cl.movevars_maxairspeed); + CL_ClientMovement_Physics_PM_Accelerate(s, wishdir, wishspeed, wishspeed0, accel, accelqw, cl.movevars_airaccel_sideways_friction / cl.movevars_maxairspeed); if(cl.movevars_aircontrol) CL_ClientMovement_Physics_CPM_PM_Aircontrol(s, wishdir, wishspeed2); @@ -1350,9 +1405,11 @@ void CL_UpdateMoveVars(void) { if (cls.protocol == PROTOCOL_QUAKEWORLD) { + cl.moveflags = 0; } else if (cl.stats[STAT_MOVEVARS_TICRATE]) { + cl.moveflags = cl.stats[STAT_MOVEFLAGS]; cl.movevars_ticrate = cl.statsf[STAT_MOVEVARS_TICRATE]; cl.movevars_timescale = cl.statsf[STAT_MOVEVARS_TIMESCALE]; cl.movevars_gravity = cl.statsf[STAT_MOVEVARS_GRAVITY]; @@ -1384,6 +1441,7 @@ void CL_UpdateMoveVars(void) } else { + cl.moveflags = 0; cl.movevars_ticrate = slowmo.value / bound(1.0f, cl_netfps.value, 1000.0f); cl.movevars_timescale = slowmo.value; cl.movevars_gravity = sv_gravity.value; @@ -1413,6 +1471,12 @@ void CL_UpdateMoveVars(void) cl.movevars_warsowbunny_turnaccel = 0; cl.movevars_warsowbunny_backtosideratio = 0; } + + if(!(cl.moveflags & MOVEFLAG_VALID)) + { + if(gamemode == GAME_NEXUIZ) + cl.moveflags = MOVEFLAG_Q2AIRACCELERATE; + } } void CL_ClientMovement_Replay(void) @@ -1456,22 +1520,25 @@ void CL_ClientMovement_Replay(void) s.cmd.canjump = cl.movecmd[i+1].canjump; // if a move is more than 50ms, do it as two moves (matching qwsv) //Con_Printf("%i ", s.cmd.msec); - if (s.cmd.frametime > 0.05) + if(s.cmd.frametime > 0.0005) { - s.cmd.frametime /= 2; + if (s.cmd.frametime > 0.05) + { + s.cmd.frametime /= 2; + CL_ClientMovement_PlayerMove(&s); + } CL_ClientMovement_PlayerMove(&s); + cl.movecmd[i].canjump = s.cmd.canjump; } - CL_ClientMovement_PlayerMove(&s); - cl.movecmd[i].canjump = s.cmd.canjump; } //Con_Printf("\n"); + CL_ClientMovement_UpdateStatus(&s); } else { // get the first movement queue entry to know whether to crouch and such s.cmd = cl.movecmd[0]; } - CL_ClientMovement_UpdateStatus(&s); if (cls.demoplayback) // for bob, speedometer VectorCopy(cl.mvelocity[0], cl.movement_velocity); @@ -1556,6 +1623,15 @@ void QW_MSG_WriteDeltaUsercmd(sizebuf_t *buf, usercmd_t *from, usercmd_t *to) MSG_WriteByte(buf, to->msec); } +void CL_NewFrameReceived(int num) +{ + if (developer_networkentities.integer >= 10) + Con_Printf("recv: svc_entities %i\n", num); + cl.latestframenums[cl.latestframenumsposition] = num; + cl.latestsendnums[cl.latestframenumsposition] = cl.cmd.sequence; + cl.latestframenumsposition = (cl.latestframenumsposition + 1) % LATESTFRAMENUMS; +} + /* ============== CL_SendMove @@ -1574,6 +1650,7 @@ void CL_SendMove(void) double packettime; int msecdelta; qboolean quemove; + qboolean important; // if playing a demo, do nothing if (!cls.netcon) @@ -1682,24 +1759,23 @@ void CL_SendMove(void) float maxtic = cl.movevars_ticrate / cl.movevars_timescale; packettime = min(packettime, maxtic); } - // send input every frame in singleplayer - if (cl.islocalgame) - packettime = 0; - // do not send if we do not have anything useful to send - if(msecdelta <= 0 && cls.signon == SIGNONS && !cl.paused && cl.movevars_ticrate > 0) + // do not send 0ms packets because they mess up physics + if(cl.cmd.msec == 0 && cl.time > cl.oldtime && (cls.protocol == PROTOCOL_QUAKEWORLD || cls.signon == SIGNONS)) return; // always send if buttons changed or an impulse is pending // even if it violates the rate limit! - if (!cl.cmd.impulse && (!cl_netimmediatebuttons.integer || cl.cmd.buttons == cl.movecmd[1].buttons)) - { - // don't choke the connection with packets (obey rate limit) - if ((cls.protocol == PROTOCOL_QUAKEWORLD || cls.signon == SIGNONS) && !NetConn_CanSend(cls.netcon) && !cl.islocalgame) - return; - // don't send too often (cl_netfps) - if (realtime < cl.lastpackettime + packettime) - return; - } + important = (cl.cmd.impulse || (cl_netimmediatebuttons.integer && cl.cmd.buttons != cl.movecmd[1].buttons)); + // don't send too often (cl_netfps) + if (!important && realtime < cl.lastpackettime + packettime) + return; + // don't choke the connection with packets (obey rate limit) + // it is important that this check be last, because it adds a new + // frame to the shownetgraph output and any cancelation after this + // will produce a nasty spike-like look to the netgraph + // we also still send if it is important + if (!NetConn_CanSend(cls.netcon) && !important) + return; // try to round off the lastpackettime to a multiple of the packet interval // (this causes it to emit packets at a steady beat) if (packettime > 0) @@ -1738,7 +1814,7 @@ void CL_SendMove(void) MSG_WriteByte(&buf, 0); // packet loss percentage for (j = 0, packetloss = 0;j < NETGRAPH_PACKETS;j++) - if (cls.netcon->incoming_unreliablesize[j] == NETGRAPH_LOSTPACKET) + if (cls.netcon->incoming_netgraph[j].unreliablebytes == NETGRAPH_LOSTPACKET) packetloss++; packetloss = packetloss * 100 / NETGRAPH_PACKETS; MSG_WriteByte(&buf, packetloss); @@ -1866,17 +1942,24 @@ void CL_SendMove(void) if (cls.protocol != PROTOCOL_QUAKEWORLD && buf.cursize) { - // ack the last few frame numbers + // ack entity frame numbers received since the last input was sent // (redundent to improve handling of client->server packet loss) - // for LATESTFRAMENUMS == 3 case this is 15 bytes + // if cl_netrepeatinput is 1 and client framerate matches server + // framerate, this is 10 bytes, if client framerate is lower this + // will be more... + int i, j; + int oldsequence = cl.cmd.sequence - bound(1, cl_netrepeatinput.integer + 1, 3); + if (oldsequence < 1) + oldsequence = 1; for (i = 0;i < LATESTFRAMENUMS;i++) { - if (cl.latestframenums[i] > 0) + j = (cl.latestframenumsposition + i) % LATESTFRAMENUMS; + if (cl.latestsendnums[j] >= oldsequence) { if (developer_networkentities.integer >= 10) - Con_Printf("send clc_ackframe %i\n", cl.latestframenums[i]); + Con_Printf("send clc_ackframe %i\n", cl.latestframenums[j]); MSG_WriteByte(&buf, clc_ackframe); - MSG_WriteLong(&buf, cl.latestframenums[i]); + MSG_WriteLong(&buf, cl.latestframenums[j]); } } }