/* ================= CL_SendCmd ================= */ void CL_SendCmd (void) { sizebuf_t buf; byte data[128]; int i; usercmd_t *cmd; if (cls.demoplayback) return; // sendcmds come from the demo // save this command off for prediction i = cls.netchan.outgoing_sequence & UPDATE_MASK; cmd = &cl.frames[i].cmd; cl.frames[i].senttime = realtime; cl.frames[i].receivedtime = -1; // we haven't gotten a reply yet // get basic movement from keyboard CL_BaseMove (cmd); // allow mice or other external controllers to add to the move IN_Move (cmd); // if we are spectator, try autocam if (cl.spectator) Cam_Track(cmd); CL_FinishMove(cmd); Cam_FinishMove(cmd); // send this and the previous cmds in the message, so // if the last packet was dropped, it can be recovered buf.maxsize = 128; buf.cursize = 0; buf.data = data; MSG_WriteByte (&buf, clc_move); i = (cls.netchan.outgoing_sequence-2) & UPDATE_MASK; MSG_WriteUsercmd (&buf, &cl.frames[i].cmd, false); i = (cls.netchan.outgoing_sequence-1) & UPDATE_MASK; MSG_WriteUsercmd (&buf, &cl.frames[i].cmd, false); i = (cls.netchan.outgoing_sequence) & UPDATE_MASK; MSG_WriteUsercmd (&buf, &cl.frames[i].cmd, true); // Con_Printf("I %hd %hd %hd\n",cmd->forwardmove, cmd->sidemove, cmd->upmove); // request delta compression of entities if (cls.netchan.outgoing_sequence - cl.validsequence >= UPDATE_BACKUP-1) cl.validsequence = 0; if (cl.validsequence && !cl_nodelta.value && cls.state == ca_active && !cls.demorecording) { cl.frames[cls.netchan.outgoing_sequence&UPDATE_MASK].delta_sequence = cl.validsequence; MSG_WriteByte (&buf, clc_delta); MSG_WriteByte (&buf, cl.validsequence&255); } else cl.frames[cls.netchan.outgoing_sequence&UPDATE_MASK].delta_sequence = -1; if (cls.demorecording) CL_WriteDemoCmd(cmd); // // deliver the message // Netchan_Transmit (&cls.netchan, buf.cursize, buf.data); }
void CL_SendCmd (void) { sizebuf_t buf; byte data[128]; usercmd_t *cmd, *oldcmd; int i, checksumIndex, lost; qbool dontdrop; static float pps_balance = 0; static int dropcount = 0; if (cls.demoplayback && !cls.mvdplayback) return; // sendcmds come from the demo #ifdef FTE_PEXT_CHUNKEDDOWNLOADS CL_SendChunkDownloadReq(); #endif // save this command off for prediction i = cls.netchan.outgoing_sequence & UPDATE_MASK; cmd = &cl.frames[i].cmd; cl.frames[i].senttime = cls.realtime; cl.frames[i].receivedtime = -1; // we haven't gotten a reply yet // update network stats table i = cls.netchan.outgoing_sequence&NETWORK_STATS_MASK; network_stats[i].delta = 0; // filled-in later network_stats[i].sentsize = 0; // filled-in later network_stats[i].senttime = cls.realtime; network_stats[i].receivedtime = -1; // get basic movement from keyboard CL_BaseMove (cmd); // allow mice or other external controllers to add to the move if (cl_independentPhysics.value == 0 || (physframe && cl_independentPhysics.value != 0)) { IN_Move(cmd); } // if we are spectator, try autocam if (cl.spectator) Cam_Track(cmd); CL_FinishMove(cmd); cmdtime_msec += cmd->msec; Cam_FinishMove(cmd); if (cls.mvdplayback) { CL_CalcPlayerFPS(&cl.players[cl.playernum], cmd->msec); cls.netchan.outgoing_sequence++; return; } SZ_Init (&buf, data, sizeof(data)); SZ_Write (&buf, cls.cmdmsg.data, cls.cmdmsg.cursize); if (cls.cmdmsg.overflowed) Com_DPrintf("cls.cmdmsg overflowed\n"); SZ_Clear (&cls.cmdmsg); // begin a client move command MSG_WriteByte (&buf, clc_move); // save the position for a checksum byte checksumIndex = buf.cursize; MSG_WriteByte (&buf, 0); // write our lossage percentage lost = CL_CalcNet(); MSG_WriteByte (&buf, (byte)lost); // send this and the previous two cmds in the message, so if the last packet was dropped, it can be recovered dontdrop = false; i = (cls.netchan.outgoing_sequence - 2) & UPDATE_MASK; cmd = &cl.frames[i].cmd; if (cl_c2sImpulseBackup.value >= 2) dontdrop = dontdrop || cmd->impulse; MSG_WriteDeltaUsercmd (&buf, &nullcmd, cmd); oldcmd = cmd; i = (cls.netchan.outgoing_sequence - 1) & UPDATE_MASK; cmd = &cl.frames[i].cmd; if (cl_c2sImpulseBackup.value >= 3) dontdrop = dontdrop || cmd->impulse; MSG_WriteDeltaUsercmd (&buf, oldcmd, cmd); oldcmd = cmd; i = (cls.netchan.outgoing_sequence) & UPDATE_MASK; cmd = &cl.frames[i].cmd; if (cl_c2sImpulseBackup.value >= 1) dontdrop = dontdrop || cmd->impulse; MSG_WriteDeltaUsercmd (&buf, oldcmd, cmd); // calculate a checksum over the move commands buf.data[checksumIndex] = COM_BlockSequenceCRCByte( buf.data + checksumIndex + 1, buf.cursize - checksumIndex - 1, cls.netchan.outgoing_sequence); // request delta compression of entities if (cls.netchan.outgoing_sequence - cl.validsequence >= UPDATE_BACKUP - 1) { cl.validsequence = 0; cl.delta_sequence = 0; } if (cl.delta_sequence && !cl_nodelta.value && cls.state == ca_active) { cl.frames[cls.netchan.outgoing_sequence & UPDATE_MASK].delta_sequence = cl.delta_sequence; MSG_WriteByte (&buf, clc_delta); MSG_WriteByte (&buf, cl.delta_sequence & 255); // network stats table network_stats[cls.netchan.outgoing_sequence&NETWORK_STATS_MASK].delta = 1; } else { cl.frames[cls.netchan.outgoing_sequence & UPDATE_MASK].delta_sequence = -1; } if (cls.demorecording) CL_WriteDemoCmd (cmd); if (cl_c2spps.value) { pps_balance += cls.frametime; // never drop more than 2 messages in a row -- that'll cause PL // and don't drop if one of the last two movemessages have an impulse if (pps_balance > 0 || dropcount >= 2 || dontdrop) { float pps; pps = cl_c2spps.value; if (pps < 10) pps = 10; if (pps > 72) pps = 72; pps_balance -= 1 / pps; // bound pps_balance. FIXME: is there a better way? if (pps_balance > 0.1) pps_balance = 0.1; if (pps_balance < -0.1) pps_balance = -0.1; dropcount = 0; } else { // don't count this message when calculating PL cl.frames[i].receivedtime = -3; // drop this message cls.netchan.outgoing_sequence++; dropcount++; return; } } else { pps_balance = 0; dropcount = 0; } #ifdef FTE_PEXT2_VOICECHAT S_Voip_Transmit(clc_voicechat, &buf); #endif cl.frames[cls.netchan.outgoing_sequence&UPDATE_MASK].sentsize = buf.cursize + 8; // 8 = PACKET_HEADER // network stats table network_stats[cls.netchan.outgoing_sequence&NETWORK_STATS_MASK].sentsize = buf.cursize + 8; // deliver the message Netchan_Transmit (&cls.netchan, buf.cursize, buf.data); }
/* ================= CL_SendCmd ================= */ void CL_SendCmd (void) { sizebuf_t buf; byte data[128]; int i; usercmd_t *cmd, *oldcmd; int checksumIndex; int lost; int seq_hash; if (cls.demoplayback) return; // sendcmds come from the demo // save this command off for prediction i = cls.netchan.outgoing_sequence & UPDATE_MASK; cmd = &cl.frames[i].cmd; cl.frames[i].senttime = realtime; cl.frames[i].receivedtime = -1; // we haven't gotten a reply yet // seq_hash = (cls.netchan.outgoing_sequence & 0xffff) ; // ^ QW_CHECK_HASH; seq_hash = cls.netchan.outgoing_sequence; // get basic movement from keyboard CL_BaseMove (cmd); // allow mice or other external controllers to add to the move IN_Move (cmd); // if we are spectator, try autocam if (cl.spectator) Cam_Track(cmd); CL_FinishMove(cmd); Cam_FinishMove(cmd); // send this and the previous cmds in the message, so // if the last packet was dropped, it can be recovered buf.maxsize = 128; buf.cursize = 0; buf.data = data; MSG_WriteByte (&buf, clc_move); // save the position for a checksum byte checksumIndex = buf.cursize; MSG_WriteByte (&buf, 0); // write our lossage percentage lost = CL_CalcNet(); MSG_WriteByte (&buf, (byte)lost); i = (cls.netchan.outgoing_sequence-2) & UPDATE_MASK; cmd = &cl.frames[i].cmd; MSG_WriteDeltaUsercmd (&buf, &nullcmd, cmd); oldcmd = cmd; i = (cls.netchan.outgoing_sequence-1) & UPDATE_MASK; cmd = &cl.frames[i].cmd; MSG_WriteDeltaUsercmd (&buf, oldcmd, cmd); oldcmd = cmd; i = (cls.netchan.outgoing_sequence) & UPDATE_MASK; cmd = &cl.frames[i].cmd; MSG_WriteDeltaUsercmd (&buf, oldcmd, cmd); // calculate a checksum over the move commands buf.data[checksumIndex] = COM_BlockSequenceCRCByte( buf.data + checksumIndex + 1, buf.cursize - checksumIndex - 1, seq_hash); // request delta compression of entities if (cls.netchan.outgoing_sequence - cl.validsequence >= UPDATE_BACKUP-1) cl.validsequence = 0; if (cl.validsequence && !cl_nodelta.value && cls.state == ca_active && !cls.demorecording) { cl.frames[cls.netchan.outgoing_sequence&UPDATE_MASK].delta_sequence = cl.validsequence; MSG_WriteByte (&buf, clc_delta); MSG_WriteByte (&buf, cl.validsequence&255); } else cl.frames[cls.netchan.outgoing_sequence&UPDATE_MASK].delta_sequence = -1; if (cls.demorecording) CL_WriteDemoCmd(cmd); // // deliver the message // Netchan_Transmit (&cls.netchan, buf.cursize, buf.data); }