Main Page | Class Hierarchy | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals

cl_input.c

Go to the documentation of this file.
00001 /*
00002 ===========================================================================
00003 Copyright (C) 1999-2005 Id Software, Inc.
00004 
00005 This file is part of Quake III Arena source code.
00006 
00007 Quake III Arena source code is free software; you can redistribute it
00008 and/or modify it under the terms of the GNU General Public License as
00009 published by the Free Software Foundation; either version 2 of the License,
00010 or (at your option) any later version.
00011 
00012 Quake III Arena source code is distributed in the hope that it will be
00013 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015 GNU General Public License for more details.
00016 
00017 You should have received a copy of the GNU General Public License
00018 along with Foobar; if not, write to the Free Software
00019 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00020 ===========================================================================
00021 */
00022 // cl.input.c  -- builds an intended movement command to send to the server
00023 
00024 #include "client.h"
00025 
00026 unsigned    frame_msec;
00027 int         old_com_frameTime;
00028 
00029 /*
00030 ===============================================================================
00031 
00032 KEY BUTTONS
00033 
00034 Continuous button event tracking is complicated by the fact that two different
00035 input sources (say, mouse button 1 and the control key) can both press the
00036 same button, but the button should only be released when both of the
00037 pressing key have been released.
00038 
00039 When a key event issues a button command (+forward, +attack, etc), it appends
00040 its key number as argv(1) so it can be matched up with the release.
00041 
00042 argv(2) will be set to the time the event happened, which allows exact
00043 control even at low framerates when the down and up events may both get qued
00044 at the same time.
00045 
00046 ===============================================================================
00047 */
00048 
00049 
00050 kbutton_t   in_left, in_right, in_forward, in_back;
00051 kbutton_t   in_lookup, in_lookdown, in_moveleft, in_moveright;
00052 kbutton_t   in_strafe, in_speed;
00053 kbutton_t   in_up, in_down;
00054 
00055 kbutton_t   in_buttons[16];
00056 
00057 
00058 qboolean    in_mlooking;
00059 
00060 
00061 void IN_MLookDown( void ) {
00062     in_mlooking = qtrue;
00063 }
00064 
00065 void IN_MLookUp( void ) {
00066     in_mlooking = qfalse;
00067     if ( !cl_freelook->integer ) {
00068         IN_CenterView ();
00069     }
00070 }
00071 
00072 void IN_KeyDown( kbutton_t *b ) {
00073     int     k;
00074     char    *c;
00075     
00076     c = Cmd_Argv(1);
00077     if ( c[0] ) {
00078         k = atoi(c);
00079     } else {
00080         k = -1;     // typed manually at the console for continuous down
00081     }
00082 
00083     if ( k == b->down[0] || k == b->down[1] ) {
00084         return;     // repeating key
00085     }
00086     
00087     if ( !b->down[0] ) {
00088         b->down[0] = k;
00089     } else if ( !b->down[1] ) {
00090         b->down[1] = k;
00091     } else {
00092         Com_Printf ("Three keys down for a button!\n");
00093         return;
00094     }
00095     
00096     if ( b->active ) {
00097         return;     // still down
00098     }
00099 
00100     // save timestamp for partial frame summing
00101     c = Cmd_Argv(2);
00102     b->downtime = atoi(c);
00103 
00104     b->active = qtrue;
00105     b->wasPressed = qtrue;
00106 }
00107 
00108 void IN_KeyUp( kbutton_t *b ) {
00109     int     k;
00110     char    *c;
00111     unsigned    uptime;
00112 
00113     c = Cmd_Argv(1);
00114     if ( c[0] ) {
00115         k = atoi(c);
00116     } else {
00117         // typed manually at the console, assume for unsticking, so clear all
00118         b->down[0] = b->down[1] = 0;
00119         b->active = qfalse;
00120         return;
00121     }
00122 
00123     if ( b->down[0] == k ) {
00124         b->down[0] = 0;
00125     } else if ( b->down[1] == k ) {
00126         b->down[1] = 0;
00127     } else {
00128         return;     // key up without coresponding down (menu pass through)
00129     }
00130     if ( b->down[0] || b->down[1] ) {
00131         return;     // some other key is still holding it down
00132     }
00133 
00134     b->active = qfalse;
00135 
00136     // save timestamp for partial frame summing
00137     c = Cmd_Argv(2);
00138     uptime = atoi(c);
00139     if ( uptime ) {
00140         b->msec += uptime - b->downtime;
00141     } else {
00142         b->msec += frame_msec / 2;
00143     }
00144 
00145     b->active = qfalse;
00146 }
00147 
00148 
00149 
00150 /*
00151 ===============
00152 CL_KeyState
00153 
00154 Returns the fraction of the frame that the key was down
00155 ===============
00156 */
00157 float CL_KeyState( kbutton_t *key ) {
00158     float       val;
00159     int         msec;
00160 
00161     msec = key->msec;
00162     key->msec = 0;
00163 
00164     if ( key->active ) {
00165         // still down
00166         if ( !key->downtime ) {
00167             msec = com_frameTime;
00168         } else {
00169             msec += com_frameTime - key->downtime;
00170         }
00171         key->downtime = com_frameTime;
00172     }
00173 
00174 #if 0
00175     if (msec) {
00176         Com_Printf ("%i ", msec);
00177     }
00178 #endif
00179 
00180     val = (float)msec / frame_msec;
00181     if ( val < 0 ) {
00182         val = 0;
00183     }
00184     if ( val > 1 ) {
00185         val = 1;
00186     }
00187 
00188     return val;
00189 }
00190 
00191 
00192 
00193 void IN_UpDown(void) {IN_KeyDown(&in_up);}
00194 void IN_UpUp(void) {IN_KeyUp(&in_up);}
00195 void IN_DownDown(void) {IN_KeyDown(&in_down);}
00196 void IN_DownUp(void) {IN_KeyUp(&in_down);}
00197 void IN_LeftDown(void) {IN_KeyDown(&in_left);}
00198 void IN_LeftUp(void) {IN_KeyUp(&in_left);}
00199 void IN_RightDown(void) {IN_KeyDown(&in_right);}
00200 void IN_RightUp(void) {IN_KeyUp(&in_right);}
00201 void IN_ForwardDown(void) {IN_KeyDown(&in_forward);}
00202 void IN_ForwardUp(void) {IN_KeyUp(&in_forward);}
00203 void IN_BackDown(void) {IN_KeyDown(&in_back);}
00204 void IN_BackUp(void) {IN_KeyUp(&in_back);}
00205 void IN_LookupDown(void) {IN_KeyDown(&in_lookup);}
00206 void IN_LookupUp(void) {IN_KeyUp(&in_lookup);}
00207 void IN_LookdownDown(void) {IN_KeyDown(&in_lookdown);}
00208 void IN_LookdownUp(void) {IN_KeyUp(&in_lookdown);}
00209 void IN_MoveleftDown(void) {IN_KeyDown(&in_moveleft);}
00210 void IN_MoveleftUp(void) {IN_KeyUp(&in_moveleft);}
00211 void IN_MoverightDown(void) {IN_KeyDown(&in_moveright);}
00212 void IN_MoverightUp(void) {IN_KeyUp(&in_moveright);}
00213 
00214 void IN_SpeedDown(void) {IN_KeyDown(&in_speed);}
00215 void IN_SpeedUp(void) {IN_KeyUp(&in_speed);}
00216 void IN_StrafeDown(void) {IN_KeyDown(&in_strafe);}
00217 void IN_StrafeUp(void) {IN_KeyUp(&in_strafe);}
00218 
00219 void IN_Button0Down(void) {IN_KeyDown(&in_buttons[0]);}
00220 void IN_Button0Up(void) {IN_KeyUp(&in_buttons[0]);}
00221 void IN_Button1Down(void) {IN_KeyDown(&in_buttons[1]);}
00222 void IN_Button1Up(void) {IN_KeyUp(&in_buttons[1]);}
00223 void IN_Button2Down(void) {IN_KeyDown(&in_buttons[2]);}
00224 void IN_Button2Up(void) {IN_KeyUp(&in_buttons[2]);}
00225 void IN_Button3Down(void) {IN_KeyDown(&in_buttons[3]);}
00226 void IN_Button3Up(void) {IN_KeyUp(&in_buttons[3]);}
00227 void IN_Button4Down(void) {IN_KeyDown(&in_buttons[4]);}
00228 void IN_Button4Up(void) {IN_KeyUp(&in_buttons[4]);}
00229 void IN_Button5Down(void) {IN_KeyDown(&in_buttons[5]);}
00230 void IN_Button5Up(void) {IN_KeyUp(&in_buttons[5]);}
00231 void IN_Button6Down(void) {IN_KeyDown(&in_buttons[6]);}
00232 void IN_Button6Up(void) {IN_KeyUp(&in_buttons[6]);}
00233 void IN_Button7Down(void) {IN_KeyDown(&in_buttons[7]);}
00234 void IN_Button7Up(void) {IN_KeyUp(&in_buttons[7]);}
00235 void IN_Button8Down(void) {IN_KeyDown(&in_buttons[8]);}
00236 void IN_Button8Up(void) {IN_KeyUp(&in_buttons[8]);}
00237 void IN_Button9Down(void) {IN_KeyDown(&in_buttons[9]);}
00238 void IN_Button9Up(void) {IN_KeyUp(&in_buttons[9]);}
00239 void IN_Button10Down(void) {IN_KeyDown(&in_buttons[10]);}
00240 void IN_Button10Up(void) {IN_KeyUp(&in_buttons[10]);}
00241 void IN_Button11Down(void) {IN_KeyDown(&in_buttons[11]);}
00242 void IN_Button11Up(void) {IN_KeyUp(&in_buttons[11]);}
00243 void IN_Button12Down(void) {IN_KeyDown(&in_buttons[12]);}
00244 void IN_Button12Up(void) {IN_KeyUp(&in_buttons[12]);}
00245 void IN_Button13Down(void) {IN_KeyDown(&in_buttons[13]);}
00246 void IN_Button13Up(void) {IN_KeyUp(&in_buttons[13]);}
00247 void IN_Button14Down(void) {IN_KeyDown(&in_buttons[14]);}
00248 void IN_Button14Up(void) {IN_KeyUp(&in_buttons[14]);}
00249 void IN_Button15Down(void) {IN_KeyDown(&in_buttons[15]);}
00250 void IN_Button15Up(void) {IN_KeyUp(&in_buttons[15]);}
00251 
00252 void IN_ButtonDown (void) {
00253     IN_KeyDown(&in_buttons[1]);}
00254 void IN_ButtonUp (void) {
00255     IN_KeyUp(&in_buttons[1]);}
00256 
00257 void IN_CenterView (void) {
00258     cl.viewangles[PITCH] = -SHORT2ANGLE(cl.snap.ps.delta_angles[PITCH]);
00259 }
00260 
00261 
00262 //==========================================================================
00263 
00264 cvar_t  *cl_upspeed;
00265 cvar_t  *cl_forwardspeed;
00266 cvar_t  *cl_sidespeed;
00267 
00268 cvar_t  *cl_yawspeed;
00269 cvar_t  *cl_pitchspeed;
00270 
00271 cvar_t  *cl_run;
00272 
00273 cvar_t  *cl_anglespeedkey;
00274 
00275 
00276 /*
00277 ================
00278 CL_AdjustAngles
00279 
00280 Moves the local angle positions
00281 ================
00282 */
00283 void CL_AdjustAngles( void ) {
00284     float   speed;
00285     
00286     if ( in_speed.active ) {
00287         speed = 0.001 * cls.frametime * cl_anglespeedkey->value;
00288     } else {
00289         speed = 0.001 * cls.frametime;
00290     }
00291 
00292     if ( !in_strafe.active ) {
00293         cl.viewangles[YAW] -= speed*cl_yawspeed->value*CL_KeyState (&in_right);
00294         cl.viewangles[YAW] += speed*cl_yawspeed->value*CL_KeyState (&in_left);
00295     }
00296 
00297     cl.viewangles[PITCH] -= speed*cl_pitchspeed->value * CL_KeyState (&in_lookup);
00298     cl.viewangles[PITCH] += speed*cl_pitchspeed->value * CL_KeyState (&in_lookdown);
00299 }
00300 
00301 /*
00302 ================
00303 CL_KeyMove
00304 
00305 Sets the usercmd_t based on key states
00306 ================
00307 */
00308 void CL_KeyMove( usercmd_t *cmd ) {
00309     int     movespeed;
00310     int     forward, side, up;
00311 
00312     //
00313     // adjust for speed key / running
00314     // the walking flag is to keep animations consistant
00315     // even during acceleration and develeration
00316     //
00317     if ( in_speed.active ^ cl_run->integer ) {
00318         movespeed = 127;
00319         cmd->buttons &= ~BUTTON_WALKING;
00320     } else {
00321         cmd->buttons |= BUTTON_WALKING;
00322         movespeed = 64;
00323     }
00324 
00325     forward = 0;
00326     side = 0;
00327     up = 0;
00328     if ( in_strafe.active ) {
00329         side += movespeed * CL_KeyState (&in_right);
00330         side -= movespeed * CL_KeyState (&in_left);
00331     }
00332 
00333     side += movespeed * CL_KeyState (&in_moveright);
00334     side -= movespeed * CL_KeyState (&in_moveleft);
00335 
00336 
00337     up += movespeed * CL_KeyState (&in_up);
00338     up -= movespeed * CL_KeyState (&in_down);
00339 
00340     forward += movespeed * CL_KeyState (&in_forward);
00341     forward -= movespeed * CL_KeyState (&in_back);
00342 
00343     cmd->forwardmove = ClampChar( forward );
00344     cmd->rightmove = ClampChar( side );
00345     cmd->upmove = ClampChar( up );
00346 }
00347 
00348 /*
00349 =================
00350 CL_MouseEvent
00351 =================
00352 */
00353 void CL_MouseEvent( int dx, int dy, int time ) {
00354     if ( cls.keyCatchers & KEYCATCH_UI ) {
00355         VM_Call( uivm, UI_MOUSE_EVENT, dx, dy );
00356     } else if (cls.keyCatchers & KEYCATCH_CGAME) {
00357         VM_Call (cgvm, CG_MOUSE_EVENT, dx, dy);
00358     } else {
00359         cl.mouseDx[cl.mouseIndex] += dx;
00360         cl.mouseDy[cl.mouseIndex] += dy;
00361     }
00362 }
00363 
00364 /*
00365 =================
00366 CL_JoystickEvent
00367 
00368 Joystick values stay set until changed
00369 =================
00370 */
00371 void CL_JoystickEvent( int axis, int value, int time ) {
00372     if ( axis < 0 || axis >= MAX_JOYSTICK_AXIS ) {
00373         Com_Error( ERR_DROP, "CL_JoystickEvent: bad axis %i", axis );
00374     }
00375     cl.joystickAxis[axis] = value;
00376 }
00377 
00378 /*
00379 =================
00380 CL_JoystickMove
00381 =================
00382 */
00383 void CL_JoystickMove( usercmd_t *cmd ) {
00384     int     movespeed;
00385     float   anglespeed;
00386 
00387     if ( in_speed.active ^ cl_run->integer ) {
00388         movespeed = 2;
00389     } else {
00390         movespeed = 1;
00391         cmd->buttons |= BUTTON_WALKING;
00392     }
00393 
00394     if ( in_speed.active ) {
00395         anglespeed = 0.001 * cls.frametime * cl_anglespeedkey->value;
00396     } else {
00397         anglespeed = 0.001 * cls.frametime;
00398     }
00399 
00400     if ( !in_strafe.active ) {
00401         cl.viewangles[YAW] += anglespeed * cl_yawspeed->value * cl.joystickAxis[AXIS_SIDE];
00402     } else {
00403         cmd->rightmove = ClampChar( cmd->rightmove + cl.joystickAxis[AXIS_SIDE] );
00404     }
00405 
00406     if ( in_mlooking ) {
00407         cl.viewangles[PITCH] += anglespeed * cl_pitchspeed->value * cl.joystickAxis[AXIS_FORWARD];
00408     } else {
00409         cmd->forwardmove = ClampChar( cmd->forwardmove + cl.joystickAxis[AXIS_FORWARD] );
00410     }
00411 
00412     cmd->upmove = ClampChar( cmd->upmove + cl.joystickAxis[AXIS_UP] );
00413 }
00414 
00415 /*
00416 =================
00417 CL_MouseMove
00418 =================
00419 */
00420 void CL_MouseMove( usercmd_t *cmd ) {
00421     float   mx, my;
00422     float   accelSensitivity;
00423     float   rate;
00424 
00425     // allow mouse smoothing
00426     if ( m_filter->integer ) {
00427         mx = ( cl.mouseDx[0] + cl.mouseDx[1] ) * 0.5;
00428         my = ( cl.mouseDy[0] + cl.mouseDy[1] ) * 0.5;
00429     } else {
00430         mx = cl.mouseDx[cl.mouseIndex];
00431         my = cl.mouseDy[cl.mouseIndex];
00432     }
00433     cl.mouseIndex ^= 1;
00434     cl.mouseDx[cl.mouseIndex] = 0;
00435     cl.mouseDy[cl.mouseIndex] = 0;
00436 
00437     rate = sqrt( mx * mx + my * my ) / (float)frame_msec;
00438     accelSensitivity = cl_sensitivity->value + rate * cl_mouseAccel->value;
00439 
00440     // scale by FOV
00441     accelSensitivity *= cl.cgameSensitivity;
00442 
00443     if ( rate && cl_showMouseRate->integer ) {
00444         Com_Printf( "%f : %f\n", rate, accelSensitivity );
00445     }
00446 
00447     mx *= accelSensitivity;
00448     my *= accelSensitivity;
00449 
00450     if (!mx && !my) {
00451         return;
00452     }
00453 
00454     // add mouse X/Y movement to cmd
00455     if ( in_strafe.active ) {
00456         cmd->rightmove = ClampChar( cmd->rightmove + m_side->value * mx );
00457     } else {
00458         cl.viewangles[YAW] -= m_yaw->value * mx;
00459     }
00460 
00461     if ( (in_mlooking || cl_freelook->integer) && !in_strafe.active ) {
00462         cl.viewangles[PITCH] += m_pitch->value * my;
00463     } else {
00464         cmd->forwardmove = ClampChar( cmd->forwardmove - m_forward->value * my );
00465     }
00466 }
00467 
00468 
00469 /*
00470 ==============
00471 CL_CmdButtons
00472 ==============
00473 */
00474 void CL_CmdButtons( usercmd_t *cmd ) {
00475     int     i;
00476 
00477     //
00478     // figure button bits
00479     // send a button bit even if the key was pressed and released in
00480     // less than a frame
00481     //  
00482     for (i = 0 ; i < 15 ; i++) {
00483         if ( in_buttons[i].active || in_buttons[i].wasPressed ) {
00484             cmd->buttons |= 1 << i;
00485         }
00486         in_buttons[i].wasPressed = qfalse;
00487     }
00488 
00489     if ( cls.keyCatchers ) {
00490         cmd->buttons |= BUTTON_TALK;
00491     }
00492 
00493     // allow the game to know if any key at all is
00494     // currently pressed, even if it isn't bound to anything
00495     if ( anykeydown && !cls.keyCatchers ) {
00496         cmd->buttons |= BUTTON_ANY;
00497     }
00498 }
00499 
00500 
00501 /*
00502 ==============
00503 CL_FinishMove
00504 ==============
00505 */
00506 void CL_FinishMove( usercmd_t *cmd ) {
00507     int     i;
00508 
00509     // copy the state that the cgame is currently sending
00510     cmd->weapon = cl.cgameUserCmdValue;
00511 
00512     // send the current server time so the amount of movement
00513     // can be determined without allowing cheating
00514     cmd->serverTime = cl.serverTime;
00515 
00516     for (i=0 ; i<3 ; i++) {
00517         cmd->angles[i] = ANGLE2SHORT(cl.viewangles[i]);
00518     }
00519 }
00520 
00521 
00522 /*
00523 =================
00524 CL_CreateCmd
00525 =================
00526 */
00527 usercmd_t CL_CreateCmd( void ) {
00528     usercmd_t   cmd;
00529     vec3_t      oldAngles;
00530 
00531     VectorCopy( cl.viewangles, oldAngles );
00532 
00533     // keyboard angle adjustment
00534     CL_AdjustAngles ();
00535     
00536     Com_Memset( &cmd, 0, sizeof( cmd ) );
00537 
00538     CL_CmdButtons( &cmd );
00539 
00540     // get basic movement from keyboard
00541     CL_KeyMove( &cmd );
00542 
00543     // get basic movement from mouse
00544     CL_MouseMove( &cmd );
00545 
00546     // get basic movement from joystick
00547     CL_JoystickMove( &cmd );
00548 
00549     // check to make sure the angles haven't wrapped
00550     if ( cl.viewangles[PITCH] - oldAngles[PITCH] > 90 ) {
00551         cl.viewangles[PITCH] = oldAngles[PITCH] + 90;
00552     } else if ( oldAngles[PITCH] - cl.viewangles[PITCH] > 90 ) {
00553         cl.viewangles[PITCH] = oldAngles[PITCH] - 90;
00554     } 
00555 
00556     // store out the final values
00557     CL_FinishMove( &cmd );
00558 
00559     // draw debug graphs of turning for mouse testing
00560     if ( cl_debugMove->integer ) {
00561         if ( cl_debugMove->integer == 1 ) {
00562             SCR_DebugGraph( abs(cl.viewangles[YAW] - oldAngles[YAW]), 0 );
00563         }
00564         if ( cl_debugMove->integer == 2 ) {
00565             SCR_DebugGraph( abs(cl.viewangles[PITCH] - oldAngles[PITCH]), 0 );
00566         }
00567     }
00568 
00569     return cmd;
00570 }
00571 
00572 
00573 /*
00574 =================
00575 CL_CreateNewCommands
00576 
00577 Create a new usercmd_t structure for this frame
00578 =================
00579 */
00580 void CL_CreateNewCommands( void ) {
00581     usercmd_t   *cmd;
00582     int         cmdNum;
00583 
00584     // no need to create usercmds until we have a gamestate
00585     if ( cls.state < CA_PRIMED ) {
00586         return;
00587     }
00588 
00589     frame_msec = com_frameTime - old_com_frameTime;
00590 
00591     // if running less than 5fps, truncate the extra time to prevent
00592     // unexpected moves after a hitch
00593     if ( frame_msec > 200 ) {
00594         frame_msec = 200;
00595     }
00596     old_com_frameTime = com_frameTime;
00597 
00598 
00599     // generate a command for this frame
00600     cl.cmdNumber++;
00601     cmdNum = cl.cmdNumber & CMD_MASK;
00602     cl.cmds[cmdNum] = CL_CreateCmd ();
00603     cmd = &cl.cmds[cmdNum];
00604 }
00605 
00606 /*
00607 =================
00608 CL_ReadyToSendPacket
00609 
00610 Returns qfalse if we are over the maxpackets limit
00611 and should choke back the bandwidth a bit by not sending
00612 a packet this frame.  All the commands will still get
00613 delivered in the next packet, but saving a header and
00614 getting more delta compression will reduce total bandwidth.
00615 =================
00616 */
00617 qboolean CL_ReadyToSendPacket( void ) {
00618     int     oldPacketNum;
00619     int     delta;
00620 
00621     // don't send anything if playing back a demo
00622     if ( clc.demoplaying || cls.state == CA_CINEMATIC ) {
00623         return qfalse;
00624     }
00625 
00626     // If we are downloading, we send no less than 50ms between packets
00627     if ( *clc.downloadTempName &&
00628         cls.realtime - clc.lastPacketSentTime < 50 ) {
00629         return qfalse;
00630     }
00631 
00632     // if we don't have a valid gamestate yet, only send
00633     // one packet a second
00634     if ( cls.state != CA_ACTIVE && 
00635         cls.state != CA_PRIMED && 
00636         !*clc.downloadTempName &&
00637         cls.realtime - clc.lastPacketSentTime < 1000 ) {
00638         return qfalse;
00639     }
00640 
00641     // send every frame for loopbacks
00642     if ( clc.netchan.remoteAddress.type == NA_LOOPBACK ) {
00643         return qtrue;
00644     }
00645 
00646     // send every frame for LAN
00647     if ( Sys_IsLANAddress( clc.netchan.remoteAddress ) ) {
00648         return qtrue;
00649     }
00650 
00651     // check for exceeding cl_maxpackets
00652     if ( cl_maxpackets->integer < 15 ) {
00653         Cvar_Set( "cl_maxpackets", "15" );
00654     } else if ( cl_maxpackets->integer > 125 ) {
00655         Cvar_Set( "cl_maxpackets", "125" );
00656     }
00657     oldPacketNum = (clc.netchan.outgoingSequence - 1) & PACKET_MASK;
00658     delta = cls.realtime -  cl.outPackets[ oldPacketNum ].p_realtime;
00659     if ( delta < 1000 / cl_maxpackets->integer ) {
00660         // the accumulated commands will go out in the next packet
00661         return qfalse;
00662     }
00663 
00664     return qtrue;
00665 }
00666 
00667 /*
00668 ===================
00669 CL_WritePacket
00670 
00671 Create and send the command packet to the server
00672 Including both the reliable commands and the usercmds
00673 
00674 During normal gameplay, a client packet will contain something like:
00675 
00676 4   sequence number
00677 2   qport
00678 4   serverid
00679 4   acknowledged sequence number
00680 4   clc.serverCommandSequence
00681 <optional reliable commands>
00682 1   clc_move or clc_moveNoDelta
00683 1   command count
00684 <count * usercmds>
00685 
00686 ===================
00687 */
00688 void CL_WritePacket( void ) {
00689     msg_t       buf;
00690     byte        data[MAX_MSGLEN];
00691     int         i, j;
00692     usercmd_t   *cmd, *oldcmd;
00693     usercmd_t   nullcmd;
00694     int         packetNum;
00695     int         oldPacketNum;
00696     int         count, key;
00697 
00698     // don't send anything if playing back a demo
00699     if ( clc.demoplaying || cls.state == CA_CINEMATIC ) {
00700         return;
00701     }
00702 
00703     Com_Memset( &nullcmd, 0, sizeof(nullcmd) );
00704     oldcmd = &nullcmd;
00705 
00706     MSG_Init( &buf, data, sizeof(data) );
00707 
00708     MSG_Bitstream( &buf );
00709     // write the current serverId so the server
00710     // can tell if this is from the current gameState
00711     MSG_WriteLong( &buf, cl.serverId );
00712 
00713     // write the last message we received, which can
00714     // be used for delta compression, and is also used
00715     // to tell if we dropped a gamestate
00716     MSG_WriteLong( &buf, clc.serverMessageSequence );
00717 
00718     // write the last reliable message we received
00719     MSG_WriteLong( &buf, clc.serverCommandSequence );
00720 
00721     // write any unacknowledged clientCommands
00722     for ( i = clc.reliableAcknowledge + 1 ; i <= clc.reliableSequence ; i++ ) {
00723         MSG_WriteByte( &buf, clc_clientCommand );
00724         MSG_WriteLong( &buf, i );
00725         MSG_WriteString( &buf, clc.reliableCommands[ i & (MAX_RELIABLE_COMMANDS-1) ] );
00726     }
00727 
00728     // we want to send all the usercmds that were generated in the last
00729     // few packet, so even if a couple packets are dropped in a row,
00730     // all the cmds will make it to the server
00731     if ( cl_packetdup->integer < 0 ) {
00732         Cvar_Set( "cl_packetdup", "0" );
00733     } else if ( cl_packetdup->integer > 5 ) {
00734         Cvar_Set( "cl_packetdup", "5" );
00735     }
00736     oldPacketNum = (clc.netchan.outgoingSequence - 1 - cl_packetdup->integer) & PACKET_MASK;
00737     count = cl.cmdNumber - cl.outPackets[ oldPacketNum ].p_cmdNumber;
00738     if ( count > MAX_PACKET_USERCMDS ) {
00739         count = MAX_PACKET_USERCMDS;
00740         Com_Printf("MAX_PACKET_USERCMDS\n");
00741     }
00742     if ( count >= 1 ) {
00743         if ( cl_showSend->integer ) {
00744             Com_Printf( "(%i)", count );
00745         }
00746 
00747         // begin a client move command
00748         if ( cl_nodelta->integer || !cl.snap.valid || clc.demowaiting
00749             || clc.serverMessageSequence != cl.snap.messageNum ) {
00750             MSG_WriteByte (&buf, clc_moveNoDelta);
00751         } else {
00752             MSG_WriteByte (&buf, clc_move);
00753         }
00754 
00755         // write the command count
00756         MSG_WriteByte( &buf, count );
00757 
00758         // use the checksum feed in the key
00759         key = clc.checksumFeed;
00760         // also use the message acknowledge
00761         key ^= clc.serverMessageSequence;
00762         // also use the last acknowledged server command in the key
00763         key ^= Com_HashKey(clc.serverCommands[ clc.serverCommandSequence & (MAX_RELIABLE_COMMANDS-1) ], 32);
00764 
00765         // write all the commands, including the predicted command
00766         for ( i = 0 ; i < count ; i++ ) {
00767             j = (cl.cmdNumber - count + i + 1) & CMD_MASK;
00768             cmd = &cl.cmds[j];
00769             MSG_WriteDeltaUsercmdKey (&buf, key, oldcmd, cmd);
00770             oldcmd = cmd;
00771         }
00772     }
00773 
00774     //
00775     // deliver the message
00776     //
00777     packetNum = clc.netchan.outgoingSequence & PACKET_MASK;
00778     cl.outPackets[ packetNum ].p_realtime = cls.realtime;
00779     cl.outPackets[ packetNum ].p_serverTime = oldcmd->serverTime;
00780     cl.outPackets[ packetNum ].p_cmdNumber = cl.cmdNumber;
00781     clc.lastPacketSentTime = cls.realtime;
00782 
00783     if ( cl_showSend->integer ) {
00784         Com_Printf( "%i ", buf.cursize );
00785     }
00786 
00787     CL_Netchan_Transmit (&clc.netchan, &buf);   
00788 
00789     // clients never really should have messages large enough
00790     // to fragment, but in case they do, fire them all off
00791     // at once
00792     // TTimo: this causes a packet burst, which is bad karma for winsock
00793     // added a WARNING message, we'll see if there are legit situations where this happens
00794     while ( clc.netchan.unsentFragments ) {
00795         Com_DPrintf( "WARNING: #462 unsent fragments (not supposed to happen!)\n" );
00796         CL_Netchan_TransmitNextFragment( &clc.netchan );
00797     }
00798 }
00799 
00800 /*
00801 =================
00802 CL_SendCmd
00803 
00804 Called every frame to builds and sends a command packet to the server.
00805 =================
00806 */
00807 void CL_SendCmd( void ) {
00808     // don't send any message if not connected
00809     if ( cls.state < CA_CONNECTED ) {
00810         return;
00811     }
00812 
00813     // don't send commands if paused
00814     if ( com_sv_running->integer && sv_paused->integer && cl_paused->integer ) {
00815         return;
00816     }
00817 
00818     // we create commands even if a demo is playing,
00819     CL_CreateNewCommands();
00820 
00821     // don't send a packet if the last packet was sent too recently
00822     if ( !CL_ReadyToSendPacket() ) {
00823         if ( cl_showSend->integer ) {
00824             Com_Printf( ". " );
00825         }
00826         return;
00827     }
00828 
00829     CL_WritePacket();
00830 }
00831 
00832 /*
00833 ============
00834 CL_InitInput
00835 ============
00836 */
00837 void CL_InitInput( void ) {
00838     Cmd_AddCommand ("centerview",IN_CenterView);
00839 
00840     Cmd_AddCommand ("+moveup",IN_UpDown);
00841     Cmd_AddCommand ("-moveup",IN_UpUp);
00842     Cmd_AddCommand ("+movedown",IN_DownDown);
00843     Cmd_AddCommand ("-movedown",IN_DownUp);
00844     Cmd_AddCommand ("+left",IN_LeftDown);
00845     Cmd_AddCommand ("-left",IN_LeftUp);
00846     Cmd_AddCommand ("+right",IN_RightDown);
00847     Cmd_AddCommand ("-right",IN_RightUp);
00848     Cmd_AddCommand ("+forward",IN_ForwardDown);
00849     Cmd_AddCommand ("-forward",IN_ForwardUp);
00850     Cmd_AddCommand ("+back",IN_BackDown);
00851     Cmd_AddCommand ("-back",IN_BackUp);
00852     Cmd_AddCommand ("+lookup", IN_LookupDown);
00853     Cmd_AddCommand ("-lookup", IN_LookupUp);
00854     Cmd_AddCommand ("+lookdown", IN_LookdownDown);
00855     Cmd_AddCommand ("-lookdown", IN_LookdownUp);
00856     Cmd_AddCommand ("+strafe", IN_StrafeDown);
00857     Cmd_AddCommand ("-strafe", IN_StrafeUp);
00858     Cmd_AddCommand ("+moveleft", IN_MoveleftDown);
00859     Cmd_AddCommand ("-moveleft", IN_MoveleftUp);
00860     Cmd_AddCommand ("+moveright", IN_MoverightDown);
00861     Cmd_AddCommand ("-moveright", IN_MoverightUp);
00862     Cmd_AddCommand ("+speed", IN_SpeedDown);
00863     Cmd_AddCommand ("-speed", IN_SpeedUp);
00864     Cmd_AddCommand ("+attack", IN_Button0Down);
00865     Cmd_AddCommand ("-attack", IN_Button0Up);
00866     Cmd_AddCommand ("+button0", IN_Button0Down);
00867     Cmd_AddCommand ("-button0", IN_Button0Up);
00868     Cmd_AddCommand ("+button1", IN_Button1Down);
00869     Cmd_AddCommand ("-button1", IN_Button1Up);
00870     Cmd_AddCommand ("+button2", IN_Button2Down);
00871     Cmd_AddCommand ("-button2", IN_Button2Up);
00872     Cmd_AddCommand ("+button3", IN_Button3Down);
00873     Cmd_AddCommand ("-button3", IN_Button3Up);
00874     Cmd_AddCommand ("+button4", IN_Button4Down);
00875     Cmd_AddCommand ("-button4", IN_Button4Up);
00876     Cmd_AddCommand ("+button5", IN_Button5Down);
00877     Cmd_AddCommand ("-button5", IN_Button5Up);
00878     Cmd_AddCommand ("+button6", IN_Button6Down);
00879     Cmd_AddCommand ("-button6", IN_Button6Up);
00880     Cmd_AddCommand ("+button7", IN_Button7Down);
00881     Cmd_AddCommand ("-button7", IN_Button7Up);
00882     Cmd_AddCommand ("+button8", IN_Button8Down);
00883     Cmd_AddCommand ("-button8", IN_Button8Up);
00884     Cmd_AddCommand ("+button9", IN_Button9Down);
00885     Cmd_AddCommand ("-button9", IN_Button9Up);
00886     Cmd_AddCommand ("+button10", IN_Button10Down);
00887     Cmd_AddCommand ("-button10", IN_Button10Up);
00888     Cmd_AddCommand ("+button11", IN_Button11Down);
00889     Cmd_AddCommand ("-button11", IN_Button11Up);
00890     Cmd_AddCommand ("+button12", IN_Button12Down);
00891     Cmd_AddCommand ("-button12", IN_Button12Up);
00892     Cmd_AddCommand ("+button13", IN_Button13Down);
00893     Cmd_AddCommand ("-button13", IN_Button13Up);
00894     Cmd_AddCommand ("+button14", IN_Button14Down);
00895     Cmd_AddCommand ("-button14", IN_Button14Up);
00896     Cmd_AddCommand ("+mlook", IN_MLookDown);
00897     Cmd_AddCommand ("-mlook", IN_MLookUp);
00898 
00899     cl_nodelta = Cvar_Get ("cl_nodelta", "0", 0);
00900     cl_debugMove = Cvar_Get ("cl_debugMove", "0", 0);
00901 }

Generated on Thu Aug 25 12:37:26 2005 for Quake III Arena by  doxygen 1.3.9.1