Files
MinecraftConsoles/Minecraft.Client/Common/XUI/XUI_TransferToXboxOne.cpp
ModMaker101 a9be52c41a Project modernization (#630)
* Fixed boats falling and a TP glitch #266

* Replaced every C-style cast with C++ ones

* Replaced every C-style cast with C++ ones

* Fixed boats falling and a TP glitch #266

* Updated NULL to nullptr and fixing some type issues

* Modernized and fixed a few bugs

- Replaced most instances of `NULL` with `nullptr`.
- Replaced most `shared_ptr(new ...)` with `make_shared`.
- Removed the `nullptr` macro as it was interfering with the actual nullptr keyword in some instances.

* Fixing more conflicts

* Replace int loops with size_t and start work on overrides
2026-03-08 09:56:03 +07:00

570 lines
18 KiB
C++

#include "stdafx.h"
#include <xuiresource.h>
#include <xuiapp.h>
#include <assert.h>
#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 = static_cast<LoadMenuInitData *>(pInitData->pvInitData);
m_iPad=m_params->iPad;
m_bRetrievingSaveInfo=false;
m_bIgnoreInput=false;
MapChildControls();
VOID *pObj;
XuiObjectFromHandle( m_SavesSlotList, &pObj );
m_pSavesSlotList = static_cast<CXuiCtrl4JList *>(pObj);
m_pbImageData=nullptr;
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=nullptr;
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;i<m_MaxSlotC;i++)
{
memcpy(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;
m_pSavesSlotList->AddData(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 = static_cast<CScene_TransferToXboxOne *>(pParam);
pClass->m_bWaitingForWrite=false;
return 0;
}
//----------------------------------------------------------------------------------
// TMSPPSlotListReturned callback
//----------------------------------------------------------------------------------
int CScene_TransferToXboxOne::TMSPPDeleteReturned(LPVOID pParam,int iPad,int iUserData)
{
CScene_TransferToXboxOne* pClass = static_cast<CScene_TransferToXboxOne *>(pParam);
pClass->m_SavesSlotListTimer.SetShow(FALSE);
pClass->m_bIgnoreInput=false;
// update the slots
delete pClass->m_pbSlotListFile;
pClass->m_pbSlotListFile=nullptr;
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;i<pClass->m_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 = static_cast<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;i<pClass->m_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_MaxSlotC<uiSlotListFileSlots)?pClass->m_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;i<pClass->m_MaxSlotC;i++)
{
if(i<uiNewSlotsC)
{
ListInfo.pwszText = pClass->m_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!=nullptr)
{
// 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=nullptr;
PBYTE pbCurrentSlotDataPtr=nullptr;
// there may be no slot file yet
if(m_pbSlotListFile!=nullptr)
{
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;i<m_MaxSlotC;i++)
{
if(i==iIndexBeingUpdated)
{
uiBytesRequired+=dwImageBytes;
}
else
{
uiBytesRequired+=m_pSlotDataA[i].uiImageLength;
}
}
PBYTE pbNewSlotFileData= new BYTE [uiBytesRequired];
*((unsigned int *)pbNewSlotFileData)=m_MaxSlotC;
PBYTE pbNewSlotFileDataSlots=pbNewSlotFileData + sizeof(unsigned int);
PBYTE pbNewSlotImageDataPtr=pbNewSlotFileData + sizeof(unsigned int) + sizeof(SLOTDATA)*m_MaxSlotC;
SLOTDATA *pNewSlotData=(SLOTDATA *)pbNewSlotFileDataSlots;
// copy the slot info into the new memory, just after the first int
memcpy(pbNewSlotFileDataSlots,m_pSlotDataA,sizeof(SLOTDATA)*m_MaxSlotC);
for(int i=0;i<m_MaxSlotC;i++)
{
if(i==iIndexBeingUpdated)
{
memcpy(pbNewSlotImageDataPtr,pbImageData,dwImageBytes);
pbNewSlotImageDataPtr+=dwImageBytes;
// update the fields
pNewSlotData[i].uiImageLength=dwImageBytes;
// save title is already correct
}
else
{
if(pbCurrentSlotDataPtr!=nullptr)
{
memcpy(pbNewSlotImageDataPtr,pbCurrentSlotDataPtr,pCurrentSlotData[i].uiImageLength);
pbNewSlotImageDataPtr+=pCurrentSlotData[i].uiImageLength;
}
// fields are already correct
}
// move to the next image data in the current slot file
if(pbCurrentSlotDataPtr!=nullptr)
{
pbCurrentSlotDataPtr+=pCurrentSlotData[i].uiImageLength;
}
}
// free the previous file data and the current file data
delete m_pbSlotListFile;
// reset the pointer until we have the exit from this scene running
m_pbSlotListFile = pbNewSlotFileData;
m_uiSlotListFileBytes = uiBytesRequired;
m_pSlotDataA = (SLOTDATA *)pbNewSlotFileDataSlots;
LoadingInputParams *loadingParams = new LoadingInputParams();
loadingParams->func = &CScene_TransferToXboxOne::UploadSaveForXboxOneThreadProc;
loadingParams->lpParam = static_cast<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 = static_cast<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=static_cast<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 = static_cast<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!=nullptr)
{
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;
}