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 kbutton_t in_buttons[16];
56
57
58 qboolean in_mlooking;
59
60
IN_MLookDown(void)61 void IN_MLookDown( void ) {
62 in_mlooking = qtrue;
63 }
64
IN_MLookUp(void)65 void IN_MLookUp( void ) {
66 in_mlooking = qfalse;
67 if ( !cl_freelook->integer ) {
68 IN_CenterView ();
69 }
70 }
71
IN_KeyDown(kbutton_t * b)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
IN_KeyUp(kbutton_t * b)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 */
CL_KeyState(kbutton_t * key)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
IN_UpDown(void)193 void IN_UpDown(void) {IN_KeyDown(&in_up);}
IN_UpUp(void)194 void IN_UpUp(void) {IN_KeyUp(&in_up);}
IN_DownDown(void)195 void IN_DownDown(void) {IN_KeyDown(&in_down);}
IN_DownUp(void)196 void IN_DownUp(void) {IN_KeyUp(&in_down);}
IN_LeftDown(void)197 void IN_LeftDown(void) {IN_KeyDown(&in_left);}
IN_LeftUp(void)198 void IN_LeftUp(void) {IN_KeyUp(&in_left);}
IN_RightDown(void)199 void IN_RightDown(void) {IN_KeyDown(&in_right);}
IN_RightUp(void)200 void IN_RightUp(void) {IN_KeyUp(&in_right);}
IN_ForwardDown(void)201 void IN_ForwardDown(void) {IN_KeyDown(&in_forward);}
IN_ForwardUp(void)202 void IN_ForwardUp(void) {IN_KeyUp(&in_forward);}
IN_BackDown(void)203 void IN_BackDown(void) {IN_KeyDown(&in_back);}
IN_BackUp(void)204 void IN_BackUp(void) {IN_KeyUp(&in_back);}
IN_LookupDown(void)205 void IN_LookupDown(void) {IN_KeyDown(&in_lookup);}
IN_LookupUp(void)206 void IN_LookupUp(void) {IN_KeyUp(&in_lookup);}
IN_LookdownDown(void)207 void IN_LookdownDown(void) {IN_KeyDown(&in_lookdown);}
IN_LookdownUp(void)208 void IN_LookdownUp(void) {IN_KeyUp(&in_lookdown);}
IN_MoveleftDown(void)209 void IN_MoveleftDown(void) {IN_KeyDown(&in_moveleft);}
IN_MoveleftUp(void)210 void IN_MoveleftUp(void) {IN_KeyUp(&in_moveleft);}
IN_MoverightDown(void)211 void IN_MoverightDown(void) {IN_KeyDown(&in_moveright);}
IN_MoverightUp(void)212 void IN_MoverightUp(void) {IN_KeyUp(&in_moveright);}
213
IN_SpeedDown(void)214 void IN_SpeedDown(void) {IN_KeyDown(&in_speed);}
IN_SpeedUp(void)215 void IN_SpeedUp(void) {IN_KeyUp(&in_speed);}
IN_StrafeDown(void)216 void IN_StrafeDown(void) {IN_KeyDown(&in_strafe);}
IN_StrafeUp(void)217 void IN_StrafeUp(void) {IN_KeyUp(&in_strafe);}
218
IN_Button0Down(void)219 void IN_Button0Down(void) {IN_KeyDown(&in_buttons[0]);}
IN_Button0Up(void)220 void IN_Button0Up(void) {IN_KeyUp(&in_buttons[0]);}
IN_Button1Down(void)221 void IN_Button1Down(void) {IN_KeyDown(&in_buttons[1]);}
IN_Button1Up(void)222 void IN_Button1Up(void) {IN_KeyUp(&in_buttons[1]);}
IN_Button2Down(void)223 void IN_Button2Down(void) {IN_KeyDown(&in_buttons[2]);}
IN_Button2Up(void)224 void IN_Button2Up(void) {IN_KeyUp(&in_buttons[2]);}
IN_Button3Down(void)225 void IN_Button3Down(void) {IN_KeyDown(&in_buttons[3]);}
IN_Button3Up(void)226 void IN_Button3Up(void) {IN_KeyUp(&in_buttons[3]);}
IN_Button4Down(void)227 void IN_Button4Down(void) {IN_KeyDown(&in_buttons[4]);}
IN_Button4Up(void)228 void IN_Button4Up(void) {IN_KeyUp(&in_buttons[4]);}
IN_Button5Down(void)229 void IN_Button5Down(void) {IN_KeyDown(&in_buttons[5]);}
IN_Button5Up(void)230 void IN_Button5Up(void) {IN_KeyUp(&in_buttons[5]);}
IN_Button6Down(void)231 void IN_Button6Down(void) {IN_KeyDown(&in_buttons[6]);}
IN_Button6Up(void)232 void IN_Button6Up(void) {IN_KeyUp(&in_buttons[6]);}
IN_Button7Down(void)233 void IN_Button7Down(void) {IN_KeyDown(&in_buttons[7]);}
IN_Button7Up(void)234 void IN_Button7Up(void) {IN_KeyUp(&in_buttons[7]);}
IN_Button8Down(void)235 void IN_Button8Down(void) {IN_KeyDown(&in_buttons[8]);}
IN_Button8Up(void)236 void IN_Button8Up(void) {IN_KeyUp(&in_buttons[8]);}
IN_Button9Down(void)237 void IN_Button9Down(void) {IN_KeyDown(&in_buttons[9]);}
IN_Button9Up(void)238 void IN_Button9Up(void) {IN_KeyUp(&in_buttons[9]);}
IN_Button10Down(void)239 void IN_Button10Down(void) {IN_KeyDown(&in_buttons[10]);}
IN_Button10Up(void)240 void IN_Button10Up(void) {IN_KeyUp(&in_buttons[10]);}
IN_Button11Down(void)241 void IN_Button11Down(void) {IN_KeyDown(&in_buttons[11]);}
IN_Button11Up(void)242 void IN_Button11Up(void) {IN_KeyUp(&in_buttons[11]);}
IN_Button12Down(void)243 void IN_Button12Down(void) {IN_KeyDown(&in_buttons[12]);}
IN_Button12Up(void)244 void IN_Button12Up(void) {IN_KeyUp(&in_buttons[12]);}
IN_Button13Down(void)245 void IN_Button13Down(void) {IN_KeyDown(&in_buttons[13]);}
IN_Button13Up(void)246 void IN_Button13Up(void) {IN_KeyUp(&in_buttons[13]);}
IN_Button14Down(void)247 void IN_Button14Down(void) {IN_KeyDown(&in_buttons[14]);}
IN_Button14Up(void)248 void IN_Button14Up(void) {IN_KeyUp(&in_buttons[14]);}
IN_Button15Down(void)249 void IN_Button15Down(void) {IN_KeyDown(&in_buttons[15]);}
IN_Button15Up(void)250 void IN_Button15Up(void) {IN_KeyUp(&in_buttons[15]);}
251
IN_ButtonDown(void)252 void IN_ButtonDown (void) {
253 IN_KeyDown(&in_buttons[1]);}
IN_ButtonUp(void)254 void IN_ButtonUp (void) {
255 IN_KeyUp(&in_buttons[1]);}
256
IN_CenterView(void)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 */
CL_AdjustAngles(void)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 */
CL_KeyMove(usercmd_t * cmd)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 */
CL_MouseEvent(int dx,int dy,int time)353 void CL_MouseEvent( int dx, int dy, int time ) {
354 if ( Key_GetCatcher( ) & KEYCATCH_UI ) {
355 VM_Call( uivm, UI_MOUSE_EVENT, dx, dy );
356 } else if (Key_GetCatcher( ) & 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 */
CL_JoystickEvent(int axis,int value,int time)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 */
CL_JoystickMove(usercmd_t * cmd)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 */
CL_MouseMove(usercmd_t * cmd)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 *
439 cl_platformSensitivity->value ) + rate * cl_mouseAccel->value;
440
441 // scale by FOV
442 accelSensitivity *= cl.cgameSensitivity;
443
444 if ( rate && cl_showMouseRate->integer ) {
445 Com_Printf( "%f : %f\n", rate, accelSensitivity );
446 }
447
448 mx *= accelSensitivity;
449 my *= accelSensitivity;
450
451 if (!mx && !my) {
452 return;
453 }
454
455 // add mouse X/Y movement to cmd
456 if ( in_strafe.active ) {
457 cmd->rightmove = ClampChar( cmd->rightmove + m_side->value * mx );
458 } else {
459 cl.viewangles[YAW] -= m_yaw->value * mx;
460 }
461
462 if ( (in_mlooking || cl_freelook->integer) && !in_strafe.active ) {
463 cl.viewangles[PITCH] += m_pitch->value * my;
464 } else {
465 cmd->forwardmove = ClampChar( cmd->forwardmove - m_forward->value * my );
466 }
467 }
468
469
470 /*
471 ==============
472 CL_CmdButtons
473 ==============
474 */
CL_CmdButtons(usercmd_t * cmd)475 void CL_CmdButtons( usercmd_t *cmd ) {
476 int i;
477
478 //
479 // figure button bits
480 // send a button bit even if the key was pressed and released in
481 // less than a frame
482 //
483 for (i = 0 ; i < 15 ; i++) {
484 if ( in_buttons[i].active || in_buttons[i].wasPressed ) {
485 cmd->buttons |= 1 << i;
486 }
487 in_buttons[i].wasPressed = qfalse;
488 }
489
490 if ( Key_GetCatcher( ) ) {
491 cmd->buttons |= BUTTON_TALK;
492 }
493
494 // allow the game to know if any key at all is
495 // currently pressed, even if it isn't bound to anything
496 if ( anykeydown && Key_GetCatcher( ) == 0 ) {
497 cmd->buttons |= BUTTON_ANY;
498 }
499 }
500
501
502 /*
503 ==============
504 CL_FinishMove
505 ==============
506 */
CL_FinishMove(usercmd_t * cmd)507 void CL_FinishMove( usercmd_t *cmd ) {
508 int i;
509
510 // copy the state that the cgame is currently sending
511 cmd->weapon = cl.cgameUserCmdValue;
512
513 // send the current server time so the amount of movement
514 // can be determined without allowing cheating
515 cmd->serverTime = cl.serverTime;
516
517 for (i=0 ; i<3 ; i++) {
518 cmd->angles[i] = ANGLE2SHORT(cl.viewangles[i]);
519 }
520 }
521
522
523 /*
524 =================
525 CL_CreateCmd
526 =================
527 */
CL_CreateCmd(void)528 usercmd_t CL_CreateCmd( void ) {
529 usercmd_t cmd;
530 vec3_t oldAngles;
531
532 VectorCopy( cl.viewangles, oldAngles );
533
534 // keyboard angle adjustment
535 CL_AdjustAngles ();
536
537 Com_Memset( &cmd, 0, sizeof( cmd ) );
538
539 CL_CmdButtons( &cmd );
540
541 // get basic movement from keyboard
542 CL_KeyMove( &cmd );
543
544 // get basic movement from mouse
545 CL_MouseMove( &cmd );
546
547 // get basic movement from joystick
548 CL_JoystickMove( &cmd );
549
550 // check to make sure the angles haven't wrapped
551 if ( cl.viewangles[PITCH] - oldAngles[PITCH] > 90 ) {
552 cl.viewangles[PITCH] = oldAngles[PITCH] + 90;
553 } else if ( oldAngles[PITCH] - cl.viewangles[PITCH] > 90 ) {
554 cl.viewangles[PITCH] = oldAngles[PITCH] - 90;
555 }
556
557 // store out the final values
558 CL_FinishMove( &cmd );
559
560 // draw debug graphs of turning for mouse testing
561 if ( cl_debugMove->integer ) {
562 if ( cl_debugMove->integer == 1 ) {
563 SCR_DebugGraph( abs(cl.viewangles[YAW] - oldAngles[YAW]), 0 );
564 }
565 if ( cl_debugMove->integer == 2 ) {
566 SCR_DebugGraph( abs(cl.viewangles[PITCH] - oldAngles[PITCH]), 0 );
567 }
568 }
569
570 return cmd;
571 }
572
573
574 /*
575 =================
576 CL_CreateNewCommands
577
578 Create a new usercmd_t structure for this frame
579 =================
580 */
CL_CreateNewCommands(void)581 void CL_CreateNewCommands( void ) {
582 usercmd_t *cmd;
583 int cmdNum;
584
585 // no need to create usercmds until we have a gamestate
586 if ( cls.state < CA_PRIMED ) {
587 return;
588 }
589
590 frame_msec = com_frameTime - old_com_frameTime;
591
592 // if running less than 5fps, truncate the extra time to prevent
593 // unexpected moves after a hitch
594 if ( frame_msec > 200 ) {
595 frame_msec = 200;
596 }
597 old_com_frameTime = com_frameTime;
598
599
600 // generate a command for this frame
601 cl.cmdNumber++;
602 cmdNum = cl.cmdNumber & CMD_MASK;
603 cl.cmds[cmdNum] = CL_CreateCmd ();
604 cmd = &cl.cmds[cmdNum];
605 }
606
607 /*
608 =================
609 CL_ReadyToSendPacket
610
611 Returns qfalse if we are over the maxpackets limit
612 and should choke back the bandwidth a bit by not sending
613 a packet this frame. All the commands will still get
614 delivered in the next packet, but saving a header and
615 getting more delta compression will reduce total bandwidth.
616 =================
617 */
CL_ReadyToSendPacket(void)618 qboolean CL_ReadyToSendPacket( void ) {
619 int oldPacketNum;
620 int delta;
621
622 // don't send anything if playing back a demo
623 if ( clc.demoplaying || cls.state == CA_CINEMATIC ) {
624 return qfalse;
625 }
626
627 // If we are downloading, we send no less than 50ms between packets
628 if ( *clc.downloadTempName &&
629 cls.realtime - clc.lastPacketSentTime < 50 ) {
630 return qfalse;
631 }
632
633 // if we don't have a valid gamestate yet, only send
634 // one packet a second
635 if ( cls.state != CA_ACTIVE &&
636 cls.state != CA_PRIMED &&
637 !*clc.downloadTempName &&
638 cls.realtime - clc.lastPacketSentTime < 1000 ) {
639 return qfalse;
640 }
641
642 // send every frame for loopbacks
643 if ( clc.netchan.remoteAddress.type == NA_LOOPBACK ) {
644 return qtrue;
645 }
646
647 // send every frame for LAN
648 if ( cl_lanForcePackets->integer && Sys_IsLANAddress( clc.netchan.remoteAddress ) ) {
649 return qtrue;
650 }
651
652 // check for exceeding cl_maxpackets
653 if ( cl_maxpackets->integer < 15 ) {
654 Cvar_Set( "cl_maxpackets", "15" );
655 } else if ( cl_maxpackets->integer > 125 ) {
656 Cvar_Set( "cl_maxpackets", "125" );
657 }
658 oldPacketNum = (clc.netchan.outgoingSequence - 1) & PACKET_MASK;
659 delta = cls.realtime - cl.outPackets[ oldPacketNum ].p_realtime;
660 if ( delta < 1000 / cl_maxpackets->integer ) {
661 // the accumulated commands will go out in the next packet
662 return qfalse;
663 }
664
665 return qtrue;
666 }
667
668 /*
669 ===================
670 CL_WritePacket
671
672 Create and send the command packet to the server
673 Including both the reliable commands and the usercmds
674
675 During normal gameplay, a client packet will contain something like:
676
677 4 sequence number
678 2 qport
679 4 serverid
680 4 acknowledged sequence number
681 4 clc.serverCommandSequence
682 <optional reliable commands>
683 1 clc_move or clc_moveNoDelta
684 1 command count
685 <count * usercmds>
686
687 ===================
688 */
CL_WritePacket(void)689 void CL_WritePacket( void ) {
690 msg_t buf;
691 byte data[MAX_MSGLEN];
692 int i, j;
693 usercmd_t *cmd, *oldcmd;
694 usercmd_t nullcmd;
695 int packetNum;
696 int oldPacketNum;
697 int count, key;
698
699 // don't send anything if playing back a demo
700 if ( clc.demoplaying || cls.state == CA_CINEMATIC ) {
701 return;
702 }
703
704 Com_Memset( &nullcmd, 0, sizeof(nullcmd) );
705 oldcmd = &nullcmd;
706
707 MSG_Init( &buf, data, sizeof(data) );
708
709 MSG_Bitstream( &buf );
710 // write the current serverId so the server
711 // can tell if this is from the current gameState
712 MSG_WriteLong( &buf, cl.serverId );
713
714 // write the last message we received, which can
715 // be used for delta compression, and is also used
716 // to tell if we dropped a gamestate
717 MSG_WriteLong( &buf, clc.serverMessageSequence );
718
719 // write the last reliable message we received
720 MSG_WriteLong( &buf, clc.serverCommandSequence );
721
722 // write any unacknowledged clientCommands
723 for ( i = clc.reliableAcknowledge + 1 ; i <= clc.reliableSequence ; i++ ) {
724 MSG_WriteByte( &buf, clc_clientCommand );
725 MSG_WriteLong( &buf, i );
726 MSG_WriteString( &buf, clc.reliableCommands[ i & (MAX_RELIABLE_COMMANDS-1) ] );
727 }
728
729 // we want to send all the usercmds that were generated in the last
730 // few packet, so even if a couple packets are dropped in a row,
731 // all the cmds will make it to the server
732 if ( cl_packetdup->integer < 0 ) {
733 Cvar_Set( "cl_packetdup", "0" );
734 } else if ( cl_packetdup->integer > 5 ) {
735 Cvar_Set( "cl_packetdup", "5" );
736 }
737 oldPacketNum = (clc.netchan.outgoingSequence - 1 - cl_packetdup->integer) & PACKET_MASK;
738 count = cl.cmdNumber - cl.outPackets[ oldPacketNum ].p_cmdNumber;
739 if ( count > MAX_PACKET_USERCMDS ) {
740 count = MAX_PACKET_USERCMDS;
741 Com_Printf("MAX_PACKET_USERCMDS\n");
742 }
743 if ( count >= 1 ) {
744 if ( cl_showSend->integer ) {
745 Com_Printf( "(%i)", count );
746 }
747
748 // begin a client move command
749 if ( cl_nodelta->integer || !cl.snap.valid || clc.demowaiting
750 || clc.serverMessageSequence != cl.snap.messageNum ) {
751 MSG_WriteByte (&buf, clc_moveNoDelta);
752 } else {
753 MSG_WriteByte (&buf, clc_move);
754 }
755
756 // write the command count
757 MSG_WriteByte( &buf, count );
758
759 // use the checksum feed in the key
760 key = clc.checksumFeed;
761 // also use the message acknowledge
762 key ^= clc.serverMessageSequence;
763 // also use the last acknowledged server command in the key
764 key ^= Com_HashKey(clc.serverCommands[ clc.serverCommandSequence & (MAX_RELIABLE_COMMANDS-1) ], 32);
765
766 // write all the commands, including the predicted command
767 for ( i = 0 ; i < count ; i++ ) {
768 j = (cl.cmdNumber - count + i + 1) & CMD_MASK;
769 cmd = &cl.cmds[j];
770 MSG_WriteDeltaUsercmdKey (&buf, key, oldcmd, cmd);
771 oldcmd = cmd;
772 }
773 }
774
775 //
776 // deliver the message
777 //
778 packetNum = clc.netchan.outgoingSequence & PACKET_MASK;
779 cl.outPackets[ packetNum ].p_realtime = cls.realtime;
780 cl.outPackets[ packetNum ].p_serverTime = oldcmd->serverTime;
781 cl.outPackets[ packetNum ].p_cmdNumber = cl.cmdNumber;
782 clc.lastPacketSentTime = cls.realtime;
783
784 if ( cl_showSend->integer ) {
785 Com_Printf( "%i ", buf.cursize );
786 }
787
788 CL_Netchan_Transmit (&clc.netchan, &buf);
789
790 // clients never really should have messages large enough
791 // to fragment, but in case they do, fire them all off
792 // at once
793 // TTimo: this causes a packet burst, which is bad karma for winsock
794 // added a WARNING message, we'll see if there are legit situations where this happens
795 while ( clc.netchan.unsentFragments ) {
796 Com_DPrintf( "WARNING: #462 unsent fragments (not supposed to happen!)\n" );
797 CL_Netchan_TransmitNextFragment( &clc.netchan );
798 }
799 }
800
801 /*
802 =================
803 CL_SendCmd
804
805 Called every frame to builds and sends a command packet to the server.
806 =================
807 */
CL_SendCmd(void)808 void CL_SendCmd( void ) {
809 // don't send any message if not connected
810 if ( cls.state < CA_CONNECTED ) {
811 return;
812 }
813
814 // don't send commands if paused
815 if ( com_sv_running->integer && sv_paused->integer && cl_paused->integer ) {
816 return;
817 }
818
819 // we create commands even if a demo is playing,
820 CL_CreateNewCommands();
821
822 // don't send a packet if the last packet was sent too recently
823 if ( !CL_ReadyToSendPacket() ) {
824 if ( cl_showSend->integer ) {
825 Com_Printf( ". " );
826 }
827 return;
828 }
829
830 CL_WritePacket();
831 }
832
833 /*
834 ============
835 CL_InitInput
836 ============
837 */
CL_InitInput(void)838 void CL_InitInput( void ) {
839 Cmd_AddCommand ("centerview",IN_CenterView);
840
841 Cmd_AddCommand ("+moveup",IN_UpDown);
842 Cmd_AddCommand ("-moveup",IN_UpUp);
843 Cmd_AddCommand ("+movedown",IN_DownDown);
844 Cmd_AddCommand ("-movedown",IN_DownUp);
845 Cmd_AddCommand ("+left",IN_LeftDown);
846 Cmd_AddCommand ("-left",IN_LeftUp);
847 Cmd_AddCommand ("+right",IN_RightDown);
848 Cmd_AddCommand ("-right",IN_RightUp);
849 Cmd_AddCommand ("+forward",IN_ForwardDown);
850 Cmd_AddCommand ("-forward",IN_ForwardUp);
851 Cmd_AddCommand ("+back",IN_BackDown);
852 Cmd_AddCommand ("-back",IN_BackUp);
853 Cmd_AddCommand ("+lookup", IN_LookupDown);
854 Cmd_AddCommand ("-lookup", IN_LookupUp);
855 Cmd_AddCommand ("+lookdown", IN_LookdownDown);
856 Cmd_AddCommand ("-lookdown", IN_LookdownUp);
857 Cmd_AddCommand ("+strafe", IN_StrafeDown);
858 Cmd_AddCommand ("-strafe", IN_StrafeUp);
859 Cmd_AddCommand ("+moveleft", IN_MoveleftDown);
860 Cmd_AddCommand ("-moveleft", IN_MoveleftUp);
861 Cmd_AddCommand ("+moveright", IN_MoverightDown);
862 Cmd_AddCommand ("-moveright", IN_MoverightUp);
863 Cmd_AddCommand ("+speed", IN_SpeedDown);
864 Cmd_AddCommand ("-speed", IN_SpeedUp);
865 Cmd_AddCommand ("+attack", IN_Button0Down);
866 Cmd_AddCommand ("-attack", IN_Button0Up);
867 Cmd_AddCommand ("+button0", IN_Button0Down);
868 Cmd_AddCommand ("-button0", IN_Button0Up);
869 Cmd_AddCommand ("+button1", IN_Button1Down);
870 Cmd_AddCommand ("-button1", IN_Button1Up);
871 Cmd_AddCommand ("+button2", IN_Button2Down);
872 Cmd_AddCommand ("-button2", IN_Button2Up);
873 Cmd_AddCommand ("+button3", IN_Button3Down);
874 Cmd_AddCommand ("-button3", IN_Button3Up);
875 Cmd_AddCommand ("+button4", IN_Button4Down);
876 Cmd_AddCommand ("-button4", IN_Button4Up);
877 Cmd_AddCommand ("+button5", IN_Button5Down);
878 Cmd_AddCommand ("-button5", IN_Button5Up);
879 Cmd_AddCommand ("+button6", IN_Button6Down);
880 Cmd_AddCommand ("-button6", IN_Button6Up);
881 Cmd_AddCommand ("+button7", IN_Button7Down);
882 Cmd_AddCommand ("-button7", IN_Button7Up);
883 Cmd_AddCommand ("+button8", IN_Button8Down);
884 Cmd_AddCommand ("-button8", IN_Button8Up);
885 Cmd_AddCommand ("+button9", IN_Button9Down);
886 Cmd_AddCommand ("-button9", IN_Button9Up);
887 Cmd_AddCommand ("+button10", IN_Button10Down);
888 Cmd_AddCommand ("-button10", IN_Button10Up);
889 Cmd_AddCommand ("+button11", IN_Button11Down);
890 Cmd_AddCommand ("-button11", IN_Button11Up);
891 Cmd_AddCommand ("+button12", IN_Button12Down);
892 Cmd_AddCommand ("-button12", IN_Button12Up);
893 Cmd_AddCommand ("+button13", IN_Button13Down);
894 Cmd_AddCommand ("-button13", IN_Button13Up);
895 Cmd_AddCommand ("+button14", IN_Button14Down);
896 Cmd_AddCommand ("-button14", IN_Button14Up);
897 Cmd_AddCommand ("+mlook", IN_MLookDown);
898 Cmd_AddCommand ("-mlook", IN_MLookUp);
899
900 cl_nodelta = Cvar_Get ("cl_nodelta", "0", 0);
901 cl_debugMove = Cvar_Get ("cl_debugMove", "0", 0);
902 }
903