1 /*
2 Copyright (C) 1996-1997 Id Software, Inc.
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 #ifndef CLIENTONLY
23 #include "qwsvdef.h"
24 
25 server_static_t	svs;				// persistent server info
26 server_t		sv;					// local server
27 demo_t			demo;				// server demo struct
28 
29 char	localmodels[MAX_MODELS][5];	// inline model names for precache
30 
31 //char localinfo[MAX_LOCALINFO_STRING+1]; // local game info
32 ctxinfo_t _localinfo_;
33 
34 int fofs_items2;
35 int fofs_maxspeed, fofs_gravity;
36 int fofs_movement;
37 int fofs_vw_index;
38 int fofs_hideentity;
39 int fofs_trackent;
40 int fofs_visibility;
41 int fofs_hide_players;
42 int fofs_teleported;
43 
44 /*
45 ================
46 SV_ModelIndex
47 
48 ================
49 */
SV_ModelIndex(char * name)50 int SV_ModelIndex (char *name)
51 {
52 	int i;
53 
54 	if (!name || !name[0])
55 		return 0;
56 
57 	for (i=0 ; i<MAX_MODELS && sv.model_precache[i] ; i++)
58 		if (!strcmp(sv.model_precache[i], name))
59 			return i;
60 	if (i==MAX_MODELS || !sv.model_precache[i])
61 		SV_Error ("SV_ModelIndex: model %s not precached", name);
62 	return i;
63 }
64 
65 /*
66 ================
67 SV_FlushSignon
68 
69 Moves to the next signon buffer if needed
70 ================
71 */
SV_FlushSignon(void)72 void SV_FlushSignon (void)
73 {
74 	if (sv.signon.cursize < sv.signon.maxsize - 512)
75 		return;
76 
77 	if (sv.num_signon_buffers == MAX_SIGNON_BUFFERS-1)
78 		SV_Error ("sv.num_signon_buffers == MAX_SIGNON_BUFFERS-1");
79 
80 	sv.signon_buffer_size[sv.num_signon_buffers-1] = sv.signon.cursize;
81 	sv.signon.data = sv.signon_buffers[sv.num_signon_buffers];
82 	sv.num_signon_buffers++;
83 	sv.signon.cursize = 0;
84 }
85 
86 /*
87 ================
88 SV_CreateBaseline
89 
90 Entity baselines are used to compress the update messages
91 to the clients -- only the fields that differ from the
92 baseline will be transmitted
93 ================
94 */
SV_CreateBaseline(void)95 static void SV_CreateBaseline (void)
96 {
97 	edict_t  *svent;
98 	int      entnum;
99 
100 	for (entnum = 0; entnum < sv.num_edicts ; entnum++)
101 	{
102 		svent = EDICT_NUM(entnum);
103 		if (svent->e->free)
104 			continue;
105 		// create baselines for all player slots,
106 		// and any other edict that has a visible model
107 		if (entnum > MAX_CLIENTS && !svent->v.modelindex)
108 			continue;
109 
110 		//
111 		// create entity baseline
112 		//
113 		svent->e->baseline.number = entnum;
114 		VectorCopy (svent->v.origin, svent->e->baseline.origin);
115 		VectorCopy (svent->v.angles, svent->e->baseline.angles);
116 		svent->e->baseline.frame = svent->v.frame;
117 		svent->e->baseline.skinnum = svent->v.skin;
118 		if (entnum > 0 && entnum <= MAX_CLIENTS)
119 		{
120 			svent->e->baseline.colormap = entnum;
121 			svent->e->baseline.modelindex = SV_ModelIndex("progs/player.mdl");
122 		}
123 		else
124 		{
125 			svent->e->baseline.colormap = 0;
126 			svent->e->baseline.modelindex = svent->v.modelindex;
127 		}
128 	}
129 	sv.num_baseline_edicts = sv.num_edicts;
130 }
131 
132 /*
133 ================
134 SV_SaveSpawnparms
135 
136 Grabs the current state of the progs serverinfo flags
137 and each client for saving across the
138 transition to another level
139 ================
140 */
SV_SaveSpawnparms(void)141 static void SV_SaveSpawnparms (void)
142 {
143 	int i, j;
144 
145 	if (!sv.state)
146 		return;		// no progs loaded yet
147 
148 	// serverflags is the only game related thing maintained
149 	svs.serverflags = PR_GLOBAL(serverflags);
150 
151 	for (i=0, sv_client = svs.clients ; i<MAX_CLIENTS ; i++, sv_client++)
152 	{
153 		if (sv_client->state != cs_spawned)
154 			continue;
155 
156 		// needs to reconnect
157 		sv_client->state = cs_connected;
158 
159 		// call the progs to get default spawn parms for the new client
160 		pr_global_struct->self = EDICT_TO_PROG(sv_client->edict);
161 		PR_GameSetChangeParms();
162 		for (j=0 ; j<NUM_SPAWN_PARMS ; j++)
163 			sv_client->spawn_parms[j] = (&PR_GLOBAL(parm1))[j];
164 	}
165 }
166 
SV_CheckModel(char * mdl)167 static unsigned SV_CheckModel(char *mdl)
168 {
169 	unsigned char *buf;
170 	unsigned short crc;
171 	int filesize;
172 	int mark;
173 
174 	mark = Hunk_LowMark ();
175 	buf = (byte *) FS_LoadHunkFile (mdl, &filesize);
176 	if (!buf)
177 	{
178 		if (!strcmp (mdl, "progs/player.mdl"))
179 			return 33168;
180 		else if (!strcmp (mdl, "progs/newplayer.mdl"))
181 			return 62211;
182 		else if (!strcmp (mdl, "progs/eyes.mdl"))
183 			return 6967;
184 		else
185 			SV_Error ("SV_CheckModel: could not load %s\n", mdl);
186 	}
187 
188 	crc = CRC_Block (buf, filesize);
189 	Hunk_FreeToLowMark (mark);
190 
191 	return crc;
192 }
193 
194 /*
195 ================
196 SV_SpawnServer
197 
198 Change the server to a new map, taking all connected
199 clients along with it.
200 
201 This is called from the SV_Map_f() function, and when loading .sav files
202 ================
203 */
SV_SpawnServer(char * mapname,qbool devmap,char * entityfile,qbool loading_savegame)204 void SV_SpawnServer(char *mapname, qbool devmap, char* entityfile, qbool loading_savegame)
205 {
206 	extern func_t ED_FindFunctionOffset (char *name);
207 
208 	edict_t *ent;
209 	int i;
210 	int skill_level = current_skill;
211 
212 	extern cvar_t sv_loadentfiles, sv_loadentfiles_dir;
213 	char *entitystring;
214 	char oldmap[MAP_NAME_LEN];
215 	extern qbool	sv_allow_cheats;
216 	extern cvar_t	sv_cheats, sv_paused, sv_bigcoords;
217 #ifndef SERVERONLY
218 	extern void CL_ClearState (void);
219 #endif
220 
221 	// store old map name
222 	snprintf (oldmap, MAP_NAME_LEN, "%s", sv.mapname);
223 
224 	Con_DPrintf ("SpawnServer: %s\n",mapname);
225 
226 #ifndef SERVERONLY
227 	// As client+server we do it here.
228 	// As serveronly we do it in NET_Init().
229 	NET_InitServer();
230 #endif
231 
232 	SV_SaveSpawnparms ();
233 	SV_LoadAccounts();
234 
235 #ifdef USE_PR2
236 	// remove bot clients
237 	for (i = 0; i < MAX_CLIENTS; i++)
238 	{
239 		if( sv_vm && svs.clients[i].isBot )
240 		{
241 			svs.clients[i].old_frags = 0;
242 			svs.clients[i].edict->v.frags = 0.0;
243 			svs.clients[i].name[0] = 0;
244 			svs.clients[i].state = cs_free;
245 			Info_RemoveAll(&svs.clients[i]._userinfo_ctx_);
246 			Info_RemoveAll(&svs.clients[i]._userinfoshort_ctx_);
247 			SV_FullClientUpdate(&svs.clients[i], &sv.reliable_datagram);
248 			svs.clients[i].isBot = 0;
249 		}
250 	}
251 #endif
252 
253 	// Shutdown game.
254 	PR_GameShutDown();
255 	PR_UnLoadProgs();
256 
257 	svs.spawncount++; // any partially connected client will be restarted
258 
259 #ifndef SERVERONLY
260 	com_serveractive = false;
261 #endif
262 	sv.state = ss_dead;
263 	sv.paused = false;
264 	Cvar_SetROM(&sv_paused, "0");
265 
266 	Host_ClearMemory();
267 
268 #ifndef SERVERONLY
269 	if (!oldmap[0]) {
270 		Cbuf_InsertTextEx(&cbuf_server, "exec server.cfg\n");
271 		Cbuf_ExecuteEx(&cbuf_server);
272 	}
273 #endif
274 
275 	if (loading_savegame) {
276 		Cvar_SetValue(&skill, skill_level);
277 		Cvar_SetValue(&deathmatch, 0);
278 		Cvar_SetValue(&coop, 0);
279 		Cvar_SetValue(&teamplay, 0);
280 		Cvar_SetValue(&maxclients, 1);
281 		Cvar_Set(&sv_progsname, "spprogs"); // force progsname
282 #ifdef USE_PR2
283 		Cvar_SetValue(&sv_progtype, 0); // force .dat
284 #endif
285 	}
286 
287 #ifdef FTE_PEXT_FLOATCOORDS
288 	if (sv_bigcoords.value)
289 	{
290 		msg_coordsize = 4;
291 		msg_anglesize = 2;
292 	}
293 	else
294 	{
295 		msg_coordsize = 2;
296 		msg_anglesize = 1;
297 	}
298 #endif
299 
300 	if ((int)coop.value)
301 		Cvar_Set (&deathmatch, "0");
302 	current_skill = (int) (skill.value + 0.5);
303 	if (current_skill < 0)
304 		current_skill = 0;
305 	Cvar_Set (&skill, va("%d", current_skill));
306 	if (current_skill > 3)
307 		current_skill = 3;
308 
309 	if ((sv_cheats.value || devmap) && !sv_allow_cheats) {
310 		sv_allow_cheats = true;
311 		Info_SetValueForStarKey (svs.info, "*cheats", "ON", MAX_SERVERINFO_STRING);
312 	}
313 	else if ((!sv_cheats.value && !devmap) && sv_allow_cheats) {
314 		sv_allow_cheats = false;
315 		Info_SetValueForStarKey (svs.info, "*cheats", "", MAX_SERVERINFO_STRING);
316 	}
317 
318 
319 	// wipe the entire per-level structure
320 	// NOTE: this also set sv.mvdrecording to false, so calling SV_MVD_Record() at end of function
321 	memset (&sv, 0, sizeof(sv));
322 	sv.max_edicts = MAX_EDICTS_SAFE;
323 
324 	sv.datagram.maxsize = sizeof(sv.datagram_buf);
325 	sv.datagram.data = sv.datagram_buf;
326 	sv.datagram.allowoverflow = true;
327 
328 	sv.reliable_datagram.maxsize = sizeof(sv.reliable_datagram_buf);
329 	sv.reliable_datagram.data = sv.reliable_datagram_buf;
330 
331 	sv.multicast.maxsize = sizeof(sv.multicast_buf);
332 	sv.multicast.data = sv.multicast_buf;
333 
334 	sv.signon.maxsize = sizeof(sv.signon_buffers[0]);
335 	sv.signon.data = sv.signon_buffers[0];
336 	sv.num_signon_buffers = 1;
337 
338 	sv.time = 1.0;
339 
340 	// load progs to get entity field count
341 	// which determines how big each edict is
342 	// and allocate edicts
343 	PR_LoadProgs ();
344 #ifdef WITH_NQPROGS
345 	PR_InitPatchTables();
346 #endif
347 	PR_InitProg();
348 
349 	for (i = 0; i < sv.max_edicts; i++)
350 	{
351 		ent = EDICT_NUM(i);
352 		ent->e = &sv.sv_edicts[i]; // assigning ->e field in each edict_t
353 		ent->e->entnum = i;
354 		ent->e->area.ed = ent; // yeah, pretty funny, but this help to find which edict_t own this area (link_t)
355 		PR_ClearEdict(ent);
356 	}
357 
358 	fofs_items2 = ED_FindFieldOffset ("items2"); // ZQ_ITEMS2 extension
359 	fofs_maxspeed = ED_FindFieldOffset ("maxspeed");
360 	fofs_gravity = ED_FindFieldOffset ("gravity");
361 	fofs_movement = ED_FindFieldOffset ("movement");
362 	fofs_vw_index = ED_FindFieldOffset ("vw_index");
363 	fofs_hideentity = ED_FindFieldOffset ("hideentity");
364 	fofs_trackent = ED_FindFieldOffset ("trackent");
365 	fofs_visibility = ED_FindFieldOffset ("visclients");
366 	fofs_hide_players = ED_FindFieldOffset ("hideplayers");
367 	fofs_teleported = ED_FindFieldOffset ("teleported");
368 
369 #ifdef MVD_PEXT1_HIGHLAGTELEPORT
370 	if (fofs_teleported) {
371 		svs.mvdprotocolextension1 |= MVD_PEXT1_HIGHLAGTELEPORT;
372 	}
373 	else {
374 		svs.mvdprotocolextension1 &= ~MVD_PEXT1_HIGHLAGTELEPORT;
375 	}
376 #endif
377 #ifdef MVD_PEXT1_SERVERSIDEWEAPON
378 	{
379 		extern cvar_t sv_pext_mvdsv_serversideweapon;
380 
381 		// Cheap 'ktx' detection
382 		if (sv_pext_mvdsv_serversideweapon.value && strstr(Cvar_String("qwm_name"), "KTX")) {
383 			svs.mvdprotocolextension1 |= MVD_PEXT1_SERVERSIDEWEAPON;
384 #ifdef MVD_PEXT1_SERVERSIDEWEAPON2
385 			svs.mvdprotocolextension1 |= MVD_PEXT1_SERVERSIDEWEAPON2;
386 #endif
387 		}
388 		else {
389 			svs.mvdprotocolextension1 &= ~MVD_PEXT1_SERVERSIDEWEAPON;
390 #ifdef MVD_PEXT1_SERVERSIDEWEAPON2
391 			svs.mvdprotocolextension1 &= ~MVD_PEXT1_SERVERSIDEWEAPON2;
392 #endif
393 		}
394 
395 	}
396 #endif
397 #ifdef MVD_PEXT1_DEBUG_ANTILAG
398 	{
399 		extern cvar_t sv_debug_antilag;
400 
401 		if (sv_debug_antilag.value) {
402 			svs.mvdprotocolextension1 |= MVD_PEXT1_DEBUG_ANTILAG;
403 		}
404 		else {
405 			svs.mvdprotocolextension1 &= ~MVD_PEXT1_DEBUG_ANTILAG;
406 		}
407 	}
408 #endif
409 #ifdef MVD_PEXT1_DEBUG_WEAPON
410 	{
411 		extern cvar_t sv_debug_weapons;
412 
413 		if (sv_debug_weapons.value) {
414 			svs.mvdprotocolextension1 |= MVD_PEXT1_DEBUG_WEAPON;
415 		}
416 		else {
417 			svs.mvdprotocolextension1 &= ~MVD_PEXT1_DEBUG_WEAPON;
418 		}
419 	}
420 #endif
421 
422 	// find optional QC-exported functions.
423 	// we have it here, so we set it to NULL in case of PR2 progs.
424 	mod_SpectatorConnect = ED_FindFunctionOffset ("SpectatorConnect");
425 	mod_SpectatorThink = ED_FindFunctionOffset ("SpectatorThink");
426 	mod_SpectatorDisconnect = ED_FindFunctionOffset ("SpectatorDisconnect");
427 	mod_ChatMessage = ED_FindFunctionOffset ("ChatMessage");
428 	mod_UserInfo_Changed = ED_FindFunctionOffset ("UserInfo_Changed");
429 	mod_ConsoleCmd = ED_FindFunctionOffset ("ConsoleCmd");
430 	mod_UserCmd = ED_FindFunctionOffset ("UserCmd");
431 	mod_localinfoChanged = ED_FindFunctionOffset ("localinfoChanged");
432 	GE_ClientCommand = ED_FindFunctionOffset ("GE_ClientCommand");
433 	GE_PausedTic = ED_FindFunctionOffset ("GE_PausedTic");
434 	GE_ShouldPause = ED_FindFunctionOffset ("GE_ShouldPause");
435 
436 	// leave slots at start for clients only
437 	sv.num_edicts = MAX_CLIENTS+1;
438 	for (i=0 ; i<MAX_CLIENTS ; i++)
439 	{
440 		ent = EDICT_NUM(i+1);
441 		// restore client name.
442 		PR_SetEntityString(ent, ent->v.netname, svs.clients[i].name);
443 		// reserve edict.
444 		svs.clients[i].edict = ent;
445 		//ZOID - make sure we update frags right
446 		svs.clients[i].old_frags = 0;
447 	}
448 
449 	// fill sv.mapname and sv.modelname with new map name
450 	strlcpy (sv.mapname, mapname, sizeof(sv.mapname));
451 	snprintf (sv.modelname, sizeof(sv.modelname), "maps/%s.bsp", sv.mapname);
452 #ifndef SERVERONLY
453 	// set cvar
454 	Cvar_ForceSet (&host_mapname, mapname);
455 #endif
456 
457 	if (!(sv.worldmodel = CM_LoadMap (sv.modelname, false, &sv.map_checksum, &sv.map_checksum2))) // true if bad map
458 	{
459 		Con_Printf ("Cant load map %s, falling back to %s\n", mapname, oldmap);
460 
461 		// fill mapname, sv.mapname and sv.modelname with old map name
462 		strlcpy (sv.mapname, oldmap, sizeof(sv.mapname));
463 		snprintf (sv.modelname, sizeof(sv.modelname), "maps/%s.bsp", sv.mapname);
464 		mapname = oldmap;
465 
466 		// and re-load old map
467 		sv.worldmodel = CM_LoadMap (sv.modelname, false, &sv.map_checksum, &sv.map_checksum2);
468 
469 		// this should never happen
470 		if (!sv.worldmodel)
471 			SV_Error ("CM_LoadMap: bad map");
472 	}
473 
474 	{
475 		extern cvar_t sv_extlimits, sv_bspversion;
476 
477 		if (sv_extlimits.value == 0 || (sv_extlimits.value == 2 && sv_bspversion.value < 2)) {
478 			sv.max_edicts = min(sv.max_edicts, MAX_EDICTS_SAFE);
479 		}
480 	}
481 
482 	sv.map_checksum2 = Com_TranslateMapChecksum (sv.mapname, sv.map_checksum2);
483 	sv.static_entity_count = 0;
484 
485 	SV_ClearWorld (); // clear physics interaction links
486 
487 #ifdef USE_PR2
488 	if ( sv_vm )
489 	{
490 		sv.sound_precache[0] = "";
491 		sv.model_precache[0] = "";
492 	}
493 	else
494 #endif
495 	{
496 		sv.sound_precache[0] = pr_strings;
497 		sv.model_precache[0] = pr_strings;
498 	}
499 	sv.model_precache[1] = sv.modelname;
500 	sv.models[1] = sv.worldmodel;
501 	for (i = 1; i < CM_NumInlineModels(); i++)
502 	{
503 		sv.model_precache[1+i] = localmodels[i];
504 		sv.models[i+1] =  CM_InlineModel (localmodels[i]);
505 	}
506 
507 	//check player/eyes models for hacks
508 	sv.model_player_checksum = SV_CheckModel("progs/player.mdl");
509 	sv.model_newplayer_checksum = SV_CheckModel("progs/newplayer.mdl");
510 	sv.eyes_player_checksum = SV_CheckModel("progs/eyes.mdl");
511 
512 	//
513 	// spawn the rest of the entities on the map
514 	//
515 
516 	// precache and static commands can be issued during
517 	// map initialization
518 	sv.state = ss_loading;
519 #ifndef SERVERONLY
520 	com_serveractive = true;
521 #endif
522 
523 	ent = EDICT_NUM(0);
524 	ent->e->free = false;
525 	PR_SetEntityString(ent, ent->v.model, sv.modelname);
526 	ent->v.modelindex = 1;		// world model
527 	ent->v.solid = SOLID_BSP;
528 	ent->v.movetype = MOVETYPE_PUSH;
529 
530 	// information about the server
531 	PR_SetEntityString(ent, ent->v.netname, VersionStringFull());
532 	PR_SetEntityString(ent, ent->v.targetname, SERVER_NAME);
533 	ent->v.impulse = VERSION_NUM;
534 	ent->v.items = pr_numbuiltins - 1;
535 
536 	PR_SetGlobalString(PR_GLOBAL(mapname), sv.mapname);
537 	// serverflags are for cross level information (sigils)
538 	PR_GLOBAL(serverflags) = svs.serverflags;
539 	if (pr_nqprogs)
540 	{
541 		pr_globals[35] = deathmatch.value;
542 		pr_globals[36] = coop.value;
543 		pr_globals[37] = teamplay.value;
544 		NQP_Reset ();
545 	}
546 
547 	if (pr_nqprogs)
548 	{
549 		// register the cvars that NetQuake provides for mod use
550 		const char **var, *nqcvars[] = {"gamecfg", "scratch1", "scratch2", "scratch3", "scratch4",
551 			"saved1", "saved2", "saved3", "saved4", "savedgamecfg", "temp1", NULL};
552 		for (var = nqcvars; *var; var++)
553 			Cvar_Create((char *)/*stupid const warning*/ *var, "0", 0);
554 	}
555 
556 	// run the frame start qc function to let progs check cvars
557 	if (!pr_nqprogs)
558 		SV_ProgStartFrame (false);
559 
560 	// ********* External Entity support (.ent file(s) in gamedir/maps) pinched from ZQuake *********
561 	// load and spawn all other entities
562 	entitystring = NULL;
563 	if ((int)sv_loadentfiles.value)
564 	{
565 		char ent_path[1024] = {0};
566 
567 		if (!entityfile || !entityfile[0])
568 			entityfile = sv.mapname;
569 
570 		// first try maps/sv_loadentfiles_dir/
571 		if (sv_loadentfiles_dir.string[0])
572 		{
573 			snprintf(ent_path, sizeof(ent_path), "maps/%s/%s.ent", sv_loadentfiles_dir.string, entityfile);
574 			entitystring = (char *) FS_LoadHunkFile(ent_path, NULL);
575 		}
576 
577 		// try maps/ if not loaded yet.
578 		if (!entitystring)
579 		{
580 			snprintf(ent_path, sizeof(ent_path), "maps/%s.ent", entityfile);
581 			entitystring = (char *) FS_LoadHunkFile(ent_path, NULL);
582 		}
583 
584 		if (entitystring) {
585 			Con_DPrintf ("Using entfile %s\n", ent_path);
586 		}
587 	}
588 
589 	if (!entitystring) {
590 		entitystring = CM_EntityString();
591 	}
592 
593 	PR_LoadEnts(entitystring);
594 	// ********* End of External Entity support code *********
595 
596 	// look up some model indexes for specialized message compression
597 	SV_FindModelNumbers ();
598 
599 	// all spawning is completed, any further precache statements
600 	// or prog writes to the signon message are errors
601 	sv.state = ss_active;
602 
603 	// run two frames to allow everything to settle
604 	SV_Physics ();
605 	sv.time += 0.1;
606 	SV_Physics ();
607 	sv.time += 0.1;
608 	sv.old_time = sv.time;
609 
610 	// save movement vars
611 	SV_SetMoveVars();
612 
613 	// create a baseline for more efficient communications
614 	SV_CreateBaseline ();
615 	sv.signon_buffer_size[sv.num_signon_buffers-1] = sv.signon.cursize;
616 
617 	Info_SetValueForKey (svs.info, "map", sv.mapname, MAX_SERVERINFO_STRING);
618 
619 	// calltimeofday.
620 	{
621 		extern void PF_calltimeofday (void);
622 		pr_global_struct->time = sv.time;
623 		pr_global_struct->self = 0;
624 
625 		PF_calltimeofday();
626 	}
627 
628 	Con_DPrintf ("Server spawned.\n");
629 
630 	// we change map - clear whole demo struct and sent initial state to all dest if any (for QTV only I thought)
631 	SV_MVD_Record(NULL, true);
632 
633 #ifndef SERVERONLY
634 	CL_ClearState ();
635 #endif
636 }
637 
638 #endif // !CLIENTONLY
639