sys_savegame.h 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484
  1. /*
  2. ===========================================================================
  3. Doom 3 BFG Edition GPL Source Code
  4. Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
  5. This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
  6. Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation, either version 3 of the License, or
  9. (at your option) any later version.
  10. Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. GNU General Public License for more details.
  14. You should have received a copy of the GNU General Public License
  15. along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
  16. 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.
  17. 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.
  18. ===========================================================================
  19. */
  20. #ifndef __SYS_SAVEGAME_H__
  21. #define __SYS_SAVEGAME_H__
  22. #ifdef OUTPUT_FUNC
  23. #undef OUTPUT_FUNC
  24. #endif
  25. #ifdef OUTPUT_FUNC_EXIT
  26. #undef OUTPUT_FUNC_EXIT
  27. #endif
  28. #define OUTPUT_FUNC() idLib::PrintfIf( saveGame_verbose.GetBool(), "[%s] Enter\n", __FUNCTION__ )
  29. #define OUTPUT_FUNC_EXIT() idLib::PrintfIf( saveGame_verbose.GetBool(), "[%s] Exit\n", __FUNCTION__ )
  30. #define DEFINE_CLASS( x ) virtual const char * Name() const { return #x; }
  31. #define MAX_SAVEGAMES 16
  32. #define MAX_FILES_WITHIN_SAVEGAME 10
  33. #define MIN_SAVEGAME_SIZE_BYTES ( 4 * 1024 * 1024 )
  34. #define MAX_SAVEGAME_STRING_TABLE_SIZE 400 * 1024 // 400 kB max string table size
  35. #define MAX_FILENAME_LENGTH 255
  36. #define MAX_FILENAME_LENGTH_PATTERN 8
  37. #define MAX_FOLDER_NAME_LENGTH 64
  38. #define SAVEGAME_DETAILS_FILENAME "game.details"
  39. // PS3 restrictions: The only characters that can be used are 0-9 (numbers), A-Z (uppercase alphabet), "_" (underscore), and "-" (hyphen)
  40. #define SAVEGAME_AUTOSAVE_FOLDER "AUTOSAVE" // auto save slot
  41. // common descriptors for savegame description fields
  42. #define SAVEGAME_DETAIL_FIELD_EXPANSION "expansion"
  43. #define SAVEGAME_DETAIL_FIELD_MAP "mapName"
  44. #define SAVEGAME_DETAIL_FIELD_MAP_LOCATE "mapLocation"
  45. #define SAVEGAME_DETAIL_FIELD_DIFFICULTY "difficulty"
  46. #define SAVEGAME_DETAIL_FIELD_PLAYTIME "playTime"
  47. #define SAVEGAME_DETAIL_FIELD_LANGUAGE "language"
  48. #define SAVEGAME_DETAIL_FIELD_SAVE_VERSION "saveVersion"
  49. #define SAVEGAME_DETAIL_FIELD_CHECKSUM "checksum"
  50. #define SAVEGAME_GAME_DIRECTORY_PREFIX "GAME-"
  51. #define SAVEGAME_PROFILE_DIRECTORY_PREFIX ""
  52. #define SAVEGAME_RAW_DIRECTORY_PREFIX ""
  53. extern idCVar saveGame_verbose;
  54. extern idCVar saveGame_enable;
  55. class idGameSpawnInfo;
  56. class idSession;
  57. class idSessionLocal;
  58. class idSaveGameManager;
  59. // Specific savegame sub-system errors
  60. enum saveGameError_t {
  61. SAVEGAME_E_NONE = 0,
  62. SAVEGAME_E_CANCELLED = BIT( 0 ),
  63. SAVEGAME_E_INSUFFICIENT_ROOM = BIT( 1 ),
  64. SAVEGAME_E_CORRUPTED = BIT( 2 ),
  65. SAVEGAME_E_UNABLE_TO_SELECT_STORAGE_DEVICE = BIT( 3 ),
  66. SAVEGAME_E_UNKNOWN = BIT( 4 ),
  67. SAVEGAME_E_INVALID_FILENAME = BIT( 5 ),
  68. SAVEGAME_E_STEAM_ERROR = BIT( 6 ),
  69. SAVEGAME_E_FOLDER_NOT_FOUND = BIT( 7 ),
  70. SAVEGAME_E_FILE_NOT_FOUND = BIT( 8 ),
  71. SAVEGAME_E_DLC_NOT_FOUND = BIT( 9 ),
  72. SAVEGAME_E_INVALID_USER = BIT( 10 ),
  73. SAVEGAME_E_PROFILE_TOO_BIG = BIT( 11 ),
  74. SAVEGAME_E_DISC_SWAP = BIT( 12 ),
  75. SAVEGAME_E_INCOMPATIBLE_NEWER_VERSION = BIT( 13 ),
  76. SAVEGAME_E_BITS_USED = 14,
  77. SAVEGAME_E_NUM = SAVEGAME_E_BITS_USED + 1 // because we're counting "none"
  78. };
  79. // Modes to control behavior of savegame manager
  80. enum saveGameModeBitfield_t {
  81. SAVEGAME_MBF_NONE = 0,
  82. SAVEGAME_MBF_LOAD = BIT( 0 ), // standard file load (can be individual/multiple files described in parms)
  83. SAVEGAME_MBF_SAVE = BIT( 1 ), // standard file save (can be individual/multiple files described in parms)
  84. SAVEGAME_MBF_DELETE_FOLDER = BIT( 2 ), // standard package delete
  85. SAVEGAME_MBF_DELETE_ALL_FOLDERS = BIT( 3 ), // deletes all of the savegame folders (should only be used in testing)
  86. SAVEGAME_MBF_ENUMERATE = BIT( 4 ), // gets listing of all savegame folders, typically used with READ_DETAILS to read the description file
  87. SAVEGAME_MBF_NO_COMPRESS = BIT( 5 ), // tells the system the files aren't compressed, usually only needed when reading the descriptors file internally
  88. 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)
  89. SAVEGAME_MBF_DELETE_FILES = BIT( 7 ), // deletes individual files within a particular savegame folder (can be individual/multiple files or pattern described in parms)
  90. SAVEGAME_MBF_READ_DETAILS = BIT( 8 ), // reads the description file (if specified, parms.enumeratedEntry.name & parms.enumeratedEntry.type must be specified)
  91. SAVEGAME_MBF_KEEP_FOLDER = BIT( 9 ) // don't delete the folder before saving
  92. };
  93. typedef interlockedInt_t saveGameHandle_t;
  94. typedef int savegameUserId_t; // [internal] hash of gamer tag for steam
  95. /*
  96. ================================================
  97. saveGameCheck_t
  98. ================================================
  99. */
  100. struct saveGameCheck_t {
  101. saveGameCheck_t() {
  102. exists = false;
  103. autosaveExists = false;
  104. autosaveFolder = NULL;
  105. }
  106. bool exists;
  107. bool autosaveExists;
  108. const char * autosaveFolder;
  109. };
  110. /*
  111. ================================================
  112. idSaveGameDetails
  113. ================================================
  114. */
  115. class idSaveGameDetails {
  116. public:
  117. idSaveGameDetails();
  118. ~idSaveGameDetails() { Clear(); }
  119. void Clear();
  120. bool operator==( const idSaveGameDetails & other ) const { return ( idStr::Icmp( slotName, other.slotName ) == 0 ); }
  121. idSaveGameDetails & operator=( const idSaveGameDetails &other ) {
  122. descriptors.Clear();
  123. descriptors = other.descriptors;
  124. damaged = other.damaged;
  125. date = other.date;
  126. slotName = other.slotName;
  127. return *this;
  128. }
  129. // for std::sort, sort newer (larger date) towards start of list
  130. bool operator<( const idSaveGameDetails & other ) { return date > other.date; }
  131. idStr GetMapName() const { return descriptors.GetString( SAVEGAME_DETAIL_FIELD_MAP, "" ); }
  132. idStr GetLocation() const { return descriptors.GetString( SAVEGAME_DETAIL_FIELD_MAP_LOCATE, "" ); }
  133. idStr GetLanguage() const { return descriptors.GetString( SAVEGAME_DETAIL_FIELD_LANGUAGE, "" ); }
  134. int GetPlaytime() const { return descriptors.GetInt( SAVEGAME_DETAIL_FIELD_PLAYTIME, 0 ); }
  135. int GetExpansion() const { return descriptors.GetInt( SAVEGAME_DETAIL_FIELD_EXPANSION, 0 ); }
  136. int GetDifficulty() const { return descriptors.GetInt( SAVEGAME_DETAIL_FIELD_DIFFICULTY, -1 ); }
  137. int GetSaveVersion() const { return descriptors.GetInt( SAVEGAME_DETAIL_FIELD_SAVE_VERSION, 0 ); }
  138. public:
  139. 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.
  140. bool damaged; // [out]
  141. time_t date; // [out] read from the filesystem, not set by client
  142. idStrStatic< MAX_FOLDER_NAME_LENGTH > slotName; // [out] folder/slot name, e.g. AUTOSAVE
  143. };
  144. typedef idStaticList< idSaveGameDetails, MAX_SAVEGAMES > saveGameDetailsList_t;
  145. // Making a auto_ptr to handle lifetime issues better
  146. typedef idList< idFile_SaveGame *, TAG_SAVEGAMES > saveFileEntryList_t;
  147. /*
  148. ================================================
  149. idSaveLoadParms
  150. ================================================
  151. */
  152. class idSaveLoadParms {
  153. public:
  154. idSaveLoadParms();
  155. ~idSaveLoadParms();
  156. void ResetCancelled();
  157. void Init();
  158. void SetDefaults( int inputDevice = -1 ); // doesn't clear out things that should be persistent across entire processor
  159. void CancelSaveGameFilePipelines();
  160. void AbortSaveGameFilePipeline();
  161. const int & GetError() const { return errorCode; }
  162. const int & GetHandledErrors() const { return handledErrorCodes; }
  163. const saveGameHandle_t & GetHandle() const { return handle; }
  164. public:
  165. idStrStatic< MAX_FOLDER_NAME_LENGTH > directory; // [in] real directory of the savegame package
  166. idStrStatic< MAX_FILENAME_LENGTH_PATTERN > pattern; // [in] pattern to use while enumerating/deleting files within a savegame folder
  167. idStrStatic< MAX_FILENAME_LENGTH_PATTERN > postPattern; // [in] pattern at the end of the file to use while enumerating/deleting files within a savegame folder
  168. int mode; // [in] SAVE, LOAD, ENUM, DELETE, etc.
  169. 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
  170. 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
  171. saveGameDetailsList_t detailList; // [out] listing of the enumerated savegames used only with SAVEGAME_MBF_ENUMERATE
  172. int errorCode; // [out] combination of saveGameError_t bits
  173. int handledErrorCodes; // [out] combination of saveGameError_t bits
  174. int64 requiredSpaceInBytes; // [out] when fails for insufficient space, this is populated with additional space required
  175. int skipErrorDialogMask;
  176. // ----------------------
  177. // Internal vars
  178. // ----------------------
  179. idSysSignal callbackSignal; // [internal] used to signal savegame manager that the Process() call is completed (we still might have more Process() calls to make though...)
  180. 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.
  181. savegameUserId_t userId; // [internal] to get the proper user during every step
  182. int inputDeviceId; // [internal] consoles will use this to segregate each player's files
  183. saveGameHandle_t handle;
  184. private:
  185. // Don't allow copies
  186. idSaveLoadParms( const idSaveLoadParms & s ) {}
  187. void operator=( const idSaveLoadParms & s ) {}
  188. };
  189. // Using function pointers because:
  190. // 1. CompletedCallback methods in processors weren't generic enough, we could use SaveFiles processors
  191. // for profiles/games, but there would be a single completed callback and we'd have to update
  192. // the callback to detect what type of call it was, store the type in the processor, etc.
  193. // 2. Using a functor class would require us to define classes for each callback. The definition of those
  194. // classes could be scattered and a little difficult to follow
  195. // 3. With callback methods, we assign them when needed and know exactly where they are defined/declared.
  196. //typedef void (*saveGameProcessorCallback_t)( idSaveLoadParms & parms );
  197. /*
  198. ================================================
  199. saveGameThreadArgs_t
  200. ================================================
  201. */
  202. struct saveGameThreadArgs_t {
  203. saveGameThreadArgs_t() :
  204. saveLoadParms( NULL ) {
  205. }
  206. idSaveLoadParms * saveLoadParms;
  207. };
  208. /*
  209. ================================================
  210. idSaveGameThread
  211. ================================================
  212. */
  213. class idSaveGameThread : public idSysThread {
  214. public:
  215. idSaveGameThread() : cancel( false ) {}
  216. int Run();
  217. void CancelOperations() { cancel = true; }
  218. private:
  219. int Save();
  220. int Load();
  221. int Enumerate();
  222. int Delete();
  223. int DeleteAll();
  224. int DeleteFiles();
  225. int EnumerateFiles();
  226. public:
  227. saveGameThreadArgs_t data;
  228. volatile bool cancel;
  229. };
  230. /*
  231. ================================================
  232. idSaveGameProcessor
  233. ================================================
  234. */
  235. class idSaveGameProcessor {
  236. friend class idSaveGameManager;
  237. public:
  238. DEFINE_CLASS( idSaveGameProcessor );
  239. static const int MAX_COMPLETED_CALLBACKS = 5;
  240. idSaveGameProcessor();
  241. virtual ~idSaveGameProcessor() { }
  242. //------------------------
  243. // Virtuals
  244. //------------------------
  245. // Basic init
  246. virtual bool Init();
  247. // This method should returns true if the processor has additional sub-states to
  248. // manage. The saveGameManager will retain the current state and Process() will be called again. When this method
  249. // returns false Process() will not be called again. For example, during save, you might want to load other files
  250. // and save them somewhere else, return true until you are done with the entire state.
  251. virtual bool Process() { return false; }
  252. // Gives each processor to validate an error returned from the previous process call.
  253. // This is useful when processors have a multi-stage Process() and expect some benign errors like
  254. // deleting a savegame folder before copying into it.
  255. virtual bool ValidateLastError() { return false; }
  256. // Processors need to override this if they will eventually reset the map.
  257. // If it could possibly reset the map through any of its stages, including kicking off another processor in completed callback, return false.
  258. // 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.
  259. virtual bool IsSimpleProcessor() const { return true; }
  260. // This is a fail-safe to catch a timing issue on the PS3 where the nextmap processor could sometimes hang during a level transition
  261. virtual bool ShouldTimeout() const { return false; }
  262. //------------------------
  263. // Commands
  264. //------------------------
  265. // Cancels this processor in whatever state it's currently in and sets an error code for SAVEGAME_E_CANCELLED
  266. void Cancel() { parms.cancelled = true; parms.errorCode = SAVEGAME_E_CANCELLED; }
  267. //------------------------
  268. // Accessors
  269. //------------------------
  270. // Returns error status
  271. idSysSignal & GetSignal() { return parms.callbackSignal; }
  272. // Returns error status
  273. const int & GetError() const { return parms.errorCode; }
  274. // Returns the processor's save/load parms
  275. const idSaveLoadParms & GetParms() const { return parms; }
  276. // Returns the processor's save/load parms
  277. idSaveLoadParms & GetParmsNonConst() { return parms; }
  278. // Returns if this processor is currently working
  279. bool IsWorking() const { return working; }
  280. // This is a way to tell the processor which errors shouldn't be handled by the processor or system.
  281. void SetSkipSystemErrorDialogMask( const int errorMask ) { parms.skipErrorDialogMask = errorMask; }
  282. int GetSkipSystemErrorDialogMask() const { return parms.skipErrorDialogMask; }
  283. // Returns the handle given by execution
  284. saveGameHandle_t GetHandle() const { return parms.GetHandle(); }
  285. // These can be overridden by game code, like the GUI, when the processor is done executing.
  286. // Game classes like the GUI can create a processor derived from a game's Save processor impl and simply use
  287. // this method to know when everything is done. It eases the burden of constantly checking the working flag.
  288. // This will be called back within the game thread during SaveGameManager::Pump().
  289. void AddCompletedCallback( const idCallback & callback );
  290. private:
  291. // Returns whether or not the thread is finished operating, should only be called by the savegame manager
  292. bool IsThreadFinished();
  293. protected:
  294. idSaveLoadParms parms;
  295. int savegameLogicTestIterator;
  296. private:
  297. bool init;
  298. bool working;
  299. idStaticList< idCallback *, MAX_COMPLETED_CALLBACKS > completedCallbacks;
  300. };
  301. /*
  302. ================================================
  303. idSaveGameManager
  304. Why all the object-oriented nonsense?
  305. - Savegames need to be processed asynchronously, saving/loading/deleting files should happen during the game frame
  306. so there is a common way to update the render device.
  307. - When executing commands, if no "strategy"s are used, the pump() method would need to have a switch statement,
  308. extending the manager for other commands would mean modifying the manager itself for various commands.
  309. By making it a strategy, we are able to create custom commands and define the behavior within game code and keep
  310. the manager code in the engine static.
  311. ================================================
  312. */
  313. class idSaveGameManager {
  314. public:
  315. enum packageType_t {
  316. PACKAGE_PROFILE,
  317. PACKAGE_GAME,
  318. PACKAGE_RAW,
  319. PACKAGE_NUM
  320. };
  321. const static int MAX_SAVEGAME_DIRECTORY_DEPTH = 5;
  322. explicit idSaveGameManager();
  323. ~idSaveGameManager();
  324. // Called within main game thread
  325. void Pump();
  326. // Has the storage device been selected yet? This is only an issue on the 360, and primarily for development purposes
  327. bool IsStorageAvailable() const { return storageAvailable; }
  328. void SetStorageAvailable( const bool available ) { storageAvailable = available; }
  329. // Check to see if a processor is set within the manager
  330. bool IsWorking() const;
  331. // Assign a processor to the manager. The processor should belong in game-side code
  332. // This queues up processors and executes them serially
  333. // Returns whether or not the processor is immediately executed
  334. saveGameHandle_t ExecuteProcessor( idSaveGameProcessor * processor );
  335. // Synchronous version, CompletedCallback is NOT called.
  336. saveGameHandle_t ExecuteProcessorAndWait( idSaveGameProcessor * processor );
  337. // Lets the currently processing queue finish, but clears the processor queue
  338. void Clear();
  339. void WaitForAllProcessors( bool overrideSimpleProcessorCheck = false );
  340. const bool IsCancelled() const { return cancel; }
  341. void CancelAllProcessors( const bool forceCancelInFlightProcessor );
  342. void CancelToTerminate();
  343. idSaveGameThread & GetSaveGameThread() { return saveThread; }
  344. 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
  345. void Set360RetrySaveAfterDeviceSelected( const char * folder, const int64 bytes );
  346. bool DeviceSelectorWaitingOnSaveRetry();
  347. void ShowRetySaveDialog( const char * folder, const int64 bytes );
  348. void ShowRetySaveDialog();
  349. void ClearRetryInfo();
  350. void RetrySave();
  351. // This will cause the processor to cancel execution, the completion callback will be called
  352. void CancelWithHandle( const saveGameHandle_t & handle );
  353. const saveGameDetailsList_t & GetEnumeratedSavegames() const { return enumeratedSaveGames; }
  354. saveGameDetailsList_t & GetEnumeratedSavegamesNonConst() { return enumeratedSaveGames; }
  355. private:
  356. // These are to make sure that all processors start and finish in the same way without a lot of code duplication.
  357. // We need to make sure that we adhere to PS3 system combination initialization issues.
  358. void StartNextProcessor();
  359. void FinishProcessor( idSaveGameProcessor * processor );
  360. // Calls start on the processor after it's been assigned
  361. void Start();
  362. private:
  363. idSaveGameProcessor * processor;
  364. idStaticList< idSaveGameProcessor *, 4 > processorQueue;
  365. bool cancel;
  366. idSaveGameThread saveThread;
  367. int startTime;
  368. bool continueProcessing;
  369. saveGameHandle_t submittedProcessorHandle;
  370. saveGameHandle_t executingProcessorHandle;
  371. saveGameHandle_t lastExecutedProcessorHandle;
  372. saveGameDetailsList_t enumeratedSaveGames;
  373. bool storageAvailable; // On 360, this is false by default, after the storage device is selected
  374. // it becomes true. This allows us to start the game without a storage device
  375. // selected and pop the selector when necessary.
  376. const char * retryFolder;
  377. int64 retryBytes;
  378. bool retrySave;
  379. idSysSignal deviceRequestedSignal;
  380. };
  381. // Bridge between the session's APIs and the savegame thread
  382. void Sys_ExecuteSavegameCommandAsync( idSaveLoadParms * savegameParms );
  383. // Folder prefix should be NULL for everything except PS3
  384. // Synchronous check, just checks if any savegame exists for master local user and if one is an autosave
  385. void Sys_SaveGameCheck( bool & exists, bool & autosaveExists );
  386. const idStr & GetSaveFolder( idSaveGameManager::packageType_t type );
  387. idStr AddSaveFolderPrefix( const char * folder, idSaveGameManager::packageType_t type );
  388. idStr RemoveSaveFolderPrefix( const char * folder, idSaveGameManager::packageType_t type );
  389. bool SavegameReadDetailsFromFile( idFile * file, idSaveGameDetails & details );
  390. idStr GetSaveGameErrorString( int errorMask );
  391. #endif // __SYS_SAVEGAME_H__