#include "stdafx.h" #include #include #include #include "..\..\..\Minecraft.World\StringHelpers.h" #include "..\..\Common\Tutorial\TutorialMode.h" #include "..\..\..\Minecraft.World\ConsoleSaveFileIO.h" #include "..\..\LocalPlayer.h" #include "..\..\Minecraft.h" #include "..\..\ProgressRenderer.h" #include "..\..\..\Minecraft.World\AABB.h" #include "..\..\..\Minecraft.World\Vec3.h" #include "..\..\..\Minecraft.World\ArrayWithLength.h" #include "..\..\..\Minecraft.World\File.h" #include "..\..\..\Minecraft.World\InputOutputStream.h" #include "XUI_Ctrl_4JList.h" #include "XUI_Ctrl_4JIcon.h" #include "XUI_LoadSettings.h" #include "XUI_MultiGameInfo.h" #include "XUI_MultiGameJoinLoad.h" #include "XUI_MultiGameCreate.h" #include "..\..\MinecraftServer.h" #include "..\..\Options.h" #include "..\GameRules\LevelGenerationOptions.h" #include "..\..\TexturePackRepository.h" #include "..\..\TexturePack.h" #include "..\..\..\Minecraft.World\LevelSettings.h" #define CHECKFORAVAILABLETEXTUREPACKS_TIMER_ID 3 #define CHECKFORAVAILABLETEXTUREPACKS_TIMER_TIME 100 //---------------------------------------------------------------------------------- // Performs initialization tasks - retrieves controls. //---------------------------------------------------------------------------------- HRESULT CScene_MultiGameJoinLoad::OnInit( XUIMessageInit* pInitData, BOOL& bHandled ) { m_iPad=*(int *)pInitData->pvInitData; m_bReady=false; MapChildControls(); m_iTexturePacksNotInstalled=0; m_iConfigA=NULL; XuiControlSetText(m_LabelNoGames,app.GetString(IDS_NO_GAMES_FOUND)); XuiControlSetText(m_GamesList,app.GetString(IDS_JOIN_GAME)); XuiControlSetText(m_SavesList,app.GetString(IDS_START_GAME)); const DWORD LOCATOR_SIZE = 256; // Use this to allocate space to hold a ResourceLocator string WCHAR szResourceLocator[ LOCATOR_SIZE ]; const ULONG_PTR c_ModuleHandle = (ULONG_PTR)GetModuleHandle(NULL); swprintf(szResourceLocator, LOCATOR_SIZE ,L"section://%X,%ls#%ls",c_ModuleHandle,L"media", L"media/Graphics/TexturePackIcon.png"); m_DefaultMinecraftIconSize = 0; HRESULT hr = XuiResourceLoadAllNoLoc(szResourceLocator, &m_DefaultMinecraftIconData, &m_DefaultMinecraftIconSize); m_localPlayers = 1; m_bKillSaveInfoEnumerate=false; m_bShowingPartyGamesOnly = false; m_bRetrievingSaveInfo=false; m_bSaveTransferInProgress=false; // check for a default custom cloak in the global storage // 4J-PB - changed to a config file // if(ProfileManager.IsSignedInLive( m_iPad )) // { // app.InstallDefaultCape(); // } m_initData= new JoinMenuInitData(); m_bMultiplayerAllowed = ProfileManager.IsSignedInLive( m_iPad ) && ProfileManager.AllowedToPlayMultiplayer(m_iPad); XPARTY_USER_LIST partyList; if((XPartyGetUserList( &partyList ) != XPARTY_E_NOT_IN_PARTY ) && (partyList.dwUserCount>1)) { m_bInParty=true; } else { m_bInParty=false; } int iLB = -1; if(m_bInParty) iLB = IDS_TOOLTIPS_PARTY_GAMES; XuiSetTimer(m_hObj,JOIN_LOAD_ONLINE_TIMER_ID,JOIN_LOAD_ONLINE_TIMER_TIME); m_iSaveInfoC=0; VOID *pObj; XuiObjectFromHandle( m_SavesList, &pObj ); m_pSavesList = (CXuiCtrl4JList *)pObj; XuiObjectFromHandle( m_GamesList, &pObj ); m_pGamesList = (CXuiCtrl4JList *)pObj; // 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) { // not doing a mount, so enable input m_bIgnoreInput=true; } else { // 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=false; m_iChangingSaveGameInfoIndex = 0; m_generators = app.getLevelGenerators(); m_iDefaultButtonsC = 0; m_iMashUpButtonsC=0; // check if we're in the trial version if(ProfileManager.IsFullVersion()==false) { ui.SetTooltips( DEFAULT_XUI_MENU_USER, IDS_TOOLTIPS_SELECT,IDS_TOOLTIPS_BACK, -1, -1, -1, -1,iLB); AddDefaultButtons(); m_pSavesList->SetCurSelVisible(0); } else if(StorageManager.GetSaveDisabled()) { if(StorageManager.GetSaveDeviceSelected(m_iPad)) { // saving is disabled, but we should still be able to load from a selected save device ui.SetTooltips( DEFAULT_XUI_MENU_USER, IDS_TOOLTIPS_SELECT,IDS_TOOLTIPS_BACK,IDS_TOOLTIPS_CHANGEDEVICE,-1,-1,-1,iLB,IDS_TOOLTIPS_DELETESAVE); GetSaveInfo(); } else { ui.SetTooltips( DEFAULT_XUI_MENU_USER, IDS_TOOLTIPS_SELECT,IDS_TOOLTIPS_BACK,IDS_TOOLTIPS_SELECTDEVICE,-1,-1,-1,iLB); AddDefaultButtons(); m_SavesListTimer.SetShow( FALSE ); m_pSavesList->SetCurSelVisible(0); } } 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(); ui.SetTooltips( DEFAULT_XUI_MENU_USER, IDS_TOOLTIPS_SELECT,IDS_TOOLTIPS_BACK,IDS_TOOLTIPS_CHANGEDEVICE,-1,-1,-1,-1,bCanRename?IDS_TOOLTIPS_SAVEOPTIONS:IDS_TOOLTIPS_DELETESAVE); GetSaveInfo(); } } //XuiElementSetDisableFocusRecursion( m_pGamesList->m_hObj, TRUE); UpdateGamesList(); g_NetworkManager.SetSessionsUpdatedCallback( &CScene_MultiGameJoinLoad::UpdateGamesListCallback, this ); // 4J Stu - Fix for #12530 -TCR 001 BAS Game Stability: Title will crash if the player disconnects while starting a new world and then opts to play the tutorial once they have been returned to the Main Menu. MinecraftServer::resetFlags(); // 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(); } // 4J-PB - Load up any texture pack data we have locally in the XZP for(int i=0;iskins->getTexturePackCount(); //CXuiCtrl4JList::LIST_ITEM_INFO ListInfo; //HRESULT hr; for(unsigned int i = 0; i < app.GetDLCInfoTexturesOffersCount(); ++i) { bTexturePackAlreadyListed=false; ULONGLONG ull=app.GetDLCInfoTexturesFullOffer(i); pDLCInfo=app.GetDLCInfoForFullOfferID(ull); for(unsigned int i = 0; i < texturePacksCount; ++i) { TexturePack *tp = pMinecraft->skins->getTexturePackByIndex(i); if(pDLCInfo->iConfig==tp->getDLCParentPackId()) { bTexturePackAlreadyListed=true; } } if(bTexturePackAlreadyListed==false) { // some missing bNeedToGetTPD=true; m_iTexturePacksNotInstalled++; } } if(bNeedToGetTPD==true) { // add a TMS request for them app.DebugPrintf("+++ Adding TMSPP request for texture pack data\n"); app.AddTMSPPFileTypeRequest(e_DLC_TexturePackData); m_iConfigA= new int [m_iTexturePacksNotInstalled]; m_iTexturePacksNotInstalled=0; for(unsigned int i = 0; i < app.GetDLCInfoTexturesOffersCount(); ++i) { bTexturePackAlreadyListed=false; ULONGLONG ull=app.GetDLCInfoTexturesFullOffer(i); pDLCInfo=app.GetDLCInfoForFullOfferID(ull); for(unsigned int i = 0; i < texturePacksCount; ++i) { TexturePack *tp = pMinecraft->skins->getTexturePackByIndex(i); if(pDLCInfo->iConfig==tp->getDLCParentPackId()) { bTexturePackAlreadyListed=true; } } if(bTexturePackAlreadyListed==false) { m_iConfigA[m_iTexturePacksNotInstalled++]=pDLCInfo->iConfig; } } } XuiSetTimer(m_hObj,CHECKFORAVAILABLETEXTUREPACKS_TIMER_ID,CHECKFORAVAILABLETEXTUREPACKS_TIMER_TIME); return S_OK; } void CScene_MultiGameJoinLoad::AddDefaultButtons() { CXuiCtrl4JList::LIST_ITEM_INFO ListInfo; // Add two for New Game and Tutorial ZeroMemory(&ListInfo,sizeof(CXuiCtrl4JList::LIST_ITEM_INFO)); ListInfo.pwszText = app.GetString(IDS_CREATE_NEW_WORLD); ListInfo.fEnabled = TRUE; ListInfo.iData = -1; m_pSavesList->AddData(ListInfo); int iSavesListIndex = 0; int iGeneratorIndex = 0; m_iMashUpButtonsC=0; for(AUTO_VAR(it, m_generators->begin()); it != m_generators->end(); ++it) { LevelGenerationOptions *levelGen = *it; ListInfo.pwszText = levelGen->getWorldName(); ListInfo.fEnabled = TRUE; ListInfo.iData = iGeneratorIndex++; // used to index into the list of generators // need to check if the user has disabled this pack in the save display list unsigned int uiTexturePackID=levelGen->getRequiredTexturePackId(); if(uiTexturePackID!=0) { unsigned int uiMashUpWorldsBitmask=app.GetMashupPackWorlds(m_iPad); if((uiMashUpWorldsBitmask & (1<<(uiTexturePackID-1024)))==0) { // this world is hidden, so skip continue; } } m_pSavesList->AddData(ListInfo); // retrieve the save icon from the texture pack, if there is one if(uiTexturePackID!=0) { // increment the count of the mash-up pack worlds in the save list m_iMashUpButtonsC++; TexturePack *tp = Minecraft::GetInstance()->skins->getTexturePackById(levelGen->getRequiredTexturePackId()); DWORD dwImageBytes; PBYTE pbImageData = tp->getPackIcon(dwImageBytes); HXUIBRUSH hXuiBrush; if(dwImageBytes > 0 && pbImageData) { XuiCreateTextureBrushFromMemory(pbImageData,dwImageBytes,&hXuiBrush); // the index inside the list item for this will be i+1 because they start at m_vListData.size(), so the first etry (tutorial) is 1 m_pSavesList->UpdateGraphic(iSavesListIndex+1,hXuiBrush); } } ++iSavesListIndex; } m_iDefaultButtonsC = iSavesListIndex + 1; } HRESULT CScene_MultiGameJoinLoad::GetSaveInfo( ) { unsigned int uiSaveC=0; // This will return with the number retrieved in uiSaveC if(app.DebugSettingsOn() && app.GetLoadSavesFromFolderEnabled()) { uiSaveC = 0; File savesDir(L"GAME:\\Saves"); if( savesDir.exists() ) { m_saves = savesDir.listFiles(); uiSaveC = (unsigned int)m_saves->size(); } // add the New Game and Tutorial after the saves list is retrieved, if there are any saves // Add two for New Game and Tutorial unsigned int listItems = uiSaveC; CXuiCtrl4JList::LIST_ITEM_INFO ListInfo; ZeroMemory(&ListInfo,sizeof(CXuiCtrl4JList::LIST_ITEM_INFO)); AddDefaultButtons(); for(unsigned int i=0;iat(i)->getName(); wchar_t *name = new wchar_t[wName.size()+1]; for(unsigned int j = 0; j < wName.size(); ++j) { name[j] = wName[j]; } name[wName.size()] = 0; ListInfo.pwszText = name; ListInfo.fEnabled=TRUE; ListInfo.iData = -1; m_pSavesList->AddData(ListInfo); } m_pSavesList->SetCurSelVisible(0); } else { m_bRetrievingSaveInfo=true; // we're blocking the exit from this scene until complete // clear the saves list m_pSavesList->RemoveAllData(); m_iSaveInfoC=0; #ifdef _XBOX C4JStorage::ESGIStatus eSGIStatus=StorageManager.GetSavesInfo(ProfileManager.GetPrimaryPad(),&CScene_MultiGameJoinLoad::GetSavesInfoCallback,this,"savegame.dat"); if(eSGIStatus==C4JStorage::ESGIStatus_NoSaves) { uiSaveC=0; m_SavesListTimer.SetShow( FALSE ); m_SavesList.SetEnable(TRUE); } #else //C4JStorage::ESaveGameState eStatus=StorageManager.GetSavesInfo(ProfileManager.GetPrimaryPad(),&CScene_MultiGameJoinLoad::GetSavesInfoCallback,this,"savegame.dat"); #endif } return S_OK; } HRESULT CScene_MultiGameJoinLoad::OnDestroy() { g_NetworkManager.SetSessionsUpdatedCallback( NULL, NULL ); for(AUTO_VAR(it, currentSessions.begin()); it < currentSessions.end(); ++it) { delete (*it); } if(m_bSaveTransferInProgress) { CancelSaveUploadCallback(this); } // Reset the background downloading, in case we changed it by attempting to download a texture pack XBackgroundDownloadSetMode(XBACKGROUND_DOWNLOAD_MODE_AUTO); // clear out the texture pack data for(int i=0;im_bIgnoreInput=false; return 0; } //---------------------------------------------------------------------------------- // Handler for the button press message. //---------------------------------------------------------------------------------- HRESULT CScene_MultiGameJoinLoad::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_GamesList ) { m_bIgnoreInput=true; DWORD nIndex = m_pGamesList->GetCurSel(); if( m_pGamesList->GetItemCount() > 0 && nIndex < currentSessions.size() ) { //CScene_MultiGameInfo::JoinMenuInitData *initData = new CScene_MultiGameInfo::JoinMenuInitData(); m_initData->iPad = m_iPad; m_initData->selectedSession = currentSessions.at( nIndex ); // check that we have the texture pack available // If it's not the default texture pack if(m_initData->selectedSession->data.texturePackParentId!=0) { int texturePacksCount = Minecraft::GetInstance()->skins->getTexturePackCount(); bool bHasTexturePackInstalled=false; for(int i=0;iskins->getTexturePackByIndex(i); if(tp->getDLCParentPackId()==m_initData->selectedSession->data.texturePackParentId) { bHasTexturePackInstalled=true; break; } } if(bHasTexturePackInstalled==false) { // upsell the texture pack // tell sentient about the upsell of the full version of the skin pack ULONGLONG ullOfferID_Full; app.GetDLCFullOfferIDForPackID(m_initData->selectedSession->data.texturePackParentId,&ullOfferID_Full); TelemetryManager->RecordUpsellPresented(pNotifyPressData->UserIndex, eSet_UpsellID_Texture_DLC, ullOfferID_Full & 0xFFFFFFFF); UINT uiIDA[3]; // Need to check if the texture pack has both Full and Trial versions - we may do some as free ones, so only Full DLC_INFO *pDLCInfo=app.GetDLCInfoForFullOfferID(ullOfferID_Full); if(pDLCInfo->ullOfferID_Trial!=0LL) { uiIDA[0]=IDS_TEXTUREPACK_FULLVERSION; uiIDA[1]=IDS_TEXTURE_PACK_TRIALVERSION; uiIDA[2]=IDS_CONFIRM_CANCEL; // Give the player a warning about the texture pack missing StorageManager.RequestMessageBox(IDS_DLC_TEXTUREPACK_NOT_PRESENT_TITLE, IDS_DLC_TEXTUREPACK_NOT_PRESENT, uiIDA, 3, ProfileManager.GetPrimaryPad(),&CScene_MultiGameJoinLoad::TexturePackDialogReturned,this,app.GetStringTable()); } else { uiIDA[0]=IDS_TEXTUREPACK_FULLVERSION; uiIDA[1]=IDS_CONFIRM_CANCEL; // Give the player a warning about the texture pack missing StorageManager.RequestMessageBox(IDS_DLC_TEXTUREPACK_NOT_PRESENT_TITLE, IDS_DLC_TEXTUREPACK_NOT_PRESENT, uiIDA, 2, ProfileManager.GetPrimaryPad(),&CScene_MultiGameJoinLoad::TexturePackDialogReturned,this,app.GetStringTable()); } return S_OK; } } m_NetGamesListTimer.SetShow( FALSE ); // Reset the background downloading, in case we changed it by attempting to download a texture pack XBackgroundDownloadSetMode(XBACKGROUND_DOWNLOAD_MODE_AUTO); // kill the texture pack check timer XuiKillTimer(m_hObj,CHECKFORAVAILABLETEXTUREPACKS_TIMER_ID); app.NavigateToScene(pNotifyPressData->UserIndex,eUIScene_JoinMenu,m_initData); } } else if(hObjPressed==m_SavesList) { m_bIgnoreInput=true; CXuiControl pItem; int iIndex; // get the selected item iIndex=m_SavesList.GetCurSel(&pItem); CXuiCtrl4JList::LIST_ITEM_INFO info = m_pSavesList->GetData(iIndex); if(iIndex == JOIN_LOAD_CREATE_BUTTON_INDEX) { app.SetTutorialMode( false ); m_NetGamesListTimer.SetShow( FALSE ); app.SetCorruptSaveDeleted(false); CreateWorldMenuInitData *params = new CreateWorldMenuInitData(); params->iPad = m_iPad; app.NavigateToScene(pNotifyPressData->UserIndex,eUIScene_CreateWorldMenu,(void *)params); } else if(info.iData >= 0) { LevelGenerationOptions *levelGen = m_generators->at(info.iData); app.SetTutorialMode( levelGen->isTutorial() ); // Reset the autosave time app.SetAutosaveTimerTime(); if(levelGen->isTutorial()) { LoadLevelGen(levelGen); } else { LoadMenuInitData *params = new LoadMenuInitData(); params->iPad = m_iPad; // need to get the iIndex from the list item, since the position in the list doesn't correspond to the GetSaveGameInfo list because of sorting params->iSaveGameInfoIndex=-1; //params->pbSaveRenamed=&m_bSaveRenamed; params->levelGen = levelGen; // navigate to the settings scene app.NavigateToScene(ProfileManager.GetPrimaryPad(),eUIScene_LoadMenu, params); } } else { // check if this is a damaged save if(m_pSavesList->GetData(iIndex).bIsDamaged) { // give the option to delete the save UINT uiIDA[2]; uiIDA[0]=IDS_CONFIRM_CANCEL; uiIDA[1]=IDS_CONFIRM_OK; StorageManager.RequestMessageBox(IDS_CORRUPT_OR_DAMAGED_SAVE_TITLE, IDS_CORRUPT_OR_DAMAGED_SAVE_TEXT, uiIDA, 2, pNotifyPressData->UserIndex,&CScene_MultiGameJoinLoad::DeleteSaveDialogReturned,this, app.GetStringTable()); } else { app.SetTutorialMode( false ); if(app.DebugSettingsOn() && app.GetLoadSavesFromFolderEnabled()) { LoadSaveFromDisk(m_saves->at(iIndex-m_iDefaultButtonsC)); } else { LoadMenuInitData *params = new LoadMenuInitData(); params->iPad = m_iPad; // need to get the iIndex from the list item, since the position in the list doesn't correspond to the GetSaveGameInfo list because of sorting params->iSaveGameInfoIndex=m_pSavesList->GetData(iIndex).iIndex-m_iDefaultButtonsC; //params->pbSaveRenamed=&m_bSaveRenamed; params->levelGen = NULL; // kill the texture pack timer XuiKillTimer(m_hObj,CHECKFORAVAILABLETEXTUREPACKS_TIMER_ID); // navigate to the settings scene app.NavigateToScene(ProfileManager.GetPrimaryPad(),eUIScene_LoadMenu, params); } } } } return S_OK; } HRESULT CScene_MultiGameJoinLoad::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: m_NetGamesListTimer.SetShow( FALSE ); app.NavigateBack(XUSER_INDEX_ANY); rfHandled = TRUE; break; case VK_PAD_X: // Change device // Fix for #12531 - TCR 001: BAS Game Stability: When a player selects to change a storage // device, and repeatedly backs out of the SD screen, disconnects from LIVE, and then selects a SD, the title crashes. m_bIgnoreInput=true; StorageManager.SetSaveDevice(&CScene_MultiGameJoinLoad::DeviceSelectReturned,this,true); CXuiSceneBase::PlayUISFX(eSFX_Press); break; case VK_PAD_Y: if(m_pGamesList->TreeHasFocus() && m_pGamesList->GetItemCount() > 0) { DWORD nIndex = m_pGamesList->GetCurSel(); FriendSessionInfo *pSelectedSession = currentSessions.at( nIndex ); PlayerUID xuid = pSelectedSession->data.hostPlayerUID; if( xuid != INVALID_XUID ) hr = XShowGamerCardUI(ProfileManager.GetLockedProfile(), xuid); CXuiSceneBase::PlayUISFX(eSFX_Press); } else if(DoesSavesListHaveFocus()) { // save transfer - make sure they want to overwrite a save that is up there if(ProfileManager.IsSignedInLive( m_iPad )) { // 4J-PB - required for a delete of the save if it's found to be a corrupted save DWORD nIndex = m_pSavesList->GetCurSel(); m_iChangingSaveGameInfoIndex=m_pSavesList->GetData(nIndex).iIndex; UINT uiIDA[2]; uiIDA[0]=IDS_UPLOAD_SAVE; uiIDA[1]=IDS_CONFIRM_CANCEL; ui.RequestMessageBox(IDS_SAVE_TRANSFER_TITLE, IDS_SAVE_TRANSFER_TEXT, uiIDA, 2, pInputData->UserIndex,&CScene_MultiGameJoinLoad::SaveTransferDialogReturned,this, app.GetStringTable()); } } break; case VK_PAD_RSHOULDER: if(DoesSavesListHaveFocus()) { m_bIgnoreInput = true; int iIndex=m_SavesList.GetCurSel(); m_iChangingSaveGameInfoIndex=m_pSavesList->GetData(iIndex).iIndex; // Could be delete save or Save Options if(StorageManager.GetSaveDisabled()) { // 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; StorageManager.RequestMessageBox(IDS_TOOLTIPS_DELETESAVE, IDS_TEXT_DELETE_SAVE, uiIDA, 2, pInputData->UserIndex,&CScene_MultiGameJoinLoad::DeleteSaveDialogReturned,this, app.GetStringTable()); } else { if(StorageManager.EnoughSpaceForAMinSaveGame()) { UINT uiIDA[3]; uiIDA[0]=IDS_CONFIRM_CANCEL; uiIDA[1]=IDS_TITLE_RENAMESAVE; uiIDA[2]=IDS_TOOLTIPS_DELETESAVE; StorageManager.RequestMessageBox(IDS_TOOLTIPS_SAVEOPTIONS, IDS_TEXT_SAVEOPTIONS, uiIDA, 3, pInputData->UserIndex,&CScene_MultiGameJoinLoad::SaveOptionsDialogReturned,this, app.GetStringTable()); } else { // 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; StorageManager.RequestMessageBox(IDS_TOOLTIPS_DELETESAVE, IDS_TEXT_DELETE_SAVE, uiIDA, 2, pInputData->UserIndex,&CScene_MultiGameJoinLoad::DeleteSaveDialogReturned,this, app.GetStringTable()); } } CXuiSceneBase::PlayUISFX(eSFX_Press); } else if(DoesMashUpWorldHaveFocus()) { // hiding a mash-up world // get the mash-up pack id CXuiControl pItem; int iIndex; iIndex=m_SavesList.GetCurSel(&pItem); CXuiCtrl4JList::LIST_ITEM_INFO info = m_pSavesList->GetData(iIndex); if((iIndex != JOIN_LOAD_CREATE_BUTTON_INDEX) && (info.iData >= 0)) { LevelGenerationOptions *levelGen = m_generators->at(info.iData); if(!levelGen->isTutorial()) { if(levelGen->requiresTexturePack()) { unsigned int uiPackID=levelGen->getRequiredTexturePackId(); m_bIgnoreInput = true; app.HideMashupPackWorld(m_iPad,uiPackID); // update the saves list m_pSavesList->RemoveAllData(); m_iSaveInfoC=0; GetSaveInfo(); m_bIgnoreInput = false; } } } CXuiSceneBase::PlayUISFX(eSFX_Press); } break; case VK_PAD_LSHOULDER: if( m_bInParty ) { m_bShowingPartyGamesOnly = !m_bShowingPartyGamesOnly; UpdateGamesList(); CXuiSceneBase::PlayUISFX(eSFX_Press); } break; } return hr; } HRESULT CScene_MultiGameJoinLoad::OnNavReturn(HXUIOBJ hSceneFrom,BOOL& rfHandled) { CXuiSceneBase::ShowLogo( DEFAULT_XUI_MENU_USER, TRUE ); // start the texture pack timer again XuiSetTimer(m_hObj,CHECKFORAVAILABLETEXTUREPACKS_TIMER_ID,CHECKFORAVAILABLETEXTUREPACKS_TIMER_TIME); m_bMultiplayerAllowed = ProfileManager.IsSignedInLive( m_iPad ) && ProfileManager.AllowedToPlayMultiplayer(m_iPad); // re-enable button presses m_bIgnoreInput=false; if( m_bMultiplayerAllowed ) { HXUICLASS hClassFullscreenProgress = XuiFindClass( L"CScene_FullscreenProgress" ); HXUICLASS hClassConnectingProgress = XuiFindClass( L"CScene_ConnectingProgress" ); // If we are navigating back from a full screen progress scene, then that means a connection attempt failed if( XuiIsInstanceOf( hSceneFrom, hClassFullscreenProgress ) || XuiIsInstanceOf( hSceneFrom, hClassConnectingProgress ) ) { UpdateGamesList(); } } else { m_pGamesList->RemoveAllData(); //m_GamesList.DeleteItems(0, m_GamesList.GetItemCount() ); m_pGamesList->SetEnable(FALSE); //XuiElementSetDisableFocusRecursion( m_pGamesList->m_hObj, TRUE); m_NetGamesListTimer.SetShow( TRUE ); m_LabelNoGames.SetShow( FALSE ); m_SavesList.InitFocus(m_iPad); } // are we back here because of a delete of a corrupt save? if(app.GetCorruptSaveDeleted()) { // need to re-get the saves list and update the display // clear the saves list m_pSavesList->RemoveAllData(); m_iSaveInfoC=0; GetSaveInfo(); app.SetCorruptSaveDeleted(false); } int iY = -1; int iRB=-1; if( DoesGamesListHaveFocus() ) { iY = IDS_TOOLTIPS_VIEW_GAMERCARD; } else if(DoesSavesListHaveFocus()) { if(ProfileManager.IsSignedInLive( m_iPad )) { iY=IDS_TOOLTIPS_UPLOAD_SAVE_FOR_XBOXONE; } if(StorageManager.GetSaveDisabled()) { iRB=IDS_TOOLTIPS_DELETESAVE; } else { // 4J-PB - we need to check that there is enough space left to create a copy of the save (for a rename) if(StorageManager.EnoughSpaceForAMinSaveGame()) { iRB=IDS_TOOLTIPS_SAVEOPTIONS; } else { iRB=IDS_TOOLTIPS_DELETESAVE; } } } else if(DoesMashUpWorldHaveFocus()) { // If it's a mash-up pack world, give the Hide option iRB=IDS_TOOLTIPS_HIDE; } int iLB = -1; if(m_bInParty) { if( m_bShowingPartyGamesOnly ) iLB = IDS_TOOLTIPS_ALL_GAMES; else iLB = IDS_TOOLTIPS_PARTY_GAMES; } if(ProfileManager.IsFullVersion()==false ) { ui.SetTooltips( DEFAULT_XUI_MENU_USER, IDS_TOOLTIPS_SELECT, IDS_TOOLTIPS_BACK, -1, -1,-1,-1,iLB); } else if(StorageManager.GetSaveDisabled()) { // clear out the saves list, since the disable save may have happened in the load screen because of a device removal ui.SetTooltips( DEFAULT_XUI_MENU_USER, IDS_TOOLTIPS_SELECT,IDS_TOOLTIPS_BACK,IDS_TOOLTIPS_SELECTDEVICE,iY,-1,-1,iLB,iRB); } else { ui.SetTooltips( DEFAULT_XUI_MENU_USER, IDS_TOOLTIPS_SELECT, IDS_TOOLTIPS_BACK, IDS_TOOLTIPS_CHANGEDEVICE, iY,-1,-1,iLB,iRB); } return S_OK; } HRESULT CScene_MultiGameJoinLoad::OnNotifySelChanged(HXUIOBJ hObjSource, XUINotifySelChanged *pNotifySelChangedData, BOOL& bHandled) { if(m_bReady) { CXuiSceneBase::PlayUISFX(eSFX_Focus); } return S_OK; } HRESULT CScene_MultiGameJoinLoad::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); KillTimer(JOIN_LOAD_ONLINE_TIMER_ID); } else if(pTransition->dwTransType == XUI_TRANSITION_TO || pTransition->dwTransType == XUI_TRANSITION_BACKTO) { SetTimer(JOIN_LOAD_ONLINE_TIMER_ID,JOIN_LOAD_ONLINE_TIMER_TIME); // 4J-PB - Need to check for installed DLC, which might have happened while you were on the info scene if(pTransition->dwTransType == XUI_TRANSITION_BACKTO) { // Can't call this here because if you back out of the load info screen and then go back in and load a game, it will attempt to use the dlc as it's running a mount of the dlc // 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)==false) { // not doing a mount, so re-enable input m_bIgnoreInput=false; } else { m_bIgnoreInput=true; m_pSavesList->RemoveAllData(); m_SavesListTimer.SetShow( TRUE ); } } } return S_OK; } HRESULT CScene_MultiGameJoinLoad::OnFontRendererChange() { // update the tooltips // if the saves list has focus, then we should show the Delete Save tooltip // if the games list has focus, then we should the the View Gamercard tooltip int iRB=-1; int iY = -1; if( DoesGamesListHaveFocus() ) { iY = IDS_TOOLTIPS_VIEW_GAMERCARD; } else if(DoesSavesListHaveFocus()) { if(ProfileManager.IsSignedInLive( m_iPad )) { iY=IDS_TOOLTIPS_UPLOAD_SAVE_FOR_XBOXONE; } if(StorageManager.GetSaveDisabled()) { iRB=IDS_TOOLTIPS_DELETESAVE; } else { if(StorageManager.EnoughSpaceForAMinSaveGame()) { iRB=IDS_TOOLTIPS_SAVEOPTIONS; } else { iRB=IDS_TOOLTIPS_DELETESAVE; } } } else if(DoesMashUpWorldHaveFocus()) { // If it's a mash-up pack world, give the Hide option iRB=IDS_TOOLTIPS_HIDE; } int iLB = -1; if(m_bInParty) { if( m_bShowingPartyGamesOnly ) iLB = IDS_TOOLTIPS_ALL_GAMES; else iLB = IDS_TOOLTIPS_PARTY_GAMES; } if(ProfileManager.IsFullVersion()==false ) { ui.SetTooltips( DEFAULT_XUI_MENU_USER, IDS_TOOLTIPS_SELECT, IDS_TOOLTIPS_BACK, -1, iY,-1,-1,iLB,-1,-1,true); } else if(StorageManager.GetSaveDisabled()) { ui.SetTooltips( DEFAULT_XUI_MENU_USER, IDS_TOOLTIPS_SELECT,IDS_TOOLTIPS_BACK,IDS_TOOLTIPS_SELECTDEVICE,iY,-1,-1,iLB,iRB,-1,true); } else { ui.SetTooltips( DEFAULT_XUI_MENU_USER, IDS_TOOLTIPS_SELECT, IDS_TOOLTIPS_BACK, IDS_TOOLTIPS_CHANGEDEVICE, iY,-1,-1,iLB,iRB,-1,true); } return S_OK; } HRESULT CScene_MultiGameJoinLoad::OnNotifySetFocus(HXUIOBJ hObjSource, XUINotifyFocus *pNotifyFocusData, BOOL& bHandled) { // update the tooltips // if the saves list has focus, then we should show the Delete Save tooltip // if the games list has focus, then we should the the View Gamercard tooltip int iRB=-1; int iY = -1; if( DoesGamesListHaveFocus() ) { iY = IDS_TOOLTIPS_VIEW_GAMERCARD; } else if(DoesSavesListHaveFocus()) { if(ProfileManager.IsSignedInLive( m_iPad )) { iY=IDS_TOOLTIPS_UPLOAD_SAVE_FOR_XBOXONE; } if(StorageManager.GetSaveDisabled()) { iRB=IDS_TOOLTIPS_DELETESAVE; } else { if(StorageManager.EnoughSpaceForAMinSaveGame()) { iRB=IDS_TOOLTIPS_SAVEOPTIONS; } else { iRB=IDS_TOOLTIPS_DELETESAVE; } } } else if(DoesMashUpWorldHaveFocus()) { // If it's a mash-up pack world, give the Hide option iRB=IDS_TOOLTIPS_HIDE; } int iLB = -1; if(m_bInParty) { if( m_bShowingPartyGamesOnly ) iLB = IDS_TOOLTIPS_ALL_GAMES; else iLB = IDS_TOOLTIPS_PARTY_GAMES; } if(ProfileManager.IsFullVersion()==false ) { ui.SetTooltips( DEFAULT_XUI_MENU_USER, IDS_TOOLTIPS_SELECT, IDS_TOOLTIPS_BACK, -1, iY,-1,-1,iLB,-1); } else if(StorageManager.GetSaveDisabled()) { ui.SetTooltips( DEFAULT_XUI_MENU_USER, IDS_TOOLTIPS_SELECT,IDS_TOOLTIPS_BACK,IDS_TOOLTIPS_SELECTDEVICE,iY,-1,-1,iLB,iRB); } else { ui.SetTooltips( DEFAULT_XUI_MENU_USER, IDS_TOOLTIPS_SELECT, IDS_TOOLTIPS_BACK, IDS_TOOLTIPS_CHANGEDEVICE, iY,-1,-1,iLB,iRB); } return S_OK; } HRESULT CScene_MultiGameJoinLoad::OnNotifyKillFocus(HXUIOBJ hObjSource, XUINotifyFocus *pNotifyFocusData, BOOL& bHandled) { return S_OK; } bool CScene_MultiGameJoinLoad::DoesSavesListHaveFocus() { HXUIOBJ hParentObj,hObj=TreeGetFocus(); if(hObj!=NULL) { // get the parent and see if it's the saves list XuiElementGetParent(hObj,&hParentObj); if(hParentObj==m_SavesList.m_hObj) { // check it's not the first or second element (new world or tutorial) if(m_SavesList.GetCurSel()>(m_iDefaultButtonsC-1)) { return true; } } } return false; } bool CScene_MultiGameJoinLoad::DoesMashUpWorldHaveFocus() { HXUIOBJ hParentObj,hObj=TreeGetFocus(); if(hObj!=NULL) { // get the parent and see if it's the saves list XuiElementGetParent(hObj,&hParentObj); if(hParentObj==m_SavesList.m_hObj) { // check it's not the first or second element (new world or tutorial) if(m_SavesList.GetCurSel()>(m_iDefaultButtonsC-1)) { return false; } if(m_SavesList.GetCurSel()>(m_iDefaultButtonsC - 1 - m_iMashUpButtonsC)) { return true; } else return false; } else return false; } return false; } bool CScene_MultiGameJoinLoad::DoesGamesListHaveFocus() { HXUIOBJ hParentObj,hObj=TreeGetFocus(); if(hObj!=NULL) { // get the parent and see if it's the saves list XuiElementGetParent(hObj,&hParentObj); if(hParentObj==m_pGamesList->m_hObj) { return true; } } return false; } void CScene_MultiGameJoinLoad::UpdateGamesListCallback(LPVOID lpParam) { if(lpParam != NULL) { CScene_MultiGameJoinLoad* pClass = (CScene_MultiGameJoinLoad *) lpParam; // check this there's no save transfer in progress if(!pClass->m_bSaveTransferInProgress) { pClass->UpdateGamesList(); } } } void CScene_MultiGameJoinLoad::UpdateGamesList() { if( m_bIgnoreInput ) return; // if we're retrieving save info, don't show the list yet as we will be ignoring press events if(m_bRetrievingSaveInfo) { return; } DWORD nIndex = -1; FriendSessionInfo *pSelectedSession = NULL; if(m_pGamesList->TreeHasFocus() && m_pGamesList->GetItemCount() > 0) { nIndex = m_pGamesList->GetCurSel(); pSelectedSession = currentSessions.at( nIndex ); } SessionID selectedSessionId; if( pSelectedSession != NULL )selectedSessionId = pSelectedSession->sessionId; pSelectedSession = NULL; for(AUTO_VAR(it, currentSessions.begin()); it < currentSessions.end(); ++it) { delete (*it); } currentSessions.clear(); m_NetGamesListTimer.SetShow( FALSE ); // if the saves list has focus, then we should show the Delete Save tooltip // if the games list has focus, then we should show the View Gamercard tooltip int iRB=-1; int iY = -1; if( DoesGamesListHaveFocus() ) { iY = IDS_TOOLTIPS_VIEW_GAMERCARD; } else if(DoesSavesListHaveFocus()) { if(ProfileManager.IsSignedInLive( m_iPad )) { iY=IDS_TOOLTIPS_UPLOAD_SAVE_FOR_XBOXONE; } if(StorageManager.GetSaveDisabled()) { iRB=IDS_TOOLTIPS_DELETESAVE; } else { if(StorageManager.EnoughSpaceForAMinSaveGame()) { iRB=IDS_TOOLTIPS_SAVEOPTIONS; } else { iRB=IDS_TOOLTIPS_DELETESAVE; } } } else if(DoesMashUpWorldHaveFocus()) { // If it's a mash-up pack world, give the Hide option iRB=IDS_TOOLTIPS_HIDE; } int iLB = -1; if(m_bInParty) { if( m_bShowingPartyGamesOnly ) iLB = IDS_TOOLTIPS_ALL_GAMES; else iLB = IDS_TOOLTIPS_PARTY_GAMES; } if(ProfileManager.IsFullVersion()==false ) { ui.SetTooltips( DEFAULT_XUI_MENU_USER, IDS_TOOLTIPS_SELECT, IDS_TOOLTIPS_BACK, -1, iY,-1,-1,iLB,-1); } else if(StorageManager.GetSaveDisabled()) { ui.SetTooltips( DEFAULT_XUI_MENU_USER, IDS_TOOLTIPS_SELECT,IDS_TOOLTIPS_BACK,IDS_TOOLTIPS_SELECTDEVICE,iY,-1,-1,iLB,iRB); } else { ui.SetTooltips( DEFAULT_XUI_MENU_USER, IDS_TOOLTIPS_SELECT, IDS_TOOLTIPS_BACK, IDS_TOOLTIPS_CHANGEDEVICE, iY,-1,-1,iLB,iRB); } currentSessions = *g_NetworkManager.GetSessionList( m_iPad, m_localPlayers, m_bShowingPartyGamesOnly ); // Update the xui list displayed unsigned int xuiListSize = m_pGamesList->GetItemCount(); unsigned int filteredListSize = (unsigned int)currentSessions.size(); BOOL gamesListHasFocus = m_pGamesList->TreeHasFocus(); if(filteredListSize > 0) { if( !m_pGamesList->IsEnabled() ) { m_pGamesList->SetEnable(TRUE); //XuiElementSetDisableFocusRecursion( m_pGamesList->m_hObj, FALSE); m_pGamesList->SetCurSel( 0 ); } m_LabelNoGames.SetShow( FALSE ); m_NetGamesListTimer.SetShow( FALSE ); } else { m_pGamesList->SetEnable(FALSE); //XuiElementSetDisableFocusRecursion(m_pGamesList->m_hObj, TRUE); m_NetGamesListTimer.SetShow( FALSE ); m_LabelNoGames.SetShow( TRUE ); if( gamesListHasFocus ) m_pGamesList->InitFocus(m_iPad); } // clear out the games list and re-fill m_pGamesList->RemoveAllData(); if( filteredListSize > 0 ) { // Reset the focus to the selected session if it still exists unsigned int sessionIndex = 0; m_pGamesList->SetCurSel(0); for( AUTO_VAR(it, currentSessions.begin()); it < currentSessions.end(); ++it) { FriendSessionInfo *sessionInfo = *it; HXUIBRUSH hXuiBrush; CXuiCtrl4JList::LIST_ITEM_INFO ListInfo; ZeroMemory(&ListInfo,sizeof(CXuiCtrl4JList::LIST_ITEM_INFO)); ListInfo.pwszText = sessionInfo->displayLabel; ListInfo.fEnabled = TRUE; ListInfo.iData = sessionIndex; m_pGamesList->AddData(ListInfo); // display an icon too // Is this a default game or a texture pack game? if(sessionInfo->data.texturePackParentId!=0) { // Do we have the texture pack Minecraft *pMinecraft = Minecraft::GetInstance(); TexturePack *tp = pMinecraft->skins->getTexturePackById(sessionInfo->data.texturePackParentId); HRESULT hr; DWORD dwImageBytes=0; PBYTE pbImageData=NULL; if(tp==NULL) { DWORD dwBytes=0; PBYTE pbData=NULL; app.GetTPD(sessionInfo->data.texturePackParentId,&pbData,&dwBytes); // is it in the tpd data ? app.GetFileFromTPD(eTPDFileType_Icon,pbData,dwBytes,&pbImageData,&dwImageBytes ); if(dwImageBytes > 0 && pbImageData) { hr=XuiCreateTextureBrushFromMemory(pbImageData,dwImageBytes,&hXuiBrush); m_pGamesList->UpdateGraphic(sessionIndex,hXuiBrush); } } else { pbImageData = tp->getPackIcon(dwImageBytes); if(dwImageBytes > 0 && pbImageData) { hr=XuiCreateTextureBrushFromMemory(pbImageData,dwImageBytes,&hXuiBrush); m_pGamesList->UpdateGraphic(sessionIndex,hXuiBrush); } } } else { // default texture pack XuiCreateTextureBrushFromMemory(m_DefaultMinecraftIconData,m_DefaultMinecraftIconSize,&hXuiBrush); m_pGamesList->UpdateGraphic(sessionIndex,hXuiBrush); } if(memcmp( &selectedSessionId, &sessionInfo->sessionId, sizeof(SessionID) ) == 0) { m_pGamesList->SetCurSel(sessionIndex); break; } ++sessionIndex; } } } void CScene_MultiGameJoinLoad::UpdateGamesList(DWORD dwNumResults, IQNetGameSearch *pGameSearch) { // We don't use the QNet callback, but could resurrect this if we ever do normal matchmaking, but updated to work as the function above #if 0 const XSESSION_SEARCHRESULT *pSearchResult; const XNQOSINFO * pxnqi; if(m_searches>0) --m_searches; if(m_searches==0) { m_NetGamesListTimer.SetShow( FALSE ); // if the saves list has focus, then we should show the Delete Save tooltip // if the games list has focus, then we should show the View Gamercard tooltip int iRB=-1; int iY = -1; if( DoesGamesListHaveFocus() ) { iY = IDS_TOOLTIPS_VIEW_GAMERCARD; } else if(DoesSavesListHaveFocus()) { iRB=IDS_TOOLTIPS_DELETESAVE; } int iLB = -1; if(m_bInParty) { if( m_bShowingPartyGamesOnly ) iLB = IDS_TOOLTIPS_ALL_GAMES else iLB = IDS_TOOLTIPS_PARTY_GAMES; } if(ProfileManager.IsFullVersion()==false ) { ui.SetTooltips( DEFAULT_XUI_MENU_USER, IDS_TOOLTIPS_SELECT, IDS_TOOLTIPS_BACK, -1, iY,-1,-1,iLB,iRB); } else if(StorageManager.GetSaveDisabled()) { ui.SetTooltips( DEFAULT_XUI_MENU_USER, IDS_TOOLTIPS_SELECT,IDS_TOOLTIPS_BACK,IDS_TOOLTIPS_SELECTDEVICE,iY,-1,-1,iLB,iRB); } else { ui.SetTooltips( DEFAULT_XUI_MENU_USER, IDS_TOOLTIPS_SELECT, IDS_TOOLTIPS_BACK, IDS_TOOLTIPS_CHANGEDEVICE, iY,-1,-1,iLB,iRB); } } if( dwNumResults == 0 ) { if(m_searches==0 && m_GamesList.GetItemCount() == 0) { m_LabelNoGames.SetShow( TRUE ); } return; } unsigned int startOffset = m_GamesList.GetItemCount(); //m_GamesList.InsertItems(startOffset,dwNumResults); //m_GamesList.SetEnable(TRUE); //XuiElementSetDisableFocusRecursion( m_GamesList.m_hObj, FALSE); // Loop through all the results. for( DWORD dwResult = 0; dwResult < pGameSearch->GetNumResults(); dwResult++ ) { pSearchResult = pGameSearch->GetSearchResultAtIndex( dwResult ); // No room for us, so ignore it if(pSearchResult->dwOpenPublicSlots < m_localPlayers) continue; FriendSessionInfo *sessionInfo = NULL; bool foundSession = false; for(AUTO_VAR(it, friendsSessions.begin()); it < friendsSessions.end(); ++it) { sessionInfo = *it; if(memcmp( &pSearchResult->info.sessionID, &sessionInfo->sessionId, sizeof(SessionID) ) == 0) { sessionInfo->searchResult = *pSearchResult; sessionInfo->displayLabel = new wchar_t[100]; foundSession = true; break; } } // We received a search result for a session no longer in our list of friends sessions if(!foundSession) continue; // Print some info about this result. //printf( "Search result %u:\n", dwResult ); //printf( " public slots open = %u, filled = %u\n", pSearchResult->dwOpenPublicSlots, pSearchResult->dwFilledPublicSlots ); //printf( " private slots open = %u, filled = %u\n", pSearchResult->dwOpenPrivateSlots, pSearchResult->dwFilledPrivateSlots ); // See if this result was contacted successfully via QoS probes. pxnqi = pGameSearch->GetQosInfoAtIndex( dwResult ); if( pxnqi->bFlags & XNET_XNQOSINFO_TARGET_CONTACTED ) { // Print the round trip time and the rough estimation of // bandwidth. app.DebugPrintf( " RTT min = %u, med = %u\n", pxnqi->wRttMinInMsecs, pxnqi->wRttMedInMsecs ); app.DebugPrintf( " bps up = %u, down = %u\n", pxnqi->dwUpBitsPerSec, pxnqi->dwDnBitsPerSec ); if(pxnqi->cbData > 0) { sessionInfo->data = *(GameSessionData *)pxnqi->pbData; wstring gamerName = convStringToWstring(sessionInfo->data.hostName); swprintf(sessionInfo->displayLabel,L"%ls's Game", gamerName.c_str() ); } else { swprintf(sessionInfo->displayLabel,L"Unknown host Game"); } // If this host wasn't disabled use this one. if( !( pxnqi->bFlags & XNET_XNQOSINFO_TARGET_DISABLED ) && sessionInfo->data.netVersion == MINECRAFT_NET_VERSION ) { //printf("This game is valid\n"); filteredResults.push_back(sessionInfo); m_GamesList.InsertItems(startOffset,1); m_GamesList.SetText(startOffset,sessionInfo->displayLabel); startOffset++; } #ifndef _CONTENT_PACKAGE if( sessionInfo->data.netVersion != MINECRAFT_NET_VERSION ) { wprintf(L"%ls version of %d does not match our version of %d\n", sessionInfo->displayLabel, sessionInfo->data.netVersion, MINECRAFT_NET_VERSION); } #endif } } if( m_GamesList.GetItemCount() == 0) { m_LabelNoGames.SetShow( TRUE ); } else { m_GamesList.SetEnable(TRUE); XuiElementSetDisableFocusRecursion( m_GamesList.m_hObj, FALSE); if( DoesGamesListHaveFocus() ) { m_GamesList.SetCurSel(0); } } #endif } /*void CScene_MultiGameJoinLoad::UpdateGamesListLabels() { for( unsigned int i = 0; i < currentSessions.size(); ++i ) { FriendSessionInfo *sessionInfo = currentSessions.at(i); m_GamesList.SetText(i,sessionInfo->displayLabel); HXUIBRUSH hBrush; CXuiCtrl4JList::LIST_ITEM_INFO info = m_pGamesList->GetData(i); // display an icon too XuiCreateTextureBrushFromMemory(m_DefaultMinecraftIconData,m_DefaultMinecraftIconSize,&hBrush); m_pGamesList->UpdateGraphic(i,hBrush); } #if 0 XUIRect xuiRect; HXUIOBJ item = XuiListGetItemControl(m_GamesList,0); HXUIOBJ hObj=NULL; HXUIOBJ hTextPres=NULL; HRESULT hr=XuiControlGetVisual(item,&hObj); hr=XuiElementGetChildById(hObj,L"text_Label",&hTextPres); unsigned char displayLabelViewableStartIndex = 0; for( unsigned int i = 0; i < currentSessions.size(); ++i ) { FriendSessionInfo *sessionInfo = currentSessions.at(i); if(hTextPres != NULL ) { hr=XuiTextPresenterMeasureText(hTextPres, sessionInfo->displayLabel, &xuiRect); float fWidth, fHeight; XuiElementGetBounds(hTextPres,&fWidth,&fHeight); int characters = (fWidth/xuiRect.right) * sessionInfo->displayLabelLength; if( characters < sessionInfo->displayLabelLength ) { static wchar_t temp[100]; ZeroMemory(temp, (100)*sizeof(wchar_t)); wcsncpy_s( temp, sessionInfo->displayLabel+sessionInfo->displayLabelViewableStartIndex, characters ); m_GamesList.SetText(i,temp); sessionInfo->displayLabelViewableStartIndex++; if( sessionInfo->displayLabelViewableStartIndex >= sessionInfo->displayLabelLength ) sessionInfo->displayLabelViewableStartIndex = 0; } } } #endif }*/ void CScene_MultiGameJoinLoad::SearchForGameCallback(void *param, DWORD dwNumResults, IQNetGameSearch *pGameSearch) { #if 0 HXUIOBJ hObj = (HXUIOBJ)param; void *pObj; XuiObjectFromHandle( hObj, &pObj); CScene_MultiGameJoinLoad *MultiGameJoinLoad = (CScene_MultiGameJoinLoad *)pObj; MultiGameJoinLoad->UpdateGamesList(dwNumResults, pGameSearch); #endif } int CScene_MultiGameJoinLoad::DeviceSelectReturned(void *pParam,bool bContinue) { CScene_MultiGameJoinLoad* pClass = (CScene_MultiGameJoinLoad*)pParam; //HRESULT hr; if(bContinue==true) { // if the saves list has focus, then we should show the Delete Save tooltip // if the games list has focus, then we should show the View Gamercard tooltip int iRB=-1; int iY = -1; if( pClass->DoesGamesListHaveFocus() ) { iY = IDS_TOOLTIPS_VIEW_GAMERCARD; } else if(pClass->DoesSavesListHaveFocus()) { if(ProfileManager.IsSignedInLive( pClass->m_iPad )) { iY=IDS_TOOLTIPS_UPLOAD_SAVE_FOR_XBOXONE; } if(StorageManager.GetSaveDisabled()) { iRB=IDS_TOOLTIPS_DELETESAVE; } else { if(StorageManager.EnoughSpaceForAMinSaveGame()) { iRB=IDS_TOOLTIPS_SAVEOPTIONS; } else { iRB=IDS_TOOLTIPS_DELETESAVE; } } } else if(pClass->DoesMashUpWorldHaveFocus()) { // If it's a mash-up pack world, give the Hide option iRB=IDS_TOOLTIPS_HIDE; } int iLB = -1; if(pClass->m_bInParty) { if( pClass->m_bShowingPartyGamesOnly ) iLB = IDS_TOOLTIPS_ALL_GAMES; else iLB = IDS_TOOLTIPS_PARTY_GAMES; } //BOOL bOnlineGame=pClass->m_CheckboxOnline.IsChecked(); // refresh the saves list (if there is a device selected) // clear out the list first if(StorageManager.GetSaveDisabled()) { if(StorageManager.GetSaveDeviceSelected(pClass->m_iPad)) { ui.SetTooltips( DEFAULT_XUI_MENU_USER, IDS_TOOLTIPS_SELECT,IDS_TOOLTIPS_BACK,IDS_TOOLTIPS_CHANGEDEVICE,iY,-1,-1,iLB,iRB); // saving is disabled, but we should still be able to load from a selected save device pClass->GetSaveInfo(); } else { ui.SetTooltips( DEFAULT_XUI_MENU_USER, IDS_TOOLTIPS_SELECT,IDS_TOOLTIPS_BACK,IDS_TOOLTIPS_SELECTDEVICE,iY,-1,-1,iLB,iRB); // clear the saves list pClass->m_pSavesList->RemoveAllData(); pClass->m_iSaveInfoC=0; //pClass->m_iThumbnailsLoadedC=0; pClass->AddDefaultButtons(); pClass->m_SavesListTimer.SetShow( FALSE ); pClass->m_pSavesList->SetCurSelVisible(0); } } else { ui.SetTooltips( DEFAULT_XUI_MENU_USER, IDS_TOOLTIPS_SELECT,IDS_TOOLTIPS_BACK,IDS_TOOLTIPS_CHANGEDEVICE,iY,-1,-1,iLB,iRB); pClass->GetSaveInfo(); } } // enable input again pClass->m_bIgnoreInput=false; return 0; } HRESULT CScene_MultiGameJoinLoad::OnTimer( XUIMessageTimer *pTimer, BOOL& bHandled ) { // 4J-PB - TODO - Don't think we can do this - if a 2nd player signs in here with an offline profile, the signed in LIVE player gets re-logged in, and bMultiplayerAllowed is false briefly switch(pTimer->nId) { case JOIN_LOAD_ONLINE_TIMER_ID: { XPARTY_USER_LIST partyList; if((XPartyGetUserList( &partyList ) != XPARTY_E_NOT_IN_PARTY ) && (partyList.dwUserCount>1)) { m_bInParty=true; } else { m_bInParty=false; } bool bMultiplayerAllowed = ProfileManager.IsSignedInLive( m_iPad ) && ProfileManager.AllowedToPlayMultiplayer(m_iPad); if(bMultiplayerAllowed != m_bMultiplayerAllowed) { if( bMultiplayerAllowed ) { // m_CheckboxOnline.SetEnable(TRUE); // m_CheckboxPrivate.SetEnable(TRUE); } else { m_bInParty = false; m_pGamesList->RemoveAllData(); //m_GamesList.DeleteItems(0, m_GamesList.GetItemCount() ); m_pGamesList->SetEnable(FALSE); //XuiElementSetDisableFocusRecursion( m_pGamesList->m_hObj, TRUE); m_NetGamesListTimer.SetShow( TRUE ); m_LabelNoGames.SetShow( FALSE ); } int iLB = -1; if(m_bInParty) { if( m_bShowingPartyGamesOnly ) iLB = IDS_TOOLTIPS_ALL_GAMES; else iLB = IDS_TOOLTIPS_PARTY_GAMES; } int iRB=-1; int iY=-1; if( DoesGamesListHaveFocus() ) { } else if(DoesSavesListHaveFocus()) { if(ProfileManager.IsSignedInLive( m_iPad )) { iY=IDS_TOOLTIPS_UPLOAD_SAVE_FOR_XBOXONE; } if(StorageManager.GetSaveDisabled()) { iRB=IDS_TOOLTIPS_DELETESAVE; } else { if(StorageManager.EnoughSpaceForAMinSaveGame()) { iRB=IDS_TOOLTIPS_SAVEOPTIONS; } else { iRB=IDS_TOOLTIPS_DELETESAVE; } } } else if(DoesMashUpWorldHaveFocus()) { // If it's a mash-up pack world, give the Hide option iRB=IDS_TOOLTIPS_HIDE; } if(ProfileManager.IsFullVersion()==false ) { ui.SetTooltips( DEFAULT_XUI_MENU_USER, IDS_TOOLTIPS_SELECT, IDS_TOOLTIPS_BACK, -1, -1,-1,-1,iLB); } else if(StorageManager.GetSaveDisabled()) { ui.SetTooltips( DEFAULT_XUI_MENU_USER, IDS_TOOLTIPS_SELECT,IDS_TOOLTIPS_BACK,IDS_TOOLTIPS_SELECTDEVICE,-1,-1,-1,iLB,iRB); } else { ui.SetTooltips( DEFAULT_XUI_MENU_USER, IDS_TOOLTIPS_SELECT, IDS_TOOLTIPS_BACK, IDS_TOOLTIPS_CHANGEDEVICE,iY,-1,-1,iLB,iRB); } m_bMultiplayerAllowed = bMultiplayerAllowed; } } break; case JOIN_LOAD_SEARCH_MINIMUM_TIMER_ID: { XuiKillTimer( m_hObj, JOIN_LOAD_SEARCH_MINIMUM_TIMER_ID ); m_NetGamesListTimer.SetShow( FALSE ); m_LabelNoGames.SetShow( TRUE ); } break; case JOIN_LOAD_SCROLL_GAME_NAMES_TIMER_ID: { // This is called by the gameslist callback function, so isn't needed on a timer //UpdateGamesListLabels(); } break; case CHECKFORAVAILABLETEXTUREPACKS_TIMER_ID: { // also check for any new texture packs info being available // for each item in the mem list, check it's in the data list //CXuiCtrl4JList::LIST_ITEM_INFO ListInfo; // for each iConfig, check if the data is available, and add it to the List, then remove it from the viConfig for(int i=0;i 0 && pbData) { //update the games list UpdateGamesList(); m_iConfigA[i]=-1; } } } bool bAllDone=true; for(int i=0;im_bIgnoreInput=false; } return 0; } */ int CScene_MultiGameJoinLoad::StartGame_SignInReturned(void *pParam,bool bContinue, int iPad) { CScene_MultiGameJoinLoad* pClass = (CScene_MultiGameJoinLoad*)pParam; if(bContinue==true) { // It's possible that the player has not signed in - they can back out if(ProfileManager.IsSignedIn(iPad)) { DWORD dwLocalUsersMask = 0; for(unsigned int index = 0; index < XUSER_MAX_COUNT; ++index) { if(ProfileManager.IsSignedIn(index) ) { dwLocalUsersMask |= CGameNetworkManager::GetLocalPlayerMask(index); } } StartGameFromSave(pClass, dwLocalUsersMask); } } else { pClass->m_bIgnoreInput=false; } return 0; } // 4J Stu - Shared functionality that is the same whether we needed a quadrant sign-in or not void CScene_MultiGameJoinLoad::StartGameFromSave(CScene_MultiGameJoinLoad* pClass, DWORD dwLocalUsersMask) { /*bool isClientSide = ProfileManager.IsSignedInLive(ProfileManager.GetPrimaryPad()) && pClass->m_CheckboxOnline.IsChecked() == TRUE; //bool isPrivate = pClass->m_CheckboxPrivate.IsChecked() == TRUE; SenStatGameEvent(ProfileManager.GetPrimaryPad(),eTelemetryGameEvent_Load,Minecraft::GetInstance()->options->difficulty, isClientSide, ProfileManager.IsFullVersion(), 1,0 ); g_NetworkManager.HostGame(dwLocalUsersMask,isClientSide,isPrivate,MINECRAFT_NET_MAX_PLAYERS,0); LoadingInputParams *loadingParams = new LoadingInputParams(); loadingParams->func = &CGameNetworkManager::RunNetworkGameThreadProc; loadingParams->lpParam = NULL; UIFullscreenProgressCompletionData *completionData = new UIFullscreenProgressCompletionData(); completionData->bShowBackground=TRUE; completionData->bShowLogo=TRUE; completionData->type = e_ProgressCompletion_CloseAllPlayersUIScenes; completionData->iPad = DEFAULT_XUI_MENU_USER; loadingParams->completionData = completionData; app.NavigateToScene(ProfileManager.GetPrimaryPad(),eUIScene_FullscreenProgress, loadingParams);*/ } int CScene_MultiGameJoinLoad::DeleteSaveDataReturned(void *pParam,bool bSuccess) { CScene_MultiGameJoinLoad* pClass = (CScene_MultiGameJoinLoad*)pParam; if(bSuccess==true) { // need to re-get the saves list and update the display // clear the saves list pClass->m_pSavesList->RemoveAllData(); pClass->m_iSaveInfoC=0; pClass->GetSaveInfo(); } pClass->m_bIgnoreInput=false; return 0; } void CScene_MultiGameJoinLoad::LoadLevelGen(LevelGenerationOptions *levelGen) { // Load data from disc //File saveFile( L"Tutorial\\Tutorial" ); //LoadSaveFromDisk(&saveFile); // clear out the app's terrain features list app.ClearTerrainFeaturePosition(); StorageManager.ResetSaveData(); // Make our next save default to the name of the level StorageManager.SetSaveTitle(levelGen->getDefaultSaveName().c_str()); bool isClientSide = false; bool isPrivate = false; int maxPlayers = MINECRAFT_NET_MAX_PLAYERS; if( app.GetTutorialMode() ) { isClientSide = false; maxPlayers = 4; } g_NetworkManager.HostGame(0,isClientSide,isPrivate,maxPlayers,0); NetworkGameInitData *param = new NetworkGameInitData(); param->seed = 0; param->saveData = NULL; param->settings = app.GetGameHostOption( eGameHostOption_Tutorial ); param->levelGen = levelGen; if(levelGen->requiresTexturePack()) { param->texturePackId = levelGen->getRequiredTexturePackId(); Minecraft *pMinecraft = Minecraft::GetInstance(); pMinecraft->skins->selectTexturePackById(param->texturePackId); //pMinecraft->skins->updateUI(); } LoadingInputParams *loadingParams = new LoadingInputParams(); loadingParams->func = &CGameNetworkManager::RunNetworkGameThreadProc; loadingParams->lpParam = (LPVOID)param; UIFullscreenProgressCompletionData *completionData = new UIFullscreenProgressCompletionData(); completionData->bShowBackground=TRUE; completionData->bShowLogo=TRUE; completionData->type = e_ProgressCompletion_CloseAllPlayersUIScenes; completionData->iPad = DEFAULT_XUI_MENU_USER; loadingParams->completionData = completionData; app.NavigateToScene(ProfileManager.GetPrimaryPad(),eUIScene_FullscreenProgress, loadingParams); } void CScene_MultiGameJoinLoad::LoadSaveFromDisk(File *saveFile) { // we'll only be coming in here when the tutorial is loaded now StorageManager.ResetSaveData(); // Make our next save default to the name of the level StorageManager.SetSaveTitle(saveFile->getName().c_str()); int64_t fileSize = saveFile->length(); FileInputStream fis(*saveFile); byteArray ba(fileSize); fis.read(ba); fis.close(); bool isClientSide = false; bool isPrivate = false; int maxPlayers = MINECRAFT_NET_MAX_PLAYERS; if( app.GetTutorialMode() ) { isClientSide = false; maxPlayers = 4; } app.SetGameHostOption(eGameHostOption_GameType,GameType::CREATIVE->getId()); g_NetworkManager.HostGame(0,isClientSide,isPrivate,maxPlayers,0); LoadSaveDataThreadParam *saveData = new LoadSaveDataThreadParam(ba.data, ba.length, saveFile->getName()); NetworkGameInitData *param = new NetworkGameInitData(); param->seed = 0; param->saveData = saveData; param->settings = app.GetGameHostOption( eGameHostOption_All ); LoadingInputParams *loadingParams = new LoadingInputParams(); loadingParams->func = &CGameNetworkManager::RunNetworkGameThreadProc; loadingParams->lpParam = (LPVOID)param; UIFullscreenProgressCompletionData *completionData = new UIFullscreenProgressCompletionData(); completionData->bShowBackground=TRUE; completionData->bShowLogo=TRUE; completionData->type = e_ProgressCompletion_CloseAllPlayersUIScenes; completionData->iPad = DEFAULT_XUI_MENU_USER; loadingParams->completionData = completionData; app.NavigateToScene(ProfileManager.GetPrimaryPad(),eUIScene_FullscreenProgress, loadingParams); } int CScene_MultiGameJoinLoad::DeleteSaveDialogReturned(void *pParam,int iPad,C4JStorage::EMessageResult result) { CScene_MultiGameJoinLoad* pClass = (CScene_MultiGameJoinLoad*)pParam; // results switched for this dialog if(result==C4JStorage::EMessage_ResultDecline) { if(app.DebugSettingsOn() && app.GetLoadSavesFromFolderEnabled()) { pClass->m_bIgnoreInput=false; } else { XCONTENT_DATA XContentData; StorageManager.GetSaveCacheFileInfo(pClass->m_iChangingSaveGameInfoIndex-pClass->m_iDefaultButtonsC,XContentData); StorageManager.DeleteSaveData(&XContentData,CScene_MultiGameJoinLoad::DeleteSaveDataReturned,pClass); pClass->m_SavesListTimer.SetShow( TRUE ); } } else { pClass->m_bIgnoreInput=false; } return 0; } int CScene_MultiGameJoinLoad::SaveTransferDialogReturned(void *pParam,int iPad,C4JStorage::EMessageResult result) { CScene_MultiGameJoinLoad* pClass = (CScene_MultiGameJoinLoad*)pParam; // results switched for this dialog if(result==C4JStorage::EMessage_ResultAccept) { // upload the save // first load the save int iIndex=pClass->m_pSavesList->GetData(pClass->m_pSavesList->GetCurSel()).iIndex-pClass->m_iDefaultButtonsC; XCONTENT_DATA ContentData; // 4J-PB - ensure we've switched to the right title group id for uploading to app.TMSPP_SetTitleGroupID(SAVETRANSFER_GROUP_ID); StorageManager.GetSaveCacheFileInfo(iIndex,ContentData); C4JStorage::ELoadGameStatus eLoadStatus=StorageManager.LoadSaveData(&ContentData,CScene_MultiGameJoinLoad::LoadSaveDataReturned,pClass); pClass->m_bIgnoreInput=false; } else { pClass->m_bIgnoreInput=false; } return 0; } int CScene_MultiGameJoinLoad::UploadSaveForXboxOneThreadProc( LPVOID lpParameter ) { CScene_MultiGameJoinLoad* pClass = (CScene_MultiGameJoinLoad *) lpParameter; Minecraft *pMinecraft = Minecraft::GetInstance(); pMinecraft->progressRenderer->progressStart(IDS_SAVE_TRANSFER_TITLE); pMinecraft->progressRenderer->progressStage( IDS_SAVE_TRANSFER_UPLOADING ); // Delete the marker file DeleteFile(pClass, "completemarker"); if(!WaitForTransferComplete(pClass)) return 0; // Upload the save data { unsigned int uiSaveBytes; uiSaveBytes=StorageManager.GetSaveSize(); pClass->m_pbSaveTransferData=new BYTE [uiSaveBytes]; StorageManager.GetSaveData(pClass->m_pbSaveTransferData,&uiSaveBytes); app.DebugPrintf("Uploading save data (%d bytes)\n", uiSaveBytes); UploadFile(pClass, "savedata", pClass->m_pbSaveTransferData, uiSaveBytes); } if(!WaitForTransferComplete(pClass)) return 0; if(pClass->m_bTransferFail) { // something went wrong, user has been informed pMinecraft->progressRenderer->progressStage( IDS_SAVE_TRANSFER_UPLOADFAILED ); return 0; } // Upload the metadata and thumbnail { ByteArrayOutputStream baos; DataOutputStream dos(&baos); LPCWSTR title = StorageManager.GetSaveTitle(); dos.writeUTF(title); char szUniqueMapName[14]; StorageManager.GetSaveUniqueFilename(szUniqueMapName); dos.writeUTF(convStringToWstring(szUniqueMapName)); { // set the save icon PBYTE pbImageData=NULL; DWORD dwImageBytes=0; XCONTENT_DATA XContentData; int iIndex=pClass->m_pSavesList->GetData(pClass->m_pSavesList->GetCurSel()).iIndex-pClass->m_iDefaultButtonsC; StorageManager.GetSaveCacheFileInfo(iIndex,XContentData); StorageManager.GetSaveCacheFileInfo(iIndex,&pbImageData,&dwImageBytes); // 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 if(pbImageData==NULL) { DWORD dwResult=XContentGetThumbnail(ProfileManager.GetPrimaryPad(),&XContentData,NULL,&dwImageBytes,NULL); if(dwResult==ERROR_SUCCESS) { pClass->m_pbSaveTransferData = new BYTE[dwImageBytes]; pbImageData = pClass->m_pbSaveTransferData; // Copy pointer so that we can use the same name as the library owned one, but m_pbSaveTransferData will get deleted when done XContentGetThumbnail(ProfileManager.GetPrimaryPad(),&XContentData,pbImageData,&dwImageBytes,NULL); } } dos.writeInt(dwImageBytes); byteArray ba(pbImageData, dwImageBytes); dos.write(ba); } pClass->m_pbSaveTransferData=new BYTE [baos.size()]; memcpy(pClass->m_pbSaveTransferData,baos.buf.data,baos.size()); app.DebugPrintf("Uploading meta data (%d bytes)\n", baos.size()); UploadFile(pClass, "metadata", pClass->m_pbSaveTransferData, baos.size()); } // Wait for metadata and thumbnail if(!WaitForTransferComplete(pClass)) return 0; if(pClass->m_bTransferFail) { // something went wrong, user has been informed pMinecraft->progressRenderer->progressStage( IDS_SAVE_TRANSFER_UPLOADFAILED ); return 0; } // Upload the marker file { char singleByteData[1] = {1}; app.DebugPrintf("Uploading marker (%d bytes)\n", 1); UploadFile(pClass, "completemarker", &singleByteData, 1); } // Wait for marker if(!WaitForTransferComplete(pClass)) return 0; if(pClass->m_bTransferFail) { // something went wrong, user has been informed pMinecraft->progressRenderer->progressStage( IDS_SAVE_TRANSFER_UPLOADFAILED ); return 0; } // change text for completion confirmation pMinecraft->progressRenderer->progressStage( IDS_SAVE_TRANSFER_UPLOADCOMPLETE ); // done return 0; } void CScene_MultiGameJoinLoad::DeleteFile(CScene_MultiGameJoinLoad *pClass, char *filename) { pClass->m_fProgress=0.0f; pClass->m_bTransferComplete=false; C4JStorage::ETMSStatus result = StorageManager.TMSPP_DeleteFile( ProfileManager.GetPrimaryPad(), filename, C4JStorage::TMS_FILETYPE_BINARY, &CScene_MultiGameJoinLoad::DeleteComplete, pClass, NULL); if(result != C4JStorage::ETMSStatus_DeleteInProgress) { DeleteComplete(pClass,ProfileManager.GetPrimaryPad(), -1); } } void CScene_MultiGameJoinLoad::UploadFile(CScene_MultiGameJoinLoad *pClass, char *filename, LPVOID data, DWORD size) { pClass->m_fProgress=0.0f; pClass->m_bTransferComplete=false; C4JStorage::ETMSStatus result = StorageManager.TMSPP_WriteFileWithProgress( ProfileManager.GetPrimaryPad(), C4JStorage::eGlobalStorage_TitleUser, C4JStorage::TMS_FILETYPE_BINARY, C4JStorage::TMS_UGCTYPE_NONE, filename, (CHAR *)data, size, &CScene_MultiGameJoinLoad::TransferComplete,pClass, 0, &CScene_MultiGameJoinLoad::Progress,pClass); #ifdef _DEBUG_MENUS_ENABLED if(app.GetWriteSavesToFolderEnabled()) { File targetFileDir(L"GAME:\\FakeTMSPP"); if(!targetFileDir.exists()) targetFileDir.mkdir(); string path = string( wstringtofilename( targetFileDir.getPath() ) ).append("\\").append(filename); HANDLE hSaveFile = CreateFile( path.c_str(), GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, FILE_FLAG_RANDOM_ACCESS, NULL); DWORD numberOfBytesWritten = 0; WriteFile( hSaveFile,data,size,&numberOfBytesWritten,NULL); assert(numberOfBytesWritten == size); CloseHandle(hSaveFile); } #endif if(result != C4JStorage::ETMSStatus_WriteInProgress) { TransferComplete(pClass,ProfileManager.GetPrimaryPad(), -1); } } bool CScene_MultiGameJoinLoad::WaitForTransferComplete( CScene_MultiGameJoinLoad *pClass ) { Minecraft *pMinecraft = Minecraft::GetInstance(); // loop until complete while(pClass->m_bTransferComplete==false) { // check for a cancel if(pClass->m_bSaveTransferInProgress==false) { // cancelled return false; } Sleep(50); // update the progress pMinecraft->progressRenderer->progressStagePercentage((unsigned int)(pClass->m_fProgress*100.0f)); } // was there a transfer error? return true; } int CScene_MultiGameJoinLoad::SaveOptionsDialogReturned(void *pParam,int iPad,C4JStorage::EMessageResult result) { CScene_MultiGameJoinLoad* pClass = (CScene_MultiGameJoinLoad*)pParam; // results switched for this dialog // EMessage_ResultAccept means cancel if(result==C4JStorage::EMessage_ResultDecline || result==C4JStorage::EMessage_ResultThirdOption) { if(result==C4JStorage::EMessage_ResultDecline) // rename { ZeroMemory(pClass->m_wchNewName,sizeof(WCHAR)*XCONTENT_MAX_DISPLAYNAME_LENGTH); // bring up a keyboard InputManager.RequestKeyboard(IDS_RENAME_WORLD_TITLE,L"",IDS_RENAME_WORLD_TEXT,iPad,pClass->m_wchNewName,XCONTENT_MAX_DISPLAYNAME_LENGTH,&CScene_MultiGameJoinLoad::KeyboardReturned,pClass,C_4JInput::EKeyboardMode_Default,app.GetStringTable()); } else // delete { // 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; StorageManager.RequestMessageBox(IDS_TOOLTIPS_DELETESAVE, IDS_TEXT_DELETE_SAVE, uiIDA, 2, iPad,&CScene_MultiGameJoinLoad::DeleteSaveDialogReturned,pClass, app.GetStringTable()); //pClass->m_bIgnoreInput=false; } } else { pClass->m_bIgnoreInput=false; } return 0; } int CScene_MultiGameJoinLoad::LoadSaveDataReturned(void *pParam,bool bContinue) { CScene_MultiGameJoinLoad* pClass = (CScene_MultiGameJoinLoad*)pParam; if(bContinue==true) { pClass->m_bSaveTransferInProgress=true; LoadingInputParams *loadingParams = new LoadingInputParams(); loadingParams->func = &CScene_MultiGameJoinLoad::UploadSaveForXboxOneThreadProc; loadingParams->lpParam = (LPVOID)pParam; UIFullscreenProgressCompletionData *completionData = new UIFullscreenProgressCompletionData(); completionData->bShowBackground=TRUE; completionData->bShowLogo=TRUE; completionData->type = e_ProgressCompletion_NavigateBack; completionData->iPad = DEFAULT_XUI_MENU_USER; completionData->bRequiresUserAction=TRUE; loadingParams->completionData = completionData; loadingParams->cancelFunc=&CScene_MultiGameJoinLoad::CancelSaveUploadCallback; loadingParams->completeFunc=&CScene_MultiGameJoinLoad::SaveUploadCompleteCallback; loadingParams->m_cancelFuncParam=pClass; loadingParams->m_completeFuncParam=pClass; loadingParams->cancelText=IDS_TOOLTIPS_CANCEL; app.NavigateToScene(ProfileManager.GetPrimaryPad(),eUIScene_FullscreenProgress, loadingParams); } else { // switch back to the normal title group id app.TMSPP_SetTitleGroupID(GROUP_ID); // the save is corrupt! pClass->SetShow( TRUE ); pClass->m_bIgnoreInput=false; // give the option to delete the save UINT uiIDA[2]; uiIDA[0]=IDS_CONFIRM_CANCEL; uiIDA[1]=IDS_CONFIRM_OK; StorageManager.RequestMessageBox(IDS_CORRUPT_OR_DAMAGED_SAVE_TITLE, IDS_CORRUPT_OR_DAMAGED_SAVE_TEXT, uiIDA, 2, pClass->m_iPad,&CScene_MultiGameJoinLoad::DeleteSaveDialogReturned,pClass, app.GetStringTable()); } return 0; } int CScene_MultiGameJoinLoad::Progress(void *pParam,float fProgress) { CScene_MultiGameJoinLoad* pClass = (CScene_MultiGameJoinLoad*)pParam; app.DebugPrintf("Progress - %f\n",fProgress); pClass->m_fProgress=fProgress; return 0; } int CScene_MultiGameJoinLoad::TransferComplete(void *pParam,int iPad, int iResult) { CScene_MultiGameJoinLoad* pClass = (CScene_MultiGameJoinLoad*)pParam; delete [] pClass->m_pbSaveTransferData; pClass->m_pbSaveTransferData = NULL; if(iResult!=0) { // There was a transfer fail // Display a dialog UINT uiIDA[1]; uiIDA[0]=IDS_CONFIRM_OK; StorageManager.RequestMessageBox(IDS_SAVE_TRANSFER_TITLE, IDS_SAVE_TRANSFER_UPLOADFAILED, uiIDA, 1, ProfileManager.GetPrimaryPad(),NULL,NULL,app.GetStringTable()); pClass->m_bTransferFail=true; } else { pClass->m_bTransferFail=false; } pClass->m_bTransferComplete=true; //pClass->m_bSaveTransferInProgress=false; return 0; } int CScene_MultiGameJoinLoad::DeleteComplete(void *pParam,int iPad, int iResult) { CScene_MultiGameJoinLoad* pClass = (CScene_MultiGameJoinLoad*)pParam; pClass->m_bTransferComplete=true; return 0; } int CScene_MultiGameJoinLoad::KeyboardReturned(void *pParam,bool bSet) { CScene_MultiGameJoinLoad* pClass = (CScene_MultiGameJoinLoad*)pParam; HRESULT hr = S_OK; // if the user has left the name empty, treat this as backing out if((pClass->m_wchNewName[0]!=0) && bSet) { #ifdef _XBOX XCONTENT_DATA XContentData; StorageManager.GetSaveCacheFileInfo(pClass->m_iChangingSaveGameInfoIndex-pClass->m_iDefaultButtonsC,XContentData); C4JStorage::ELoadGameStatus eLoadStatus=StorageManager.LoadSaveData(&XContentData,CScene_MultiGameJoinLoad::LoadSaveDataForRenameReturned,pClass); if(eLoadStatus==C4JStorage::ELoadGame_DeviceRemoved) { // disable saving StorageManager.SetSaveDisabled(true); StorageManager.SetSaveDeviceSelected(ProfileManager.GetPrimaryPad(),false); UINT uiIDA[1]; uiIDA[0]=IDS_OK; StorageManager.RequestMessageBox(IDS_STORAGEDEVICEPROBLEM_TITLE, IDS_FAILED_TO_LOADSAVE_TEXT, uiIDA, 1, ProfileManager.GetPrimaryPad(),&CScene_MultiGameJoinLoad::DeviceRemovedDialogReturned,pClass); } #else // rename the save #endif } else { pClass->m_bIgnoreInput=false; } return hr; } int CScene_MultiGameJoinLoad::LoadSaveDataForRenameReturned(void *pParam,bool bContinue) { CScene_MultiGameJoinLoad* pClass = (CScene_MultiGameJoinLoad*)pParam; #ifdef _XBOX if(bContinue==true) { // set the save icon PBYTE pbImageData=NULL; DWORD dwImageBytes=0; HXUIBRUSH hXuiBrush; XCONTENT_DATA XContentData; StorageManager.GetSaveCacheFileInfo(pClass->m_iChangingSaveGameInfoIndex-pClass->m_iDefaultButtonsC,XContentData); StorageManager.GetSaveCacheFileInfo(pClass->m_iChangingSaveGameInfoIndex-pClass->m_iDefaultButtonsC,&pbImageData,&dwImageBytes); // 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 if(pbImageData==NULL) { DWORD dwResult=XContentGetThumbnail(ProfileManager.GetPrimaryPad(),&XContentData,NULL,&dwImageBytes,NULL); if(dwResult==ERROR_SUCCESS) { pbImageData = new BYTE[dwImageBytes]; XContentGetThumbnail(ProfileManager.GetPrimaryPad(),&XContentData,pbImageData,&dwImageBytes,NULL); XuiCreateTextureBrushFromMemory(pbImageData,dwImageBytes,&hXuiBrush); } } else { XuiCreateTextureBrushFromMemory(pbImageData,dwImageBytes,&hXuiBrush); } // save the data with this icon StorageManager.CopySaveDataToNewSave( pbImageData,dwImageBytes,pClass->m_wchNewName,&CScene_MultiGameJoinLoad::CopySaveReturned,pClass); } else #endif { //pClass->SetShow( TRUE ); pClass->m_bIgnoreInput=false; } return 0; } int CScene_MultiGameJoinLoad::CopySaveReturned(void *pParam,bool bResult) { CScene_MultiGameJoinLoad* pClass = (CScene_MultiGameJoinLoad*)pParam; #ifdef _XBOX if(bResult) { // and delete the old save XCONTENT_DATA XContentData; StorageManager.GetSaveCacheFileInfo(pClass->m_iChangingSaveGameInfoIndex-pClass->m_iDefaultButtonsC,XContentData); StorageManager.DeleteSaveData(&XContentData,CScene_MultiGameJoinLoad::DeleteSaveDataReturned,pClass); pClass->m_SavesListTimer.SetShow( TRUE ); } else #endif { //pClass->SetShow( TRUE ); pClass->m_bIgnoreInput=false; } return 0; } int CScene_MultiGameJoinLoad::TexturePackDialogReturned(void *pParam,int iPad,C4JStorage::EMessageResult result) { CScene_MultiGameJoinLoad *pClass = (CScene_MultiGameJoinLoad *)pParam; // Exit with or without saving // Decline means install full version of the texture pack in this dialog if(result==C4JStorage::EMessage_ResultDecline || result==C4JStorage::EMessage_ResultAccept) { // we need to enable background downloading for the DLC XBackgroundDownloadSetMode(XBACKGROUND_DOWNLOAD_MODE_ALWAYS_ALLOW); ULONGLONG ullOfferID_Full; ULONGLONG ullIndexA[1]; app.GetDLCFullOfferIDForPackID(pClass->m_initData->selectedSession->data.texturePackParentId,&ullOfferID_Full); if( result==C4JStorage::EMessage_ResultAccept ) // Full version { ullIndexA[0]=ullOfferID_Full; StorageManager.InstallOffer(1,ullIndexA,NULL,NULL); } else // trial version { // if there is no trial version, this is a Cancel DLC_INFO *pDLCInfo=app.GetDLCInfoForFullOfferID(ullOfferID_Full); if(pDLCInfo->ullOfferID_Trial!=0LL) { ullIndexA[0]=pDLCInfo->ullOfferID_Trial; StorageManager.InstallOffer(1,ullIndexA,NULL,NULL); } } } pClass->m_bIgnoreInput=false; return 0; } HRESULT CScene_MultiGameJoinLoad::OnCustomMessage_DLCInstalled() { // mounted DLC may have changed if(app.StartInstallDLCProcess(m_iPad)==false) { // not doing a mount, so re-enable input m_bIgnoreInput=false; } else { m_bIgnoreInput=true; // clear out the saves list and re-fill m_pSavesList->RemoveAllData(); m_SavesListTimer.SetShow( TRUE ); } // this will send a CustomMessage_DLCMountingComplete when done return S_OK; } HRESULT CScene_MultiGameJoinLoad::OnCustomMessage_DLCMountingComplete() { VOID *pObj; XuiObjectFromHandle( m_SavesList, &pObj ); m_pSavesList = (CXuiCtrl4JList *)pObj; m_iChangingSaveGameInfoIndex = 0; m_generators = app.getLevelGenerators(); m_iDefaultButtonsC = 0; m_iMashUpButtonsC = 0; XPARTY_USER_LIST partyList; if((XPartyGetUserList( &partyList ) != XPARTY_E_NOT_IN_PARTY ) && (partyList.dwUserCount>1)) { m_bInParty=true; } else { m_bInParty=false; } int iLB = -1; int iY=-1; if(DoesSavesListHaveFocus()) { if(ProfileManager.IsSignedInLive( m_iPad )) { iY=IDS_TOOLTIPS_UPLOAD_SAVE_FOR_XBOXONE; } } if(m_bInParty) iLB = IDS_TOOLTIPS_PARTY_GAMES; // check if we're in the trial version if(ProfileManager.IsFullVersion()==false) { ui.SetTooltips( DEFAULT_XUI_MENU_USER, IDS_TOOLTIPS_SELECT,IDS_TOOLTIPS_BACK, -1, -1, -1, -1,iLB); AddDefaultButtons(); m_pSavesList->SetCurSelVisible(0); } else if(StorageManager.GetSaveDisabled()) { if(StorageManager.GetSaveDeviceSelected(m_iPad)) { // saving is disabled, but we should still be able to load from a selected save device ui.SetTooltips( DEFAULT_XUI_MENU_USER, IDS_TOOLTIPS_SELECT,IDS_TOOLTIPS_BACK,IDS_TOOLTIPS_CHANGEDEVICE,iY,-1,-1,iLB,IDS_TOOLTIPS_DELETESAVE); GetSaveInfo(); } else { ui.SetTooltips( DEFAULT_XUI_MENU_USER, IDS_TOOLTIPS_SELECT,IDS_TOOLTIPS_BACK,IDS_TOOLTIPS_SELECTDEVICE,iY,-1,-1,iLB); AddDefaultButtons(); m_SavesListTimer.SetShow( FALSE ); m_pSavesList->SetCurSelVisible(0); } } 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(); ui.SetTooltips( DEFAULT_XUI_MENU_USER, IDS_TOOLTIPS_SELECT,IDS_TOOLTIPS_BACK,IDS_TOOLTIPS_CHANGEDEVICE,iY,-1,-1,-1,bCanRename?IDS_TOOLTIPS_SAVEOPTIONS:IDS_TOOLTIPS_DELETESAVE); GetSaveInfo(); } m_bIgnoreInput=false; app.m_dlcManager.checkForCorruptDLCAndAlert(); return S_OK; } /* void CScene_MultiGameJoinLoad::UpdateTooltips() { int iA=IDS_TOOLTIPS_SELECT; int iB=IDS_TOOLTIPS_BACK; int iX=-1; int iY=-1 int iLB = -1; XPARTY_USER_LIST partyList; if((XPartyGetUserList( &partyList ) != XPARTY_E_NOT_IN_PARTY ) && (partyList.dwUserCount>1)) { m_bInParty=true; } else { m_bInParty=false; } if(m_bInParty) iLB = IDS_TOOLTIPS_PARTY_GAMES; if(ProfileManager.IsFullVersion()==false) { ui.SetTooltips( DEFAULT_XUI_MENU_USER, IDS_TOOLTIPS_SELECT,IDS_TOOLTIPS_BACK, -1, -1, -1, -1,iLB); } else if(StorageManager.GetSaveDisabled()) { if(StorageManager.GetSaveDeviceSelected(m_iPad)) { // saving is disabled, but we should still be able to load from a selected save device iX=IDS_TOOLTIPS_CHANGEDEVICE; iRB=IDS_TOOLTIPS_DELETESAVE; } else { iX=IDS_TOOLTIPS_SELECTDEVICE; } } 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(); if(bCanRename) { iRB=IDS_TOOLTIPS_SAVEOPTIONS; } else { iRB=IDS_TOOLTIPS_DELETESAVE; } } ui.SetTooltips( DEFAULT_XUI_MENU_USER, iA,iB, iX, iY, iLT, iRT,iLB, iRB); } */ #ifdef _XBOX bool CScene_MultiGameJoinLoad::GetSavesInfoCallback(LPVOID pParam,int iTotalSaveInfoC, C4JStorage::CACHEINFOSTRUCT *InfoA, int iPad, HRESULT hResult) { CScene_MultiGameJoinLoad *pClass=(CScene_MultiGameJoinLoad *)pParam; CXuiCtrl4JList::LIST_ITEM_INFO ListInfo; PBYTE pbImageData=(PBYTE)InfoA; PBYTE pbCurrentImagePtr; HXUIBRUSH hXuiBrush; HRESULT hr; // move the image data pointer to the right place if(iTotalSaveInfoC!=0) { pbImageData+=sizeof(C4JStorage::CACHEINFOSTRUCT)*iTotalSaveInfoC; } pClass->m_SavesListTimer.SetShow( FALSE ); pClass->m_SavesList.SetEnable(TRUE); pClass->AddDefaultButtons(); for(int i=0;im_pSavesList->AddData(ListInfo,-1); // update the graphic on the list item // if there is no thumbnail, this is a corrupt file if(InfoA[i].dwImageBytes!=0) { pbCurrentImagePtr=pbImageData+InfoA[i].dwImageOffset; hr=XuiCreateTextureBrushFromMemory(pbCurrentImagePtr,InfoA[i].dwImageBytes,&hXuiBrush); pClass->m_pSavesList->UpdateGraphic(i+pClass->m_iDefaultButtonsC,hXuiBrush ); } else { // we could put in a damaged save icon here const DWORD LOCATOR_SIZE = 256; // Use this to allocate space to hold a ResourceLocator string WCHAR szResourceLocator[ LOCATOR_SIZE ]; const ULONG_PTR c_ModuleHandle = (ULONG_PTR)GetModuleHandle(NULL); swprintf(szResourceLocator, LOCATOR_SIZE, L"section://%X,%ls#%ls",c_ModuleHandle,L"media", L"media/Graphics/MinecraftBrokenIcon.png"); XuiCreateTextureBrush(szResourceLocator,&hXuiBrush); pClass->m_pSavesList->UpdateGraphic(i+pClass->m_iDefaultButtonsC,hXuiBrush ); } } } pClass->m_iSaveInfoC=iTotalSaveInfoC; // If there are some saves, then set the focus to be on the most recent one, which will be the first one after the create and tutorial if(iTotalSaveInfoC>0) { pClass->m_pSavesList->SetCurSelVisible(pClass->m_iDefaultButtonsC); pClass->m_bReady=true; } pClass->m_bRetrievingSaveInfo=false; // It's possible that the games list is updated but we haven't displayed it yet as we were still waiting on saves list to load // This is to fix a bug where joining a game before the saves list has loaded causes a crash when this callback is called // as the scene no longer exists pClass->UpdateGamesList(); // Fix for #45154 - Frontend: DLC: Content can only be downloaded from the frontend if you have not joined/exited multiplayer XBackgroundDownloadSetMode(XBACKGROUND_DOWNLOAD_MODE_AUTO); return false; } #else int CScene_MultiGameJoinLoad::GetSavesInfoCallback(LPVOID lpParam,const bool) { return true; } #endif void CScene_MultiGameJoinLoad::CancelSaveUploadCallback(LPVOID lpParam) { CScene_MultiGameJoinLoad* pClass = (CScene_MultiGameJoinLoad *) lpParam; StorageManager.TMSPP_CancelWriteFileWithProgress(pClass->m_iPad); pClass->m_bSaveTransferInProgress=false; // change back to the normal title group id app.TMSPP_SetTitleGroupID(GROUP_ID); // app.getRemoteStorage()->abort(); // pClass->m_eSaveUploadState = eSaveUpload_Idle; UINT uiIDA[1] = { IDS_CONFIRM_OK }; ui.RequestMessageBox(IDS_XBONE_CANCEL_UPLOAD_TITLE, IDS_XBONE_CANCEL_UPLOAD_TEXT, uiIDA, 1, pClass->m_iPad, NULL, NULL, app.GetStringTable()); } void CScene_MultiGameJoinLoad::SaveUploadCompleteCallback(LPVOID lpParam) { CScene_MultiGameJoinLoad* pClass = (CScene_MultiGameJoinLoad *) lpParam; pClass->m_bSaveTransferInProgress=false; // change back to the normal title group id app.TMSPP_SetTitleGroupID(GROUP_ID); // app.getRemoteStorage()->abort(); // pClass->m_eSaveUploadState = eSaveUpload_Idle; }