/* ================= CL_UpdateCmd Updates msec, angles and builds interpolated movement vector for local prediction. Doesn't touch command forward/side/upmove, these are filled by CL_FinalizeCmd. ================= */ void CL_UpdateCmd( int msec ) { VectorClear( cl.localmove ); if( sv_paused->integer ) { return; } // add to milliseconds of time to apply the move cl.cmd.msec += msec; // adjust viewangles CL_AdjustAngles( msec ); // get basic movement from keyboard CL_BaseMove( cl.localmove ); // allow mice to add to the move CL_MouseMove(); // add accumulated mouse forward/side movement cl.localmove[0] += cl.mousemove[0]; cl.localmove[1] += cl.mousemove[1]; // clamp to server defined max speed CL_ClampSpeed( cl.localmove ); CL_ClampPitch(); cl.cmd.angles[0] = ANGLE2SHORT( cl.viewangles[0] ); cl.cmd.angles[1] = ANGLE2SHORT( cl.viewangles[1] ); cl.cmd.angles[2] = ANGLE2SHORT( cl.viewangles[2] ); }
void CL_SendCmd(void) { usercmd_t cmd; if (cls.state != ca_connected) return; if (cls.signon == SIGNONS) { // get basic movement from keyboard CL_BaseMove(&cmd); // allow mice or other external controllers to add to the move IN_Move(&cmd); // send the unreliable message CL_SendMove(&cmd); } if (cls.demoplayback) { SZ_Clear(&cls.message); return; } // send the reliable message if (!cls.message.cursize) return; // no message at all if (!NET_CanSendMessage(cls.netcon)) { Con_DPrintf("CL_WriteToServer: can't send\n"); return; } if (NET_SendMessage(cls.netcon, &cls.message) == -1) Host_Error("CL_WriteToServer: lost server connection"); SZ_Clear(&cls.message); }
usercmd_t CL_CreateCmd(void) { usercmd_t cmd; frame_msec = sys_frame_time - old_sys_frame_time; if (frame_msec < 1) { frame_msec = 1; } if (frame_msec > 200) { frame_msec = 200; } /* get basic movement from keyboard */ CL_BaseMove(&cmd); /* allow mice or other external controllers to add to the move */ IN_Move(&cmd); CL_FinishMove(&cmd); old_sys_frame_time = sys_frame_time; return cmd; }
/* ================= CL_RefreshCmd jec - Adds any new input changes to usercmd that occurred since last Init or RefreshCmd. ================= */ void CL_RefreshCmd (void) { int ms; usercmd_t *cmd = &cl.cmds[ cls.netchan.outgoing_sequence & (CMD_BACKUP-1) ]; // get delta for this sample. frame_msec = sys_frame_time - old_sys_frame_time; // bounds checking if (frame_msec < 1) return; if (frame_msec > 200) frame_msec = 200; //cmd->forwardmove = cmd->sidemove = cmd->upmove = 0; // Get basic movement from keyboard CL_BaseMove (cmd); // Allow mice or other external controllers to add to the move IN_Move (cmd); // Update cmd viewangles for CL_PredictMove CL_ClampPitch (); cmd->angles[0] = ANGLE2SHORT(cl.viewangles[0]); cmd->angles[1] = ANGLE2SHORT(cl.viewangles[1]); cmd->angles[2] = ANGLE2SHORT(cl.viewangles[2]); // Update cmd->msec for CL_PredictMove ms = (int)(cls.netFrameTime * 1000); if (ms > 250) ms = 100; cmd->msec = ms; // Update counter old_sys_frame_time = sys_frame_time; //7 = starting attack 1 2 4 //5 = during attack 1 4 //4 = idle 4 // Send packet immediately on important events if (((in_attack.state & 2) || (in_attack2.state & 2) || (in_use.state & 2))) cls.forcePacket = true; }
void CL_RefreshCmd(void) { int ms; usercmd_t *cmd; // CMD to fill cmd = &cl.cmds[cls.netchan.outgoing_sequence & (CMD_BACKUP - 1)]; // Calculate delta frame_msec = sys_frame_time - old_sys_frame_time; // Check bounds if (frame_msec < 1) { return; } else if (frame_msec > 200) { frame_msec = 200; } // Add movement CL_BaseMove(cmd); input_command(cmd); // Clamp angels for prediction CL_ClampPitch(); cmd->angles[0] = ANGLE2SHORT(cl.viewangles[0]); cmd->angles[1] = ANGLE2SHORT(cl.viewangles[1]); cmd->angles[2] = ANGLE2SHORT(cl.viewangles[2]); // Update time for prediction ms = (int) (cls.nframetime * 1000.0f); if (ms > 250) { ms = 100; } cmd->msec = ms; // Update frame time for the next call old_sys_frame_time = sys_frame_time; // Important events are send immediately if (((in_attack.state & 2)) || (in_use.state & 2)) { cls.forcePacket = true; } }
/* ================= CL_RefreshMove Just updates movement, such as when disconnected. ================= */ void CL_RefreshMove (void) { usercmd_t *cmd = &cl.cmds[ cls.netchan.outgoing_sequence & (CMD_BACKUP-1) ]; // get delta for this sample. frame_msec = sys_frame_time - old_sys_frame_time; // bounds checking if (frame_msec < 1) return; if (frame_msec > 200) frame_msec = 200; // Get basic movement from keyboard CL_BaseMove (cmd); // Allow mice or other external controllers to add to the move IN_Move (cmd); // Update counter old_sys_frame_time = sys_frame_time; }
void CL_RefreshMove(void) { usercmd_t *cmd; // CMD to fill cmd = &cl.cmds[cls.netchan.outgoing_sequence & (CMD_BACKUP - 1)]; // Calculate delta frame_msec = sys_frame_time - old_sys_frame_time; // Check bounds if (frame_msec < 1) { return; } else if (frame_msec > 200) { frame_msec = 200; } // Add movement CL_BaseMove(cmd); input_command(cmd); old_sys_frame_time = sys_frame_time; }
/* ================= CL_CreateCmd ================= */ usercmd_t CL_CreateCmd (void) { usercmd_t cmd; frame_msec = sys_frame_time - old_sys_frame_time; if (frame_msec < 1) frame_msec = 1; if (frame_msec > 200) frame_msec = 200; // get basic movement from keyboard CL_BaseMove (&cmd); // allow mice or other external controllers to add to the move IN_Move (&cmd); CL_FinishMove (&cmd); old_sys_frame_time = sys_frame_time; //cmd.impulse = cls.framecount; return cmd; }
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; 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); }
/* ================= CL_FinalizeCmd Builds the actual movement vector for sending to server. Assumes that msec and angles are already set for this frame by CL_UpdateCmd. ================= */ void CL_FinalizeCmd( void ) { vec3_t move; // command buffer ticks in sync with cl_maxfps if( cmd_buffer.waitCount > 0 ) { cmd_buffer.waitCount--; } if( cl_cmdbuf.waitCount > 0 ) { cl_cmdbuf.waitCount--; } if( cls.state < ca_active ) { return; // not talking to a server } if( sv_paused->integer ) { return; } // // figure button bits // if( in_attack.state & 3 ) cl.cmd.buttons |= BUTTON_ATTACK; if( in_use.state & 3 ) cl.cmd.buttons |= BUTTON_USE; in_attack.state &= ~2; in_use.state &= ~2; if( cls.key_dest == KEY_GAME && Key_AnyKeyDown() ) { cl.cmd.buttons |= BUTTON_ANY; } if( cl.cmd.msec > 250 ) { cl.cmd.msec = 100; // time was unreasonable } // rebuild the movement vector VectorClear( move ); // get basic movement from keyboard CL_BaseMove( move ); // add mouse forward/side movement move[0] += cl.mousemove[0]; move[1] += cl.mousemove[1]; // clamp to server defined max speed CL_ClampSpeed( move ); // store the movement vector cl.cmd.forwardmove = move[0]; cl.cmd.sidemove = move[1]; cl.cmd.upmove = move[2]; // clear all states cl.mousemove[0] = 0; cl.mousemove[1] = 0; KeyClear( &in_right ); KeyClear( &in_left ); KeyClear( &in_moveright ); KeyClear( &in_moveleft ); KeyClear( &in_up ); KeyClear( &in_down ); KeyClear( &in_forward ); KeyClear( &in_back ); KeyClear( &in_lookup ); KeyClear( &in_lookdown ); cl.cmd.impulse = in_impulse; in_impulse = 0; // save this command off for prediction cl.cmdNumber++; cl.cmds[cl.cmdNumber & CMD_MASK] = cl.cmd; // clear pending cmd memset( &cl.cmd, 0, sizeof( cl.cmd ) ); }
/* ================= 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); }