- // send the movement message
- // PROTOCOL_QUAKE clc_move = 16 bytes total
- // PROTOCOL_QUAKEDP clc_move = 16 bytes total
- // PROTOCOL_NEHAHRAMOVIE clc_move = 16 bytes total
- // PROTOCOL_DARKPLACES1 clc_move = 19 bytes total
- // PROTOCOL_DARKPLACES2 clc_move = 25 bytes total
- // PROTOCOL_DARKPLACES3 clc_move = 25 bytes total
- // PROTOCOL_DARKPLACES4 clc_move = 19 bytes total
- // PROTOCOL_DARKPLACES5 clc_move = 19 bytes total
- // PROTOCOL_DARKPLACES6 clc_move = 52 bytes total
- // PROTOCOL_DARKPLACES7 clc_move = 56 bytes total
- // PROTOCOL_QUAKEWORLD clc_move = 34 bytes total (typically, but can reach 43 bytes, or even 49 bytes with roll)
- if (cls.protocol == PROTOCOL_QUAKEWORLD)
- {
- int checksumindex;
- double msectime;
- static double oldmsectime;
- qw_usercmd_t *cmd, *oldcmd;
- qw_usercmd_t nullcmd;
-
- //Con_Printf("code qw_clc_move\n");
-
- i = cls.netcon->qw.outgoing_sequence & QW_UPDATE_MASK;
- cmd = &cl.qw_moves[i];
- memset(&nullcmd, 0, sizeof(nullcmd));
- memset(cmd, 0, sizeof(*cmd));
- cmd->buttons = bits;
- cmd->impulse = impulse;
- cmd->forwardmove = (short)bound(-32768, forwardmove, 32767);
- cmd->sidemove = (short)bound(-32768, sidemove, 32767);
- cmd->upmove = (short)bound(-32768, upmove, 32767);
- VectorCopy(cl.viewangles, cmd->angles);
- msectime = realtime * 1000;
- cmd->msec = (unsigned char)bound(0, msectime - oldmsectime, 255);
- // ridiculous value rejection (matches qw)
- if (cmd->msec > 250)
- cmd->msec = 100;
- oldmsectime = msectime;
-
- CL_ClientMovement_InputQW(cmd);
-
- MSG_WriteByte(&buf, qw_clc_move);
- // save the position for a checksum byte
- checksumindex = buf.cursize;
- MSG_WriteByte(&buf, 0);
- // packet loss percentage
- // FIXME: netgraph stuff
- MSG_WriteByte(&buf, 0);
- // write most recent 3 moves
- i = (cls.netcon->qw.outgoing_sequence-2) & QW_UPDATE_MASK;
- cmd = &cl.qw_moves[i];
- QW_MSG_WriteDeltaUsercmd(&buf, &nullcmd, cmd);
- oldcmd = cmd;
- i = (cls.netcon->qw.outgoing_sequence-1) & QW_UPDATE_MASK;
- cmd = &cl.qw_moves[i];
- QW_MSG_WriteDeltaUsercmd(&buf, oldcmd, cmd);
- oldcmd = cmd;
- i = cls.netcon->qw.outgoing_sequence & QW_UPDATE_MASK;
- cmd = &cl.qw_moves[i];
- QW_MSG_WriteDeltaUsercmd(&buf, oldcmd, cmd);
- // calculate the checksum
- buf.data[checksumindex] = COM_BlockSequenceCRCByteQW(buf.data + checksumindex + 1, buf.cursize - checksumindex - 1, cls.netcon->qw.outgoing_sequence);
- // if delta compression history overflows, request no delta
- if (cls.netcon->qw.outgoing_sequence - cl.qw_validsequence >= QW_UPDATE_BACKUP-1)
- cl.qw_validsequence = 0;
- // request delta compression if appropriate
- if (cl.qw_validsequence && !cl_nodelta.integer && cls.state == ca_connected && !cls.demorecording)
- {
- cl.qw_deltasequence[cls.netcon->qw.outgoing_sequence & QW_UPDATE_MASK] = cl.qw_validsequence;
- MSG_WriteByte(&buf, qw_clc_delta);
- MSG_WriteByte(&buf, cl.qw_validsequence & 255);
- }
- else
- cl.qw_deltasequence[cls.netcon->qw.outgoing_sequence & QW_UPDATE_MASK] = -1;
- }
- else if (cls.protocol == PROTOCOL_QUAKE || cls.protocol == PROTOCOL_QUAKEDP || cls.protocol == PROTOCOL_NEHAHRAMOVIE)
- {
- // 5 bytes
- MSG_WriteByte (&buf, clc_move);
- MSG_WriteFloat (&buf, cl.mtime[0]); // so server can get ping times
- // 3 bytes
- for (i = 0;i < 3;i++)
- MSG_WriteAngle8i (&buf, cl.viewangles[i]);
- // 6 bytes
- MSG_WriteCoord16i (&buf, forwardmove);
- MSG_WriteCoord16i (&buf, sidemove);
- MSG_WriteCoord16i (&buf, upmove);
- // 2 bytes
- MSG_WriteByte (&buf, bits);
- MSG_WriteByte (&buf, impulse);
-
- CL_ClientMovement_Input((bits & 2) != 0, false);
- }
- else if (cls.protocol == PROTOCOL_DARKPLACES2 || cls.protocol == PROTOCOL_DARKPLACES3)
- {
- // 5 bytes
- MSG_WriteByte (&buf, clc_move);
- MSG_WriteFloat (&buf, cl.mtime[0]); // so server can get ping times
- // 12 bytes
- for (i = 0;i < 3;i++)
- MSG_WriteAngle32f (&buf, cl.viewangles[i]);
- // 6 bytes
- MSG_WriteCoord16i (&buf, forwardmove);
- MSG_WriteCoord16i (&buf, sidemove);
- MSG_WriteCoord16i (&buf, upmove);
- // 2 bytes
- MSG_WriteByte (&buf, bits);
- MSG_WriteByte (&buf, impulse);
-
- CL_ClientMovement_Input((bits & 2) != 0, false);
- }
- else if (cls.protocol == PROTOCOL_DARKPLACES1 || cls.protocol == PROTOCOL_DARKPLACES4 || cls.protocol == PROTOCOL_DARKPLACES5)
- {
- // 5 bytes
- MSG_WriteByte (&buf, clc_move);
- MSG_WriteFloat (&buf, cl.mtime[0]); // so server can get ping times
- // 6 bytes
- for (i = 0;i < 3;i++)
- MSG_WriteAngle16i (&buf, cl.viewangles[i]);
- // 6 bytes
- MSG_WriteCoord16i (&buf, forwardmove);
- MSG_WriteCoord16i (&buf, sidemove);
- MSG_WriteCoord16i (&buf, upmove);
- // 2 bytes
- MSG_WriteByte (&buf, bits);
- MSG_WriteByte (&buf, impulse);
-
- CL_ClientMovement_Input((bits & 2) != 0, false);
- }
- else
+ cl.qw_deltasequence[cls.netcon->qw.outgoing_sequence & QW_UPDATE_MASK] = cl.qw_validsequence;
+ MSG_WriteByte(&buf, qw_clc_delta);
+ MSG_WriteByte(&buf, cl.qw_validsequence & 255);
+ }
+ else
+ cl.qw_deltasequence[cls.netcon->qw.outgoing_sequence & QW_UPDATE_MASK] = -1;
+ }
+ else if (cls.signon == SIGNONS)
+ {
+ if (cls.protocol == PROTOCOL_QUAKE || cls.protocol == PROTOCOL_QUAKEDP || cls.protocol == PROTOCOL_NEHAHRAMOVIE)
+ {
+ // 5 bytes
+ MSG_WriteByte (&buf, clc_move);
+ MSG_WriteFloat (&buf, cl.movecmd[0].time); // last server packet time
+ // 3 bytes
+ for (i = 0;i < 3;i++)
+ MSG_WriteAngle8i (&buf, cl.movecmd[0].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);
+ // 2 bytes
+ MSG_WriteByte (&buf, cl.movecmd[0].buttons);
+ MSG_WriteByte (&buf, cl.movecmd[0].impulse);
+ }
+ else if (cls.protocol == PROTOCOL_DARKPLACES2 || cls.protocol == PROTOCOL_DARKPLACES3)
+ {
+ // 5 bytes
+ MSG_WriteByte (&buf, clc_move);
+ MSG_WriteFloat (&buf, cl.movecmd[0].time); // last server packet time
+ // 12 bytes
+ for (i = 0;i < 3;i++)
+ MSG_WriteAngle32f (&buf, cl.movecmd[0].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);
+ // 2 bytes
+ MSG_WriteByte (&buf, cl.movecmd[0].buttons);
+ MSG_WriteByte (&buf, cl.movecmd[0].impulse);
+ }
+ else if (cls.protocol == PROTOCOL_DARKPLACES1 || cls.protocol == PROTOCOL_DARKPLACES4 || cls.protocol == PROTOCOL_DARKPLACES5)
+ {
+ // 5 bytes
+ MSG_WriteByte (&buf, clc_move);
+ MSG_WriteFloat (&buf, cl.movecmd[0].time); // last server packet time
+ // 6 bytes
+ for (i = 0;i < 3;i++)
+ MSG_WriteAngle16i (&buf, cl.movecmd[0].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);
+ // 2 bytes
+ MSG_WriteByte (&buf, cl.movecmd[0].buttons);
+ MSG_WriteByte (&buf, cl.movecmd[0].impulse);
+ }
+ else if (cls.signon == SIGNONS)
+ {
+ int maxusercmds;
+ usercmd_t *cmd;
+
+ // FIXME: cl.movecmd[0].buttons & 16 is +button5, Nexuiz specific
+ CL_ClientMovement_Input((cl.movecmd[0].buttons & 2) != 0, (cl.movecmd[0].buttons & 16) != 0);
+
+ // set the maxusercmds variable to limit how many should be sent
+ maxusercmds = bound(1, cl_netinputpacketlosstolerance.integer + 1, CL_MAX_USERCMDS);
+ // when movement prediction is off, there's not much point in repeating old input as it will just be ignored
+ if (!cl.cmd.predicted)
+ maxusercmds = 1;
+
+ // send the latest moves in order, the old ones will be
+ // ignored by the server harmlessly, however if the previous
+ // packets were lost these moves will be used
+ //
+ // this reduces packet loss impact on gameplay.
+ for (j = 0, cmd = &cl.movecmd[maxusercmds-1];j < maxusercmds;j++, cmd--)