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