#include "stdafx.h" #include #include #include #include "XUI_Ctrl_4JList.h" #include "XUI_Ctrl_4JIcon.h" #include "XUI_LoadSettings.h" #include "..\..\ProgressRenderer.h" #include "XUI_TransferToXboxOne.h" //---------------------------------------------------------------------------------- // Performs initialization tasks - retrieves controls. //---------------------------------------------------------------------------------- HRESULT CScene_TransferToXboxOne::OnInit( XUIMessageInit* pInitData, BOOL& bHandled ) { m_iX=-1; m_params = (LoadMenuInitData *)pInitData->pvInitData; m_iPad=m_params->iPad; m_bRetrievingSaveInfo=false; m_bIgnoreInput=false; MapChildControls(); VOID *pObj; XuiObjectFromHandle( m_SavesSlotList, &pObj ); m_pSavesSlotList = (CXuiCtrl4JList *)pObj; m_pbImageData=NULL; m_dwImageBytes=0; StorageManager.GetSaveCacheFileInfo(m_params->iSaveGameInfoIndex,m_XContentData); StorageManager.GetSaveCacheFileInfo(m_params->iSaveGameInfoIndex,&m_pbImageData,&m_dwImageBytes); m_SavesSlotListTimer.SetShow(TRUE); XuiControlSetText(m_SavesSlotList,app.GetString(IDS_XBONE_SELECTSLOT)); // insert the current save slot names m_MaxSlotC=app.m_uiTransferSlotC; m_pSlotDataA = new SLOTDATA [m_MaxSlotC]; ZeroMemory(m_pSlotDataA,sizeof(SLOTDATA)*m_MaxSlotC); // saves will be called slot1 to slotx // there will be a details file with the names and png of each slot m_pbSlotListFile=NULL; m_uiSlotListFileBytes=0; if(StorageManager.TMSPP_InFileList(C4JStorage::eGlobalStorage_TitleUser,m_iPad,L"XboxOne/SlotList")) { // there is a slot list file with details of the saves C4JStorage::ETMSStatus status=StorageManager.TMSPP_ReadFile(m_iPad,C4JStorage::eGlobalStorage_TitleUser,C4JStorage::TMS_FILETYPE_BINARY,"XboxOne/SlotList",&CScene_TransferToXboxOne::TMSPPSlotListReturned,this); m_iX=IDS_TOOLTIPS_CLEARSLOTS; } else { CXuiCtrl4JList::LIST_ITEM_INFO ListInfo; ZeroMemory(&ListInfo,sizeof(CXuiCtrl4JList::LIST_ITEM_INFO)); // create dummy slots for(int i=0;iAddData(ListInfo); } m_SavesSlotListTimer.SetShow(FALSE); } CXuiSceneBase::SetTooltips( DEFAULT_XUI_MENU_USER, IDS_TOOLTIPS_SELECT, IDS_TOOLTIPS_BACK, m_iX, -1,-1,-1,-1,-1,-1,true); return S_OK; } //---------------------------------------------------------------------------------- // TMSPPSlotListReturned callback //---------------------------------------------------------------------------------- int CScene_TransferToXboxOne::TMSPPWriteReturned(LPVOID pParam,int iPad,int iUserData) { CScene_TransferToXboxOne* pClass = (CScene_TransferToXboxOne *) pParam; pClass->m_bWaitingForWrite=false; return 0; } //---------------------------------------------------------------------------------- // TMSPPSlotListReturned callback //---------------------------------------------------------------------------------- int CScene_TransferToXboxOne::TMSPPDeleteReturned(LPVOID pParam,int iPad,int iUserData) { CScene_TransferToXboxOne* pClass = (CScene_TransferToXboxOne *) pParam; pClass->m_SavesSlotListTimer.SetShow(FALSE); pClass->m_bIgnoreInput=false; // update the slots delete pClass->m_pbSlotListFile; pClass->m_pbSlotListFile=NULL; pClass->m_uiSlotListFileBytes=0; pClass->m_pSavesSlotList->RemoveAllData(); CXuiCtrl4JList::LIST_ITEM_INFO ListInfo; ZeroMemory(&ListInfo,sizeof(CXuiCtrl4JList::LIST_ITEM_INFO)); // clear our slot info ZeroMemory(pClass->m_pSlotDataA,sizeof(SLOTDATA)*pClass->m_MaxSlotC); for(int i=0;im_MaxSlotC;i++) { memcpy(pClass->m_pSlotDataA[i].wchSaveTitle,app.GetString(IDS_XBONE_EMPTYSLOT),sizeof(WCHAR)*XCONTENT_MAX_DISPLAYNAME_LENGTH); ListInfo.pwszText = app.GetString(IDS_XBONE_EMPTYSLOT); ListInfo.fEnabled = TRUE; ListInfo.iData = -1; pClass->m_pSavesSlotList->AddData(ListInfo); } return 0; } //---------------------------------------------------------------------------------- // TMSPPSlotListReturned callback //---------------------------------------------------------------------------------- int CScene_TransferToXboxOne::TMSPPSlotListReturned(LPVOID pParam,int iPad,int iUserData,C4JStorage::PTMSPP_FILEDATA pFileData, LPCSTR szFilename) { CScene_TransferToXboxOne* pClass = (CScene_TransferToXboxOne *) pParam; unsigned int uiSlotListFileSlots=*((unsigned int *)pFileData->pbData); pClass->m_pbSlotListFile=pFileData->pbData; pClass->m_uiSlotListFileBytes=pFileData->dwSize; // clear our slot info ZeroMemory(pClass->m_pSlotDataA,sizeof(SLOTDATA)*pClass->m_MaxSlotC); // set the empty slot strings for(int i=0;im_MaxSlotC;i++) { memcpy(pClass->m_pSlotDataA[i].wchSaveTitle,app.GetString(IDS_XBONE_EMPTYSLOT),sizeof(WCHAR)*XCONTENT_MAX_DISPLAYNAME_LENGTH); } // update our slot info with the data from the file - might have less slots unsigned int uiNewSlotsC=(pClass->m_MaxSlotCm_MaxSlotC:uiSlotListFileSlots; memcpy(pClass->m_pSlotDataA,pClass->m_pbSlotListFile + sizeof(unsigned int),sizeof(SLOTDATA)*uiNewSlotsC); CXuiCtrl4JList::LIST_ITEM_INFO ListInfo; ZeroMemory(&ListInfo,sizeof(CXuiCtrl4JList::LIST_ITEM_INFO)); PBYTE pbImageData=pClass->m_pbSlotListFile + sizeof(unsigned int) + sizeof(SLOTDATA)*uiSlotListFileSlots; // fill out the slot info for(int i=0;im_MaxSlotC;i++) { if(im_pSlotDataA[i].wchSaveTitle; ListInfo.fEnabled = TRUE; ListInfo.iData = -1; pClass->m_pSavesSlotList->AddData(ListInfo); if(pClass->m_pSlotDataA[i].uiImageLength!=0) { XuiCreateTextureBrushFromMemory(pbImageData,pClass->m_pSlotDataA[i].uiImageLength,&pClass->m_hXuiBrush); pClass->m_pSavesSlotList->UpdateGraphic(i,pClass->m_hXuiBrush); // increment the image data pointer pbImageData+=pClass->m_pSlotDataA[i].uiImageLength; } } else { // make it blank ListInfo.pwszText = app.GetString(IDS_XBONE_EMPTYSLOT); ListInfo.fEnabled = TRUE; ListInfo.iData = -1; pClass->m_pSavesSlotList->AddData(ListInfo); } } pClass->m_SavesSlotListTimer.SetShow(FALSE); return 0; } //---------------------------------------------------------------------------------- // Handler for OnDestroy //---------------------------------------------------------------------------------- HRESULT CScene_TransferToXboxOne::OnDestroy() { return S_OK; } //---------------------------------------------------------------------------------- // Handler for the button press message. //---------------------------------------------------------------------------------- HRESULT CScene_TransferToXboxOne::OnNotifyPressEx(HXUIOBJ hObjPressed, XUINotifyPress* pNotifyPressData, BOOL& rfHandled) { if(m_bIgnoreInput) return S_OK; // if we're retrieving save info, ignore key presses if(m_bRetrievingSaveInfo) { return S_OK; } // This assumes all buttons can only be pressed with the A button ui.AnimateKeyPress(pNotifyPressData->UserIndex, VK_PAD_A); if(hObjPressed==m_SavesSlotList) { m_bIgnoreInput=true; // update the info in the SlotList file CXuiControl pItem; int iIndex; // get the selected item iIndex=m_SavesSlotList.GetCurSel(&pItem); // check if there is a save there CXuiCtrl4JList::LIST_ITEM_INFO info = m_pSavesSlotList->GetData(iIndex); if(info.pwszImage!=NULL) { // we have a save here // Are you sure, etc. } // update the data memcpy(m_pSlotDataA[iIndex].wchSaveTitle,m_XContentData.szDisplayName,sizeof(WCHAR)*XCONTENT_MAX_DISPLAYNAME_LENGTH); m_pSavesSlotList->UpdateText(iIndex,m_pSlotDataA[iIndex].wchSaveTitle); // if there is no thumbnail, retrieve the default one from the file. // Don't delete the image data after creating the xuibrush, since we'll use it in the rename of the save bool bHostOptionsRead = false; unsigned int uiHostOptions = 0; XuiCreateTextureBrushFromMemory(m_pbImageData,m_dwImageBytes,&m_hXuiBrush); m_pSavesSlotList->UpdateGraphic(iIndex,m_hXuiBrush); m_pSlotDataA[iIndex].uiImageLength=m_dwImageBytes; m_bIgnoreInput=false; // finished so navigate back //app.NavigateBack(XUSER_INDEX_ANY); BuildSlotFile(iIndex,m_pbImageData,m_dwImageBytes); } return S_OK; } HRESULT CScene_TransferToXboxOne::BuildSlotFile(int iIndexBeingUpdated,PBYTE pbImageData,DWORD dwImageBytes ) { SLOTDATA *pCurrentSlotData=NULL; PBYTE pbCurrentSlotDataPtr=NULL; // there may be no slot file yet if(m_pbSlotListFile!=NULL) { pCurrentSlotData=(SLOTDATA *)(m_pbSlotListFile+sizeof(unsigned int)); pbCurrentSlotDataPtr=m_pbSlotListFile + sizeof(unsigned int) + sizeof(SLOTDATA)*m_MaxSlotC; } m_uiSlotID=iIndexBeingUpdated; // memory required - first int is the number of slots in this file, in case that changes later unsigned int uiBytesRequired=sizeof(unsigned int) + sizeof(SLOTDATA)*m_MaxSlotC; for(int i=0;ifunc = &CScene_TransferToXboxOne::UploadSaveForXboxOneThreadProc; loadingParams->lpParam = (LPVOID)this; UIFullscreenProgressCompletionData *completionData = new UIFullscreenProgressCompletionData(); completionData->bShowBackground=TRUE; completionData->bShowLogo=TRUE; completionData->iPad = m_iPad; completionData->type = e_ProgressCompletion_NavigateBackToScene; completionData->scene = eUIScene_LoadMenu; loadingParams->completionData = completionData; app.NavigateToScene(m_iPad,eUIScene_FullscreenProgress, loadingParams); return S_OK; } int CScene_TransferToXboxOne::UploadSaveForXboxOneThreadProc( LPVOID lpParameter ) { HRESULT hr = S_OK; char szFilename[32]; CScene_TransferToXboxOne* pClass = (CScene_TransferToXboxOne *) lpParameter; Minecraft *pMinecraft = Minecraft::GetInstance(); unsigned int uiComplete=0; pClass->m_bWaitingForWrite=true; pMinecraft->progressRenderer->progressStart(IDS_XBONE_UPLOAD_SAVE_TITLE); pMinecraft->progressRenderer->progressStage( IDS_XBONE_UPLOAD_METADATA ); // now write the new slot data file to global storage, and then write the save data C4JStorage::ETMSStatus eStatus=StorageManager.TMSPP_WriteFile(pClass->m_iPad,C4JStorage::eGlobalStorage_TitleUser,C4JStorage::TMS_FILETYPE_BINARY,C4JStorage::TMS_UGCTYPE_NONE,"XboxOne/SlotList",(PCHAR) pClass->m_pbSlotListFile, pClass->m_uiSlotListFileBytes, &CScene_TransferToXboxOne::TMSPPWriteReturned,lpParameter, 0); if(eStatus!=C4JStorage::ETMSStatus_WriteInProgress) { // failed pClass->m_bWaitingForWrite=false; } else { // loop waiting for the write to complete uiComplete=0; while(pClass->m_bWaitingForWrite && (hr == S_OK)) { Sleep(50); uiComplete++; if(uiComplete>100) uiComplete=100; pMinecraft->progressRenderer->progressStagePercentage(uiComplete); if(app.GetChangingSessionType()) { // 4J Stu - This causes the fullscreenprogress scene to ignore the action it was given hr = ERROR_CANCELLED; } } if(hr!=S_OK) return -1; // finish the bar for(int i=uiComplete;i<100;i++) { Sleep(5); pMinecraft->progressRenderer->progressStagePercentage(i); } // now upload the save data pMinecraft->progressRenderer->progressStage( IDS_XBONE_UPLOAD_SAVE ); // write the save file, and increment the progress percentage pMinecraft->progressRenderer->progressStagePercentage(25); pClass->m_bSaveDataReceived=false; C4JStorage::ELoadGameStatus eLoadStatus=StorageManager.LoadSaveData(&pClass->m_XContentData,CScene_TransferToXboxOne::LoadSaveDataReturned,lpParameter); // sleep until we have the data while(pClass->m_bSaveDataReceived==false) { Sleep(50); } // write the save to user TMS // break the file up into 256K chunks unsigned int uiChunkSize=262144; unsigned int uiBytesLeft=pClass->m_uiStorageLength; C4JStorage::ETMSStatus eStatus; // max file size would be 100*256K unsigned int uiPercentageChunk=100/(pClass->m_uiStorageLength/uiChunkSize); uiComplete=0; if(uiPercentageChunk==0) uiPercentageChunk=1; for(int i=0;i<(pClass->m_uiStorageLength/uiChunkSize)+1;i++) { sprintf( szFilename, "XboxOne/Slot%.2d%.2d", pClass->m_uiSlotID,i ); PCHAR pchData=((PCHAR)pClass->m_pvSaveMem)+i*uiChunkSize; pClass->m_bWaitingForWrite=true; if(uiBytesLeft>=uiChunkSize) { eStatus=StorageManager.TMSPP_WriteFile(pClass->m_iPad,C4JStorage::eGlobalStorage_TitleUser,C4JStorage::TMS_FILETYPE_BINARY,C4JStorage::TMS_UGCTYPE_NONE,szFilename,pchData, uiChunkSize, &CScene_TransferToXboxOne::TMSPPWriteReturned,lpParameter, 0); uiBytesLeft-=uiChunkSize; } else { // last bit of the file to upload is less than uiChunkSize eStatus=StorageManager.TMSPP_WriteFile(pClass->m_iPad,C4JStorage::eGlobalStorage_TitleUser,C4JStorage::TMS_FILETYPE_BINARY,C4JStorage::TMS_UGCTYPE_NONE,szFilename,pchData, uiBytesLeft, &CScene_TransferToXboxOne::TMSPPWriteReturned,lpParameter, 0); } // wait until if(eStatus!=C4JStorage::ETMSStatus_WriteInProgress) { // failed pClass->m_bWaitingForWrite=false; } else { // loop waiting for the write to complete while(pClass->m_bWaitingForWrite && (hr == S_OK)) { Sleep(50); } uiComplete+=uiPercentageChunk; if(uiComplete>100) uiComplete=100; // update the progress pMinecraft->progressRenderer->progressStagePercentage(uiComplete); } } delete pClass->m_pvSaveMem; } return hr; } int CScene_TransferToXboxOne::LoadSaveDataReturned(void *pParam,bool bContinue) { CScene_TransferToXboxOne* pClass = (CScene_TransferToXboxOne*)pParam; if(bContinue==true) { unsigned int uiFileSize = StorageManager.GetSaveSize(); pClass->m_pvSaveMem = new BYTE [uiFileSize]; pClass->m_uiStorageLength=0; StorageManager.GetSaveData( pClass->m_pvSaveMem, &pClass->m_uiStorageLength ); pClass->m_bSaveDataReceived=true; } return 0; } HRESULT CScene_TransferToXboxOne::OnKeyDown(XUIMessageInput* pInputData, BOOL& rfHandled) { if(m_bIgnoreInput) return S_OK; // if we're retrieving save info, ignore key presses if(m_bRetrievingSaveInfo) { return S_OK; } ui.AnimateKeyPress(pInputData->UserIndex, pInputData->dwKeyCode); HRESULT hr = S_OK; // Explicitly handle B button presses switch(pInputData->dwKeyCode) { case VK_PAD_B: case VK_ESCAPE: app.NavigateBack(XUSER_INDEX_ANY); rfHandled = TRUE; break; case VK_PAD_X: // wipe the save slots if(m_pbSlotListFile!=NULL) { m_SavesSlotListTimer.SetShow(TRUE); m_bIgnoreInput=true; C4JStorage::ETMSStatus eStatus=StorageManager.TMSPP_DeleteFile(m_iPad,"XboxOne/SlotList",C4JStorage::TMS_FILETYPE_BINARY,&CScene_TransferToXboxOne::TMSPPDeleteReturned,this, 0); } break; } return hr; } HRESULT CScene_TransferToXboxOne::OnNotifySelChanged(HXUIOBJ hObjSource, XUINotifySelChanged *pNotifySelChangedData, BOOL& bHandled) { //if(m_bReady) { CXuiSceneBase::PlayUISFX(eSFX_Focus); } return S_OK; } HRESULT CScene_TransferToXboxOne::OnTransitionStart( XUIMessageTransition *pTransition, BOOL& bHandled ) { //if(pTransition->dwTransAction==XUI_TRANSITION_ACTION_DESTROY ) return S_OK; if(pTransition->dwTransAction==XUI_TRANSITION_ACTION_DESTROY || pTransition->dwTransType == XUI_TRANSITION_FROM || pTransition->dwTransType == XUI_TRANSITION_BACKFROM) { // 4J Stu - We may have had to unload our font renderer in this scene if one of the save files // uses characters not in our font (eg asian chars) so restore our font renderer // This will not do anything if our font renderer is already loaded app.OverrideFontRenderer(true,true); } return S_OK; } HRESULT CScene_TransferToXboxOne::OnFontRendererChange() { // update the tooltips CXuiSceneBase::SetTooltips( DEFAULT_XUI_MENU_USER, IDS_TOOLTIPS_SELECT, IDS_TOOLTIPS_BACK, m_iX, -1,-1,-1,-1,-1,-1,true); return S_OK; } HRESULT CScene_TransferToXboxOne::OnNotifySetFocus(HXUIOBJ hObjSource, XUINotifyFocus *pNotifyFocusData, BOOL& bHandled) { // update the tooltips CXuiSceneBase::SetTooltips( DEFAULT_XUI_MENU_USER, IDS_TOOLTIPS_SELECT, IDS_TOOLTIPS_BACK, m_iX, -1,-1,-1,-1,-1,-1,true); return S_OK; } HRESULT CScene_TransferToXboxOne::OnNotifyKillFocus(HXUIOBJ hObjSource, XUINotifyFocus *pNotifyFocusData, BOOL& bHandled) { return S_OK; }