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_cgame.c  -- client system interaction with client game
23 
24 #include "client.h"
25 
26 #include "../botlib/botlib.h"
27 
28 #include "libmumblelink.h"
29 
30 extern	botlib_export_t	*botlib_export;
31 
32 extern qboolean loadCamera(const char *name);
33 extern void startCamera(int time);
34 extern qboolean getCameraInfo(int time, vec3_t *origin, vec3_t *angles);
35 
36 /*
37 ====================
38 CL_GetGameState
39 ====================
40 */
CL_GetGameState(gameState_t * gs)41 void CL_GetGameState( gameState_t *gs ) {
42 	*gs = cl.gameState;
43 }
44 
45 /*
46 ====================
47 CL_GetGlconfig
48 ====================
49 */
CL_GetGlconfig(glConfig_t * glconfig)50 void CL_GetGlconfig( glConfig_t *glconfig ) {
51 	*glconfig = cls.glconfig;
52 }
53 
54 
55 /*
56 ====================
57 CL_GetUserCmd
58 ====================
59 */
CL_GetUserCmd(int cmdNumber,usercmd_t * ucmd)60 qboolean CL_GetUserCmd( int cmdNumber, usercmd_t *ucmd ) {
61 	// cmds[cmdNumber] is the last properly generated command
62 
63 	// can't return anything that we haven't created yet
64 	if ( cmdNumber > cl.cmdNumber ) {
65 		Com_Error( ERR_DROP, "CL_GetUserCmd: %i >= %i", cmdNumber, cl.cmdNumber );
66 	}
67 
68 	// the usercmd has been overwritten in the wrapping
69 	// buffer because it is too far out of date
70 	if ( cmdNumber <= cl.cmdNumber - CMD_BACKUP ) {
71 		return qfalse;
72 	}
73 
74 	*ucmd = cl.cmds[ cmdNumber & CMD_MASK ];
75 
76 	return qtrue;
77 }
78 
CL_GetCurrentCmdNumber(void)79 int CL_GetCurrentCmdNumber( void ) {
80 	return cl.cmdNumber;
81 }
82 
83 
84 /*
85 ====================
86 CL_GetParseEntityState
87 ====================
88 */
CL_GetParseEntityState(int parseEntityNumber,entityState_t * state)89 qboolean	CL_GetParseEntityState( int parseEntityNumber, entityState_t *state ) {
90 	// can't return anything that hasn't been parsed yet
91 	if ( parseEntityNumber >= cl.parseEntitiesNum ) {
92 		Com_Error( ERR_DROP, "CL_GetParseEntityState: %i >= %i",
93 			parseEntityNumber, cl.parseEntitiesNum );
94 	}
95 
96 	// can't return anything that has been overwritten in the circular buffer
97 	if ( parseEntityNumber <= cl.parseEntitiesNum - MAX_PARSE_ENTITIES ) {
98 		return qfalse;
99 	}
100 
101 	*state = cl.parseEntities[ parseEntityNumber & ( MAX_PARSE_ENTITIES - 1 ) ];
102 	return qtrue;
103 }
104 
105 /*
106 ====================
107 CL_GetCurrentSnapshotNumber
108 ====================
109 */
CL_GetCurrentSnapshotNumber(int * snapshotNumber,int * serverTime)110 void	CL_GetCurrentSnapshotNumber( int *snapshotNumber, int *serverTime ) {
111 	*snapshotNumber = cl.snap.messageNum;
112 	*serverTime = cl.snap.serverTime;
113 }
114 
115 /*
116 ====================
117 CL_GetSnapshot
118 ====================
119 */
CL_GetSnapshot(int snapshotNumber,snapshot_t * snapshot)120 qboolean	CL_GetSnapshot( int snapshotNumber, snapshot_t *snapshot ) {
121 	clSnapshot_t	*clSnap;
122 	int				i, count;
123 
124 	if ( snapshotNumber > cl.snap.messageNum ) {
125 		Com_Error( ERR_DROP, "CL_GetSnapshot: snapshotNumber > cl.snapshot.messageNum" );
126 	}
127 
128 	// if the frame has fallen out of the circular buffer, we can't return it
129 	if ( cl.snap.messageNum - snapshotNumber >= PACKET_BACKUP ) {
130 		return qfalse;
131 	}
132 
133 	// if the frame is not valid, we can't return it
134 	clSnap = &cl.snapshots[snapshotNumber & PACKET_MASK];
135 	if ( !clSnap->valid ) {
136 		return qfalse;
137 	}
138 
139 	// if the entities in the frame have fallen out of their
140 	// circular buffer, we can't return it
141 	if ( cl.parseEntitiesNum - clSnap->parseEntitiesNum >= MAX_PARSE_ENTITIES ) {
142 		return qfalse;
143 	}
144 
145 	// write the snapshot
146 	snapshot->snapFlags = clSnap->snapFlags;
147 	snapshot->serverCommandSequence = clSnap->serverCommandNum;
148 	snapshot->ping = clSnap->ping;
149 	snapshot->serverTime = clSnap->serverTime;
150 	Com_Memcpy( snapshot->areamask, clSnap->areamask, sizeof( snapshot->areamask ) );
151 	snapshot->ps = clSnap->ps;
152 	count = clSnap->numEntities;
153 	if ( count > MAX_ENTITIES_IN_SNAPSHOT ) {
154 		Com_DPrintf( "CL_GetSnapshot: truncated %i entities to %i\n", count, MAX_ENTITIES_IN_SNAPSHOT );
155 		count = MAX_ENTITIES_IN_SNAPSHOT;
156 	}
157 	snapshot->numEntities = count;
158 	for ( i = 0 ; i < count ; i++ ) {
159 		snapshot->entities[i] =
160 			cl.parseEntities[ ( clSnap->parseEntitiesNum + i ) & (MAX_PARSE_ENTITIES-1) ];
161 	}
162 
163 	// FIXME: configstring changes and server commands!!!
164 
165 	return qtrue;
166 }
167 
168 /*
169 =====================
170 CL_SetUserCmdValue
171 =====================
172 */
CL_SetUserCmdValue(int userCmdValue,float sensitivityScale)173 void CL_SetUserCmdValue( int userCmdValue, float sensitivityScale ) {
174 	cl.cgameUserCmdValue = userCmdValue;
175 	cl.cgameSensitivity = sensitivityScale;
176 }
177 
178 /*
179 =====================
180 CL_AddCgameCommand
181 =====================
182 */
CL_AddCgameCommand(const char * cmdName)183 void CL_AddCgameCommand( const char *cmdName ) {
184 	Cmd_AddCommand( cmdName, NULL );
185 }
186 
187 /*
188 =====================
189 CL_CgameError
190 =====================
191 */
CL_CgameError(const char * string)192 void CL_CgameError( const char *string ) {
193 	Com_Error( ERR_DROP, "%s", string );
194 }
195 
196 
197 /*
198 =====================
199 CL_ConfigstringModified
200 =====================
201 */
CL_ConfigstringModified(void)202 void CL_ConfigstringModified( void ) {
203 	char		*old, *s;
204 	int			i, index;
205 	char		*dup;
206 	gameState_t	oldGs;
207 	int			len;
208 
209 	index = atoi( Cmd_Argv(1) );
210 	if ( index < 0 || index >= MAX_CONFIGSTRINGS ) {
211 		Com_Error( ERR_DROP, "configstring > MAX_CONFIGSTRINGS" );
212 	}
213 	// get everything after "cs <num>"
214 	s = Cmd_ArgsFrom(2);
215 
216 	old = cl.gameState.stringData + cl.gameState.stringOffsets[ index ];
217 	if ( !strcmp( old, s ) ) {
218 		return;		// unchanged
219 	}
220 
221 	// build the new gameState_t
222 	oldGs = cl.gameState;
223 
224 	Com_Memset( &cl.gameState, 0, sizeof( cl.gameState ) );
225 
226 	// leave the first 0 for uninitialized strings
227 	cl.gameState.dataCount = 1;
228 
229 	for ( i = 0 ; i < MAX_CONFIGSTRINGS ; i++ ) {
230 		if ( i == index ) {
231 			dup = s;
232 		} else {
233 			dup = oldGs.stringData + oldGs.stringOffsets[ i ];
234 		}
235 		if ( !dup[0] ) {
236 			continue;		// leave with the default empty string
237 		}
238 
239 		len = strlen( dup );
240 
241 		if ( len + 1 + cl.gameState.dataCount > MAX_GAMESTATE_CHARS ) {
242 			Com_Error( ERR_DROP, "MAX_GAMESTATE_CHARS exceeded" );
243 		}
244 
245 		// append it to the gameState string buffer
246 		cl.gameState.stringOffsets[ i ] = cl.gameState.dataCount;
247 		Com_Memcpy( cl.gameState.stringData + cl.gameState.dataCount, dup, len + 1 );
248 		cl.gameState.dataCount += len + 1;
249 	}
250 
251 	if ( index == CS_SYSTEMINFO ) {
252 		// parse serverId and other cvars
253 		CL_SystemInfoChanged();
254 	}
255 
256 }
257 
258 
259 /*
260 ===================
261 CL_GetServerCommand
262 
263 Set up argc/argv for the given command
264 ===================
265 */
CL_GetServerCommand(int serverCommandNumber)266 qboolean CL_GetServerCommand( int serverCommandNumber ) {
267 	char	*s;
268 	char	*cmd;
269 	static char bigConfigString[BIG_INFO_STRING];
270 	int argc;
271 
272 	// if we have irretrievably lost a reliable command, drop the connection
273 	if ( serverCommandNumber <= clc.serverCommandSequence - MAX_RELIABLE_COMMANDS ) {
274 		// when a demo record was started after the client got a whole bunch of
275 		// reliable commands then the client never got those first reliable commands
276 		if ( clc.demoplaying )
277 			return qfalse;
278 		Com_Error( ERR_DROP, "CL_GetServerCommand: a reliable command was cycled out" );
279 		return qfalse;
280 	}
281 
282 	if ( serverCommandNumber > clc.serverCommandSequence ) {
283 		Com_Error( ERR_DROP, "CL_GetServerCommand: requested a command not received" );
284 		return qfalse;
285 	}
286 
287 	s = clc.serverCommands[ serverCommandNumber & ( MAX_RELIABLE_COMMANDS - 1 ) ];
288 	clc.lastExecutedServerCommand = serverCommandNumber;
289 
290 	Com_DPrintf( "serverCommand: %i : %s\n", serverCommandNumber, s );
291 
292 rescan:
293 	Cmd_TokenizeString( s );
294 	cmd = Cmd_Argv(0);
295 	argc = Cmd_Argc();
296 
297 	if ( !strcmp( cmd, "disconnect" ) ) {
298 		// https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=552
299 		// allow server to indicate why they were disconnected
300 		if ( argc >= 2 )
301 			Com_Error( ERR_SERVERDISCONNECT, "Server disconnected - %s", Cmd_Argv( 1 ) );
302 		else
303 			Com_Error( ERR_SERVERDISCONNECT, "Server disconnected\n" );
304 	}
305 
306 	if ( !strcmp( cmd, "bcs0" ) ) {
307 		Com_sprintf( bigConfigString, BIG_INFO_STRING, "cs %s \"%s", Cmd_Argv(1), Cmd_Argv(2) );
308 		return qfalse;
309 	}
310 
311 	if ( !strcmp( cmd, "bcs1" ) ) {
312 		s = Cmd_Argv(2);
313 		if( strlen(bigConfigString) + strlen(s) >= BIG_INFO_STRING ) {
314 			Com_Error( ERR_DROP, "bcs exceeded BIG_INFO_STRING" );
315 		}
316 		strcat( bigConfigString, s );
317 		return qfalse;
318 	}
319 
320 	if ( !strcmp( cmd, "bcs2" ) ) {
321 		s = Cmd_Argv(2);
322 		if( strlen(bigConfigString) + strlen(s) + 1 >= BIG_INFO_STRING ) {
323 			Com_Error( ERR_DROP, "bcs exceeded BIG_INFO_STRING" );
324 		}
325 		strcat( bigConfigString, s );
326 		strcat( bigConfigString, "\"" );
327 		s = bigConfigString;
328 		goto rescan;
329 	}
330 
331 	if ( !strcmp( cmd, "cs" ) ) {
332 		CL_ConfigstringModified();
333 		// reparse the string, because CL_ConfigstringModified may have done another Cmd_TokenizeString()
334 		Cmd_TokenizeString( s );
335 		return qtrue;
336 	}
337 
338 	if ( !strcmp( cmd, "map_restart" ) ) {
339 		// clear notify lines and outgoing commands before passing
340 		// the restart to the cgame
341 		Con_ClearNotify();
342 		Com_Memset( cl.cmds, 0, sizeof( cl.cmds ) );
343 		return qtrue;
344 	}
345 
346 	// the clientLevelShot command is used during development
347 	// to generate 128*128 screenshots from the intermission
348 	// point of levels for the menu system to use
349 	// we pass it along to the cgame to make apropriate adjustments,
350 	// but we also clear the console and notify lines here
351 	if ( !strcmp( cmd, "clientLevelShot" ) ) {
352 		// don't do it if we aren't running the server locally,
353 		// otherwise malicious remote servers could overwrite
354 		// the existing thumbnails
355 		if ( !com_sv_running->integer ) {
356 			return qfalse;
357 		}
358 		// close the console
359 		Con_Close();
360 		// take a special screenshot next frame
361 		Cbuf_AddText( "wait ; wait ; wait ; wait ; screenshot levelshot\n" );
362 		return qtrue;
363 	}
364 
365 	// we may want to put a "connect to other server" command here
366 
367 	// cgame can now act on the command
368 	return qtrue;
369 }
370 
371 
372 /*
373 ====================
374 CL_CM_LoadMap
375 
376 Just adds default parameters that cgame doesn't need to know about
377 ====================
378 */
CL_CM_LoadMap(const char * mapname)379 void CL_CM_LoadMap( const char *mapname ) {
380 	int		checksum;
381 
382 	CM_LoadMap( mapname, qtrue, &checksum );
383 }
384 
385 /*
386 ====================
387 CL_ShutdonwCGame
388 
389 ====================
390 */
CL_ShutdownCGame(void)391 void CL_ShutdownCGame( void ) {
392 	Key_SetCatcher( Key_GetCatcher( ) & ~KEYCATCH_CGAME );
393 	cls.cgameStarted = qfalse;
394 	if ( !cgvm ) {
395 		return;
396 	}
397 	VM_Call( cgvm, CG_SHUTDOWN );
398 	VM_Free( cgvm );
399 	cgvm = NULL;
400 }
401 
FloatAsInt(float f)402 static int	FloatAsInt( float f ) {
403 	int		temp;
404 
405 	*(float *)&temp = f;
406 
407 	return temp;
408 }
409 
410 /*
411 ====================
412 CL_CgameSystemCalls
413 
414 The cgame module is making a system call
415 ====================
416 */
CL_CgameSystemCalls(intptr_t * args)417 intptr_t CL_CgameSystemCalls( intptr_t *args ) {
418 	switch( args[0] ) {
419 	case CG_PRINT:
420 		Com_Printf( "%s", (const char*)VMA(1) );
421 		return 0;
422 	case CG_ERROR:
423 		Com_Error( ERR_DROP, "%s", (const char*)VMA(1) );
424 		return 0;
425 	case CG_MILLISECONDS:
426 		return Sys_Milliseconds();
427 	case CG_CVAR_REGISTER:
428 		Cvar_Register( VMA(1), VMA(2), VMA(3), args[4] );
429 		return 0;
430 	case CG_CVAR_UPDATE:
431 		Cvar_Update( VMA(1) );
432 		return 0;
433 	case CG_CVAR_SET:
434 		Cvar_Set( VMA(1), VMA(2) );
435 		return 0;
436 	case CG_CVAR_VARIABLESTRINGBUFFER:
437 		Cvar_VariableStringBuffer( VMA(1), VMA(2), args[3] );
438 		return 0;
439 	case CG_ARGC:
440 		return Cmd_Argc();
441 	case CG_ARGV:
442 		Cmd_ArgvBuffer( args[1], VMA(2), args[3] );
443 		return 0;
444 	case CG_ARGS:
445 		Cmd_ArgsBuffer( VMA(1), args[2] );
446 		return 0;
447 	case CG_FS_FOPENFILE:
448 		return FS_FOpenFileByMode( VMA(1), VMA(2), args[3] );
449 	case CG_FS_READ:
450 		FS_Read2( VMA(1), args[2], args[3] );
451 		return 0;
452 	case CG_FS_WRITE:
453 		FS_Write( VMA(1), args[2], args[3] );
454 		return 0;
455 	case CG_FS_FCLOSEFILE:
456 		FS_FCloseFile( args[1] );
457 		return 0;
458 	case CG_FS_SEEK:
459 		return FS_Seek( args[1], args[2], args[3] );
460 	case CG_SENDCONSOLECOMMAND:
461 		Cbuf_AddText( VMA(1) );
462 		return 0;
463 	case CG_ADDCOMMAND:
464 		CL_AddCgameCommand( VMA(1) );
465 		return 0;
466 	case CG_REMOVECOMMAND:
467 		Cmd_RemoveCommand( VMA(1) );
468 		return 0;
469 	case CG_SENDCLIENTCOMMAND:
470 		CL_AddReliableCommand( VMA(1) );
471 		return 0;
472 	case CG_UPDATESCREEN:
473 		// this is used during lengthy level loading, so pump message loop
474 //		Com_EventLoop();	// FIXME: if a server restarts here, BAD THINGS HAPPEN!
475 // We can't call Com_EventLoop here, a restart will crash and this _does_ happen
476 // if there is a map change while we are downloading at pk3.
477 // ZOID
478 		SCR_UpdateScreen();
479 		return 0;
480 	case CG_CM_LOADMAP:
481 		CL_CM_LoadMap( VMA(1) );
482 		return 0;
483 	case CG_CM_NUMINLINEMODELS:
484 		return CM_NumInlineModels();
485 	case CG_CM_INLINEMODEL:
486 		return CM_InlineModel( args[1] );
487 	case CG_CM_TEMPBOXMODEL:
488 		return CM_TempBoxModel( VMA(1), VMA(2), /*int capsule*/ qfalse );
489 	case CG_CM_TEMPCAPSULEMODEL:
490 		return CM_TempBoxModel( VMA(1), VMA(2), /*int capsule*/ qtrue );
491 	case CG_CM_POINTCONTENTS:
492 		return CM_PointContents( VMA(1), args[2] );
493 	case CG_CM_TRANSFORMEDPOINTCONTENTS:
494 		return CM_TransformedPointContents( VMA(1), args[2], VMA(3), VMA(4) );
495 	case CG_CM_BOXTRACE:
496 		CM_BoxTrace( VMA(1), VMA(2), VMA(3), VMA(4), VMA(5), args[6], args[7], /*int capsule*/ qfalse );
497 		return 0;
498 	case CG_CM_CAPSULETRACE:
499 		CM_BoxTrace( VMA(1), VMA(2), VMA(3), VMA(4), VMA(5), args[6], args[7], /*int capsule*/ qtrue );
500 		return 0;
501 	case CG_CM_TRANSFORMEDBOXTRACE:
502 		CM_TransformedBoxTrace( VMA(1), VMA(2), VMA(3), VMA(4), VMA(5), args[6], args[7], VMA(8), VMA(9), /*int capsule*/ qfalse );
503 		return 0;
504 	case CG_CM_TRANSFORMEDCAPSULETRACE:
505 		CM_TransformedBoxTrace( VMA(1), VMA(2), VMA(3), VMA(4), VMA(5), args[6], args[7], VMA(8), VMA(9), /*int capsule*/ qtrue );
506 		return 0;
507 	case CG_CM_MARKFRAGMENTS:
508 		return re.MarkFragments( args[1], VMA(2), VMA(3), args[4], VMA(5), args[6], VMA(7) );
509 	case CG_S_STARTSOUND:
510 		S_StartSound( VMA(1), args[2], args[3], args[4] );
511 		return 0;
512 	case CG_S_STARTLOCALSOUND:
513 		S_StartLocalSound( args[1], args[2] );
514 		return 0;
515 	case CG_S_CLEARLOOPINGSOUNDS:
516 		S_ClearLoopingSounds(args[1]);
517 		return 0;
518 	case CG_S_ADDLOOPINGSOUND:
519 		S_AddLoopingSound( args[1], VMA(2), VMA(3), args[4] );
520 		return 0;
521 	case CG_S_ADDREALLOOPINGSOUND:
522 		S_AddRealLoopingSound( args[1], VMA(2), VMA(3), args[4] );
523 		return 0;
524 	case CG_S_STOPLOOPINGSOUND:
525 		S_StopLoopingSound( args[1] );
526 		return 0;
527 	case CG_S_UPDATEENTITYPOSITION:
528 		S_UpdateEntityPosition( args[1], VMA(2) );
529 		return 0;
530 	case CG_S_RESPATIALIZE:
531 		S_Respatialize( args[1], VMA(2), VMA(3), args[4] );
532 		return 0;
533 	case CG_S_REGISTERSOUND:
534 		return S_RegisterSound( VMA(1), args[2] );
535 	case CG_S_STARTBACKGROUNDTRACK:
536 		S_StartBackgroundTrack( VMA(1), VMA(2) );
537 		return 0;
538 	case CG_R_LOADWORLDMAP:
539 		re.LoadWorld( VMA(1) );
540 		return 0;
541 	case CG_R_REGISTERMODEL:
542 		return re.RegisterModel( VMA(1) );
543 	case CG_R_REGISTERSKIN:
544 		return re.RegisterSkin( VMA(1) );
545 	case CG_R_REGISTERSHADER:
546 		return re.RegisterShader( VMA(1) );
547 	case CG_R_REGISTERSHADERNOMIP:
548 		return re.RegisterShaderNoMip( VMA(1) );
549 	case CG_R_REGISTERFONT:
550 		re.RegisterFont( VMA(1), args[2], VMA(3));
551 	case CG_R_CLEARSCENE:
552 		re.ClearScene();
553 		return 0;
554 	case CG_R_ADDREFENTITYTOSCENE:
555 		re.AddRefEntityToScene( VMA(1) );
556 		return 0;
557 	case CG_R_ADDPOLYTOSCENE:
558 		re.AddPolyToScene( args[1], args[2], VMA(3), 1 );
559 		return 0;
560 	case CG_R_ADDPOLYSTOSCENE:
561 		re.AddPolyToScene( args[1], args[2], VMA(3), args[4] );
562 		return 0;
563 	case CG_R_LIGHTFORPOINT:
564 		return re.LightForPoint( VMA(1), VMA(2), VMA(3), VMA(4) );
565 	case CG_R_ADDLIGHTTOSCENE:
566 		re.AddLightToScene( VMA(1), VMF(2), VMF(3), VMF(4), VMF(5) );
567 		return 0;
568 	case CG_R_ADDADDITIVELIGHTTOSCENE:
569 		re.AddAdditiveLightToScene( VMA(1), VMF(2), VMF(3), VMF(4), VMF(5) );
570 		return 0;
571 	case CG_R_RENDERSCENE:
572 		re.RenderScene( VMA(1) );
573 		return 0;
574 	case CG_R_SETCOLOR:
575 		re.SetColor( VMA(1) );
576 		return 0;
577 	case CG_R_DRAWSTRETCHPIC:
578 		re.DrawStretchPic( VMF(1), VMF(2), VMF(3), VMF(4), VMF(5), VMF(6), VMF(7), VMF(8), args[9] );
579 		return 0;
580 	case CG_R_MODELBOUNDS:
581 		re.ModelBounds( args[1], VMA(2), VMA(3) );
582 		return 0;
583 	case CG_R_LERPTAG:
584 		return re.LerpTag( VMA(1), args[2], args[3], args[4], VMF(5), VMA(6) );
585 	case CG_GETGLCONFIG:
586 		CL_GetGlconfig( VMA(1) );
587 		return 0;
588 	case CG_GETGAMESTATE:
589 		CL_GetGameState( VMA(1) );
590 		return 0;
591 	case CG_GETCURRENTSNAPSHOTNUMBER:
592 		CL_GetCurrentSnapshotNumber( VMA(1), VMA(2) );
593 		return 0;
594 	case CG_GETSNAPSHOT:
595 		return CL_GetSnapshot( args[1], VMA(2) );
596 	case CG_GETSERVERCOMMAND:
597 		return CL_GetServerCommand( args[1] );
598 	case CG_GETCURRENTCMDNUMBER:
599 		return CL_GetCurrentCmdNumber();
600 	case CG_GETUSERCMD:
601 		return CL_GetUserCmd( args[1], VMA(2) );
602 	case CG_SETUSERCMDVALUE:
603 		CL_SetUserCmdValue( args[1], VMF(2) );
604 		return 0;
605 	case CG_MEMORY_REMAINING:
606 		return Hunk_MemoryRemaining();
607   case CG_KEY_ISDOWN:
608 		return Key_IsDown( args[1] );
609   case CG_KEY_GETCATCHER:
610 		return Key_GetCatcher();
611   case CG_KEY_SETCATCHER:
612 		// Don't allow the cgame module to close the console
613 		Key_SetCatcher( args[1] | ( Key_GetCatcher( ) & KEYCATCH_CONSOLE ) );
614     return 0;
615   case CG_KEY_GETKEY:
616 		return Key_GetKey( VMA(1) );
617 
618 
619 
620 	case CG_MEMSET:
621 		Com_Memset( VMA(1), args[2], args[3] );
622 		return 0;
623 	case CG_MEMCPY:
624 		Com_Memcpy( VMA(1), VMA(2), args[3] );
625 		return 0;
626 	case CG_STRNCPY:
627 		strncpy( VMA(1), VMA(2), args[3] );
628 		return args[1];
629 	case CG_SIN:
630 		return FloatAsInt( sin( VMF(1) ) );
631 	case CG_COS:
632 		return FloatAsInt( cos( VMF(1) ) );
633 	case CG_ATAN2:
634 		return FloatAsInt( atan2( VMF(1), VMF(2) ) );
635 	case CG_SQRT:
636 		return FloatAsInt( sqrt( VMF(1) ) );
637 	case CG_FLOOR:
638 		return FloatAsInt( floor( VMF(1) ) );
639 	case CG_CEIL:
640 		return FloatAsInt( ceil( VMF(1) ) );
641 	case CG_ACOS:
642 		return FloatAsInt( Q_acos( VMF(1) ) );
643 
644 	case CG_PC_ADD_GLOBAL_DEFINE:
645 		return botlib_export->PC_AddGlobalDefine( VMA(1) );
646 	case CG_PC_LOAD_SOURCE:
647 		return botlib_export->PC_LoadSourceHandle( VMA(1) );
648 	case CG_PC_FREE_SOURCE:
649 		return botlib_export->PC_FreeSourceHandle( args[1] );
650 	case CG_PC_READ_TOKEN:
651 		return botlib_export->PC_ReadTokenHandle( args[1], VMA(2) );
652 	case CG_PC_SOURCE_FILE_AND_LINE:
653 		return botlib_export->PC_SourceFileAndLine( args[1], VMA(2), VMA(3) );
654 
655 	case CG_S_STOPBACKGROUNDTRACK:
656 		S_StopBackgroundTrack();
657 		return 0;
658 
659 	case CG_REAL_TIME:
660 		return Com_RealTime( VMA(1) );
661 	case CG_SNAPVECTOR:
662 		Sys_SnapVector( VMA(1) );
663 		return 0;
664 
665 	case CG_CIN_PLAYCINEMATIC:
666 	  return CIN_PlayCinematic(VMA(1), args[2], args[3], args[4], args[5], args[6]);
667 
668 	case CG_CIN_STOPCINEMATIC:
669 	  return CIN_StopCinematic(args[1]);
670 
671 	case CG_CIN_RUNCINEMATIC:
672 	  return CIN_RunCinematic(args[1]);
673 
674 	case CG_CIN_DRAWCINEMATIC:
675 	  CIN_DrawCinematic(args[1]);
676 	  return 0;
677 
678 	case CG_CIN_SETEXTENTS:
679 	  CIN_SetExtents(args[1], args[2], args[3], args[4], args[5]);
680 	  return 0;
681 
682 	case CG_R_REMAP_SHADER:
683 		re.RemapShader( VMA(1), VMA(2), VMA(3) );
684 		return 0;
685 
686 /*
687 	case CG_LOADCAMERA:
688 		return loadCamera(VMA(1));
689 
690 	case CG_STARTCAMERA:
691 		startCamera(args[1]);
692 		return 0;
693 
694 	case CG_GETCAMERAINFO:
695 		return getCameraInfo(args[1], VMA(2), VMA(3));
696 */
697 	case CG_GET_ENTITY_TOKEN:
698 		return re.GetEntityToken( VMA(1), args[2] );
699 	case CG_R_INPVS:
700 		return re.inPVS( VMA(1), VMA(2) );
701 
702 	default:
703 	        assert(0);
704 		Com_Error( ERR_DROP, "Bad cgame system trap: %ld", (long int) args[0] );
705 	}
706 	return 0;
707 }
708 
709 
710 /*
711 ====================
712 CL_InitCGame
713 
714 Should only be called by CL_StartHunkUsers
715 ====================
716 */
CL_InitCGame(void)717 void CL_InitCGame( void ) {
718 	const char			*info;
719 	const char			*mapname;
720 	int					t1, t2;
721 	vmInterpret_t		interpret;
722 
723 	t1 = Sys_Milliseconds();
724 
725 	// put away the console
726 	Con_Close();
727 
728 	// find the current mapname
729 	info = cl.gameState.stringData + cl.gameState.stringOffsets[ CS_SERVERINFO ];
730 	mapname = Info_ValueForKey( info, "mapname" );
731 	Com_sprintf( cl.mapname, sizeof( cl.mapname ), "maps/%s.bsp", mapname );
732 
733 	// load the dll or bytecode
734 	if ( cl_connectedToPureServer != 0 ) {
735 		// if sv_pure is set we only allow qvms to be loaded
736 		interpret = VMI_COMPILED;
737 	}
738 	else {
739 		interpret = Cvar_VariableValue( "vm_cgame" );
740 	}
741 	cgvm = VM_Create( "cgame", CL_CgameSystemCalls, interpret );
742 	if ( !cgvm ) {
743 		Com_Error( ERR_DROP, "VM_Create on cgame failed" );
744 	}
745 	cls.state = CA_LOADING;
746 
747 	// init for this gamestate
748 	// use the lastExecutedServerCommand instead of the serverCommandSequence
749 	// otherwise server commands sent just before a gamestate are dropped
750 	VM_Call( cgvm, CG_INIT, clc.serverMessageSequence, clc.lastExecutedServerCommand, clc.clientNum );
751 
752 	// reset any CVAR_CHEAT cvars registered by cgame
753 	if ( !clc.demoplaying && !cl_connectedToCheatServer )
754 		Cvar_SetCheatState();
755 
756 	// we will send a usercmd this frame, which
757 	// will cause the server to send us the first snapshot
758 	cls.state = CA_PRIMED;
759 
760 	t2 = Sys_Milliseconds();
761 
762 	Com_Printf( "CL_InitCGame: %5.2f seconds\n", (t2-t1)/1000.0 );
763 
764 	// have the renderer touch all its images, so they are present
765 	// on the card even if the driver does deferred loading
766 	re.EndRegistration();
767 
768 	// make sure everything is paged in
769 	if (!Sys_LowPhysicalMemory()) {
770 		Com_TouchMemory();
771 	}
772 
773 	// clear anything that got printed
774 	Con_ClearNotify ();
775 }
776 
777 
778 /*
779 ====================
780 CL_GameCommand
781 
782 See if the current console command is claimed by the cgame
783 ====================
784 */
CL_GameCommand(void)785 qboolean CL_GameCommand( void ) {
786 	if ( !cgvm ) {
787 		return qfalse;
788 	}
789 
790 	return VM_Call( cgvm, CG_CONSOLE_COMMAND );
791 }
792 
793 
794 
795 /*
796 =====================
797 CL_CGameRendering
798 =====================
799 */
CL_CGameRendering(stereoFrame_t stereo)800 void CL_CGameRendering( stereoFrame_t stereo ) {
801 	VM_Call( cgvm, CG_DRAW_ACTIVE_FRAME, cl.serverTime, stereo, clc.demoplaying );
802 	VM_Debug( 0 );
803 }
804 
805 
806 /*
807 =================
808 CL_AdjustTimeDelta
809 
810 Adjust the clients view of server time.
811 
812 We attempt to have cl.serverTime exactly equal the server's view
813 of time plus the timeNudge, but with variable latencies over
814 the internet it will often need to drift a bit to match conditions.
815 
816 Our ideal time would be to have the adjusted time approach, but not pass,
817 the very latest snapshot.
818 
819 Adjustments are only made when a new snapshot arrives with a rational
820 latency, which keeps the adjustment process framerate independent and
821 prevents massive overadjustment during times of significant packet loss
822 or bursted delayed packets.
823 =================
824 */
825 
826 #define	RESET_TIME	500
827 
CL_AdjustTimeDelta(void)828 void CL_AdjustTimeDelta( void ) {
829 	int		resetTime;
830 	int		newDelta;
831 	int		deltaDelta;
832 
833 	cl.newSnapshots = qfalse;
834 
835 	// the delta never drifts when replaying a demo
836 	if ( clc.demoplaying ) {
837 		return;
838 	}
839 
840 	// if the current time is WAY off, just correct to the current value
841 	if ( com_sv_running->integer ) {
842 		resetTime = 100;
843 	} else {
844 		resetTime = RESET_TIME;
845 	}
846 
847 	newDelta = cl.snap.serverTime - cls.realtime;
848 	deltaDelta = abs( newDelta - cl.serverTimeDelta );
849 
850 	if ( deltaDelta > RESET_TIME ) {
851 		cl.serverTimeDelta = newDelta;
852 		cl.oldServerTime = cl.snap.serverTime;	// FIXME: is this a problem for cgame?
853 		cl.serverTime = cl.snap.serverTime;
854 		if ( cl_showTimeDelta->integer ) {
855 			Com_Printf( "<RESET> " );
856 		}
857 	} else if ( deltaDelta > 100 ) {
858 		// fast adjust, cut the difference in half
859 		if ( cl_showTimeDelta->integer ) {
860 			Com_Printf( "<FAST> " );
861 		}
862 		cl.serverTimeDelta = ( cl.serverTimeDelta + newDelta ) >> 1;
863 	} else {
864 		// slow drift adjust, only move 1 or 2 msec
865 
866 		// if any of the frames between this and the previous snapshot
867 		// had to be extrapolated, nudge our sense of time back a little
868 		// the granularity of +1 / -2 is too high for timescale modified frametimes
869 		if ( com_timescale->value == 0 || com_timescale->value == 1 ) {
870 			if ( cl.extrapolatedSnapshot ) {
871 				cl.extrapolatedSnapshot = qfalse;
872 				cl.serverTimeDelta -= 2;
873 			} else {
874 				// otherwise, move our sense of time forward to minimize total latency
875 				cl.serverTimeDelta++;
876 			}
877 		}
878 	}
879 
880 	if ( cl_showTimeDelta->integer ) {
881 		Com_Printf( "%i ", cl.serverTimeDelta );
882 	}
883 }
884 
885 
886 /*
887 ==================
888 CL_FirstSnapshot
889 ==================
890 */
CL_FirstSnapshot(void)891 void CL_FirstSnapshot( void ) {
892 	// ignore snapshots that don't have entities
893 	if ( cl.snap.snapFlags & SNAPFLAG_NOT_ACTIVE ) {
894 		return;
895 	}
896 	cls.state = CA_ACTIVE;
897 
898 	// set the timedelta so we are exactly on this first frame
899 	cl.serverTimeDelta = cl.snap.serverTime - cls.realtime;
900 	cl.oldServerTime = cl.snap.serverTime;
901 
902 	clc.timeDemoBaseTime = cl.snap.serverTime;
903 
904 	// if this is the first frame of active play,
905 	// execute the contents of activeAction now
906 	// this is to allow scripting a timedemo to start right
907 	// after loading
908 	if ( cl_activeAction->string[0] ) {
909 		Cbuf_AddText( cl_activeAction->string );
910 		Cvar_Set( "activeAction", "" );
911 	}
912 
913 #ifdef USE_MUMBLE
914 	if ((cl_useMumble->integer) && !mumble_islinked()) {
915 		int ret = mumble_link(CLIENT_WINDOW_TITLE);
916 		Com_Printf("Mumble: Linking to Mumble application %s\n", ret==0?"ok":"failed");
917 	}
918 #endif
919 
920 #if USE_VOIP
921 	if (!clc.speexInitialized) {
922 		int i;
923 		speex_bits_init(&clc.speexEncoderBits);
924 		speex_bits_reset(&clc.speexEncoderBits);
925 		clc.speexEncoder = speex_encoder_init(&speex_nb_mode);
926 		for (i = 0; i < MAX_CLIENTS; i++) {
927 			speex_bits_init(&clc.speexDecoderBits[i]);
928 			speex_bits_reset(&clc.speexDecoderBits[i]);
929 			clc.speexDecoder[i] = speex_decoder_init(&speex_nb_mode);
930 			clc.voipIgnore[i] = qfalse;
931 			clc.voipGain[i] = 1.0f;
932 		}
933 		speex_encoder_ctl(clc.speexEncoder, SPEEX_GET_FRAME_SIZE,
934 		                  &clc.speexFrameSize);
935 		clc.speexInitialized = qtrue;
936 		clc.voipMuteAll = qfalse;
937 		Cmd_AddCommand ("voip", CL_Voip_f);
938 		Cvar_Set("cl_voipSendTarget", "all");
939 		clc.voipTarget1 = clc.voipTarget2 = clc.voipTarget3 = 0x7FFFFFFF;
940 	}
941 #endif
942 }
943 
944 /*
945 ==================
946 CL_SetCGameTime
947 ==================
948 */
CL_SetCGameTime(void)949 void CL_SetCGameTime( void ) {
950 	// getting a valid frame message ends the connection process
951 	if ( cls.state != CA_ACTIVE ) {
952 		if ( cls.state != CA_PRIMED ) {
953 			return;
954 		}
955 		if ( clc.demoplaying ) {
956 			// we shouldn't get the first snapshot on the same frame
957 			// as the gamestate, because it causes a bad time skip
958 			if ( !clc.firstDemoFrameSkipped ) {
959 				clc.firstDemoFrameSkipped = qtrue;
960 				return;
961 			}
962 			CL_ReadDemoMessage();
963 		}
964 		if ( cl.newSnapshots ) {
965 			cl.newSnapshots = qfalse;
966 			CL_FirstSnapshot();
967 		}
968 		if ( cls.state != CA_ACTIVE ) {
969 			return;
970 		}
971 	}
972 
973 	// if we have gotten to this point, cl.snap is guaranteed to be valid
974 	if ( !cl.snap.valid ) {
975 		Com_Error( ERR_DROP, "CL_SetCGameTime: !cl.snap.valid" );
976 	}
977 
978 	// allow pause in single player
979 	if ( sv_paused->integer && CL_CheckPaused() && com_sv_running->integer ) {
980 		// paused
981 		return;
982 	}
983 
984 	if ( cl.snap.serverTime < cl.oldFrameServerTime ) {
985 		Com_Error( ERR_DROP, "cl.snap.serverTime < cl.oldFrameServerTime" );
986 	}
987 	cl.oldFrameServerTime = cl.snap.serverTime;
988 
989 
990 	// get our current view of time
991 
992 	if ( clc.demoplaying && cl_freezeDemo->integer ) {
993 		// cl_freezeDemo is used to lock a demo in place for single frame advances
994 
995 	} else {
996 		// cl_timeNudge is a user adjustable cvar that allows more
997 		// or less latency to be added in the interest of better
998 		// smoothness or better responsiveness.
999 		int tn;
1000 
1001 		tn = cl_timeNudge->integer;
1002 		if (tn<-30) {
1003 			tn = -30;
1004 		} else if (tn>30) {
1005 			tn = 30;
1006 		}
1007 
1008 		cl.serverTime = cls.realtime + cl.serverTimeDelta - tn;
1009 
1010 		// guarantee that time will never flow backwards, even if
1011 		// serverTimeDelta made an adjustment or cl_timeNudge was changed
1012 		if ( cl.serverTime < cl.oldServerTime ) {
1013 			cl.serverTime = cl.oldServerTime;
1014 		}
1015 		cl.oldServerTime = cl.serverTime;
1016 
1017 		// note if we are almost past the latest frame (without timeNudge),
1018 		// so we will try and adjust back a bit when the next snapshot arrives
1019 		if ( cls.realtime + cl.serverTimeDelta >= cl.snap.serverTime - 5 ) {
1020 			cl.extrapolatedSnapshot = qtrue;
1021 		}
1022 	}
1023 
1024 	// if we have gotten new snapshots, drift serverTimeDelta
1025 	// don't do this every frame, or a period of packet loss would
1026 	// make a huge adjustment
1027 	if ( cl.newSnapshots ) {
1028 		CL_AdjustTimeDelta();
1029 	}
1030 
1031 	if ( !clc.demoplaying ) {
1032 		return;
1033 	}
1034 
1035 	// if we are playing a demo back, we can just keep reading
1036 	// messages from the demo file until the cgame definately
1037 	// has valid snapshots to interpolate between
1038 
1039 	// a timedemo will always use a deterministic set of time samples
1040 	// no matter what speed machine it is run on,
1041 	// while a normal demo may have different time samples
1042 	// each time it is played back
1043 	if ( cl_timedemo->integer ) {
1044 		int now = Sys_Milliseconds( );
1045 		int frameDuration;
1046 
1047 		if (!clc.timeDemoStart) {
1048 			clc.timeDemoStart = clc.timeDemoLastFrame = now;
1049 			clc.timeDemoMinDuration = INT_MAX;
1050 			clc.timeDemoMaxDuration = 0;
1051 		}
1052 
1053 		frameDuration = now - clc.timeDemoLastFrame;
1054 		clc.timeDemoLastFrame = now;
1055 
1056 		// Ignore the first measurement as it'll always be 0
1057 		if( clc.timeDemoFrames > 0 )
1058 		{
1059 			if( frameDuration > clc.timeDemoMaxDuration )
1060 				clc.timeDemoMaxDuration = frameDuration;
1061 
1062 			if( frameDuration < clc.timeDemoMinDuration )
1063 				clc.timeDemoMinDuration = frameDuration;
1064 
1065 			// 255 ms = about 4fps
1066 			if( frameDuration > UCHAR_MAX )
1067 				frameDuration = UCHAR_MAX;
1068 
1069 			clc.timeDemoDurations[ ( clc.timeDemoFrames - 1 ) %
1070 				MAX_TIMEDEMO_DURATIONS ] = frameDuration;
1071 		}
1072 
1073 		clc.timeDemoFrames++;
1074 		cl.serverTime = clc.timeDemoBaseTime + clc.timeDemoFrames * 50;
1075 	}
1076 
1077 	while ( cl.serverTime >= cl.snap.serverTime ) {
1078 		// feed another messag, which should change
1079 		// the contents of cl.snap
1080 		CL_ReadDemoMessage();
1081 		if ( cls.state != CA_ACTIVE ) {
1082 			return;		// end of demo
1083 		}
1084 	}
1085 
1086 }
1087 
1088 
1089 
1090