#include "../../Minecraft.World/Platform/stdafx.h" #include "../../Minecraft.World/Util/Random.h" #include "../../Minecraft.World/Util/StringHelpers.h" #include "XUI_MultiGameCreate.h" #include "XUI_Controls.h" #include "../../Minecraft.Client/MinecraftServer.h" #include "../../Minecraft.Client/Minecraft.h" #include "../../Minecraft.Client/GameState/Options.h" #include "../../Minecraft.World/Level/Storage/LevelSettings.h" #include "XUI_MultiGameLaunchMoreOptions.h" #include "../../Minecraft.World/WorldGen/Biomes/BiomeSource.h" #include "../../Minecraft.World/Util/IntCache.h" #include "../../Minecraft.World/Level/Storage/LevelType.h" #include "../../Minecraft.Client/Textures/Packs/TexturePackRepository.h" #include "../../Minecraft.Client/Textures/Packs/TexturePack.h" #include "../DLC/DLCLocalisationFile.h" #include "../../Minecraft.Client/Utils/StringTable.h" #include "../../Minecraft.Client/Textures/Packs/DLCTexturePack.h" #define GAME_CREATE_ONLINE_TIMER_ID 0 #define GAME_CREATE_ONLINE_TIMER_TIME 100 #define CHECKFORAVAILABLETEXTUREPACKS_TIMER_ID 1 #define CHECKFORAVAILABLETEXTUREPACKS_TIMER_TIME 100 int CScene_MultiGameCreate::m_iDifficultyTitleSettingA[4] = { IDS_DIFFICULTY_TITLE_PEACEFUL, IDS_DIFFICULTY_TITLE_EASY, IDS_DIFFICULTY_TITLE_NORMAL, IDS_DIFFICULTY_TITLE_HARD}; //---------------------------------------------------------------------------------- // Performs initialization tasks - retrieves controls. //---------------------------------------------------------------------------------- HRESULT CScene_MultiGameCreate::OnInit(XUIMessageInit* pInitData, BOOL& bHandled) { m_bSetup = false; m_texturePackDescDisplayed = false; m_iConfigA = NULL; WCHAR TempString[256]; MapChildControls(); XuiControlSetText(m_EditWorldName, app.GetString(IDS_DEFAULT_WORLD_NAME)); XuiControlSetText(m_MoreOptions, app.GetString(IDS_MORE_OPTIONS)); XuiControlSetText(m_NewWorld, app.GetString(IDS_CREATE_NEW_WORLD)); XuiControlSetText(m_labelWorldName, app.GetString(IDS_WORLD_NAME)); XuiControlSetText(m_labelSeed, app.GetString(IDS_CREATE_NEW_WORLD_SEED)); XuiControlSetText(m_labelRandomSeed, app.GetString(IDS_CREATE_NEW_WORLD_RANDOM_SEED)); XuiControlSetText(m_pTexturePacksList->m_hObj, app.GetString(IDS_DLC_MENU_TEXTUREPACKS)); CreateWorldMenuInitData* params = (CreateWorldMenuInitData*)pInitData->pvInitData; m_MoreOptionsParams.bGenerateOptions = true; m_MoreOptionsParams.bStructures = true; m_MoreOptionsParams.bFlatWorld = false; m_MoreOptionsParams.bBonusChest = false; m_MoreOptionsParams.bPVP = true; m_MoreOptionsParams.bTrust = true; m_MoreOptionsParams.bFireSpreads = true; m_MoreOptionsParams.bHostPrivileges = false; m_MoreOptionsParams.bTNT = true; m_MoreOptionsParams.iPad = params->iPad; m_iPad = params->iPad; delete params; m_bMultiplayerAllowed = ProfileManager.IsSignedInLive(m_iPad) && ProfileManager.AllowedToPlayMultiplayer(m_iPad); // 4J-PB - read the settings for the online flag. We'll only save this // setting if the user changed it. bool bGameSetting_Online = (app.GetGameSettings(m_iPad, eGameSetting_Online) != 0); m_MoreOptionsParams.bOnlineSettingChangedBySystem = false; // Set the text for friends of friends, and default to on if (m_bMultiplayerAllowed) { m_MoreOptionsParams.bOnlineGame = bGameSetting_Online; if (bGameSetting_Online) { m_MoreOptionsParams.bInviteOnly = app.GetGameSettings(m_iPad, eGameSetting_InviteOnly) != 0; m_MoreOptionsParams.bAllowFriendsOfFriends = app.GetGameSettings(m_iPad, eGameSetting_FriendsOfFriends) != 0; } else { m_MoreOptionsParams.bInviteOnly = false; m_MoreOptionsParams.bAllowFriendsOfFriends = false; } } else { m_MoreOptionsParams.bOnlineGame = false; m_MoreOptionsParams.bInviteOnly = false; m_MoreOptionsParams.bAllowFriendsOfFriends = false; if (bGameSetting_Online) { // The profile settings say Online, but either the player is // offline, or they are not allowed to play online m_MoreOptionsParams.bOnlineSettingChangedBySystem = true; } } m_ButtonGameMode.SetText(app.GetString(IDS_GAMEMODE_SURVIVAL)); m_bGameModeSurvival = true; m_CurrentDifficulty = app.GetGameSettings(m_iPad, eGameSetting_Difficulty); m_SliderDifficulty.SetValue(m_CurrentDifficulty); swprintf((WCHAR*)TempString, 256, L"%ls: %ls", app.GetString(IDS_SLIDER_DIFFICULTY), app.GetString(m_iDifficultyTitleSettingA[m_CurrentDifficulty])); m_SliderDifficulty.SetText(TempString); ui.SetTooltips(DEFAULT_XUI_MENU_USER, IDS_TOOLTIPS_SELECT, IDS_TOOLTIPS_BACK); CXuiSceneBase::ShowLogo(DEFAULT_XUI_MENU_USER, FALSE); // restrict the keyboard - don't want languages that are not supported, like // cyrillic, etc. switch (XGetLanguage()) { case XC_LANGUAGE_ENGLISH: case XC_LANGUAGE_GERMAN: case XC_LANGUAGE_FRENCH: case XC_LANGUAGE_SPANISH: case XC_LANGUAGE_ITALIAN: case XC_LANGUAGE_PORTUGUESE: case XC_LANGUAGE_JAPANESE: case XC_LANGUAGE_TCHINESE: case XC_LANGUAGE_KOREAN: m_EditWorldName.SetKeyboardType(C_4JInput::EKeyboardMode_Default); m_EditWorldName.SetKeyboardType(C_4JInput::EKeyboardMode_Default); break; default: m_EditWorldName.SetKeyboardType(C_4JInput::EKeyboardMode_Full); m_EditWorldName.SetKeyboardType(C_4JInput::EKeyboardMode_Full); break; } m_NewWorld.SetEnable(true); m_EditWorldName.SetTextLimit(XCONTENT_MAX_DISPLAYNAME_LENGTH); std::wstring wWorldName = m_EditWorldName.GetText(); // set the caret to the end of the default text m_EditWorldName.SetCaretPosition((int)wWorldName.length()); // In the dashboard, there's room for about 30 W characters on two lines // before they go over the top of things m_EditWorldName.SetTextLimit(25); m_EditWorldName.SetTitleAndText(IDS_NAME_WORLD, IDS_NAME_WORLD_TEXT); m_EditSeed.SetTitleAndText(IDS_CREATE_NEW_WORLD, IDS_CREATE_NEW_WORLD_SEEDTEXT); XuiSetTimer(m_hObj, GAME_CREATE_ONLINE_TIMER_ID, GAME_CREATE_ONLINE_TIMER_TIME); XuiSetTimer(m_hObj, CHECKFORAVAILABLETEXTUREPACKS_TIMER_ID, CHECKFORAVAILABLETEXTUREPACKS_TIMER_TIME); TelemetryManager->RecordMenuShown(m_iPad, eUIScene_CreateWorldMenu, 0); // 4J-PB - Load up any texture pack data we have locally in the XZP for (int i = 0; i < TMS_COUNT; i++) { if (app.TMSFileA[i].eTMSType == eTMSFileType_TexturePack) { app.LoadLocalTMSFile(app.TMSFileA[i].wchFilename, app.TMSFileA[i].eEXT); app.AddMemoryTPDFile(app.TMSFileA[i].iConfig, app.TMSFileA[i].pbData, app.TMSFileA[i].uiSize); } } m_iTexturePacksNotInstalled = 0; // 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; m_pTexturePacksList->SetSelectionChangedHandle(m_hObj); Minecraft* pMinecraft = Minecraft::GetInstance(); int texturePacksCount = pMinecraft->skins->getTexturePackCount(); CXuiCtrl4JList::LIST_ITEM_INFO ListInfo; HRESULT hr; for (unsigned int i = 0; i < texturePacksCount; ++i) { TexturePack* tp = pMinecraft->skins->getTexturePackByIndex(i); ZeroMemory(&ListInfo, sizeof(CXuiCtrl4JList::LIST_ITEM_INFO)); std::uint32_t imageBytes = 0; std::uint8_t* imageData = tp->getPackIcon(imageBytes); if (imageBytes > 0 && imageData) { ListInfo.fEnabled = TRUE; DLCTexturePack* pDLCTexPack = (DLCTexturePack*)tp; if (pDLCTexPack) { int id = pDLCTexPack->getDLCParentPackId(); if (id == 0) { // default texture pack - should come first ListInfo.iSortIndex = 0x0FFFFFFF; } else { ListInfo.iSortIndex = id; ListInfo.iData = id; } } #ifdef _DEBUG app.DebugPrintf("TP - "); OutputDebugStringW(tp->getName().c_str()); app.DebugPrintf(", sort index - %d\n", ListInfo.iSortIndex); #endif hr = XuiCreateTextureBrushFromMemory(imageData, imageBytes, &ListInfo.hXuiBrush); m_pTexturePacksList->AddData(ListInfo, 0, CXuiCtrl4JList::eSortList_Index); } } // 4J-PB - there may be texture packs we don't have, so use the info // from TMS for this DLC_INFO* pDLCInfo = NULL; // first pass - look to see if there are any that are not in the list bool bTexturePackAlreadyListed; bool bNeedToGetTPD = false; 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; } } } m_currentTexturePackIndex = pMinecraft->skins->getTexturePackIndex(0); UpdateTexturePackDescription(m_currentTexturePackIndex); m_bSetup = true; } return S_OK; } HRESULT CScene_MultiGameCreate::OnDestroy() { // clear out the texture pack data for (int i = 0; i < TMS_COUNT; i++) { if (app.TMSFileA[i].eTMSType == eTMSFileType_TexturePack) { app.RemoveMemoryTPDFile(app.TMSFileA[i].iConfig); } } app.FreeLocalTMSFiles(eTMSFileType_TexturePack); return S_OK; } //---------------------------------------------------------------------------------- // Handler for the button press message. //---------------------------------------------------------------------------------- HRESULT CScene_MultiGameCreate::OnNotifyPressEx( HXUIOBJ hObjPressed, XUINotifyPress* pNotifyPressData, BOOL& rfHandled) { if (m_bIgnoreInput) return S_OK; Minecraft* pMinecraft = Minecraft::GetInstance(); // This assumes all buttons can only be pressed with the A button ui.AnimateKeyPress(pNotifyPressData->UserIndex, VK_PAD_A); if (hObjPressed == m_NewWorld) { // Check if we need to upsell the texture pack if (m_MoreOptionsParams.dwTexturePack != 0) { // texture pack hasn't been set yet, so check what it will be TexturePack* pTexturePack = pMinecraft->skins->getTexturePackById( m_MoreOptionsParams.dwTexturePack); if (pTexturePack == NULL) { // They've selected a texture pack they don't have yet // upsell CXuiCtrl4JList::LIST_ITEM_INFO ListItem; // get the current index of the list, and then get the data ListItem = m_pTexturePacksList->GetData(m_currentTexturePackIndex); // upsell the texture pack // tell sentient about the upsell of the full version of the // skin pack ULONGLONG ullOfferID_Full; app.GetDLCFullOfferIDForPackID(ListItem.iData, &ullOfferID_Full); // DLC might have been corrupt if (ullOfferID_Full != 0LL) { TelemetryManager->RecordUpsellPresented( ProfileManager.GetPrimaryPad(), eSet_UpsellID_Texture_DLC, ullOfferID_Full & 0xFFFFFFFF); unsigned int 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_MultiGameCreate::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_MultiGameCreate::TexturePackDialogReturned, this, app.GetStringTable()); } return S_OK; } } } m_bIgnoreInput = true; SetShow(FALSE); bool isClientSide = ProfileManager.IsSignedInLive(ProfileManager.GetPrimaryPad()) && m_MoreOptionsParams.bOnlineGame; // if the profile data has been changed, then force a profile write (we // save the online/invite/friends of friends settings) It seems we're // allowed to break the 5 minute rule if it's the result of a user // action check the checkboxes // Only save the online setting if the user changed it - we may change // it because we're offline, but don't want that saved if (!m_MoreOptionsParams.bOnlineSettingChangedBySystem) { app.SetGameSettings(m_iPad, eGameSetting_Online, m_MoreOptionsParams.bOnlineGame ? 1 : 0); } app.SetGameSettings(m_iPad, eGameSetting_InviteOnly, m_MoreOptionsParams.bInviteOnly ? 1 : 0); app.SetGameSettings(m_iPad, eGameSetting_FriendsOfFriends, m_MoreOptionsParams.bAllowFriendsOfFriends ? 1 : 0); app.CheckGameSettingsChanged(true, pNotifyPressData->UserIndex); // Check that we have the rights to use a texture pack we have selected. if (m_MoreOptionsParams.dwTexturePack != 0) { // texture pack hasn't been set yet, so check what it will be TexturePack* pTexturePack = pMinecraft->skins->getTexturePackById( m_MoreOptionsParams.dwTexturePack); if (pTexturePack == NULL) { // corrupt DLC so set it to the default textures m_MoreOptionsParams.dwTexturePack = 0; } else { m_pDLCPack = pTexturePack->getDLCPack(); // do we have a license? if (m_pDLCPack && !m_pDLCPack->hasPurchasedFile( DLCManager::e_DLCType_Texture, L"")) { // no unsigned int uiIDA[1]; uiIDA[0] = IDS_OK; if (!ProfileManager.IsSignedInLive( pNotifyPressData->UserIndex)) { // need to be signed in to live StorageManager.RequestMessageBox( IDS_PRO_NOTONLINE_TITLE, IDS_PRO_XBOXLIVE_NOTIFICATION, uiIDA, 1); return S_OK; } else { // upsell DLC_INFO* pDLCInfo = app.GetDLCInfoForTrialOfferID( m_pDLCPack->getPurchaseOfferId()); ULONGLONG ullOfferID_Full; if (pDLCInfo != NULL) { ullOfferID_Full = pDLCInfo->ullOfferID_Full; } else { ullOfferID_Full = pTexturePack->getDLCPack() ->getPurchaseOfferId(); } // tell sentient about the upsell of the full version of // the skin pack TelemetryManager->RecordUpsellPresented( pNotifyPressData->UserIndex, eSet_UpsellID_Texture_DLC, ullOfferID_Full & 0xFFFFFFFF); unsigned int uiIDA[1]; uiIDA[0] = IDS_CONFIRM_OK; // 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, 1, pNotifyPressData->UserIndex, &CScene_MultiGameCreate:: WarningTrialTexturePackReturned, this, app.GetStringTable()); return S_OK; } } } } if (m_bGameModeSurvival != true || m_MoreOptionsParams.bHostPrivileges) { unsigned int uiIDA[2]; uiIDA[0] = IDS_CONFIRM_OK; uiIDA[1] = IDS_CONFIRM_CANCEL; if (m_bGameModeSurvival != true) { StorageManager.RequestMessageBox( IDS_TITLE_START_GAME, IDS_CONFIRM_START_CREATIVE, uiIDA, 2, m_iPad, &CScene_MultiGameCreate::ConfirmCreateReturned, this, app.GetStringTable()); } else { StorageManager.RequestMessageBox( IDS_TITLE_START_GAME, IDS_CONFIRM_START_HOST_PRIVILEGES, uiIDA, 2, m_iPad, &CScene_MultiGameCreate::ConfirmCreateReturned, this, app.GetStringTable()); } } else { // 4J Stu - If we only have one controller connected, then don't // show the sign-in UI again int connectedControllers = 0; for (unsigned int i = 0; i < XUSER_MAX_COUNT; ++i) { if (InputManager.IsPadConnected(i) || ProfileManager.IsSignedIn(i)) ++connectedControllers; } if (isClientSide && connectedControllers > 1 && RenderManager.IsHiDef()) { ProfileManager.RequestSignInUI( false, false, false, true, false, &CScene_MultiGameCreate::StartGame_SignInReturned, this, ProfileManager.GetPrimaryPad()); } else { // Check if user-created content is allowed, as we cannot play // multiplayer if it's not // bool isClientSide = // ProfileManager.IsSignedInLive(ProfileManager.GetPrimaryPad()) // && m_MoreOptionsParams.bOnlineGame; bool noUGC = false; bool pccAllowed = true; bool pccFriendsAllowed = true; ProfileManager.AllowedPlayerCreatedContent( ProfileManager.GetPrimaryPad(), false, &pccAllowed, &pccFriendsAllowed); if (!pccAllowed && !pccFriendsAllowed) noUGC = true; if (isClientSide && noUGC) { m_bIgnoreInput = false; SetShow(TRUE); unsigned int uiIDA[1]; uiIDA[0] = IDS_CONFIRM_OK; StorageManager.RequestMessageBox( IDS_FAILED_TO_CREATE_GAME_TITLE, IDS_NO_USER_CREATED_CONTENT_PRIVILEGE_CREATE, uiIDA, 1, ProfileManager.GetPrimaryPad(), NULL, NULL, app.GetStringTable()); } else { CreateGame(this, 0); } } } } else if (hObjPressed == m_MoreOptions) { app.NavigateToScene(pNotifyPressData->UserIndex, eUIScene_LaunchMoreOptionsMenu, &m_MoreOptionsParams); } else if (hObjPressed == m_ButtonGameMode) { if (m_bGameModeSurvival) { m_ButtonGameMode.SetText(app.GetString(IDS_GAMEMODE_CREATIVE)); m_bGameModeSurvival = false; } else { m_ButtonGameMode.SetText(app.GetString(IDS_GAMEMODE_SURVIVAL)); m_bGameModeSurvival = true; } } else if (hObjPressed == m_pTexturePacksList->m_hObj) { UpdateCurrentTexturePack(); } return S_OK; } int CScene_MultiGameCreate::UnlockTexturePackReturned( void* pParam, int iPad, C4JStorage::EMessageResult result) { CScene_MultiGameCreate* pScene = (CScene_MultiGameCreate*)pParam; #ifdef _XBOX if (result == C4JStorage::EMessage_ResultAccept) { if (ProfileManager.IsSignedIn(iPad)) { ULONGLONG ullIndexA[1]; DLC_INFO* pDLCInfo = app.GetDLCInfoForTrialOfferID( pScene->m_pDLCPack->getPurchaseOfferId()); if (pDLCInfo != NULL) { ullIndexA[0] = pDLCInfo->ullOfferID_Full; } else { ullIndexA[0] = pScene->m_pDLCPack->getPurchaseOfferId(); } StorageManager.InstallOffer(1, ullIndexA, NULL, NULL); // the license change coming in when the offer has been installed // will cause this scene to refresh } } else { TelemetryManager->RecordUpsellResponded( iPad, eSet_UpsellID_Texture_DLC, (pScene->m_pDLCPack->getPurchaseOfferId() & 0xFFFFFFFF), eSen_UpsellOutcome_Declined); } #endif pScene->m_bIgnoreInput = false; pScene->SetShow(TRUE); return 0; } int CScene_MultiGameCreate::WarningTrialTexturePackReturned( void* pParam, int iPad, C4JStorage::EMessageResult result) { CScene_MultiGameCreate* pScene = (CScene_MultiGameCreate*)pParam; pScene->m_bIgnoreInput = false; pScene->SetShow(TRUE); bool isClientSide = ProfileManager.IsSignedInLive(ProfileManager.GetPrimaryPad()) && pScene->m_MoreOptionsParams.bOnlineGame; // 4J Stu - If we only have one controller connected, then don't show the // sign-in UI again int connectedControllers = 0; for (unsigned int i = 0; i < XUSER_MAX_COUNT; ++i) { if (InputManager.IsPadConnected(i) || ProfileManager.IsSignedIn(i)) ++connectedControllers; } if (isClientSide && connectedControllers > 1 && RenderManager.IsHiDef()) { ProfileManager.RequestSignInUI( false, false, false, true, false, &CScene_MultiGameCreate::StartGame_SignInReturned, pScene, ProfileManager.GetPrimaryPad()); } else { // Check if user-created content is allowed, as we cannot play // multiplayer if it's not bool noUGC = false; bool pccAllowed = true; bool pccFriendsAllowed = true; ProfileManager.AllowedPlayerCreatedContent( ProfileManager.GetPrimaryPad(), false, &pccAllowed, &pccFriendsAllowed); if (!pccAllowed && !pccFriendsAllowed) noUGC = true; if (isClientSide && noUGC) { unsigned int uiIDA[1]; uiIDA[0] = IDS_CONFIRM_OK; StorageManager.RequestMessageBox( IDS_FAILED_TO_CREATE_GAME_TITLE, IDS_NO_USER_CREATED_CONTENT_PRIVILEGE_CREATE, uiIDA, 1, ProfileManager.GetPrimaryPad(), NULL, NULL, app.GetStringTable()); } else { // This is called from a storage manager thread... need to set up // thread storage for IntCache as CreateGame requires this to search // for a suitable seed if we haven't set a seed. IntCache::CreateNewThreadStorage(); CreateGame(pScene, 0); IntCache::ReleaseThreadStorage(); } } return 0; } HRESULT CScene_MultiGameCreate::OnKeyDown(XUIMessageInput* pInputData, BOOL& rfHandled) { if (m_bIgnoreInput) return S_OK; ui.AnimateKeyPress(pInputData->UserIndex, pInputData->dwKeyCode); // Explicitly handle B button presses switch (pInputData->dwKeyCode) { case VK_PAD_B: case VK_ESCAPE: app.NavigateBack(pInputData->UserIndex); rfHandled = TRUE; break; } return S_OK; } HRESULT CScene_MultiGameCreate::OnNotifyValueChanged( HXUIOBJ hObjSource, XUINotifyValueChanged* pValueChangedData, BOOL& rfHandled) { WCHAR TempString[256]; if (hObjSource == m_EditWorldName) { // Enable the done button when we have all of the necessary information std::wstring wWorldName = m_EditWorldName.GetText(); bool bHasWorldName = (wWorldName.length() != 0); m_NewWorld.SetEnable(bHasWorldName); } else if (hObjSource == m_SliderDifficulty.GetSlider()) { app.SetGameSettings(m_iPad, eGameSetting_Difficulty, pValueChangedData->nValue); swprintf((WCHAR*)TempString, 256, L"%ls: %ls", app.GetString(IDS_SLIDER_DIFFICULTY), app.GetString( m_iDifficultyTitleSettingA[pValueChangedData->nValue])); m_SliderDifficulty.SetText(TempString); } return S_OK; } HRESULT CScene_MultiGameCreate::OnControlNavigate( XUIMessageControlNavigate* pControlNavigateData, BOOL& bHandled) { pControlNavigateData->hObjDest = XuiControlGetNavigation( pControlNavigateData->hObjSource, pControlNavigateData->nControlNavigate, TRUE, TRUE); if (pControlNavigateData->hObjDest == NULL) { pControlNavigateData->hObjDest = pControlNavigateData->hObjSource; } bHandled = TRUE; return S_OK; } HRESULT CScene_MultiGameCreate::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 GAME_CREATE_ONLINE_TIMER_ID: { bool bMultiplayerAllowed = ProfileManager.IsSignedInLive(m_iPad) && ProfileManager.AllowedToPlayMultiplayer(m_iPad); if (bMultiplayerAllowed != m_bMultiplayerAllowed) { if (bMultiplayerAllowed) { bool bGameSetting_Online = (app.GetGameSettings(m_iPad, eGameSetting_Online) != 0); m_MoreOptionsParams.bOnlineGame = bGameSetting_Online; if (bGameSetting_Online) { m_MoreOptionsParams.bInviteOnly = app.GetGameSettings(m_iPad, eGameSetting_InviteOnly) != 0; m_MoreOptionsParams.bAllowFriendsOfFriends = app.GetGameSettings( m_iPad, eGameSetting_FriendsOfFriends) != 0; } else { m_MoreOptionsParams.bInviteOnly = false; m_MoreOptionsParams.bAllowFriendsOfFriends = false; } } else { m_MoreOptionsParams.bOnlineGame = false; m_MoreOptionsParams.bInviteOnly = false; m_MoreOptionsParams.bAllowFriendsOfFriends = false; } m_bMultiplayerAllowed = bMultiplayerAllowed; } } 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 < m_iTexturePacksNotInstalled; i++) { if (m_iConfigA[i] != -1) { unsigned int dwBytes = 0; std::uint8_t* pbData = NULL; // app.DebugPrintf("Retrieving iConfig %d from // TPD\n",m_iConfigA[i]); app.GetTPD(m_iConfigA[i], &pbData, &dwBytes); ZeroMemory(&ListInfo, sizeof(CXuiCtrl4JList::LIST_ITEM_INFO)); if (dwBytes > 0 && pbData) { unsigned int dwImageBytes = 0; std::uint8_t* pbImageData = NULL; app.GetFileFromTPD(eTPDFileType_Icon, pbData, dwBytes, &pbImageData, &dwImageBytes); ListInfo.fEnabled = TRUE; ListInfo.iData = m_iConfigA[i]; HRESULT hr = XuiCreateTextureBrushFromMemory( pbImageData, dwImageBytes, &ListInfo.hXuiBrush); app.DebugPrintf("Adding texturepack %d from TPD\n", m_iConfigA[i]); ListInfo.iSortIndex = m_iConfigA[i]; m_pTexturePacksList->AddData( ListInfo, 0, CXuiCtrl4JList::eSortList_Index); m_iConfigA[i] = -1; } } } bool bAllDone = true; for (int i = 0; i < m_iTexturePacksNotInstalled; i++) { if (m_iConfigA[i] != -1) { bAllDone = false; } } if (bAllDone) { // kill this timer XuiKillTimer(m_hObj, CHECKFORAVAILABLETEXTUREPACKS_TIMER_ID); } } break; } return S_OK; } int CScene_MultiGameCreate::ConfirmCreateReturned( void* pParam, int iPad, C4JStorage::EMessageResult result) { CScene_MultiGameCreate* pClass = (CScene_MultiGameCreate*)pParam; if (result == C4JStorage::EMessage_ResultAccept) { bool isClientSide = ProfileManager.IsSignedInLive(ProfileManager.GetPrimaryPad()) && pClass->m_MoreOptionsParams.bOnlineGame; // 4J Stu - If we only have one controller connected, then don't show // the sign-in UI again int connectedControllers = 0; for (unsigned int i = 0; i < XUSER_MAX_COUNT; ++i) { if (InputManager.IsPadConnected(i) || ProfileManager.IsSignedIn(i)) ++connectedControllers; } if (isClientSide && connectedControllers > 1 && RenderManager.IsHiDef()) { ProfileManager.RequestSignInUI( false, false, false, true, false, &CScene_MultiGameCreate::StartGame_SignInReturned, pClass, ProfileManager.GetPrimaryPad()); } else { // Check if user-created content is allowed, as we cannot play // multiplayer if it's not bool isClientSide = ProfileManager.IsSignedInLive(ProfileManager.GetPrimaryPad()) && pClass->m_MoreOptionsParams.bOnlineGame; bool noUGC = false; bool pccAllowed = true; bool pccFriendsAllowed = true; ProfileManager.AllowedPlayerCreatedContent( ProfileManager.GetPrimaryPad(), false, &pccAllowed, &pccFriendsAllowed); if (!pccAllowed && !pccFriendsAllowed) noUGC = true; if (isClientSide && noUGC) { pClass->m_bIgnoreInput = false; pClass->SetShow(TRUE); unsigned int uiIDA[1]; uiIDA[0] = IDS_CONFIRM_OK; StorageManager.RequestMessageBox( IDS_FAILED_TO_CREATE_GAME_TITLE, IDS_NO_USER_CREATED_CONTENT_PRIVILEGE_CREATE, uiIDA, 1, ProfileManager.GetPrimaryPad(), NULL, NULL, app.GetStringTable()); } else { // This is called from a storage manager thread... need to set // up thread storage for IntCache as CreateGame requires this to // search for a suitable seed if we haven't set a seed. IntCache::CreateNewThreadStorage(); CreateGame(pClass, 0); IntCache::ReleaseThreadStorage(); } } } else { pClass->m_bIgnoreInput = false; pClass->SetShow(TRUE); } return 0; } int CScene_MultiGameCreate::StartGame_SignInReturned(void* pParam, bool bContinue, int iPad) { CScene_MultiGameCreate* pClass = (CScene_MultiGameCreate*)pParam; if (bContinue == true) { // It's possible that the player has not signed in - they can back out if (ProfileManager.IsSignedIn(iPad)) { unsigned int dwLocalUsersMask = 0; bool isClientSide = ProfileManager.IsSignedInLive(ProfileManager.GetPrimaryPad()) && pClass->m_MoreOptionsParams.bOnlineGame; bool noPrivileges = false; for (unsigned int index = 0; index < XUSER_MAX_COUNT; ++index) { if (ProfileManager.IsSignedIn(index)) { if (!ProfileManager.AllowedToPlayMultiplayer(index)) noPrivileges = true; dwLocalUsersMask |= CGameNetworkManager::GetLocalPlayerMask(index); } } // Check if user-created content is allowed, as we cannot play // multiplayer if it's not bool noUGC = false; bool pccAllowed = true; bool pccFriendsAllowed = true; ProfileManager.AllowedPlayerCreatedContent( ProfileManager.GetPrimaryPad(), false, &pccAllowed, &pccFriendsAllowed); if (!pccAllowed && !pccFriendsAllowed) noUGC = true; if (isClientSide && (noPrivileges || noUGC)) { if (noUGC) { pClass->m_bIgnoreInput = false; pClass->SetShow(TRUE); unsigned int uiIDA[1]; uiIDA[0] = IDS_CONFIRM_OK; StorageManager.RequestMessageBox( IDS_FAILED_TO_CREATE_GAME_TITLE, IDS_NO_USER_CREATED_CONTENT_PRIVILEGE_CREATE, uiIDA, 1, ProfileManager.GetPrimaryPad(), NULL, NULL, app.GetStringTable()); } else { pClass->m_bIgnoreInput = false; pClass->SetShow(TRUE); unsigned int uiIDA[1]; uiIDA[0] = IDS_CONFIRM_OK; StorageManager.RequestMessageBox( IDS_NO_MULTIPLAYER_PRIVILEGE_TITLE, IDS_NO_MULTIPLAYER_PRIVILEGE_HOST_TEXT, uiIDA, 1, ProfileManager.GetPrimaryPad(), NULL, NULL, app.GetStringTable()); } } else { // This is NOT called from a storage manager thread, and is in // fact called from the main thread in the Profile library tick. // Therefore we use the main threads IntCache. CreateGame(pClass, dwLocalUsersMask); } } } else { pClass->m_bIgnoreInput = false; pClass->SetShow(TRUE); } return 0; } // 4J Stu - Shared functionality that is the same whether we needed a quadrant // sign-in or not void CScene_MultiGameCreate::CreateGame(CScene_MultiGameCreate* pClass, DWORD dwLocalUsersMask) { // stop the timer running that causes a check for new texture packs in TMS // but not installed, since this will run all through the create game, and // will crash if it tries to create an hbrush XuiKillTimer(pClass->m_hObj, CHECKFORAVAILABLETEXTUREPACKS_TIMER_ID); bool isClientSide = ProfileManager.IsSignedInLive(ProfileManager.GetPrimaryPad()) && pClass->m_MoreOptionsParams.bOnlineGame; bool isPrivate = pClass->m_MoreOptionsParams.bInviteOnly ? true : false; // clear out the app's terrain features list app.ClearTerrainFeaturePosition(); // create the world and launch std::wstring wWorldName = pClass->m_EditWorldName.GetText(); StorageManager.ResetSaveData(); // Make our next save default to the name of the level StorageManager.SetSaveTitle((wchar_t*)wWorldName.c_str()); bool bHasSeed = (pClass->m_EditSeed.GetText() != NULL); std::wstring wSeed; if (bHasSeed) { wSeed = pClass->m_EditSeed.GetText(); } else { // random wSeed = L""; } // start the game bool isFlat = pClass->m_MoreOptionsParams.bFlatWorld; __int64 seedValue = 0; // BiomeSource::findSeed(isFlat?LevelType::lvl_flat:LevelType::lvl_normal); // // 4J - was (new Random())->nextLong() - now trying to actually // find a seed to suit our requirements if (wSeed.length() != 0) { __int64 value = 0; unsigned int len = (unsigned int)wSeed.length(); // Check if the input string contains a numerical value bool isNumber = true; for (unsigned int i = 0; i < len; ++i) if (wSeed.at(i) < L'0' || wSeed.at(i) > L'9') if (!(i == 0 && wSeed.at(i) == L'-')) { isNumber = false; break; } // If the input string is a numerical value, convert it to a number if (isNumber) value = _fromString<__int64>(wSeed); // If the value is not 0 use it, otherwise use the algorithm from the // java String.hashCode() function to hash it if (value != 0) seedValue = value; else { int hashValue = 0; for (unsigned int i = 0; i < len; ++i) hashValue = 31 * hashValue + wSeed.at(i); seedValue = hashValue; } } else { seedValue = BiomeSource::findSeed( isFlat ? LevelType::lvl_flat : LevelType::lvl_normal); // 4J - was (new // Random())->nextLong() - now // trying to actually find a seed // to suit our requirements } g_NetworkManager.HostGame(dwLocalUsersMask, isClientSide, isPrivate, MINECRAFT_NET_MAX_PLAYERS, 0); NetworkGameInitData* param = new NetworkGameInitData(); param->seed = seedValue; param->saveData = NULL; param->texturePackId = pClass->m_MoreOptionsParams.dwTexturePack; Minecraft* pMinecraft = Minecraft::GetInstance(); pMinecraft->skins->selectTexturePackById( pClass->m_MoreOptionsParams.dwTexturePack); // pMinecraft->skins->updateUI(); app.SetGameHostOption(eGameHostOption_Difficulty, Minecraft::GetInstance()->options->difficulty); app.SetGameHostOption(eGameHostOption_FriendsOfFriends, pClass->m_MoreOptionsParams.bAllowFriendsOfFriends); app.SetGameHostOption( eGameHostOption_Gamertags, app.GetGameSettings(pClass->m_iPad, eGameSetting_GamertagsVisible) ? 1 : 0); app.SetGameHostOption( eGameHostOption_BedrockFog, app.GetGameSettings(pClass->m_iPad, eGameSetting_BedrockFog) ? 1 : 0); // CXuiList listObject; // listObject.Attach( pClass->m_GameMode.GetListObject() ); app.SetGameHostOption(eGameHostOption_GameType, pClass->m_bGameModeSurvival ? GameType::SURVIVAL->getId() : GameType::CREATIVE->getId()); app.SetGameHostOption(eGameHostOption_LevelType, pClass->m_MoreOptionsParams.bFlatWorld); app.SetGameHostOption(eGameHostOption_Structures, pClass->m_MoreOptionsParams.bStructures); app.SetGameHostOption(eGameHostOption_BonusChest, pClass->m_MoreOptionsParams.bBonusChest); app.SetGameHostOption(eGameHostOption_PvP, pClass->m_MoreOptionsParams.bPVP); app.SetGameHostOption(eGameHostOption_TrustPlayers, pClass->m_MoreOptionsParams.bTrust); app.SetGameHostOption(eGameHostOption_FireSpreads, pClass->m_MoreOptionsParams.bFireSpreads); app.SetGameHostOption(eGameHostOption_TNT, pClass->m_MoreOptionsParams.bTNT); app.SetGameHostOption(eGameHostOption_HostCanFly, pClass->m_MoreOptionsParams.bHostPrivileges); app.SetGameHostOption(eGameHostOption_HostCanChangeHunger, pClass->m_MoreOptionsParams.bHostPrivileges); app.SetGameHostOption(eGameHostOption_HostCanBeInvisible, pClass->m_MoreOptionsParams.bHostPrivileges); param->settings = app.GetGameHostOption(eGameHostOption_All); LoadingInputParams* loadingParams = new LoadingInputParams(); loadingParams->func = &CGameNetworkManager::RunNetworkGameThreadProc; loadingParams->lpParam = param; // Reset the autosave time app.SetAutosaveTimerTime(); 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); } HRESULT CScene_MultiGameCreate::OnTransitionStart( XUIMessageTransition* pTransition, BOOL& bHandled) { if (pTransition->dwTransAction == XUI_TRANSITION_ACTION_DESTROY) return S_OK; if (pTransition->dwTransType == XUI_TRANSITION_TO || pTransition->dwTransType == XUI_TRANSITION_BACKTO) { m_SliderDifficulty.SetValueDisplay(FALSE); } return S_OK; } HRESULT CScene_MultiGameCreate::OnTransitionEnd( 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) { } else if (pTransition->dwTransType == XUI_TRANSITION_TO || pTransition->dwTransType == XUI_TRANSITION_BACKTO) { if (m_bSetup && m_texturePackDescDisplayed) { XUITimeline* timeline; XUINamedFrame *startFrame, *endFrame; GetTimeline(&timeline); startFrame = timeline->FindNamedFrame(L"SlideOutEnd"); endFrame = timeline->FindNamedFrame(L"SlideOutEnd"); timeline->Play(startFrame->m_dwFrame, startFrame->m_dwFrame, endFrame->m_dwFrame, FALSE, FALSE); m_texturePackDescDisplayed = true; } // 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_pTexturePacksList->RemoveAllData(); } } } return S_OK; } HRESULT CScene_MultiGameCreate::OnNotifySelChanged( HXUIOBJ hObjSource, XUINotifySelChanged* pNotifySelChangedData, BOOL& bHandled) { if (hObjSource == m_pTexturePacksList->m_hObj) { UpdateTexturePackDescription(pNotifySelChangedData->iItem); // 4J-JEV: Removed expand description check, taken care of elsewhere. } return S_OK; } HRESULT CScene_MultiGameCreate::OnNotifyKillFocus( HXUIOBJ hObjSource, XUINotifyFocus* pNotifyFocusData, BOOL& bHandled) { HXUIOBJ hSourceParent, hDestParent; XuiElementGetParent(hObjSource, &hSourceParent); XuiElementGetParent(pNotifyFocusData->hObjOther, &hDestParent); if (hSourceParent != hDestParent && pNotifyFocusData->hObjOther != m_pTexturePacksList->m_hObj && hSourceParent == m_pTexturePacksList->m_hObj) { m_pTexturePacksList->SetCurSel(m_currentTexturePackIndex); m_pTexturePacksList->SetTopItem( m_currentTexturePackIndex); // scroll the item into view if it's // not visible } else if (!m_texturePackDescDisplayed && pNotifyFocusData->hObjOther == m_pTexturePacksList->m_hObj) { // 4J-JEV: Shouldn't we always do this? // int texturePacksCount = // Minecraft::GetInstance()->skins->getTexturePackCount(); // if(texturePacksCount == 1) //{ XUITimeline* timeline; XUINamedFrame *startFrame, *endFrame; GetTimeline(&timeline); startFrame = timeline->FindNamedFrame(L"SlideOut"); endFrame = timeline->FindNamedFrame(L"SlideOutEnd"); timeline->Play(startFrame->m_dwFrame, startFrame->m_dwFrame, endFrame->m_dwFrame, FALSE, FALSE); m_texturePackDescDisplayed = true; //} } return S_OK; } void CScene_MultiGameCreate::UpdateTexturePackDescription(int index) { int iTexPackId = m_pTexturePacksList->GetData(index).iData; TexturePack* tp = Minecraft::GetInstance()->skins->getTexturePackById(iTexPackId); if (tp == NULL) { // this is probably a texture pack icon added from TMS unsigned int dwBytes = 0; unsigned int dwFileBytes = 0; std::uint8_t* pbData = NULL; std::uint8_t* pbFileData = NULL; CXuiCtrl4JList::LIST_ITEM_INFO ListItem; // get the current index of the list, and then get the data ListItem = m_pTexturePacksList->GetData(index); app.GetTPD(ListItem.iData, &pbData, &dwBytes); app.GetFileFromTPD(eTPDFileType_Loc, pbData, dwBytes, &pbFileData, &dwFileBytes); if (dwFileBytes > 0 && pbFileData) { StringTable* pStringTable = new StringTable(pbFileData, dwFileBytes); m_texturePackTitle.SetText( pStringTable->getString(L"IDS_DISPLAY_NAME")); m_texturePackDescription.SetText( pStringTable->getString(L"IDS_TP_DESCRIPTION")); } app.GetFileFromTPD(eTPDFileType_Icon, pbData, dwBytes, &pbFileData, &dwFileBytes); if (dwFileBytes > 0 && pbFileData) { XuiCreateTextureBrushFromMemory(pbFileData, dwFileBytes, &m_hTexturePackIconBrush); m_texturePackIcon->UseBrush(m_hTexturePackIconBrush); } app.GetFileFromTPD(eTPDFileType_Comparison, pbData, dwBytes, &pbFileData, &dwFileBytes); if (dwFileBytes > 0 && pbFileData) { XuiCreateTextureBrushFromMemory(pbFileData, dwFileBytes, &m_hTexturePackComparisonBrush); m_texturePackComparison->UseBrush(m_hTexturePackComparisonBrush); } else { m_texturePackComparison->UseBrush(NULL); } } else { m_texturePackTitle.SetText(tp->getName().c_str()); m_texturePackDescription.SetText(tp->getDesc1().c_str()); std::uint32_t imageBytes = 0; std::uint8_t* imageData = tp->getPackIcon(imageBytes); if (imageBytes > 0 && imageData) { XuiCreateTextureBrushFromMemory(imageData, imageBytes, &m_hTexturePackIconBrush); m_texturePackIcon->UseBrush(m_hTexturePackIconBrush); } imageData = tp->getPackComparison(imageBytes); if (imageBytes > 0 && imageData) { XuiCreateTextureBrushFromMemory(imageData, imageBytes, &m_hTexturePackComparisonBrush); m_texturePackComparison->UseBrush(m_hTexturePackComparisonBrush); } else { m_texturePackComparison->UseBrush(NULL); } } } void CScene_MultiGameCreate::UpdateCurrentTexturePack() { m_currentTexturePackIndex = m_pTexturePacksList->GetCurSel(); int iTexPackId = m_pTexturePacksList->GetData(m_currentTexturePackIndex).iData; TexturePack* tp = Minecraft::GetInstance()->skins->getTexturePackById(iTexPackId); // if the texture pack is null, you don't have it yet if (tp == NULL) { // Upsell CXuiCtrl4JList::LIST_ITEM_INFO ListItem; // get the current index of the list, and then get the data ListItem = m_pTexturePacksList->GetData(m_currentTexturePackIndex); // upsell the texture pack // tell sentient about the upsell of the full version of the skin pack ULONGLONG ullOfferID_Full; app.GetDLCFullOfferIDForPackID(ListItem.iData, &ullOfferID_Full); TelemetryManager->RecordUpsellPresented(ProfileManager.GetPrimaryPad(), eSet_UpsellID_Texture_DLC, ullOfferID_Full & 0xFFFFFFFF); unsigned int 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_MultiGameCreate::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_MultiGameCreate::TexturePackDialogReturned, this, app.GetStringTable()); } // do set the texture pack id, and on the user pressing create world, // check they have it m_MoreOptionsParams.dwTexturePack = ListItem.iData; return; } else { m_MoreOptionsParams.dwTexturePack = tp->getId(); } } int CScene_MultiGameCreate::TexturePackDialogReturned( void* pParam, int iPad, C4JStorage::EMessageResult result) { CScene_MultiGameCreate* pClass = (CScene_MultiGameCreate*)pParam; pClass->m_currentTexturePackIndex = pClass->m_pTexturePacksList->GetCurSel(); // 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]; CXuiCtrl4JList::LIST_ITEM_INFO ListItem; // get the current index of the list, and then get the data ListItem = pClass->m_pTexturePacksList->GetData( pClass->m_currentTexturePackIndex); app.GetDLCFullOfferIDForPackID(ListItem.iData, &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_MultiGameCreate::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 texture pack list m_pTexturePacksList->RemoveAllData(); ClearTexturePackDescription(); } // this will send a CustomMessage_DLCMountingComplete when done return S_OK; } HRESULT CScene_MultiGameCreate::OnCustomMessage_DLCMountingComplete() { // refill the texture pack list m_pTexturePacksList->SetSelectionChangedHandle(m_hObj); Minecraft* pMinecraft = Minecraft::GetInstance(); int texturePacksCount = pMinecraft->skins->getTexturePackCount(); CXuiCtrl4JList::LIST_ITEM_INFO ListInfo; HRESULT hr; for (unsigned int i = 0; i < texturePacksCount; ++i) { TexturePack* tp = pMinecraft->skins->getTexturePackByIndex(i); ZeroMemory(&ListInfo, sizeof(CXuiCtrl4JList::LIST_ITEM_INFO)); std::uint32_t imageBytes = 0; std::uint8_t* imageData = tp->getPackIcon(imageBytes); if (imageBytes > 0 && imageData) { ListInfo.fEnabled = TRUE; hr = XuiCreateTextureBrushFromMemory(imageData, imageBytes, &ListInfo.hXuiBrush); DLCTexturePack* pDLCTexPack = (DLCTexturePack*)tp; if (pDLCTexPack) { int id = pDLCTexPack->getDLCParentPackId(); if (id == 0) { // default texture pack - should come first ListInfo.iSortIndex = 0x0FFFFFFF; } else { ListInfo.iSortIndex = id; ListInfo.iData = id; } } m_pTexturePacksList->AddData(ListInfo, 0, CXuiCtrl4JList::eSortList_Index); } } m_iTexturePacksNotInstalled = 0; // 4J-PB - there may be texture packs we don't have, so use the info from // TMS for this REMOVE UNTIL WORKING DLC_INFO* pDLCInfo = NULL; // first pass - look to see if there are any that are not in the list bool bTexturePackAlreadyListed; bool bNeedToGetTPD = false; 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); if (m_iConfigA != NULL) { delete m_iConfigA; } 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; } } } m_currentTexturePackIndex = pMinecraft->skins->getTexturePackIndex(0); UpdateTexturePackDescription(m_currentTexturePackIndex); m_bSetup = true; m_bIgnoreInput = false; app.m_dlcManager.checkForCorruptDLCAndAlert(); return S_OK; } void CScene_MultiGameCreate::ClearTexturePackDescription() { m_texturePackTitle.SetText(L" "); m_texturePackDescription.SetText(L" "); m_texturePackComparison->UseBrush(NULL); m_texturePackIcon->UseBrush(NULL); }