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