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