X-Git-Url: https://git.xonotic.org/?a=blobdiff_plain;f=cl_input.c;h=57f403660b79a3c5468658db1cb12f0f4db34eb6;hb=cbc1d1f6486479a673fe565d149a4e96287d6343;hp=abe87409f180b2f771a2fe9c7f6a117d1046b76d;hpb=d9cb39ec64e03c6ae38a67de2e9a6053cd885daf;p=xonotic%2Fdarkplaces.git diff --git a/cl_input.c b/cl_input.c index abe87409..57f40366 100644 --- a/cl_input.c +++ b/cl_input.c @@ -365,9 +365,9 @@ float CL_KeyState (kbutton_t *key) float val; qboolean impulsedown, impulseup, down; - impulsedown = key->state & 2; - impulseup = key->state & 4; - down = key->state & 1; + impulsedown = (key->state & 2) != 0; + impulseup = (key->state & 4) != 0; + down = (key->state & 1) != 0; val = 0; if (impulsedown && !impulseup) @@ -423,6 +423,7 @@ cvar_t cl_pitchspeed = {CVAR_SAVE, "cl_pitchspeed","150","keyboard pitch turning cvar_t cl_anglespeedkey = {CVAR_SAVE, "cl_anglespeedkey","1.5","how much +speed multiplies keyboard turning speed"}; cvar_t cl_movement = {CVAR_SAVE, "cl_movement", "0", "enables clientside prediction of your player movement"}; +cvar_t cl_movement_nettimeout = {CVAR_SAVE, "cl_movement_nettimeout", "0.3", "stops predicting moves when server is lagging badly (avoids major performance problems), timeout in seconds"}; cvar_t cl_movement_minping = {CVAR_SAVE, "cl_movement_minping", "0", "whether to use prediction when ping is lower than this value in milliseconds"}; cvar_t cl_movement_track_canjump = {CVAR_SAVE, "cl_movement_track_canjump", "1", "track if the player released the jump key between two jumps to decide if he is able to jump or not; when off, this causes some \"sliding\" slightly above the floor when the jump key is held too long; if the mod allows repeated jumping by holding space all the time, this has to be set to zero too"}; cvar_t cl_movement_maxspeed = {0, "cl_movement_maxspeed", "320", "how fast you can move (should match sv_maxspeed)"}; @@ -845,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; @@ -876,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; } @@ -895,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; } } @@ -937,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) @@ -1000,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; @@ -1101,11 +1102,17 @@ 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; vec3_t vel_perpend; vec_t addspeed; + vec_t savespeed; + + if(cl.moveflags & MOVEFLAG_Q2AIRACCELERATE) + wishspeed0 = wishspeed; // don't need to emulate this Q1 bug + + savespeed = VectorLength2(s->velocity); vel_straight = DotProduct(s->velocity, wishdir); vel_z = s->velocity[2]; @@ -1113,11 +1120,22 @@ void CL_ClientMovement_Physics_PM_Accelerate(cl_clientmovement_state_t *s, vec3_ addspeed = wishspeed - vel_straight; if(addspeed > 0) - vel_straight = vel_straight + min(addspeed, accel * s->cmd.frametime * wishspeed) * accelqw; + vel_straight = vel_straight + min(addspeed, accel * s->cmd.frametime * wishspeed0) * accelqw; if(wishspeed > 0) - vel_straight = vel_straight + min(wishspeed, accel * s->cmd.frametime * wishspeed) * (1 - accelqw); + vel_straight = vel_straight + min(wishspeed, accel * s->cmd.frametime * wishspeed0) * (1 - accelqw); - VectorScale(vel_perpend, 1 - s->cmd.frametime * wishspeed * sidefric, vel_perpend); + if(sidefric < 0 && VectorLength2(vel_perpend)) + { + vec_t f, fmin; + f = 1 + s->cmd.frametime * wishspeed * sidefric; + fmin = (savespeed - 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); + } + else + VectorScale(vel_perpend, 1 - s->cmd.frametime * wishspeed * sidefric, vel_perpend); VectorMA(vel_perpend, vel_straight, wishdir, s->velocity); s->velocity[2] += vel_z; @@ -1236,9 +1254,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; } @@ -1264,10 +1282,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; @@ -1307,7 +1326,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); @@ -1335,9 +1354,12 @@ 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]; cl.movevars_stopspeed = cl.statsf[STAT_MOVEVARS_STOPSPEED] ; @@ -1368,6 +1390,8 @@ 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; cl.movevars_stopspeed = cl_movement_stopspeed.value; @@ -1396,6 +1420,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) @@ -1439,22 +1469,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,14 +1589,19 @@ void CL_SendMove(void) unsigned char data[1024]; double packettime; int msecdelta; + qboolean quemove; + qboolean important; // if playing a demo, do nothing if (!cls.netcon) return; - // we build up cl.movecmd[0] and then decide whether to send or not - // the prediction code will use this command even though it has not been - // sent yet + // we don't que moves during a lag spike (potential network timeout) + quemove = realtime - cl.last_received_message < cl_movement_nettimeout.value; + + // we build up cl.cmd and then decide whether to send or not + // we store this into cl.movecmd[0] for prediction each frame even if we + // do not send, to make sure that prediction is instant cl.cmd.time = cl.time; cl.cmd.sequence = cls.netcon->outgoing_unreliable_sequence; @@ -1610,7 +1648,7 @@ void CL_SendMove(void) cl.cmd.msec = 100; cl.cmd.frametime = cl.cmd.msec * (1.0 / 1000.0); - cl.cmd.predicted = cl_movement.integer; + cl.cmd.predicted = cl_movement.integer != 0; // movement is set by input code (forwardmove/sidemove/upmove) // always dump the first two moves, because they may contain leftover inputs from the last level @@ -1636,14 +1674,15 @@ void CL_SendMove(void) break; case PROTOCOL_DARKPLACES6: case PROTOCOL_DARKPLACES7: - // FIXME: cl.movecmd[0].buttons & 16 is +button5, Nexuiz specific + // FIXME: cl.cmd.buttons & 16 is +button5, Nexuiz specific cl.cmd.crouch = (cl.cmd.buttons & 16) != 0; break; case PROTOCOL_UNKNOWN: break; } - cl.movecmd[0] = cl.cmd; + if (quemove) + cl.movecmd[0] = cl.cmd; // don't predict more than 200fps if (realtime >= cl.lastpackettime + 0.005) @@ -1655,24 +1694,28 @@ void CL_SendMove(void) // don't send too often or else network connections can get clogged by a // high renderer framerate packettime = 1.0 / bound(1, cl_netfps.value, 1000); - // send input every frame in singleplayer - if (cl.islocalgame) - packettime = 0; + if (cl.movevars_timescale && cl.movevars_ticrate) + { + float maxtic = cl.movevars_ticrate / cl.movevars_timescale; + packettime = min(packettime, maxtic); + } - // do not send if we do not have anything useful to send - if(msecdelta <= 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.movecmd[0].impulse && (!cl_netimmediatebuttons.integer || cl.movecmd[0].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) @@ -1711,14 +1754,14 @@ 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); // write most recent 3 moves QW_MSG_WriteDeltaUsercmd(&buf, &nullcmd, &cl.movecmd[2]); QW_MSG_WriteDeltaUsercmd(&buf, &cl.movecmd[2], &cl.movecmd[1]); - QW_MSG_WriteDeltaUsercmd(&buf, &cl.movecmd[1], &cl.movecmd[0]); + QW_MSG_WriteDeltaUsercmd(&buf, &cl.movecmd[1], &cl.cmd); // calculate the checksum buf.data[checksumindex] = COM_BlockSequenceCRCByteQW(buf.data + checksumindex + 1, buf.cursize - checksumindex - 1, cls.netcon->outgoing_unreliable_sequence); // if delta compression history overflows, request no delta @@ -1742,50 +1785,50 @@ void CL_SendMove(void) case PROTOCOL_NEHAHRABJP3: // 5 bytes MSG_WriteByte (&buf, clc_move); - MSG_WriteFloat (&buf, cl.movecmd[0].time); // last server packet time + MSG_WriteFloat (&buf, cl.cmd.time); // last server packet time // 3 bytes for (i = 0;i < 3;i++) - MSG_WriteAngle8i (&buf, cl.movecmd[0].viewangles[i]); + MSG_WriteAngle8i (&buf, cl.cmd.viewangles[i]); // 6 bytes - MSG_WriteCoord16i (&buf, cl.movecmd[0].forwardmove); - MSG_WriteCoord16i (&buf, cl.movecmd[0].sidemove); - MSG_WriteCoord16i (&buf, cl.movecmd[0].upmove); + MSG_WriteCoord16i (&buf, cl.cmd.forwardmove); + MSG_WriteCoord16i (&buf, cl.cmd.sidemove); + MSG_WriteCoord16i (&buf, cl.cmd.upmove); // 2 bytes - MSG_WriteByte (&buf, cl.movecmd[0].buttons); - MSG_WriteByte (&buf, cl.movecmd[0].impulse); + MSG_WriteByte (&buf, cl.cmd.buttons); + MSG_WriteByte (&buf, cl.cmd.impulse); break; case PROTOCOL_DARKPLACES2: case PROTOCOL_DARKPLACES3: // 5 bytes MSG_WriteByte (&buf, clc_move); - MSG_WriteFloat (&buf, cl.movecmd[0].time); // last server packet time + MSG_WriteFloat (&buf, cl.cmd.time); // last server packet time // 12 bytes for (i = 0;i < 3;i++) - MSG_WriteAngle32f (&buf, cl.movecmd[0].viewangles[i]); + MSG_WriteAngle32f (&buf, cl.cmd.viewangles[i]); // 6 bytes - MSG_WriteCoord16i (&buf, cl.movecmd[0].forwardmove); - MSG_WriteCoord16i (&buf, cl.movecmd[0].sidemove); - MSG_WriteCoord16i (&buf, cl.movecmd[0].upmove); + MSG_WriteCoord16i (&buf, cl.cmd.forwardmove); + MSG_WriteCoord16i (&buf, cl.cmd.sidemove); + MSG_WriteCoord16i (&buf, cl.cmd.upmove); // 2 bytes - MSG_WriteByte (&buf, cl.movecmd[0].buttons); - MSG_WriteByte (&buf, cl.movecmd[0].impulse); + MSG_WriteByte (&buf, cl.cmd.buttons); + MSG_WriteByte (&buf, cl.cmd.impulse); break; case PROTOCOL_DARKPLACES1: case PROTOCOL_DARKPLACES4: case PROTOCOL_DARKPLACES5: // 5 bytes MSG_WriteByte (&buf, clc_move); - MSG_WriteFloat (&buf, cl.movecmd[0].time); // last server packet time + MSG_WriteFloat (&buf, cl.cmd.time); // last server packet time // 6 bytes for (i = 0;i < 3;i++) - MSG_WriteAngle16i (&buf, cl.movecmd[0].viewangles[i]); + MSG_WriteAngle16i (&buf, cl.cmd.viewangles[i]); // 6 bytes - MSG_WriteCoord16i (&buf, cl.movecmd[0].forwardmove); - MSG_WriteCoord16i (&buf, cl.movecmd[0].sidemove); - MSG_WriteCoord16i (&buf, cl.movecmd[0].upmove); + MSG_WriteCoord16i (&buf, cl.cmd.forwardmove); + MSG_WriteCoord16i (&buf, cl.cmd.sidemove); + MSG_WriteCoord16i (&buf, cl.cmd.upmove); // 2 bytes - MSG_WriteByte (&buf, cl.movecmd[0].buttons); - MSG_WriteByte (&buf, cl.movecmd[0].impulse); + MSG_WriteByte (&buf, cl.cmd.buttons); + MSG_WriteByte (&buf, cl.cmd.impulse); case PROTOCOL_DARKPLACES6: case PROTOCOL_DARKPLACES7: // set the maxusercmds variable to limit how many should be sent @@ -1871,12 +1914,15 @@ void CL_SendMove(void) if (buf.cursize || cls.netcon->message.cursize) NetConn_SendUnreliableMessage(cls.netcon, &buf, cls.protocol, max(20*(buf.cursize+40), cl_rate.integer), false); - // update the cl.movecmd array which holds the most recent moves, - // because we now need a new slot for the next input - for (i = CL_MAX_USERCMDS - 1;i >= 1;i--) - cl.movecmd[i] = cl.movecmd[i-1]; - cl.movecmd[0].msec = 0; - cl.movecmd[0].frametime = 0; + if (quemove) + { + // update the cl.movecmd array which holds the most recent moves, + // because we now need a new slot for the next input + for (i = CL_MAX_USERCMDS - 1;i >= 1;i--) + cl.movecmd[i] = cl.movecmd[i-1]; + cl.movecmd[0].msec = 0; + cl.movecmd[0].frametime = 0; + } // clear button 'click' states in_attack.state &= ~2; @@ -1991,6 +2037,7 @@ void CL_InitInput (void) Cvar_RegisterVariable(&cl_movecliptokeyboard); Cvar_RegisterVariable(&cl_movement); + Cvar_RegisterVariable(&cl_movement_nettimeout); Cvar_RegisterVariable(&cl_movement_minping); Cvar_RegisterVariable(&cl_movement_track_canjump); Cvar_RegisterVariable(&cl_movement_maxspeed);