Quake II RTX doxygen  1.0 dev
init.c
Go to the documentation of this file.
1 /*
2 Copyright (C) 1997-2001 Id Software, Inc.
3 
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (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. See the
12 GNU General Public License for more details.
13 
14 You should have received a copy of the GNU General Public License along
15 with this program; if not, write to the Free Software Foundation, Inc.,
16 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 */
18 
19 #include "server.h"
20 
21 server_static_t svs; // persistant server info
22 server_t sv; // local server
23 
24 void SV_ClientReset(client_t *client)
25 {
26  if (client->state < cs_connected) {
27  return;
28  }
29 
30  // any partially connected client will be restarted
31  client->state = cs_connected;
32  client->framenum = 1; // frame 0 can't be used
33  client->lastframe = -1;
34  client->frames_nodelta = 0;
35  client->send_delta = 0;
36  client->suppress_count = 0;
37  memset(&client->lastcmd, 0, sizeof(client->lastcmd));
38 }
39 
40 static void set_frame_time(void)
41 {
42 #if USE_FPS
43  int framediv;
44 
45  if (g_features->integer & GMF_VARIABLE_FPS)
46  framediv = sv_fps->integer / BASE_FRAMERATE;
47  else
48  framediv = 1;
49 
50  clamp(framediv, 1, MAX_FRAMEDIV);
51 
52  sv.framerate = framediv * BASE_FRAMERATE;
53  sv.frametime = BASE_FRAMETIME / framediv;
54  sv.framediv = framediv;
55 
56  Cvar_SetInteger(sv_fps, sv.framerate, FROM_CODE);
57 #endif
58 }
59 
60 static void resolve_masters(void)
61 {
62 #if !USE_CLIENT
63  master_t *m;
64  time_t now, delta;
65 
66  now = time(NULL);
68  // re-resolve valid address after one day,
69  // resolve invalid address after three hours
70  delta = m->adr.port ? 24 * 60 * 60 : 3 * 60 * 60;
71  if (now < m->last_resolved) {
72  m->last_resolved = now;
73  continue;
74  }
75  if (now - m->last_resolved < delta) {
76  continue;
77  }
78  if (NET_StringToAdr(m->name, &m->adr, PORT_MASTER)) {
79  Com_DPrintf("Master server at %s.\n", NET_AdrToString(&m->adr));
80  } else {
81  Com_WPrintf("Couldn't resolve master: %s\n", m->name);
82  m->adr.port = 0;
83  }
84  m->last_resolved = now = time(NULL);
85  }
86 #endif
87 }
88 
89 // optionally load the entity string from external source
90 static void override_entity_string(const char *server)
91 {
92  char *path = map_override_path->string;
93  char buffer[MAX_QPATH], *str;
94  ssize_t len;
95 
96  if (!*path) {
97  return;
98  }
99 
100  len = Q_concat(buffer, sizeof(buffer), path, server, ".ent", NULL);
101  if (len >= sizeof(buffer)) {
102  len = Q_ERR_NAMETOOLONG;
103  goto fail1;
104  }
105 
106  len = SV_LoadFile(buffer, (void **)&str);
107  if (!str) {
108  if (len == Q_ERR_NOENT) {
109  return;
110  }
111  goto fail1;
112  }
113 
114  if (len > MAX_MAP_ENTSTRING) {
115  len = Q_ERR_FBIG;
116  goto fail2;
117  }
118 
119  Com_Printf("Loaded entity string from %s\n", buffer);
120  sv.entitystring = str;
121  return;
122 
123 fail2:
124  SV_FreeFile(str);
125 fail1:
126  Com_EPrintf("Couldn't load entity string from %s: %s\n",
127  buffer, Q_ErrorString(len));
128 }
129 
130 
131 /*
132 ================
133 SV_SpawnServer
134 
135 Change the server to a new map, taking all connected
136 clients along with it.
137 ================
138 */
140 {
141  int i;
142  client_t *client;
143  char *entitystring;
144 
145  SCR_BeginLoadingPlaque(); // for local system
146 
147  Com_Printf("------- Server Initialization -------\n");
148  Com_Printf("SpawnServer: %s\n", cmd->server);
149 
150  static qboolean warning_printed = qfalse;
151  if (dedicated->integer && !SV_NoSaveGames() && !warning_printed)
152  {
153  Com_Printf("\nWARNING: Dedicated coop servers save game state into the same place as single player game by default (currently '%s/%s'). "
154  "To override that, set the 'sv_savedir' console variable. To host multiple dedicated coop servers on one machine, set that cvar "
155  "to different values on different instances of the server.\n\n", fs_gamedir, Cvar_WeakGet("sv_savedir")->string);
156 
157  warning_printed = qtrue;
158  }
159 
160  // everyone needs to reconnect
161  FOR_EACH_CLIENT(client) {
162  SV_ClientReset(client);
163  }
164 
165  SV_BroadcastCommand("changing map=%s\n", cmd->server);
168 
169  // free current level
170  CM_FreeMap(&sv.cm);
172 
173  // wipe the entire per-level structure
174  memset(&sv, 0, sizeof(sv));
175  sv.spawncount = (rand() | (rand() << 16)) ^ Sys_Milliseconds();
176  sv.spawncount &= 0x7FFFFFFF;
177 
178  // set legacy spawncounts
179  FOR_EACH_CLIENT(client) {
180  client->spawncount = sv.spawncount;
181  }
182 
183  // reset entity counter
184  svs.next_entity = 0;
185 
186  // set framerate parameters
187  set_frame_time();
188 
189  // save name for levels that don't set message
190  Q_strlcpy(sv.configstrings[CS_NAME], cmd->server, MAX_QPATH);
191  Q_strlcpy(sv.name, cmd->server, sizeof(sv.name));
192  Q_strlcpy(sv.mapcmd, cmd->buffer, sizeof(sv.mapcmd));
193 
194  if (Cvar_VariableInteger("deathmatch")) {
195  sprintf(sv.configstrings[CS_AIRACCEL], "%d", sv_airaccelerate->integer);
196  } else {
197  strcpy(sv.configstrings[CS_AIRACCEL], "0");
198  }
199 
200  resolve_masters();
201 
202  if (cmd->state == ss_game) {
204 
205  sv.cm = cmd->cm;
206  sprintf(sv.configstrings[CS_MAPCHECKSUM], "%d", (int)sv.cm.cache->checksum);
207 
208  // set inline model names
209  Q_concat(sv.configstrings[CS_MODELS + 1], MAX_QPATH, "maps/", cmd->server, ".bsp", NULL);
210  for (i = 1; i < sv.cm.cache->nummodels; i++) {
211  sprintf(sv.configstrings[CS_MODELS + 1 + i], "*%d", i);
212  }
213 
214  entitystring = sv.entitystring ? sv.entitystring : sv.cm.cache->entitystring;
215  } else {
216  // no real map
217  strcpy(sv.configstrings[CS_MAPCHECKSUM], "0");
218  entitystring = "";
219  }
220 
221  //
222  // clear physics interaction links
223  //
224  SV_ClearWorld();
225 
226  //
227  // spawn the rest of the entities on the map
228  //
229 
230  // precache and static commands can be issued during
231  // map initialization
232  sv.state = ss_loading;
233 
234  X86_PUSH_FPCW;
235  X86_SINGLE_FPCW;
236 
237  // load and spawn all other entities
238  ge->SpawnEntities(sv.name, entitystring, cmd->spawnpoint);
239 
240  // run two frames to allow everything to settle
241  ge->RunFrame(); sv.framenum++;
242  ge->RunFrame(); sv.framenum++;
243 
244  X86_POP_FPCW;
245 
246  // make sure maxclients string is correct
247  sprintf(sv.configstrings[CS_MAXCLIENTS], "%d", sv_maxclients->integer);
248 
249  // check for a savegame
250  SV_CheckForSavegame(cmd);
251 
252  // all precaches are complete
253  sv.state = cmd->state;
254 
255  // respawn dummy MVD client, set base states, etc
257 
258  // set serverinfo variable
259  SV_InfoSet("mapname", sv.name);
260  SV_InfoSet("port", net_port->string);
261 
262  Cvar_SetInteger(sv_running, sv.state, FROM_CODE);
263  Cvar_Set("sv_paused", "0");
264  Cvar_Set("timedemo", "0");
265 
266  EXEC_TRIGGER(sv_changemapcmd);
267 
268 #if USE_SYSCON
269  SV_SetConsoleTitle();
270 #endif
271 
272  SV_BroadcastCommand("reconnect\n");
273 
274  Com_Printf("-------------------------------------\n");
275 }
276 
277 /*
278 ==============
279 SV_ParseMapCmd
280 
281 Parses mapcmd into more C friendly form.
282 Loads and fully validates the map to make sure server doesn't get killed.
283 ==============
284 */
285 qboolean SV_ParseMapCmd(mapcmd_t *cmd)
286 {
287  char expanded[MAX_QPATH];
288  char *s, *ch;
289  qerror_t ret;
290  size_t len;
291 
292  s = cmd->buffer;
293 
294  // skip the end-of-unit flag if necessary
295  if (*s == '*') {
296  s++;
297  cmd->endofunit = qtrue;
298  }
299 
300  // if there is a + in the map, set nextserver to the remainder.
301  ch = strchr(s, '+');
302  if (ch)
303  {
304  *ch = 0;
305  Cvar_Set("nextserver", va("gamemap \"%s\"", ch + 1));
306  }
307  else
308  Cvar_Set("nextserver", "");
309 
310  cmd->server = s;
311 
312  // if there is a $, use the remainder as a spawnpoint
313  ch = strchr(s, '$');
314  if (ch) {
315  *ch = 0;
316  cmd->spawnpoint = ch + 1;
317  } else {
318  cmd->spawnpoint = cmd->buffer + strlen(cmd->buffer);
319  }
320 
321  // now expand and try to load the map
322  if (!COM_CompareExtension(s, ".pcx")) {
323  len = Q_concat(expanded, sizeof(expanded), "pics/", s, NULL);
324  if (len >= sizeof(expanded)) {
325  ret = Q_ERR_NAMETOOLONG;
326  } else {
327  ret = FS_LoadFile(expanded, NULL);
328  }
329  cmd->state = ss_pic;
330  }
331  else if (!COM_CompareExtension(s, ".cin")) {
332  ret = Q_ERR_SUCCESS;
333  cmd->state = ss_cinematic;
334  }
335  else {
336  len = Q_concat(expanded, sizeof(expanded), "maps/", s, ".bsp", NULL);
337  if (len >= sizeof(expanded)) {
338  ret = Q_ERR_NAMETOOLONG;
339  } else {
340  ret = CM_LoadMap(&cmd->cm, expanded);
341  }
342  cmd->state = ss_game;
343  }
344 
345  if (ret < 0) {
346  Com_Printf("Couldn't load %s: %s\n", expanded, Q_ErrorString(ret));
347  return qfalse;
348  }
349 
350  return qtrue;
351 }
352 
353 /*
354 ==============
355 SV_InitGame
356 
357 A brand new game has been started.
358 If mvd_spawn is non-zero, load the built-in MVD game module.
359 ==============
360 */
361 void SV_InitGame(unsigned mvd_spawn)
362 {
363  int i, entnum;
364  edict_t *ent;
365  client_t *client;
366 
367  if (svs.initialized) {
368  // cause any connected clients to reconnect
369  SV_Shutdown("Server restarted\n", ERR_RECONNECT | mvd_spawn);
370  } else {
371  // make sure the client is down
372  CL_Disconnect(ERR_RECONNECT);
374 
375  CM_FreeMap(&sv.cm);
377  memset(&sv, 0, sizeof(sv));
378 
379 #if USE_FPS
380  // set up default frametime for main loop
381  sv.frametime = BASE_FRAMETIME;
382 #endif
383  }
384 
385  // get any latched variable changes (maxclients, etc)
387 
388 #if !USE_CLIENT
389  Cvar_Reset(sv_recycle);
390 #endif
391 
392  if (mvd_spawn) {
393  Cvar_Set("deathmatch", "1");
394  Cvar_Set("coop", "0");
395  } else {
396  if (Cvar_VariableInteger("coop") &&
397  Cvar_VariableInteger("deathmatch")) {
398  Com_Printf("Deathmatch and Coop both set, disabling Coop\n");
399  Cvar_Set("coop", "0");
400  }
401 
402  // dedicated servers can't be single player and are usually DM
403  // so unless they explicity set coop, force it to deathmatch
404  if (COM_DEDICATED) {
405  if (!Cvar_VariableInteger("coop"))
406  Cvar_Set("deathmatch", "1");
407  }
408  }
409 
410  // init clients
411  if (Cvar_VariableInteger("deathmatch")) {
412  if (sv_maxclients->integer <= 1) {
413  Cvar_SetInteger(sv_maxclients, 8, FROM_CODE);
414  } else if (sv_maxclients->integer > CLIENTNUM_RESERVED) {
415  Cvar_SetInteger(sv_maxclients, CLIENTNUM_RESERVED, FROM_CODE);
416  }
417  } else if (Cvar_VariableInteger("coop")) {
418  if (sv_maxclients->integer <= 1 || sv_maxclients->integer > 4)
419  Cvar_Set("maxclients", "4");
420  } else { // non-deathmatch, non-coop is one player
421  Cvar_FullSet("maxclients", "1", CVAR_SERVERINFO | CVAR_LATCH, FROM_CODE);
422  }
423 
424  // enable networking
425  if (sv_maxclients->integer > 1) {
426  NET_Config(NET_SERVER);
427  }
428 
429  svs.client_pool = SV_Mallocz(sizeof(client_t) * sv_maxclients->integer);
430 
431  svs.num_entities = sv_maxclients->integer * UPDATE_BACKUP * MAX_PACKET_ENTITIES;
432  svs.entities = SV_Mallocz(sizeof(entity_packed_t) * svs.num_entities);
433 
434  // initialize MVD server
435  if (!mvd_spawn) {
436  SV_MvdInit();
437  }
438 
440 
441 #if USE_ZLIB
442  svs.z.zalloc = SV_zalloc;
443  svs.z.zfree = SV_zfree;
444  if (deflateInit2(&svs.z, Z_DEFAULT_COMPRESSION, Z_DEFLATED,
445  -MAX_WBITS, 9, Z_DEFAULT_STRATEGY) != Z_OK) {
446  Com_Error(ERR_FATAL, "%s: deflateInit2() failed", __func__);
447  }
448 #endif
449 
450  // init game
451 #if USE_MVD_CLIENT
452  if (mvd_spawn) {
453  if (ge) {
455  }
456  ge = &mvd_ge;
457  ge->Init();
458  } else
459 #endif
461 
462  // send heartbeat very soon
463  svs.last_heartbeat = -(HEARTBEAT_SECONDS - 5) * 1000;
464 
465  for (i = 0; i < sv_maxclients->integer; i++) {
466  client = svs.client_pool + i;
467  entnum = i + 1;
468  ent = EDICT_NUM(entnum);
469  ent->s.number = entnum;
470  client->edict = ent;
471  client->number = i;
472  }
473 
474  AC_Connect(mvd_spawn);
475 
476  svs.initialized = qtrue;
477 }
478 
client_s::lastframe
int lastframe
Definition: server.h:290
server_static_s::next_entity
unsigned next_entity
Definition: server.h:459
server_t::framenum
int framenum
Definition: server.h:155
server_t::entitystring
char * entitystring
Definition: server.h:162
SV_Shutdown
void SV_Shutdown(const char *finalmsg, error_type_t type)
Definition: main.c:2252
Cvar_Set
cvar_t * Cvar_Set(const char *var_name, const char *value)
Definition: cvar.c:466
CM_FreeMap
void CM_FreeMap(cm_t *cm)
Definition: cmodel.c:47
set_frame_time
static void set_frame_time(void)
Definition: init.c:40
server_t
Definition: server.h:145
SV_BroadcastCommand
void SV_BroadcastCommand(const char *fmt,...)
Definition: send.c:214
svs
server_static_t svs
Definition: init.c:21
NET_AdrToString
char * NET_AdrToString(const netadr_t *a)
Definition: net.c:257
client_s::send_delta
unsigned send_delta
Definition: server.h:312
mapcmd_t::state
server_state_t state
Definition: server.h:441
CM_LoadMap
qerror_t CM_LoadMap(cm_t *cm, const char *name)
Definition: cmodel.c:64
master_t
Definition: server.h:429
server_static_s::entities
entity_packed_t * entities
Definition: server.h:460
SV_CheckForSavegame
void SV_CheckForSavegame(mapcmd_t *cmd)
Definition: save.c:550
Q_ErrorString
const char * Q_ErrorString(qerror_t error)
Definition: error.c:51
client_s::state
clstate_t state
Definition: server.h:260
SV_SendClientMessages
void SV_SendClientMessages(void)
Definition: send.c:880
client_s::number
int number
Definition: server.h:262
client_s::spawncount
int spawncount
Definition: server.h:348
SV_ClearWorld
void SV_ClearWorld(void)
Definition: world.c:101
override_entity_string
static void override_entity_string(const char *server)
Definition: init.c:90
server_t::mapcmd
char mapcmd[MAX_QPATH]
Definition: server.h:158
SV_InfoSet
#define SV_InfoSet(var, val)
Definition: server.h:73
mapcmd_t::spawnpoint
char * spawnpoint
Definition: server.h:440
SV_MvdInit
void SV_MvdInit(void)
Definition: mvd.c:2068
client_s::suppress_count
int suppress_count
Definition: server.h:311
sv_changemapcmd
cvar_t * sv_changemapcmd
Definition: main.c:74
sv_airaccelerate
cvar_t * sv_airaccelerate
Definition: main.c:54
Sys_Milliseconds
unsigned Sys_Milliseconds(void)
Definition: system.c:644
CL_Disconnect
void CL_Disconnect(error_type_t type)
Definition: main.c:740
FOR_EACH_MASTER
#define FOR_EACH_MASTER(m)
Definition: server.h:447
SV_MvdMapChanged
void SV_MvdMapChanged(void)
Definition: mvd.c:1990
FOR_EACH_CLIENT
#define FOR_EACH_CLIENT(client)
Definition: server.h:239
sv_reserved_slots
cvar_t * sv_reserved_slots
Definition: main.c:59
resolve_masters
static void resolve_masters(void)
Definition: init.c:60
mapcmd_t::server
char * server
Definition: server.h:439
server_static_s::last_heartbeat
unsigned last_heartbeat
Definition: server.h:466
Com_Error
void Com_Error(error_type_t type, const char *fmt,...)
Definition: g_main.c:258
HEARTBEAT_SECONDS
#define HEARTBEAT_SECONDS
Definition: server.h:427
dedicated
cvar_t * dedicated
Definition: g_main.c:46
SV_SendAsyncPackets
void SV_SendAsyncPackets(void)
Definition: send.c:987
sv
server_t sv
Definition: init.c:22
SV_ParseMapCmd
qboolean SV_ParseMapCmd(mapcmd_t *cmd)
Definition: init.c:285
AC_Connect
void AC_Connect(unsigned mvd_spawn)
Definition: ac.c:1437
SV_SpawnServer
void SV_SpawnServer(mapcmd_t *cmd)
Definition: init.c:139
SV_LoadFile
#define SV_LoadFile(path, buf)
Definition: server.h:57
net_port
cvar_t * net_port
Definition: net.c:88
va
char * va(const char *format,...)
Definition: shared.c:429
server_static_s::client_pool
client_t * client_pool
Definition: server.h:456
client_s::lastcmd
usercmd_t lastcmd
Definition: server.h:291
server_static_s::initialized
qboolean initialized
Definition: server.h:453
m
static struct mdfour * m
Definition: mdfour.c:32
SV_FreeFile
#define SV_FreeFile(buf)
Definition: server.h:58
Cvar_VariableInteger
int Cvar_VariableInteger(const char *var_name)
Definition: cvar.c:105
NET_StringToAdr
qboolean NET_StringToAdr(const char *s, netadr_t *a, int default_port)
Definition: net.c:332
NET_Config
void NET_Config(netflag_t flag)
Definition: net.c:1312
Q_strlcpy
size_t Q_strlcpy(char *dst, const char *src, size_t size)
Definition: shared.c:715
SV_InitGameProgs
void SV_InitGameProgs(void)
Definition: game.c:841
ge
game_export_t * ge
Definition: game.c:22
mapcmd_t
Definition: server.h:437
Cvar_SetInteger
void Cvar_SetInteger(cvar_t *var, int value, from_t from)
Definition: cvar.c:509
Cvar_FullSet
cvar_t * Cvar_FullSet(const char *var_name, const char *value, int flags, from_t from)
Definition: cvar.c:437
server_static_s
Definition: server.h:452
Cvar_WeakGet
cvar_t * Cvar_WeakGet(const char *var_name)
Definition: cvar.c:324
server_static_s::num_entities
unsigned num_entities
Definition: server.h:458
server_t::cm
cm_t cm
Definition: server.h:161
mapcmd_t::cm
cm_t cm
Definition: server.h:444
mapcmd_t::endofunit
qboolean endofunit
Definition: server.h:443
Cvar_ClampInteger
int Cvar_ClampInteger(cvar_t *var, int min, int max)
Definition: cvar.c:549
SV_InitGame
void SV_InitGame(unsigned mvd_spawn)
Definition: init.c:361
g_features
cvar_t * g_features
Definition: main.c:99
sv_recycle
cvar_t * sv_recycle
Definition: main.c:83
Cvar_GetLatchedVars
void Cvar_GetLatchedVars(void)
Definition: cvar.c:626
SV_ShutdownGameProgs
void SV_ShutdownGameProgs(void)
Definition: game.c:786
server_t::state
server_state_t state
Definition: server.h:146
mapcmd_t::buffer
char buffer[MAX_QPATH]
Definition: server.h:438
client_s
Definition: server.h:256
SV_Mallocz
#define SV_Mallocz(size)
Definition: server.h:55
SCR_BeginLoadingPlaque
void SCR_BeginLoadingPlaque(void)
Definition: screen.c:1424
SV_NoSaveGames
int SV_NoSaveGames(void)
Definition: save.c:460
mvd_ge
game_export_t mvd_ge
Definition: game.c:2285
sv_running
cvar_t * sv_running
Definition: common.c:95
Q_concat
size_t Q_concat(char *dest, size_t size,...)
Definition: shared.c:758
EDICT_NUM
#define EDICT_NUM(n)
Definition: server.h:173
server_t::spawncount
int spawncount
Definition: server.h:147
server.h
server_t::configstrings
char configstrings[MAX_CONFIGSTRINGS][MAX_QPATH]
Definition: server.h:164
map_override_path
cvar_t * map_override_path
Definition: main.c:101
fs_gamedir
char fs_gamedir[MAX_OSPATH]
Definition: files.c:171
client_s::framenum
int framenum
Definition: server.h:303
cs_connected
@ cs_connected
Definition: server.h:190
server_t::name
char name[MAX_QPATH]
Definition: server.h:160
SV_ClientReset
void SV_ClientReset(client_t *client)
Definition: init.c:24
client_s::frames_nodelta
unsigned frames_nodelta
Definition: server.h:302
client_s::edict
edict_t * edict
Definition: server.h:261
sv_maxclients
cvar_t * sv_maxclients
Definition: main.c:58