Quake II RTX doxygen  1.0 dev
save.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 #define SAVE_MAGIC1 (('2'<<24)|('V'<<16)|('S'<<8)|'S') // "SSV2"
22 #define SAVE_MAGIC2 (('2'<<24)|('V'<<16)|('A'<<8)|'S') // "SAV2"
23 #define SAVE_VERSION 1
24 
25 #define SAVE_CURRENT ".current"
26 #define SAVE_AUTO "save0"
27 
28 cvar_t *sv_savedir = NULL;
29 
30 
31 static int write_server_file(qboolean autosave)
32 {
33  char name[MAX_OSPATH];
34  cvar_t *var;
35  size_t len;
36  qerror_t ret;
37  uint64_t timestamp;
38 
39  // write magic
42 
43  timestamp = (uint64_t)time(NULL);
44 
45  // write the comment field
46  MSG_WriteLong(timestamp & 0xffffffff);
47  MSG_WriteLong(timestamp >> 32);
48  MSG_WriteByte(autosave);
50 
51  // write the mapcmd
53 
54  // write all CVAR_LATCH cvars
55  // these will be things like coop, skill, deathmatch, etc
56  for (var = cvar_vars; var; var = var->next) {
57  if (!(var->flags & CVAR_LATCH))
58  continue;
59  if (var->flags & CVAR_PRIVATE)
60  continue;
61  MSG_WriteString(var->name);
62  MSG_WriteString(var->string);
63  }
64  MSG_WriteString(NULL);
65 
66  // write server state
67  Q_snprintf(name, MAX_OSPATH, "%s/%s/server.ssv", sv_savedir->string, SAVE_CURRENT);
68  ret = FS_WriteFile(name, msg_write.data, msg_write.cursize);
69 
71 
72  if (ret < 0)
73  return -1;
74 
75  // write game state
76  len = Q_snprintf(name, MAX_OSPATH,
77  "%s/%s/%s/game.ssv", fs_gamedir, sv_savedir->string, SAVE_CURRENT);
78  if (len >= MAX_OSPATH)
79  return -1;
80 
81  ge->WriteGame(name, autosave);
82  return 0;
83 }
84 
85 static int write_level_file(void)
86 {
87  char name[MAX_OSPATH];
88  int i;
89  char *s;
90  size_t len;
91  byte portalbits[MAX_MAP_PORTAL_BYTES];
92  qerror_t ret;
93 
94  // write magic
97 
98  // write configstrings
99  for (i = 0; i < MAX_CONFIGSTRINGS; i++) {
100  s = sv.configstrings[i];
101  if (!s[0])
102  continue;
103 
104  len = strlen(s);
105  if (len > MAX_QPATH)
106  len = MAX_QPATH;
107 
108  MSG_WriteShort(i);
109  MSG_WriteData(s, len);
110  MSG_WriteByte(0);
111  }
112  MSG_WriteShort(MAX_CONFIGSTRINGS);
113 
114  len = CM_WritePortalBits(&sv.cm, portalbits);
115  MSG_WriteByte(len);
116  MSG_WriteData(portalbits, len);
117 
118  len = Q_snprintf(name, MAX_QPATH, "%s/%s/%s.sv2", sv_savedir->string, SAVE_CURRENT, sv.name);
119  if (len >= MAX_QPATH)
120  ret = -1;
121  else
122  ret = FS_WriteFile(name, msg_write.data, msg_write.cursize);
123 
125 
126  if (ret < 0)
127  return -1;
128 
129  // write game level
130  len = Q_snprintf(name, MAX_OSPATH,
131  "%s/%s/%s/%s.sav", fs_gamedir, sv_savedir->string, SAVE_CURRENT, sv.name);
132  if (len >= MAX_OSPATH)
133  return -1;
134 
135  ge->WriteLevel(name);
136  return 0;
137 }
138 
139 static int copy_file(const char *src, const char *dst, const char *name)
140 {
141  char path[MAX_OSPATH];
142  byte buf[0x10000];
143  FILE *ifp, *ofp;
144  size_t len, res;
145  int ret = -1;
146 
147  len = Q_snprintf(path, MAX_OSPATH, "%s/%s/%s/%s", fs_gamedir, sv_savedir->string, src, name);
148  if (len >= MAX_OSPATH)
149  goto fail0;
150 
151  ifp = fopen(path, "rb");
152  if (!ifp)
153  goto fail0;
154 
155  len = Q_snprintf(path, MAX_OSPATH, "%s/%s/%s/%s", fs_gamedir, sv_savedir->string, dst, name);
156  if (len >= MAX_OSPATH)
157  goto fail1;
158 
159  if (FS_CreatePath(path))
160  goto fail1;
161 
162  ofp = fopen(path, "wb");
163  if (!ofp)
164  goto fail1;
165 
166  do {
167  len = fread(buf, 1, sizeof(buf), ifp);
168  res = fwrite(buf, 1, len, ofp);
169  } while (len == sizeof(buf) && res == len);
170 
171  if (ferror(ifp))
172  goto fail2;
173 
174  if (ferror(ofp))
175  goto fail2;
176 
177  ret = 0;
178 fail2:
179  fclose(ofp);
180 fail1:
181  fclose(ifp);
182 fail0:
183  return ret;
184 }
185 
186 static int remove_file(const char *dir, const char *name)
187 {
188  char path[MAX_OSPATH];
189  size_t len;
190 
191  len = Q_snprintf(path, MAX_OSPATH, "%s/%s/%s/%s", fs_gamedir, sv_savedir->string, dir, name);
192  if (len >= MAX_OSPATH)
193  return -1;
194 
195  return remove(path);
196 }
197 
198 static void **list_save_dir(const char *dir, int *count)
199 {
200  return FS_ListFiles(va("%s/%s", sv_savedir->string, dir), ".ssv;.sav;.sv2",
201  FS_TYPE_REAL | FS_PATH_GAME, count);
202 }
203 
204 static int wipe_save_dir(const char *dir)
205 {
206  void **list;
207  int i, count, ret = 0;
208 
209  if ((list = list_save_dir(dir, &count)) == NULL)
210  return 0;
211 
212  for (i = 0; i < count; i++)
213  ret |= remove_file(dir, list[i]);
214 
215  FS_FreeList(list);
216  return ret;
217 }
218 
219 static int copy_save_dir(const char *src, const char *dst)
220 {
221  void **list;
222  int i, count, ret = 0;
223 
224  if ((list = list_save_dir(src, &count)) == NULL)
225  return -1;
226 
227  for (i = 0; i < count; i++)
228  ret |= copy_file(src, dst, list[i]);
229 
230  FS_FreeList(list);
231  return ret;
232 }
233 
234 static int read_binary_file(const char *name)
235 {
236  qhandle_t f;
237  size_t len;
238 
239  len = FS_FOpenFile(name, &f, FS_MODE_READ | FS_TYPE_REAL | FS_PATH_GAME);
240  if (!f)
241  return -1;
242 
243  if (len > MAX_MSGLEN)
244  goto fail;
245 
246  if (FS_Read(msg_read_buffer, len, f) != len)
247  goto fail;
248 
250  msg_read.cursize = len;
251 
252  FS_FCloseFile(f);
253  return 0;
254 
255 fail:
256  FS_FCloseFile(f);
257  return -1;
258 }
259 
260 char *SV_GetSaveInfo(const char *dir)
261 {
262  char name[MAX_QPATH], date[MAX_QPATH];
263  size_t len;
264  uint64_t timestamp;
265  int autosave, year;
266  time_t t;
267  struct tm *tm;
268 
269  len = Q_snprintf(name, MAX_QPATH, "%s/%s/server.ssv", sv_savedir->string, dir);
270  if (len >= MAX_QPATH)
271  return NULL;
272 
273  if (read_binary_file(name))
274  return NULL;
275 
276  if (MSG_ReadLong() != SAVE_MAGIC1)
277  return NULL;
278 
279  if (MSG_ReadLong() != SAVE_VERSION)
280  return NULL;
281 
282  // read the comment field
283  timestamp = (uint64_t)MSG_ReadLong();
284  timestamp |= (uint64_t)MSG_ReadLong() << 32;
285  autosave = MSG_ReadByte();
286  MSG_ReadString(name, sizeof(name));
287 
288  if (autosave)
289  return Z_CopyString(va("ENTERING %s", name));
290 
291  // get current year
292  t = time(NULL);
293  tm = localtime(&t);
294  year = tm ? tm->tm_year : -1;
295 
296  // format savegame date
297  t = (time_t)timestamp;
298  len = 0;
299  if ((tm = localtime(&t)) != NULL) {
300  if (tm->tm_year == year)
301  len = strftime(date, sizeof(date), "%b %d %H:%M", tm);
302  else
303  len = strftime(date, sizeof(date), "%b %d %Y", tm);
304  }
305  if (!len)
306  strcpy(date, "???");
307 
308  return Z_CopyString(va("%s %s", date, name));
309 }
310 
311 static void abort_func(void *arg)
312 {
313  CM_FreeMap(arg);
314 }
315 
316 static int read_server_file(void)
317 {
318  char name[MAX_OSPATH], string[MAX_STRING_CHARS];
319  mapcmd_t cmd;
320  size_t len;
321 
322  // errors like missing file, bad version, etc are
323  // non-fatal and just return to the command handler
324 
325  Q_snprintf(name, MAX_OSPATH, "%s/%s/server.ssv", sv_savedir->string, SAVE_CURRENT);
326  if (read_binary_file(name))
327  return -1;
328 
329  if (MSG_ReadLong() != SAVE_MAGIC1)
330  return -1;
331 
332  if (MSG_ReadLong() != SAVE_VERSION)
333  return -1;
334 
335  memset(&cmd, 0, sizeof(cmd));
336 
337  // read the comment field
338  MSG_ReadLong();
339  MSG_ReadLong();
340  if (MSG_ReadByte())
341  cmd.loadgame = 2; // autosave
342  else
343  cmd.loadgame = 1; // regular savegame
344  MSG_ReadString(NULL, 0);
345 
346  // read the mapcmd
347  len = MSG_ReadString(cmd.buffer, sizeof(cmd.buffer));
348  if (len >= sizeof(cmd.buffer))
349  return -1;
350 
351  // now try to load the map
352  if (!SV_ParseMapCmd(&cmd))
353  return -1;
354 
355  // save pending CM to be freed later if ERR_DROP is thrown
356  Com_AbortFunc(abort_func, &cmd.cm);
357 
358  // any error will drop from this point
359  SV_Shutdown("Server restarted\n", ERR_RECONNECT);
360 
361  // the rest can't underflow
362  msg_read.allowunderflow = qfalse;
363 
364  // read all CVAR_LATCH cvars
365  // these will be things like coop, skill, deathmatch, etc
366  while (1) {
367  len = MSG_ReadString(name, MAX_QPATH);
368  if (!len)
369  break;
370  if (len >= MAX_QPATH)
371  Com_Error(ERR_DROP, "Savegame cvar name too long");
372 
373  len = MSG_ReadString(string, sizeof(string));
374  if (len >= sizeof(string))
375  Com_Error(ERR_DROP, "Savegame cvar value too long");
376 
377  Cvar_UserSet(name, string);
378  }
379 
380  // start a new game fresh with new cvars
382 
383  // error out immediately if game doesn't support safe savegames
384  if (!(g_features->integer & GMF_ENHANCED_SAVEGAMES))
385  Com_Error(ERR_DROP, "Game does not support enhanced savegames");
386 
387  // read game state
388  len = Q_snprintf(name, MAX_OSPATH,
389  "%s/%s/%s/game.ssv", fs_gamedir, sv_savedir->string, SAVE_CURRENT);
390  if (len >= MAX_OSPATH)
391  Com_Error(ERR_DROP, "Savegame path too long");
392 
393  ge->ReadGame(name);
394 
395  // clear pending CM
396  Com_AbortFunc(NULL, NULL);
397 
398  // go to the map
399  SV_SpawnServer(&cmd);
400  return 0;
401 }
402 
403 static int read_level_file(void)
404 {
405  char name[MAX_OSPATH];
406  size_t len, maxlen;
407  int index;
408 
409  len = Q_snprintf(name, MAX_QPATH, "%s/%s/%s.sv2", sv_savedir->string, SAVE_CURRENT, sv.name);
410  if (len >= MAX_QPATH)
411  return -1;
412 
413  if (read_binary_file(name))
414  return -1;
415 
416  if (MSG_ReadLong() != SAVE_MAGIC2)
417  return -1;
418 
419  if (MSG_ReadLong() != SAVE_VERSION)
420  return -1;
421 
422  // any error will drop from this point
423 
424  // the rest can't underflow
425  msg_read.allowunderflow = qfalse;
426 
427  // read all configstrings
428  while (1) {
429  index = MSG_ReadShort();
430  if (index == MAX_CONFIGSTRINGS)
431  break;
432 
433  if (index < 0 || index > MAX_CONFIGSTRINGS)
434  Com_Error(ERR_DROP, "Bad savegame configstring index");
435 
436  maxlen = CS_SIZE(index);
437  len = MSG_ReadString(sv.configstrings[index], maxlen);
438  if (len >= maxlen)
439  Com_Error(ERR_DROP, "Savegame configstring too long");
440  }
441 
442  len = MSG_ReadByte();
443  if (len > MAX_MAP_PORTAL_BYTES)
444  Com_Error(ERR_DROP, "Savegame portalbits too long");
445 
446  SV_ClearWorld();
447 
448  CM_SetPortalStates(&sv.cm, MSG_ReadData(len), len);
449 
450  // read game level
451  len = Q_snprintf(name, MAX_OSPATH, "%s/%s/%s/%s.sav",
453  if (len >= MAX_OSPATH)
454  Com_Error(ERR_DROP, "Savegame path too long");
455 
456  ge->ReadLevel(name);
457  return 0;
458 }
459 
460 int SV_NoSaveGames(void)
461 {
462  if (dedicated->integer && !Cvar_VariableInteger("coop"))
463  return 1;
464 
465  if (!(g_features->integer & GMF_ENHANCED_SAVEGAMES))
466  return 1;
467 
468  if (Cvar_VariableInteger("deathmatch"))
469  return 1;
470 
471  return 0;
472 }
473 
475 {
476  byte bitmap[MAX_CLIENTS / CHAR_BIT];
477  edict_t *ent;
478  int i;
479 
480  // check for clearing the current savegame
481  if (cmd->endofunit) {
483  return;
484  }
485 
486  if (sv.state != ss_game)
487  return;
488 
489  if (SV_NoSaveGames())
490  return;
491 
492  memset(bitmap, 0, sizeof(bitmap));
493 
494  // clear all the client inuse flags before saving so that
495  // when the level is re-entered, the clients will spawn
496  // at spawn points instead of occupying body shells
497  for (i = 0; i < sv_maxclients->integer; i++) {
498  ent = EDICT_NUM(i + 1);
499  if (ent->inuse) {
500  Q_SetBit(bitmap, i);
501  ent->inuse = qfalse;
502  }
503  }
504 
505  // save the map just exited
506  if (write_level_file())
507  Com_EPrintf("Couldn't write level file.\n");
508 
509  // we must restore these for clients to transfer over correctly
510  for (i = 0; i < sv_maxclients->integer; i++) {
511  ent = EDICT_NUM(i + 1);
512  ent->inuse = Q_IsBitSet(bitmap, i);
513  }
514 }
515 
516 void SV_AutoSaveEnd(void)
517 {
518  if (sv.state != ss_game)
519  return;
520 
521  if (SV_NoSaveGames())
522  return;
523 
524  // save the map just entered to include the player position (client edict shell)
525  if (write_level_file())
526  {
527  Com_EPrintf("Couldn't write level file.\n");
528  return;
529  }
530 
531  // save server state
532  if (write_server_file(qtrue)) {
533  Com_EPrintf("Couldn't write server file.\n");
534  return;
535  }
536 
537  // clear whatever savegames are there
538  if (wipe_save_dir(SAVE_AUTO)) {
539  Com_EPrintf("Couldn't wipe '%s' directory.\n", SAVE_AUTO);
540  return;
541  }
542 
543  // copy off the level to the autosave slot
545  Com_EPrintf("Couldn't write '%s' directory.\n", SAVE_AUTO);
546  return;
547  }
548 }
549 
551 {
552  if (SV_NoSaveGames())
553  return;
554 
555  if (read_level_file()) {
556  // only warn when loading a regular savegame. autosave without level
557  // file is ok and simply starts the map from the beginning.
558  if (cmd->loadgame == 1)
559  Com_EPrintf("Couldn't read level file.\n");
560  return;
561  }
562 
563  if (cmd->loadgame) {
564  // called from SV_Loadgame_f
565  ge->RunFrame();
566  ge->RunFrame();
567  } else {
568  int i;
569 
570  // coming back to a level after being in a different
571  // level, so run it for ten seconds
572  for (i = 0; i < 100; i++)
573  ge->RunFrame();
574  }
575 }
576 
577 static void SV_Savegame_c(genctx_t *ctx, int argnum)
578 {
579  if (argnum == 1) {
580  FS_File_g("save", NULL, FS_SEARCH_DIRSONLY | FS_TYPE_REAL | FS_PATH_GAME, ctx);
581  }
582 }
583 
584 static void SV_Loadgame_f(void)
585 {
586  char *dir;
587 
588  if (Cmd_Argc() != 2) {
589  Com_Printf("Usage: %s <directory>\n", Cmd_Argv(0));
590  return;
591  }
592 
593  if (dedicated->integer) {
594  Com_Printf("Savegames are for listen servers only.\n");
595  return;
596  }
597 
598  dir = Cmd_Argv(1);
599  if (!COM_IsPath(dir)) {
600  Com_Printf("Bad savedir.\n");
601  return;
602  }
603 
604  // make sure the server files exist
605  if (!FS_FileExistsEx(va("%s/%s/server.ssv", sv_savedir->string, dir), FS_TYPE_REAL | FS_PATH_GAME) ||
606  !FS_FileExistsEx(va("%s/%s/game.ssv", sv_savedir->string, dir), FS_TYPE_REAL | FS_PATH_GAME)) {
607  Com_Printf ("No such savegame: %s\n", dir);
608  return;
609  }
610 
611  // clear whatever savegames are there
613  Com_Printf("Couldn't wipe '%s' directory.\n", SAVE_CURRENT);
614  return;
615  }
616 
617  // copy it off
618  if (copy_save_dir(dir, SAVE_CURRENT)) {
619  Com_Printf("Couldn't read '%s' directory.\n", dir);
620  return;
621  }
622 
623  // read server state
624  if (read_server_file()) {
625  Com_Printf("Couldn't read server file.\n");
626  return;
627  }
628 }
629 
630 static void SV_Savegame_f(void)
631 {
632  char *dir;
633 
634  if (sv.state != ss_game) {
635  Com_Printf("You must be in a game to save.\n");
636  return;
637  }
638 
639  if (dedicated->integer) {
640  Com_Printf("Savegames are for listen servers only.\n");
641  return;
642  }
643 
644  // don't bother saving if we can't read them back!
645  if (!(g_features->integer & GMF_ENHANCED_SAVEGAMES)) {
646  Com_Printf("Game does not support enhanced savegames.\n");
647  return;
648  }
649 
650  if (Cvar_VariableInteger("deathmatch")) {
651  Com_Printf("Can't savegame in a deathmatch.\n");
652  return;
653  }
654 
655  if (sv_maxclients->integer == 1 && svs.client_pool[0].edict->client->ps.stats[STAT_HEALTH] <= 0) {
656  Com_Printf("Can't savegame while dead!\n");
657  return;
658  }
659 
660  if (Cmd_Argc() != 2) {
661  Com_Printf("Usage: %s <directory>\n", Cmd_Argv(0));
662  return;
663  }
664 
665  dir = Cmd_Argv(1);
666  if (!COM_IsPath(dir)) {
667  Com_Printf("Bad savedir.\n");
668  return;
669  }
670 
671  // archive current level, including all client edicts.
672  // when the level is reloaded, they will be shells awaiting
673  // a connecting client
674  if (write_level_file()) {
675  Com_Printf("Couldn't write level file.\n");
676  return;
677  }
678 
679  // save server state
680  if (write_server_file(qfalse)) {
681  Com_Printf("Couldn't write server file.\n");
682  return;
683  }
684 
685  // clear whatever savegames are there
686  if (wipe_save_dir(dir)) {
687  Com_Printf("Couldn't wipe '%s' directory.\n", dir);
688  return;
689  }
690 
691  // copy it off
692  if (copy_save_dir(SAVE_CURRENT, dir)) {
693  Com_Printf("Couldn't write '%s' directory.\n", dir);
694  return;
695  }
696 
697  Com_Printf("Game saved.\n");
698 }
699 
700 static const cmdreg_t c_savegames[] = {
701  { "save", SV_Savegame_f, SV_Savegame_c },
702  { "load", SV_Loadgame_f, SV_Savegame_c },
703  { NULL }
704 };
705 
707 {
709  sv_savedir = Cvar_Get("sv_savedir", "save", 0);
710 }
SAVE_MAGIC2
#define SAVE_MAGIC2
Definition: save.c:22
SV_Shutdown
void SV_Shutdown(const char *finalmsg, error_type_t type)
Definition: main.c:2252
SV_RegisterSavegames
void SV_RegisterSavegames(void)
Definition: save.c:706
gtv_s::name
char name[MAX_MVD_NAME]
Definition: client.c:51
MVD_SPAWN_DISABLED
#define MVD_SPAWN_DISABLED
Definition: server.h:94
cvar_vars
cvar_t * cvar_vars
Definition: cvar.c:30
CM_FreeMap
void CM_FreeMap(cm_t *cm)
Definition: cmodel.c:47
msg_read
sizebuf_t msg_read
Definition: msg.c:37
msg_read_buffer
byte msg_read_buffer[MAX_MSGLEN]
Definition: msg.c:38
svs
server_static_t svs
Definition: init.c:21
Q_snprintf
size_t Q_snprintf(char *dest, size_t size, const char *fmt,...)
Definition: shared.c:846
FS_Read
ssize_t FS_Read(void *buf, size_t len, qhandle_t f)
Definition: files.c:1547
COM_IsPath
qboolean COM_IsPath(const char *s)
Definition: shared.c:348
SV_CheckForSavegame
void SV_CheckForSavegame(mapcmd_t *cmd)
Definition: save.c:550
c_savegames
static const cmdreg_t c_savegames[]
Definition: save.c:700
copy_save_dir
static int copy_save_dir(const char *src, const char *dst)
Definition: save.c:219
Cvar_Get
cvar_t * Cvar_Get(const char *var_name, const char *var_value, int flags)
Definition: cvar.c:257
FS_FreeList
void FS_FreeList(void **list)
Definition: files.c:2939
SV_ClearWorld
void SV_ClearWorld(void)
Definition: world.c:101
Com_AbortFunc
void Com_AbortFunc(void(*func)(void *), void *arg)
Definition: common.c:588
server_t::mapcmd
char mapcmd[MAX_QPATH]
Definition: server.h:158
read_level_file
static int read_level_file(void)
Definition: save.c:403
FS_WriteFile
qerror_t FS_WriteFile(const char *path, const void *data, size_t len)
Definition: files.c:1932
SV_AutoSaveBegin
void SV_AutoSaveBegin(mapcmd_t *cmd)
Definition: save.c:474
SAVE_MAGIC1
#define SAVE_MAGIC1
Definition: save.c:21
MSG_WriteByte
void MSG_WriteByte(int c)
Definition: msg.c:107
Cmd_Argv
char * Cmd_Argv(int arg)
Definition: cmd.c:899
SZ_Init
void SZ_Init(sizebuf_t *buf, void *data, size_t size)
Definition: sizebuf.c:31
SAVE_AUTO
#define SAVE_AUTO
Definition: save.c:26
sv_savedir
cvar_t * sv_savedir
Definition: save.c:28
Cmd_Argc
int Cmd_Argc(void)
Definition: cmd.c:889
mapcmd_t::loadgame
int loadgame
Definition: server.h:442
SV_Savegame_f
static void SV_Savegame_f(void)
Definition: save.c:630
wipe_save_dir
static int wipe_save_dir(const char *dir)
Definition: save.c:204
FS_FOpenFile
ssize_t FS_FOpenFile(const char *name, qhandle_t *f, unsigned mode)
Definition: files.c:1692
Com_Error
void Com_Error(error_type_t type, const char *fmt,...)
Definition: g_main.c:258
dedicated
cvar_t * dedicated
Definition: g_main.c:46
MSG_ReadData
byte * MSG_ReadData(size_t len)
Definition: msg.c:1443
sv
server_t sv
Definition: init.c:22
SV_ParseMapCmd
qboolean SV_ParseMapCmd(mapcmd_t *cmd)
Definition: init.c:285
msg_write
sizebuf_t msg_write
Definition: msg.c:34
SV_SpawnServer
void SV_SpawnServer(mapcmd_t *cmd)
Definition: init.c:139
copy_file
static int copy_file(const char *src, const char *dst, const char *name)
Definition: save.c:139
va
char * va(const char *format,...)
Definition: shared.c:429
FS_File_g
void FS_File_g(const char *path, const char *ext, unsigned flags, genctx_t *ctx)
Definition: files.c:2954
server_static_s::client_pool
client_t * client_pool
Definition: server.h:456
remove_file
static int remove_file(const char *dir, const char *name)
Definition: save.c:186
CM_WritePortalBits
int CM_WritePortalBits(cm_t *cm, byte *buffer)
Definition: cmodel.c:955
Cmd_Register
void Cmd_Register(const cmdreg_t *reg)
Definition: cmd.c:1572
MSG_ReadLong
int MSG_ReadLong(void)
Definition: msg.c:1517
FS_ListFiles
void ** FS_ListFiles(const char *path, const char *filter, unsigned flags, int *count_p)
Definition: files.c:2716
SV_Loadgame_f
static void SV_Loadgame_f(void)
Definition: save.c:584
write_server_file
static int write_server_file(qboolean autosave)
Definition: save.c:31
read_server_file
static int read_server_file(void)
Definition: save.c:316
Cvar_VariableInteger
int Cvar_VariableInteger(const char *var_name)
Definition: cvar.c:105
SV_AutoSaveEnd
void SV_AutoSaveEnd(void)
Definition: save.c:516
MSG_WriteShort
void MSG_WriteShort(int c)
Definition: msg.c:125
ge
game_export_t * ge
Definition: game.c:22
mapcmd_t
Definition: server.h:437
SAVE_VERSION
#define SAVE_VERSION
Definition: save.c:23
Cvar_UserSet
cvar_t * Cvar_UserSet(const char *var_name, const char *value)
Definition: cvar.c:476
abort_func
static void abort_func(void *arg)
Definition: save.c:311
server_t::cm
cm_t cm
Definition: server.h:161
MSG_WriteString
void MSG_WriteString(const char *string)
Definition: msg.c:160
mapcmd_t::cm
cm_t cm
Definition: server.h:444
mapcmd_t::endofunit
qboolean endofunit
Definition: server.h:443
MSG_WriteLong
void MSG_WriteLong(int c)
Definition: msg.c:144
SV_Savegame_c
static void SV_Savegame_c(genctx_t *ctx, int argnum)
Definition: save.c:577
SAVE_CURRENT
#define SAVE_CURRENT
Definition: save.c:25
SV_InitGame
void SV_InitGame(unsigned mvd_spawn)
Definition: init.c:361
g_features
cvar_t * g_features
Definition: main.c:99
MSG_ReadString
size_t MSG_ReadString(char *dest, size_t size)
Definition: msg.c:1531
server_t::state
server_state_t state
Definition: server.h:146
mapcmd_t::buffer
char buffer[MAX_QPATH]
Definition: server.h:438
SV_NoSaveGames
int SV_NoSaveGames(void)
Definition: save.c:460
SV_GetSaveInfo
char * SV_GetSaveInfo(const char *dir)
Definition: save.c:260
FS_CreatePath
qerror_t FS_CreatePath(char *path)
Definition: files.c:605
FS_FCloseFile
void FS_FCloseFile(qhandle_t f)
Definition: files.c:759
MSG_ReadByte
int MSG_ReadByte(void)
Definition: msg.c:1475
EDICT_NUM
#define EDICT_NUM(n)
Definition: server.h:173
server.h
server_t::configstrings
char configstrings[MAX_CONFIGSTRINGS][MAX_QPATH]
Definition: server.h:164
write_level_file
static int write_level_file(void)
Definition: save.c:85
list_save_dir
static void ** list_save_dir(const char *dir, int *count)
Definition: save.c:198
CM_SetPortalStates
void CM_SetPortalStates(cm_t *cm, byte *buffer, int bytes)
Definition: cmodel.c:982
fs_gamedir
char fs_gamedir[MAX_OSPATH]
Definition: files.c:171
read_binary_file
static int read_binary_file(const char *name)
Definition: save.c:234
server_t::name
char name[MAX_QPATH]
Definition: server.h:160
SZ_Clear
void SZ_Clear(sizebuf_t *buf)
Definition: sizebuf.c:40
MSG_ReadShort
int MSG_ReadShort(void)
Definition: msg.c:1489
client_s::edict
edict_t * edict
Definition: server.h:261
sv_maxclients
cvar_t * sv_maxclients
Definition: main.c:58