2012-11-26 18:58:24 +00:00
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
Doom 3 BFG Edition GPL Source Code
2012-11-28 15:47:07 +00:00
Copyright ( C ) 1993 - 2012 id Software LLC , a ZeniMax Media company .
2012-11-26 18:58:24 +00:00
2012-11-28 15:47:07 +00:00
This file is part of the Doom 3 BFG Edition GPL Source Code ( " Doom 3 BFG Edition Source Code " ) .
2012-11-26 18:58:24 +00:00
Doom 3 BFG Edition Source Code 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 3 of the License , or
( at your option ) any later version .
Doom 3 BFG Edition Source Code 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 Doom 3 BFG Edition Source Code . If not , see < http : //www.gnu.org/licenses/>.
In addition , the Doom 3 BFG Edition Source Code is also subject to certain additional terms . You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code . If not , please request a copy in writing from id Software at the address below .
If you have questions concerning this license or the applicable additional terms , you may contact in writing id Software LLC , c / o ZeniMax Media Inc . , Suite 120 , Rockville , Maryland 20850 USA .
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
# ifndef __SYS_SAVEGAME_H__
# define __SYS_SAVEGAME_H__
# ifdef OUTPUT_FUNC
# undef OUTPUT_FUNC
# endif
# ifdef OUTPUT_FUNC_EXIT
# undef OUTPUT_FUNC_EXIT
# endif
# define OUTPUT_FUNC() idLib::PrintfIf( saveGame_verbose.GetBool(), "[%s] Enter\n", __FUNCTION__ )
# define OUTPUT_FUNC_EXIT() idLib::PrintfIf( saveGame_verbose.GetBool(), "[%s] Exit\n", __FUNCTION__ )
# define DEFINE_CLASS( x ) virtual const char * Name() const { return #x; }
# define MAX_SAVEGAMES 16
# define MAX_FILES_WITHIN_SAVEGAME 10
# define MIN_SAVEGAME_SIZE_BYTES ( 4 * 1024 * 1024 )
# define MAX_SAVEGAME_STRING_TABLE_SIZE 400 * 1024 // 400 kB max string table size
# define MAX_FILENAME_LENGTH 255
# define MAX_FILENAME_LENGTH_PATTERN 8
# define MAX_FOLDER_NAME_LENGTH 64
# define SAVEGAME_DETAILS_FILENAME "game.details"
// PS3 restrictions: The only characters that can be used are 0-9 (numbers), A-Z (uppercase alphabet), "_" (underscore), and "-" (hyphen)
# define SAVEGAME_AUTOSAVE_FOLDER "AUTOSAVE" // auto save slot
// common descriptors for savegame description fields
# define SAVEGAME_DETAIL_FIELD_EXPANSION "expansion"
# define SAVEGAME_DETAIL_FIELD_MAP "mapName"
# define SAVEGAME_DETAIL_FIELD_MAP_LOCATE "mapLocation"
# define SAVEGAME_DETAIL_FIELD_DIFFICULTY "difficulty"
# define SAVEGAME_DETAIL_FIELD_PLAYTIME "playTime"
# define SAVEGAME_DETAIL_FIELD_LANGUAGE "language"
# define SAVEGAME_DETAIL_FIELD_SAVE_VERSION "saveVersion"
# define SAVEGAME_DETAIL_FIELD_CHECKSUM "checksum"
# define SAVEGAME_GAME_DIRECTORY_PREFIX "GAME-"
# define SAVEGAME_PROFILE_DIRECTORY_PREFIX ""
# define SAVEGAME_RAW_DIRECTORY_PREFIX ""
extern idCVar saveGame_verbose ;
extern idCVar saveGame_enable ;
class idGameSpawnInfo ;
class idSession ;
class idSessionLocal ;
class idSaveGameManager ;
// Specific savegame sub-system errors
2012-11-28 15:47:07 +00:00
enum saveGameError_t
{
2012-11-26 18:58:24 +00:00
SAVEGAME_E_NONE = 0 ,
SAVEGAME_E_CANCELLED = BIT ( 0 ) ,
SAVEGAME_E_INSUFFICIENT_ROOM = BIT ( 1 ) ,
SAVEGAME_E_CORRUPTED = BIT ( 2 ) ,
SAVEGAME_E_UNABLE_TO_SELECT_STORAGE_DEVICE = BIT ( 3 ) ,
SAVEGAME_E_UNKNOWN = BIT ( 4 ) ,
SAVEGAME_E_INVALID_FILENAME = BIT ( 5 ) ,
SAVEGAME_E_STEAM_ERROR = BIT ( 6 ) ,
SAVEGAME_E_FOLDER_NOT_FOUND = BIT ( 7 ) ,
SAVEGAME_E_FILE_NOT_FOUND = BIT ( 8 ) ,
SAVEGAME_E_DLC_NOT_FOUND = BIT ( 9 ) ,
SAVEGAME_E_INVALID_USER = BIT ( 10 ) ,
SAVEGAME_E_PROFILE_TOO_BIG = BIT ( 11 ) ,
SAVEGAME_E_DISC_SWAP = BIT ( 12 ) ,
SAVEGAME_E_INCOMPATIBLE_NEWER_VERSION = BIT ( 13 ) ,
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
SAVEGAME_E_BITS_USED = 14 ,
SAVEGAME_E_NUM = SAVEGAME_E_BITS_USED + 1 // because we're counting "none"
} ;
// Modes to control behavior of savegame manager
2012-11-28 15:47:07 +00:00
enum saveGameModeBitfield_t
{
2012-11-26 18:58:24 +00:00
SAVEGAME_MBF_NONE = 0 ,
SAVEGAME_MBF_LOAD = BIT ( 0 ) , // standard file load (can be individual/multiple files described in parms)
SAVEGAME_MBF_SAVE = BIT ( 1 ) , // standard file save (can be individual/multiple files described in parms)
SAVEGAME_MBF_DELETE_FOLDER = BIT ( 2 ) , // standard package delete
SAVEGAME_MBF_DELETE_ALL_FOLDERS = BIT ( 3 ) , // deletes all of the savegame folders (should only be used in testing)
SAVEGAME_MBF_ENUMERATE = BIT ( 4 ) , // gets listing of all savegame folders, typically used with READ_DETAILS to read the description file
SAVEGAME_MBF_NO_COMPRESS = BIT ( 5 ) , // tells the system the files aren't compressed, usually only needed when reading the descriptors file internally
SAVEGAME_MBF_ENUMERATE_FILES = BIT ( 6 ) , // enumerates all the files within a particular savegame folder (can be individual/multiple files or pattern described in parms)
SAVEGAME_MBF_DELETE_FILES = BIT ( 7 ) , // deletes individual files within a particular savegame folder (can be individual/multiple files or pattern described in parms)
SAVEGAME_MBF_READ_DETAILS = BIT ( 8 ) , // reads the description file (if specified, parms.enumeratedEntry.name & parms.enumeratedEntry.type must be specified)
SAVEGAME_MBF_KEEP_FOLDER = BIT ( 9 ) // don't delete the folder before saving
} ;
typedef interlockedInt_t saveGameHandle_t ;
typedef int savegameUserId_t ; // [internal] hash of gamer tag for steam
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
saveGameCheck_t
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
struct saveGameCheck_t
{
saveGameCheck_t ( )
{
2012-11-26 18:58:24 +00:00
exists = false ;
autosaveExists = false ;
autosaveFolder = NULL ;
}
bool exists ;
bool autosaveExists ;
2012-11-28 15:47:07 +00:00
const char * autosaveFolder ;
2012-11-26 18:58:24 +00:00
} ;
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
2012-11-28 15:47:07 +00:00
idSaveGameDetails
2012-11-26 18:58:24 +00:00
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
class idSaveGameDetails
{
2012-11-26 18:58:24 +00:00
public :
idSaveGameDetails ( ) ;
2012-11-28 15:47:07 +00:00
~ idSaveGameDetails ( )
{
Clear ( ) ;
}
2012-11-26 18:58:24 +00:00
void Clear ( ) ;
2012-11-28 15:47:07 +00:00
bool operator = = ( const idSaveGameDetails & other ) const
{
return ( idStr : : Icmp ( slotName , other . slotName ) = = 0 ) ;
}
idSaveGameDetails & operator = ( const idSaveGameDetails & other )
{
2012-11-26 18:58:24 +00:00
descriptors . Clear ( ) ;
descriptors = other . descriptors ;
damaged = other . damaged ;
date = other . date ;
slotName = other . slotName ;
return * this ;
}
// for std::sort, sort newer (larger date) towards start of list
2012-12-02 21:37:32 +00:00
bool operator < ( const idSaveGameDetails & other ) const
2012-11-28 15:47:07 +00:00
{
return date > other . date ;
}
idStr GetMapName ( ) const
{
return descriptors . GetString ( SAVEGAME_DETAIL_FIELD_MAP , " " ) ;
}
idStr GetLocation ( ) const
{
return descriptors . GetString ( SAVEGAME_DETAIL_FIELD_MAP_LOCATE , " " ) ;
}
idStr GetLanguage ( ) const
{
return descriptors . GetString ( SAVEGAME_DETAIL_FIELD_LANGUAGE , " " ) ;
}
int GetPlaytime ( ) const
{
return descriptors . GetInt ( SAVEGAME_DETAIL_FIELD_PLAYTIME , 0 ) ;
}
int GetExpansion ( ) const
{
return descriptors . GetInt ( SAVEGAME_DETAIL_FIELD_EXPANSION , 0 ) ;
}
int GetDifficulty ( ) const
{
return descriptors . GetInt ( SAVEGAME_DETAIL_FIELD_DIFFICULTY , - 1 ) ;
}
int GetSaveVersion ( ) const
{
return descriptors . GetInt ( SAVEGAME_DETAIL_FIELD_SAVE_VERSION , 0 ) ;
}
2012-11-26 18:58:24 +00:00
public :
idDict descriptors ; // [in] Descriptors available to be shown on the save/load screen. Each game can define their own, e.g. Difficulty, level, map, score, time.
bool damaged ; // [out]
time_t date ; // [out] read from the filesystem, not set by client
idStrStatic < MAX_FOLDER_NAME_LENGTH > slotName ; // [out] folder/slot name, e.g. AUTOSAVE
} ;
typedef idStaticList < idSaveGameDetails , MAX_SAVEGAMES > saveGameDetailsList_t ;
// Making a auto_ptr to handle lifetime issues better
2012-11-28 15:47:07 +00:00
typedef idList < idFile_SaveGame * , TAG_SAVEGAMES > saveFileEntryList_t ;
2012-11-26 18:58:24 +00:00
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
2012-11-28 15:47:07 +00:00
idSaveLoadParms
2012-11-26 18:58:24 +00:00
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
class idSaveLoadParms
{
2012-11-26 18:58:24 +00:00
public :
2012-11-28 15:47:07 +00:00
idSaveLoadParms ( ) ;
~ idSaveLoadParms ( ) ;
2012-11-26 18:58:24 +00:00
void ResetCancelled ( ) ;
void Init ( ) ;
void SetDefaults ( int inputDevice = - 1 ) ; // doesn't clear out things that should be persistent across entire processor
void CancelSaveGameFilePipelines ( ) ;
void AbortSaveGameFilePipeline ( ) ;
2012-11-28 15:47:07 +00:00
const int & GetError ( ) const
{
return errorCode ;
}
const int & GetHandledErrors ( ) const
{
return handledErrorCodes ;
}
const saveGameHandle_t & GetHandle ( ) const
{
return handle ;
}
2012-11-26 18:58:24 +00:00
public :
idStrStatic < MAX_FOLDER_NAME_LENGTH > directory ; // [in] real directory of the savegame package
idStrStatic < MAX_FILENAME_LENGTH_PATTERN > pattern ; // [in] pattern to use while enumerating/deleting files within a savegame folder
idStrStatic < MAX_FILENAME_LENGTH_PATTERN > postPattern ; // [in] pattern at the end of the file to use while enumerating/deleting files within a savegame folder
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
int mode ; // [in] SAVE, LOAD, ENUM, DELETE, etc.
idSaveGameDetails description ; // [in/out] in: description used to serialize into game.details file, out: if SAVEGAME_MBF_READ_DETAILS used with certain modes, item 0 contains the read details
saveFileEntryList_t files ; // [in/out] in: files to be saved, out: objects loaded, for SAVEGAME_MBF_ENUMERATE_FILES, it contains a listing of the filenames only
saveGameDetailsList_t detailList ; // [out] listing of the enumerated savegames used only with SAVEGAME_MBF_ENUMERATE
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
int errorCode ; // [out] combination of saveGameError_t bits
int handledErrorCodes ; // [out] combination of saveGameError_t bits
int64 requiredSpaceInBytes ; // [out] when fails for insufficient space, this is populated with additional space required
int skipErrorDialogMask ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// ----------------------
// Internal vars
// ----------------------
idSysSignal callbackSignal ; // [internal] used to signal savegame manager that the Process() call is completed (we still might have more Process() calls to make though...)
volatile bool cancelled ; // [internal] while processor is running, this can be set outside of the normal operation of the processor. Each implementation should check this during operation to allow it to shutdown cleanly.
savegameUserId_t userId ; // [internal] to get the proper user during every step
int inputDeviceId ; // [internal] consoles will use this to segregate each player's files
saveGameHandle_t handle ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
private :
// Don't allow copies
2012-11-28 15:47:07 +00:00
idSaveLoadParms ( const idSaveLoadParms & s ) { }
void operator = ( const idSaveLoadParms & s ) { }
2012-11-26 18:58:24 +00:00
} ;
// Using function pointers because:
// 1. CompletedCallback methods in processors weren't generic enough, we could use SaveFiles processors
// for profiles/games, but there would be a single completed callback and we'd have to update
// the callback to detect what type of call it was, store the type in the processor, etc.
// 2. Using a functor class would require us to define classes for each callback. The definition of those
// classes could be scattered and a little difficult to follow
// 3. With callback methods, we assign them when needed and know exactly where they are defined/declared.
//typedef void (*saveGameProcessorCallback_t)( idSaveLoadParms & parms );
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
2012-11-28 15:47:07 +00:00
saveGameThreadArgs_t
2012-11-26 18:58:24 +00:00
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
struct saveGameThreadArgs_t
{
2012-11-26 18:58:24 +00:00
saveGameThreadArgs_t ( ) :
2012-11-28 15:47:07 +00:00
saveLoadParms ( NULL )
{
2012-11-26 18:58:24 +00:00
}
2012-11-28 15:47:07 +00:00
idSaveLoadParms * saveLoadParms ;
2012-11-26 18:58:24 +00:00
} ;
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
2012-11-28 15:47:07 +00:00
idSaveGameThread
2012-11-26 18:58:24 +00:00
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
class idSaveGameThread : public idSysThread
{
2012-11-26 18:58:24 +00:00
public :
2012-11-28 15:47:07 +00:00
idSaveGameThread ( ) : cancel ( false ) { }
2012-11-26 18:58:24 +00:00
int Run ( ) ;
2012-11-28 15:47:07 +00:00
void CancelOperations ( )
{
cancel = true ;
}
2012-11-26 18:58:24 +00:00
private :
int Save ( ) ;
int Load ( ) ;
int Enumerate ( ) ;
int Delete ( ) ;
int DeleteAll ( ) ;
int DeleteFiles ( ) ;
int EnumerateFiles ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
public :
saveGameThreadArgs_t data ;
volatile bool cancel ;
} ;
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
2012-11-28 15:47:07 +00:00
idSaveGameProcessor
2012-11-26 18:58:24 +00:00
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
class idSaveGameProcessor
{
2012-11-26 18:58:24 +00:00
friend class idSaveGameManager ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
public :
DEFINE_CLASS ( idSaveGameProcessor ) ;
static const int MAX_COMPLETED_CALLBACKS = 5 ;
2012-11-28 15:47:07 +00:00
idSaveGameProcessor ( ) ;
2012-11-26 18:58:24 +00:00
virtual ~ idSaveGameProcessor ( ) { }
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
//------------------------
// Virtuals
//------------------------
// Basic init
virtual bool Init ( ) ;
2012-11-28 15:47:07 +00:00
// This method should returns true if the processor has additional sub-states to
2012-11-26 18:58:24 +00:00
// manage. The saveGameManager will retain the current state and Process() will be called again. When this method
// returns false Process() will not be called again. For example, during save, you might want to load other files
// and save them somewhere else, return true until you are done with the entire state.
2012-11-28 15:47:07 +00:00
virtual bool Process ( )
{
return false ;
}
2012-11-26 18:58:24 +00:00
// Gives each processor to validate an error returned from the previous process call.
// This is useful when processors have a multi-stage Process() and expect some benign errors like
// deleting a savegame folder before copying into it.
2012-11-28 15:47:07 +00:00
virtual bool ValidateLastError ( )
{
return false ;
}
2012-11-26 18:58:24 +00:00
// Processors need to override this if they will eventually reset the map.
// If it could possibly reset the map through any of its stages, including kicking off another processor in completed callback, return false.
// We will force non-simple processors to execute last and won't block the map heap reset due if non-simple processors are still executing.
2012-11-28 15:47:07 +00:00
virtual bool IsSimpleProcessor ( ) const
{
return true ;
}
2012-11-26 18:58:24 +00:00
// This is a fail-safe to catch a timing issue on the PS3 where the nextmap processor could sometimes hang during a level transition
2012-11-28 15:47:07 +00:00
virtual bool ShouldTimeout ( ) const
{
return false ;
}
2012-11-26 18:58:24 +00:00
//------------------------
// Commands
//------------------------
// Cancels this processor in whatever state it's currently in and sets an error code for SAVEGAME_E_CANCELLED
2012-11-28 15:47:07 +00:00
void Cancel ( )
{
parms . cancelled = true ;
parms . errorCode = SAVEGAME_E_CANCELLED ;
}
2012-11-26 18:58:24 +00:00
//------------------------
// Accessors
//------------------------
// Returns error status
2012-11-28 15:47:07 +00:00
idSysSignal & GetSignal ( )
{
return parms . callbackSignal ;
}
2012-11-26 18:58:24 +00:00
// Returns error status
2012-11-28 15:47:07 +00:00
const int & GetError ( ) const
{
return parms . errorCode ;
}
2012-11-26 18:58:24 +00:00
// Returns the processor's save/load parms
2012-11-28 15:47:07 +00:00
const idSaveLoadParms & GetParms ( ) const
{
return parms ;
}
2012-11-26 18:58:24 +00:00
// Returns the processor's save/load parms
2012-11-28 15:47:07 +00:00
idSaveLoadParms & GetParmsNonConst ( )
{
return parms ;
}
2012-11-26 18:58:24 +00:00
// Returns if this processor is currently working
2012-11-28 15:47:07 +00:00
bool IsWorking ( ) const
{
return working ;
}
2012-11-26 18:58:24 +00:00
// This is a way to tell the processor which errors shouldn't be handled by the processor or system.
2012-11-28 15:47:07 +00:00
void SetSkipSystemErrorDialogMask ( const int errorMask )
{
parms . skipErrorDialogMask = errorMask ;
}
int GetSkipSystemErrorDialogMask ( ) const
{
return parms . skipErrorDialogMask ;
}
2012-11-26 18:58:24 +00:00
// Returns the handle given by execution
2012-11-28 15:47:07 +00:00
saveGameHandle_t GetHandle ( ) const
{
return parms . GetHandle ( ) ;
}
2012-11-26 18:58:24 +00:00
// These can be overridden by game code, like the GUI, when the processor is done executing.
// Game classes like the GUI can create a processor derived from a game's Save processor impl and simply use
// this method to know when everything is done. It eases the burden of constantly checking the working flag.
// This will be called back within the game thread during SaveGameManager::Pump().
2012-11-28 15:47:07 +00:00
void AddCompletedCallback ( const idCallback & callback ) ;
2012-11-26 18:58:24 +00:00
private :
// Returns whether or not the thread is finished operating, should only be called by the savegame manager
bool IsThreadFinished ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
protected :
idSaveLoadParms parms ;
int savegameLogicTestIterator ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
private :
2012-11-28 15:47:07 +00:00
bool init ;
2012-11-26 18:58:24 +00:00
bool working ;
2012-11-28 15:47:07 +00:00
idStaticList < idCallback * , MAX_COMPLETED_CALLBACKS > completedCallbacks ;
2012-11-26 18:58:24 +00:00
} ;
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
2012-11-28 15:47:07 +00:00
idSaveGameManager
2012-11-26 18:58:24 +00:00
Why all the object - oriented nonsense ?
- Savegames need to be processed asynchronously , saving / loading / deleting files should happen during the game frame
so there is a common way to update the render device .
- When executing commands , if no " strategy " s are used , the pump ( ) method would need to have a switch statement ,
extending the manager for other commands would mean modifying the manager itself for various commands .
By making it a strategy , we are able to create custom commands and define the behavior within game code and keep
the manager code in the engine static .
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
class idSaveGameManager
{
2012-11-26 18:58:24 +00:00
public :
2012-11-28 15:47:07 +00:00
enum packageType_t
{
2012-11-26 18:58:24 +00:00
PACKAGE_PROFILE ,
PACKAGE_GAME ,
PACKAGE_RAW ,
PACKAGE_NUM
} ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
const static int MAX_SAVEGAME_DIRECTORY_DEPTH = 5 ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
explicit idSaveGameManager ( ) ;
2012-11-28 15:47:07 +00:00
~ idSaveGameManager ( ) ;
2012-11-26 18:58:24 +00:00
// Called within main game thread
void Pump ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// Has the storage device been selected yet? This is only an issue on the 360, and primarily for development purposes
2012-11-28 15:47:07 +00:00
bool IsStorageAvailable ( ) const
{
return storageAvailable ;
}
void SetStorageAvailable ( const bool available )
{
storageAvailable = available ;
}
2012-11-26 18:58:24 +00:00
// Check to see if a processor is set within the manager
bool IsWorking ( ) const ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// Assign a processor to the manager. The processor should belong in game-side code
// This queues up processors and executes them serially
// Returns whether or not the processor is immediately executed
2012-11-28 15:47:07 +00:00
saveGameHandle_t ExecuteProcessor ( idSaveGameProcessor * processor ) ;
2012-11-26 18:58:24 +00:00
// Synchronous version, CompletedCallback is NOT called.
2012-11-28 15:47:07 +00:00
saveGameHandle_t ExecuteProcessorAndWait ( idSaveGameProcessor * processor ) ;
2012-11-26 18:58:24 +00:00
// Lets the currently processing queue finish, but clears the processor queue
void Clear ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
void WaitForAllProcessors ( bool overrideSimpleProcessorCheck = false ) ;
2012-11-28 15:47:07 +00:00
const bool IsCancelled ( ) const
{
return cancel ;
}
2012-11-26 18:58:24 +00:00
void CancelAllProcessors ( const bool forceCancelInFlightProcessor ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
void CancelToTerminate ( ) ;
2012-11-28 15:47:07 +00:00
idSaveGameThread & GetSaveGameThread ( )
{
return saveThread ;
}
bool IsSaveGameCompletedFromHandle ( const saveGameHandle_t & handle ) const
{
return handle < = lastExecutedProcessorHandle | | handle = = 0 ; // last case should never be reached since it would be also be true in first case, this is just to show intent
}
void Set360RetrySaveAfterDeviceSelected ( const char * folder , const int64 bytes ) ;
2012-11-26 18:58:24 +00:00
bool DeviceSelectorWaitingOnSaveRetry ( ) ;
2012-11-28 15:47:07 +00:00
void ShowRetySaveDialog ( const char * folder , const int64 bytes ) ;
2012-11-26 18:58:24 +00:00
void ShowRetySaveDialog ( ) ;
void ClearRetryInfo ( ) ;
void RetrySave ( ) ;
2012-11-28 15:47:07 +00:00
// This will cause the processor to cancel execution, the completion callback will be called
void CancelWithHandle ( const saveGameHandle_t & handle ) ;
const saveGameDetailsList_t & GetEnumeratedSavegames ( ) const
{
return enumeratedSaveGames ;
}
saveGameDetailsList_t & GetEnumeratedSavegamesNonConst ( )
{
return enumeratedSaveGames ;
}
2012-11-26 18:58:24 +00:00
private :
// These are to make sure that all processors start and finish in the same way without a lot of code duplication.
// We need to make sure that we adhere to PS3 system combination initialization issues.
void StartNextProcessor ( ) ;
2012-11-28 15:47:07 +00:00
void FinishProcessor ( idSaveGameProcessor * processor ) ;
2012-11-26 18:58:24 +00:00
// Calls start on the processor after it's been assigned
void Start ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
private :
2012-11-28 15:47:07 +00:00
idSaveGameProcessor * processor ;
idStaticList < idSaveGameProcessor * , 4 > processorQueue ;
2012-11-26 18:58:24 +00:00
bool cancel ;
idSaveGameThread saveThread ;
int startTime ;
bool continueProcessing ;
saveGameHandle_t submittedProcessorHandle ;
saveGameHandle_t executingProcessorHandle ;
saveGameHandle_t lastExecutedProcessorHandle ;
saveGameDetailsList_t enumeratedSaveGames ;
bool storageAvailable ; // On 360, this is false by default, after the storage device is selected
2012-11-28 15:47:07 +00:00
// it becomes true. This allows us to start the game without a storage device
// selected and pop the selector when necessary.
const char * retryFolder ;
2012-11-26 18:58:24 +00:00
int64 retryBytes ;
bool retrySave ;
idSysSignal deviceRequestedSignal ;
} ;
// Bridge between the session's APIs and the savegame thread
2012-11-28 15:47:07 +00:00
void Sys_ExecuteSavegameCommandAsync ( idSaveLoadParms * savegameParms ) ;
2012-11-26 18:58:24 +00:00
// Folder prefix should be NULL for everything except PS3
// Synchronous check, just checks if any savegame exists for master local user and if one is an autosave
2012-11-28 15:47:07 +00:00
void Sys_SaveGameCheck ( bool & exists , bool & autosaveExists ) ;
2012-11-26 18:58:24 +00:00
2012-11-28 15:47:07 +00:00
const idStr & GetSaveFolder ( idSaveGameManager : : packageType_t type ) ;
idStr AddSaveFolderPrefix ( const char * folder , idSaveGameManager : : packageType_t type ) ;
idStr RemoveSaveFolderPrefix ( const char * folder , idSaveGameManager : : packageType_t type ) ;
2012-11-26 18:58:24 +00:00
2012-11-28 15:47:07 +00:00
bool SavegameReadDetailsFromFile ( idFile * file , idSaveGameDetails & details ) ;
2012-11-26 18:58:24 +00:00
idStr GetSaveGameErrorString ( int errorMask ) ;
# endif // __SYS_SAVEGAME_H__