summaryrefslogtreecommitdiff
path: root/src/sv_save.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/sv_save.c')
-rw-r--r--src/sv_save.c313
1 files changed, 161 insertions, 152 deletions
diff --git a/src/sv_save.c b/src/sv_save.c
index ba91721..e946fae 100644
--- a/src/sv_save.c
+++ b/src/sv_save.c
@@ -8,7 +8,7 @@ of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
@@ -35,57 +35,59 @@ SAVEGAME FILES
===============================================================================
*/
-static qerror_t write_server_file( qboolean autosave ) {
+static qerror_t write_server_file(qboolean autosave)
+{
char name[MAX_OSPATH];
cvar_t *var;
size_t len;
qerror_t ret;
// write magic
- MSG_WriteLong( SAVE_MAGIC1 );
- MSG_WriteLong( SAVE_VERSION );
+ MSG_WriteLong(SAVE_MAGIC1);
+ MSG_WriteLong(SAVE_VERSION);
// write the comment field
- MSG_WriteByte( autosave );
- MSG_WriteString( sv.configstrings[CS_NAME] );
+ MSG_WriteByte(autosave);
+ MSG_WriteString(sv.configstrings[CS_NAME]);
// write the mapcmd
- MSG_WriteString( sv.name );
+ MSG_WriteString(sv.name);
// write all CVAR_LATCH cvars
// these will be things like coop, skill, deathmatch, etc
- for( var = cvar_vars; var; var = var->next ) {
+ for (var = cvar_vars; var; var = var->next) {
if (!(var->flags & CVAR_LATCH))
continue;
if (var->flags & CVAR_PRIVATE)
continue;
- MSG_WriteString( var->name );
- MSG_WriteString( var->string );
+ MSG_WriteString(var->name);
+ MSG_WriteString(var->string);
}
- MSG_WriteString( NULL );
+ MSG_WriteString(NULL);
// write server state
- ret = FS_WriteFile( "save/" SAVE_CURRENT "/server.state",
- msg_write.data, msg_write.cursize );
+ ret = FS_WriteFile("save/" SAVE_CURRENT "/server.state",
+ msg_write.data, msg_write.cursize);
- SZ_Clear( &msg_write );
+ SZ_Clear(&msg_write);
- if( ret < 0 ) {
+ if (ret < 0) {
return ret;
}
// write game state
- len = Q_snprintf( name, sizeof( name ),
- "%s/save/" SAVE_CURRENT "/game.state", fs_gamedir );
- if( len >= sizeof( name ) ) {
+ len = Q_snprintf(name, sizeof(name),
+ "%s/save/" SAVE_CURRENT "/game.state", fs_gamedir);
+ if (len >= sizeof(name)) {
return Q_ERR_NAMETOOLONG;
}
- ge->WriteGame (name, autosave);
+ ge->WriteGame(name, autosave);
return Q_ERR_SUCCESS;
}
-static qerror_t write_level_file( void ) {
+static qerror_t write_level_file(void)
+{
char name[MAX_OSPATH];
int i;
char *s;
@@ -94,130 +96,134 @@ static qerror_t write_level_file( void ) {
qerror_t ret;
// write magic
- MSG_WriteLong( SAVE_MAGIC2 );
- MSG_WriteLong( SAVE_VERSION );
+ MSG_WriteLong(SAVE_MAGIC2);
+ MSG_WriteLong(SAVE_VERSION);
// write configstrings
- for( i = 0; i < MAX_CONFIGSTRINGS; i++ ) {
+ for (i = 0; i < MAX_CONFIGSTRINGS; i++) {
s = sv.configstrings[i];
- if( !s[0] ) {
+ if (!s[0]) {
continue;
}
- len = strlen( s );
- if( len > MAX_QPATH ) {
+ len = strlen(s);
+ if (len > MAX_QPATH) {
len = MAX_QPATH;
}
- MSG_WriteShort( i );
- MSG_WriteData( s, len );
- MSG_WriteByte( 0 );
+ MSG_WriteShort(i);
+ MSG_WriteData(s, len);
+ MSG_WriteByte(0);
}
- MSG_WriteShort( MAX_CONFIGSTRINGS );
+ MSG_WriteShort(MAX_CONFIGSTRINGS);
- len = CM_WritePortalBits( &sv.cm, portalbits );
- MSG_WriteByte( len );
- MSG_WriteData( portalbits, len );
+ len = CM_WritePortalBits(&sv.cm, portalbits);
+ MSG_WriteByte(len);
+ MSG_WriteData(portalbits, len);
- ret = FS_WriteFile( "save/" SAVE_CURRENT "/server.level",
- msg_write.data, msg_write.cursize );
+ ret = FS_WriteFile("save/" SAVE_CURRENT "/server.level",
+ msg_write.data, msg_write.cursize);
- SZ_Clear( &msg_write );
+ SZ_Clear(&msg_write);
- if( ret < 0 ) {
+ if (ret < 0) {
return ret;
}
// write game level
- len = Q_snprintf( name, sizeof( name ),
- "%s/save/" SAVE_CURRENT "/game.level", fs_gamedir );
- if( len >= sizeof( name ) ) {
+ len = Q_snprintf(name, sizeof(name),
+ "%s/save/" SAVE_CURRENT "/game.level", fs_gamedir);
+ if (len >= sizeof(name)) {
return Q_ERR_NAMETOOLONG;
}
- ge->WriteLevel( name );
+ ge->WriteLevel(name);
return Q_ERR_SUCCESS;
}
-static qerror_t rename_file( const char *dir, const char *base, const char *suf ) {
+static qerror_t rename_file(const char *dir, const char *base, const char *suf)
+{
char from[MAX_QPATH];
char to[MAX_QPATH];
size_t len;
- len = Q_snprintf( from, sizeof( from ), "save/%s/%s%s", SAVE_CURRENT, base, suf );
- if( len >= sizeof( from ) )
+ len = Q_snprintf(from, sizeof(from), "save/%s/%s%s", SAVE_CURRENT, base, suf);
+ if (len >= sizeof(from))
return Q_ERR_NAMETOOLONG;
- len = Q_snprintf( to, sizeof( to ), "save/%s/%s%s", dir, base, suf );
- if( len >= sizeof( to ) )
+ len = Q_snprintf(to, sizeof(to), "save/%s/%s%s", dir, base, suf);
+ if (len >= sizeof(to))
return Q_ERR_NAMETOOLONG;
- return FS_RenameFile( from, to );
+ return FS_RenameFile(from, to);
}
-static qerror_t move_files( const char *dir ) {
+static qerror_t move_files(const char *dir)
+{
char name[MAX_OSPATH];
size_t len;
qerror_t ret;
- len = Q_snprintf( name, sizeof( name ), "%s/save/%s/", fs_gamedir, dir );
- if( len >= sizeof( name ) )
+ len = Q_snprintf(name, sizeof(name), "%s/save/%s/", fs_gamedir, dir);
+ if (len >= sizeof(name))
return Q_ERR_NAMETOOLONG;
- ret = FS_CreatePath( name );
- if( ret )
+ ret = FS_CreatePath(name);
+ if (ret)
return ret;
- ret = rename_file( dir, "game", ".level" );
- if( ret )
+ ret = rename_file(dir, "game", ".level");
+ if (ret)
return ret;
- ret = rename_file( dir, "server", ".level" );
- if( ret )
+ ret = rename_file(dir, "server", ".level");
+ if (ret)
return ret;
- ret = rename_file( dir, "game", ".state" );
- if( ret )
+ ret = rename_file(dir, "game", ".state");
+ if (ret)
return ret;
- ret = rename_file( dir, "server", ".state" );
- if( ret )
+ ret = rename_file(dir, "server", ".state");
+ if (ret)
return ret;
return Q_ERR_SUCCESS;
}
-static qerror_t read_binary_file( const char *name ) {
+static qerror_t read_binary_file(const char *name)
+{
qhandle_t f;
ssize_t len, read;
qerror_t ret;
- len = FS_FOpenFile( name, &f,
- FS_MODE_READ | FS_TYPE_REAL | FS_PATH_GAME );
- if( !f ) {
+ len = FS_FOpenFile(name, &f,
+ FS_MODE_READ | FS_TYPE_REAL | FS_PATH_GAME);
+ if (!f) {
return len;
}
- if( len > MAX_MSGLEN ) {
+ if (len > MAX_MSGLEN) {
ret = Q_ERR_FBIG;
goto fail;
}
- read = FS_Read( msg_read_buffer, len, f );
- if( read != len ) {
+ read = FS_Read(msg_read_buffer, len, f);
+ if (read != len) {
ret = read < 0 ? read : Q_ERR_UNEXPECTED_EOF;
goto fail;
}
- SZ_Init( &msg_read, msg_read_buffer, len );
+ SZ_Init(&msg_read, msg_read_buffer, len);
msg_read.cursize = len;
ret = Q_ERR_SUCCESS;
fail:
- FS_FCloseFile( f );
+ FS_FCloseFile(f);
return ret;
}
-static qerror_t read_server_file( const char *dir ) {
+static qerror_t read_server_file(const char *dir)
+{
char name[MAX_OSPATH], string[MAX_STRING_CHARS];
char mapcmd[MAX_QPATH];
char *s, *ch, *spawnpoint;
@@ -227,30 +233,30 @@ static qerror_t read_server_file( const char *dir ) {
// errors like missing file, bad version, etc are
// non-fatal and just return to the command handler
- len = Q_snprintf( name, MAX_QPATH, "save/%s/server.state", dir );
- if( len >= MAX_QPATH ) {
+ len = Q_snprintf(name, MAX_QPATH, "save/%s/server.state", dir);
+ if (len >= MAX_QPATH) {
return Q_ERR_NAMETOOLONG;
}
- ret = read_binary_file( name );
- if( ret ) {
+ ret = read_binary_file(name);
+ if (ret) {
return ret;
}
- if( MSG_ReadLong() != SAVE_MAGIC1 ) {
+ if (MSG_ReadLong() != SAVE_MAGIC1) {
return Q_ERR_UNKNOWN_FORMAT;
}
- if( MSG_ReadLong() != SAVE_VERSION ) {
+ if (MSG_ReadLong() != SAVE_VERSION) {
return Q_ERR_INVALID_FORMAT;
}
// read the comment field
MSG_ReadByte();
- MSG_ReadString( NULL, 0 );
+ MSG_ReadString(NULL, 0);
// read the mapcmd
- len = MSG_ReadString( mapcmd, sizeof( mapcmd ) );
- if( len >= sizeof( mapcmd ) ) {
+ len = MSG_ReadString(mapcmd, sizeof(mapcmd));
+ if (len >= sizeof(mapcmd)) {
return Q_ERR_STRING_TRUNCATED;
}
@@ -258,19 +264,19 @@ static qerror_t read_server_file( const char *dir ) {
// if there is a + in the map, set nextserver to the remainder
// we go directly to nextserver as we don't support cinematics
- ch = strchr( s, '+' );
- if( ch ) {
+ ch = strchr(s, '+');
+ if (ch) {
s = ch + 1;
}
// skip the end-of-unit flag if necessary
- if( *s == '*' ) {
+ if (*s == '*') {
s++;
}
// if there is a $, use the remainder as a spawnpoint
- ch = strchr( s, '$' );
- if( ch ) {
+ ch = strchr(s, '$');
+ if (ch) {
*ch = 0;
spawnpoint = ch + 1;
} else {
@@ -278,89 +284,90 @@ static qerror_t read_server_file( const char *dir ) {
}
// now expand and try to load the map
- len = Q_concat( name, MAX_QPATH, "maps/", s, ".bsp", NULL );
- if( len >= MAX_QPATH ) {
+ len = Q_concat(name, MAX_QPATH, "maps/", s, ".bsp", NULL);
+ if (len >= MAX_QPATH) {
return Q_ERR_NAMETOOLONG;
}
- ret = CM_LoadMap( &cm, name );
- if( ret ) {
+ ret = CM_LoadMap(&cm, name);
+ if (ret) {
return ret;
}
// any error will drop from this point
- SV_Shutdown( "Server restarted\n", ERR_RECONNECT );
+ SV_Shutdown("Server restarted\n", ERR_RECONNECT);
// the rest can't underflow
msg_read.allowunderflow = qfalse;
// read all CVAR_LATCH cvars
// these will be things like coop, skill, deathmatch, etc
- while( 1 ) {
- len = MSG_ReadString( name, MAX_QPATH );
- if( !len )
+ while (1) {
+ len = MSG_ReadString(name, MAX_QPATH);
+ if (!len)
break;
- if( len >= MAX_QPATH ) {
+ if (len >= MAX_QPATH) {
ret = Q_ERR_STRING_TRUNCATED;
goto fail;
}
- len = MSG_ReadString( string, sizeof( string ) );
- if( len >= sizeof( string ) ) {
+ len = MSG_ReadString(string, sizeof(string));
+ if (len >= sizeof(string)) {
ret = Q_ERR_STRING_TRUNCATED;
goto fail;
}
- Cvar_UserSet( name, string );
+ Cvar_UserSet(name, string);
}
// start a new game fresh with new cvars
- SV_InitGame( MVD_SPAWN_DISABLED );
+ SV_InitGame(MVD_SPAWN_DISABLED);
// error out immediately if game doesn't support safe savegames
- if( !( g_features->integer & GMF_ENHANCED_SAVEGAMES ) ) {
- Com_Error( ERR_DROP, "Game does not support enhanced savegames" );
+ if (!(g_features->integer & GMF_ENHANCED_SAVEGAMES)) {
+ Com_Error(ERR_DROP, "Game does not support enhanced savegames");
}
// read game state
- len = Q_snprintf( name, sizeof( name ), "%s/save/%s/game.state", fs_gamedir, dir );
- if( len >= sizeof( name ) ) {
+ len = Q_snprintf(name, sizeof(name), "%s/save/%s/game.state", fs_gamedir, dir);
+ if (len >= sizeof(name)) {
ret = Q_ERR_NAMETOOLONG;
goto fail;
}
- ge->ReadGame (name);
+ ge->ReadGame(name);
// go to the map
- SV_SpawnServer( &cm, s, spawnpoint );
+ SV_SpawnServer(&cm, s, spawnpoint);
return Q_ERR_SUCCESS;
fail:
- Com_Error( ERR_DROP, "Couldn't load %s: %s", dir, Q_ErrorString( ret ) );
+ Com_Error(ERR_DROP, "Couldn't load %s: %s", dir, Q_ErrorString(ret));
}
-static void read_level_file( const char *dir ) {
+static void read_level_file(const char *dir)
+{
char name[MAX_OSPATH];
size_t len, maxlen;
qerror_t ret;
int index;
- len = Q_snprintf( name, MAX_QPATH, "save/%s/server.level", dir );
- if( len >= MAX_QPATH ) {
+ len = Q_snprintf(name, MAX_QPATH, "save/%s/server.level", dir);
+ if (len >= MAX_QPATH) {
ret = Q_ERR_NAMETOOLONG;
goto fail;
}
- ret = read_binary_file( name );
- if( ret ) {
+ ret = read_binary_file(name);
+ if (ret) {
goto fail;
}
- if( MSG_ReadLong() != SAVE_MAGIC2 ) {
+ if (MSG_ReadLong() != SAVE_MAGIC2) {
ret = Q_ERR_UNKNOWN_FORMAT;
goto fail;
}
- if( MSG_ReadLong() != SAVE_VERSION ) {
+ if (MSG_ReadLong() != SAVE_VERSION) {
ret = Q_ERR_INVALID_FORMAT;
goto fail;
}
@@ -368,49 +375,49 @@ static void read_level_file( const char *dir ) {
// the rest can't underflow
msg_read.allowunderflow = qfalse;
- while( 1 ) {
+ while (1) {
index = MSG_ReadShort();
- if( index == MAX_CONFIGSTRINGS ) {
+ if (index == MAX_CONFIGSTRINGS) {
break;
}
- if( index < 0 || index >= MAX_CONFIGSTRINGS ) {
+ if (index < 0 || index >= MAX_CONFIGSTRINGS) {
ret = Q_ERR_BAD_INDEX;
goto fail;
}
- maxlen = CS_SIZE( index );
- len = MSG_ReadString( sv.configstrings[index], maxlen );
- if( len >= maxlen ) {
+ maxlen = CS_SIZE(index);
+ len = MSG_ReadString(sv.configstrings[index], maxlen);
+ if (len >= maxlen) {
ret = Q_ERR_STRING_TRUNCATED;
goto fail;
}
}
len = MSG_ReadByte();
- if( len > MAX_MAP_PORTAL_BYTES ) {
+ if (len > MAX_MAP_PORTAL_BYTES) {
ret = Q_ERR_INVALID_FORMAT;
goto fail;
}
SV_ClearWorld();
- CM_SetPortalStates( &sv.cm, MSG_ReadData( len ), len );
+ CM_SetPortalStates(&sv.cm, MSG_ReadData(len), len);
// read game level
- len = Q_snprintf( name, sizeof( name ), "%s/save/%s/game.level", fs_gamedir, dir );
- if( len >= sizeof( name ) ) {
+ len = Q_snprintf(name, sizeof(name), "%s/save/%s/game.level", fs_gamedir, dir);
+ if (len >= sizeof(name)) {
ret = Q_ERR_NAMETOOLONG;
goto fail;
}
- ge->ReadLevel( name );
+ ge->ReadLevel(name);
ge->RunFrame();
ge->RunFrame();
return;
fail:
- Com_Error( ERR_DROP, "Couldn't load %s: %s", dir, Q_ErrorString( ret ) );
+ Com_Error(ERR_DROP, "Couldn't load %s: %s", dir, Q_ErrorString(ret));
}
@@ -420,33 +427,34 @@ SV_Loadgame_f
==============
*/
-void SV_Loadgame_f (void) {
+void SV_Loadgame_f(void)
+{
char *dir;
qerror_t ret;
if (Cmd_Argc() != 2) {
- Com_Printf ("Usage: %s <directory>\n", Cmd_Argv(0));
+ Com_Printf("Usage: %s <directory>\n", Cmd_Argv(0));
return;
}
- if( dedicated->integer ) {
- Com_Printf ("Savegames are for listen servers only\n");
+ if (dedicated->integer) {
+ Com_Printf("Savegames are for listen servers only\n");
return;
}
dir = Cmd_Argv(1);
- if (!COM_IsPath(dir) ) {
- Com_Printf ("Bad savedir.\n");
+ if (!COM_IsPath(dir)) {
+ Com_Printf("Bad savedir.\n");
return;
}
- ret = read_server_file( dir );
- if( ret ) {
- Com_Printf( "Couldn't load %s: %s\n", dir, Q_ErrorString( ret ) );
+ ret = read_server_file(dir);
+ if (ret) {
+ Com_Printf("Couldn't load %s: %s\n", dir, Q_ErrorString(ret));
return;
}
- read_level_file( dir );
+ read_level_file(dir);
}
@@ -456,44 +464,45 @@ SV_Savegame_f
==============
*/
-void SV_Savegame_f( void ) {
+void SV_Savegame_f(void)
+{
char *dir;
qerror_t ret;
if (sv.state != ss_game) {
- Com_Printf ("You must be in a game to save.\n");
+ Com_Printf("You must be in a game to save.\n");
return;
}
- if( dedicated->integer ) {
- Com_Printf ("Savegames are for listen servers only\n");
+ if (dedicated->integer) {
+ Com_Printf("Savegames are for listen servers only\n");
return;
}
-
+
// don't bother saving if we can't read them back!
- if( !( g_features->integer & GMF_ENHANCED_SAVEGAMES ) ) {
- Com_Printf ("Game does not support enhanced savegames\n");
+ if (!(g_features->integer & GMF_ENHANCED_SAVEGAMES)) {
+ Com_Printf("Game does not support enhanced savegames\n");
return;
}
if (Cvar_VariableInteger("deathmatch")) {
- Com_Printf ("Can't savegame in a deathmatch\n");
+ Com_Printf("Can't savegame in a deathmatch\n");
return;
}
if (sv_maxclients->integer == 1 && svs.client_pool[0].edict->client->ps.stats[STAT_HEALTH] <= 0) {
- Com_Printf ("Can't savegame while dead!\n");
+ Com_Printf("Can't savegame while dead!\n");
return;
}
if (Cmd_Argc() != 2) {
- Com_Printf ("Usage: %s <directory>\n", Cmd_Argv(0));
+ Com_Printf("Usage: %s <directory>\n", Cmd_Argv(0));
return;
}
dir = Cmd_Argv(1);
- if (!COM_IsPath(dir) ) {
- Com_Printf ("Bad savedir.\n");
+ if (!COM_IsPath(dir)) {
+ Com_Printf("Bad savedir.\n");
return;
}
@@ -501,23 +510,23 @@ void SV_Savegame_f( void ) {
// when the level is reloaded, they will be shells awaiting
// a connecting client
ret = write_level_file();
- if( ret )
+ if (ret)
goto fail;
// save server state
- ret = write_server_file( qfalse );
- if( ret )
+ ret = write_server_file(qfalse);
+ if (ret)
goto fail;
// rename all stuff
- ret = move_files( dir );
- if( ret )
+ ret = move_files(dir);
+ if (ret)
goto fail;
- Com_Printf ("Game saved.\n");
+ Com_Printf("Game saved.\n");
return;
fail:
- Com_EPrintf( "Couldn't write %s: %s\n", dir, Q_ErrorString( ret ) );
+ Com_EPrintf("Couldn't write %s: %s\n", dir, Q_ErrorString(ret));
}