cl_input.c (23867B)
1 /* 2 =========================================================================== 3 Copyright (C) 1999-2005 Id Software, Inc. 4 5 This file is part of Quake III Arena source code. 6 7 Quake III Arena source code is free software; you can redistribute it 8 and/or modify it under the terms of the GNU General Public License as 9 published by the Free Software Foundation; either version 2 of the License, 10 or (at your option) any later version. 11 12 Quake III Arena source code is distributed in the hope that it will be 13 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 GNU General Public License for more details. 16 17 You should have received a copy of the GNU General Public License 18 along with Foobar; if not, write to the Free Software 19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 20 =========================================================================== 21 */ 22 // cl.input.c -- builds an intended movement command to send to the server 23 24 #include "client.h" 25 26 unsigned frame_msec; 27 int old_com_frameTime; 28 29 /* 30 =============================================================================== 31 32 KEY BUTTONS 33 34 Continuous button event tracking is complicated by the fact that two different 35 input sources (say, mouse button 1 and the control key) can both press the 36 same button, but the button should only be released when both of the 37 pressing key have been released. 38 39 When a key event issues a button command (+forward, +attack, etc), it appends 40 its key number as argv(1) so it can be matched up with the release. 41 42 argv(2) will be set to the time the event happened, which allows exact 43 control even at low framerates when the down and up events may both get qued 44 at the same time. 45 46 =============================================================================== 47 */ 48 49 50 kbutton_t in_left, in_right, in_forward, in_back; 51 kbutton_t in_lookup, in_lookdown, in_moveleft, in_moveright; 52 kbutton_t in_strafe, in_speed; 53 kbutton_t in_up, in_down; 54 55 kbutton_t in_buttons[16]; 56 57 58 qboolean in_mlooking; 59 60 61 void IN_MLookDown( void ) { 62 in_mlooking = qtrue; 63 } 64 65 void IN_MLookUp( void ) { 66 in_mlooking = qfalse; 67 if ( !cl_freelook->integer ) { 68 IN_CenterView (); 69 } 70 } 71 72 void IN_KeyDown( kbutton_t *b ) { 73 int k; 74 char *c; 75 76 c = Cmd_Argv(1); 77 if ( c[0] ) { 78 k = atoi(c); 79 } else { 80 k = -1; // typed manually at the console for continuous down 81 } 82 83 if ( k == b->down[0] || k == b->down[1] ) { 84 return; // repeating key 85 } 86 87 if ( !b->down[0] ) { 88 b->down[0] = k; 89 } else if ( !b->down[1] ) { 90 b->down[1] = k; 91 } else { 92 Com_Printf ("Three keys down for a button!\n"); 93 return; 94 } 95 96 if ( b->active ) { 97 return; // still down 98 } 99 100 // save timestamp for partial frame summing 101 c = Cmd_Argv(2); 102 b->downtime = atoi(c); 103 104 b->active = qtrue; 105 b->wasPressed = qtrue; 106 } 107 108 void IN_KeyUp( kbutton_t *b ) { 109 int k; 110 char *c; 111 unsigned uptime; 112 113 c = Cmd_Argv(1); 114 if ( c[0] ) { 115 k = atoi(c); 116 } else { 117 // typed manually at the console, assume for unsticking, so clear all 118 b->down[0] = b->down[1] = 0; 119 b->active = qfalse; 120 return; 121 } 122 123 if ( b->down[0] == k ) { 124 b->down[0] = 0; 125 } else if ( b->down[1] == k ) { 126 b->down[1] = 0; 127 } else { 128 return; // key up without coresponding down (menu pass through) 129 } 130 if ( b->down[0] || b->down[1] ) { 131 return; // some other key is still holding it down 132 } 133 134 b->active = qfalse; 135 136 // save timestamp for partial frame summing 137 c = Cmd_Argv(2); 138 uptime = atoi(c); 139 if ( uptime ) { 140 b->msec += uptime - b->downtime; 141 } else { 142 b->msec += frame_msec / 2; 143 } 144 145 b->active = qfalse; 146 } 147 148 149 150 /* 151 =============== 152 CL_KeyState 153 154 Returns the fraction of the frame that the key was down 155 =============== 156 */ 157 float CL_KeyState( kbutton_t *key ) { 158 float val; 159 int msec; 160 161 msec = key->msec; 162 key->msec = 0; 163 164 if ( key->active ) { 165 // still down 166 if ( !key->downtime ) { 167 msec = com_frameTime; 168 } else { 169 msec += com_frameTime - key->downtime; 170 } 171 key->downtime = com_frameTime; 172 } 173 174 #if 0 175 if (msec) { 176 Com_Printf ("%i ", msec); 177 } 178 #endif 179 180 val = (float)msec / frame_msec; 181 if ( val < 0 ) { 182 val = 0; 183 } 184 if ( val > 1 ) { 185 val = 1; 186 } 187 188 return val; 189 } 190 191 192 193 void IN_UpDown(void) {IN_KeyDown(&in_up);} 194 void IN_UpUp(void) {IN_KeyUp(&in_up);} 195 void IN_DownDown(void) {IN_KeyDown(&in_down);} 196 void IN_DownUp(void) {IN_KeyUp(&in_down);} 197 void IN_LeftDown(void) {IN_KeyDown(&in_left);} 198 void IN_LeftUp(void) {IN_KeyUp(&in_left);} 199 void IN_RightDown(void) {IN_KeyDown(&in_right);} 200 void IN_RightUp(void) {IN_KeyUp(&in_right);} 201 void IN_ForwardDown(void) {IN_KeyDown(&in_forward);} 202 void IN_ForwardUp(void) {IN_KeyUp(&in_forward);} 203 void IN_BackDown(void) {IN_KeyDown(&in_back);} 204 void IN_BackUp(void) {IN_KeyUp(&in_back);} 205 void IN_LookupDown(void) {IN_KeyDown(&in_lookup);} 206 void IN_LookupUp(void) {IN_KeyUp(&in_lookup);} 207 void IN_LookdownDown(void) {IN_KeyDown(&in_lookdown);} 208 void IN_LookdownUp(void) {IN_KeyUp(&in_lookdown);} 209 void IN_MoveleftDown(void) {IN_KeyDown(&in_moveleft);} 210 void IN_MoveleftUp(void) {IN_KeyUp(&in_moveleft);} 211 void IN_MoverightDown(void) {IN_KeyDown(&in_moveright);} 212 void IN_MoverightUp(void) {IN_KeyUp(&in_moveright);} 213 214 void IN_SpeedDown(void) {IN_KeyDown(&in_speed);} 215 void IN_SpeedUp(void) {IN_KeyUp(&in_speed);} 216 void IN_StrafeDown(void) {IN_KeyDown(&in_strafe);} 217 void IN_StrafeUp(void) {IN_KeyUp(&in_strafe);} 218 219 void IN_Button0Down(void) {IN_KeyDown(&in_buttons[0]);} 220 void IN_Button0Up(void) {IN_KeyUp(&in_buttons[0]);} 221 void IN_Button1Down(void) {IN_KeyDown(&in_buttons[1]);} 222 void IN_Button1Up(void) {IN_KeyUp(&in_buttons[1]);} 223 void IN_Button2Down(void) {IN_KeyDown(&in_buttons[2]);} 224 void IN_Button2Up(void) {IN_KeyUp(&in_buttons[2]);} 225 void IN_Button3Down(void) {IN_KeyDown(&in_buttons[3]);} 226 void IN_Button3Up(void) {IN_KeyUp(&in_buttons[3]);} 227 void IN_Button4Down(void) {IN_KeyDown(&in_buttons[4]);} 228 void IN_Button4Up(void) {IN_KeyUp(&in_buttons[4]);} 229 void IN_Button5Down(void) {IN_KeyDown(&in_buttons[5]);} 230 void IN_Button5Up(void) {IN_KeyUp(&in_buttons[5]);} 231 void IN_Button6Down(void) {IN_KeyDown(&in_buttons[6]);} 232 void IN_Button6Up(void) {IN_KeyUp(&in_buttons[6]);} 233 void IN_Button7Down(void) {IN_KeyDown(&in_buttons[7]);} 234 void IN_Button7Up(void) {IN_KeyUp(&in_buttons[7]);} 235 void IN_Button8Down(void) {IN_KeyDown(&in_buttons[8]);} 236 void IN_Button8Up(void) {IN_KeyUp(&in_buttons[8]);} 237 void IN_Button9Down(void) {IN_KeyDown(&in_buttons[9]);} 238 void IN_Button9Up(void) {IN_KeyUp(&in_buttons[9]);} 239 void IN_Button10Down(void) {IN_KeyDown(&in_buttons[10]);} 240 void IN_Button10Up(void) {IN_KeyUp(&in_buttons[10]);} 241 void IN_Button11Down(void) {IN_KeyDown(&in_buttons[11]);} 242 void IN_Button11Up(void) {IN_KeyUp(&in_buttons[11]);} 243 void IN_Button12Down(void) {IN_KeyDown(&in_buttons[12]);} 244 void IN_Button12Up(void) {IN_KeyUp(&in_buttons[12]);} 245 void IN_Button13Down(void) {IN_KeyDown(&in_buttons[13]);} 246 void IN_Button13Up(void) {IN_KeyUp(&in_buttons[13]);} 247 void IN_Button14Down(void) {IN_KeyDown(&in_buttons[14]);} 248 void IN_Button14Up(void) {IN_KeyUp(&in_buttons[14]);} 249 void IN_Button15Down(void) {IN_KeyDown(&in_buttons[15]);} 250 void IN_Button15Up(void) {IN_KeyUp(&in_buttons[15]);} 251 252 void IN_ButtonDown (void) { 253 IN_KeyDown(&in_buttons[1]);} 254 void IN_ButtonUp (void) { 255 IN_KeyUp(&in_buttons[1]);} 256 257 void IN_CenterView (void) { 258 cl.viewangles[PITCH] = -SHORT2ANGLE(cl.snap.ps.delta_angles[PITCH]); 259 } 260 261 262 //========================================================================== 263 264 cvar_t *cl_upspeed; 265 cvar_t *cl_forwardspeed; 266 cvar_t *cl_sidespeed; 267 268 cvar_t *cl_yawspeed; 269 cvar_t *cl_pitchspeed; 270 271 cvar_t *cl_run; 272 273 cvar_t *cl_anglespeedkey; 274 275 276 /* 277 ================ 278 CL_AdjustAngles 279 280 Moves the local angle positions 281 ================ 282 */ 283 void CL_AdjustAngles( void ) { 284 float speed; 285 286 if ( in_speed.active ) { 287 speed = 0.001 * cls.frametime * cl_anglespeedkey->value; 288 } else { 289 speed = 0.001 * cls.frametime; 290 } 291 292 if ( !in_strafe.active ) { 293 cl.viewangles[YAW] -= speed*cl_yawspeed->value*CL_KeyState (&in_right); 294 cl.viewangles[YAW] += speed*cl_yawspeed->value*CL_KeyState (&in_left); 295 } 296 297 cl.viewangles[PITCH] -= speed*cl_pitchspeed->value * CL_KeyState (&in_lookup); 298 cl.viewangles[PITCH] += speed*cl_pitchspeed->value * CL_KeyState (&in_lookdown); 299 } 300 301 /* 302 ================ 303 CL_KeyMove 304 305 Sets the usercmd_t based on key states 306 ================ 307 */ 308 void CL_KeyMove( usercmd_t *cmd ) { 309 int movespeed; 310 int forward, side, up; 311 312 // 313 // adjust for speed key / running 314 // the walking flag is to keep animations consistant 315 // even during acceleration and develeration 316 // 317 if ( in_speed.active ^ cl_run->integer ) { 318 movespeed = 127; 319 cmd->buttons &= ~BUTTON_WALKING; 320 } else { 321 cmd->buttons |= BUTTON_WALKING; 322 movespeed = 64; 323 } 324 325 forward = 0; 326 side = 0; 327 up = 0; 328 if ( in_strafe.active ) { 329 side += movespeed * CL_KeyState (&in_right); 330 side -= movespeed * CL_KeyState (&in_left); 331 } 332 333 side += movespeed * CL_KeyState (&in_moveright); 334 side -= movespeed * CL_KeyState (&in_moveleft); 335 336 337 up += movespeed * CL_KeyState (&in_up); 338 up -= movespeed * CL_KeyState (&in_down); 339 340 forward += movespeed * CL_KeyState (&in_forward); 341 forward -= movespeed * CL_KeyState (&in_back); 342 343 cmd->forwardmove = ClampChar( forward ); 344 cmd->rightmove = ClampChar( side ); 345 cmd->upmove = ClampChar( up ); 346 } 347 348 /* 349 ================= 350 CL_MouseEvent 351 ================= 352 */ 353 void CL_MouseEvent( int dx, int dy, int time ) { 354 if ( cls.keyCatchers & KEYCATCH_UI ) { 355 VM_Call( uivm, UI_MOUSE_EVENT, dx, dy ); 356 } else if (cls.keyCatchers & KEYCATCH_CGAME) { 357 VM_Call (cgvm, CG_MOUSE_EVENT, dx, dy); 358 } else { 359 cl.mouseDx[cl.mouseIndex] += dx; 360 cl.mouseDy[cl.mouseIndex] += dy; 361 } 362 } 363 364 /* 365 ================= 366 CL_JoystickEvent 367 368 Joystick values stay set until changed 369 ================= 370 */ 371 void CL_JoystickEvent( int axis, int value, int time ) { 372 if ( axis < 0 || axis >= MAX_JOYSTICK_AXIS ) { 373 Com_Error( ERR_DROP, "CL_JoystickEvent: bad axis %i", axis ); 374 } 375 cl.joystickAxis[axis] = value; 376 } 377 378 /* 379 ================= 380 CL_JoystickMove 381 ================= 382 */ 383 void CL_JoystickMove( usercmd_t *cmd ) { 384 int movespeed; 385 float anglespeed; 386 387 if ( in_speed.active ^ cl_run->integer ) { 388 movespeed = 2; 389 } else { 390 movespeed = 1; 391 cmd->buttons |= BUTTON_WALKING; 392 } 393 394 if ( in_speed.active ) { 395 anglespeed = 0.001 * cls.frametime * cl_anglespeedkey->value; 396 } else { 397 anglespeed = 0.001 * cls.frametime; 398 } 399 400 if ( !in_strafe.active ) { 401 cl.viewangles[YAW] += anglespeed * cl_yawspeed->value * cl.joystickAxis[AXIS_SIDE]; 402 } else { 403 cmd->rightmove = ClampChar( cmd->rightmove + cl.joystickAxis[AXIS_SIDE] ); 404 } 405 406 if ( in_mlooking ) { 407 cl.viewangles[PITCH] += anglespeed * cl_pitchspeed->value * cl.joystickAxis[AXIS_FORWARD]; 408 } else { 409 cmd->forwardmove = ClampChar( cmd->forwardmove + cl.joystickAxis[AXIS_FORWARD] ); 410 } 411 412 cmd->upmove = ClampChar( cmd->upmove + cl.joystickAxis[AXIS_UP] ); 413 } 414 415 /* 416 ================= 417 CL_MouseMove 418 ================= 419 */ 420 void CL_MouseMove( usercmd_t *cmd ) { 421 float mx, my; 422 float accelSensitivity; 423 float rate; 424 425 // allow mouse smoothing 426 if ( m_filter->integer ) { 427 mx = ( cl.mouseDx[0] + cl.mouseDx[1] ) * 0.5; 428 my = ( cl.mouseDy[0] + cl.mouseDy[1] ) * 0.5; 429 } else { 430 mx = cl.mouseDx[cl.mouseIndex]; 431 my = cl.mouseDy[cl.mouseIndex]; 432 } 433 cl.mouseIndex ^= 1; 434 cl.mouseDx[cl.mouseIndex] = 0; 435 cl.mouseDy[cl.mouseIndex] = 0; 436 437 rate = sqrt( mx * mx + my * my ) / (float)frame_msec; 438 accelSensitivity = cl_sensitivity->value + rate * cl_mouseAccel->value; 439 440 // scale by FOV 441 accelSensitivity *= cl.cgameSensitivity; 442 443 if ( rate && cl_showMouseRate->integer ) { 444 Com_Printf( "%f : %f\n", rate, accelSensitivity ); 445 } 446 447 mx *= accelSensitivity; 448 my *= accelSensitivity; 449 450 if (!mx && !my) { 451 return; 452 } 453 454 // add mouse X/Y movement to cmd 455 if ( in_strafe.active ) { 456 cmd->rightmove = ClampChar( cmd->rightmove + m_side->value * mx ); 457 } else { 458 cl.viewangles[YAW] -= m_yaw->value * mx; 459 } 460 461 if ( (in_mlooking || cl_freelook->integer) && !in_strafe.active ) { 462 cl.viewangles[PITCH] += m_pitch->value * my; 463 } else { 464 cmd->forwardmove = ClampChar( cmd->forwardmove - m_forward->value * my ); 465 } 466 } 467 468 469 /* 470 ============== 471 CL_CmdButtons 472 ============== 473 */ 474 void CL_CmdButtons( usercmd_t *cmd ) { 475 int i; 476 477 // 478 // figure button bits 479 // send a button bit even if the key was pressed and released in 480 // less than a frame 481 // 482 for (i = 0 ; i < 15 ; i++) { 483 if ( in_buttons[i].active || in_buttons[i].wasPressed ) { 484 cmd->buttons |= 1 << i; 485 } 486 in_buttons[i].wasPressed = qfalse; 487 } 488 489 if ( cls.keyCatchers ) { 490 cmd->buttons |= BUTTON_TALK; 491 } 492 493 // allow the game to know if any key at all is 494 // currently pressed, even if it isn't bound to anything 495 if ( anykeydown && !cls.keyCatchers ) { 496 cmd->buttons |= BUTTON_ANY; 497 } 498 } 499 500 501 /* 502 ============== 503 CL_FinishMove 504 ============== 505 */ 506 void CL_FinishMove( usercmd_t *cmd ) { 507 int i; 508 509 // copy the state that the cgame is currently sending 510 cmd->weapon = cl.cgameUserCmdValue; 511 512 // send the current server time so the amount of movement 513 // can be determined without allowing cheating 514 cmd->serverTime = cl.serverTime; 515 516 for (i=0 ; i<3 ; i++) { 517 cmd->angles[i] = ANGLE2SHORT(cl.viewangles[i]); 518 } 519 } 520 521 522 /* 523 ================= 524 CL_CreateCmd 525 ================= 526 */ 527 usercmd_t CL_CreateCmd( void ) { 528 usercmd_t cmd; 529 vec3_t oldAngles; 530 531 VectorCopy( cl.viewangles, oldAngles ); 532 533 // keyboard angle adjustment 534 CL_AdjustAngles (); 535 536 Com_Memset( &cmd, 0, sizeof( cmd ) ); 537 538 CL_CmdButtons( &cmd ); 539 540 // get basic movement from keyboard 541 CL_KeyMove( &cmd ); 542 543 // get basic movement from mouse 544 CL_MouseMove( &cmd ); 545 546 // get basic movement from joystick 547 CL_JoystickMove( &cmd ); 548 549 // check to make sure the angles haven't wrapped 550 if ( cl.viewangles[PITCH] - oldAngles[PITCH] > 90 ) { 551 cl.viewangles[PITCH] = oldAngles[PITCH] + 90; 552 } else if ( oldAngles[PITCH] - cl.viewangles[PITCH] > 90 ) { 553 cl.viewangles[PITCH] = oldAngles[PITCH] - 90; 554 } 555 556 // store out the final values 557 CL_FinishMove( &cmd ); 558 559 // draw debug graphs of turning for mouse testing 560 if ( cl_debugMove->integer ) { 561 if ( cl_debugMove->integer == 1 ) { 562 SCR_DebugGraph( abs(cl.viewangles[YAW] - oldAngles[YAW]), 0 ); 563 } 564 if ( cl_debugMove->integer == 2 ) { 565 SCR_DebugGraph( abs(cl.viewangles[PITCH] - oldAngles[PITCH]), 0 ); 566 } 567 } 568 569 return cmd; 570 } 571 572 573 /* 574 ================= 575 CL_CreateNewCommands 576 577 Create a new usercmd_t structure for this frame 578 ================= 579 */ 580 void CL_CreateNewCommands( void ) { 581 usercmd_t *cmd; 582 int cmdNum; 583 584 // no need to create usercmds until we have a gamestate 585 if ( cls.state < CA_PRIMED ) { 586 return; 587 } 588 589 frame_msec = com_frameTime - old_com_frameTime; 590 591 // if running less than 5fps, truncate the extra time to prevent 592 // unexpected moves after a hitch 593 if ( frame_msec > 200 ) { 594 frame_msec = 200; 595 } 596 old_com_frameTime = com_frameTime; 597 598 599 // generate a command for this frame 600 cl.cmdNumber++; 601 cmdNum = cl.cmdNumber & CMD_MASK; 602 cl.cmds[cmdNum] = CL_CreateCmd (); 603 cmd = &cl.cmds[cmdNum]; 604 } 605 606 /* 607 ================= 608 CL_ReadyToSendPacket 609 610 Returns qfalse if we are over the maxpackets limit 611 and should choke back the bandwidth a bit by not sending 612 a packet this frame. All the commands will still get 613 delivered in the next packet, but saving a header and 614 getting more delta compression will reduce total bandwidth. 615 ================= 616 */ 617 qboolean CL_ReadyToSendPacket( void ) { 618 int oldPacketNum; 619 int delta; 620 621 // don't send anything if playing back a demo 622 if ( clc.demoplaying || cls.state == CA_CINEMATIC ) { 623 return qfalse; 624 } 625 626 // If we are downloading, we send no less than 50ms between packets 627 if ( *clc.downloadTempName && 628 cls.realtime - clc.lastPacketSentTime < 50 ) { 629 return qfalse; 630 } 631 632 // if we don't have a valid gamestate yet, only send 633 // one packet a second 634 if ( cls.state != CA_ACTIVE && 635 cls.state != CA_PRIMED && 636 !*clc.downloadTempName && 637 cls.realtime - clc.lastPacketSentTime < 1000 ) { 638 return qfalse; 639 } 640 641 // send every frame for loopbacks 642 if ( clc.netchan.remoteAddress.type == NA_LOOPBACK ) { 643 return qtrue; 644 } 645 646 // send every frame for LAN 647 if ( Sys_IsLANAddress( clc.netchan.remoteAddress ) ) { 648 return qtrue; 649 } 650 651 // check for exceeding cl_maxpackets 652 if ( cl_maxpackets->integer < 15 ) { 653 Cvar_Set( "cl_maxpackets", "15" ); 654 } else if ( cl_maxpackets->integer > 125 ) { 655 Cvar_Set( "cl_maxpackets", "125" ); 656 } 657 oldPacketNum = (clc.netchan.outgoingSequence - 1) & PACKET_MASK; 658 delta = cls.realtime - cl.outPackets[ oldPacketNum ].p_realtime; 659 if ( delta < 1000 / cl_maxpackets->integer ) { 660 // the accumulated commands will go out in the next packet 661 return qfalse; 662 } 663 664 return qtrue; 665 } 666 667 /* 668 =================== 669 CL_WritePacket 670 671 Create and send the command packet to the server 672 Including both the reliable commands and the usercmds 673 674 During normal gameplay, a client packet will contain something like: 675 676 4 sequence number 677 2 qport 678 4 serverid 679 4 acknowledged sequence number 680 4 clc.serverCommandSequence 681 <optional reliable commands> 682 1 clc_move or clc_moveNoDelta 683 1 command count 684 <count * usercmds> 685 686 =================== 687 */ 688 void CL_WritePacket( void ) { 689 msg_t buf; 690 byte data[MAX_MSGLEN]; 691 int i, j; 692 usercmd_t *cmd, *oldcmd; 693 usercmd_t nullcmd; 694 int packetNum; 695 int oldPacketNum; 696 int count, key; 697 698 // don't send anything if playing back a demo 699 if ( clc.demoplaying || cls.state == CA_CINEMATIC ) { 700 return; 701 } 702 703 Com_Memset( &nullcmd, 0, sizeof(nullcmd) ); 704 oldcmd = &nullcmd; 705 706 MSG_Init( &buf, data, sizeof(data) ); 707 708 MSG_Bitstream( &buf ); 709 // write the current serverId so the server 710 // can tell if this is from the current gameState 711 MSG_WriteLong( &buf, cl.serverId ); 712 713 // write the last message we received, which can 714 // be used for delta compression, and is also used 715 // to tell if we dropped a gamestate 716 MSG_WriteLong( &buf, clc.serverMessageSequence ); 717 718 // write the last reliable message we received 719 MSG_WriteLong( &buf, clc.serverCommandSequence ); 720 721 // write any unacknowledged clientCommands 722 for ( i = clc.reliableAcknowledge + 1 ; i <= clc.reliableSequence ; i++ ) { 723 MSG_WriteByte( &buf, clc_clientCommand ); 724 MSG_WriteLong( &buf, i ); 725 MSG_WriteString( &buf, clc.reliableCommands[ i & (MAX_RELIABLE_COMMANDS-1) ] ); 726 } 727 728 // we want to send all the usercmds that were generated in the last 729 // few packet, so even if a couple packets are dropped in a row, 730 // all the cmds will make it to the server 731 if ( cl_packetdup->integer < 0 ) { 732 Cvar_Set( "cl_packetdup", "0" ); 733 } else if ( cl_packetdup->integer > 5 ) { 734 Cvar_Set( "cl_packetdup", "5" ); 735 } 736 oldPacketNum = (clc.netchan.outgoingSequence - 1 - cl_packetdup->integer) & PACKET_MASK; 737 count = cl.cmdNumber - cl.outPackets[ oldPacketNum ].p_cmdNumber; 738 if ( count > MAX_PACKET_USERCMDS ) { 739 count = MAX_PACKET_USERCMDS; 740 Com_Printf("MAX_PACKET_USERCMDS\n"); 741 } 742 if ( count >= 1 ) { 743 if ( cl_showSend->integer ) { 744 Com_Printf( "(%i)", count ); 745 } 746 747 // begin a client move command 748 if ( cl_nodelta->integer || !cl.snap.valid || clc.demowaiting 749 || clc.serverMessageSequence != cl.snap.messageNum ) { 750 MSG_WriteByte (&buf, clc_moveNoDelta); 751 } else { 752 MSG_WriteByte (&buf, clc_move); 753 } 754 755 // write the command count 756 MSG_WriteByte( &buf, count ); 757 758 // use the checksum feed in the key 759 key = clc.checksumFeed; 760 // also use the message acknowledge 761 key ^= clc.serverMessageSequence; 762 // also use the last acknowledged server command in the key 763 key ^= Com_HashKey(clc.serverCommands[ clc.serverCommandSequence & (MAX_RELIABLE_COMMANDS-1) ], 32); 764 765 // write all the commands, including the predicted command 766 for ( i = 0 ; i < count ; i++ ) { 767 j = (cl.cmdNumber - count + i + 1) & CMD_MASK; 768 cmd = &cl.cmds[j]; 769 MSG_WriteDeltaUsercmdKey (&buf, key, oldcmd, cmd); 770 oldcmd = cmd; 771 } 772 } 773 774 // 775 // deliver the message 776 // 777 packetNum = clc.netchan.outgoingSequence & PACKET_MASK; 778 cl.outPackets[ packetNum ].p_realtime = cls.realtime; 779 cl.outPackets[ packetNum ].p_serverTime = oldcmd->serverTime; 780 cl.outPackets[ packetNum ].p_cmdNumber = cl.cmdNumber; 781 clc.lastPacketSentTime = cls.realtime; 782 783 if ( cl_showSend->integer ) { 784 Com_Printf( "%i ", buf.cursize ); 785 } 786 787 CL_Netchan_Transmit (&clc.netchan, &buf); 788 789 // clients never really should have messages large enough 790 // to fragment, but in case they do, fire them all off 791 // at once 792 // TTimo: this causes a packet burst, which is bad karma for winsock 793 // added a WARNING message, we'll see if there are legit situations where this happens 794 while ( clc.netchan.unsentFragments ) { 795 Com_DPrintf( "WARNING: #462 unsent fragments (not supposed to happen!)\n" ); 796 CL_Netchan_TransmitNextFragment( &clc.netchan ); 797 } 798 } 799 800 /* 801 ================= 802 CL_SendCmd 803 804 Called every frame to builds and sends a command packet to the server. 805 ================= 806 */ 807 void CL_SendCmd( void ) { 808 // don't send any message if not connected 809 if ( cls.state < CA_CONNECTED ) { 810 return; 811 } 812 813 // don't send commands if paused 814 if ( com_sv_running->integer && sv_paused->integer && cl_paused->integer ) { 815 return; 816 } 817 818 // we create commands even if a demo is playing, 819 CL_CreateNewCommands(); 820 821 // don't send a packet if the last packet was sent too recently 822 if ( !CL_ReadyToSendPacket() ) { 823 if ( cl_showSend->integer ) { 824 Com_Printf( ". " ); 825 } 826 return; 827 } 828 829 CL_WritePacket(); 830 } 831 832 /* 833 ============ 834 CL_InitInput 835 ============ 836 */ 837 void CL_InitInput( void ) { 838 Cmd_AddCommand ("centerview",IN_CenterView); 839 840 Cmd_AddCommand ("+moveup",IN_UpDown); 841 Cmd_AddCommand ("-moveup",IN_UpUp); 842 Cmd_AddCommand ("+movedown",IN_DownDown); 843 Cmd_AddCommand ("-movedown",IN_DownUp); 844 Cmd_AddCommand ("+left",IN_LeftDown); 845 Cmd_AddCommand ("-left",IN_LeftUp); 846 Cmd_AddCommand ("+right",IN_RightDown); 847 Cmd_AddCommand ("-right",IN_RightUp); 848 Cmd_AddCommand ("+forward",IN_ForwardDown); 849 Cmd_AddCommand ("-forward",IN_ForwardUp); 850 Cmd_AddCommand ("+back",IN_BackDown); 851 Cmd_AddCommand ("-back",IN_BackUp); 852 Cmd_AddCommand ("+lookup", IN_LookupDown); 853 Cmd_AddCommand ("-lookup", IN_LookupUp); 854 Cmd_AddCommand ("+lookdown", IN_LookdownDown); 855 Cmd_AddCommand ("-lookdown", IN_LookdownUp); 856 Cmd_AddCommand ("+strafe", IN_StrafeDown); 857 Cmd_AddCommand ("-strafe", IN_StrafeUp); 858 Cmd_AddCommand ("+moveleft", IN_MoveleftDown); 859 Cmd_AddCommand ("-moveleft", IN_MoveleftUp); 860 Cmd_AddCommand ("+moveright", IN_MoverightDown); 861 Cmd_AddCommand ("-moveright", IN_MoverightUp); 862 Cmd_AddCommand ("+speed", IN_SpeedDown); 863 Cmd_AddCommand ("-speed", IN_SpeedUp); 864 Cmd_AddCommand ("+attack", IN_Button0Down); 865 Cmd_AddCommand ("-attack", IN_Button0Up); 866 Cmd_AddCommand ("+button0", IN_Button0Down); 867 Cmd_AddCommand ("-button0", IN_Button0Up); 868 Cmd_AddCommand ("+button1", IN_Button1Down); 869 Cmd_AddCommand ("-button1", IN_Button1Up); 870 Cmd_AddCommand ("+button2", IN_Button2Down); 871 Cmd_AddCommand ("-button2", IN_Button2Up); 872 Cmd_AddCommand ("+button3", IN_Button3Down); 873 Cmd_AddCommand ("-button3", IN_Button3Up); 874 Cmd_AddCommand ("+button4", IN_Button4Down); 875 Cmd_AddCommand ("-button4", IN_Button4Up); 876 Cmd_AddCommand ("+button5", IN_Button5Down); 877 Cmd_AddCommand ("-button5", IN_Button5Up); 878 Cmd_AddCommand ("+button6", IN_Button6Down); 879 Cmd_AddCommand ("-button6", IN_Button6Up); 880 Cmd_AddCommand ("+button7", IN_Button7Down); 881 Cmd_AddCommand ("-button7", IN_Button7Up); 882 Cmd_AddCommand ("+button8", IN_Button8Down); 883 Cmd_AddCommand ("-button8", IN_Button8Up); 884 Cmd_AddCommand ("+button9", IN_Button9Down); 885 Cmd_AddCommand ("-button9", IN_Button9Up); 886 Cmd_AddCommand ("+button10", IN_Button10Down); 887 Cmd_AddCommand ("-button10", IN_Button10Up); 888 Cmd_AddCommand ("+button11", IN_Button11Down); 889 Cmd_AddCommand ("-button11", IN_Button11Up); 890 Cmd_AddCommand ("+button12", IN_Button12Down); 891 Cmd_AddCommand ("-button12", IN_Button12Up); 892 Cmd_AddCommand ("+button13", IN_Button13Down); 893 Cmd_AddCommand ("-button13", IN_Button13Up); 894 Cmd_AddCommand ("+button14", IN_Button14Down); 895 Cmd_AddCommand ("-button14", IN_Button14Up); 896 Cmd_AddCommand ("+mlook", IN_MLookDown); 897 Cmd_AddCommand ("-mlook", IN_MLookUp); 898 899 cl_nodelta = Cvar_Get ("cl_nodelta", "0", 0); 900 cl_debugMove = Cvar_Get ("cl_debugMove", "0", 0); 901 }