#include "stdafx.h" #include "UI.h" #include "UIScene_InGameSaveManagementMenu.h" #if defined(__ORBIS__) || defined(__PSVITA__) #include #endif int UIScene_InGameSaveManagementMenu::LoadSaveDataThumbnailReturned(LPVOID lpParam,PBYTE pbThumbnail,DWORD dwThumbnailBytes) { UIScene_InGameSaveManagementMenu *pClass= static_cast(lpParam); app.DebugPrintf("Received data for save thumbnail\n"); if(pbThumbnail && dwThumbnailBytes) { pClass->m_saveDetails[pClass->m_iRequestingThumbnailId].pbThumbnailData = new BYTE[dwThumbnailBytes]; memcpy(pClass->m_saveDetails[pClass->m_iRequestingThumbnailId].pbThumbnailData, pbThumbnail, dwThumbnailBytes); pClass->m_saveDetails[pClass->m_iRequestingThumbnailId].dwThumbnailSize = dwThumbnailBytes; } else { pClass->m_saveDetails[pClass->m_iRequestingThumbnailId].pbThumbnailData = nullptr; pClass->m_saveDetails[pClass->m_iRequestingThumbnailId].dwThumbnailSize = 0; app.DebugPrintf("Save thumbnail data is nullptr, or has size 0\n"); } pClass->m_bSaveThumbnailReady = true; return 0; } UIScene_InGameSaveManagementMenu::UIScene_InGameSaveManagementMenu(int iPad, void *initData, UILayer *parentLayer) : UIScene(iPad, parentLayer) { // Setup all the Iggy references we need for this scene initialiseMovie(); m_iRequestingThumbnailId = 0; m_iSaveInfoC=0; m_bIgnoreInput = false; m_iState=e_SavesIdle; //m_bRetrievingSaveInfo=false; m_buttonListSaves.init(eControl_SavesList); m_labelSavesListTitle.init( app.GetString(IDS_SAVE_INCOMPLETE_DELETE_SAVES) ); m_controlSavesTimer.setVisible( true ); #if defined(_XBOX_ONE) || defined(__ORBIS__) m_spaceIndicatorSaves.init(L"",eControl_SpaceIndicator,0, (4LL *1024LL * 1024LL * 1024LL) ); #endif m_bUpdateSaveSize = false; m_bAllLoaded = false; m_bRetrievingSaveThumbnails = false; m_bSaveThumbnailReady = false; m_bExitScene=false; m_pSaveDetails=nullptr; m_bSavesDisplayed=false; m_saveDetails = nullptr; m_iSaveDetailsCount = 0; #if defined(__PS3__) || defined(__ORBIS__) || defined(__PSVITA__) || defined(_DURANGO) // Always clear the saves when we enter this menu StorageManager.ClearSavesInfo(); #endif // block input if we're waiting for DLC to install, and wipe the saves list. The end of dlc mounting custom message will fill the list again if(app.StartInstallDLCProcess(m_iPad)==true || app.DLCInstallPending()) { // if we're waiting for DLC to mount, don't fill the save list. The custom message on end of dlc mounting will do that m_bIgnoreInput = true; } else { Initialise(); } #ifdef __PSVITA__ if(CGameNetworkManager::usingAdhocMode() && SQRNetworkManager_AdHoc_Vita::GetAdhocStatus()) { g_NetworkManager.startAdhocMatching(); // create the client matching context and clear out the friends list } #endif // If we're not ignoring input, then we aren't still waiting for the DLC to mount, and can now check for corrupt dlc. Otherwise this will happen when the dlc has finished mounting. if( !m_bIgnoreInput) { app.m_dlcManager.checkForCorruptDLCAndAlert(); } parentLayer->addComponent(iPad,eUIComponent_MenuBackground); } UIScene_InGameSaveManagementMenu::~UIScene_InGameSaveManagementMenu() { m_parentLayer->removeComponent(eUIComponent_MenuBackground); if(m_saveDetails) { for(int i = 0; i < m_iSaveDetailsCount; ++i) { delete m_saveDetails[i].pbThumbnailData; } delete [] m_saveDetails; } app.LeaveSaveNotificationSection(); StorageManager.SetSaveDisabled(false); StorageManager.ContinueIncompleteOperation(); } void UIScene_InGameSaveManagementMenu::updateTooltips() { int iA = -1; if( m_bSavesDisplayed && m_iSaveDetailsCount > 0) { iA = IDS_TOOLTIPS_DELETESAVE; } ui.SetTooltips( m_parentLayer->IsFullscreenGroup()?XUSER_INDEX_ANY:m_iPad, iA, IDS_SAVE_INCOMPLETE_RETRY_SAVING); } // void UIScene_InGameSaveManagementMenu::Initialise() { m_iSaveListIndex = 0; // Check if we're in the trial version if(ProfileManager.IsFullVersion()==false) { } else if(StorageManager.GetSaveDisabled()) { GetSaveInfo(); } else { // 4J-PB - we need to check that there is enough space left to create a copy of the save (for a rename) bool bCanRename = StorageManager.EnoughSpaceForAMinSaveGame(); GetSaveInfo(); } m_bIgnoreInput=false; } void UIScene_InGameSaveManagementMenu::handleReload() { m_bIgnoreInput = false; m_iRequestingThumbnailId = 0; m_bAllLoaded=false; m_bRetrievingSaveThumbnails=false; m_bSavesDisplayed=false; m_iSaveInfoC=0; } void UIScene_InGameSaveManagementMenu::handleGainFocus(bool navBack) { UIScene::handleGainFocus(navBack); updateTooltips(); if(navBack) { // re-enable button presses m_bIgnoreInput=false; } } wstring UIScene_InGameSaveManagementMenu::getMoviePath() { return L"SaveMenu"; } void UIScene_InGameSaveManagementMenu::tick() { UIScene::tick(); if(m_bExitScene) // navigate forward or back { if(!m_bRetrievingSaveThumbnails) { // need to wait for any callback retrieving thumbnail to complete navigateBack(); } } // Stop loading thumbnails if we navigate forwards if(hasFocus(m_iPad)) { if(m_bUpdateSaveSize) { m_spaceIndicatorSaves.selectSave(m_iSaveListIndex); m_bUpdateSaveSize = false; } // Display the saves if we have them if(!m_bSavesDisplayed) { m_pSaveDetails=StorageManager.ReturnSavesInfo(); if(m_pSaveDetails!=nullptr) { m_spaceIndicatorSaves.reset(); m_bSavesDisplayed=true; if(m_saveDetails!=nullptr) { for(unsigned int i = 0; i < m_pSaveDetails->iSaveC; ++i) { if(m_saveDetails[i].pbThumbnailData!=nullptr) { delete m_saveDetails[i].pbThumbnailData; } } delete m_saveDetails; } m_saveDetails = new SaveListDetails[m_pSaveDetails->iSaveC]; m_iSaveDetailsCount = m_pSaveDetails->iSaveC; for(unsigned int i = 0; i < m_pSaveDetails->iSaveC; ++i) { #if defined(_XBOX_ONE) m_spaceIndicatorSaves.addSave( m_pSaveDetails->SaveInfoA[i].totalSize ); #elif defined(__ORBIS__) m_spaceIndicatorSaves.addSave( m_pSaveDetails->SaveInfoA[i].blocksUsed * (32 * 1024) ); #endif #ifdef _DURANGO m_buttonListSaves.addItem(m_pSaveDetails->SaveInfoA[i].UTF16SaveTitle, L""); m_saveDetails[i].saveId = i; memcpy(m_saveDetails[i].UTF16SaveName, m_pSaveDetails->SaveInfoA[i].UTF16SaveTitle, 128); memcpy(m_saveDetails[i].UTF16SaveFilename, m_pSaveDetails->SaveInfoA[i].UTF16SaveFilename, MAX_SAVEFILENAME_LENGTH); #else m_buttonListSaves.addItem(m_pSaveDetails->SaveInfoA[i].UTF8SaveTitle, L""); m_saveDetails[i].saveId = i; memcpy(m_saveDetails[i].UTF8SaveName, m_pSaveDetails->SaveInfoA[i].UTF8SaveTitle, 128); memcpy(m_saveDetails[i].UTF8SaveFilename, m_pSaveDetails->SaveInfoA[i].UTF8SaveFilename, MAX_SAVEFILENAME_LENGTH); #endif } m_controlSavesTimer.setVisible( false ); // set focus on the first button } } if(!m_bExitScene && m_bSavesDisplayed && !m_bRetrievingSaveThumbnails && !m_bAllLoaded) { if( m_iRequestingThumbnailId < (m_buttonListSaves.getItemCount() )) { m_bRetrievingSaveThumbnails = true; app.DebugPrintf("Requesting the first thumbnail\n"); // set the save to load PSAVE_DETAILS pSaveDetails=StorageManager.ReturnSavesInfo(); C4JStorage::ESaveGameState eLoadStatus=StorageManager.LoadSaveDataThumbnail(&pSaveDetails->SaveInfoA[(int)m_iRequestingThumbnailId],&LoadSaveDataThumbnailReturned,this); if(eLoadStatus!=C4JStorage::ESaveGame_GetSaveThumbnail) { // something went wrong m_bRetrievingSaveThumbnails=false; m_bAllLoaded = true; } } } else if (m_bSavesDisplayed && m_bSaveThumbnailReady) { m_bSaveThumbnailReady = false; // check we're not waiting to exit the scene if(!m_bExitScene) { // convert to utf16 uint16_t u16Message[MAX_SAVEFILENAME_LENGTH]; #ifdef _DURANGO // Already utf16 on durango memcpy(u16Message, m_saveDetails[m_iRequestingThumbnailId].UTF16SaveFilename, MAX_SAVEFILENAME_LENGTH); #elif defined(_WINDOWS64) int result = ::MultiByteToWideChar( CP_UTF8, // convert from UTF-8 MB_ERR_INVALID_CHARS, // error on invalid chars m_saveDetails[m_iRequestingThumbnailId].UTF8SaveFilename, // source UTF-8 string MAX_SAVEFILENAME_LENGTH, // total length of source UTF-8 string, // in CHAR's (= bytes), including end-of-string \0 (wchar_t *)u16Message, // destination buffer MAX_SAVEFILENAME_LENGTH // size of destination buffer, in WCHAR's ); #else #ifdef __PS3 size_t srcmax,dstmax; #else uint32_t srcmax,dstmax; uint32_t srclen,dstlen; #endif srcmax=MAX_SAVEFILENAME_LENGTH; dstmax=MAX_SAVEFILENAME_LENGTH; #if defined(__PS3__) L10nResult lres= UTF8stoUTF16s((uint8_t *)m_saveDetails[m_iRequestingThumbnailId].UTF8SaveFilename,&srcmax,u16Message,&dstmax); #else SceCesUcsContext context; sceCesUcsContextInit(&context); sceCesUtf8StrToUtf16Str(&context, (uint8_t *)m_saveDetails[m_iRequestingThumbnailId].UTF8SaveFilename,srcmax,&srclen,u16Message,dstmax,&dstlen); #endif #endif if( m_saveDetails[m_iRequestingThumbnailId].pbThumbnailData ) { registerSubstitutionTexture((wchar_t *)u16Message,m_saveDetails[m_iRequestingThumbnailId].pbThumbnailData,m_saveDetails[m_iRequestingThumbnailId].dwThumbnailSize); } m_buttonListSaves.setTextureName(m_iRequestingThumbnailId, (wchar_t *)u16Message); ++m_iRequestingThumbnailId; if( m_iRequestingThumbnailId < (m_buttonListSaves.getItemCount() )) { app.DebugPrintf("Requesting another thumbnail\n"); // set the save to load PSAVE_DETAILS pSaveDetails=StorageManager.ReturnSavesInfo(); C4JStorage::ESaveGameState eLoadStatus=StorageManager.LoadSaveDataThumbnail(&pSaveDetails->SaveInfoA[(int)m_iRequestingThumbnailId],&LoadSaveDataThumbnailReturned,this); if(eLoadStatus!=C4JStorage::ESaveGame_GetSaveThumbnail) { // something went wrong m_bRetrievingSaveThumbnails=false; m_bAllLoaded = true; } } else { m_bRetrievingSaveThumbnails = false; m_bAllLoaded = true; } } else { // stop retrieving thumbnails, and exit m_bRetrievingSaveThumbnails = false; } } } switch(m_iState) { case e_SavesIdle: break; case e_SavesRepopulateAfterDelete: m_bIgnoreInput = false; m_iRequestingThumbnailId = 0; m_bAllLoaded=false; m_bRetrievingSaveThumbnails=false; m_bSavesDisplayed=false; m_iSaveInfoC=0; m_buttonListSaves.clearList(); //StorageManager.ClearSavesInfo(); //GetSaveInfo(); m_iState=e_SavesIdle; break; } } void UIScene_InGameSaveManagementMenu::GetSaveInfo( ) { unsigned int uiSaveC=0; // This will return with the number retrieved in uiSaveC // clear the saves list m_bSavesDisplayed = false; // we're blocking the exit from this scene until complete m_buttonListSaves.clearList(); m_iSaveInfoC=0; m_controlSavesTimer.setVisible(true); m_pSaveDetails=StorageManager.ReturnSavesInfo(); if(m_pSaveDetails==nullptr) { C4JStorage::ESaveGameState eSGIStatus= StorageManager.GetSavesInfo(m_iPad,nullptr,this,"save"); } return; } void UIScene_InGameSaveManagementMenu::handleInput(int iPad, int key, bool repeat, bool pressed, bool released, bool &handled) { if(m_bIgnoreInput) return; // if we're retrieving save info, ignore key presses if(!m_bSavesDisplayed) return; ui.AnimateKeyPress(m_iPad, key, repeat, pressed, released); switch(key) { case ACTION_MENU_CANCEL: if(pressed) { #if defined(__PS3__) || defined(__ORBIS__) || defined(__PSVITA__) m_bExitScene=true; #else navigateBack(); #endif handled = true; } break; case ACTION_MENU_OK: #ifdef __ORBIS__ case ACTION_MENU_TOUCHPAD_PRESS: #endif case ACTION_MENU_UP: case ACTION_MENU_DOWN: case ACTION_MENU_PAGEUP: case ACTION_MENU_PAGEDOWN: sendInputToMovie(key, repeat, pressed, released); handled = true; break; } } void UIScene_InGameSaveManagementMenu::handleInitFocus(F64 controlId, F64 childId) { app.DebugPrintf(app.USER_SR, "UIScene_InGameSaveManagementMenu::handleInitFocus - %d , %d\n", static_cast(controlId), static_cast(childId)); } void UIScene_InGameSaveManagementMenu::handleFocusChange(F64 controlId, F64 childId) { app.DebugPrintf(app.USER_SR, "UIScene_InGameSaveManagementMenu::handleFocusChange - %d , %d\n", static_cast(controlId), static_cast(childId)); m_iSaveListIndex = childId; if(m_bSavesDisplayed) m_bUpdateSaveSize = true; updateTooltips(); } void UIScene_InGameSaveManagementMenu::handlePress(F64 controlId, F64 childId) { switch(static_cast(controlId)) { case eControl_SavesList: { m_bIgnoreInput = true; // delete the save game // Have to ask the player if they are sure they want to delete this game UINT uiIDA[2]; uiIDA[0]=IDS_CONFIRM_CANCEL; uiIDA[1]=IDS_CONFIRM_OK; ui.RequestErrorMessage(IDS_TOOLTIPS_DELETESAVE, IDS_TEXT_DELETE_SAVE, uiIDA, 2,m_iPad,&UIScene_InGameSaveManagementMenu::DeleteSaveDialogReturned,this); ui.PlayUISFX(eSFX_Press); break; } } } int UIScene_InGameSaveManagementMenu::DeleteSaveDialogReturned(void *pParam,int iPad,C4JStorage::EMessageResult result) { UIScene_InGameSaveManagementMenu* pClass = static_cast(pParam); // results switched for this dialog if(result==C4JStorage::EMessage_ResultDecline) { if(app.DebugSettingsOn() && app.GetLoadSavesFromFolderEnabled()) { pClass->m_bIgnoreInput=false; } else { StorageManager.DeleteSaveData(&pClass->m_pSaveDetails->SaveInfoA[pClass->m_iSaveListIndex],UIScene_InGameSaveManagementMenu::DeleteSaveDataReturned,pClass); pClass->m_controlSavesTimer.setVisible( true ); } } else { pClass->m_bIgnoreInput=false; } return 0; } int UIScene_InGameSaveManagementMenu::DeleteSaveDataReturned(LPVOID lpParam,bool bRes) { UIScene_InGameSaveManagementMenu* pClass = static_cast(lpParam); if(bRes) { // wipe the list and repopulate it pClass->m_iState=e_SavesRepopulateAfterDelete; } else pClass->m_bIgnoreInput=false; pClass->updateTooltips(); return 0; } bool UIScene_InGameSaveManagementMenu::hasFocus(int iPad) { return bHasFocus && (iPad == m_iPad || m_iPad == XUSER_INDEX_ANY); }