1 /*
2 Copyright (C) 2003-2006 Andrey Nazarov
3 
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8 
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12 
13 See the GNU General Public License for more details.
14 
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18 
19 */
20 
21 //
22 // mvd_client.c
23 //
24 
25 #include "server.h"
26 #include "mvd.h"
27 #include "version.h"
28 
29 mvd_t			mvd;
30 
31 // FIXME: these are used only for translating client_t into mvdClient_t
32 edict_t			mvd_edicts[MAX_CLIENTS + 1];
33 
34 cmdbuf_t	mvd_buffer;
35 byte		mvd_buffer_text[MAX_STRING_CHARS];
36 
37 cvar_t *mvd_buffer_size;
38 cvar_t *mvd_pause;
39 
40 void MVD_DPrintf( const char *fmt, ... )
41     __attribute__(( format( printf, 1, 2 ) ));
42 
MVD_DPrintf(const char * fmt,...)43 void MVD_DPrintf( const char *fmt, ... ) {
44 	va_list		argptr;
45 	char		text[MAXPRINTMSG];
46 
47 	if( !mvd_debug->integer ) {
48 		return;
49 	}
50 
51 	va_start( argptr, fmt );
52 	Q_vsnprintf( text, sizeof( text ), fmt, argptr );
53 	va_end( argptr );
54 
55 	Com_Printf( S_COLOR_BLUE "%s", text );
56 }
57 
MVD_ClientCommand(const char * string)58 void MVD_ClientCommand( const char *string ) {
59     if( !mvd.netchan ) {
60         return;
61     }
62     MSG_WriteByte( clc_stringcmd );
63     MSG_WriteString( string );
64     MSG_FlushTo( &mvd.netchan->message );
65 }
66 
MVD_ForwardToServer_f(void)67 void MVD_ForwardToServer_f( void ) {
68     if( mvd.state < MVD_CONNECTED ) {
69         Com_Printf( "Can't \"%s\", not connected\n", Cmd_Argv( 0 ) );
70         return;
71     }
72 
73     if( mvd.demoplayback ) {
74         return;
75     }
76 
77     // don't forward the first argument
78     if( Cmd_Argc() > 1 ) {
79         MVD_ClientCommand( Cmd_RawArgs() );
80     }
81 }
82 
83 /* called initially at ClientBegin */
MVD_GameSetValidPos(mvdClient_t * client)84 static void MVD_GameSetValidPos( mvdClient_t *client ) {
85 	mvdFrame_t *frame;
86 	player_state_t *ps;
87 	entityStateEx_t *ent;
88 	mvdGamestate_t *gs;
89 	int i, j;
90 
91 	ps = &client->ps;
92 	memset( ps, 0, sizeof( *ps ) );
93 
94 	if( client->admin ) {
95 		gs = &mvd.gamestates[mvd.gamestateSequence & GAMESTATE_MASK];
96 	} else {
97 		gs = &mvd.gamestates[mvd.activeGamestateSequence & GAMESTATE_MASK];
98 	}
99 
100 	if( gs->spawnSet ) {
101 		VectorScale( gs->spawnOrigin, 8, ps->pmove.origin );
102 		VectorCopy( gs->spawnAngles, ps->viewangles );
103 	} else {
104 		frame = &mvd.frames[mvd.activePacketNum % mvd.frameBackup];
105 		for( i = 0; i < frame->numEntityStates; i++ ) {
106 			j = ( frame->firstEntityState + i ) % mvd.maxEntityStates;
107 			ent = &mvd.entityStates[j];
108 			if( ent->s.solid != 31 ) {
109 				VectorScale( ent->s.origin, 8, ps->pmove.origin );
110 				break;
111 			}
112 		}
113 		if( i == frame->numEntityStates ) {
114 			Com_WPrintf( "Don't know where to spawn %s\n", client->cl->name );
115 		}
116 	}
117 
118 	ps->viewangles[ROLL] = 0;
119 	for( i = 0; i < 3; i++ ) {
120 		ps->pmove.delta_angles[i] = ANGLE2SHORT( ps->viewangles[i] ) -
121 			client->lastcmd.angles[i];
122 	}
123 
124 	ps->fov = client->fov;
125 	ps->pmove.pm_flags = client->pmflags;
126 	ps->pmove.pm_type = PM_SPECTATOR;
127 
128     client->clientNum = CLIENTNUM_NONE;
129 	client->savedClientNum = CLIENTNUM_NONE;
130 	client->followClientNum = CLIENTNUM_NONE;
131 	client->following = qfalse;
132 }
133 
MVD_GameStartObserving(mvdClient_t * client)134 static void MVD_GameStartObserving( mvdClient_t *client ) {
135 	player_state_t *ps;
136 	mvdPlayer_t *oldplayer;
137 	int i, length;
138 	int savedLayouts;
139 
140 	ps = &client->ps;
141 	ps->viewangles[ROLL] = 0;
142 	for( i = 0; i < 3; i++ ) {
143 		ps->pmove.delta_angles[i] = ANGLE2SHORT( ps->viewangles[i] ) -
144 			client->lastcmd.angles[i];
145 	}
146 
147 	VectorClear( ps->kick_angles );
148 
149 	ps->fov = client->fov;
150 	ps->blend[0] = 0;
151 	ps->blend[1] = 0;
152 	ps->blend[2] = 0;
153 	ps->blend[3] = 0;
154 	ps->pmove.pm_flags = client->pmflags;
155 	ps->pmove.pm_type = PM_SPECTATOR;
156 	ps->rdflags = 0;
157 	ps->gunindex = 0;
158 
159 	if( client->scoreboard <= SBOARD_FOLLOW ) {
160 		savedLayouts = 0;
161 	} else {
162 		savedLayouts = ps->stats[STAT_LAYOUTS];
163 	}
164 	for( i = 0; i < MAX_STATS; i++ ) {
165 		ps->stats[i] = 0;
166 	}
167 	ps->stats[STAT_HEALTH] = 100;
168 	ps->stats[STAT_LAYOUTS] = savedLayouts;
169 
170 	if( client->following && client->followClientNum != CLIENTNUM_NONE ) {
171 		oldplayer = &mvd.players[client->followClientNum];
172 		for( i = 0; i < MAX_CONFIGSTRINGS; i++ ) {
173 			if( oldplayer->configstrings[i] ) {
174 				MSG_WriteByte( svc_configstring );
175 				MSG_WriteShort( i );
176 				length = strlen( sv.configstrings[i] );
177 				if( length > MAX_QPATH ) {
178 					length = MAX_QPATH;
179 				}
180 				MSG_WriteData( sv.configstrings[i], length );
181 				MSG_WriteByte( 0 );
182 				SV_ClientAddMessage( client->cl, MSG_RELIABLE|MSG_CLEAR );
183 			}
184 		}
185 	}
186 
187     client->clientNum = CLIENTNUM_NONE;
188 	client->savedClientNum = client->followClientNum;
189 	client->followClientNum = CLIENTNUM_NONE;
190 	client->following = qfalse;
191 	client->savedFollowing = qfalse;
192 
193 	SV_ClientPrintf( client->cl, PRINT_MEDIUM,
194             "[MVD] Switched to freefloat mode.\n" );
195 }
196 
MVD_UpdateFollower(mvdClient_t * client,playerStateEx_t * src)197 void MVD_UpdateFollower( mvdClient_t *client, playerStateEx_t *src ) {
198 	player_state_t *ps = &client->ps;
199 
200 	*ps = src->ps;
201 	if( client->cl->protocol == PROTOCOL_VERSION_Q2PRO ) {
202 		if( client->cl->settings[CLS_LOCALFOV] ) {
203 			ps->fov = client->fov;
204 		}
205 	} else if( mvd_custom_fov->integer ) {
206 		ps->fov = client->fov;
207 	}
208 	ps->pmove.pm_flags &= ~PMF_TELEPORT_BIT;
209 	ps->pmove.pm_flags |= client->pmflags | PMF_NO_PREDICTION;
210 	ps->pmove.pm_type = PM_FREEZE;
211 	if( !client->admin ) {
212 		if( client->scoreboard > SBOARD_FOLLOW ) {
213 			ps->stats[STAT_LAYOUTS] = 1;
214 		} else if( client->scoreboard == SBOARD_NONE ) {
215 			ps->stats[STAT_LAYOUTS] = 0;
216 		}
217 	}
218     client->clientNum = src->clientNum;
219 }
220 
MVD_UpdateLayoutClients(mvdClient_t * client)221 static void MVD_UpdateLayoutClients( mvdClient_t *client ) {
222 	char layout[MAX_STRING_CHARS];
223 	char buffer[MAX_STRING_CHARS];
224 	char status[MAX_QPATH];
225 	static const char *header =
226 		"xl 32 yb -40 string2 \""APPLICATION" "VERSION"\" "
227 		"yb -32 string http://q2pro.sf.net "
228 		"xv 0 yv 0 string2 Name "
229 		"xv 152 string2 Ping "
230 		"xv 208 string2 Status ";
231 	int length, totalLength;
232 	client_t *cl;
233 	mvdClient_t *mvdcl;
234     char name[MAX_CLIENT_NAME];
235     char *s;
236 	int y;
237 
238 	strcpy( layout, header );
239 	totalLength = strlen( layout );
240 
241 	y = 8;
242     FOR_EACH_CLIENT( cl ) {
243 		if( cl->state < cs_connected ) {
244 			continue;
245 		}
246         if( cl->protocol == PROTOCOL_VERSION_MVD ) {
247             continue;
248         }
249 		if( cl->state == cs_spawned ) {
250 			mvdcl = ( mvdClient_t * )cl->edict->client;
251 			if( mvdcl->following ) {
252 				if( mvd.serverProtocol == PROTOCOL_VERSION_MVD ) {
253                     s = sv.configstrings[CS_PLAYERSKINS + mvdcl->followClientNum];
254                     Q_strncpyz( name, s, sizeof( name ) );
255                     s = strchr( name, '\\' );
256                     if( s ) {
257                         *s = 0;
258                     }
259 					Com_sprintf( status, sizeof( status ), "-> %s", name );
260 				} else {
261 					strcpy( status, "following" );
262 				}
263 			} else {
264 				strcpy( status, "observing" );
265 			}
266 		} else {
267 			strcpy( status, "connecting" );
268 		}
269 		length = Com_sprintf( buffer, sizeof( buffer ),
270 			"xv 0 yv %d string \"%.16s\" "
271 			"xv 152 string %d "
272 			"xv 208 string \"%s\" ",
273 			y, cl->name, cl->ping, status );
274 		if( totalLength + length > sizeof( layout ) - 1 ) {
275 			break;
276 		}
277 		strcpy( layout + totalLength, buffer );
278 		totalLength += length;
279 		y += 8;
280 	}
281 
282 	MSG_WriteByte( svc_layout );
283 	MSG_WriteString( layout );
284 
285 	SV_ClientAddMessage( client->cl, MSG_RELIABLE|MSG_CLEAR );
286 
287 	client->ps.stats[STAT_LAYOUTS] = 1;
288 	client->layoutTime = sv.time + LAYOUT_MSEC;
289 }
290 
MVD_UpdateLayoutScores(mvdClient_t * client)291 static void MVD_UpdateLayoutScores( mvdClient_t *client ) {
292 	mvdPlayer_t *player;
293 
294 	if( mvd.serverProtocol == PROTOCOL_VERSION_MVD ) {
295 		if( mvd.clientNum == CLIENTNUM_NONE ) {
296 			client->ps.stats[STAT_LAYOUTS] = 1;
297 			return;
298 		}
299 		player = &mvd.players[mvd.clientNum];
300 	} else {
301 		player = &mvd.players[0];
302 	}
303 	MSG_WriteByte( svc_layout );
304 	MSG_WriteString( player->layout );
305 	SV_ClientAddMessage( client->cl, MSG_RELIABLE|MSG_CLEAR );
306 
307 	client->ps.stats[STAT_LAYOUTS] = 1;
308 }
309 
MVD_SetDefaultLayout(mvdClient_t * client)310 static void MVD_SetDefaultLayout( mvdClient_t *client ) {
311 	/*if( mvd.serverProtocol == PROTOCOL_VERSION_MVD ) {
312 		client->scoreboard = SBOARD_FOLLOW;
313 		MVD_UpdateLayoutFollow( client );
314 	} else*/ {
315 		client->ps.stats[STAT_LAYOUTS] = 0;
316 		client->scoreboard = SBOARD_NONE;
317 	}
318 }
319 
MVD_GameStartFollowing(mvdClient_t * client,int playerNum)320 static void MVD_GameStartFollowing( mvdClient_t *client, int playerNum ) {
321 	mvdPlayer_t *player, *oldplayer;
322 	int i, j, length;
323     char name[MAX_CLIENT_NAME];
324     char *s;
325 	mvdFrame_t *frame;
326 	playerStateEx_t *ps = NULL;
327 
328 	if( client->admin ) {
329 		frame = &mvd.frames[mvd.validPacketNum % mvd.frameBackup];
330 	} else {
331 		frame = &mvd.frames[mvd.activePacketNum % mvd.frameBackup];
332 	}
333 
334 	if( !frame->numPlayerStates ) {
335 		SV_ClientPrintf( client->cl, PRINT_MEDIUM,
336 			"[MVD] No players to follow.\n" );
337 		if( client->following ) {
338 			MVD_GameStartObserving( client );
339 		}
340 		return;
341 	}
342 
343 	// find the desired player in current frame
344 	for( i = 0; i < frame->numPlayerStates; i++ ) {
345 		j = ( frame->firstPlayerState + i ) % mvd.maxPlayerStates;
346 		ps = &mvd.playerStates[j];
347 		if( ps->number == playerNum ) {
348 			break;
349 		}
350 	}
351 
352 	if( i == frame->numPlayerStates ) {
353 		// pick up the first player
354 		if( playerNum != CLIENTNUM_NONE ) {
355 			SV_ClientPrintf( client->cl, PRINT_MEDIUM,
356 				"[MVD] Player %d is not active.\n", playerNum );
357 		}
358 		j = frame->firstPlayerState % mvd.maxPlayerStates;
359 		ps = &mvd.playerStates[j];
360 		playerNum = ps->number;
361 	}
362 
363 	if( client->following && playerNum == client->followClientNum ) {
364 		return;
365 	}
366 
367 	player = &mvd.players[playerNum];
368 	oldplayer = NULL;
369 	if( client->following && client->followClientNum != CLIENTNUM_NONE ) {
370 		oldplayer = &mvd.players[client->followClientNum];
371 	}
372 
373 	client->savedClientNum = client->followClientNum;
374 	client->followClientNum = playerNum;
375 	client->following = qtrue;
376 
377 	client->pmflags ^= PMF_TELEPORT_BIT;
378 	MVD_UpdateFollower( client, ps );
379 
380 	if( mvd.serverProtocol == PROTOCOL_VERSION_MVD ) {
381         s = sv.configstrings[CS_PLAYERSKINS + playerNum];
382         Q_strncpyz( name, s, sizeof( name ) );
383         s = strchr( name, '\\' );
384         if( s ) {
385             *s = 0;
386         }
387 	} else {
388 		strcpy( name, "the camera" );
389 	}
390 
391 	SV_ClientPrintf( client->cl, PRINT_MEDIUM, "[MVD] Following %s.\n", name );
392 
393 	// send delta configstrings
394 	for( i = 0; i < MAX_CONFIGSTRINGS; i++ ) {
395 		if( player->configstrings[i] ) {
396 			MSG_WriteByte( svc_configstring );
397 			MSG_WriteShort( i );
398 			MSG_WriteString( player->configstrings[i] );
399 			SV_ClientAddMessage( client->cl, MSG_RELIABLE|MSG_CLEAR );
400 		} else if( oldplayer && oldplayer->configstrings[i] ) {
401 			MSG_WriteByte( svc_configstring );
402 			MSG_WriteShort( i );
403 			length = strlen( sv.configstrings[i] );
404 			if( length > MAX_QPATH ) {
405 				length = MAX_QPATH;
406 			}
407 			MSG_WriteData( sv.configstrings[i], length );
408 			MSG_WriteByte( 0 );
409 			SV_ClientAddMessage( client->cl, MSG_RELIABLE|MSG_CLEAR );
410 		}
411 	}
412 
413 	// send layout
414 	if( client->scoreboard == SBOARD_FOLLOW ) {
415 		MSG_WriteByte( svc_layout );
416 		MSG_WriteString( player->layout );
417 		SV_ClientAddMessage( client->cl, MSG_RELIABLE|MSG_CLEAR );
418 
419 		client->ps.stats[STAT_LAYOUTS] = ps->ps.stats[STAT_LAYOUTS] & 1;
420 	}
421 
422 }
423 
MVD_GameFollowCycle(mvdClient_t * client,int dir)424 static void MVD_GameFollowCycle( mvdClient_t *client, int dir ) {
425 	mvdFrame_t *frame;
426 	playerStateEx_t *ps;
427 	int i, j;
428 
429 	if( client->admin ) {
430 		frame = &mvd.frames[mvd.validPacketNum % mvd.frameBackup];
431 	} else {
432 		frame = &mvd.frames[mvd.activePacketNum % mvd.frameBackup];
433 	}
434 
435 	if( !frame->numPlayerStates ) {
436 		return;
437 	}
438 
439 	for( i = 0; i < frame->numPlayerStates; i++ ) {
440 		j = ( frame->firstPlayerState + i ) % mvd.maxPlayerStates;
441 		ps = &mvd.playerStates[j];
442 		if( ps->number == client->followClientNum ) {
443 			i += dir;
444 			break;
445 		}
446 	}
447 
448 	i %= frame->numPlayerStates;
449 	j = ( frame->firstPlayerState + i ) % mvd.maxPlayerStates;
450 	ps = &mvd.playerStates[j];
451 
452 	MVD_GameStartFollowing( client, ps->number );
453 }
454 
MVD_SetActiveState(void)455 static void MVD_SetActiveState( void ) {
456 	client_t *client;
457 
458 	mvd.state = MVD_ACTIVE;
459 
460     FOR_EACH_CLIENT( client ) {
461 		if( client->state != cs_ready ) {
462 			continue;
463 		}
464 		Com_DPrintf( "Going from cs_ready to cs_spawned for %s\n",
465                 client->name );
466 		client->state = cs_spawned;
467 		client->sendTime = 0;
468 		client->surpressCount = 0;
469 		client->commandMsec = 1800;
470 
471 		// call the game begin function
472 		sv_client = client;
473 		sv_player = client->edict;
474 		ge->ClientBegin( client->edict );
475 		sv_client = NULL;
476 		sv_player = NULL;
477 
478 	}
479 }
480 
481 typedef struct {
482 	byte *data;
483 	int mask;
484 	int offset;
485 	int last;
486 } mvdReadStruct_t;
487 
MVD_ReadByte(mvdReadStruct_t * msg)488 int MVD_ReadByte( mvdReadStruct_t *msg ) {
489 	int	c, mask;
490 	byte *data;
491 
492 	if( msg->offset + 1 > msg->last ) {
493 		c = -1;
494 	} else {
495 		data = msg->data;
496 		mask = msg->mask;
497 		c = ( unsigned char )data[msg->offset & mask];
498 	}
499 	msg->offset++;
500 
501 	return c;
502 }
503 
MVD_ReadShort(mvdReadStruct_t * msg)504 int MVD_ReadShort( mvdReadStruct_t *msg ) {
505 	int	c, mask, ofs;
506 	byte *data;
507 
508 	if( msg->offset + 2 > msg->last ) {
509 		c = -1;
510 	} else {
511 		mask = msg->mask;
512 		data = msg->data;
513 		ofs = msg->offset;
514 		c = ( short )( data[ofs & mask]
515 		+ ( data[( ofs + 1 ) & mask] << 8 ) );
516 	}
517 
518 	msg->offset += 2;
519 
520 	return c;
521 }
522 
MVD_ReadLong(mvdReadStruct_t * msg)523 int MVD_ReadLong( mvdReadStruct_t *msg ) {
524 	int	c, mask, ofs;
525 	byte *data;
526 
527 	if( msg->offset + 4 > msg->last ) {
528 		c = -1;
529 	} else {
530 		mask = msg->mask;
531 		data = msg->data;
532 		ofs = msg->offset;
533 		c = data[ofs & mask]
534 		+ ( data[( ofs + 1 ) & mask] << 8 )
535 		+ ( data[( ofs + 2 ) & mask] << 16 )
536 		+ ( data[( ofs + 3 ) & mask] << 24 );
537 	}
538 
539 	msg->offset += 4;
540 
541 	return c;
542 }
543 
MVD_ReadString(mvdReadStruct_t * msg)544 char *MVD_ReadString( mvdReadStruct_t *msg ) {
545 	static char	string[MAX_NET_STRING];
546 	int		l,c;
547 
548 	l = 0;
549 	do {
550 		c = MVD_ReadByte( msg );
551 		if( c == -1 || c == 0 ) {
552 			break;
553 		}
554 		if( c == 0xFF ) {
555 			c = '.';
556 		}
557 		string[l] = c;
558 		l++;
559 	} while( l < sizeof( string ) - 1 );
560 
561 	string[l] = 0;
562 
563 	return string;
564 }
565 
MVD_Multicast(qboolean unbuffered,vec3_t origin,multicast_t to)566 void MVD_Multicast( qboolean unbuffered, vec3_t origin, multicast_t to ) {
567 	client_t	*client;
568 	byte		*mask;
569 	cleaf_t		*leaf;
570 	int			cluster;
571 	int			area1, area2;
572 	int			flags;
573 	vec3_t		org;
574 	mvdClient_t *mvdcl;
575 	player_state_t	*ps;
576 	mvdGamestate_t *gs;
577 
578 	if( unbuffered ) {
579 		gs = &mvd.gamestates[mvd.gamestateSequence & GAMESTATE_MASK];
580 	} else {
581 		gs = &mvd.gamestates[mvd.activeGamestateSequence & GAMESTATE_MASK];
582 	}
583 
584 	flags = 0;
585 
586 	switch( to ) {
587 	case MULTICAST_ALL_R:
588 		flags |= MSG_RELIABLE;	// intentional fallthrough
589 	case MULTICAST_ALL:
590 		area1 = 0;
591 		cluster = 0;
592 		mask = NULL;
593 		break;
594 
595 	case MULTICAST_PHS_R:
596 		flags |= MSG_RELIABLE;	// intentional fallthrough
597 	case MULTICAST_PHS:
598 		leaf = CM_PointLeaf( &gs->cm, origin );
599 		area1 = CM_LeafArea( leaf );
600 		cluster = CM_LeafCluster( leaf );
601 		mask = CM_ClusterPHS( &gs->cm, cluster );
602 		break;
603 
604 	case MULTICAST_PVS_R:
605 		flags |= MSG_RELIABLE;	// intentional fallthrough
606 	case MULTICAST_PVS:
607 		leaf = CM_PointLeaf( &gs->cm, origin );
608 		area1 = CM_LeafArea( leaf );
609 		cluster = CM_LeafCluster( leaf );
610 		mask = CM_ClusterPVS( &gs->cm, cluster );
611 		break;
612 
613 	default:
614 		mask = NULL;
615 		area1 = 0;
616 		Com_Error( ERR_DROP, "MVD_Multicast: bad to: %i", to );
617 	}
618 
619 	// send the data to all relevent clients
620     FOR_EACH_CLIENT( client ) {
621 		if( client->state < cs_connected ) {
622 			continue;
623 		}
624         if( client->protocol == PROTOCOL_VERSION_MVD ) {
625             continue;
626         }
627 		mvdcl = ( mvdClient_t * )client->edict->client;
628 		if( mvdcl->admin != unbuffered ) {
629 			continue;
630 		}
631 
632 		if( !( flags & MSG_RELIABLE ) ) {
633 			/* do not send unreliables to connecting clients */
634 			if( client->state != cs_spawned || client->download || client->nodata ) {
635 				continue;
636 			}
637 		}
638 
639 		if( mask ) {
640 			// find the client's PVS
641 			ps = &client->edict->client->ps;
642 			VectorMA( ps->viewoffset, 0.125f, ps->pmove.origin, org );
643 			leaf = CM_PointLeaf( &gs->cm, org );
644 			area2 = CM_LeafArea( leaf );
645 			if( !CM_AreasConnected( &gs->cm, area1, area2 ) )
646 				continue;
647 			cluster = CM_LeafCluster( leaf );
648 			if( !Q_IsBitSet( mask, cluster ) ) {
649 				continue;
650 			}
651 		}
652 
653 		SV_ClientAddMessage( client, flags );
654 	}
655 
656 	/* clear the buffer */
657 	SZ_Clear( &msg_write );
658 
659 }
660 
MVD_FrameParseMulticast(mvdReadStruct_t * msg)661 static void MVD_FrameParseMulticast( mvdReadStruct_t *msg ) {
662 	multicast_t to;
663 	int length;
664     union {
665         vec_t v[3];
666         uint32 l[3];
667     } origin;
668 	int i, c;
669 
670 	length = MVD_ReadShort( msg );
671 	to = ( length >> 12 ) & 7;
672 	length &= 0xFFF;
673 
674 	if( to > MULTICAST_PVS_R ) {
675 		Com_Error( ERR_DROP, "MVD_FrameParseMulticast: bad to" );
676 	}
677 
678 	if( length < 1 ) {
679 		Com_Error( ERR_DROP, "MVD_FrameParseMulticast: bad length" );
680 	}
681 
682 	if( to != MULTICAST_ALL && to != MULTICAST_ALL_R ) {
683 		origin.l[0] = MVD_ReadLong( msg );
684 		origin.l[1] = MVD_ReadLong( msg );
685 		origin.l[2] = MVD_ReadLong( msg );
686 	} else {
687 		VectorClear( origin.v );
688 	}
689 
690 	if( msg->offset + length > msg->last ) {
691 		Com_Error( ERR_DROP,
692                 "MVD_FrameParseMulticast: read past end of message" );
693 	}
694 
695 	/* copy it byte-to-byte */
696 	for( i = 0; i < length; i++ ) {
697 		c = MVD_ReadByte( msg );
698 		MSG_WriteByte( c );
699 	}
700 
701 	MVD_Multicast( qfalse, origin.v, to );
702 
703 }
704 
MVD_FrameParseUnicast(mvdReadStruct_t * msg)705 static void MVD_FrameParseUnicast( mvdReadStruct_t *msg ) {
706 	int clientNum, length, last;
707 	int flags;
708 	client_t *client;
709 	mvdClient_t *gclient;
710 	mvdPlayer_t *player;
711 	int i, c, offset;
712 	char *s;
713 	qboolean gotLayout, wantLayout;
714 
715 	flags = 0;
716 	clientNum = MVD_ReadByte( msg );
717 	if( clientNum & 0x80 ) {
718 		flags |= MSG_RELIABLE;
719 	}
720 	clientNum &= 0x7F;
721 	length = MVD_ReadShort( msg );
722 
723     if( mvd_debug->integer > 1 ) {
724         Com_Printf( "Unicast to %d (%d bytes)\n", clientNum, length );
725     }
726 
727 	if( ( unsigned )clientNum >= mvd.maxPlayers ) {
728 		Com_Error( ERR_DROP, "MVD_FrameParseUnicast: bad clientNum" );
729 	}
730 
731 	if( length < 1 ) {
732 		Com_Error( ERR_DROP, "MVD_FrameParseUnicast: bad length" );
733 	}
734 
735 	last = msg->offset + length;
736 	if( last > msg->last ) {
737 		Com_Error( ERR_DROP, "MVD_FrameParseUnicast: read past end of message" );
738 	}
739 
740 	player = &mvd.players[clientNum];
741 
742 	gotLayout = qfalse;
743 
744 
745 	/* attempt to parse the datagram and find custom configstrings,
746      * layouts, etc. give up if unknown command byte is encountered */
747 	while( 1 ) {
748 		if( msg->offset > last ) {
749 			Com_Error( ERR_DROP,
750                     "MVD_FrameParseUnicast: read past end of message" );
751 		}
752 
753 		if( msg->offset == last ) {
754 			break;
755 		}
756 
757 		if( ( c = MVD_ReadByte( msg ) ) == -1 ) {
758 			break;
759 		}
760 
761         if( mvd_debug->integer > 1 ) {
762             Com_Printf( "%s\n", MSG_ServerCommandString( c ) );
763         }
764 
765 		switch( c ) {
766 		case svc_layout:
767 			s = MVD_ReadString( msg );
768 			Q_strncpyz( player->layout, s, sizeof( player->layout ) );
769 			gotLayout = qtrue;
770 			break;
771 		case svc_configstring:
772 			i = MVD_ReadShort( msg );
773 			s = MVD_ReadString( msg );
774 			if( ( unsigned )i >= MAX_CONFIGSTRINGS ) {
775 				Com_Error( ERR_DROP,
776                         "MVD_FrameParseUnicast: bad configstring index" );
777 			}
778 			if( player->configstrings[i] ) {
779 				Z_Free( player->configstrings[i] );
780 			}
781 			player->configstrings[i] = MVD_CopyString( s );
782 			MSG_WriteByte( svc_configstring );
783 			MSG_WriteShort( i );
784 			MSG_WriteString( s );
785 			break;
786 		case svc_print:
787 			i = MVD_ReadByte( msg );
788 			s = MVD_ReadString( msg );
789 			MSG_WriteByte( svc_print );
790 			MSG_WriteByte( i );
791 			MSG_WriteString( s );
792 			break;
793 		case svc_stufftext:
794 			s = MVD_ReadString( msg );
795 			MSG_WriteByte( svc_stufftext );
796 			MSG_WriteString( s );
797 			break;
798 		default:
799 			/* copy the rest byte-to-byte */
800 			MSG_WriteByte( c );
801 			for( offset = msg->offset; offset < last; offset++ ) {
802 				c = MVD_ReadByte( msg );
803 				MSG_WriteByte( c );
804 			}
805 			msg->offset = offset;
806 			goto breakOut;
807 		}
808 	}
809 
810 breakOut:
811 	/* send to all relevant clients */
812 	wantLayout = qfalse;
813     FOR_EACH_CLIENT( client ) {
814 		if( client->state < cs_spawned ) {
815 			continue;
816 		}
817         if( client->protocol == PROTOCOL_VERSION_MVD ) {
818             continue;
819         }
820 		gclient = ( mvdClient_t * )client->edict->client;
821 		if( gclient->admin ) {
822 			continue;
823 		}
824 		if( gclient->scoreboard == SBOARD_SCORES ) {
825 			if( mvd.serverProtocol != PROTOCOL_VERSION_MVD ||
826                     clientNum == mvd.clientNum )
827             {
828 				wantLayout = qtrue;
829 			}
830 		}
831 		if( !gclient->following ) {
832 			if( mvd.serverProtocol == PROTOCOL_VERSION_MVD &&
833                     clientNum == mvd.clientNum )
834             {
835 				SV_ClientAddMessage( client, flags );
836 			}
837 			continue;
838 		}
839 		if( gclient->followClientNum == clientNum ) {
840 			SV_ClientAddMessage( client, flags );
841 			if( gclient->scoreboard == SBOARD_FOLLOW ) {
842 				wantLayout = qtrue;
843 			}
844 		}
845 	}
846 
847 	SZ_Clear( &msg_write );
848 
849 	if( !gotLayout || !wantLayout ) {
850 		return;
851 	}
852 
853 	MSG_WriteByte( svc_layout );
854 	MSG_WriteString( player->layout );
855 
856     FOR_EACH_CLIENT( client ) {
857 		if( client->state < cs_spawned ) {
858 			continue;
859 		}
860         if( client->protocol == PROTOCOL_VERSION_MVD ) {
861             continue;
862         }
863 		gclient = ( mvdClient_t * )client->edict->client;
864 		if( gclient->admin ) {
865 			continue;
866 		}
867 		if( gclient->scoreboard == SBOARD_SCORES ) {
868 			if( mvd.serverProtocol != PROTOCOL_VERSION_MVD ||
869                     clientNum == mvd.clientNum )
870             {
871 				SV_ClientAddMessage( client, flags );
872 				continue;
873 			}
874 		}
875 		if( gclient->followClientNum == clientNum ) {
876 			if( gclient->scoreboard == SBOARD_FOLLOW ) {
877 				SV_ClientAddMessage( client, flags );
878 			}
879 		}
880 	}
881 
882 	SZ_Clear( &msg_write );
883 }
884 
MVD_FrameParseConfigstring(mvdReadStruct_t * msg)885 static void MVD_FrameParseConfigstring( mvdReadStruct_t *msg ) {
886 	int index, length;
887 	char *string;
888 	client_t *client;
889 	mvdClient_t *mvdcl;
890 
891 	index = MVD_ReadShort( msg );
892 	string = MVD_ReadString( msg );
893 
894 	if( ( unsigned )index >= MAX_CONFIGSTRINGS ) {
895 		Com_Error( ERR_DROP,
896 			"MVD_FrameParseConfigstring: bad index: %d\n", index );
897 	}
898 
899 	length = strlen( string );
900 
901 	if( sizeof( sv.configstrings[0] ) * index + length >
902 		sizeof( sv.configstrings ) - 1 )
903 	{
904 		Com_Error( ERR_DROP,
905 			"MVD_FrameParseConfigstring: oversize configstring: %d", index );
906 	}
907 
908 	if( !strcmp( sv.configstrings[index], string ) ) {
909 		return;
910 	}
911 
912 	strcpy( sv.configstrings[index], string );
913 
914 	MSG_WriteByte( svc_configstring );
915 	MSG_WriteShort( index );
916 	MSG_WriteString( string );
917 
918     FOR_EACH_CLIENT( client ) {
919 		if( client->state < cs_connected ) {
920 			continue;
921 		}
922         if( client->protocol == PROTOCOL_VERSION_MVD ) {
923             continue;
924         }
925 		mvdcl = ( mvdClient_t * )client->edict->client;
926 		if( mvdcl->admin ) {
927 			continue;
928 		}
929 		SV_ClientAddMessage( client, MSG_RELIABLE );
930 	}
931 
932 	SZ_Clear( &msg_write );
933 }
934 
MVD_FrameParseMessages(mvdReadStruct_t * msg)935 static void MVD_FrameParseMessages( mvdReadStruct_t *msg ) {
936 	int cmd;
937 
938 //
939 // parse the message
940 //
941 	while( 1 ) {
942 		if( msg->offset > msg->last ) {
943 			Com_Error( ERR_DROP,
944                     "MVD_FrameParseMessages: read past end of message" );
945 		}
946 
947 		if( ( cmd = MVD_ReadByte( msg ) ) == -1 ) {
948 			break;
949 		}
950 
951 //		MVD_ShowSVC(cmd);
952 
953 		switch( cmd ) {
954 		case svc_multicast:
955 			MVD_FrameParseMulticast( msg );
956 			break;
957 		case svc_unicast:
958 			MVD_FrameParseUnicast( msg );
959 			break;
960 		case svc_configstring:
961 			MVD_FrameParseConfigstring( msg );
962 			break;
963 		default:
964 			Com_Error( ERR_DROP,
965                     "MVD_FrameParseMessages: illegible command: %d", cmd );
966 			break;
967 		}
968 	}
969 }
970 
MVD_TransitionGamestate(int sequence)971 void MVD_TransitionGamestate( int sequence ) {
972 	mvdConfigstring_t *cs, *nextcs;
973 	mvdGamestate_t *gs;
974 	mvdPlayer_t *player, *last;
975 	client_t *client;
976 	mvdClient_t *mvdcl;
977 	int i, j;
978 
979 	Com_Printf( "------- MVD_TransitionGamestate -------\n" );
980 
981 	MVD_DPrintf( "Going from %d to %d (frame %d)\n",
982 		mvd.activeGamestateSequence, sequence, mvd.activePacketNum );
983 
984 	Cvar_Set( "timedemo", "0" );
985 	Cvar_Set( "sv_paused", "0" );
986 
987 	if( sequence < mvd.activeGamestateSequence ) {
988 		Com_Error( ERR_DROP, "MVD_TransitionGamestate: sequence < active" );
989 	}
990 
991 	/* free old gamestate */
992 	for( j = mvd.activeGamestateSequence; j < sequence; j++ ) {
993 		gs = &mvd.gamestates[j & GAMESTATE_MASK];
994 
995 		for( i = 0; i < SV_BASELINES_CHUNKS; i++ ) {
996 			if( gs->baselines[i] ) {
997 				Z_Free( gs->baselines[i] );
998 			}
999 		}
1000 		for( cs = gs->headCS; cs; cs = nextcs ) {
1001 			nextcs = cs->next;
1002 			Z_Free( cs );
1003 		}
1004 		CM_FreeMap( &gs->cm );
1005 		memset( gs, 0, sizeof( *gs ) );
1006 	}
1007 
1008 	gs = &mvd.gamestates[sequence & GAMESTATE_MASK];
1009 	mvd.activeGamestateSequence = sequence;
1010 
1011 	/* reset player slots */
1012 	last = mvd.players + mvd.maxPlayers;
1013 	for( player = mvd.players; player != last; player++ ) {
1014 		for( i = 0; i < MAX_CONFIGSTRINGS; i++ ) {
1015 			if( player->configstrings[i] ) {
1016 				Z_Free( player->configstrings[i] );
1017 			}
1018 		}
1019 		memset( player, 0, sizeof( *player ) );
1020 	}
1021 
1022 	MSG_WriteByte( svc_stufftext );
1023 	MSG_WriteString( "changing\n" );
1024 
1025     FOR_EACH_CLIENT( client ) {
1026 		if( client->state < cs_connected ) {
1027 			continue;
1028 		}
1029 		if( client->protocol == PROTOCOL_VERSION_MVD ) {
1030 			continue;
1031 		}
1032 		mvdcl = ( mvdClient_t * )client->edict->client;
1033 		if( mvdcl->admin ) {
1034 			continue;
1035 		}
1036 
1037 		memset( &mvdcl->lastcmd, 0, sizeof( mvdcl->lastcmd ) );
1038 
1039 		client->state = cs_connected;
1040 		client->lastframe = -1;
1041 		client->sendTime = 0;
1042 		client->surpressCount = 0;
1043 
1044 		SV_ClientAddMessage( client, MSG_RELIABLE );
1045 	}
1046 
1047 	SZ_Clear( &msg_write );
1048 
1049     SV_SendAsyncPackets();
1050 
1051 	memset( sv.configstrings, 0, sizeof( sv.configstrings ) );
1052 
1053 	i = strlen( gs->mapname );
1054 	if( i > 9 ) {
1055 		Q_strncpyz( sv.name, gs->mapname + 5, sizeof( sv.name ) ); // skip "maps/"
1056 		sv.name[i - 9] = 0; // cut off ".bsp"
1057 	} else {
1058 		Q_strncpyz( sv.name, gs->mapname, sizeof( sv.name ) );
1059 	}
1060 
1061 	Com_Printf( "Map         : %s\n", sv.name );
1062 	Com_Printf( "Max players : %d\n", gs->maxclients );
1063 
1064 	svs.spawncount = ( rand() | ( rand() << 16 ) ) ^ Sys_Realtime();
1065 	svs.spawncount &= 0x7FFFFFFF;	// any partially connected client will be
1066 									// restarted
1067 
1068 	/* set up configstrings */
1069 	for( cs = gs->headCS; cs; cs = cs->next ) {
1070 		strcpy( sv.configstrings[cs->index], cs->string );
1071 	}
1072 
1073 	MSG_WriteByte( svc_stufftext );
1074 	MSG_WriteString( "reconnect\n" );
1075 
1076     FOR_EACH_CLIENT( client ) {
1077 		if( client->state < cs_connected ) {
1078 			continue;
1079 		}
1080 		if( client->protocol == PROTOCOL_VERSION_MVD ) {
1081 			continue;
1082 		}
1083 		mvdcl = ( mvdClient_t * )client->edict->client;
1084 		if( mvdcl->admin ) {
1085 			continue;
1086 		}
1087 
1088 		SV_ClientAddMessage( client, MSG_RELIABLE );
1089 	}
1090 
1091 	SZ_Clear( &msg_write );
1092 
1093 	/* set serverinfo variable */
1094 	Cvar_FullSet( "mapname", sv.name, CVAR_SERVERINFO|CVAR_NOSET, CVAR_SET_DIRECT );
1095 
1096 	Cvar_SetInteger( "sv_running", ss_broadcast );
1097 	Cvar_SetInteger( "sv_paused", 0 );
1098 
1099 	sv.state = ss_broadcast;
1100 
1101 	Com_Printf( "---------------------------------------\n" );
1102 }
1103 
1104 #define RESET_DELTA		16
1105 
MVD_DriftTime(void)1106 static void MVD_DriftTime( void ) {
1107 	int delta, drift;
1108 
1109 	delta = mvd.serverPacketNum - mvd.activePacketNum + 1;
1110 	drift = mvd_buffer_size->integer - delta;
1111 	clamp( drift, -RESET_DELTA, RESET_DELTA );
1112 
1113 	if( mvd_debug->integer > 2 ) {
1114 		Com_Printf( "MVD_DriftTime: frame=%d delta=%d ",
1115                 mvd.activePacketNum, delta );
1116 		if( drift > 0 ) {
1117 			Com_Printf( "[fast]\n" );
1118 		} else if( drift < 0 ) {
1119 			Com_Printf( "[slow]\n" );
1120 		} else {
1121 			Com_Printf( "\n" );
1122 		}
1123 	}
1124 
1125 	sv.time += drift;
1126 }
1127 
MVD_TransitionFrame(mvdFrame_t * frame)1128 static void MVD_TransitionFrame( mvdFrame_t *frame ) {
1129 	mvdReadStruct_t msg;
1130 	mvdGamestate_t *gs;
1131 
1132 	/* add unreliable datagram messages present in this frame */
1133 	if( frame->numMessageBytes ) {
1134 		msg.data = mvd.messageBytes;
1135 		msg.mask = mvd.maxMessageBytes - 1;
1136 		msg.offset = frame->firstMessageByte;
1137 		msg.last = frame->firstMessageByte + frame->numMessageBytes;
1138 		if( mvd_debug->integer > 1 ) {
1139 			Com_Printf( "Adding %d bytes of unreliable messages\n",
1140 					msg.last - msg.offset );
1141 		}
1142 		MVD_FrameParseMessages( &msg );
1143 	}
1144 
1145 	/* update areaportals */
1146 	if( mvd.serverProtocol == PROTOCOL_VERSION_MVD ) {
1147 		gs = &mvd.gamestates[mvd.activeGamestateSequence & GAMESTATE_MASK];
1148 		CM_SetPortalStates( &gs->cm, frame->portalbytes, frame->numPortalBytes );
1149 	}
1150 }
1151 
1152 /*
1153 MVD delay buffer:
1154                               mvd_buffer_size
1155 |          |<------------------------------------------------->|
1156 |__________|__________|________________________________________|
1157 |    16    |    16    |                                        |
1158 |<-------->|<-------->|                                        |
1159 A          B          C                                        D
1160 
1161 If mvd.state == MVD_BUFFERING, do nothing until we are beyond point B.
1162 If mvd.state == MVD_ACTIVE and we are between A and C, try to reach
1163 point B by slowly drifting sv.time.
1164 If we are ahead point C, restart buffering (with a 16 frames hysteresis).
1165 If we are beyond point A, or we have run out of entityState or playerState
1166 buffers, explicitly set mvd.activePacketNum at point B.
1167 
1168 When playing back a demo, just run towards point D and do nothing else.
1169 */
MVD_SetNextFrame(void)1170 static void MVD_SetNextFrame( void ) {
1171 	mvdFrame_t		*frame;
1172 	mvdReadStruct_t msg;
1173 	int delta;
1174 
1175 	if( mvd.state < MVD_BUFFERING ) {
1176 		return;
1177 	}
1178 
1179 	delta = mvd.serverPacketNum - mvd.activePacketNum;
1180 	if( !mvd.demoplayback ) {
1181 		if( delta < mvd_buffer_size->integer - RESET_DELTA &&
1182                 mvd.state == MVD_ACTIVE )
1183         {
1184 			/* start buffering again */
1185 			mvd.state = MVD_BUFFERING;
1186 			MVD_DPrintf( "Restarted buffering at frame %d, delta is %d\n",
1187                     mvd.serverPacketNum, delta );
1188             return;
1189 		}
1190 		if( delta < mvd_buffer_size->integer && mvd.state == MVD_BUFFERING ) {
1191 			MVD_DPrintf( "Still buffering at frame %d, delta is %d\n",
1192                     mvd.serverPacketNum, delta );
1193 			return;
1194 		}
1195 	}
1196 
1197 	if( delta > mvd.frameBackup - 1 ) {
1198 		MVD_DPrintf( "MVD_SetNextFrame: frame %d is too old, delta is %d\n",
1199                 mvd.activePacketNum, delta );
1200 		mvd.activePacketNum = mvd.serverPacketNum - mvd_buffer_size->integer;
1201 	}
1202 
1203 	frame = NULL;
1204 	while( mvd.activePacketNum < mvd.serverPacketNum ) {
1205         mvd.activePacketNum++;
1206 		frame = &mvd.frames[mvd.activePacketNum % mvd.frameBackup];
1207 
1208 		if( frame->serverPacketNum != mvd.activePacketNum ) {
1209 			MVD_DPrintf( "MVD_SetNextFrame: %d: never received\n",
1210                     mvd.activePacketNum );
1211 			continue;
1212 		}
1213 
1214 		/* got new gamestate? */
1215 		if( frame->gamestateSequence != mvd.activeGamestateSequence ) {
1216 			MVD_TransitionGamestate( frame->gamestateSequence );
1217 		}
1218 
1219 		/* does this frame contain svc_frame? */
1220 		if( !( frame->flags & MFF_ACTIVE ) ) {
1221 			continue;
1222 		}
1223 
1224 		if( !( frame->flags & MFF_VALID ) ) {
1225 			MVD_DPrintf( "MVD_SetNextFrame: %d: invalid frame\n",
1226                     mvd.activePacketNum );
1227 			continue;
1228 		}
1229 
1230 		if( mvd.nextEntityStates - frame->firstEntityState >
1231                 mvd.maxEntityStates )
1232         {
1233 			MVD_DPrintf( "MVD_SetNextFrame: %d: entityStates too old\n",
1234                     mvd.activePacketNum );
1235 			continue;
1236 		}
1237 		if( mvd.nextPlayerStates - frame->firstPlayerState >
1238                 mvd.maxPlayerStates )
1239         {
1240 			MVD_DPrintf( "MVD_SetNextFrame: %d: playerStates too old\n",
1241                     mvd.activePacketNum );
1242 			continue;
1243 		}
1244 
1245 		if( mvd.nextMessageBytes - frame->firstMessageByte >
1246                 mvd.maxMessageBytes )
1247         {
1248 			/* FIXME: use this frame anyway? */
1249 			MVD_DPrintf( "MVD_SetNextFrame: %d: messages too old\n",
1250                     mvd.activePacketNum );
1251 			continue;
1252 		}
1253 
1254 		if( !mvd.demoplayback ) {
1255 			MVD_DriftTime();
1256 		}
1257 
1258 		/* advance server state to this frame */
1259         mvd.prevPacketNum = mvd.activePacketNum - 1;
1260 		MVD_TransitionFrame( frame );
1261 
1262 		/* getting a valid frame message ends the buffering process */
1263 		if( mvd.state == MVD_BUFFERING ) {
1264 			delta = mvd.serverPacketNum - mvd.activePacketNum;
1265 			MVD_DPrintf( "Finished buffering at frame %d, delta is %d\n",
1266                     mvd.serverPacketNum, delta );
1267 			MVD_SetActiveState();
1268 		}
1269 
1270 		break;
1271 
1272 	}
1273 
1274 	if( !frame ) {
1275 		return;
1276 	}
1277 
1278 	/* add pending reliable datagram messages */
1279 	msg.data = mvd.reliableMessageBytes;
1280 	msg.mask = mvd.maxReliableMessageBytes - 1;
1281 	msg.offset = mvd.lastReliableMessageBytes;
1282 	msg.last = frame->firstReliableMessageByte + frame->numReliableMessageBytes;
1283 	if( msg.last == msg.offset ) {
1284 		return;
1285 	}
1286 
1287 	if( msg.last < msg.offset ) {
1288 		if( mvd.demoplayback ) {
1289 			/* this is normal if demo was just played backwards */
1290 			return;
1291 		}
1292 		Com_Error( ERR_DROP,
1293                 "MVD_SetNextFrame: reliable messages went backwards" );
1294 	}
1295 
1296 	if( mvd.nextReliableMessageBytes - mvd.lastReliableMessageBytes >
1297             mvd.maxReliableMessageBytes )
1298     {
1299 		Com_Error( ERR_DROP, "MVD_SetNextFrame: dropped reliable messages" );
1300 	}
1301 
1302 	if( mvd_debug->integer > 1 ) {
1303 		Com_Printf( "Adding %d bytes of reliable messages: %d --> %d\n",
1304 			msg.last - msg.offset, msg.offset, msg.last );
1305 	}
1306 	MVD_FrameParseMessages( &msg );
1307 	mvd.lastReliableMessageBytes = msg.last;
1308 }
1309 
1310 /* used for playing demo buffer backwards */
MVD_SetPrevFrame(void)1311 static void MVD_SetPrevFrame( void ) {
1312 	mvdFrame_t		*frame;
1313 
1314 	while( mvd.activePacketNum > 0 &&
1315             mvd.serverPacketNum - mvd.activePacketNum < mvd.frameBackup - 1 )
1316     {
1317 		mvd.activePacketNum--;
1318 		frame = &mvd.frames[mvd.activePacketNum % mvd.frameBackup];
1319 
1320 		if( frame->serverPacketNum != mvd.activePacketNum ) {
1321 			MVD_DPrintf( "MVD_SetPrevFrame: %d: never received\n",
1322                     mvd.activePacketNum );
1323 			continue;
1324 		}
1325 
1326 		/* got new gamestate? */
1327 		if( frame->gamestateSequence != mvd.activeGamestateSequence ) {
1328 			MVD_DPrintf( "MVD_SetPrevFrame: different gamestateSequence\n" );
1329 		    mvd.activePacketNum++;
1330 			break;
1331 		}
1332 
1333 		/* does this frame contain svc_frame? */
1334 		if( !( frame->flags & MFF_ACTIVE ) ) {
1335 			continue;
1336 		}
1337 
1338 		if( !( frame->flags & MFF_VALID ) ) {
1339 			MVD_DPrintf( "MVD_SetPrevFrame: %d: invalid frame\n",
1340                     mvd.activePacketNum );
1341 			continue;
1342 		}
1343 
1344 		if( mvd.nextEntityStates - frame->firstEntityState >
1345                 mvd.maxEntityStates )
1346         {
1347 			MVD_DPrintf( "MVD_SetPrevFrame: %d: entityStates too old\n",
1348                     mvd.activePacketNum );
1349 		    mvd.activePacketNum++;
1350 			break;
1351 		}
1352 		if( mvd.nextPlayerStates - frame->firstPlayerState >
1353                 mvd.maxPlayerStates )
1354         {
1355 			MVD_DPrintf( "MVD_SetPrevFrame: %d: playerStates too old\n",
1356                     mvd.activePacketNum );
1357 		    mvd.activePacketNum++;
1358 			break;
1359 		}
1360 
1361 		if( mvd.nextMessageBytes - frame->firstMessageByte >
1362                 mvd.maxMessageBytes )
1363         {
1364 			MVD_DPrintf( "MVD_SetPrevFrame: %d: messages too old\n",
1365                     mvd.activePacketNum );
1366 		    mvd.activePacketNum++;
1367 			break;
1368 		}
1369 
1370 		/* advance server state to this frame */
1371         mvd.prevPacketNum = mvd.activePacketNum + 1;
1372 		MVD_TransitionFrame( frame );
1373 		break;
1374 	}
1375 
1376 }
1377 
MVD_BackwardsDown_f(void)1378 void MVD_BackwardsDown_f( void ) {
1379 	mvd.demobackwards = qtrue;
1380 }
1381 
MVD_BackwardsUp_f(void)1382 void MVD_BackwardsUp_f( void ) {
1383 	mvd.demobackwards = qfalse;
1384 }
1385 
MVD_GameInit(void)1386 static void MVD_GameInit( void ) {
1387 	int i;
1388 
1389 	Com_Printf( "----- MVD_GameInit -----\n" );
1390 
1391 	mvd.clients = Z_TagMallocz( sizeof( mvdClient_t ) * sv_maxclients->integer,
1392             TAG_GAME );
1393 
1394 	mvd.players = MVD_Mallocz( sizeof( mvdPlayer_t ) * mvd.maxPlayers );
1395 
1396 	/* allocate delay buffers */
1397 	Cvar_ClampInteger( mvd_buffer_size, RESET_DELTA, 1024 );
1398 
1399 	mvd.frameBackup = mvd_buffer_size->integer + RESET_DELTA;
1400 	Com_DPrintf( "Delay buffer of %d frames total\n", mvd.frameBackup );
1401 
1402 	mvd.frames = MVD_Mallocz( sizeof( mvdFrame_t ) * mvd.frameBackup );
1403 	mvd.maxEntityStates = MAX_EDICTS * mvd.frameBackup;
1404 	mvd.maxPlayerStates = mvd.maxPlayers * mvd.frameBackup;
1405 
1406 	mvd.entityStates = MVD_Mallocz( sizeof( entityStateEx_t ) *
1407             mvd.maxEntityStates );
1408 	mvd.playerStates = MVD_Mallocz( sizeof( playerStateEx_t ) *
1409             mvd.maxPlayerStates );
1410 
1411 	i = 256 * mvd.frameBackup; /* TODO */
1412 	mvd.maxMessageBytes = Q_CeilPowerOfTwo( i );
1413 	mvd.nextMessageBytes = 0;
1414 	mvd.messageBytes = MVD_Mallocz( mvd.maxMessageBytes );
1415 
1416 	i = 256 * mvd.maxPlayers * mvd.frameBackup; /* TODO */
1417 	mvd.maxReliableMessageBytes = Q_CeilPowerOfTwo( i );
1418 	mvd.nextReliableMessageBytes = 0;
1419 	mvd.reliableMessageBytes = MVD_Mallocz( mvd.maxReliableMessageBytes );
1420 
1421 	/* prepare client slots */
1422 	for( i = 0; i < sv_maxclients->integer; i++ ) {
1423 		mvd_edicts[i + 1].client = ( gclient_t * )&mvd.clients[i];
1424 		mvd.clients[i].cl = &svs.clientpool[i];
1425 	}
1426 }
1427 
MVD_GameShutdown(void)1428 static void MVD_GameShutdown( void ) {
1429 	Com_Printf( "----- MVD_GameShutdown -----\n" );
1430 
1431 	mvd_ge.num_edicts = 0;
1432     MVD_Disconnect();
1433 
1434 }
1435 
MVD_GameSpawnEntities(char * mapname,char * entstring,char * spawnpoint)1436 void MVD_GameSpawnEntities( char *mapname, char *entstring, char *spawnpoint ) {
1437 }
MVD_GameWriteGame(char * filename,qboolean autosave)1438 static void MVD_GameWriteGame( char *filename, qboolean autosave ) {
1439 }
MVD_GameReadGame(char * filename)1440 static void MVD_GameReadGame( char *filename ) {
1441 }
MVD_GameWriteLevel(char * filename)1442 static void MVD_GameWriteLevel( char *filename ) {
1443 }
MVD_GameReadLevel(char * filename)1444 static void MVD_GameReadLevel( char *filename ) {
1445 }
1446 
MVD_GameClientConnect(edict_t * ent,char * userinfo)1447 static qboolean MVD_GameClientConnect( edict_t *ent, char *userinfo ) {
1448 	mvdClient_t *client;
1449 
1450 	client = ( mvdClient_t * )ent->client;
1451 
1452 	if( client->cl->protocol != PROTOCOL_VERSION_MVD ) {
1453 		SV_BroadcastPrintf( PRINT_HIGH, "[MVD] %s connected\n",
1454 			Info_ValueForKey( userinfo, "name" ) );
1455 	}
1456 	return qtrue;
1457 }
1458 
MVD_GameClientBegin(edict_t * ent)1459 static void MVD_GameClientBegin( edict_t *ent ) {
1460 	mvdClient_t *client;
1461 	char *s;
1462 
1463 	client = ( mvdClient_t * )ent->client;
1464 	client->savedClientNum = CLIENTNUM_NONE;
1465 
1466 	client->floodTime = 0;
1467 	client->floodHead = 0;
1468 
1469 	if( client->cl->protocol == PROTOCOL_VERSION_MVD ) {
1470 		client->connected = qtrue;
1471 		return;
1472 	}
1473 
1474 	if( !client->connected ) {
1475 		SV_BroadcastPrintf( PRINT_HIGH, "[MVD] %s entered the server\n",
1476             client->cl->name );
1477 		client->connected = qtrue;
1478 	}
1479 
1480 	if( mvd_motd->string[0] ) {
1481 		s = Cmd_MacroExpandString( mvd_motd->string, qfalse );
1482 		if( !s ) {
1483 			Com_WPrintf( "Macro expansion of mvd_motd failed\n" );
1484 			Cvar_Set( "mvd_motd", "" );
1485 		} else {
1486 			s = Q_UnescapeString( s );
1487 			MSG_WriteByte( svc_centerprint );
1488 			MSG_WriteString( s );
1489 			SV_ClientAddMessage( client->cl, MSG_RELIABLE|MSG_CLEAR );
1490 		}
1491 	}
1492 
1493 	MVD_GameSetValidPos( client );
1494     if( mvd.serverProtocol != PROTOCOL_VERSION_MVD ) {
1495     	MVD_GameStartFollowing( client, CLIENTNUM_NONE );
1496     }
1497 	MVD_SetDefaultLayout( client );
1498 }
1499 
MVD_GameClientUserinfoChanged(edict_t * ent,char * userinfo)1500 static void MVD_GameClientUserinfoChanged( edict_t *ent, char *userinfo ) {
1501 	mvdClient_t *client;
1502 	float fov;
1503 
1504 	client = ( mvdClient_t * )ent->client;
1505 	fov = atof( Info_ValueForKey( userinfo, "fov" ) );
1506 	if( fov < 1 ) {
1507 		fov = 90;
1508 	} else if( fov > 160 ) {
1509 		fov = 160;
1510 	}
1511 	client->fov = fov;
1512 	if( !client->following ) {
1513 		client->ps.fov = fov;
1514 	}
1515 }
1516 
MVD_GameClientDisconnect(edict_t * ent)1517 static void MVD_GameClientDisconnect( edict_t *ent ) {
1518 	mvdClient_t *client;
1519 	client_t *cl;
1520 
1521 	client = ( mvdClient_t * )ent->client;
1522 	cl = client->cl;
1523 	memset( client, 0, sizeof( *client ) );
1524 	client->cl = cl;
1525 
1526 	if( client->cl->protocol != PROTOCOL_VERSION_MVD ) {
1527 		SV_BroadcastPrintf( PRINT_HIGH, "[MVD] %s disconnected\n", cl->name );
1528 	}
1529 }
1530 
MVD_StartAdmin(mvdClient_t * client)1531 static void MVD_StartAdmin( mvdClient_t *client ) {
1532 	int i, length;
1533 	mvdFrame_t *src, *dst;
1534 	playerStateEx_t *ps;
1535 
1536 	src = &mvd.frames[mvd.activePacketNum % mvd.frameBackup];
1537 	dst = &mvd.frames[mvd.validPacketNum % mvd.frameBackup];
1538 
1539 	if( src->gamestateSequence != dst->gamestateSequence ) {
1540 		MSG_WriteByte( svc_stufftext );
1541 		MSG_WriteString( "changing; reconnect\n" );
1542 		SV_ClientAddMessage( client->cl, MSG_RELIABLE|MSG_CLEAR );
1543 		client->cl->state = cs_connected;
1544 		client->admin = qtrue;
1545 		return;
1546 	}
1547 
1548 	/* write delta configstrings */
1549 	for( i = 0; i < MAX_CONFIGSTRINGS; i++ ) {
1550 		length = strlen( mvd.configstrings[i] );
1551 		if( !length && sv.configstrings[i][0] ) {
1552 			MSG_WriteByte( svc_configstring );
1553 			MSG_WriteShort( i );
1554 			MSG_WriteByte( 0 );
1555 			continue;
1556 		}
1557 		if( length > MAX_QPATH ) {
1558 			length = MAX_QPATH;
1559 		}
1560 		if( strncmp( sv.configstrings[i], mvd.configstrings[i], length ) ) {
1561 			MSG_WriteByte( svc_configstring );
1562 			MSG_WriteShort( i );
1563 			MSG_WriteData( mvd.configstrings[i], length );
1564 			MSG_WriteByte( 0 );
1565 		}
1566 	}
1567 
1568 	ps = &mvd.playerStates[dst->firstPlayerState % mvd.maxPlayerStates];
1569 
1570 #if 0
1571 	client->delta_angles[0] = ANGLE2SHORT( ps->ps.viewangles[0] ) - ps->ps.pmove.delta_angles[0] - client->lastcmd.angles[0];
1572 	client->delta_angles[1] = ANGLE2SHORT( ps->ps.viewangles[1] ) - ps->ps.pmove.delta_angles[1] - client->lastcmd.angles[1];
1573 	client->delta_angles[2] = ANGLE2SHORT( ps->ps.viewangles[2] ) - ps->ps.pmove.delta_angles[2] - client->lastcmd.angles[2];
1574 #endif
1575 
1576     client->admin = qtrue;
1577 	client->pmflags ^= PMF_TELEPORT_BIT;
1578     if( mvd.serverProtocol < PROTOCOL_VERSION_MVD ) {
1579 	//	client->scoreboard = SBOARD_SCORES;
1580 	//	MVD_UpdateLayoutScores( client );
1581 		MVD_GameStartFollowing( client, CLIENTNUM_NONE );
1582     }
1583 	SV_ClientPrintf( client->cl, PRINT_HIGH, "[MVD] Granted admin status.\n" );
1584 }
1585 
MVD_StopAdmin(mvdClient_t * client)1586 static void MVD_StopAdmin( mvdClient_t *client ) {
1587 	int i, length;
1588 	mvdFrame_t *src, *dst;
1589 
1590 	src = &mvd.frames[mvd.validPacketNum % mvd.frameBackup];
1591 	dst = &mvd.frames[mvd.activePacketNum % mvd.frameBackup];
1592 
1593 	if( src->gamestateSequence != dst->gamestateSequence ) {
1594 		MSG_WriteByte( svc_stufftext );
1595 		MSG_WriteString( "changing; reconnect\n" );
1596 		SV_ClientAddMessage( client->cl, MSG_RELIABLE|MSG_CLEAR );
1597 		client->cl->state = cs_connected;
1598 		client->admin = qfalse;
1599 		return;
1600 	}
1601 
1602 	/* write delta configstrings */
1603 	for( i = 0; i < MAX_CONFIGSTRINGS; i++ ) {
1604 		length = strlen( sv.configstrings[i] );
1605 		if( !length && mvd.configstrings[i][0] ) {
1606 			MSG_WriteByte( svc_configstring );
1607 			MSG_WriteShort( i );
1608 			MSG_WriteByte( 0 );
1609 			continue;
1610 		}
1611 		if( length > MAX_QPATH ) {
1612 			length = MAX_QPATH;
1613 		}
1614 		if( strncmp( mvd.configstrings[i], sv.configstrings[i], length ) ) {
1615 			MSG_WriteByte( svc_configstring );
1616 			MSG_WriteShort( i );
1617 			MSG_WriteData( sv.configstrings[i], length );
1618 			MSG_WriteByte( 0 );
1619 		}
1620 	}
1621 
1622     client->admin = qfalse;
1623 	client->pmflags ^= PMF_TELEPORT_BIT;
1624 	SV_ClientPrintf( client->cl, PRINT_HIGH, "[MVD] Lost admin status.\n" );
1625 }
1626 
MVD_GameClientCommand(edict_t * ent)1627 static void MVD_GameClientCommand( edict_t *ent ) {
1628 	mvdClient_t *client;
1629 	char *cmd;
1630 	int clientNum, i;
1631 
1632 	if( mvd.state < MVD_PRIMED ) {
1633 		return;
1634 	}
1635 
1636 	client = ( mvdClient_t * )ent->client;
1637 	cmd = Cmd_Argv( 0 );
1638 	if( !Q_stricmp( cmd, "!mvdadmin" ) ) {
1639 		if( mvd.demoplayback || client->cl->protocol == PROTOCOL_VERSION_MVD ) {
1640 			return;
1641 		}
1642         if( client->admin ) {
1643 			MVD_StopAdmin( client );
1644             return;
1645         }
1646 		if( !NET_IsLocalAddress( &client->cl->netchan->remote_address ) ) {
1647 			if( Cmd_Argc() < 2 ) {
1648 				SV_ClientPrintf( client->cl, PRINT_HIGH, "Usage: %s <password>\n",
1649 						Cmd_Argv( 0 ) );
1650 				return;
1651 			}
1652 			if( !mvd_admin_password->string[0]
1653 					|| strcmp( mvd_admin_password->string, Cmd_Argv( 1 ) ) )
1654 			{
1655 				SV_ClientPrintf( client->cl, PRINT_HIGH, "[MVD] Invalid password.\n" );
1656 				return;
1657 			}
1658 		}
1659 		MVD_StartAdmin( client );
1660 		return;
1661 	}
1662 
1663     if( client->admin ) {
1664         MVD_ClientCommand( Cmd_RawString() );
1665         return;
1666     }
1667 
1668 	if( !Q_stricmp( cmd, "say" ) || !Q_stricmp( cmd, "say_team" ) ) {
1669 		if( client->floodTime > sv.time ) {
1670 			SV_ClientPrintf( client->cl, PRINT_HIGH,
1671 				"[MVD] You can't talk for %d more seconds.\n",
1672 				( client->floodTime - sv.time ) / 1000 );
1673 			return;
1674 		}
1675 		Cvar_ClampInteger( mvd_flood_msgs, 0, FLOOD_SAMPLES - 1 );
1676 		i = client->floodHead - mvd_flood_msgs->integer - 1;
1677 		if( i >= 0 ) {
1678 			Cvar_ClampValue( mvd_flood_persecond, 0, 60 );
1679 			if( sv.time - client->floodSamples[i & FLOOD_MASK] <
1680 				mvd_flood_persecond->value * 1000 )
1681 			{
1682 				Cvar_ClampValue( mvd_flood_waitdelay, 0, 60 );
1683 				SV_ClientPrintf( client->cl, PRINT_HIGH,
1684 					"[MVD] You can't talk for %d seconds.\n",
1685 					mvd_flood_waitdelay->integer );
1686 				client->floodTime = sv.time + mvd_flood_waitdelay->value * 1000;
1687 				return;
1688 			}
1689 		}
1690 		SV_BroadcastPrintf( PRINT_CHAT, "[MVD] %s: %s\n", client->cl->name,
1691                 Cmd_Args() );
1692 		client->floodSamples[client->floodHead & FLOOD_MASK] = sv.time;
1693 		client->floodHead++;
1694 		return;
1695 	}
1696 	if( !Q_stricmp( cmd, "playernext" ) ) {
1697 		MVD_GameFollowCycle( client, 1 );
1698 		return;
1699 	}
1700 	if( !Q_stricmp( cmd, "playerprev" ) ) {
1701 		MVD_GameFollowCycle( client, -1 );
1702 		return;
1703 	}
1704 	if( !Q_stricmp( cmd, "playertoggle" ) ) {
1705 		MVD_GameStartFollowing( client, client->savedClientNum );
1706 		return;
1707 	}
1708 	if( !Q_stricmp( cmd, "follow" ) ) {
1709 		if( Cmd_Argc() < 2 ) {
1710 			if( !client->following ) {
1711 				MVD_GameStartFollowing( client, client->savedClientNum );
1712 			}
1713 			return;
1714 		}
1715 		clientNum = atoi( Cmd_Argv( 1 ) );
1716 		MVD_GameStartFollowing( client, clientNum );
1717 		return;
1718 	}
1719 	if( !Q_stricmp( cmd, "observe" ) ) {
1720 		if( client->following ) {
1721 			MVD_GameStartObserving( client );
1722 		}
1723 		return;
1724 	}
1725 	if( !Q_stricmp( cmd, "inven" ) ) {
1726 		if( client->scoreboard == SBOARD_CLIENTS ) {
1727 			MVD_SetDefaultLayout( client );
1728 		} else {
1729 			client->scoreboard = SBOARD_CLIENTS;
1730 			MVD_UpdateLayoutClients( client );
1731 		}
1732 		return;
1733 	}
1734 	if( !Q_stricmp( cmd, "help" ) ) {
1735 		if( client->scoreboard == SBOARD_SCORES ) {
1736 			MVD_SetDefaultLayout( client );
1737 		} else {
1738 			client->scoreboard = SBOARD_SCORES;
1739 			MVD_UpdateLayoutScores( client );
1740 		}
1741 		return;
1742 	}
1743 
1744 	if( !Q_stricmp( cmd, "putaway" ) ) {
1745 		MVD_SetDefaultLayout( client );
1746 		return;
1747 	}
1748 
1749 	SV_ClientPrintf( client->cl, PRINT_LOW, "[MVD] unknown command '%s'\n", cmd );
1750 }
1751 
MVD_Trace(vec3_t start,vec3_t mins,vec3_t maxs,vec3_t end)1752 trace_t MVD_Trace( vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end ) {
1753 	return SV_Trace( start, mins, maxs, end, NULL, MASK_PLAYERSOLID );
1754 }
1755 
MVD_GameClientThink(edict_t * ent,usercmd_t * cmd)1756 static void MVD_GameClientThink( edict_t *ent, usercmd_t *cmd ) {
1757 	mvdClient_t *client;
1758 	pmove_t pm;
1759 	qboolean modeChange, playerChange;
1760 
1761 	client = ( mvdClient_t * )ent->client;
1762     if( client->admin && mvd.serverProtocol < PROTOCOL_VERSION_MVD ) {
1763        // VectorAdd( cmd->angles, client->delta_angles, mvd.cmd.angles );
1764 		VectorCopy( cmd->angles, mvd.cmd.angles );
1765         mvd.cmd.forwardmove += cmd->forwardmove;
1766         mvd.cmd.sidemove += cmd->sidemove;
1767         mvd.cmd.upmove += cmd->upmove;
1768         mvd.cmd.buttons |= cmd->buttons;
1769         mvd.cmd.msec += cmd->msec;
1770 	    client->lastcmd = *cmd;
1771         return;
1772     }
1773 	modeChange = !( client->lastcmd.buttons & BUTTON_ATTACK ) && ( cmd->buttons & BUTTON_ATTACK );
1774 	playerChange = !client->lastcmd.upmove && cmd->upmove;
1775 	client->lastcmd = *cmd;
1776 
1777 	if( modeChange ) {
1778 		if( client->following ) {
1779 			MVD_GameStartObserving( client );
1780 		} else {
1781 			MVD_GameStartFollowing( client, client->savedClientNum );
1782 		}
1783 	}
1784 
1785 	if( client->following ) {
1786 		if( playerChange ) {
1787 			MVD_GameFollowCycle( client, 1 );
1788 		}
1789 		return;
1790 	}
1791 
1792 	memset( &pm, 0, sizeof( pm ) );
1793 	pm.trace = MVD_Trace;
1794 	pm.pointcontents = SV_PointContents;
1795 	pm.s = client->ps.pmove;
1796 	pm.cmd = *cmd;
1797 
1798 	PF_Pmove( &pm );
1799 
1800 	client->ps.pmove = pm.s;
1801 	VectorCopy( pm.viewangles, client->ps.viewangles );
1802 }
1803 
MVD_GameRunFrame(void)1804 static void MVD_GameRunFrame( void ) {
1805 	client_t *client;
1806 	mvdClient_t *mvdcl;
1807 	mvdFrame_t *frames[2], *frame;
1808 	playerStateEx_t *ps;
1809 	int i, j;
1810 
1811 	if( mvd.demoplayback ) {
1812 		/* run backwards, until we run out of buffers */
1813 		if( mvd.demobackwards ) {
1814 			MVD_SetPrevFrame();
1815 			goto update;
1816 		}
1817 
1818 		/* if paused, do not run forward */
1819 		if( mvd_pause->integer ) {
1820 			goto update;
1821 		}
1822 
1823 		/* feed in next demo frame, if necessarry */
1824 		while( mvd.demofile && mvd.activePacketNum >= mvd.serverPacketNum ) {
1825 			if( !MVD_ParseNextMessage() ) {
1826 				Com_Printf( "MVD finished, closing demofile.\n" );
1827 				FS_FCloseFile( mvd.demofile );
1828 				mvd.demofile = 0;
1829 				if( mvd_nextserver->integer ) {
1830 					SV_Nextserver();
1831 				}
1832 				return;
1833 			}
1834 		}
1835 	}
1836 
1837 	if( mvd.state < MVD_CONNECTED ) {
1838 		return;
1839 	}
1840 
1841 	MVD_SetNextFrame();
1842 
1843 update:
1844 	frames[0] = &mvd.frames[mvd.activePacketNum % mvd.frameBackup];
1845 	frames[1] = &mvd.frames[mvd.validPacketNum % mvd.frameBackup];
1846 
1847 	/* update clients */
1848     FOR_EACH_CLIENT( client ) {
1849 		if( client->state < cs_spawned ) {
1850 			continue;
1851 		}
1852         if( client->protocol == PROTOCOL_VERSION_MVD ) {
1853             continue;
1854         }
1855 		mvdcl = ( mvdClient_t * )client->edict->client;
1856 		if( mvdcl->scoreboard == SBOARD_CLIENTS && mvdcl->layoutTime < sv.time && !mvdcl->admin ) {
1857 			MVD_UpdateLayoutClients( mvdcl );
1858 		}
1859 		if( !mvdcl->following ) {
1860 			continue;
1861 		}
1862 		frame = frames[mvdcl->admin];
1863 		for( i = 0; i < frame->numPlayerStates; i++ ) {
1864 			j = ( frame->firstPlayerState + i ) % mvd.maxPlayerStates;
1865 			ps = &mvd.playerStates[j];
1866 			if( ps->number == mvdcl->followClientNum ) {
1867 				MVD_UpdateFollower( mvdcl, ps );
1868 				break;
1869 			}
1870 		}
1871 		if( i == frame->numPlayerStates ) {
1872 			/* player not present in current frame */
1873 			MVD_GameStartObserving( mvdcl );
1874 			mvdcl->savedFollowing = qtrue;
1875 		}
1876 
1877 	}
1878 }
1879 
MVD_GameServerCommand(void)1880 static void MVD_GameServerCommand( void ) {
1881 }
1882 
1883 game_export_t mvd_ge = {
1884 	GAME_API_VERSION,
1885 
1886 	MVD_GameInit,
1887 	MVD_GameShutdown,
1888 
1889 	MVD_GameSpawnEntities,
1890 
1891 	MVD_GameWriteGame,
1892 	MVD_GameReadGame,
1893 
1894 	MVD_GameWriteLevel,
1895 	MVD_GameReadLevel,
1896 
1897 	MVD_GameClientConnect,
1898 	MVD_GameClientBegin,
1899 	MVD_GameClientUserinfoChanged,
1900 	MVD_GameClientDisconnect,
1901 	MVD_GameClientCommand,
1902 	MVD_GameClientThink,
1903 
1904 	MVD_GameRunFrame,
1905 
1906 	MVD_GameServerCommand,
1907 
1908 	( edict_t * )mvd_edicts,
1909 	sizeof( mvd_edicts[0] ),
1910 	MAX_CLIENTS + 1,
1911 	MAX_CLIENTS + 1
1912 };
1913 
MVD_StreamedWrite(sizebuf_t * msgbuf,int bytesToSkip)1914 void MVD_StreamedWrite( sizebuf_t *msgbuf, int bytesToSkip ) {
1915 	int		len, swlen;
1916 
1917 	// the first several bytes are just packet sequencing stuff
1918 	len = msgbuf->cursize - bytesToSkip;
1919 	if( len < 1 ) {
1920 		return; // don't write bad messages
1921 	}
1922 
1923 	swlen = LittleLong( len );
1924 	FS_Write( &swlen, 4, mvd.demofile );
1925 	FS_Write( msgbuf->data + bytesToSkip, len, mvd.demofile );
1926 }
1927 
MVD_StreamedStop_f(void)1928 void MVD_StreamedStop_f( void ) {
1929 	int length;
1930 
1931 	if( !mvd.demorecording ) {
1932 		Com_Printf( "Not recording a streamed demo.\n" );
1933 		return;
1934 	}
1935 
1936 	length = -1;
1937 	FS_Write( &length, 4, mvd.demofile );
1938 	FS_FCloseFile( mvd.demofile );
1939 
1940 	mvd.demofile = 0;
1941 	mvd.demorecording = qfalse;
1942 	mvd.demowaiting = qfalse;
1943 
1944 	Com_Printf( "Streamed demo recording completed.\n" );
1945 }
1946 
MVD_StreamedRecord_f(void)1947 void MVD_StreamedRecord_f( void ) {
1948 	mvdGamestate_t *gs;
1949 	entityStateEx_t *ent;
1950 	char *string;
1951 	int i, j, length;
1952 	char buffer[MAX_QPATH];
1953 	char *name;
1954 	fileHandle_t demofile;
1955     qboolean compressed = qfalse;
1956 
1957 	i = 1;
1958     string = Cmd_Argv( i );
1959 	if( !strcmp( string, "-c" ) || !strcmp( string, "--compressed" ) ) {
1960 		compressed = qtrue;
1961 		i++;
1962 	}
1963 
1964 	if( i >= Cmd_Argc() ) {
1965 		Com_Printf( "Usage: %s [-c|--compressed] [/]<filename>\n",
1966                 Cmd_Argv( 0 ) );
1967 		return;
1968 	}
1969 
1970 	if( mvd.demorecording ) {
1971 		Com_Printf( "Already recording a streamed demo.\n" );
1972 		return;
1973 	}
1974 
1975 	if( mvd.state < MVD_CONNECTED || mvd.demoplayback ) {
1976 		Com_Printf( "You must be connected to record.\n" );
1977 		return;
1978 	}
1979 
1980 	//
1981 	// open the demo file
1982 	//
1983 	name = Cmd_Argv( i );
1984 	if( name[0] == '/' ) {
1985 		Q_strncpyz( buffer, name + 1, sizeof( buffer ) );
1986 	} else {
1987 		Com_sprintf( buffer, sizeof( buffer ), "demos/%s", name );
1988         switch( mvd.serverProtocol ) {
1989         case PROTOCOL_VERSION_MVD:
1990             string = ".mvd2";
1991             break;
1992         case PROTOCOL_VERSION_Q2PRO:
1993             string = ".dm_36";
1994             break;
1995         case PROTOCOL_VERSION_R1Q2:
1996             string = ".dm_35";
1997             break;
1998         default:
1999             string = ".dm2";
2000             break;
2001         }
2002 		COM_DefaultExtension( buffer, string, sizeof( buffer ) );
2003 	}
2004 	if( compressed ) {
2005 		Q_strcat( buffer, sizeof( buffer ), ".gz" );
2006 	}
2007 
2008 	FS_FOpenFile( buffer, &demofile, FS_MODE_WRITE );
2009 	if( !demofile ) {
2010 		Com_EPrintf( "Couldn't open %s for writing\n", buffer );
2011 		return;
2012 	}
2013 
2014 	Com_Printf( "Recording streamed demo to %s\n", buffer );
2015 	//Com_WPrintf( "Streamed demos are currently BROKEN!\n" );
2016 
2017 	mvd.demofile = demofile;
2018 	mvd.demorecording = qtrue;
2019 	mvd.demowaiting = qtrue;
2020 
2021 	gs = &mvd.gamestates[mvd.gamestateSequence & GAMESTATE_MASK];
2022 
2023 
2024 	//
2025 	// write out messages to hold the startup information
2026 	//
2027 
2028 	// send the serverdata
2029 	MSG_WriteByte( svc_serverdata );
2030 	MSG_WriteLong( mvd.serverProtocol );
2031 	MSG_WriteLong( 0x10000 + mvd.servercount );
2032     MSG_WriteByte( ATR_DEMO );	/* demos are always attract loops */
2033 	string = Cvar_VariableString( "gamedir" );
2034     MSG_WriteString( string );
2035     MSG_WriteShort( mvd.clientNum );
2036     MSG_WriteString( gs->fullname );
2037 
2038 	// protocol-specific stuff
2039 	switch( mvd.serverProtocol ) {
2040 	case PROTOCOL_VERSION_R1Q2:
2041         MSG_WriteByte( 0 );		/* enhanced */
2042         MSG_WriteShort( PROTOCOL_VERSION_R1Q2_MINOR );
2043         MSG_WriteByte( 0 );		/* advanced deltas */
2044         MSG_WriteByte( 0 );     /* strafeHack */
2045 		break;
2046 	case PROTOCOL_VERSION_Q2PRO:
2047         MSG_WriteShort( PROTOCOL_VERSION_Q2PRO_MINOR );
2048         MSG_WriteByte( GT_DEATHMATCH );
2049         MSG_WriteByte( 0 );     /* strafeHack */
2050 		MSG_WriteByte( 0 );		//atu QWMod
2051 		break;
2052 	case PROTOCOL_VERSION_MVD:
2053 		MSG_WriteShort( PROTOCOL_VERSION_MVD_MINOR );
2054 		break;
2055 	default:
2056 		break;
2057 	}
2058 
2059     // configstrings
2060 	for( i = 0; i < MAX_CONFIGSTRINGS; i++ ) {
2061 		string = mvd.configstrings[i];
2062 		if( !string || !string[0] ) {
2063             continue;
2064         }
2065 
2066 		length = strlen( string );
2067 		if( length > MAX_QPATH ) {
2068 			length = MAX_QPATH;
2069 		}
2070 
2071 		if( mvd.serverProtocol < PROTOCOL_VERSION_Q2PRO ) {
2072 			if( msg_write.cursize + length + 4 > MAX_PACKETLEN ) {
2073 				MVD_StreamedWrite( &msg_write, 0 );
2074 				SZ_Clear( &msg_write );
2075 			}
2076 		}
2077         MSG_WriteByte( svc_configstring );
2078         MSG_WriteShort( i );
2079         MSG_WriteData( string, length );
2080 		MSG_WriteByte( 0 );
2081 	}
2082 
2083     // baselines
2084 	for( i = 0; i < SV_BASELINES_CHUNKS; i++ ) {
2085 		if( !gs->baselines[i] ) {
2086 			continue;
2087 		}
2088 		for( j = 0; j < SV_BASELINES_PER_CHUNK; j++ ) {
2089 			ent = &gs->baselines[i][j];
2090 			if( !ent->s.number ) {
2091 				continue;
2092 			}
2093 			if( mvd.serverProtocol < PROTOCOL_VERSION_Q2PRO ) {
2094 				if( msg_write.cursize + 64 > MAX_PACKETLEN ) {
2095 					MVD_StreamedWrite( &msg_write, 0 );
2096 					SZ_Clear( &msg_write );
2097 				}
2098 			}
2099 			MSG_WriteByte( svc_spawnbaseline );
2100 			MSG_WriteDeltaEntity( NULL, &ent->s, MSG_ES_FORCE );
2101 		}
2102 	}
2103 
2104 	MSG_WriteByte( svc_stufftext );
2105 	MSG_WriteString( "precache\n" );
2106 
2107 	MVD_StreamedWrite( &msg_write, 0 );
2108 	SZ_Clear( &msg_write );
2109 }
2110 
MVD_Jump_f(void)2111 void MVD_Jump_f( void ) {
2112 	int percent, delta, savedPacketNum;
2113 	mvdFrame_t *frame;
2114 	mvdClient_t *gclient;
2115 	client_t *client;
2116 
2117 	if( !mvd.demoplayback ) {
2118 		Com_Printf( "Not playing back a MVD.\n" );
2119 		return;
2120 	}
2121 
2122 	if( Cmd_Argc() < 2 ) {
2123 		Com_Printf( "Usage: %s <percent>\n", Cmd_Argv( 0 ) );
2124 		return;
2125 	}
2126 
2127 	percent = atoi( Cmd_Argv( 1 ) );
2128 	if( percent < 0 || percent > 100 ) {
2129 		Com_Printf( "Percent should be in the [0, 100] range\n" );
2130 		return;
2131 	}
2132 
2133     savedPacketNum = mvd.activePacketNum;
2134 
2135 	delta = ( 100 - percent ) * ( mvd.frameBackup - 1 ) / 100;
2136 	mvd.activePacketNum = mvd.serverPacketNum - delta - 1;
2137     if( mvd.activePacketNum < 0 ) {
2138         mvd.activePacketNum = 0;
2139     }
2140 
2141 	frame = &mvd.frames[mvd.activePacketNum % mvd.frameBackup];
2142 
2143 	while( mvd.activePacketNum < mvd.serverPacketNum ) {
2144 		mvd.activePacketNum++;
2145 		frame = &mvd.frames[mvd.activePacketNum % mvd.frameBackup];
2146 
2147         if( frame->serverPacketNum != mvd.activePacketNum ) {
2148 			MVD_DPrintf( "MVD_Jump_f: %d: never received\n",
2149                     mvd.activePacketNum );
2150             continue;
2151         }
2152 
2153 		/* got new gamestate? */
2154 		if( frame->gamestateSequence != mvd.activeGamestateSequence ) {
2155 			MVD_DPrintf( "MVD_Jump_f: %d: different gamestateSequence\n",
2156                     mvd.activePacketNum );
2157 			continue;
2158 		}
2159 
2160 		/* does this frame contain svc_frame? */
2161 		if( !( frame->flags & MFF_ACTIVE ) ) {
2162 			continue;
2163 		}
2164 
2165 		if( !( frame->flags & MFF_VALID ) ) {
2166 			MVD_DPrintf( "MVD_Jump_f: %d: invalid frame\n",
2167                     mvd.activePacketNum );
2168 			continue;
2169 		}
2170 
2171 		if( mvd.nextEntityStates - frame->firstEntityState >
2172                 mvd.maxEntityStates )
2173         {
2174 			MVD_DPrintf( "MVD_Jump_f: %d: entityStates too old\n",
2175                     mvd.activePacketNum );
2176 			continue;
2177 		}
2178 		if( mvd.nextPlayerStates - frame->firstPlayerState >
2179                 mvd.maxPlayerStates )
2180         {
2181 			MVD_DPrintf( "MVD_Jump_f: %d: playerStates too old\n",
2182                     mvd.activePacketNum );
2183 			continue;
2184 		}
2185 
2186 		if( mvd.nextMessageBytes - frame->firstMessageByte >
2187                 mvd.maxMessageBytes )
2188         {
2189 			MVD_DPrintf( "MVD_Jump_f: %d: messages too old\n",
2190                     mvd.activePacketNum );
2191 			continue;
2192 		}
2193 
2194         break;
2195 	}
2196 
2197     if( mvd.activePacketNum == savedPacketNum ) {
2198         return;
2199     }
2200 
2201     /* advance server state to this frame */
2202     mvd.prevPacketNum = mvd.activePacketNum;
2203     MVD_TransitionFrame( frame );
2204 
2205     /*for( i = 1; i < ge->num_edicts; i++, ent++ ) {
2206         ent = EDICT_NUM( i );
2207         ent->s.event = EV_OTHER_TELEPORT;
2208         if( !( ent->s.renderfx & RF_BEAM ) ) {
2209             VectorCopy( ent->s.origin, ent->s.old_origin );
2210         }
2211     }*/
2212 
2213     FOR_EACH_CLIENT( client ) {
2214 		if( client->state < cs_spawned ) {
2215 			continue;
2216 		}
2217         if( client->protocol == PROTOCOL_VERSION_MVD ) {
2218             continue;
2219         }
2220 		gclient = ( mvdClient_t * )client->edict->client;
2221 		if( !gclient->following ) {
2222 			continue;
2223 		}
2224 		gclient->pmflags ^= PMF_TELEPORT_BIT;
2225 	}
2226 }
2227 
2228 #ifndef DEDICATED_ONLY
2229 /* called by the client code */
MVD_GetDemoPercent(int * percent,int * bufferPercent)2230 qboolean MVD_GetDemoPercent( int *percent, int *bufferPercent ) {
2231 	int delta;
2232 
2233 	if( !mvd.demoplayback ) {
2234 		return qfalse;
2235 	}
2236 
2237 	delta = mvd.serverPacketNum - mvd.activePacketNum;
2238 	*bufferPercent = 100 - delta * 100 / ( mvd.frameBackup - 1 );
2239 	*percent = mvd.demofilePercent;
2240 
2241 	return qtrue;
2242 }
2243 #endif
2244 
MVD_Play_g(const char * partial,int state)2245 const char *MVD_Play_g( const char *partial, int state ) {
2246 	return Com_FileNameGeneratorByFilter( "demos", "*.mvd2;*.mvd2.gz", partial, qfalse, state );
2247 }
2248 
MVD_Play_f(void)2249 void MVD_Play_f( void ) {
2250 	char *name;
2251 	char buffer[MAX_QPATH];
2252 	fileHandle_t f;
2253 	int length;
2254 
2255 	if( Cmd_Argc() < 2 ) {
2256 		Com_Printf( "Usage: %s [/]<filename>\n", Cmd_Argv( 0 ) );
2257 		return;
2258 	}
2259 
2260 	name = Cmd_Argv( 1 );
2261 	if( name[0] == '/' ) {
2262 		Q_strncpyz( buffer, name + 1, sizeof( buffer ) );
2263 	} else {
2264 		Com_sprintf( buffer, sizeof( buffer ), "demos/%s", name );
2265 		COM_DefaultExtension( buffer, ".mvd2", sizeof( buffer ) );
2266 	}
2267 	FS_FOpenFile( buffer, &f, FS_MODE_READ );
2268 	if( !f ) {
2269 		Com_Printf( "Couldn't open '%s'\n", buffer );
2270 		return;
2271 	}
2272 
2273 	if( !MVD_ReadNextMessage( f ) ) {
2274 		Com_Printf( "Couldn't read the first message from '%s'.\n"
2275 			"Demo is possibly broken or truncated.\n", buffer );
2276 		FS_FCloseFile( f );
2277 		return;
2278 	}
2279 
2280 	SV_Shutdown( "Server restarted\n", KILL_RESTART );
2281 
2282 	mvd.demofile = f;
2283 	mvd.demoplayback = qtrue;
2284 	mvd.state = MVD_CONNECTED;
2285 
2286 	mvd.serverPacketNum++;
2287 	MVD_ParseMessage();
2288 
2289 	do {
2290 		if( !MVD_ParseNextMessage() ) {
2291 			Com_WPrintf( "Premature end of MVD.\n" );
2292 			SV_Nextserver();
2293 			return;
2294 		}
2295 		MVD_SetNextFrame();
2296 		if( mvd.state < MVD_CONNECTED ) {
2297 			return;
2298 		}
2299 	} while( mvd.state < MVD_ACTIVE );
2300 
2301     if( dedicated->integer && !sv_nextserver->string[0] ) {
2302     	Cvar_Set( "nextserver", va( "mvdplay /%s", buffer ) );
2303     }
2304 
2305 	length = FS_GetFileLengthNoCache( mvd.demofile );
2306 	mvd.demofileFrameOffset = FS_Tell( mvd.demofile );
2307 	mvd.demofileSize = length - mvd.demofileFrameOffset;
2308 	strcpy( mvd.demopath, buffer );
2309 }
2310 
MVD_ConnectionlessPacket(void)2311 static void MVD_ConnectionlessPacket( void ) {
2312     char	*c, *s;
2313 	netchan_t *netchan;
2314     netchan_type_t type;
2315 	int i, j, k;
2316 
2317     MSG_BeginReading();
2318     MSG_ReadLong();	// skip the -1
2319 
2320     s = MSG_ReadStringLine();
2321 
2322     Cmd_TokenizeString( s, qfalse );
2323 
2324     c = Cmd_Argv( 0 );
2325 
2326 	Com_DPrintf( "[MVD] ClientPacket: %s: %s\n", NET_AdrToString( &net_from ), s );
2327 
2328     /* challenge from the server we are connecting to */
2329     if ( !strcmp( c, "challenge" ) ) {
2330 		qboolean proto35 = qfalse, proto36 = qfalse, proto37 = qfalse;
2331 
2332         if ( mvd.state < MVD_CHALLENGING ) {
2333             Com_DPrintf( "[MVD] Challenge received while not connecting.  Ignored.\n" );
2334             return;
2335         }
2336         if ( !NET_IsEqualBaseAdr( &net_from, &mvd.serverAddress ) ) {
2337             Com_DPrintf( "[MVD] Challenge from different address.  Ignored.\n" );
2338             return;
2339         }
2340         if ( mvd.state > MVD_CHALLENGING ) {
2341             Com_DPrintf( "[MVD] Dup challenge received.  Ignored.\n" );
2342             return;
2343         }
2344 
2345 		/* parse additional parameters */
2346         j = Cmd_Argc();
2347 		for( i = 2; i < j; i++ ) {
2348 			s = Cmd_Argv( i );
2349 			if( !strncmp( s, "p=", 2 ) ) {
2350 				s += 2;
2351 				while( *s ) {
2352 					k = atoi( s );
2353 					if( k == PROTOCOL_VERSION_R1Q2 ) {
2354 						proto35 = qtrue;
2355 					} else if( k == PROTOCOL_VERSION_Q2PRO ) {
2356 						proto36 = qtrue;
2357 					} else if( k == PROTOCOL_VERSION_MVD ) {
2358 						proto37 = qtrue;
2359 					}
2360 					s = strchr( s, ',' );
2361 					if( s == NULL ) {
2362 						break;
2363 					}
2364 					s++;
2365 				}
2366 			}
2367         }
2368 
2369 		/* select the 'best' protocol available, unless told otherwise */
2370 		if( mvd.serverProtocol == 0 ||
2371 			( mvd.serverProtocol == PROTOCOL_VERSION_R1Q2 && !proto35 ) ||
2372 			( mvd.serverProtocol == PROTOCOL_VERSION_Q2PRO && !proto36 ) ||
2373 			( mvd.serverProtocol == PROTOCOL_VERSION_MVD && !proto37 ) )
2374 		{
2375 			if( proto37 ) {
2376 				mvd.serverProtocol = PROTOCOL_VERSION_MVD;
2377 			} else if( proto36 ) {
2378 				mvd.serverProtocol = PROTOCOL_VERSION_Q2PRO;
2379 			} else if( proto35 ) {
2380 				mvd.serverProtocol = PROTOCOL_VERSION_R1Q2;
2381 			} else {
2382 				mvd.serverProtocol = PROTOCOL_VERSION_DEFAULT;
2383 			}
2384 		}
2385 		Com_DPrintf( "[MVD] Selected protocol %d\n", mvd.serverProtocol );
2386 
2387         mvd.challenge = atoi( Cmd_Argv( 1 ) );
2388         mvd.state = MVD_CONNECTING;
2389         mvd.connectTime = -9999;
2390         mvd.connectCount = 0;
2391 		return;
2392 	}
2393 
2394 	if ( !strcmp( c, "client_connect" ) ) {
2395         if ( mvd.state < MVD_CONNECTING ) {
2396             Com_DPrintf( "[MVD] Connect received while not connecting.  Ignored.\n" );
2397             return;
2398         }
2399         if ( !NET_IsEqualBaseAdr( &net_from, &mvd.serverAddress ) ) {
2400             Com_DPrintf( "[MVD] Connect from different address.  Ignored.\n" );
2401             return;
2402         }
2403         if ( mvd.state > MVD_CONNECTING ) {
2404             Com_DPrintf( "[MVD] Dup connect received.  Ignored.\n" );
2405             return;
2406         }
2407 
2408         if( mvd.serverProtocol < PROTOCOL_VERSION_Q2PRO ) {
2409             type = NETCHAN_OLD;
2410         } else {
2411             type = NETCHAN_NEW;
2412         }
2413 
2414 		/* parse additional parameters */
2415         j = Cmd_Argc();
2416 		for( i = 1; i < j; i++ ) {
2417 			s = Cmd_Argv( i );
2418 			if( !strncmp( s, "nc=", 3 ) ) {
2419 				s += 3;
2420 				if( *s ) {
2421                     type = atoi( s );
2422                     if( type != NETCHAN_OLD && type != NETCHAN_NEW ) {
2423 			            Com_Error( ERR_DISCONNECT,
2424                             "[MVD] Server returned invalid netchan type" );
2425                     }
2426 				}
2427 			}
2428         }
2429 
2430 		netchan = Netchan_Setup( NS_CLIENT, type, &mvd.serverAddress,
2431                 mvd.quakePort, 1024, mvd.serverProtocol );
2432 
2433 		Com_Printf( "[MVD] Connection to %s established (protocol %d).\n",
2434 			NET_AdrToString( &netchan->remote_address ), mvd.serverProtocol );
2435 
2436 		mvd.state = MVD_CONNECTED;
2437 		mvd.netchan = netchan;
2438 		MVD_ClientCommand( "new" );
2439 		return;
2440 	}
2441 
2442 	if ( !strcmp( c, "print" ) ) {
2443 		if ( ( mvd.state == MVD_CHALLENGING || mvd.state == MVD_CONNECTING ) &&
2444             NET_IsEqualBaseAdr( &net_from, &mvd.serverAddress ) )
2445 		{
2446 			s = MSG_ReadString();
2447 			Com_Error( ERR_DISCONNECT, "[MVD] %s", s );
2448 		}
2449 		return;
2450 	}
2451 }
2452 
MVD_PacketEvent(int ret)2453 void MVD_PacketEvent( int ret ) {
2454 	int bytesToSkip;
2455 
2456 	if( !mvd_running->integer ) {
2457 		return;
2458 	}
2459 
2460     //
2461     // remote command packet
2462     //
2463     if ( ret == 1 && *( int * )msg_read.data == -1 ) {
2464         MVD_ConnectionlessPacket();
2465         return;
2466     }
2467 
2468 	if ( mvd.state < MVD_CONNECTED )
2469         return;		// dump it if not connected
2470 
2471     if ( ret == 1 && msg_read.cursize < 8 ) {
2472         Com_DPrintf( "[MVD] %s: runt packet\n", NET_AdrToString( &net_from ) );
2473         return;
2474     }
2475 
2476 	if ( !mvd.netchan )
2477         return;
2478 
2479     //
2480     // packet from server
2481     //
2482 	if ( !NET_IsEqualAdr( &net_from, &mvd.netchan->remote_address ) ) {
2483         Com_DPrintf( "[MVD] %s: sequenced packet without connection\n",
2484                 NET_AdrToString( &net_from ) );
2485         return;
2486     }
2487 
2488 	if( ret == -1 ) {
2489 		Com_Error( ERR_DISCONNECT, "[MVD] Connection reset by peer" );
2490 	}
2491 
2492     if ( !mvd.netchan->Process( mvd.netchan ) )
2493         return;		// wasn't accepted for some reason
2494 
2495 	bytesToSkip = msg_read.readcount;
2496 
2497 	mvd.serverPacketNum = mvd.netchan->incoming_sequence;
2498     MVD_ParseMessage();
2499 
2500 	if( mvd.demorecording && !mvd.demowaiting ) {
2501         MVD_StreamedWrite( &msg_read, bytesToSkip );
2502 	}
2503 }
2504 
MVD_CheckForResend(void)2505 void MVD_CheckForResend( void ) {
2506     char tail[32];
2507 	int ret;
2508 
2509 	if( mvd.realtime - mvd.connectTime < 3000 ) {
2510 		return;
2511 	}
2512 	mvd.connectTime = mvd.realtime;
2513 	mvd.connectCount++;
2514 
2515 	if( mvd.state < MVD_CONNECTING ) {
2516         Com_Printf( "[MVD] Requesting challenge... %i\n", mvd.connectCount );
2517         ret = Netchan_OutOfBandPrint( NS_CLIENT, &mvd.serverAddress,
2518                 "getchallenge\n" );
2519 		if( ret == -1 ) {
2520 			Com_Error( ERR_DISCONNECT, "[MVD] %s to %s\n", Sys_NetErrorString(),
2521                     NET_AdrToString( &mvd.serverAddress ) );
2522 		}
2523         return;
2524 	}
2525 
2526     Com_Printf( "[MVD] Requesting connection... %i\n", mvd.connectCount );
2527 
2528     mvd.quakePort = net_qport->integer;
2529 	if( mvd.serverProtocol != PROTOCOL_VERSION_DEFAULT ) {
2530         Com_sprintf( tail, sizeof( tail ), " %d",
2531                 net_maxmsglen->integer );
2532         if( mvd.serverProtocol >= PROTOCOL_VERSION_Q2PRO ) {
2533             strcat( tail, net_chantype->integer ? " 1" : " 0" );
2534         }
2535         mvd.quakePort &= 0xFF;
2536 	} else {
2537         tail[0] = 0;
2538 	}
2539 
2540     ret = Netchan_OutOfBandPrint( NS_CLIENT, &mvd.serverAddress,
2541 		"connect %i %i %i \"%s\"%s\n", mvd.serverProtocol, mvd.quakePort,
2542             mvd.challenge, Cvar_Userinfo(), tail );
2543 	if( ret == -1 ) {
2544 		Com_Error( ERR_DISCONNECT, "[MVD] %s to %s\n", Sys_NetErrorString(),
2545                 NET_AdrToString( &mvd.serverAddress ) );
2546 	}
2547 }
2548 
MVD_ClientFrame(int msec)2549 void MVD_ClientFrame( int msec ) {
2550 	int checksumIndex;
2551 
2552 	if( !mvd.state ) {
2553 		return;
2554 	}
2555 
2556 	Cbuf_ExecuteEx( &mvd_buffer );
2557 
2558 	mvd.realtime += msec;
2559 
2560 	if( mvd.state < MVD_CONNECTED ) {
2561 		MVD_CheckForResend();
2562 		return;
2563 	}
2564 
2565 	if( !mvd.netchan ) {
2566 		return;
2567 	}
2568 
2569     //
2570     // check timeout
2571     //
2572     if( Sys_Milliseconds() - mvd.netchan->last_received > mvd_timeout->value * 1000 ) {
2573         // timeoutcount saves debugger
2574         if ( ++mvd.timeoutcount > 5 ) {
2575             Com_Error( ERR_DISCONNECT, "[MVD] Server connection timed out." );
2576         }
2577     } else {
2578         mvd.timeoutcount = 0;
2579     }
2580 
2581 	if( cvar_infoModified & CVAR_USERINFO ) {
2582 		MSG_WriteByte( clc_userinfo );
2583 		MSG_WriteString( Cvar_Userinfo() );
2584 		MSG_FlushTo( &mvd.netchan->message );
2585 		Com_DPrintf( "[MVD] Sending userinfo update\n" );
2586 	}
2587 
2588 	if( mvd.state < MVD_BUFFERING ) {
2589 		if( mvd.netchan->ShouldUpdate( mvd.netchan ) ) {
2590 			mvd.netchan->Transmit( mvd.netchan, 0, NULL );
2591 		}
2592 		return;
2593 	}
2594 
2595 	if( mvd.realtime - mvd.sendtime < 33 &&
2596 		!mvd.netchan->ShouldUpdate( mvd.netchan ) )
2597 	{
2598 		return;
2599 	}
2600 
2601     if( !mvd.cmd.msec ) {
2602         mvd.cmd.msec = mvd.realtime - mvd.sendtime;
2603     }
2604     if( mvd.cmd.msec > 250 ) {
2605         mvd.cmd.msec = 100;
2606     }
2607 
2608     MSG_WriteByte( clc_move );
2609 
2610     // save the position for a checksum byte
2611     checksumIndex = 0;
2612     if( mvd.serverProtocol == PROTOCOL_VERSION_DEFAULT ) {
2613         checksumIndex = msg_write.cursize;
2614         SZ_GetSpace( &msg_write, 1 );
2615     }
2616     if( mvd.validPacketNum != mvd.serverPacketNum || mvd.demowaiting ) {
2617         MSG_WriteLong( -1 );
2618     } else {
2619         MSG_WriteLong( mvd.lastServerFrame );
2620     }
2621 
2622     MSG_WriteDeltaUsercmd( NULL, &mvd.cmd );
2623     MSG_WriteByte( 0 );
2624 
2625     MSG_WriteByte( 0 );
2626     MSG_WriteByte( mvd.cmd.msec );
2627     MSG_WriteByte( 0 );
2628 
2629     MSG_WriteByte( 0 );
2630     MSG_WriteByte( mvd.cmd.msec );
2631     MSG_WriteByte( 0 );
2632 
2633     if( mvd.serverProtocol == PROTOCOL_VERSION_DEFAULT ) {
2634         // calculate a checksum over the move commands
2635         msg_write.data[checksumIndex] = COM_BlockSequenceCRCByte(
2636             msg_write.data + checksumIndex + 1,
2637             msg_write.cursize - checksumIndex - 1,
2638             mvd.netchan->outgoing_sequence );
2639     }
2640 
2641     mvd.cmd.forwardmove = 0;
2642     mvd.cmd.sidemove = 0;
2643     mvd.cmd.upmove = 0;
2644     mvd.cmd.buttons = 0;
2645     mvd.cmd.msec = 0;
2646 
2647 	mvd.sendtime = mvd.realtime;
2648 
2649 	mvd.netchan->Transmit( mvd.netchan, msg_write.cursize, msg_write.data );
2650 
2651 	//Com_Printf( "Sent packet\n" );
2652 
2653 	SZ_Clear( &msg_write );
2654 
2655 }
2656 
MVD_Connect_f(void)2657 void MVD_Connect_f( void ) {
2658 	netadr_t adr;
2659 	char *s;
2660     int protocol;
2661 
2662     if ( Cmd_Argc() < 2 ) {
2663 usage:
2664         Com_Printf( "Usage: %s <server> [protocol]\n"
2665 					"Supported protocols: %d, %d, %d and %d\n",
2666             Cmd_Argv( 0 ),
2667 			PROTOCOL_VERSION_DEFAULT,
2668 			PROTOCOL_VERSION_R1Q2,
2669 			PROTOCOL_VERSION_Q2PRO,
2670             PROTOCOL_VERSION_MVD );
2671         return;
2672     }
2673 
2674 	protocol = 0;
2675 	if( Cmd_Argc() > 2 ) {
2676 		protocol = atoi( Cmd_Argv( 2 ) );
2677 		if( protocol < PROTOCOL_VERSION_DEFAULT ||
2678 			protocol > PROTOCOL_VERSION_MVD )
2679 		{
2680 			goto usage;
2681 		}
2682 	}
2683 
2684 	s = Cmd_Argv( 1 );
2685 	if( !NET_StringToAdr( s, &adr ) ) {
2686 		Com_Printf( "Bad server address: %s\n", s );
2687 		return;
2688 	}
2689 	if( !adr.port ) {
2690 		adr.port = BigShort( PORT_SERVER );
2691 	}
2692 
2693 	SV_Shutdown( "Server restarted\n", KILL_RESTART );
2694 
2695 	NET_Config( NET_CLIENT );
2696 
2697 	Cvar_SetInteger( "mvd_running", 1 );
2698 
2699 	mvd.serverAddress = adr;
2700     mvd.serverProtocol = protocol;
2701 	mvd.connectCount = 0;
2702 	mvd.connectTime = -9999;
2703 	mvd.state = MVD_CHALLENGING;
2704 }
2705 
MVD_Disconnect_f(void)2706 void MVD_Disconnect_f( void ) {
2707 	if( mvd.state ) {
2708 		Com_Error( ERR_SILENT, "[MVD] Disconnected from server.\n" );
2709 	}
2710 	Com_Printf( "Not connected to a MVD server.\n" );
2711 }
2712 
MVD_Disconnect(void)2713 void MVD_Disconnect( void ) {
2714 	int i;
2715 	mvdGamestate_t *gs;
2716 
2717 	if( mvd.demorecording ) {
2718 		MVD_StreamedStop_f();
2719 	}
2720 
2721 	if( mvd.netchan ) {
2722         MSG_WriteByte( clc_stringcmd );
2723         MSG_WriteString( "disconnect" );
2724 
2725         mvd.netchan->Transmit( mvd.netchan, msg_write.cursize, msg_write.data );
2726         mvd.netchan->Transmit( mvd.netchan, msg_write.cursize, msg_write.data );
2727         mvd.netchan->Transmit( mvd.netchan, msg_write.cursize, msg_write.data );
2728 
2729         SZ_Clear( &msg_write );
2730 
2731 		Netchan_Close( mvd.netchan );
2732 	}
2733 
2734 	if( mvd.clients ) {
2735 		Z_Free( mvd.clients );
2736 	}
2737 
2738 	Z_FreeTags( TAG_MVD );
2739 	if( mvd.demofile ) {
2740 		FS_FCloseFile( mvd.demofile );
2741 	}
2742 
2743 	for( i = 0; i < MAX_GAMESTATES; i++ ) {
2744 		gs = &mvd.gamestates[i];
2745 		if( gs->cm.cache ) {
2746 			CM_FreeMap( &gs->cm );
2747 		}
2748 	}
2749 
2750 	if( mvd.state ) {
2751 		memset( &mvd, 0, sizeof( mvd ) );
2752 	}
2753 
2754 	Cvar_SetInteger( "mvd_running", 0 );
2755 }
2756 
2757 
2758 
2759