Files
GTASource/game/SaveLoad/savegame_list.cpp

1280 lines
46 KiB
C++
Raw Permalink Normal View History

2025-02-23 17:40:52 +08:00
#if __PPU
#include <cell/rtc.h>
#endif
// Game headers
#include "Core/game.h"
#include "SaveLoad/GenericGameStorage.h"
#include "SaveLoad/savegame_channel.h"
#include "savegame_damaged_check.h"
#include "SaveLoad/savegame_list.h"
#include "SaveLoad/savegame_load.h"
#include "SaveLoad/savegame_photo_local_list.h"
#include "SaveLoad/savegame_users_and_devices.h"
#include "SaveLoad/savegame_new_game_checks.h"
#include "Network/Live/NetworkTelemetry.h"
#include "Text/TextConversion.h"
SAVEGAME_OPTIMISATIONS()
fiSaveGame::Content CSavegameList::ms_SaveGameSlots[MAX_NUM_SAVE_FILES_TO_ENUMERATE];
s32 CSavegameList::ms_NumberOfSaveGameSlots;
CSavegameDisplayData CSavegameList::ms_SavegameDisplayData[MAX_NUM_SAVES_TO_SORT_INTO_SLOTS];
int CSavegameList::ms_EpisodeNumberForSaveToBeLoaded = INDEX_OF_FIRST_LEVEL;
#if RSG_ORBIS
fiSaveGame::Content CSavegameList::ms_EnumeratedPhotos[MAX_NUM_PHOTOS_TO_ENUMERATE];
#endif // RSG_ORBIS
#if RSG_ORBIS
bool CSavegameList::ms_bSaveGamesHaveAlreadyBeenScanned = false;
int CSavegameList::ms_SlotToUpdateOnceSaveHasCompleted = -1;
int CSavegameList::ms_SlotToUpdateOnceDeleteHasCompleted = -1;
#endif // RSG_ORBIS
#if RSG_ORBIS
CSavegameQueuedOperation_PS4DamagedCheck CSavegameList::ms_PS4DamagedCheck;
s32 CSavegameList::ms_NextSlotToScanForDamage = -1;
bool CSavegameList::ms_bBackgroundScanForDamagedSavegamesHasCompleted = false;
CSavegameQueuedOperation_CreateSortedListOfSavegames CSavegameList::ms_EnumerateSavegames;
#endif
void CSavegameDisplayData::Initialise()
{
m_FirstCharacterOfMissionName = 0;
m_LengthOfMissionName = 0;
m_EpisodeNumber = 0;
m_bIsDamaged = false;
m_bHasBeenCheckedForDamage = false;
for (int loop = 0; loop < MAX_LENGTH_SAVE_DATE_TIME; loop++)
{
m_SlotSaveTime[loop] = '\0';
}
m_SaveTime.Initialise();
}
// void CSavegameList::ClearThisSlot(int SlotIndex)
// {
// ms_SaveGameSlots[SlotIndex].DeviceId = 0;
// ms_SaveGameSlots[SlotIndex].ContentType = 0;
// ms_SaveGameSlots[SlotIndex].DisplayName[0] = '\0'; // _TCHAR
// ms_SaveGameSlots[SlotIndex].Filename[0] = '\0';
// }
#if RSG_ORBIS
bool CSavegameList::GetSaveGamesHaveAlreadyBeenScanned()
{
if (ShouldEnumeratePhotos())
{
if (CSavegamePhotoLocalList::GetListHasBeenCreated())
{
savegameDisplayf("CSavegameList::GetSaveGamesHaveAlreadyBeenScanned - list of local photos has already been created so return true");
return true;
}
}
else
{
if (ms_bSaveGamesHaveAlreadyBeenScanned)
{
savegameDisplayf("CSavegameList::GetSaveGamesHaveAlreadyBeenScanned - list of savegames has already been created so return true");
return true;
}
}
return false;
}
s32 CSavegameList::ConvertBackupSlotToSavegameSlot(s32 slotIndex)
{
if(slotIndex >= TOTAL_NUMBER_OF_SLOTS_FOR_SAVEGAMES)
return (slotIndex - INDEX_OF_BACKUPSAVE_SLOT);
else
return slotIndex;
}
#endif // RSG_ORBIS
void CSavegameList::ClearSlotData(void)
{
#if RSG_ORBIS
if (ShouldEnumeratePhotos())
{
if (CSavegamePhotoLocalList::GetListHasBeenCreated())
{
savegameDisplayf("CSavegameList::ClearSlotData - list of local photos has already been created so return immediately");
return;
}
for (u32 photoLoop = 0; photoLoop < MAX_NUM_PHOTOS_TO_ENUMERATE; photoLoop++)
{
ms_EnumeratedPhotos[photoLoop].Clear();
}
}
else
#endif // RSG_ORBIS
{
#if RSG_ORBIS
if (ms_bSaveGamesHaveAlreadyBeenScanned)
{
savegameDisplayf("CSavegameList::ClearSlotData - list of savegames has already been created so return immediately");
return;
}
#endif
int loop;
for (loop = 0; loop < MAX_NUM_SAVE_FILES_TO_ENUMERATE; loop++)
{
ms_SaveGameSlots[loop].Clear();
}
for (loop = 0; loop < MAX_NUM_SAVES_TO_SORT_INTO_SLOTS; loop++)
{
ms_SavegameDisplayData[loop].Initialise();
}
}
}
void CSavegameList::Init(unsigned initMode)
{
if(initMode == INIT_CORE)
{
// #if __PPU
// SAVEGAME.SetMaxNumberOfSaveGameFilesToEnumerate(MAX_NUM_SAVE_FILES_TO_ENUMERATE);
// #endif
#if RSG_ORBIS
ms_SlotToUpdateOnceSaveHasCompleted = -1;
ms_SlotToUpdateOnceDeleteHasCompleted = -1;
#endif // RSG_ORBIS
}
else if(initMode == INIT_AFTER_MAP_LOADED)
{
ms_NumberOfSaveGameSlots = 0;
ms_EpisodeNumberForSaveToBeLoaded = INDEX_OF_FIRST_LEVEL;
}
}
int CSavegameList::GetAutosaveSlotNumberForCurrentEpisode()
{
/*
s32 CurrentEpisode = CGameLogic::GetCurrentEpisodeIndex();
switch (CurrentEpisode)
{
case 1 :
return AUTOSAVE_SLOT_FOR_EPISODE_ONE;
break;
case 2 :
return AUTOSAVE_SLOT_FOR_EPISODE_TWO;
break;
}
*/
return AUTOSAVE_SLOT_FOR_EPISODE_ZERO;
}
// *********************************************************************************************
// FUNCTION: GetNameOfSavedGameForMenu()
//
// Description:
// *********************************************************************************************
const char* CSavegameList::GetNameOfSavedGameForMenu(int SlotNumber)
{
static char TempAsciiBuffer[SAVE_GAME_MAX_DISPLAY_NAME_LENGTH];
TempAsciiBuffer[0] = '\0';
if (savegameVerifyf( (SlotNumber >= 0) && (SlotNumber < MAX_NUM_SAVES_TO_SORT_INTO_SLOTS), "CSavegameList::GetNameOfSavedGameForMenu - slot number %d should be >= 0 and < %d", SlotNumber, MAX_NUM_SAVES_TO_SORT_INTO_SLOTS))
{
int FirstCharacter = ms_SavegameDisplayData[SlotNumber].m_FirstCharacterOfMissionName;
CSavegameFilenames::CopyWideStringToUtf8String(&ms_SaveGameSlots[SlotNumber].DisplayName[FirstCharacter], ms_SavegameDisplayData[SlotNumber].m_LengthOfMissionName, TempAsciiBuffer, NELEM(TempAsciiBuffer));
// episode = ms_EpisodeNumber[SlotNumber];
}
return TempAsciiBuffer;
}
bool CSavegameList::IsThisSaveGameSlotEmpty(fiSaveGame::Content &SaveGameSlot)
{
if (SaveGameSlot.Filename[0] == '\0')
{
Assertf(SaveGameSlot.ContentType == 0, "CSavegameList::IsThisSaveGameSlotEmpty - Filename is empty for this slot, expected ContentType to be 0 too");
Assertf(SaveGameSlot.DeviceId == 0, "CSavegameList::IsThisSaveGameSlotEmpty - Filename is empty for this slot, expected DeviceId to be 0 too");
Assertf(SaveGameSlot.DisplayName[0] == '\0', "CSavegameList::IsThisSaveGameSlotEmpty - Filename is empty for this slot, expected DisplayName to be empty too");
return true;
}
return false;
}
bool CSavegameList::IsSaveGameSlotEmpty(int SlotIndex)
{
if (savegameVerifyf((SlotIndex >= 0) && (SlotIndex < MAX_NUM_SAVES_TO_SORT_INTO_SLOTS), "CSavegameList::IsSaveGameSlotEmpty - slot index %d is out of range 0 to %d", SlotIndex, MAX_NUM_SAVES_TO_SORT_INTO_SLOTS) )
{
return IsThisSaveGameSlotEmpty(ms_SaveGameSlots[SlotIndex]);
}
return false;
}
bool CSavegameList::IsThisAnAutosaveSlot(int SlotIndex)
{
if (SlotIndex == AUTOSAVE_SLOT_FOR_EPISODE_ZERO)
{
return true;
}
// if (SlotIndex == AUTOSAVE_SLOT_FOR_EPISODE_ONE)
// {
// return true;
// }
// if (SlotIndex == AUTOSAVE_SLOT_FOR_EPISODE_TWO)
// {
// return true;
// }
return false;
}
#if !__NO_OUTPUT
void CSavegameList::PrintFilenames()
{
for (u32 loop = 0; loop < MAX_NUM_SAVE_FILES_TO_ENUMERATE; loop++)
{
if (strlen(ms_SaveGameSlots[loop].Filename) > 0)
{
savegameDisplayf("CSavegameList::PrintFilenames - slot %u contains %s\n", loop, ms_SaveGameSlots[loop].Filename);
}
}
}
#endif // !__NO_OUTPUT
#if RSG_ORBIS
bool CSavegameList::ShouldEnumeratePhotos()
{
switch (CGenericGameStorage::GetSaveOperation())
{
case OPERATION_NONE :
case OPERATION_SCANNING_CONSOLE_FOR_LOADING_SAVEGAMES : // Only set by CSavegameFrontEnd::SaveGameListScreenSetup - load menu
case OPERATION_SCANNING_CONSOLE_FOR_SAVING_SAVEGAMES : // Only set by CSavegameFrontEnd::SaveGameListScreenSetup - manual save menu
// case OPERATION_SCANNING_CLOUD_FOR_LOADING_PHOTOS : // Do I need to call CGenericGameStorage::SetSaveOperation()
// case OPERATION_SCANNING_CLOUD_FOR_SAVING_PHOTOS : // for these somewhere?
case OPERATION_LOADING_SAVEGAME_FROM_CONSOLE : // This also handles the autoloading of the most recent file found by CSavegameAutoload
case OPERATION_LOADING_REPLAY_SAVEGAME_FROM_CONSOLE :
case OPERATION_LOADING_MPSTATS_FROM_CLOUD :
case OPERATION_LOADING_PHOTO_FROM_CLOUD :
case OPERATION_SAVING_SAVEGAME_TO_CONSOLE :
case OPERATION_SAVING_MISSION_REPEAT_SAVEGAME_TO_CONSOLE :
case OPERATION_SAVING_REPLAY_SAVEGAME_TO_CONSOLE :
case OPERATION_AUTOSAVING :
case OPERATION_SAVING_MPSTATS_TO_CLOUD :
case OPERATION_SAVING_PHOTO_TO_CLOUD :
#if __ALLOW_CLOUD_UPLOAD_OF_LOCAL_SAVEGAME
case OPERATION_UPLOADING_SAVEGAME_TO_CLOUD :
#endif // __ALLOW_CLOUD_UPLOAD_OF_LOCAL_SAVEGAME
#if RSG_ORBIS
case OPERATION_CHECKING_FOR_FREE_SPACE_AT_START_OF_GAME :
#endif
case OPERATION_CHECKING_FOR_FREE_SPACE : // Only set by CSaveConfirmationMessage
case OPERATION_CHECKING_IF_FILE_EXISTS :
case OPERATION_DELETING_LOCAL :
case OPERATION_DELETING_CLOUD :
case OPERATION_ENUMERATING_SAVEGAMES :
#if __ALLOW_LOCAL_MP_STATS_SAVES
case OPERATION_SAVING_MPSTATS_SAVEGAME_TO_CONSOLE :
case OPERATION_LOADING_MPSTATS_SAVEGAME_FROM_CONSOLE :
#endif // __ALLOW_LOCAL_MP_STATS_SAVES
break;
case OPERATION_SAVING_LOCAL_PHOTO :
case OPERATION_LOADING_LOCAL_PHOTO :
case OPERATION_ENUMERATING_PHOTOS : // called by CSavegameQueuedOperation_CreateSortedListOfLocalPhotos
return true;
// break;
}
return false;
}
#endif // RSG_ORBIS
void CSavegameList::FillListOfLocalPhotos(fiSaveGame::Content *pArrayOfSaveGames, u32 sizeOfArray)
{
CSavegamePhotoLocalList::Init();
for (u32 loop = 0; loop < sizeOfArray; loop++)
{
if (CSavegameFilenames::IsThisTheNameOfAPhotoFile(pArrayOfSaveGames[loop].Filename))
{
s32 nUniqueId = CSavegameFilenames::GetPhotoUniqueIdFromFilename(pArrayOfSaveGames[loop].Filename);
if (nUniqueId != 0)
{
savegameDebugf1("CSavegameList::FillListOfLocalPhotos - adding %d to local photo list\n", nUniqueId);
CSavegamePhotoUniqueId uniqueId;
uniqueId.Set(nUniqueId, false);
CSavegamePhotoLocalList::Add(uniqueId);
// safecpy(pArrayOfSaveGames[loop].Filename, "", NELEM(pArrayOfSaveGames[loop].Filename));
}
}
}
CSavegamePhotoLocalList::SetListHasBeenCreated(true);
#if !__NO_OUTPUT
photoDisplayf("CSavegameList::FillListOfLocalPhotos - list of local photos is");
CSavegamePhotoLocalList::DisplayContentsOfList();
#endif // !__NO_OUTPUT
}
bool CSavegameList::SortSaveGameSlots()
{
#if RSG_ORBIS
if (ShouldEnumeratePhotos())
{
savegameAssertf(!CSavegamePhotoLocalList::GetListHasBeenCreated(), "CSavegameList::SortSaveGameSlots - don't expect to get back in here after the list of local photos has been created");
FillListOfLocalPhotos(ms_EnumeratedPhotos, MAX_NUM_PHOTOS_TO_ENUMERATE);
return true;
}
else
#endif // RSG_ORBIS
{
#if RSG_ORBIS
Assertf(!ms_bSaveGamesHaveAlreadyBeenScanned, "CSavegameList::SortSaveGameSlots - don't expect to get back in here after ms_bSaveGamesHaveAlreadyBeenScanned has been set");
#endif
return SortSaveGameSlotsAndSizes(ms_SaveGameSlots, NULL, ms_NumberOfSaveGameSlots);
}
}
bool CSavegameList::SortSaveGameSlotsAndSizes(fiSaveGame::Content *pArrayOfSaveGames, int *pArrayOfSaveGameSizes, int NumberOfValidSlots)
{
u32 loop, loop2;
if (NumberOfValidSlots > MAX_NUM_SAVE_FILES_TO_ENUMERATE)
{
CSavegameDialogScreens::SetSaveGameError(SAVE_GAME_DIALOG_TOO_MANY_SAVE_FILES_IN_FOLDER);
return false;
}
#if !RSG_ORBIS
// On PS4, we'll enumerate the local photos separately from the savegames
FillListOfLocalPhotos(pArrayOfSaveGames, MAX_NUM_SAVE_FILES_TO_ENUMERATE);
#endif // !RSG_ORBIS
fiSaveGame::Content TempSaveGameSlot;
int TempSaveGameSize;
char NameToSearchFor[SAVE_GAME_MAX_FILENAME_LENGTH_OF_LOCAL_FILE];
// arrange the save games into their correct slots according to Filename
// Only have to ensure that the first MAX_NUM_SAVES_TO_SORT_INTO_SLOTS slots are correct
for (loop = 0; loop < MAX_NUM_SAVES_TO_SORT_INTO_SLOTS; loop++)
{
bool bAlreadySwapped = false;
CSavegameFilenames::CreateNameOfLocalFile(NameToSearchFor, SAVE_GAME_MAX_FILENAME_LENGTH_OF_LOCAL_FILE, loop);
u32 LengthOfStringToSearchFor = ustrlen(NameToSearchFor);
for (loop2 = 0; loop2 < MAX_NUM_SAVE_FILES_TO_ENUMERATE; loop2++) // start loop2 at 0 as well to deal with situations where there is only one file (e.g. savegame7) and it's in slot 0
{
if ( (strlen(pArrayOfSaveGames[loop2].Filename) == LengthOfStringToSearchFor) && (strcmp(pArrayOfSaveGames[loop2].Filename, NameToSearchFor) == 0) )
{ // Found a match
if (bAlreadySwapped)
{
savegameDebugf1("CSavegameList::SortSaveGameSlotsAndSizes - two save game files with the same name %s\n", NameToSearchFor);
#if !__FINAL
for (int debug_slot_loop = 0; debug_slot_loop < MAX_NUM_SAVE_FILES_TO_ENUMERATE; debug_slot_loop++)
{
savegameDebugf1("CSavegameList::SortSaveGameSlotsAndSizes - slot %d contains %s\n", debug_slot_loop, pArrayOfSaveGames[debug_slot_loop].Filename);
}
#endif
CSavegameDialogScreens::SetSaveGameError(SAVE_GAME_DIALOG_TWO_SAVE_FILES_WITH_SAME_NAME);
return false;
}
bAlreadySwapped = true;
if (loop2 != loop)
{
TempSaveGameSlot = pArrayOfSaveGames[loop];
pArrayOfSaveGames[loop] = pArrayOfSaveGames[loop2];
pArrayOfSaveGames[loop2] = TempSaveGameSlot;
if (pArrayOfSaveGameSizes)
{
TempSaveGameSize = pArrayOfSaveGameSizes[loop];
pArrayOfSaveGameSizes[loop] = pArrayOfSaveGameSizes[loop2];
pArrayOfSaveGameSizes[loop2] = TempSaveGameSize;
}
}
}
}
if (!bAlreadySwapped)
{ // file doesn't exist at all so have to make sure that the corresponding slot is empty
// Will try swapping this slot with an empty slot in the range MAX_NUM_SAVES_TO_SORT_INTO_SLOTS to MAX_NUM_SAVE_FILES_TO_ENUMERATE
// If that causes problems then I'll try just clearing pArrayOfSaveGames[loop]
if (IsThisSaveGameSlotEmpty(pArrayOfSaveGames[loop]) == false)
{
bool bFoundAnEmptySlot = false;
loop2 = (MAX_NUM_SAVE_FILES_TO_ENUMERATE-1);
while ((loop2 >= MAX_NUM_SAVES_TO_SORT_INTO_SLOTS) && !bFoundAnEmptySlot)
{
if (IsThisSaveGameSlotEmpty(pArrayOfSaveGames[loop2]))
{
bFoundAnEmptySlot = true;
}
else
{
loop2--;
}
}
savegameAssertf(bFoundAnEmptySlot, "CSavegameList::SortSaveGameSlotsAndSizes - need to swap one of the first %d slots with an empty slot but there aren't any empty slots", MAX_NUM_SAVES_TO_SORT_INTO_SLOTS);
if (bFoundAnEmptySlot)
{
TempSaveGameSlot = pArrayOfSaveGames[loop];
pArrayOfSaveGames[loop] = pArrayOfSaveGames[loop2];
pArrayOfSaveGames[loop2] = TempSaveGameSlot;
if (pArrayOfSaveGameSizes)
{
TempSaveGameSize = pArrayOfSaveGameSizes[loop];
pArrayOfSaveGameSizes[loop] = pArrayOfSaveGameSizes[loop2];
pArrayOfSaveGameSizes[loop2] = TempSaveGameSize;
}
}
}
}
}
return true;
}
#if RSG_ORBIS
void CSavegameList::UpdateSlotDataAfterSave(u32 modificationTimeHigh, u32 modificationTimeLow, bool savingBackupSave)
{
int slotToUpdateOnceSaveHasCompleted = ms_SlotToUpdateOnceSaveHasCompleted;
if(savingBackupSave)
{
//make sure we get the correct slot numbers for the main save and the backup save
if(ms_SlotToUpdateOnceSaveHasCompleted < TOTAL_NUMBER_OF_SLOTS_FOR_SAVEGAMES)
slotToUpdateOnceSaveHasCompleted = ms_SlotToUpdateOnceSaveHasCompleted + INDEX_OF_BACKUPSAVE_SLOT;
}
if (savegameVerifyf((slotToUpdateOnceSaveHasCompleted >= 0) && (slotToUpdateOnceSaveHasCompleted < MAX_NUM_SAVES_TO_SORT_INTO_SLOTS), "CSavegameList::UpdateSlotDataAfterSave - slot index %d is out of range 0 to %d", slotToUpdateOnceSaveHasCompleted, MAX_NUM_SAVES_TO_SORT_INTO_SLOTS))
{
ms_SavegameDisplayData[slotToUpdateOnceSaveHasCompleted].m_bIsDamaged = false;
ms_SavegameDisplayData[slotToUpdateOnceSaveHasCompleted].m_bHasBeenCheckedForDamage = true;
Assertf( (sizeof(ms_SaveGameSlots[slotToUpdateOnceSaveHasCompleted].DisplayName) / sizeof(char16) ) == 128, "CSavegameList::UpdateSlotDataAfterSave - expected DisplayName of fiSaveGame::Content to be 128 characters long");
Assertf(SAVE_GAME_MAX_DISPLAY_NAME_LENGTH == 128, "CSavegameList::UpdateSlotDataAfterSave - expected SAVE_GAME_MAX_DISPLAY_NAME_LENGTH to be 128");
wcsncpy(ms_SaveGameSlots[slotToUpdateOnceSaveHasCompleted].DisplayName, CSavegameFilenames::GetNameToDisplay(), NELEM(ms_SaveGameSlots[slotToUpdateOnceSaveHasCompleted].DisplayName));
SetModificationTime(slotToUpdateOnceSaveHasCompleted, modificationTimeHigh, modificationTimeLow);
u64 fileTime;
GetModificationTime(slotToUpdateOnceSaveHasCompleted, fileTime);
time_t SaveTimeForThisSlot = static_cast<time_t>(fileTime);
ms_SavegameDisplayData[slotToUpdateOnceSaveHasCompleted].m_SlotSaveTime[0] = '\0';
if (ms_SavegameDisplayData[slotToUpdateOnceSaveHasCompleted].m_SaveTime.ExtractDateFromTimeT(SaveTimeForThisSlot))
{
ConstructStringFromDate(slotToUpdateOnceSaveHasCompleted);
}
savegameDisplayf("CSavegameList::UpdateSlotDataAfterSave - Timestamp of newly saved file is %s", CSavegameList::GetSlotSaveTimeString(slotToUpdateOnceSaveHasCompleted));
ExtractInfoFromDisplayName(slotToUpdateOnceSaveHasCompleted);
// strncpy(ms_SaveGameSlots[slotToUpdateOnceSaveHasCompleted].Filename, CSavegameFilenames::GetNameOfFileOnDisc(), SAVE_GAME_MAX_FILENAME_LENGTH);
if(!savingBackupSave)
safecpy(ms_SaveGameSlots[slotToUpdateOnceSaveHasCompleted].Filename, CSavegameFilenames::GetFilenameOfLocalFile(), NELEM(ms_SaveGameSlots[slotToUpdateOnceSaveHasCompleted].Filename));
else
safecpy(ms_SaveGameSlots[slotToUpdateOnceSaveHasCompleted].Filename, CSavegameFilenames::GetFilenameOfBackupSaveFile(), NELEM(ms_SaveGameSlots[slotToUpdateOnceSaveHasCompleted].Filename));
// ms_SaveGameSlots[ms_SlotToUpdateOnceSaveHasCompleted].DeviceId = 0; // I think this is always 0 on PS3
// ms_SaveGameSlots[ms_SlotToUpdateOnceSaveHasCompleted].ContentType = 0; // I think this is always 0 on PS3
// rage::fiDevice::SystemTime tm;
// rage::fiDevice::GetLocalSystemTime( tm );
// char temp[128];
// sprintf( temp, "%04d%02d%02d%02d%02d%02d", tm.wYear, tm.wMonth, tm.wDay, tm.wHour, tm.wMinute, tm.wSecond );
// savegameDisplayf("CSavegameList::UpdateSlotDataAfterSave - Current clock time is %s", temp);
// CellRtcDateTime CurrentRtcDateTime;
// time_t CurrentTimeT;
// cellRtcGetCurrentClock(&CurrentRtcDateTime, 0);
// cellRtcConvertDateTimeToTime_t(&CurrentRtcDateTime, &CurrentTimeT);
// ms_SavegameDisplayData[ms_SlotToUpdateOnceSaveHasCompleted].m_SlotSaveTime[0] = '\0';
// if (ms_SavegameDisplayData[ms_SlotToUpdateOnceSaveHasCompleted].m_SaveTime.ExtractDateFromTimeT(CurrentTimeT))
// {
// ConstructStringFromDate(ms_SlotToUpdateOnceSaveHasCompleted);
// }
// savegameDisplayf("CSavegameList::UpdateSlotDataAfterSave - Current clock time is %s", CSavegameList::GetSlotSaveTimeString(ms_SlotToUpdateOnceSaveHasCompleted));
}
}
void CSavegameList::UpdateSlotDataAfterDelete()
{
if (savegameVerifyf((ms_SlotToUpdateOnceDeleteHasCompleted >= 0) && (ms_SlotToUpdateOnceDeleteHasCompleted < MAX_NUM_SAVES_TO_SORT_INTO_SLOTS), "CSavegameList::UpdateSlotDataAfterDelete - slot index %d is out of range 0 to %d", ms_SlotToUpdateOnceDeleteHasCompleted, MAX_NUM_SAVES_TO_SORT_INTO_SLOTS))
{
savegameDisplayf("CSavegameList::UpdateSlotDataAfterDelete - clearing the data for slot %d", ms_SlotToUpdateOnceDeleteHasCompleted);
ms_SaveGameSlots[ms_SlotToUpdateOnceDeleteHasCompleted].Clear();
ms_SavegameDisplayData[ms_SlotToUpdateOnceDeleteHasCompleted].Initialise();
}
}
#endif // RSG_ORBIS
#if RSG_ORBIS
void CSavegameList::BackgroundScanForDamagedSavegames()
{
if (!ms_bBackgroundScanForDamagedSavegamesHasCompleted)
{
static bool s_bEnumerationHasBeenQueued = false;
if (!CSavegameNewGameChecks::ShouldNewGameChecksBePerformed() && !CNetwork::IsNetworkOpen() && !CNetwork::HasCalledFirstEntryOpen())
{ // Do I need to check this? When this returns False, I'm treating the new game checks as complete
if (!ms_bSaveGamesHaveAlreadyBeenScanned)
{
if (!s_bEnumerationHasBeenQueued)
{
if (ms_EnumerateSavegames.GetStatus() != MEM_CARD_BUSY)
{
ms_EnumerateSavegames.Init(false);
CGenericGameStorage::PushOnToSavegameQueue(&ms_EnumerateSavegames);
s_bEnumerationHasBeenQueued = true;
}
}
}
else
{ // Only check for damage after the files have been enumerated, sorted and their times have been read
if (ms_PS4DamagedCheck.GetStatus() != MEM_CARD_BUSY)
{
// Use TOTAL_NUMBER_OF_FILES_TO_SCAN_FOR_DAMAGE instead of MAX_NUM_SAVES_TO_SORT_INTO_SLOTS to save a bit of time.
// This will avoid checking the following three files for damage - the Profile, the Mission Repeat Save, the Replay Save
const s32 TOTAL_NUMBER_OF_FILES_TO_SCAN_FOR_DAMAGE = TOTAL_NUMBER_OF_SLOTS_FOR_SAVEGAMES + NUM_BACKUPSAVE_SLOTS;
bool bFoundASaveToScan = false;
ms_NextSlotToScanForDamage++;
while (!bFoundASaveToScan && (ms_NextSlotToScanForDamage < TOTAL_NUMBER_OF_FILES_TO_SCAN_FOR_DAMAGE) )
{
if (IsSaveGameSlotEmpty(ms_NextSlotToScanForDamage))
{
savegameDisplayf("CSavegameList::BackgroundScanForDamagedSavegames - slot %d is empty so don't scan it for damage", ms_NextSlotToScanForDamage);
}
else
{
eSavegameFileType fileTypeForThisSlot = FindSavegameFileTypeForThisSlot(ms_NextSlotToScanForDamage);
switch (fileTypeForThisSlot)
{
case SG_FILE_TYPE_SAVEGAME :
bFoundASaveToScan = true;
break;
case SG_FILE_TYPE_SAVEGAME_BACKUP :
{
s32 correspondingMainSaveSlot = ConvertBackupSlotToSavegameSlot(ms_NextSlotToScanForDamage);
#if USE_SAVE_DATA_MEMORY || USE_DOWNLOAD0_FOR_AUTOSAVE_BACKUP
if (IsThisAnAutosaveSlot(correspondingMainSaveSlot))
{ // When using Save Data Memory for the main autosave or Download0 for the backup autosave, we need to use the most recent of the main and backup
// so we always need to check if the backup is damaged even if the main is fine.
bFoundASaveToScan = true;
}
else
#endif // USE_SAVE_DATA_MEMORY || USE_DOWNLOAD0_FOR_AUTOSAVE_BACKUP
{
if (!IsSaveGameSlotEmpty(correspondingMainSaveSlot) && HasBeenCheckedForDamage(correspondingMainSaveSlot) && !GetIsDamaged(correspondingMainSaveSlot))
{
savegameDisplayf("CSavegameList::BackgroundScanForDamagedSavegames - the corresponding main save slot is not damaged so we don't need to check backup slot %d", ms_NextSlotToScanForDamage);
}
else
{
bFoundASaveToScan = true;
}
}
}
break;
default :
savegameAssertf(0, "CSavegameList::BackgroundScanForDamagedSavegames - filetype %d for slot %d not handled", (s32) fileTypeForThisSlot, ms_NextSlotToScanForDamage);
break;
}
}
if (!bFoundASaveToScan)
{
ms_NextSlotToScanForDamage++;
}
}
if (ms_NextSlotToScanForDamage == TOTAL_NUMBER_OF_FILES_TO_SCAN_FOR_DAMAGE)
{
ms_bBackgroundScanForDamagedSavegamesHasCompleted = true;
savegameDebugf1("CSavegameList::BackgroundScanForDamagedSavegames has finished. Time = %d\n",sysTimer::GetSystemMsTime());
}
else
{
//check whether we are in a good condition to issue this request
//if not roll back the last checked slot and continue
if( CGenericGameStorage::IsSafeToUseSaveLibrary())
{
eSavegameFileType fileTypeForThisSlot = FindSavegameFileTypeForThisSlot(ms_NextSlotToScanForDamage);
switch (fileTypeForThisSlot)
{
case SG_FILE_TYPE_SAVEGAME :
savegameDisplayf("CSavegameList::BackgroundScanForDamagedSavegames - slot %d is a main save slot. About to scan it for damage", ms_NextSlotToScanForDamage);
break;
case SG_FILE_TYPE_SAVEGAME_BACKUP :
savegameDisplayf("CSavegameList::BackgroundScanForDamagedSavegames - slot %d is a backup save slot. About to scan it for damage", ms_NextSlotToScanForDamage);
break;
default:
savegameDisplayf("CSavegameList::BackgroundScanForDamagedSavegames - slot %d is a ??? save slot. About to scan it for damage", ms_NextSlotToScanForDamage);
break;
}
ms_PS4DamagedCheck.Init(ms_NextSlotToScanForDamage);
CGenericGameStorage::PushOnToSavegameQueue(&ms_PS4DamagedCheck);
}
else
{
ms_NextSlotToScanForDamage--;
}
}
}
}
}
}
}
#endif // RSG_ORBIS
bool CSavegameList::BeginEnumeration()
{
#if RSG_ORBIS
if (ShouldEnumeratePhotos())
{
return SAVEGAME.BeginPhotoEnumeration(CSavegameUsers::GetUser(), CGenericGameStorage::GetContentType(), ms_EnumeratedPhotos, MAX_NUM_PHOTOS_TO_ENUMERATE);
}
else
#endif // RSG_ORBIS
{
#if __PPU
SAVEGAME.SetMaxNumberOfSaveGameFilesToEnumerate(MAX_NUM_SAVE_FILES_TO_ENUMERATE);
#endif
return SAVEGAME.BeginEnumeration(CSavegameUsers::GetUser(), CGenericGameStorage::GetContentType(), ms_SaveGameSlots, MAX_NUM_SAVE_FILES_TO_ENUMERATE);
}
}
bool CSavegameList::CheckEnumeration()
{
return SAVEGAME.CheckEnumeration(CSavegameUsers::GetUser(), ms_NumberOfSaveGameSlots);
}
#define __DO_DAMAGED_CHECKS_FOR_PHOTOS (0)
MemoryCardError CSavegameList::CheckIfSlotIsDamaged(int SlotIndex)
{
if ( (SlotIndex < 0) || (SlotIndex >= MAX_NUM_SAVES_TO_SORT_INTO_SLOTS) )
{
savegameAssertf(0, "CSavegameList::CheckIfSlotIsDamaged - slot index %d is out of range 0 to %d", SlotIndex, MAX_NUM_SAVES_TO_SORT_INTO_SLOTS);
return MEM_CARD_ERROR;
}
#if RSG_ORBIS
if (ms_SavegameDisplayData[SlotIndex].m_bHasBeenCheckedForDamage)
{
// Checking if a slot is damaged takes a long time on PS3
// If it's already been scanned once then I'll just assume that I can reuse the value of m_bIsDamaged
return MEM_CARD_COMPLETE;
}
#endif // RSG_ORBIS
MemoryCardError returnValue = CSavegameDamagedCheck::CheckIfSlotIsDamaged(ms_SaveGameSlots[SlotIndex].Filename, &ms_SavegameDisplayData[SlotIndex].m_bIsDamaged);
if (MEM_CARD_COMPLETE == returnValue)
{
ms_SavegameDisplayData[SlotIndex].m_bHasBeenCheckedForDamage = true;
}
return returnValue;
}
MemoryCardError CSavegameList::GetTimeAndMissionNameFromDisplayName(int SaveGameSlot)
{
// I'll try MAX_NUM_SAVES_TO_SORT_INTO_SLOTS here for now, but this function does expect the display name
// in a specific format that may only apply for savegames so I might have to change the assert to check
// TOTAL_NUMBER_OF_SLOTS_FOR_SAVEGAMES and avoid calling this function for other file types
savegameAssertf( (SaveGameSlot >= 0) && (SaveGameSlot < MAX_NUM_SAVES_TO_SORT_INTO_SLOTS), "CSavegameList::GetTimeAndMissionNameFromDisplayName - slot number %d should be between 0 and %d", SaveGameSlot, MAX_NUM_SAVES_TO_SORT_INTO_SLOTS);
ms_SavegameDisplayData[SaveGameSlot].m_SlotSaveTime[0] = '\0';
ms_SavegameDisplayData[SaveGameSlot].m_EpisodeNumber = 0;
ms_SavegameDisplayData[SaveGameSlot].m_FirstCharacterOfMissionName = 0;
ms_SavegameDisplayData[SaveGameSlot].m_LengthOfMissionName = 0;
// What about these two?
// static time_t ms_PS3SaveTimes[MAX_NUM_SAVE_GAMES_TO_DISPLAY];
// static bool ms_bIsDamaged[MAX_NUM_SAVE_GAMES_TO_DISPLAY];
if (!IsSaveGameSlotEmpty(SaveGameSlot))
{
#if __DEV
static char TempAsciiBuffer[128];
CSavegameFilenames::CopyWideStringToUtf8String(ms_SaveGameSlots[SaveGameSlot].DisplayName, (int)wcslen(ms_SaveGameSlots[SaveGameSlot].DisplayName), TempAsciiBuffer, NELEM(TempAsciiBuffer));
savegameDebugf3("CSavegameList::GetTimeAndMissionNameFromDisplayName - slot %d has name %s\n", SaveGameSlot, TempAsciiBuffer);
#endif
savegameDebugf3("CSavegameList::GetTimeAndMissionNameFromDisplayName - slot %d has file name %s\n", SaveGameSlot, ms_SaveGameSlots[SaveGameSlot].Filename);
#if RSG_ORBIS
u64 fileTime;
GetModificationTime(SaveGameSlot, fileTime);
time_t SaveTimeForThisSlot = static_cast<time_t>(fileTime);
if (ms_SavegameDisplayData[SaveGameSlot].m_SaveTime.ExtractDateFromTimeT(SaveTimeForThisSlot))
{
ConstructStringFromDate(SaveGameSlot);
}
#endif
ExtractInfoFromDisplayName(SaveGameSlot);
#if !RSG_ORBIS
ms_SavegameDisplayData[SaveGameSlot].m_SaveTime.ExtractDateFromString(GetSlotSaveTimeString(SaveGameSlot));
#endif
savegameDebugf3("CSavegameList::GetTimeAndMissionNameFromDisplayName - slot %d saved at %s\n", SaveGameSlot, GetSlotSaveTimeString(SaveGameSlot));
}
return MEM_CARD_COMPLETE;
}
void CSavegameList::ResetFileTimeScan()
{
#if RSG_ORBIS
if (ShouldEnumeratePhotos())
{
savegameDisplayf("CSavegameList::ResetFileTimeScan - enumerating photos so return immediately");
return;
}
else
#endif // RSG_ORBIS
{
#if RSG_ORBIS
if (ms_bSaveGamesHaveAlreadyBeenScanned)
{
return;
}
#endif
// Make sure this doesn't happen half-way through the load
ms_EpisodeNumberForSaveToBeLoaded = INDEX_OF_FIRST_LEVEL;
// establish the default episode for this disc - if no suitable autoload is found then boot into this episode
// ms_EpisodeNumberForSaveToBeLoaded = EXTRACONTENT.GetDiscDefaultEpisode();
// if (EXTRACONTENT.GetIsDLCFromDisc_())
// {
// if (ms_AutoLoadEpisodeForDiscBuild != -1)
// {
// ms_EpisodeNumberForSaveToBeLoaded = ms_AutoLoadEpisodeForDiscBuild;
// }
// }
for (int loop = 0; loop < MAX_NUM_SAVES_TO_SORT_INTO_SLOTS; loop++)
{
ms_SavegameDisplayData[loop].m_SaveTime.Initialise();
}
}
}
MemoryCardError CSavegameList::GetFileTimes()
{
#if RSG_ORBIS
if (ShouldEnumeratePhotos())
{
savegameDisplayf("CSavegameList::GetFileTimes - enumerating photos so return immediately");
return MEM_CARD_COMPLETE;
}
#endif // RSG_ORBIS
s32 CurrentSlotForGetFileTime = 0;
#if RSG_ORBIS
if (ms_bSaveGamesHaveAlreadyBeenScanned)
{
// Rather than get the file times for all the slots again (which takes a long time on PS3),
// we'll try just using the existing values in ms_PS3SaveTimes
return MEM_CARD_COMPLETE;
}
#endif
// I used to call CheckIfSlotIsDamaged (on 360 anyway) before calling GetTimeAndMissionNameFromDisplayName
// I've removed the damaged check from here to speed up the time to display the Load/Save menus
// Hopefully the time can still be read from damaged saves
// The damaged check will now need to be done where necessary at some point after GetFileTimes()
// Graeme 21.09.12 - I'm going to try getting the date for photos too. This is so that the save photo routine knows which is the oldest photo for overwriting
// I'll also have to save the date and time in the photo's display name on 360
CurrentSlotForGetFileTime = 0;
while (CurrentSlotForGetFileTime < MAX_NUM_SAVES_TO_SORT_INTO_SLOTS)
{ // Get the file times for all saves
if (!IsSaveGameSlotEmpty(CurrentSlotForGetFileTime))
{
savegameAssertf(!CSavegameFilenames::IsThisTheNameOfAPhotoFile(ms_SaveGameSlots[CurrentSlotForGetFileTime].Filename), "CSavegameList::GetFileTimes - didn't expect to find any photos in this function");
if ( (CSavegameFilenames::IsThisTheNameOfASavegameFile(ms_SaveGameSlots[CurrentSlotForGetFileTime].Filename))
#if RSG_ORBIS
|| (CSavegameFilenames::IsThisTheNameOfABackupSavegameFile(ms_SaveGameSlots[CurrentSlotForGetFileTime].Filename))
#endif
// || (CSavegameFilenames::IsThisTheNameOfAPhotoFile(ms_SaveGameSlots[CurrentSlotForGetFileTime].Filename))
)
{ // Ignore any file that does not begin with the save game or photo prefix
MemoryCardError FileTimeReadStatus = GetTimeAndMissionNameFromDisplayName(CurrentSlotForGetFileTime);
if (FileTimeReadStatus == MEM_CARD_ERROR)
{
return MEM_CARD_ERROR;
}
else if (FileTimeReadStatus == MEM_CARD_BUSY)
{
savegameAssertf(0, "CSavegameList::GetFileTimes - didn't expect GetTimeAndMissionNameFromDisplayName to return MEM_CARD_BUSY");
}
}
}
CurrentSlotForGetFileTime++;
}
#if RSG_ORBIS
// By this stage, the slots will have been sorted and all the times will have been grabbed.
// Normally we'll get here through the SlowPS3Scan but if the slow scan has been
// switched off then we'll get here when the save/load menu is first displayed.
ms_bSaveGamesHaveAlreadyBeenScanned = true;
#endif
return MEM_CARD_COMPLETE;
}
MemoryCardError CSavegameList::BeginGameLoad(int SlotNumber)
{
if (!savegameVerifyf(CGenericGameStorage::GetSaveOperation() == OPERATION_NONE, "CSavegameList::BeginGameLoad - SaveOperation is not OPERATION_NONE"))
{
return MEM_CARD_ERROR;
}
if (savegameVerifyf(CSavegameLoad::GetLoadStatus() == GENERIC_LOAD_DO_NOTHING, "CSavegameList::BeginGameLoad - expected LoadStatus to be GENERIC_LOAD_DO_NOTHING"))
{
CSavegameFilenames::MakeValidSaveNameForLocalFile(SlotNumber);
CSavegameLoad::BeginLoad(SAVEGAME_SINGLE_PLAYER);
CNetworkTelemetry::LoadGame();
}
return MEM_CARD_COMPLETE;
}
#if __ALLOW_EXPORT_OF_SP_SAVEGAMES
MemoryCardError CSavegameList::BeginGameLoadForExport(int SlotNumber)
{
if (!savegameVerifyf(CGenericGameStorage::GetSaveOperation() == OPERATION_NONE, "CSavegameList::BeginGameLoadForExport - SaveOperation is not OPERATION_NONE"))
{
return MEM_CARD_ERROR;
}
if (savegameVerifyf(CSavegameLoad::GetLoadStatus() == GENERIC_LOAD_DO_NOTHING, "CSavegameList::BeginGameLoadForExport - expected LoadStatus to be GENERIC_LOAD_DO_NOTHING"))
{
CSavegameFilenames::MakeValidSaveNameForLocalFile(SlotNumber);
CSavegameLoad::BeginLoadForExport();
}
return MEM_CARD_COMPLETE;
}
#endif // __ALLOW_EXPORT_OF_SP_SAVEGAMES
void CSavegameList::SetEpisodeNumberForTheSaveGameToBeLoadedToThisSlot(int SlotNumber)
{
// This shouldn't be called for photos, MP stats or PS3 profiles so use so check in range 0 to TOTAL_NUMBER_OF_SLOTS_FOR_SAVEGAMES
#if RSG_ORBIS
if (savegameVerifyf((SlotNumber >= 0) && (SlotNumber < TOTAL_NUMBER_OF_SLOTS_FOR_SAVEGAMES+NUM_BACKUPSAVE_SLOTS), "CSavegameList::SetEpisodeNumberForTheSaveGameToBeLoadedToThisSlot - SlotNumber %d is out of range 0 to %d", SlotNumber, TOTAL_NUMBER_OF_SLOTS_FOR_SAVEGAMES+NUM_BACKUPSAVE_SLOTS))
#else
if (savegameVerifyf((SlotNumber >= 0) && (SlotNumber < TOTAL_NUMBER_OF_SLOTS_FOR_SAVEGAMES), "CSavegameList::SetEpisodeNumberForTheSaveGameToBeLoadedToThisSlot - SlotNumber %d is out of range 0 to %d", SlotNumber, TOTAL_NUMBER_OF_SLOTS_FOR_SAVEGAMES))
#endif
{
ms_EpisodeNumberForSaveToBeLoaded = ms_SavegameDisplayData[SlotNumber].m_EpisodeNumber;
}
}
// *************** Access functions for ms_SaveGameSlots ***************************************
#if RSG_ORBIS
void CSavegameList::GetModificationTime(int SlotIndex, u64 &ModificationTime)
{
if (Verifyf((SlotIndex >= 0) && (SlotIndex < MAX_NUM_SAVE_FILES_TO_ENUMERATE), "CSavegameList::GetModificationTime - slot index is out of range"))
{
ModificationTime = static_cast<u64>(ms_SaveGameSlots[SlotIndex].ModificationTimeHigh) << 32;
ModificationTime += static_cast<u64>(ms_SaveGameSlots[SlotIndex].ModificationTimeLow);
}
else
{
ModificationTime = 0;
}
}
void CSavegameList::SetModificationTime(int SlotIndex, u32 modificationTimeHigh, u32 modificationTimeLow)
{
if (Verifyf((SlotIndex >= 0) && (SlotIndex < MAX_NUM_SAVE_FILES_TO_ENUMERATE), "CSavegameList::SetModificationTime - slot index is out of range"))
{
ms_SaveGameSlots[SlotIndex].ModificationTimeHigh = modificationTimeHigh;
ms_SaveGameSlots[SlotIndex].ModificationTimeLow = modificationTimeLow;
}
}
#endif // RSG_ORBIS
s32 CSavegameList::FindFreeManualSaveSlot()
{
for (s32 slot_index = 0; slot_index < NUM_MANUAL_SAVE_SLOTS; slot_index++)
{
if (IsSaveGameSlotEmpty(slot_index))
{
return slot_index;
}
}
return -1;
}
// CSavegameList::FindMostRecentSavegame
//
// I've based this on CSavegameAutoload::GetFileTimes()
// CSavegameAutoload::GetFileTimes() ignores backup autosaves if the main autosave doesn't exist.
// It also never attempts to load backup manual saves. I can't remember if there was a good reason for that.
// The backup manual saves are stored in the normal savegame folder. (Only the backup of the autosave is stored in download0).
// So the player could delete a main manual save through the PS4 UI but leave its backup.
// For now, I won't consider backup manual saves.
//
// CSavegameFrontEnd::CreateListSortedByDate() does consider backup manual saves if the main manual save doesn't exist.
s32 CSavegameList::FindMostRecentSavegame()
{
s32 mostRecentSlot = -1;
CDate dateOfMostRecentSlot;
for (s32 loop = 0; loop < MAX_NUM_SAVES_TO_SORT_INTO_SLOTS; loop++)
{
if (!IsSaveGameSlotEmpty(loop))
{
// if (!GetIsDamaged(loop)) // Unfortunately, I can't check this here as there's no guarantee that the saves have all been checked for damage at this stage
{
savegameAssertf(!CSavegameFilenames::IsThisTheNameOfAPhotoFile(ms_SaveGameSlots[loop].Filename), "CSavegameList::FindMostRecentSavegame - didn't expect to find any photos in this function");
bool bCheckTheDateOfThisSave = false;
if (CSavegameFilenames::IsThisTheNameOfASavegameFile(ms_SaveGameSlots[loop].Filename))
{
bCheckTheDateOfThisSave = true;
}
#if USE_DOWNLOAD0_FOR_AUTOSAVE_BACKUP
else if (CSavegameFilenames::IsThisTheNameOfAnAutosaveBackupFile(ms_SaveGameSlots[loop].Filename))
{
s32 indexOfCorrespondingMainAutosave = CSavegameList::ConvertBackupSlotToSavegameSlot(loop);
if (savegameVerifyf( (indexOfCorrespondingMainAutosave >= 0) && (indexOfCorrespondingMainAutosave < MAX_NUM_SAVES_TO_SORT_INTO_SLOTS), "CSavegameList::FindMostRecentSavegame - ConvertBackupSlotToSavegameSlot returned %d. Expected it to be between 0 and %d", indexOfCorrespondingMainAutosave, MAX_NUM_SAVES_TO_SORT_INTO_SLOTS))
{
if (!IsSaveGameSlotEmpty(indexOfCorrespondingMainAutosave))
{
if (savegameVerifyf(CSavegameFilenames::IsThisTheNameOfAnAutosaveFile(ms_SaveGameSlots[indexOfCorrespondingMainAutosave].Filename), "CSavegameList::FindMostRecentSavegame - slot %d is not an autosave", indexOfCorrespondingMainAutosave))
{
bCheckTheDateOfThisSave = true; // We'll only check the date of a backup autosave if the corresponding main autosave exists
}
}
}
}
#endif // USE_DOWNLOAD0_FOR_AUTOSAVE_BACKUP
if (bCheckTheDateOfThisSave)
{
if (GetSaveTime(loop) > dateOfMostRecentSlot)
{
dateOfMostRecentSlot = GetSaveTime(loop);
mostRecentSlot = loop;
}
}
}
}
}
return mostRecentSlot;
}
eSavegameFileType CSavegameList::FindSavegameFileTypeForThisSlot(s32 SlotIndex)
{
if (SlotIndex >= 0)
{
#if RSG_ORBIS
if (SlotIndex < INDEX_OF_BACKUPSAVE_SLOT)
#elif __ALLOW_LOCAL_MP_STATS_SAVES
if (SlotIndex < INDEX_OF_FIRST_MULTIPLAYER_STATS_SAVE_SLOT)
#else
if (SlotIndex < INDEX_OF_MISSION_REPEAT_SAVE_SLOT)
#endif
{
return SG_FILE_TYPE_SAVEGAME;
}
#if RSG_ORBIS
else if (SlotIndex < (INDEX_OF_BACKUPSAVE_SLOT + NUM_BACKUPSAVE_SLOTS) )
{
return SG_FILE_TYPE_SAVEGAME_BACKUP;
}
#endif
#if __ALLOW_LOCAL_MP_STATS_SAVES
else if (SlotIndex < INDEX_OF_MISSION_REPEAT_SAVE_SLOT)
{
return SG_FILE_TYPE_MULTIPLAYER_STATS;
}
#endif // __ALLOW_LOCAL_MP_STATS_SAVES
else if (SlotIndex < (INDEX_OF_MISSION_REPEAT_SAVE_SLOT + NUM_MISSION_REPEAT_SAVE_SLOTS) )
{
return SG_FILE_TYPE_MISSION_REPEAT;
}
#if GTA_REPLAY
else if (SlotIndex < (INDEX_OF_REPLAYSAVE_SLOT + NUM_REPLAYSAVE_SLOTS) )
{
return SG_FILE_TYPE_REPLAY;
}
#endif // GTA_REPLAY
#if USE_PROFILE_SAVEGAME
else if (SlotIndex < (INDEX_OF_PS3_PROFILE_SLOT + NUM_PS3_PROFILE_SLOTS) )
{ // PS3 Profile - there should only be one of these
return SG_FILE_TYPE_PS3_PROFILE;
}
#if USE_DOWNLOAD0_FOR_PROFILE_BACKUP
else if (SlotIndex < (INDEX_OF_BACKUP_PROFILE_SLOT + NUM_BACKUP_PROFILE_SLOTS) )
{ // Backup Profile - there should only be one of these
return SG_FILE_TYPE_BACKUP_PROFILE;
}
#endif // USE_DOWNLOAD0_FOR_PROFILE_BACKUP
#endif // USE_PROFILE_SAVEGAME
else if (SlotIndex < (INDEX_OF_FIRST_LOCAL_PHOTO + NUMBER_OF_LOCAL_PHOTOS) )
{
return SG_FILE_TYPE_LOCAL_PHOTO;
}
}
savegameAssertf(0, "CSavegameList::FindSavegameFileTypeForThisSlot - SlotIndex %d is out of range 0 to %d", SlotIndex, MAX_NUM_EXPECTED_SAVE_FILES);
return SG_FILE_TYPE_UNKNOWN;
}
s32 CSavegameList::GetBaseIndexForSavegameFileType(eSavegameFileType FileType)
{
switch (FileType)
{
case SG_FILE_TYPE_UNKNOWN :
savegameAssertf(0, "CSavegameList::GetBaseIndexForSavegameFileType - didn't expect SG_FILE_TYPE_UNKNOWN to ever occur");
return -1;
// break;
case SG_FILE_TYPE_SAVEGAME :
return 0;
// break;
#if RSG_ORBIS
case SG_FILE_TYPE_SAVEGAME_BACKUP :
return INDEX_OF_BACKUPSAVE_SLOT;
// break;
#endif
#if __ALLOW_LOCAL_MP_STATS_SAVES
case SG_FILE_TYPE_MULTIPLAYER_STATS :
return INDEX_OF_FIRST_MULTIPLAYER_STATS_SAVE_SLOT;
// break;
#endif // __ALLOW_LOCAL_MP_STATS_SAVES
case SG_FILE_TYPE_MISSION_REPEAT : // Used by Andrew Minghella
return INDEX_OF_MISSION_REPEAT_SAVE_SLOT;
// break;
#if GTA_REPLAY
case SG_FILE_TYPE_REPLAY :
return INDEX_OF_REPLAYSAVE_SLOT;
// break;
#endif // GTA_REPLAY
#if USE_PROFILE_SAVEGAME
case SG_FILE_TYPE_PS3_PROFILE :
return INDEX_OF_PS3_PROFILE_SLOT;
// break;
#if USE_DOWNLOAD0_FOR_PROFILE_BACKUP
case SG_FILE_TYPE_BACKUP_PROFILE :
return INDEX_OF_BACKUP_PROFILE_SLOT;
// break;
#endif // USE_DOWNLOAD0_FOR_PROFILE_BACKUP
#endif // USE_PROFILE_SAVEGAME
case SG_FILE_TYPE_LOCAL_PHOTO :
return INDEX_OF_FIRST_LOCAL_PHOTO;
// break;
}
return -1;
}
// *************** End of Access functions for ms_SaveGameSlots ********************************
// *************** Access functions for ms_SavegameDisplayData ***************************************
void CSavegameList::ConstructStringFromDate(int SlotIndex)
{
if (savegameVerifyf((SlotIndex >= 0) && (SlotIndex < MAX_NUM_SAVES_TO_SORT_INTO_SLOTS), "CSavegameList::ConstructStringFromDate - slot index %d is out of range 0 to %d", SlotIndex, MAX_NUM_SAVES_TO_SORT_INTO_SLOTS))
{
ms_SavegameDisplayData[SlotIndex].m_SaveTime.ConstructStringFromDate(&ms_SavegameDisplayData[SlotIndex].m_SlotSaveTime[0], MAX_LENGTH_SAVE_DATE_TIME);
}
}
void CSavegameList::ExtractInfoFromDisplayName(int SlotIndex)
{
if (savegameVerifyf((SlotIndex >= 0) && (SlotIndex < MAX_NUM_SAVES_TO_SORT_INTO_SLOTS), "CSavegameList::ExtractInfoFromDisplayName - slot index %d is out of range 0 to %d", SlotIndex, MAX_NUM_SAVES_TO_SORT_INTO_SLOTS))
{
CSavegameFilenames::ExtractInfoFromDisplayName(&ms_SaveGameSlots[SlotIndex].DisplayName[0], &ms_SavegameDisplayData[SlotIndex].m_EpisodeNumber,
#if RSG_ORBIS
NULL,
#else
&ms_SavegameDisplayData[SlotIndex].m_SlotSaveTime[0],
#endif
&ms_SavegameDisplayData[SlotIndex].m_FirstCharacterOfMissionName, &ms_SavegameDisplayData[SlotIndex].m_LengthOfMissionName);
}
}
const char* CSavegameList::GetSlotSaveTimeString(int SlotIndex)
{
if (savegameVerifyf((SlotIndex >= 0) && (SlotIndex < MAX_NUM_SAVES_TO_SORT_INTO_SLOTS), "CSavegameList::GetSlotSaveTimeString - slot index %d is out of range 0 to %d", SlotIndex, MAX_NUM_SAVES_TO_SORT_INTO_SLOTS))
{
Assertf(!ms_SavegameDisplayData[SlotIndex].m_bIsDamaged, "CSavegameList::GetSlotSaveTimeString - attempting to get the time and date of a damaged slot");
return &(ms_SavegameDisplayData[SlotIndex].m_SlotSaveTime[0]);
}
return NULL;
}
bool CSavegameList::GetIsDamaged(int SlotIndex)
{
if (savegameVerifyf((SlotIndex >= 0) && (SlotIndex < MAX_NUM_SAVES_TO_SORT_INTO_SLOTS), "CSavegameList::GetIsDamaged - slot index %d is out of range 0 to %d", SlotIndex, MAX_NUM_SAVES_TO_SORT_INTO_SLOTS))
{
savegameAssertf(ms_SavegameDisplayData[SlotIndex].m_bHasBeenCheckedForDamage, "CSavegameList::GetIsDamaged - this should only be called after CheckIfSlotIsDamaged has been called - Graeme");
return ms_SavegameDisplayData[SlotIndex].m_bIsDamaged;
}
return true;
}
#if RSG_ORBIS
bool CSavegameList::HasBeenCheckedForDamage(int SlotIndex)
{
if (savegameVerifyf((SlotIndex >= 0) && (SlotIndex < MAX_NUM_SAVES_TO_SORT_INTO_SLOTS), "CSavegameList::HasBeenCheckedForDamage - slot index %d is out of range 0 to %d", SlotIndex, MAX_NUM_SAVES_TO_SORT_INTO_SLOTS))
{
return ms_SavegameDisplayData[SlotIndex].m_bHasBeenCheckedForDamage;
}
return false;
}
#endif // __PPU
CDate &CSavegameList::GetSaveTime(s32 SlotIndex)
{
if (savegameVerifyf((SlotIndex >= 0) && (SlotIndex < MAX_NUM_SAVES_TO_SORT_INTO_SLOTS), "CSavegameList::GetSaveTime - slot index %d is out of range 0 to %d", SlotIndex, MAX_NUM_SAVES_TO_SORT_INTO_SLOTS))
{
return ms_SavegameDisplayData[SlotIndex].m_SaveTime;
}
static CDate InvalidDate;
InvalidDate.Initialise();
return InvalidDate;
}
void CSavegameList::GetDisplayNameAndDateForThisSaveGameItem(s32 SlotIndex, char *pNameToFillIn, char *pDateToFillIn, bool *pbReturnSlotIsEmpty, bool *pbReturnSlotIsDamaged)
{
if (pbReturnSlotIsEmpty)
{
*pbReturnSlotIsEmpty = true;
}
else
{
Assertf(0, "CSavegameList::GetDisplayNameAndDateForThisSaveGameItem - you need to pass this function a pointer to a bool to hold SlotIsEmpty");
return;
}
if (pbReturnSlotIsDamaged)
{
*pbReturnSlotIsDamaged = false;
}
else
{
Assertf(0, "CSavegameList::GetDisplayNameAndDateForThisSaveGameItem - you need to pass this function a pointer to a bool to hold SlotIsDamaged");
return;
}
if (!pNameToFillIn)
{
Assertf(0, "CSavegameList::GetDisplayNameAndDateForThisSaveGameItem - you need to pass this function a pointer to a string to hold the name");
return;
}
if (!pDateToFillIn)
{
Assertf(0, "CSavegameList::GetDisplayNameAndDateForThisSaveGameItem - you need to pass this function a pointer to a string to hold the date");
return;
}
if (!IsSaveGameSlotEmpty(SlotIndex)) // check if valid data in slot:
{
if (GetIsDamaged(SlotIndex))
{
*pbReturnSlotIsEmpty = false;
*pbReturnSlotIsDamaged = true;
}
else
{
strcpy(pDateToFillIn, GetSlotSaveTimeString(SlotIndex));
Displayf("Save Game %d saved at %s\n", SlotIndex, pDateToFillIn);
// Remove the seconds from the time/date
int LengthOfSaveGameDate = istrlen(pDateToFillIn);
Assertf( (LengthOfSaveGameDate == 0) || (LengthOfSaveGameDate == 17), "CSavegameList::GetDisplayNameAndDateForThisSaveGameItem - expected string containing date to be 17 characters long");
if (LengthOfSaveGameDate == 17)
{
if (pDateToFillIn[14] == ':')
{
pDateToFillIn[14] = '\0';
}
else
{
Assertf(0, "CSavegameList::GetDisplayNameAndDateForThisSaveGameItem - expected a : followed by two digits at the end of the date/time string");
}
}
strcpy(pNameToFillIn, GetNameOfSavedGameForMenu(SlotIndex));
*pbReturnSlotIsEmpty = false;
}
}
}
// *************** End of Access functions for ms_SavegameDisplayData ********************************