// Minecraft.cpp : Defines the entry point for the application. // #include "../../Minecraft.World/Platform/stdafx.h" #include #include #include #include "../../Minecraft.World/Util/AABB.h" #include "../../Minecraft.World/Util/Vec3.h" #include "../../Minecraft.World/Headers/net.minecraft.stats.h" #include "../../Minecraft.Client/GameState/StatsCounter.h" #include "../../Minecraft.World/Entities/Entity.h" #include "../../Minecraft.World/Level/Level.h" #include "../../Minecraft.Client/Player/MultiPlayerLocalPlayer.h" #include "../../Minecraft.Client/MinecraftServer.h" #include "../../Minecraft.Client/Level/MultiPlayerLevel.h" #include "../../Minecraft.Client/Rendering/EntityRenderers/ProgressRenderer.h" #include "../../Minecraft.World/Network/Packets/DisconnectPacket.h" #include "../../Minecraft.Client/Minecraft.h" #include "../../Minecraft.Client/GameState/Options.h" #include "../../Minecraft.World/IO/Streams/Compression.h" #include "../../Minecraft.Client/Textures/Packs/TexturePackRepository.h" #include "../../Minecraft.Client/Textures/Packs/TexturePack.h" #include "../../Minecraft.Client/Textures/Packs/DLCTexturePack.h" #define IGNORE_KEYPRESS_TIMERID 0 #define IGNORE_KEYPRESS_TIME 100 //---------------------------------------------------------------------------------- // Performs initialization tasks - retrieves controls. //---------------------------------------------------------------------------------- HRESULT UIScene_PauseMenu::OnInit(XUIMessageInit* pInitData, BOOL& bHandled) { m_bIgnoreInput = true; m_iPad = *(int*)pInitData->pvInitData; bool bUserisClientSide = ProfileManager.IsSignedInLive(m_iPad); app.DebugPrintf( "PAUSE PRESS PROCESSING - ipad = %d, UIScene_PauseMenu::OnInit\n", m_iPad); bool bIsisPrimaryHost = g_NetworkManager.IsHost() && (ProfileManager.GetPrimaryPad() == m_iPad); bool bDisplayBanTip = !g_NetworkManager.IsLocalGame() && !bIsisPrimaryHost && !ProfileManager.IsGuest(m_iPad); MapChildControls(); XuiControlSetText(m_Buttons[BUTTON_PAUSE_RESUMEGAME], app.GetString(IDS_RESUME_GAME)); XuiControlSetText(m_Buttons[BUTTON_PAUSE_HELPANDOPTIONS], app.GetString(IDS_HELP_AND_OPTIONS)); XuiControlSetText(m_Buttons[BUTTON_PAUSE_LEADERBOARDS], app.GetString(IDS_LEADERBOARDS)); XuiControlSetText(m_Buttons[BUTTON_PAUSE_ACHIEVEMENTS], app.GetString(IDS_ACHIEVEMENTS)); XuiControlSetText(m_Buttons[BUTTON_PAUSE_SAVEGAME], app.GetString(IDS_SAVE_GAME)); XuiControlSetText(m_Buttons[BUTTON_PAUSE_EXITGAME], app.GetString(IDS_EXIT_GAME)); if (app.GetLocalPlayerCount() > 1) { m_bSplitscreen = true; app.AdjustSplitscreenScene(m_hObj, &m_OriginalPosition, m_iPad, false); CXuiSceneBase::ShowLogo(m_iPad, FALSE); } else { m_bSplitscreen = false; CXuiSceneBase::ShowLogo(m_iPad, TRUE); } // test award the theme // ProfileManager.Award( ProfileManager.GetPrimaryPad(), eAward_socialPost // ); // Display the tooltips, we are only allowed to display "SHARE" if we have // the capability (TCR). if (!ProfileManager.IsFullVersion()) { ui.SetTooltips(m_iPad, IDS_TOOLTIPS_SELECT, IDS_TOOLTIPS_BACK); // hide the trial timer CXuiSceneBase::ShowTrialTimer(FALSE); } else if (StorageManager.GetSaveDisabled()) { if (CSocialManager::Instance()->IsTitleAllowedToPostImages() && CSocialManager::Instance()->AreAllUsersAllowedToPostImages() && bUserisClientSide) { ui.SetTooltips(m_iPad, IDS_TOOLTIPS_SELECT, IDS_TOOLTIPS_BACK, bIsisPrimaryHost ? IDS_TOOLTIPS_SELECTDEVICE : -1, IDS_TOOLTIPS_SHARE, -1, -1, -1, bDisplayBanTip ? IDS_TOOLTIPS_BANLEVEL : -1); } else { ui.SetTooltips(m_iPad, IDS_TOOLTIPS_SELECT, IDS_TOOLTIPS_BACK, bIsisPrimaryHost ? IDS_TOOLTIPS_SELECTDEVICE : -1, -1, -1, -1, -1, bDisplayBanTip ? IDS_TOOLTIPS_BANLEVEL : -1); } } else { if (CSocialManager::Instance()->IsTitleAllowedToPostImages() && CSocialManager::Instance()->AreAllUsersAllowedToPostImages() && bUserisClientSide) { ui.SetTooltips(m_iPad, IDS_TOOLTIPS_SELECT, IDS_TOOLTIPS_BACK, bIsisPrimaryHost ? IDS_TOOLTIPS_CHANGEDEVICE : -1, IDS_TOOLTIPS_SHARE, -1, -1, -1, bDisplayBanTip ? IDS_TOOLTIPS_BANLEVEL : -1); } else { ui.SetTooltips(m_iPad, IDS_TOOLTIPS_SELECT, IDS_TOOLTIPS_BACK, bIsisPrimaryHost ? IDS_TOOLTIPS_CHANGEDEVICE : -1, -1, -1, -1, -1, bDisplayBanTip ? IDS_TOOLTIPS_BANLEVEL : -1); } } CXuiSceneBase::ShowDarkOverlay(m_iPad, TRUE); // are we the primary player? // 4J-PB - fix for 7844 & 7845 - // TCR # 128: XLA Pause Menu: When in a multiplayer game as a client the // Pause Menu does not have a Leaderboards option. TCR # 128: XLA Pause // Menu: When in a multiplayer game as a client the Pause Menu does not // have an Achievements option. if (ProfileManager.GetPrimaryPad() == m_iPad) // && g_NetworkManager.IsHost()) { // are we in splitscreen? // how many local players do we have? D3DXVECTOR3 vPos; if (app.GetLocalPlayerCount() > 1) { m_Buttons[BUTTON_PAUSE_LEADERBOARDS].GetPosition(&vPos); m_Buttons[BUTTON_PAUSE_SAVEGAME].SetPosition(&vPos); m_Buttons[BUTTON_PAUSE_ACHIEVEMENTS].GetPosition(&vPos); m_Buttons[BUTTON_PAUSE_EXITGAME].SetPosition(&vPos); // Hide the BUTTON_PAUSE_LEADERBOARDS and BUTTON_PAUSE_ACHIEVEMENTS XuiElementSetShow(m_Buttons[BUTTON_PAUSE_LEADERBOARDS], FALSE); XuiElementSetShow(m_Buttons[BUTTON_PAUSE_ACHIEVEMENTS], FALSE); } if (!g_NetworkManager.IsHost()) { m_Buttons[BUTTON_PAUSE_SAVEGAME].GetPosition(&vPos); m_Buttons[BUTTON_PAUSE_EXITGAME].SetPosition(&vPos); // Hide the BUTTON_PAUSE_SAVEGAME XuiElementSetShow(m_Buttons[BUTTON_PAUSE_SAVEGAME], FALSE); } } else { D3DXVECTOR3 vPos; m_Buttons[BUTTON_PAUSE_LEADERBOARDS].GetPosition(&vPos); m_Buttons[BUTTON_PAUSE_EXITGAME].SetPosition(&vPos); // Hide the BUTTON_PAUSE_LEADERBOARDS, BUTTON_PAUSE_ACHIEVEMENTS and // BUTTON_PAUSE_SAVEGAME XuiElementSetShow(m_Buttons[BUTTON_PAUSE_LEADERBOARDS], FALSE); XuiElementSetShow(m_Buttons[BUTTON_PAUSE_ACHIEVEMENTS], FALSE); XuiElementSetShow(m_Buttons[BUTTON_PAUSE_SAVEGAME], FALSE); } // is saving disabled? if (StorageManager.GetSaveDisabled()) { // disable save button m_Buttons[BUTTON_PAUSE_SAVEGAME].SetEnable(FALSE); m_Buttons[BUTTON_PAUSE_SAVEGAME].EnableInput(FALSE); } m_iLastButtonPressed = 0; // get rid of the quadrant display if it's on CXuiSceneBase::HidePressStart(); XuiSetTimer(m_hObj, IGNORE_KEYPRESS_TIMERID, IGNORE_KEYPRESS_TIME); if (g_NetworkManager.IsLocalGame() && g_NetworkManager.GetPlayerCount() == 1) { app.SetXuiServerAction(ProfileManager.GetPrimaryPad(), eXuiServerAction_PauseServer, (void*)TRUE); } TelemetryManager->RecordMenuShown(m_iPad, eUIScene_PauseMenu, 0); TelemetryManager->RecordPauseOrInactive(m_iPad); return S_OK; } //---------------------------------------------------------------------------------- // Handler for the button press message. //---------------------------------------------------------------------------------- HRESULT UIScene_PauseMenu::OnNotifyPressEx(HXUIOBJ hObjPressed, XUINotifyPress* pNotifyPressData, BOOL& rfHandled) { if (m_bIgnoreInput) return S_OK; // This assumes all buttons can only be pressed with the A button ui.AnimateKeyPress(pNotifyPressData->UserIndex, VK_PAD_A); unsigned int uiButtonCounter = 0; while ((uiButtonCounter < BUTTONS_PAUSE_MAX) && (m_Buttons[uiButtonCounter] != hObjPressed)) uiButtonCounter++; Minecraft* pMinecraft = Minecraft::GetInstance(); // ignore buttons not from this user // if(pNotifyPressData->UserIndex!=pMinecraft->player->GetXboxPad()) return // S_OK; // Determine which button was pressed, // and call the appropriate function. // store the last button pressed, so on a nav back we can set the focus // properly m_iLastButtonPressed = uiButtonCounter; switch (uiButtonCounter) { case BUTTON_PAUSE_RESUMEGAME: if (m_iPad == ProfileManager.GetPrimaryPad() && g_NetworkManager.IsLocalGame()) { app.SetXuiServerAction(ProfileManager.GetPrimaryPad(), eXuiServerAction_PauseServer, (void*)FALSE); } app.CloseXuiScenes(pNotifyPressData->UserIndex); break; case BUTTON_PAUSE_LEADERBOARDS: { unsigned int uiIDA[1]; uiIDA[0] = IDS_OK; // 4J Gordon: Being used for the leaderboards proper now // guests can't look at leaderboards if (ProfileManager.IsGuest(pNotifyPressData->UserIndex)) { StorageManager.RequestMessageBox(IDS_PRO_GUESTPROFILE_TITLE, IDS_PRO_GUESTPROFILE_TEXT, uiIDA, 1); } else if (!ProfileManager.IsSignedInLive( pNotifyPressData->UserIndex)) { StorageManager.RequestMessageBox(IDS_PRO_NOTONLINE_TITLE, IDS_PRO_XBOXLIVE_NOTIFICATION, uiIDA, 1); } else { app.NavigateToScene(pNotifyPressData->UserIndex, eUIScene_LeaderboardsMenu); } } break; case BUTTON_PAUSE_ACHIEVEMENTS: // guests can't look at achievements if (ProfileManager.IsGuest(pNotifyPressData->UserIndex)) { unsigned int uiIDA[1]; uiIDA[0] = IDS_OK; StorageManager.RequestMessageBox(IDS_PRO_GUESTPROFILE_TITLE, IDS_PRO_GUESTPROFILE_TEXT, uiIDA, 1); } else { XShowAchievementsUI(pNotifyPressData->UserIndex); } break; case BUTTON_PAUSE_HELPANDOPTIONS: if (app.GetLocalPlayerCount() > 1) { app.NavigateToScene(pNotifyPressData->UserIndex, eUIScene_HelpAndOptionsMenu); } else { app.NavigateToScene(pNotifyPressData->UserIndex, eUIScene_HelpAndOptionsMenu); } break; case BUTTON_PAUSE_SAVEGAME: { // 4J-PB - Is the player trying to save but they are using a trial // texturepack ? if (!Minecraft::GetInstance()->skins->isUsingDefaultSkin()) { TexturePack* tPack = Minecraft::GetInstance()->skins->getSelected(); DLCTexturePack* pDLCTexPack = (DLCTexturePack*)tPack; m_pDLCPack = pDLCTexPack ->getDLCInfoParentPack(); // tPack->getDLCPack(); if (!m_pDLCPack->hasPurchasedFile(DLCManager::e_DLCType_Texture, L"")) { // upsell ULONGLONG ullOfferID_Full; // get the dlc texture pack DLCTexturePack* pDLCTexPack = (DLCTexturePack*)tPack; app.GetDLCFullOfferIDForPackID( pDLCTexPack->getDLCParentPackId(), &ullOfferID_Full); // tell sentient about the upsell of the full version of the // texture pack TelemetryManager->RecordUpsellPresented( pNotifyPressData->UserIndex, eSet_UpsellID_Texture_DLC, ullOfferID_Full & 0xFFFFFFFF); unsigned int uiIDA[2]; uiIDA[0] = IDS_CONFIRM_OK; uiIDA[1] = IDS_CONFIRM_CANCEL; // Give the player a warning about the trial version of the // texture pack StorageManager.RequestMessageBox( IDS_WARNING_DLC_TRIALTEXTUREPACK_TITLE, IDS_WARNING_DLC_TRIALTEXTUREPACK_TEXT, uiIDA, 2, pNotifyPressData->UserIndex, &UIScene_PauseMenu::WarningTrialTexturePackReturned, this, app.GetStringTable()); return S_OK; } } // does the save exist? bool bSaveExists; C4JStorage::ELoadGameStatus result = StorageManager.DoesSaveExist(&bSaveExists); if (result == C4JStorage::ELoadGame_DeviceRemoved) { // this will be a tester trying to be clever unsigned int uiIDA[2]; uiIDA[0] = IDS_SELECTANEWDEVICE; uiIDA[1] = IDS_NODEVICE_DECLINE; StorageManager.RequestMessageBox( IDS_STORAGEDEVICEPROBLEM_TITLE, IDS_FAILED_TO_LOADSAVE_TEXT, uiIDA, 2, pNotifyPressData->UserIndex, &UIScene_PauseMenu::DeviceRemovedDialogReturned, this); } else { // we need to ask if they are sure they want to overwrite the // existing game if (bSaveExists) { unsigned int uiIDA[2]; uiIDA[0] = IDS_CONFIRM_CANCEL; uiIDA[1] = IDS_CONFIRM_OK; StorageManager.RequestMessageBox( IDS_TITLE_SAVE_GAME, IDS_CONFIRM_SAVE_GAME, uiIDA, 2, pNotifyPressData->UserIndex, &UIScene_PauseMenu::SaveGameDialogReturned, this, app.GetStringTable()); } else { // flag a app action of save game app.SetAction(pNotifyPressData->UserIndex, eAppAction_SaveGame); } } } break; case BUTTON_PAUSE_EXITGAME: { // Check if it's the trial version if (ProfileManager.IsFullVersion()) { unsigned int uiIDA[3]; // is it the primary player exiting? if (pNotifyPressData->UserIndex == ProfileManager.GetPrimaryPad()) { int playTime = -1; if (pMinecraft->localplayers[pNotifyPressData->UserIndex] != NULL) { playTime = (int)pMinecraft ->localplayers[pNotifyPressData->UserIndex] ->getSessionTimer(); } if (StorageManager.GetSaveDisabled()) { uiIDA[0] = IDS_CONFIRM_CANCEL; uiIDA[1] = IDS_CONFIRM_OK; StorageManager.RequestMessageBox( IDS_EXIT_GAME, IDS_CONFIRM_EXIT_GAME_PROGRESS_LOST, uiIDA, 2, pNotifyPressData->UserIndex, &UIScene_PauseMenu::ExitGameDialogReturned, this, app.GetStringTable()); } else { if (g_NetworkManager.IsHost()) { uiIDA[0] = IDS_CONFIRM_CANCEL; uiIDA[1] = IDS_EXIT_GAME_SAVE; uiIDA[2] = IDS_EXIT_GAME_NO_SAVE; if (g_NetworkManager.GetPlayerCount() > 1) { StorageManager.RequestMessageBox( IDS_EXIT_GAME, IDS_CONFIRM_EXIT_GAME_CONFIRM_DISCONNECT_SAVE, uiIDA, 3, pNotifyPressData->UserIndex, &UIScene_PauseMenu:: ExitGameSaveDialogReturned, this, app.GetStringTable()); } else { StorageManager.RequestMessageBox( IDS_EXIT_GAME, IDS_CONFIRM_EXIT_GAME, uiIDA, 3, pNotifyPressData->UserIndex, &UIScene_PauseMenu:: ExitGameSaveDialogReturned, this, app.GetStringTable()); } } else { uiIDA[0] = IDS_CONFIRM_CANCEL; uiIDA[1] = IDS_CONFIRM_OK; StorageManager.RequestMessageBox( IDS_EXIT_GAME, IDS_CONFIRM_EXIT_GAME, uiIDA, 2, pNotifyPressData->UserIndex, &UIScene_PauseMenu::ExitGameDialogReturned, this, app.GetStringTable()); } } } else { int playTime = -1; if (pMinecraft->localplayers[pNotifyPressData->UserIndex] != NULL) { playTime = (int)pMinecraft ->localplayers[pNotifyPressData->UserIndex] ->getSessionTimer(); } TelemetryManager->RecordLevelExit( pNotifyPressData->UserIndex, eSen_LevelExitStatus_Exited); // just exit the player app.SetAction(pNotifyPressData->UserIndex, eAppAction_ExitPlayer); } } else { // is it the primary player exiting? if (pNotifyPressData->UserIndex == ProfileManager.GetPrimaryPad()) { int playTime = -1; if (pMinecraft->localplayers[pNotifyPressData->UserIndex] != NULL) { playTime = (int)pMinecraft ->localplayers[pNotifyPressData->UserIndex] ->getSessionTimer(); } // adjust the trial time played CXuiSceneBase::ReduceTrialTimerValue(); // exit the level unsigned int uiIDA[2]; uiIDA[0] = IDS_CONFIRM_CANCEL; uiIDA[1] = IDS_CONFIRM_OK; StorageManager.RequestMessageBox( IDS_EXIT_GAME, IDS_CONFIRM_EXIT_GAME_PROGRESS_LOST, uiIDA, 2, pNotifyPressData->UserIndex, &UIScene_PauseMenu::ExitGameDialogReturned, this, app.GetStringTable()); } else { int playTime = -1; if (pMinecraft->localplayers[pNotifyPressData->UserIndex] != NULL) { playTime = (int)pMinecraft ->localplayers[pNotifyPressData->UserIndex] ->getSessionTimer(); } TelemetryManager->RecordLevelExit( pNotifyPressData->UserIndex, eSen_LevelExitStatus_Exited); // just exit the player app.SetAction(pNotifyPressData->UserIndex, eAppAction_ExitPlayer); } } } break; default: break; } return S_OK; } HRESULT UIScene_PauseMenu::OnKeyDown(XUIMessageInput* pInputData, BOOL& rfHandled) { if (m_bIgnoreInput) return S_OK; // ignore repeated start presses to avoid the scene closing before it's // opened if ((pInputData->dwKeyCode == VK_PAD_START) && (pInputData->dwFlags & XUI_INPUT_FLAG_REPEAT)) { rfHandled = TRUE; return S_OK; } bool bIsisPrimaryHost = g_NetworkManager.IsHost() && (ProfileManager.GetPrimaryPad() == m_iPad); bool bDisplayBanTip = !g_NetworkManager.IsLocalGame() && !bIsisPrimaryHost && !ProfileManager.IsGuest(m_iPad); bool bUserisClientSide = ProfileManager.IsSignedInLive(m_iPad); ui.AnimateKeyPress(pInputData->UserIndex, pInputData->dwKeyCode); app.DebugPrintf("PAUSE- Keydown in the xui %d flags = %d\n", pInputData->dwKeyCode, pInputData->dwFlags); switch (pInputData->dwKeyCode) { case VK_PAD_B: case VK_PAD_START: case VK_ESCAPE: app.DebugPrintf( "PAUSE PRESS PROCESSING - ipad = %d, " "UIScene_PauseMenu::OnKeyDown - LEAVING PAUSE MENU\n", m_iPad); if (m_iPad == ProfileManager.GetPrimaryPad() && g_NetworkManager.IsLocalGame()) { app.SetXuiServerAction(ProfileManager.GetPrimaryPad(), eXuiServerAction_PauseServer, (void*)FALSE); } CXuiSceneBase::PlayUISFX(eSFX_Back); app.CloseXuiScenes(pInputData->UserIndex); if (!ProfileManager.IsFullVersion()) { CXuiSceneBase::ShowTrialTimer(TRUE); } rfHandled = TRUE; break; case VK_PAD_X: // Change device if (bIsisPrimaryHost) { // we need a function to deal with the return from this - if it // changes, we need to update the pause menu and tooltips 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( &UIScene_PauseMenu::DeviceSelectReturned, this, true); } rfHandled = TRUE; break; case VK_PAD_Y: { if (bUserisClientSide) { // 4J Stu - Added check in 1.8.2 bug fix (TU6) to stop repeat // key presses bool bCanScreenshot = true; for (int j = 0; j < XUSER_MAX_COUNT; ++j) { if (app.GetXuiAction(j) == eAppAction_SocialPostScreenshot) { bCanScreenshot = false; break; } } if (bCanScreenshot) app.SetAction(pInputData->UserIndex, eAppAction_SocialPost); } rfHandled = TRUE; } break; case VK_PAD_RSHOULDER: if (bDisplayBanTip) { unsigned int uiIDA[2]; uiIDA[0] = IDS_CONFIRM_CANCEL; uiIDA[1] = IDS_CONFIRM_OK; StorageManager.RequestMessageBox( IDS_ACTION_BAN_LEVEL_TITLE, IDS_ACTION_BAN_LEVEL_DESCRIPTION, uiIDA, 2, pInputData->UserIndex, &UIScene_PauseMenu::BanGameDialogReturned, this, app.GetStringTable()); rfHandled = TRUE; } break; // handle a keyboard Return specifically, because we've turned off // the VK_A_OR_START for the pause menu, since this should exit the // menu, rather than cause the button to be activated case VK_RETURN: // call OnNotifyPressEx directly to trigger the button press action HXUIOBJ hObjPressed = TreeGetFocus(); XUINotifyPress NotifyPressData; BOOL rfHandled = FALSE; NotifyPressData.UserIndex = pInputData->UserIndex; OnNotifyPressEx(hObjPressed, &NotifyPressData, rfHandled); break; } return S_OK; } HRESULT UIScene_PauseMenu::OnNavReturn(HXUIOBJ hObj, BOOL& rfHandled) { bool bIsisPrimaryHost = g_NetworkManager.IsHost() && (ProfileManager.GetPrimaryPad() == m_iPad); bool bDisplayBanTip = !g_NetworkManager.IsLocalGame() && !bIsisPrimaryHost && !ProfileManager.IsGuest(m_iPad); bool bUserisClientSide = ProfileManager.IsSignedInLive(m_iPad); // Display the tooltips, we are only allowed to display "SHARE" if we have // the capability (TCR). if (StorageManager.GetSaveDisabled()) { if (ProfileManager.IsFullVersion() && CSocialManager::Instance()->IsTitleAllowedToPostImages() && CSocialManager::Instance()->AreAllUsersAllowedToPostImages() && bUserisClientSide) { ui.SetTooltips(m_iPad, IDS_TOOLTIPS_SELECT, IDS_TOOLTIPS_BACK, bIsisPrimaryHost ? IDS_TOOLTIPS_SELECTDEVICE : -1, IDS_TOOLTIPS_SHARE, -1, -1, -1, bDisplayBanTip ? IDS_TOOLTIPS_BANLEVEL : -1); } else { ui.SetTooltips(m_iPad, IDS_TOOLTIPS_SELECT, IDS_TOOLTIPS_BACK, -1, -1, -1, -1, -1, bDisplayBanTip ? IDS_TOOLTIPS_BANLEVEL : -1); } } else { if (CSocialManager::Instance()->IsTitleAllowedToPostImages() && CSocialManager::Instance()->AreAllUsersAllowedToPostImages() && bUserisClientSide) { ui.SetTooltips(m_iPad, IDS_TOOLTIPS_SELECT, IDS_TOOLTIPS_BACK, bIsisPrimaryHost ? IDS_TOOLTIPS_CHANGEDEVICE : -1, IDS_TOOLTIPS_SHARE, -1, -1, -1, bDisplayBanTip ? IDS_TOOLTIPS_BANLEVEL : -1); } else { ui.SetTooltips(m_iPad, IDS_TOOLTIPS_SELECT, IDS_TOOLTIPS_BACK, bIsisPrimaryHost ? IDS_TOOLTIPS_CHANGEDEVICE : -1, -1, -1, -1, -1, bDisplayBanTip ? IDS_TOOLTIPS_BANLEVEL : -1); } } // set the focus to the last button we were on XuiElementSetUserFocus(m_Buttons[m_iLastButtonPressed], m_iPad); CXuiSceneBase::ShowBackground(m_iPad, FALSE); CXuiSceneBase::ShowDarkOverlay(m_iPad, TRUE); bool isWrongSize = false; if (app.GetLocalPlayerCount() == 1) { // If we were created as a splitscreen scene, then it's now going to be // in the wrong place. Get rid of this scene. if (m_bSplitscreen) { CXuiSceneBase::ShowLogo(m_iPad, FALSE); isWrongSize = true; } else { CXuiSceneBase::ShowLogo(m_iPad, TRUE); } } else { CXuiSceneBase::ShowLogo(m_iPad, FALSE); if (!m_bSplitscreen) isWrongSize = true; } if (isWrongSize) { if (m_iPad == ProfileManager.GetPrimaryPad() && g_NetworkManager.IsLocalGame()) { app.SetXuiServerAction(ProfileManager.GetPrimaryPad(), eXuiServerAction_PauseServer, (void*)FALSE); } app.CloseXuiScenes(m_iPad); if (!ProfileManager.IsFullVersion()) { CXuiSceneBase::ShowTrialTimer(TRUE); } } return S_OK; } HRESULT UIScene_PauseMenu::OnControlNavigate( XUIMessageControlNavigate* pControlNavigateData, BOOL& bHandled) { pControlNavigateData->hObjDest = XuiControlGetNavigation( pControlNavigateData->hObjSource, pControlNavigateData->nControlNavigate, TRUE, TRUE); if (pControlNavigateData->hObjDest != NULL) { bHandled = TRUE; } return S_OK; } int UIScene_PauseMenu::BanGameDialogReturned( void* pParam, int iPad, C4JStorage::EMessageResult result) { // results switched for this dialog if (result == C4JStorage::EMessage_ResultDecline) { // 4J Stu - Only do this if we are currently idle, don't want the // (relatively) low priority ban task overriding something else if (app.GetXuiAction(iPad) == eAppAction_Idle) app.SetAction(iPad, eAppAction_BanLevel); } return 0; } int UIScene_PauseMenu::DeviceSelectReturned(void* pParam, bool bContinue) { // Has someone pulled the ethernet cable and caused the pause menu to be // closed before this callback returns? if (!app.IsPauseMenuDisplayed(ProfileManager.GetPrimaryPad())) { return 0; } UIScene_PauseMenu* pClass = (UIScene_PauseMenu*)pParam; bool bIsisPrimaryHost = g_NetworkManager.IsHost() && (ProfileManager.GetPrimaryPad() == pClass->m_iPad); bool bDisplayBanTip = !g_NetworkManager.IsLocalGame() && !bIsisPrimaryHost && !ProfileManager.IsGuest(pClass->m_iPad); bool bUserisClientSide = ProfileManager.IsSignedInLive(pClass->m_iPad); // Whatever happen, we need to update the pause menu and the tooltips // Display the tooltips, we are only allowed to display "SHARE" if we have // the capability (TCR). if (StorageManager.GetSaveDisabled()) { if (ProfileManager.IsFullVersion() && CSocialManager::Instance()->IsTitleAllowedToPostImages() && CSocialManager::Instance()->AreAllUsersAllowedToPostImages() && bUserisClientSide) { ui.SetTooltips(pClass->m_iPad, IDS_TOOLTIPS_SELECT, IDS_TOOLTIPS_BACK, bIsisPrimaryHost ? IDS_TOOLTIPS_SELECTDEVICE : -1, IDS_TOOLTIPS_SHARE, -1, -1, -1, bDisplayBanTip ? IDS_TOOLTIPS_BANLEVEL : -1); } else { ui.SetTooltips(pClass->m_iPad, IDS_TOOLTIPS_SELECT, IDS_TOOLTIPS_BACK, -1, -1, -1, -1, -1, bDisplayBanTip ? IDS_TOOLTIPS_BANLEVEL : -1); } // disable save button // set the focus on to another button pClass->m_Buttons[BUTTON_PAUSE_SAVEGAME].SetEnable(FALSE); pClass->m_Buttons[BUTTON_PAUSE_SAVEGAME].EnableInput(FALSE); pClass->m_Buttons[BUTTON_PAUSE_RESUMEGAME].InitFocus(pClass->m_iPad); } else { if (CSocialManager::Instance()->IsTitleAllowedToPostImages() && CSocialManager::Instance()->AreAllUsersAllowedToPostImages() && bUserisClientSide) { ui.SetTooltips(pClass->m_iPad, IDS_TOOLTIPS_SELECT, IDS_TOOLTIPS_BACK, bIsisPrimaryHost ? IDS_TOOLTIPS_CHANGEDEVICE : -1, IDS_TOOLTIPS_SHARE, -1, -1, -1, bDisplayBanTip ? IDS_TOOLTIPS_BANLEVEL : -1); } else { ui.SetTooltips( pClass->m_iPad, IDS_TOOLTIPS_SELECT, IDS_TOOLTIPS_BACK, bIsisPrimaryHost ? IDS_TOOLTIPS_CHANGEDEVICE : -1, -1, -1, -1, -1, bDisplayBanTip ? IDS_TOOLTIPS_BANLEVEL : -1); } // enable save button pClass->m_Buttons[BUTTON_PAUSE_SAVEGAME].SetEnable(TRUE); pClass->m_Buttons[BUTTON_PAUSE_SAVEGAME].EnableInput(TRUE); } pClass->m_bIgnoreInput = false; return 0; } HRESULT UIScene_PauseMenu::OnCustomMessage_Splitscreenplayer(bool bJoining, BOOL& bHandled) { bHandled = true; return app.AdjustSplitscreenScene_PlayerChanged(m_hObj, &m_OriginalPosition, m_iPad, bJoining, false); } HRESULT UIScene_PauseMenu::OnTimer(XUIMessageTimer* pData, BOOL& rfHandled) { if (pData->nId == IGNORE_KEYPRESS_TIMERID) { XuiKillTimer(m_hObj, IGNORE_KEYPRESS_TIMERID); // 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 { m_bIgnoreInput = false; } } return S_OK; } HRESULT UIScene_PauseMenu::OnDestroy() { // XBackgroundDownloadSetMode(XBACKGROUND_DOWNLOAD_MODE_AUTO); TelemetryManager->RecordUnpauseOrActive(m_iPad); if (m_iPad == ProfileManager.GetPrimaryPad() && g_NetworkManager.IsLocalGame()) { app.SetXuiServerAction(ProfileManager.GetPrimaryPad(), eXuiServerAction_PauseServer, (void*)FALSE); } return S_OK; } int UIScene_PauseMenu::DeviceRemovedDialogReturned( void* pParam, int iPad, C4JStorage::EMessageResult result) { // results switched for this dialog if (result == C4JStorage::EMessage_ResultDecline) { // continue without saving StorageManager.SetSaveDisabled(true); StorageManager.SetSaveDeviceSelected(ProfileManager.GetPrimaryPad(), false); // Has someone pulled the ethernet cable and caused the pause menu to be // closed before this callback returns? if (app.IsPauseMenuDisplayed(ProfileManager.GetPrimaryPad())) { UIScene_PauseMenu* pClass = (UIScene_PauseMenu*)pParam; // use the device select returned function to wipe the saves list // and change the tooltip pClass->DeviceSelectReturned(pClass, true); } } else { // Change device if (app.IsPauseMenuDisplayed(ProfileManager.GetPrimaryPad())) { UIScene_PauseMenu* pClass = (UIScene_PauseMenu*)pParam; StorageManager.SetSaveDevice( &UIScene_PauseMenu::DeviceSelectReturned, pClass, true); } } return 0; } HRESULT UIScene_PauseMenu::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; } // this will send a CustomMessage_DLCMountingComplete when done return S_OK; } HRESULT UIScene_PauseMenu::OnCustomMessage_DLCMountingComplete() { m_bIgnoreInput = false; app.m_dlcManager.checkForCorruptDLCAndAlert(); XBackgroundDownloadSetMode(XBACKGROUND_DOWNLOAD_MODE_AUTO); return S_OK; } void UIScene_PauseMenu::ShowScene(bool show) { SetShow(show ? TRUE : FALSE); } int UIScene_PauseMenu::WarningTrialTexturePackReturned( void* pParam, int iPad, C4JStorage::EMessageResult result) { UIScene_PauseMenu* pScene = (UIScene_PauseMenu*)pParam; // pScene->m_bIgnoreInput = false; pScene->ShowScene(true); if (result == C4JStorage::EMessage_ResultAccept) { if (ProfileManager.IsSignedIn(iPad)) { ULONGLONG ullIndexA[1]; TexturePack* tPack = Minecraft::GetInstance()->skins->getSelected(); // get the dlc texture pack DLCTexturePack* pDLCTexPack = (DLCTexturePack*)tPack; // Need to get the parent packs id, since this may be one of many // child packs with their own ids app.GetDLCFullOfferIDForPackID(pDLCTexPack->getDLCParentPackId(), &ullIndexA[0]); // need to allow downloads here, or the player would need to quit // the game to let the download of a texture pack happen. This might // affect the network traffic, since the download could take all the // bandwidth... XBackgroundDownloadSetMode(XBACKGROUND_DOWNLOAD_MODE_ALWAYS_ALLOW); StorageManager.InstallOffer(1, ullIndexA, NULL, NULL); } } else { TelemetryManager->RecordUpsellResponded( iPad, eSet_UpsellID_Texture_DLC, (pScene->m_pDLCPack->getPurchaseOfferId() & 0xFFFFFFFF), eSen_UpsellOutcome_Declined); } return 0; } int UIScene_PauseMenu::ExitGameSaveDialogReturned( void* pParam, int iPad, C4JStorage::EMessageResult result) { UIScene_PauseMenu* pClass = (UIScene_PauseMenu*)pParam; // Exit with or without saving // Decline means save in this dialog if (result == C4JStorage::EMessage_ResultDecline || result == C4JStorage::EMessage_ResultThirdOption) { if (result == C4JStorage::EMessage_ResultDecline) // Save { // 4J-PB - Is the player trying to save but they are using a trial // texturepack ? if (!Minecraft::GetInstance()->skins->isUsingDefaultSkin()) { TexturePack* tPack = Minecraft::GetInstance()->skins->getSelected(); DLCTexturePack* pDLCTexPack = (DLCTexturePack*)tPack; DLCPack* pDLCPack = pDLCTexPack ->getDLCInfoParentPack(); // tPack->getDLCPack(); if (!pDLCPack->hasPurchasedFile(DLCManager::e_DLCType_Texture, L"")) { #ifdef _XBOX // upsell ULONGLONG ullOfferID_Full; // get the dlc texture pack DLCTexturePack* pDLCTexPack = (DLCTexturePack*)tPack; app.GetDLCFullOfferIDForPackID( pDLCTexPack->getDLCParentPackId(), &ullOfferID_Full); // tell sentient about the upsell of the full version of the // skin pack TelemetryManager->RecordUpsellPresented( iPad, eSet_UpsellID_Texture_DLC, ullOfferID_Full & 0xFFFFFFFF); #endif unsigned int uiIDA[2]; uiIDA[0] = IDS_CONFIRM_OK; uiIDA[1] = IDS_CONFIRM_CANCEL; // Give the player a warning about the trial version of the // texture pack ui.RequestMessageBox( IDS_WARNING_DLC_TRIALTEXTUREPACK_TITLE, IDS_WARNING_DLC_TRIALTEXTUREPACK_TEXT, uiIDA, 2, ProfileManager.GetPrimaryPad(), &UIScene_PauseMenu::WarningTrialTexturePackReturned, pClass, app.GetStringTable()); return S_OK; } } // does the save exist? bool bSaveExists; StorageManager.DoesSaveExist(&bSaveExists); // 4J-PB - we check if the save exists inside the libs // we need to ask if they are sure they want to overwrite the // existing game if (bSaveExists) { unsigned int uiIDA[2]; uiIDA[0] = IDS_CONFIRM_CANCEL; uiIDA[1] = IDS_CONFIRM_OK; ui.RequestMessageBox( IDS_TITLE_SAVE_GAME, IDS_CONFIRM_SAVE_GAME, uiIDA, 2, ProfileManager.GetPrimaryPad(), &UIScene_PauseMenu::ExitGameAndSaveReturned, pClass, app.GetStringTable()); return 0; } else { MinecraftServer::getInstance()->setSaveOnExit(true); } } else { // been a few requests for a confirm on exit without saving unsigned int uiIDA[2]; uiIDA[0] = IDS_CONFIRM_CANCEL; uiIDA[1] = IDS_CONFIRM_OK; ui.RequestMessageBox( IDS_TITLE_DECLINE_SAVE_GAME, IDS_CONFIRM_DECLINE_SAVE_GAME, uiIDA, 2, ProfileManager.GetPrimaryPad(), &UIScene_PauseMenu::ExitGameDeclineSaveReturned, dynamic_cast(pClass), app.GetStringTable()); return 0; } app.SetAction(iPad, eAppAction_ExitWorld); } return 0; } int UIScene_PauseMenu::ExitGameDeclineSaveReturned( void* pParam, int iPad, C4JStorage::EMessageResult result) { // results switched for this dialog if (result == C4JStorage::EMessage_ResultDecline) { MinecraftServer::getInstance()->setSaveOnExit(false); // flag a app action of exit game app.SetAction(iPad, eAppAction_ExitWorld); } else { // has someone disconnected the ethernet here, causing the pause menu to // shut? if (ui.IsPauseMenuDisplayed(ProfileManager.GetPrimaryPad())) { IUIScene_PauseMenu* pClass = (IUIScene_PauseMenu*)pParam; unsigned int uiIDA[3]; // you cancelled the save on exit after choosing exit and save? You // go back to the Exit choices then. uiIDA[0] = IDS_CONFIRM_CANCEL; uiIDA[1] = IDS_EXIT_GAME_SAVE; uiIDA[2] = IDS_EXIT_GAME_NO_SAVE; if (g_NetworkManager.GetPlayerCount() > 1) { ui.RequestMessageBox( IDS_EXIT_GAME, IDS_CONFIRM_EXIT_GAME_CONFIRM_DISCONNECT_SAVE, uiIDA, 3, ProfileManager.GetPrimaryPad(), &UIScene_PauseMenu::ExitGameSaveDialogReturned, pClass, app.GetStringTable(), 0, 0, false); } else { ui.RequestMessageBox( IDS_EXIT_GAME, IDS_CONFIRM_EXIT_GAME, uiIDA, 3, ProfileManager.GetPrimaryPad(), &UIScene_PauseMenu::ExitGameSaveDialogReturned, pClass, app.GetStringTable(), 0, 0, false); } } } return 0; } int UIScene_PauseMenu::ExitGameAndSaveReturned( void* pParam, int iPad, C4JStorage::EMessageResult result) { // 4J-PB - we won't come in here if we have a trial texture pack // results switched for this dialog if (result == C4JStorage::EMessage_ResultDecline) { MinecraftServer::getInstance()->setSaveOnExit(true); // flag a app action of exit game app.SetAction(iPad, eAppAction_ExitWorld); } else { // has someone disconnected the ethernet here, causing the pause menu to // shut? if (ui.IsPauseMenuDisplayed(ProfileManager.GetPrimaryPad())) { UIScene_PauseMenu* pClass = (UIScene_PauseMenu*)pParam; unsigned int uiIDA[3]; // you cancelled the save on exit after choosing exit and save? You // go back to the Exit choices then. uiIDA[0] = IDS_CONFIRM_CANCEL; uiIDA[1] = IDS_EXIT_GAME_SAVE; uiIDA[2] = IDS_EXIT_GAME_NO_SAVE; if (g_NetworkManager.GetPlayerCount() > 1) { ui.RequestMessageBox( IDS_EXIT_GAME, IDS_CONFIRM_EXIT_GAME_CONFIRM_DISCONNECT_SAVE, uiIDA, 3, ProfileManager.GetPrimaryPad(), &UIScene_PauseMenu::ExitGameSaveDialogReturned, pClass, app.GetStringTable(), 0, 0, false); } else { ui.RequestMessageBox( IDS_EXIT_GAME, IDS_CONFIRM_EXIT_GAME, uiIDA, 3, ProfileManager.GetPrimaryPad(), &UIScene_PauseMenu::ExitGameSaveDialogReturned, pClass, app.GetStringTable(), 0, 0, false); } } } return 0; } int UIScene_PauseMenu::SaveGameDialogReturned( void* pParam, int iPad, C4JStorage::EMessageResult result) { // results switched for this dialog if (result == C4JStorage::EMessage_ResultDecline) { // flag a app action of save game app.SetAction(iPad, eAppAction_SaveGame); } return 0; } int UIScene_PauseMenu::ExitGameDialogReturned( void* pParam, int iPad, C4JStorage::EMessageResult result) { // results switched for this dialog if (result == C4JStorage::EMessage_ResultDecline) { app.SetAction(iPad, eAppAction_ExitWorld); } return 0; } int UIScene_PauseMenu::SaveWorldThreadProc(LPVOID lpParameter) { bool bAutosave = (bool)lpParameter; if (bAutosave) { app.SetXuiServerAction(ProfileManager.GetPrimaryPad(), eXuiServerAction_AutoSaveGame); } else { app.SetXuiServerAction(ProfileManager.GetPrimaryPad(), eXuiServerAction_SaveGame); } // Share AABB & Vec3 pools with default (main thread) - should be ok as long // as we don't tick the main thread whilst this thread is running Compression::UseDefaultThreadStorage(); Minecraft* pMinecraft = Minecraft::GetInstance(); // wprintf(L"Loading world on thread\n"); if (ProfileManager.IsFullVersion()) { app.SetGameStarted(false); while (app.GetXuiServerAction(ProfileManager.GetPrimaryPad()) != eXuiServerAction_Idle && !MinecraftServer::serverHalted()) { std::this_thread::sleep_for(std::chrono::milliseconds(10)); } if (!MinecraftServer::serverHalted() && !app.GetChangingSessionType()) app.SetGameStarted(true); } HRESULT hr = S_OK; if (app.GetChangingSessionType()) { // 4J Stu - This causes the fullscreenprogress scene to ignore the // action it was given hr = ERROR_CANCELLED; } return hr; } int UIScene_PauseMenu::ExitWorldThreadProc(void* lpParameter) { // Share AABB & Vec3 pools with default (main thread) - should be ok as long // as we don't tick the main thread whilst this thread is running Compression::UseDefaultThreadStorage(); // app.SetGameStarted(false); _ExitWorld(lpParameter); return S_OK; } // This function performs the meat of exiting from a level. It should be called // from a thread other than the main thread. void UIScene_PauseMenu::_ExitWorld(LPVOID lpParameter) { Minecraft* pMinecraft = Minecraft::GetInstance(); int exitReasonStringId = pMinecraft->progressRenderer->getCurrentTitle(); int exitReasonTitleId = IDS_CONNECTION_LOST; bool saveStats = true; if (pMinecraft->isClientSide() || g_NetworkManager.IsInSession()) { if (lpParameter != NULL) { // 4J-PB - check if we have lost connection to Live if (ProfileManager.GetLiveConnectionStatus() != XONLINE_S_LOGON_CONNECTION_ESTABLISHED) { exitReasonStringId = IDS_CONNECTION_LOST_LIVE; } else { switch (app.GetDisconnectReason()) { case DisconnectPacket::eDisconnect_Kicked: exitReasonStringId = IDS_DISCONNECTED_KICKED; break; case DisconnectPacket::eDisconnect_NoUGC_AllLocal: exitReasonStringId = IDS_NO_USER_CREATED_CONTENT_PRIVILEGE_ALL_LOCAL; exitReasonTitleId = IDS_CONNECTION_FAILED; break; case DisconnectPacket::eDisconnect_NoUGC_Single_Local: exitReasonStringId = IDS_NO_USER_CREATED_CONTENT_PRIVILEGE_SINGLE_LOCAL; exitReasonTitleId = IDS_CONNECTION_FAILED; break; #ifdef _XBOX case DisconnectPacket::eDisconnect_NoUGC_Remote: exitReasonStringId = IDS_NO_USER_CREATED_CONTENT_PRIVILEGE_REMOTE; exitReasonTitleId = IDS_CONNECTION_FAILED; break; #endif case DisconnectPacket::eDisconnect_NoFlying: exitReasonStringId = IDS_DISCONNECTED_FLYING; break; case DisconnectPacket::eDisconnect_Quitting: exitReasonStringId = IDS_DISCONNECTED_SERVER_QUIT; break; case DisconnectPacket::eDisconnect_NoFriendsInGame: exitReasonStringId = IDS_DISCONNECTED_NO_FRIENDS_IN_GAME; exitReasonTitleId = IDS_CANTJOIN_TITLE; break; case DisconnectPacket::eDisconnect_Banned: exitReasonStringId = IDS_DISCONNECTED_BANNED; exitReasonTitleId = IDS_CANTJOIN_TITLE; break; case DisconnectPacket::eDisconnect_NotFriendsWithHost: exitReasonStringId = IDS_NOTALLOWED_FRIENDSOFFRIENDS; exitReasonTitleId = IDS_CANTJOIN_TITLE; break; case DisconnectPacket::eDisconnect_OutdatedServer: exitReasonStringId = IDS_DISCONNECTED_SERVER_OLD; exitReasonTitleId = IDS_CANTJOIN_TITLE; break; case DisconnectPacket::eDisconnect_OutdatedClient: exitReasonStringId = IDS_DISCONNECTED_CLIENT_OLD; exitReasonTitleId = IDS_CANTJOIN_TITLE; break; case DisconnectPacket::eDisconnect_ServerFull: exitReasonStringId = IDS_DISCONNECTED_SERVER_FULL; exitReasonTitleId = IDS_CANTJOIN_TITLE; break; default: exitReasonStringId = IDS_CONNECTION_LOST_SERVER; } } // pMinecraft->progressRenderer->progressStartNoAbort( // exitReasonStringId ); unsigned int uiIDA[1]; uiIDA[0] = IDS_CONFIRM_OK; // 4J Stu - Fix for #48669 - TU5: Code: Compliance: TCR #15: // Incorrect/misleading messages after signing out a profile during // online game session. If the primary player is signed out, then // that is most likely the cause of the disconnection so don't // display a message box. This will allow the message box requested // by the libraries to be brought up if (ProfileManager.IsSignedIn(ProfileManager.GetPrimaryPad())) ui.RequestMessageBox(exitReasonTitleId, exitReasonStringId, uiIDA, 1, ProfileManager.GetPrimaryPad(), NULL, NULL, app.GetStringTable()); exitReasonStringId = -1; // 4J - Force a disconnection, this handles the situation that the // server has already disconnected if (pMinecraft->levels[0] != NULL) pMinecraft->levels[0]->disconnect(false); if (pMinecraft->levels[1] != NULL) pMinecraft->levels[1]->disconnect(false); if (pMinecraft->levels[2] != NULL) pMinecraft->levels[2]->disconnect(false); } else { exitReasonStringId = IDS_EXITING_GAME; pMinecraft->progressRenderer->progressStartNoAbort( IDS_EXITING_GAME); if (pMinecraft->levels[0] != NULL) pMinecraft->levels[0]->disconnect(); if (pMinecraft->levels[1] != NULL) pMinecraft->levels[1]->disconnect(); if (pMinecraft->levels[2] != NULL) pMinecraft->levels[2]->disconnect(); } // 4J Stu - This only does something if we actually have a server, so // don't need to do any other checks MinecraftServer::HaltServer(); // We need to call the stats & leaderboards save before we exit the // session 4J We need to do this in a QNet callback where it is safe // pMinecraft->forceStatsSave(); saveStats = false; // 4J Stu - Leave the session once the disconnect packet has been sent g_NetworkManager.LeaveGame(FALSE); } else { if (lpParameter != NULL && ProfileManager.IsSignedIn(ProfileManager.GetPrimaryPad())) { switch (app.GetDisconnectReason()) { case DisconnectPacket::eDisconnect_Kicked: exitReasonStringId = IDS_DISCONNECTED_KICKED; break; case DisconnectPacket::eDisconnect_NoUGC_AllLocal: exitReasonStringId = IDS_NO_USER_CREATED_CONTENT_PRIVILEGE_ALL_LOCAL; exitReasonTitleId = IDS_CONNECTION_FAILED; break; case DisconnectPacket::eDisconnect_NoUGC_Single_Local: exitReasonStringId = IDS_NO_USER_CREATED_CONTENT_PRIVILEGE_SINGLE_LOCAL; exitReasonTitleId = IDS_CONNECTION_FAILED; break; #ifdef _XBOX case DisconnectPacket::eDisconnect_NoUGC_Remote: exitReasonStringId = IDS_NO_USER_CREATED_CONTENT_PRIVILEGE_REMOTE; exitReasonTitleId = IDS_CONNECTION_FAILED; break; #endif case DisconnectPacket::eDisconnect_Quitting: exitReasonStringId = IDS_DISCONNECTED_SERVER_QUIT; break; case DisconnectPacket::eDisconnect_NoMultiplayerPrivilegesJoin: exitReasonStringId = IDS_NO_MULTIPLAYER_PRIVILEGE_JOIN_TEXT; break; case DisconnectPacket::eDisconnect_OutdatedServer: exitReasonStringId = IDS_DISCONNECTED_SERVER_OLD; exitReasonTitleId = IDS_CANTJOIN_TITLE; break; case DisconnectPacket::eDisconnect_OutdatedClient: exitReasonStringId = IDS_DISCONNECTED_CLIENT_OLD; exitReasonTitleId = IDS_CANTJOIN_TITLE; break; case DisconnectPacket::eDisconnect_ServerFull: exitReasonStringId = IDS_DISCONNECTED_SERVER_FULL; exitReasonTitleId = IDS_CANTJOIN_TITLE; break; default: exitReasonStringId = IDS_DISCONNECTED; } // pMinecraft->progressRenderer->progressStartNoAbort( // exitReasonStringId ); unsigned int uiIDA[1]; uiIDA[0] = IDS_CONFIRM_OK; ui.RequestMessageBox(exitReasonTitleId, exitReasonStringId, uiIDA, 1, ProfileManager.GetPrimaryPad(), NULL, NULL, app.GetStringTable()); exitReasonStringId = -1; } } // Fix for #93148 - TCR 001: BAS Game Stability: Title will crash for the // multiplayer client if host of the game will exit during the clients // loading to created world. while (g_NetworkManager.IsNetworkThreadRunning()) { std::this_thread::sleep_for(std::chrono::milliseconds(1)); } pMinecraft->setLevel(NULL, exitReasonStringId, nullptr, saveStats); TelemetryManager->Flush(); app.m_gameRules.unloadCurrentGameRules(); // app.m_Audio.unloadCurrentAudioDetails(); MinecraftServer::resetFlags(); // Fix for #48385 - BLACK OPS :TU5: Functional: Client becomes pseudo // soft-locked when returned to the main menu after a remote disconnect Make // sure there is text explaining why the player is waiting pMinecraft->progressRenderer->progressStart(IDS_EXITING_GAME); // Fix for #13259 - CRASH: Gameplay: loading process is halted when player // loads saved data We can't start/join a new game until the session is // destroyed, so wait for it to be idle again while (g_NetworkManager.IsInSession()) { std::this_thread::sleep_for(std::chrono::milliseconds(1)); } app.SetChangingSessionType(false); app.SetReallyChangingSessionType(false); } void UIScene_PauseMenu::SetIgnoreInput(bool ignoreInput) { m_bIgnoreInput = ignoreInput; }