mirror of
https://github.com/yquake2/yquake2remaster.git
synced 2024-11-26 06:20:48 +00:00
Den Server-Savegame-Code in eine eigenen Datei
This commit is contained in:
parent
bc2e6b671d
commit
5ddb6ab6a1
4 changed files with 449 additions and 425 deletions
12
Makefile
12
Makefile
|
@ -245,6 +245,7 @@ SERVER_OBJS = \
|
|||
build/server/sv_game.o \
|
||||
build/server/sv_init.o \
|
||||
build/server/sv_main.o \
|
||||
build/server/sv_save.o \
|
||||
build/server/sv_send.o \
|
||||
build/server/sv_user.o \
|
||||
build/server/sv_world.o
|
||||
|
@ -276,6 +277,7 @@ DEDICATED_SERVER_OBJS = \
|
|||
build/dedicated_server/sv_game.o \
|
||||
build/dedicated_server/sv_init.o \
|
||||
build/dedicated_server/sv_main.o \
|
||||
build/dedicated_server/sv_save.o \
|
||||
build/dedicated_server/sv_send.o \
|
||||
build/dedicated_server/sv_user.o \
|
||||
build/dedicated_server/sv_world.o
|
||||
|
@ -616,7 +618,10 @@ build/server/sv_init.o : src/server/sv_init.c
|
|||
|
||||
build/server/sv_main.o : src/server/sv_main.c
|
||||
$(CC) $(CFLAGS_CLIENT) -o $@ -c $<
|
||||
|
||||
|
||||
build/server/sv_save.o : src/server/sv_save.c
|
||||
$(CC) $(CFLAGS_CLIENT) -o $@ -c $<
|
||||
|
||||
build/server/sv_send.o : src/server/sv_send.c
|
||||
$(CC) $(CFLAGS_CLIENT) -o $@ -c $<
|
||||
|
||||
|
@ -672,7 +677,10 @@ build/dedicated_server/sv_init.o : src/server/sv_init.c
|
|||
|
||||
build/dedicated_server/sv_main.o : src/server/sv_main.c
|
||||
$(CC) $(CFLAGS_DEDICATED_SERVER) -o $@ -c $<
|
||||
|
||||
|
||||
build/dedicated_server/sv_save.o : src/server/sv_save.c
|
||||
$(CC) $(CFLAGS_DEDICATED_SERVER) -o $@ -c $<
|
||||
|
||||
build/dedicated_server/sv_send.o : src/server/sv_send.c
|
||||
$(CC) $(CFLAGS_DEDICATED_SERVER) -o $@ -c $<
|
||||
|
||||
|
|
|
@ -247,6 +247,14 @@ void SV_InitGameProgs ( void );
|
|||
void SV_ShutdownGameProgs ( void );
|
||||
void SV_InitEdict ( edict_t *e );
|
||||
|
||||
/* server side savegame stuff */
|
||||
void SV_WipeSavegame ( char *savename );
|
||||
void SV_CopySaveGame ( char *src, char *dst );
|
||||
void SV_WriteLevelFile ( void );
|
||||
void SV_WriteServerFile ( qboolean autosave );
|
||||
void SV_Loadgame_f ( void );
|
||||
void SV_Savegame_f ( void );
|
||||
|
||||
/* high level object sorting to reduce interaction tests */
|
||||
void SV_ClearWorld ( void );
|
||||
|
||||
|
|
|
@ -144,318 +144,6 @@ SV_SetPlayer ( void )
|
|||
return ( false );
|
||||
}
|
||||
|
||||
/*
|
||||
* ===============================================================================
|
||||
*
|
||||
* SAVEGAME FILES
|
||||
*
|
||||
* ===============================================================================
|
||||
*/
|
||||
|
||||
/*
|
||||
* Delete save/<XXX>/
|
||||
*/
|
||||
void
|
||||
SV_WipeSavegame ( char *savename )
|
||||
{
|
||||
char name [ MAX_OSPATH ];
|
||||
char *s;
|
||||
|
||||
Com_DPrintf( "SV_WipeSaveGame(%s)\n", savename );
|
||||
|
||||
Com_sprintf( name, sizeof ( name ), "%s/save/%s/server.ssv", FS_Gamedir(), savename );
|
||||
remove( name );
|
||||
Com_sprintf( name, sizeof ( name ), "%s/save/%s/game.ssv", FS_Gamedir(), savename );
|
||||
remove( name );
|
||||
|
||||
Com_sprintf( name, sizeof ( name ), "%s/save/%s/*.sav", FS_Gamedir(), savename );
|
||||
s = Sys_FindFirst( name, 0, 0 );
|
||||
|
||||
while ( s )
|
||||
{
|
||||
remove( s );
|
||||
s = Sys_FindNext( 0, 0 );
|
||||
}
|
||||
|
||||
Sys_FindClose();
|
||||
Com_sprintf( name, sizeof ( name ), "%s/save/%s/*.sv2", FS_Gamedir(), savename );
|
||||
s = Sys_FindFirst( name, 0, 0 );
|
||||
|
||||
while ( s )
|
||||
{
|
||||
remove( s );
|
||||
s = Sys_FindNext( 0, 0 );
|
||||
}
|
||||
|
||||
Sys_FindClose();
|
||||
}
|
||||
|
||||
void
|
||||
CopyFile ( char *src, char *dst )
|
||||
{
|
||||
FILE *f1, *f2;
|
||||
size_t l;
|
||||
byte buffer [ 65536 ];
|
||||
|
||||
Com_DPrintf( "CopyFile (%s, %s)\n", src, dst );
|
||||
|
||||
f1 = fopen( src, "rb" );
|
||||
|
||||
if ( !f1 )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
f2 = fopen( dst, "wb" );
|
||||
|
||||
if ( !f2 )
|
||||
{
|
||||
fclose( f1 );
|
||||
return;
|
||||
}
|
||||
|
||||
while ( 1 )
|
||||
{
|
||||
l = fread( buffer, 1, sizeof ( buffer ), f1 );
|
||||
|
||||
if ( !l )
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
fwrite( buffer, 1, l, f2 );
|
||||
}
|
||||
|
||||
fclose( f1 );
|
||||
fclose( f2 );
|
||||
}
|
||||
|
||||
void
|
||||
SV_CopySaveGame ( char *src, char *dst )
|
||||
{
|
||||
char name [ MAX_OSPATH ], name2 [ MAX_OSPATH ];
|
||||
size_t l, len;
|
||||
char *found;
|
||||
|
||||
Com_DPrintf( "SV_CopySaveGame(%s, %s)\n", src, dst );
|
||||
|
||||
SV_WipeSavegame( dst );
|
||||
|
||||
/* copy the savegame over */
|
||||
Com_sprintf( name, sizeof ( name ), "%s/save/%s/server.ssv", FS_Gamedir(), src );
|
||||
Com_sprintf( name2, sizeof ( name2 ), "%s/save/%s/server.ssv", FS_Gamedir(), dst );
|
||||
FS_CreatePath( name2 );
|
||||
CopyFile( name, name2 );
|
||||
|
||||
Com_sprintf( name, sizeof ( name ), "%s/save/%s/game.ssv", FS_Gamedir(), src );
|
||||
Com_sprintf( name2, sizeof ( name2 ), "%s/save/%s/game.ssv", FS_Gamedir(), dst );
|
||||
CopyFile( name, name2 );
|
||||
|
||||
Com_sprintf( name, sizeof ( name ), "%s/save/%s/", FS_Gamedir(), src );
|
||||
len = strlen( name );
|
||||
Com_sprintf( name, sizeof ( name ), "%s/save/%s/*.sav", FS_Gamedir(), src );
|
||||
found = Sys_FindFirst( name, 0, 0 );
|
||||
|
||||
while ( found )
|
||||
{
|
||||
strcpy( name + len, found + len );
|
||||
|
||||
Com_sprintf( name2, sizeof ( name2 ), "%s/save/%s/%s", FS_Gamedir(), dst, found + len );
|
||||
CopyFile( name, name2 );
|
||||
|
||||
/* change sav to sv2 */
|
||||
l = strlen( name );
|
||||
strcpy( name + l - 3, "sv2" );
|
||||
l = strlen( name2 );
|
||||
strcpy( name2 + l - 3, "sv2" );
|
||||
CopyFile( name, name2 );
|
||||
|
||||
found = Sys_FindNext( 0, 0 );
|
||||
}
|
||||
|
||||
Sys_FindClose();
|
||||
}
|
||||
|
||||
void
|
||||
SV_WriteLevelFile ( void )
|
||||
{
|
||||
char name [ MAX_OSPATH ];
|
||||
FILE *f;
|
||||
|
||||
Com_DPrintf( "SV_WriteLevelFile()\n" );
|
||||
|
||||
Com_sprintf( name, sizeof ( name ), "%s/save/current/%s.sv2", FS_Gamedir(), sv.name );
|
||||
f = fopen( name, "wb" );
|
||||
|
||||
if ( !f )
|
||||
{
|
||||
Com_Printf( "Failed to open %s\n", name );
|
||||
return;
|
||||
}
|
||||
|
||||
fwrite( sv.configstrings, sizeof ( sv.configstrings ), 1, f );
|
||||
CM_WritePortalState( f );
|
||||
fclose( f );
|
||||
|
||||
Com_sprintf( name, sizeof ( name ), "%s/save/current/%s.sav", FS_Gamedir(), sv.name );
|
||||
ge->WriteLevel( name );
|
||||
}
|
||||
|
||||
void CM_ReadPortalState ( fileHandle_t f );
|
||||
|
||||
void
|
||||
SV_ReadLevelFile ( void )
|
||||
{
|
||||
char name [ MAX_OSPATH ];
|
||||
fileHandle_t f;
|
||||
|
||||
Com_DPrintf( "SV_ReadLevelFile()\n" );
|
||||
|
||||
Com_sprintf( name, sizeof ( name ), "save/current/%s.sv2", sv.name );
|
||||
FS_FOpenFile( name, &f, FS_READ );
|
||||
|
||||
if ( !f )
|
||||
{
|
||||
Com_Printf( "Failed to open %s\n", name );
|
||||
return;
|
||||
}
|
||||
|
||||
FS_Read( sv.configstrings, sizeof ( sv.configstrings ), f );
|
||||
CM_ReadPortalState( f );
|
||||
FS_FCloseFile( f );
|
||||
|
||||
Com_sprintf( name, sizeof ( name ), "%s/save/current/%s.sav", FS_Gamedir(), sv.name );
|
||||
ge->ReadLevel( name );
|
||||
}
|
||||
|
||||
void
|
||||
SV_WriteServerFile ( qboolean autosave )
|
||||
{
|
||||
FILE *f;
|
||||
cvar_t *var;
|
||||
char name [ MAX_OSPATH ], string [ 128 ];
|
||||
char comment [ 32 ];
|
||||
time_t aclock;
|
||||
struct tm *newtime;
|
||||
|
||||
Com_DPrintf( "SV_WriteServerFile(%s)\n", autosave ? "true" : "false" );
|
||||
|
||||
Com_sprintf( name, sizeof ( name ), "%s/save/current/server.ssv", FS_Gamedir() );
|
||||
f = fopen( name, "wb" );
|
||||
|
||||
if ( !f )
|
||||
{
|
||||
Com_Printf( "Couldn't write %s\n", name );
|
||||
return;
|
||||
}
|
||||
|
||||
/* write the comment field */
|
||||
memset( comment, 0, sizeof ( comment ) );
|
||||
|
||||
if ( !autosave )
|
||||
{
|
||||
time( &aclock );
|
||||
newtime = localtime( &aclock );
|
||||
Com_sprintf( comment, sizeof ( comment ), "%2i:%i%i %2i/%2i ", newtime->tm_hour,
|
||||
newtime->tm_min / 10, newtime->tm_min % 10,
|
||||
newtime->tm_mon + 1, newtime->tm_mday );
|
||||
strncat( comment, sv.configstrings [ CS_NAME ], sizeof ( comment ) - 1 - strlen( comment ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
/* autosaved */
|
||||
Com_sprintf( comment, sizeof ( comment ), "ENTERING %s", sv.configstrings [ CS_NAME ] );
|
||||
}
|
||||
|
||||
fwrite( comment, 1, sizeof ( comment ), f );
|
||||
|
||||
/* write the mapcmd */
|
||||
fwrite( svs.mapcmd, 1, sizeof ( svs.mapcmd ), f );
|
||||
|
||||
/* write all CVAR_LATCH cvars
|
||||
these will be things like coop, skill, deathmatch, etc */
|
||||
for ( var = cvar_vars; var; var = var->next )
|
||||
{
|
||||
if ( !( var->flags & CVAR_LATCH ) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( ( strlen( var->name ) >= sizeof ( name ) - 1 ) ||
|
||||
( strlen( var->string ) >= sizeof ( string ) - 1 ) )
|
||||
{
|
||||
Com_Printf( "Cvar too long: %s = %s\n", var->name, var->string );
|
||||
continue;
|
||||
}
|
||||
|
||||
memset( name, 0, sizeof ( name ) );
|
||||
memset( string, 0, sizeof ( string ) );
|
||||
strcpy( name, var->name );
|
||||
strcpy( string, var->string );
|
||||
fwrite( name, 1, sizeof ( name ), f );
|
||||
fwrite( string, 1, sizeof ( string ), f );
|
||||
}
|
||||
|
||||
fclose( f );
|
||||
|
||||
/* write game state */
|
||||
Com_sprintf( name, sizeof ( name ), "%s/save/current/game.ssv", FS_Gamedir() );
|
||||
ge->WriteGame( name, autosave );
|
||||
}
|
||||
|
||||
void
|
||||
SV_ReadServerFile ( void )
|
||||
{
|
||||
fileHandle_t f;
|
||||
char name [ MAX_OSPATH ], string [ 128 ];
|
||||
char comment [ 32 ];
|
||||
char mapcmd [ MAX_TOKEN_CHARS ];
|
||||
|
||||
Com_DPrintf( "SV_ReadServerFile()\n" );
|
||||
|
||||
Com_sprintf( name, sizeof ( name ), "save/current/server.ssv" );
|
||||
FS_FOpenFile( name, &f, FS_READ );
|
||||
|
||||
if ( !f )
|
||||
{
|
||||
Com_Printf( "Couldn't read %s\n", name );
|
||||
return;
|
||||
}
|
||||
|
||||
/* read the comment field */
|
||||
FS_Read( comment, sizeof ( comment ), f );
|
||||
|
||||
/* read the mapcmd */
|
||||
FS_Read( mapcmd, sizeof ( mapcmd ), f );
|
||||
|
||||
/* read all CVAR_LATCH cvars
|
||||
these will be things like coop, skill, deathmatch, etc */
|
||||
while ( 1 )
|
||||
{
|
||||
if ( !FS_FRead( name, 1, sizeof ( name ), f ) )
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
FS_Read( string, sizeof ( string ), f );
|
||||
Com_DPrintf( "Set %s = %s\n", name, string );
|
||||
Cvar_ForceSet( name, string );
|
||||
}
|
||||
|
||||
FS_FCloseFile( f );
|
||||
|
||||
/* start a new game fresh with new cvars */
|
||||
SV_InitGame();
|
||||
|
||||
strcpy( svs.mapcmd, mapcmd );
|
||||
|
||||
/* read game state */
|
||||
Com_sprintf( name, sizeof ( name ), "%s/save/current/game.ssv", FS_Gamedir() );
|
||||
ge->ReadGame( name );
|
||||
}
|
||||
|
||||
/* ========================================================= */
|
||||
|
||||
/*
|
||||
* Puts the server in demo mode on a specific map/cinematic
|
||||
*/
|
||||
|
@ -596,117 +284,6 @@ SV_Map_f ( void )
|
|||
SV_GameMap_f();
|
||||
}
|
||||
|
||||
/*
|
||||
* =====================================================================
|
||||
*
|
||||
* SAVEGAMES
|
||||
*
|
||||
* =====================================================================
|
||||
*/
|
||||
|
||||
void
|
||||
SV_Loadgame_f ( void )
|
||||
{
|
||||
char name [ MAX_OSPATH ];
|
||||
FILE *f;
|
||||
char *dir;
|
||||
|
||||
if ( Cmd_Argc() != 2 )
|
||||
{
|
||||
Com_Printf( "USAGE: loadgame <directory>\n" );
|
||||
return;
|
||||
}
|
||||
|
||||
Com_Printf( "Loading game...\n" );
|
||||
|
||||
dir = Cmd_Argv( 1 );
|
||||
|
||||
if ( strstr( dir, ".." ) || strstr( dir, "/" ) || strstr( dir, "\\" ) )
|
||||
{
|
||||
Com_Printf( "Bad savedir.\n" );
|
||||
}
|
||||
|
||||
/* make sure the server.ssv file exists */
|
||||
Com_sprintf( name, sizeof ( name ), "%s/save/%s/server.ssv", FS_Gamedir(), Cmd_Argv( 1 ) );
|
||||
f = fopen( name, "rb" );
|
||||
|
||||
if ( !f )
|
||||
{
|
||||
Com_Printf( "No such savegame: %s\n", name );
|
||||
return;
|
||||
}
|
||||
|
||||
fclose( f );
|
||||
|
||||
SV_CopySaveGame( Cmd_Argv( 1 ), "current" );
|
||||
|
||||
SV_ReadServerFile();
|
||||
|
||||
/* go to the map */
|
||||
sv.state = ss_dead; /* don't save current level when changing */
|
||||
SV_Map( false, svs.mapcmd, true );
|
||||
}
|
||||
|
||||
void
|
||||
SV_Savegame_f ( void )
|
||||
{
|
||||
char *dir;
|
||||
|
||||
if ( sv.state != ss_game )
|
||||
{
|
||||
Com_Printf( "You must be in a game to save.\n" );
|
||||
return;
|
||||
}
|
||||
|
||||
if ( Cmd_Argc() != 2 )
|
||||
{
|
||||
Com_Printf( "USAGE: savegame <directory>\n" );
|
||||
return;
|
||||
}
|
||||
|
||||
if ( Cvar_VariableValue( "deathmatch" ) )
|
||||
{
|
||||
Com_Printf( "Can't savegame in a deathmatch\n" );
|
||||
return;
|
||||
}
|
||||
|
||||
if ( !strcmp( Cmd_Argv( 1 ), "current" ) )
|
||||
{
|
||||
Com_Printf( "Can't save to 'current'\n" );
|
||||
return;
|
||||
}
|
||||
|
||||
if ( ( maxclients->value == 1 ) && ( svs.clients [ 0 ].edict->client->ps.stats [ STAT_HEALTH ] <= 0 ) )
|
||||
{
|
||||
Com_Printf( "\nCan't savegame while dead!\n" );
|
||||
return;
|
||||
}
|
||||
|
||||
dir = Cmd_Argv( 1 );
|
||||
|
||||
if ( strstr( dir, ".." ) || strstr( dir, "/" ) || strstr( dir, "\\" ) )
|
||||
{
|
||||
Com_Printf( "Bad savedir.\n" );
|
||||
}
|
||||
|
||||
Com_Printf( "Saving game...\n" );
|
||||
|
||||
/* archive current level, including all client edicts.
|
||||
when the level is reloaded, they will be shells awaiting
|
||||
a connecting client */
|
||||
SV_WriteLevelFile();
|
||||
|
||||
/* save server state */
|
||||
SV_WriteServerFile( false );
|
||||
|
||||
/* copy it off */
|
||||
SV_CopySaveGame( "current", dir );
|
||||
|
||||
Com_Printf( "Done.\n" );
|
||||
}
|
||||
|
||||
/* =============================================================== */
|
||||
|
||||
/*
|
||||
* Kick a user off of the server
|
||||
*/
|
||||
|
|
431
src/server/sv_save.c
Normal file
431
src/server/sv_save.c
Normal file
|
@ -0,0 +1,431 @@
|
|||
/*
|
||||
* Copyright (C) 1997-2001 Id Software, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 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.
|
||||
*
|
||||
* See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
* 02111-1307, USA.
|
||||
*
|
||||
* =======================================================================
|
||||
*
|
||||
* Serverside savegame code.
|
||||
*
|
||||
* =======================================================================
|
||||
*/
|
||||
|
||||
#include "header/server.h"
|
||||
|
||||
void CM_ReadPortalState ( fileHandle_t f );
|
||||
|
||||
/*
|
||||
* Delete save/<XXX>/
|
||||
*/
|
||||
void
|
||||
SV_WipeSavegame ( char *savename )
|
||||
{
|
||||
char name [ MAX_OSPATH ];
|
||||
char *s;
|
||||
|
||||
Com_DPrintf( "SV_WipeSaveGame(%s)\n", savename );
|
||||
|
||||
Com_sprintf( name, sizeof ( name ), "%s/save/%s/server.ssv", FS_Gamedir(), savename );
|
||||
remove( name );
|
||||
Com_sprintf( name, sizeof ( name ), "%s/save/%s/game.ssv", FS_Gamedir(), savename );
|
||||
remove( name );
|
||||
|
||||
Com_sprintf( name, sizeof ( name ), "%s/save/%s/*.sav", FS_Gamedir(), savename );
|
||||
s = Sys_FindFirst( name, 0, 0 );
|
||||
|
||||
while ( s )
|
||||
{
|
||||
remove( s );
|
||||
s = Sys_FindNext( 0, 0 );
|
||||
}
|
||||
|
||||
Sys_FindClose();
|
||||
Com_sprintf( name, sizeof ( name ), "%s/save/%s/*.sv2", FS_Gamedir(), savename );
|
||||
s = Sys_FindFirst( name, 0, 0 );
|
||||
|
||||
while ( s )
|
||||
{
|
||||
remove( s );
|
||||
s = Sys_FindNext( 0, 0 );
|
||||
}
|
||||
|
||||
Sys_FindClose();
|
||||
}
|
||||
|
||||
void
|
||||
CopyFile ( char *src, char *dst )
|
||||
{
|
||||
FILE *f1, *f2;
|
||||
size_t l;
|
||||
byte buffer [ 65536 ];
|
||||
|
||||
Com_DPrintf( "CopyFile (%s, %s)\n", src, dst );
|
||||
|
||||
f1 = fopen( src, "rb" );
|
||||
|
||||
if ( !f1 )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
f2 = fopen( dst, "wb" );
|
||||
|
||||
if ( !f2 )
|
||||
{
|
||||
fclose( f1 );
|
||||
return;
|
||||
}
|
||||
|
||||
while ( 1 )
|
||||
{
|
||||
l = fread( buffer, 1, sizeof ( buffer ), f1 );
|
||||
|
||||
if ( !l )
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
fwrite( buffer, 1, l, f2 );
|
||||
}
|
||||
|
||||
fclose( f1 );
|
||||
fclose( f2 );
|
||||
}
|
||||
|
||||
void
|
||||
SV_CopySaveGame ( char *src, char *dst )
|
||||
{
|
||||
char name [ MAX_OSPATH ], name2 [ MAX_OSPATH ];
|
||||
size_t l, len;
|
||||
char *found;
|
||||
|
||||
Com_DPrintf( "SV_CopySaveGame(%s, %s)\n", src, dst );
|
||||
|
||||
SV_WipeSavegame( dst );
|
||||
|
||||
/* copy the savegame over */
|
||||
Com_sprintf( name, sizeof ( name ), "%s/save/%s/server.ssv", FS_Gamedir(), src );
|
||||
Com_sprintf( name2, sizeof ( name2 ), "%s/save/%s/server.ssv", FS_Gamedir(), dst );
|
||||
FS_CreatePath( name2 );
|
||||
CopyFile( name, name2 );
|
||||
|
||||
Com_sprintf( name, sizeof ( name ), "%s/save/%s/game.ssv", FS_Gamedir(), src );
|
||||
Com_sprintf( name2, sizeof ( name2 ), "%s/save/%s/game.ssv", FS_Gamedir(), dst );
|
||||
CopyFile( name, name2 );
|
||||
|
||||
Com_sprintf( name, sizeof ( name ), "%s/save/%s/", FS_Gamedir(), src );
|
||||
len = strlen( name );
|
||||
Com_sprintf( name, sizeof ( name ), "%s/save/%s/*.sav", FS_Gamedir(), src );
|
||||
found = Sys_FindFirst( name, 0, 0 );
|
||||
|
||||
while ( found )
|
||||
{
|
||||
strcpy( name + len, found + len );
|
||||
|
||||
Com_sprintf( name2, sizeof ( name2 ), "%s/save/%s/%s", FS_Gamedir(), dst, found + len );
|
||||
CopyFile( name, name2 );
|
||||
|
||||
/* change sav to sv2 */
|
||||
l = strlen( name );
|
||||
strcpy( name + l - 3, "sv2" );
|
||||
l = strlen( name2 );
|
||||
strcpy( name2 + l - 3, "sv2" );
|
||||
CopyFile( name, name2 );
|
||||
|
||||
found = Sys_FindNext( 0, 0 );
|
||||
}
|
||||
|
||||
Sys_FindClose();
|
||||
}
|
||||
|
||||
void
|
||||
SV_WriteLevelFile ( void )
|
||||
{
|
||||
char name [ MAX_OSPATH ];
|
||||
FILE *f;
|
||||
|
||||
Com_DPrintf( "SV_WriteLevelFile()\n" );
|
||||
|
||||
Com_sprintf( name, sizeof ( name ), "%s/save/current/%s.sv2", FS_Gamedir(), sv.name );
|
||||
f = fopen( name, "wb" );
|
||||
|
||||
if ( !f )
|
||||
{
|
||||
Com_Printf( "Failed to open %s\n", name );
|
||||
return;
|
||||
}
|
||||
|
||||
fwrite( sv.configstrings, sizeof ( sv.configstrings ), 1, f );
|
||||
CM_WritePortalState( f );
|
||||
fclose( f );
|
||||
|
||||
Com_sprintf( name, sizeof ( name ), "%s/save/current/%s.sav", FS_Gamedir(), sv.name );
|
||||
ge->WriteLevel( name );
|
||||
}
|
||||
|
||||
void
|
||||
SV_ReadLevelFile ( void )
|
||||
{
|
||||
char name [ MAX_OSPATH ];
|
||||
fileHandle_t f;
|
||||
|
||||
Com_DPrintf( "SV_ReadLevelFile()\n" );
|
||||
|
||||
Com_sprintf( name, sizeof ( name ), "save/current/%s.sv2", sv.name );
|
||||
FS_FOpenFile( name, &f, FS_READ );
|
||||
|
||||
if ( !f )
|
||||
{
|
||||
Com_Printf( "Failed to open %s\n", name );
|
||||
return;
|
||||
}
|
||||
|
||||
FS_Read( sv.configstrings, sizeof ( sv.configstrings ), f );
|
||||
CM_ReadPortalState( f );
|
||||
FS_FCloseFile( f );
|
||||
|
||||
Com_sprintf( name, sizeof ( name ), "%s/save/current/%s.sav", FS_Gamedir(), sv.name );
|
||||
ge->ReadLevel( name );
|
||||
}
|
||||
|
||||
void
|
||||
SV_WriteServerFile ( qboolean autosave )
|
||||
{
|
||||
FILE *f;
|
||||
cvar_t *var;
|
||||
char name [ MAX_OSPATH ], string [ 128 ];
|
||||
char comment [ 32 ];
|
||||
time_t aclock;
|
||||
struct tm *newtime;
|
||||
|
||||
Com_DPrintf( "SV_WriteServerFile(%s)\n", autosave ? "true" : "false" );
|
||||
|
||||
Com_sprintf( name, sizeof ( name ), "%s/save/current/server.ssv", FS_Gamedir() );
|
||||
f = fopen( name, "wb" );
|
||||
|
||||
if ( !f )
|
||||
{
|
||||
Com_Printf( "Couldn't write %s\n", name );
|
||||
return;
|
||||
}
|
||||
|
||||
/* write the comment field */
|
||||
memset( comment, 0, sizeof ( comment ) );
|
||||
|
||||
if ( !autosave )
|
||||
{
|
||||
time( &aclock );
|
||||
newtime = localtime( &aclock );
|
||||
Com_sprintf( comment, sizeof ( comment ), "%2i:%i%i %2i/%2i ", newtime->tm_hour,
|
||||
newtime->tm_min / 10, newtime->tm_min % 10,
|
||||
newtime->tm_mon + 1, newtime->tm_mday );
|
||||
strncat( comment, sv.configstrings [ CS_NAME ], sizeof ( comment ) - 1 - strlen( comment ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
/* autosaved */
|
||||
Com_sprintf( comment, sizeof ( comment ), "ENTERING %s", sv.configstrings [ CS_NAME ] );
|
||||
}
|
||||
|
||||
fwrite( comment, 1, sizeof ( comment ), f );
|
||||
|
||||
/* write the mapcmd */
|
||||
fwrite( svs.mapcmd, 1, sizeof ( svs.mapcmd ), f );
|
||||
|
||||
/* write all CVAR_LATCH cvars
|
||||
these will be things like coop, skill, deathmatch, etc */
|
||||
for ( var = cvar_vars; var; var = var->next )
|
||||
{
|
||||
if ( !( var->flags & CVAR_LATCH ) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( ( strlen( var->name ) >= sizeof ( name ) - 1 ) ||
|
||||
( strlen( var->string ) >= sizeof ( string ) - 1 ) )
|
||||
{
|
||||
Com_Printf( "Cvar too long: %s = %s\n", var->name, var->string );
|
||||
continue;
|
||||
}
|
||||
|
||||
memset( name, 0, sizeof ( name ) );
|
||||
memset( string, 0, sizeof ( string ) );
|
||||
strcpy( name, var->name );
|
||||
strcpy( string, var->string );
|
||||
fwrite( name, 1, sizeof ( name ), f );
|
||||
fwrite( string, 1, sizeof ( string ), f );
|
||||
}
|
||||
|
||||
fclose( f );
|
||||
|
||||
/* write game state */
|
||||
Com_sprintf( name, sizeof ( name ), "%s/save/current/game.ssv", FS_Gamedir() );
|
||||
ge->WriteGame( name, autosave );
|
||||
}
|
||||
|
||||
void
|
||||
SV_ReadServerFile ( void )
|
||||
{
|
||||
fileHandle_t f;
|
||||
char name [ MAX_OSPATH ], string [ 128 ];
|
||||
char comment [ 32 ];
|
||||
char mapcmd [ MAX_TOKEN_CHARS ];
|
||||
|
||||
Com_DPrintf( "SV_ReadServerFile()\n" );
|
||||
|
||||
Com_sprintf( name, sizeof ( name ), "save/current/server.ssv" );
|
||||
FS_FOpenFile( name, &f, FS_READ );
|
||||
|
||||
if ( !f )
|
||||
{
|
||||
Com_Printf( "Couldn't read %s\n", name );
|
||||
return;
|
||||
}
|
||||
|
||||
/* read the comment field */
|
||||
FS_Read( comment, sizeof ( comment ), f );
|
||||
|
||||
/* read the mapcmd */
|
||||
FS_Read( mapcmd, sizeof ( mapcmd ), f );
|
||||
|
||||
/* read all CVAR_LATCH cvars
|
||||
these will be things like coop, skill, deathmatch, etc */
|
||||
while ( 1 )
|
||||
{
|
||||
if ( !FS_FRead( name, 1, sizeof ( name ), f ) )
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
FS_Read( string, sizeof ( string ), f );
|
||||
Com_DPrintf( "Set %s = %s\n", name, string );
|
||||
Cvar_ForceSet( name, string );
|
||||
}
|
||||
|
||||
FS_FCloseFile( f );
|
||||
|
||||
/* start a new game fresh with new cvars */
|
||||
SV_InitGame();
|
||||
|
||||
strcpy( svs.mapcmd, mapcmd );
|
||||
|
||||
/* read game state */
|
||||
Com_sprintf( name, sizeof ( name ), "%s/save/current/game.ssv", FS_Gamedir() );
|
||||
ge->ReadGame( name );
|
||||
}
|
||||
|
||||
void
|
||||
SV_Loadgame_f ( void )
|
||||
{
|
||||
char name [ MAX_OSPATH ];
|
||||
FILE *f;
|
||||
char *dir;
|
||||
|
||||
if ( Cmd_Argc() != 2 )
|
||||
{
|
||||
Com_Printf( "USAGE: loadgame <directory>\n" );
|
||||
return;
|
||||
}
|
||||
|
||||
Com_Printf( "Loading game...\n" );
|
||||
|
||||
dir = Cmd_Argv( 1 );
|
||||
|
||||
if ( strstr( dir, ".." ) || strstr( dir, "/" ) || strstr( dir, "\\" ) )
|
||||
{
|
||||
Com_Printf( "Bad savedir.\n" );
|
||||
}
|
||||
|
||||
/* make sure the server.ssv file exists */
|
||||
Com_sprintf( name, sizeof ( name ), "%s/save/%s/server.ssv", FS_Gamedir(), Cmd_Argv( 1 ) );
|
||||
f = fopen( name, "rb" );
|
||||
|
||||
if ( !f )
|
||||
{
|
||||
Com_Printf( "No such savegame: %s\n", name );
|
||||
return;
|
||||
}
|
||||
|
||||
fclose( f );
|
||||
|
||||
SV_CopySaveGame( Cmd_Argv( 1 ), "current" );
|
||||
|
||||
SV_ReadServerFile();
|
||||
|
||||
/* go to the map */
|
||||
sv.state = ss_dead; /* don't save current level when changing */
|
||||
SV_Map( false, svs.mapcmd, true );
|
||||
}
|
||||
|
||||
void
|
||||
SV_Savegame_f ( void )
|
||||
{
|
||||
char *dir;
|
||||
|
||||
if ( sv.state != ss_game )
|
||||
{
|
||||
Com_Printf( "You must be in a game to save.\n" );
|
||||
return;
|
||||
}
|
||||
|
||||
if ( Cmd_Argc() != 2 )
|
||||
{
|
||||
Com_Printf( "USAGE: savegame <directory>\n" );
|
||||
return;
|
||||
}
|
||||
|
||||
if ( Cvar_VariableValue( "deathmatch" ) )
|
||||
{
|
||||
Com_Printf( "Can't savegame in a deathmatch\n" );
|
||||
return;
|
||||
}
|
||||
|
||||
if ( !strcmp( Cmd_Argv( 1 ), "current" ) )
|
||||
{
|
||||
Com_Printf( "Can't save to 'current'\n" );
|
||||
return;
|
||||
}
|
||||
|
||||
if ( ( maxclients->value == 1 ) && ( svs.clients [ 0 ].edict->client->ps.stats [ STAT_HEALTH ] <= 0 ) )
|
||||
{
|
||||
Com_Printf( "\nCan't savegame while dead!\n" );
|
||||
return;
|
||||
}
|
||||
|
||||
dir = Cmd_Argv( 1 );
|
||||
|
||||
if ( strstr( dir, ".." ) || strstr( dir, "/" ) || strstr( dir, "\\" ) )
|
||||
{
|
||||
Com_Printf( "Bad savedir.\n" );
|
||||
}
|
||||
|
||||
Com_Printf( "Saving game...\n" );
|
||||
|
||||
/* archive current level, including all client edicts.
|
||||
when the level is reloaded, they will be shells awaiting
|
||||
a connecting client */
|
||||
SV_WriteLevelFile();
|
||||
|
||||
/* save server state */
|
||||
SV_WriteServerFile( false );
|
||||
|
||||
/* copy it off */
|
||||
SV_CopySaveGame( "current", dir );
|
||||
|
||||
Com_Printf( "Done.\n" );
|
||||
}
|
||||
|
Loading…
Reference in a new issue