#include "app/common/Game.h" #include "platform/PlatformTypes.h" #include "platform/InputActions.h" #include "platform/sdl2/Profile.h" #include "platform/sdl2/Render.h" #include "platform/sdl2/Storage.h" #include "app/common/App_Defines.h" #include "app/common/App_enums.h" #include "app/common/App_structs.h" #include "app/common/src/Console_Debug_enum.h" #include "app/common/src/DLC/DLCManager.h" #include "app/common/src/DLC/DLCSkinFile.h" #include "app/common/src/GameRules/GameRuleManager.h" #include "app/common/src/Network/GameNetworkManager.h" #include "app/common/src/Network/NetworkPlayerInterface.h" #include "app/common/src/Tutorial/Tutorial.h" #include "app/common/src/UI/All Platforms/UIEnums.h" #include "app/common/src/UI/All Platforms/UIStructs.h" #include "app/common/src/UI/Scenes/UIScene_FullscreenProgress.h" #include "app/linux/LinuxGame.h" #include "app/linux/Linux_UIController.h" #include "app/linux/Stubs/winapi_stubs.h" #include "app/include/NetTypes.h" #include "SkinBox.h" #include "XboxStubs.h" #include "platform/PlatformServices.h" #include "java/Class.h" #include "java/File.h" #include "java/Random.h" #include "minecraft/client/Minecraft.h" #include "minecraft/client/Options.h" #include "minecraft/client/ProgressRenderer.h" #include "minecraft/client/model/geom/Model.h" #include "minecraft/client/multiplayer/ClientConnection.h" #include "minecraft/client/multiplayer/MultiPlayerGameMode.h" #include "minecraft/client/multiplayer/MultiPlayerLevel.h" #include "minecraft/client/multiplayer/MultiPlayerLocalPlayer.h" #include "minecraft/client/renderer/GameRenderer.h" #include "minecraft/client/renderer/Textures.h" #include "minecraft/client/renderer/entity/EntityRenderer.h" #include "minecraft/client/skins/TexturePack.h" #include "minecraft/network/packet/DisconnectPacket.h" #include "minecraft/server/MinecraftServer.h" #include "minecraft/stats/StatsCounter.h" #include "minecraft/world/Container.h" #include "minecraft/world/entity/item/MinecartHopper.h" #include "minecraft/world/entity/player/Player.h" #include "minecraft/world/item/crafting/Recipy.h" #include "minecraft/world/level/tile/Tile.h" #include "minecraft/world/level/tile/entity/HopperTileEntity.h" #include "strings.h" #if defined(_WINDOWS64) #include "app/windows/XML/ATGXmlParser.h" #include "app/windows/XML/xmlFilesCallback.h" #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef __android__ #include #define TAG "4JCRAFT" #define AndroidPrintf(...) do { __android_log_print(ANDROID_LOG_DEBUG, TAG, __VA_ARGS__); printf( __VA_ARGS__); } while( 0 ); #endif #include "platform/sdl2/Input.h" #include "app/common/src/Audio/SoundEngine.h" #include "app/common/src/Colours/ColourTable.h" #include "app/common/src/DLC/DLCPack.h" #include "app/common/src/Localisation/StringTable.h" #include "app/common/src/UI/All Platforms/ArchiveFile.h" #include "app/common/src/UI/Scenes/In-Game Menu Screens/UIScene_PauseMenu.h" #include "Minecraft_Macros.h" #include "util/Timer.h" #include "util/StringHelpers.h" #include "minecraft/world/level/storage/ConsoleSaveFileIO/compression.h" #include "minecraft/client/User.h" #include "minecraft/client/gui/Gui.h" #include "minecraft/client/renderer/entity/EntityRenderDispatcher.h" #include "minecraft/client/skins/DLCTexturePack.h" #include "minecraft/client/skins/TexturePackRepository.h" #include "minecraft/server/PlayerList.h" #include "minecraft/server/level/ServerPlayer.h" class BeaconTileEntity; class BrewingStandTileEntity; class DispenserTileEntity; class EntityHorse; class FurnaceTileEntity; class INVITE_INFO; class Inventory; class Level; class LevelChunk; class LevelGenerationOptions; class LocalPlayer; class Merchant; class ModelPart; class SignTileEntity; // Game app; unsigned int Game::m_uiLastSignInData = 0; const float Game::fSafeZoneX = 64.0f; // 5% of 1280 const float Game::fSafeZoneY = 36.0f; // 5% of 720 int Game::s_iHTMLFontSizesA[eHTMLSize_COUNT] = { // 20,15,20,24 20, 13, 20, 26}; Game::Game() { if (GAME_SETTINGS_PROFILE_DATA_BYTES != sizeof(GAME_SETTINGS)) { // 4J Stu - See comment for GAME_SETTINGS_PROFILE_DATA_BYTES in // Xbox_App.h DebugPrintf( "WARNING: The size of the profile GAME_SETTINGS struct has " "changed, so all stat data is likely incorrect. Is: %d, Should be: " "%d\n", sizeof(GAME_SETTINGS), GAME_SETTINGS_PROFILE_DATA_BYTES); #if !defined(_CONTENT_PACKAGE) __debugbreak(); #endif } for (int i = 0; i < XUSER_MAX_COUNT; i++) { m_eTMSAction[i] = eTMSAction_Idle; m_eXuiAction[i] = eAppAction_Idle; m_eXuiActionParam[i] = nullptr; // m_dwAdditionalModelParts[i] = 0; if (FAILED(XUserGetSigninInfo(i, XUSER_GET_SIGNIN_INFO_OFFLINE_XUID_ONLY, &m_currentSigninInfo[i]))) { m_currentSigninInfo[i].xuid = INVALID_XUID; m_currentSigninInfo[i].dwGuestNumber = 0; } DebugPrintf("Player at index %d has guest number %d\n", i, m_currentSigninInfo[i].dwGuestNumber); m_bRead_BannedListA[i] = false; SetBanListCheck(i, false); m_uiOpacityCountDown[i] = 0; } m_eGlobalXuiAction = eAppAction_Idle; m_eGlobalXuiServerAction = eXuiServerAction_Idle; m_bResourcesLoaded = false; m_bGameStarted = false; m_bIsAppPaused = false; // m_bSplitScreenEnabled = false; m_bIntroRunning = false; m_eGameMode = eMode_Singleplayer; m_bLoadSavesFromFolderEnabled = false; m_bWriteSavesToFolderEnabled = false; // m_bInterfaceRenderingOff = false; // m_bHandRenderingOff = false; m_bTutorialMode = false; m_disconnectReason = DisconnectPacket::eDisconnect_None; m_bLiveLinkRequired = false; m_bChangingSessionType = false; m_bReallyChangingSessionType = false; #if defined(_DEBUG_MENUS_ENABLED) #if defined(_CONTENT_PACKAGE) m_bDebugOptions = false; // make them off by default in a content package build #else m_bDebugOptions = true; #endif #else m_bDebugOptions = false; #endif // memset(m_PreviewBuffer, 0, sizeof(XSOCIAL_PREVIEWIMAGE)*XUSER_MAX_COUNT); m_xuidNotch = INVALID_XUID; memset(&m_InviteData, 0, sizeof(JoinFromInviteData)); // m_bRead_TMS_XUIDS_XML=false; // m_bRead_TMS_DLCINFO_XML=false; m_pDLCFileBuffer = nullptr; m_dwDLCFileSize = 0; m_pBannedListFileBuffer = nullptr; m_dwBannedListFileSize = 0; m_bDefaultCapeInstallAttempted = false; m_bDLCInstallProcessCompleted = false; m_bDLCInstallPending = false; m_iTotalDLC = 0; m_iTotalDLCInstalled = 0; mfTrialPausedTime = 0.0f; m_uiAutosaveTimer = {}; memset(m_pszUniqueMapName, 0, 14); m_bNewDLCAvailable = false; m_bSeenNewDLCTip = false; m_uiGameHostSettings = 0; #if defined(_LARGE_WORLDS) m_GameNewWorldSize = 0; m_bGameNewWorldSizeUseMoat = false; m_GameNewHellScale = 0; #endif memset(m_playerColours, 0, MINECRAFT_NET_MAX_PLAYERS); m_iDLCOfferC = 0; m_bAllDLCContentRetrieved = true; m_bAllTMSContentRetrieved = true; m_bTickTMSDLCFiles = true; m_saveNotificationDepth = 0; m_dwRequiredTexturePackID = 0; m_bResetNether = false; #if defined(_CONTENT_PACAKGE) m_bUseDPadForDebug = false; #else m_bUseDPadForDebug = true; #endif for (int i = 0; i < XUSER_MAX_COUNT; i++) { m_vBannedListA[i] = new std::vector; } LocaleAndLanguageInit(); } void Game::DebugPrintf(const char* szFormat, ...) { #if !defined(_FINAL_BUILD) char buf[1024]; va_list ap; va_start(ap, szFormat); vsnprintf(buf, sizeof(buf), szFormat, ap); va_end(ap); #if defined(__android__) AndroidPrintf("%s", buf); #else OutputDebugStringA(buf); #endif #endif } void Game::DebugPrintf(int user, const char* szFormat, ...) { #if !defined(_FINAL_BUILD) if (user == USER_NONE) return; char buf[1024]; va_list ap; va_start(ap, szFormat); vsnprintf(buf, sizeof(buf), szFormat, ap); va_end(ap); #if defined(__android__) AndroidPrintf("%s", buf); #else OutputDebugStringA(buf); #endif if (user == USER_UI) { ui.logDebugString(buf); } #endif } const wchar_t* Game::GetString(int iID) { // return L"Değişiklikler ve Yenilikler"; // return L"ÕÕÕÕÖÖÖÖ"; return app.m_stringTable->getString(iID); } void Game::SetAction(int iPad, eXuiAction action, void* param) { if ((m_eXuiAction[iPad] == eAppAction_ReloadTexturePack) && (action == eAppAction_EthernetDisconnected)) { app.DebugPrintf( "Invalid change of App action for pad %d from %d to %d, ignoring\n", iPad, m_eXuiAction[iPad], action); } else if ((m_eXuiAction[iPad] == eAppAction_ReloadTexturePack) && (action == eAppAction_ExitWorld)) { app.DebugPrintf( "Invalid change of App action for pad %d from %d to %d, ignoring\n", iPad, m_eXuiAction[iPad], action); } else if (m_eXuiAction[iPad] == eAppAction_ExitWorldCapturedThumbnail && action != eAppAction_Idle) { app.DebugPrintf( "Invalid change of App action for pad %d from %d to %d, ignoring\n", iPad, m_eXuiAction[iPad], action); } else { app.DebugPrintf("Changing App action for pad %d from %d to %d\n", iPad, m_eXuiAction[iPad], action); m_eXuiAction[iPad] = action; m_eXuiActionParam[iPad] = param; } } bool Game::IsAppPaused() { return m_bIsAppPaused; } void Game::SetAppPaused(bool val) { m_bIsAppPaused = val; } void Game::HandleButtonPresses() { for (int i = 0; i < 4; i++) { HandleButtonPresses(i); } } void Game::HandleButtonPresses(int iPad) { // // test an update of the profile data // void *pData=ProfileManager.GetGameDefinedProfileData(iPad); // // unsigned char *pchData= (unsigned char *)pData; // int iCount=0; // for(int i=0;i player, bool bNavigateBack) { bool success = true; InventoryScreenInput* initData = new InventoryScreenInput(); initData->player = player; initData->bNavigateBack = bNavigateBack; initData->iPad = iPad; if (app.GetLocalPlayerCount() > 1) { initData->bSplitscreen = true; success = ui.NavigateToScene(iPad, eUIScene_InventoryMenu, initData); } else { initData->bSplitscreen = false; success = ui.NavigateToScene(iPad, eUIScene_InventoryMenu, initData); } return success; } bool Game::LoadCreativeMenu(int iPad, std::shared_ptr player, bool bNavigateBack) { bool success = true; InventoryScreenInput* initData = new InventoryScreenInput(); initData->player = player; initData->bNavigateBack = bNavigateBack; initData->iPad = iPad; if (app.GetLocalPlayerCount() > 1) { initData->bSplitscreen = true; success = ui.NavigateToScene(iPad, eUIScene_CreativeMenu, initData); } else { initData->bSplitscreen = false; success = ui.NavigateToScene(iPad, eUIScene_CreativeMenu, initData); } return success; } bool Game::LoadCrafting2x2Menu(int iPad, std::shared_ptr player) { bool success = true; CraftingPanelScreenInput* initData = new CraftingPanelScreenInput(); initData->player = player; initData->iContainerType = RECIPE_TYPE_2x2; initData->iPad = iPad; initData->x = 0; initData->y = 0; initData->z = 0; if (app.GetLocalPlayerCount() > 1) { initData->bSplitscreen = true; success = ui.NavigateToScene(iPad, eUIScene_Crafting2x2Menu, initData); } else { initData->bSplitscreen = false; success = ui.NavigateToScene(iPad, eUIScene_Crafting2x2Menu, initData); } return success; } bool Game::LoadCrafting3x3Menu(int iPad, std::shared_ptr player, int x, int y, int z) { bool success = true; CraftingPanelScreenInput* initData = new CraftingPanelScreenInput(); initData->player = player; initData->iContainerType = RECIPE_TYPE_3x3; initData->iPad = iPad; initData->x = x; initData->y = y; initData->z = z; if (app.GetLocalPlayerCount() > 1) { initData->bSplitscreen = true; success = ui.NavigateToScene(iPad, eUIScene_Crafting3x3Menu, initData); } else { initData->bSplitscreen = false; success = ui.NavigateToScene(iPad, eUIScene_Crafting3x3Menu, initData); } return success; } bool Game::LoadFireworksMenu(int iPad, std::shared_ptr player, int x, int y, int z) { bool success = true; FireworksScreenInput* initData = new FireworksScreenInput(); initData->player = player; initData->iPad = iPad; initData->x = x; initData->y = y; initData->z = z; if (app.GetLocalPlayerCount() > 1) { initData->bSplitscreen = true; success = ui.NavigateToScene(iPad, eUIScene_FireworksMenu, initData); } else { initData->bSplitscreen = false; success = ui.NavigateToScene(iPad, eUIScene_FireworksMenu, initData); } return success; } bool Game::LoadEnchantingMenu(int iPad, std::shared_ptr inventory, int x, int y, int z, Level* level, const std::wstring& name) { bool success = true; EnchantingScreenInput* initData = new EnchantingScreenInput(); initData->inventory = inventory; initData->level = level; initData->x = x; initData->y = y; initData->z = z; initData->iPad = iPad; initData->name = name; if (app.GetLocalPlayerCount() > 1) { initData->bSplitscreen = true; success = ui.NavigateToScene(iPad, eUIScene_EnchantingMenu, initData); } else { initData->bSplitscreen = false; success = ui.NavigateToScene(iPad, eUIScene_EnchantingMenu, initData); } return success; } bool Game::LoadFurnaceMenu( int iPad, std::shared_ptr inventory, std::shared_ptr furnace) { bool success = true; FurnaceScreenInput* initData = new FurnaceScreenInput(); initData->furnace = furnace; initData->inventory = inventory; initData->iPad = iPad; // Load the scene. if (app.GetLocalPlayerCount() > 1) { initData->bSplitscreen = true; success = ui.NavigateToScene(iPad, eUIScene_FurnaceMenu, initData); } else { initData->bSplitscreen = false; success = ui.NavigateToScene(iPad, eUIScene_FurnaceMenu, initData); } return success; } bool Game::LoadBrewingStandMenu( int iPad, std::shared_ptr inventory, std::shared_ptr brewingStand) { bool success = true; BrewingScreenInput* initData = new BrewingScreenInput(); initData->brewingStand = brewingStand; initData->inventory = inventory; initData->iPad = iPad; // Load the scene. if (app.GetLocalPlayerCount() > 1) { initData->bSplitscreen = true; success = ui.NavigateToScene(iPad, eUIScene_BrewingStandMenu, initData); } else { initData->bSplitscreen = false; success = ui.NavigateToScene(iPad, eUIScene_BrewingStandMenu, initData); } return success; } bool Game::LoadContainerMenu(int iPad, std::shared_ptr inventory, std::shared_ptr container) { bool success = true; ContainerScreenInput* initData = new ContainerScreenInput(); initData->inventory = inventory; initData->container = container; initData->iPad = iPad; // Load the scene. if (app.GetLocalPlayerCount() > 1) { initData->bSplitscreen = true; bool bLargeChest = (initData->container->getContainerSize() > 3 * 9) ? true : false; if (bLargeChest) { success = ui.NavigateToScene(iPad, eUIScene_LargeContainerMenu, initData); } else { success = ui.NavigateToScene(iPad, eUIScene_ContainerMenu, initData); } } else { initData->bSplitscreen = false; success = ui.NavigateToScene(iPad, eUIScene_ContainerMenu, initData); } return success; } bool Game::LoadTrapMenu(int iPad, std::shared_ptr inventory, std::shared_ptr trap) { bool success = true; TrapScreenInput* initData = new TrapScreenInput(); initData->inventory = inventory; initData->trap = trap; initData->iPad = iPad; // Load the scene. if (app.GetLocalPlayerCount() > 1) { initData->bSplitscreen = true; success = ui.NavigateToScene(iPad, eUIScene_DispenserMenu, initData); } else { initData->bSplitscreen = false; success = ui.NavigateToScene(iPad, eUIScene_DispenserMenu, initData); } return success; } bool Game::LoadSignEntryMenu(int iPad, std::shared_ptr sign) { bool success = true; SignEntryScreenInput* initData = new SignEntryScreenInput(); initData->sign = sign; initData->iPad = iPad; success = ui.NavigateToScene(iPad, eUIScene_SignEntryMenu, initData); delete initData; return success; } bool Game::LoadRepairingMenu(int iPad, std::shared_ptr inventory, Level* level, int x, int y, int z) { bool success = true; AnvilScreenInput* initData = new AnvilScreenInput(); initData->inventory = inventory; initData->level = level; initData->x = x; initData->y = y; initData->z = z; initData->iPad = iPad; if (app.GetLocalPlayerCount() > 1) initData->bSplitscreen = true; else initData->bSplitscreen = false; success = ui.NavigateToScene(iPad, eUIScene_AnvilMenu, initData); return success; } bool Game::LoadTradingMenu(int iPad, std::shared_ptr inventory, std::shared_ptr trader, Level* level, const std::wstring& name) { bool success = true; TradingScreenInput* initData = new TradingScreenInput(); initData->inventory = inventory; initData->trader = trader; initData->level = level; initData->iPad = iPad; if (app.GetLocalPlayerCount() > 1) initData->bSplitscreen = true; else initData->bSplitscreen = false; success = ui.NavigateToScene(iPad, eUIScene_TradingMenu, initData); return success; } bool Game::LoadHopperMenu(int iPad, std::shared_ptr inventory, std::shared_ptr hopper) { bool success = true; HopperScreenInput* initData = new HopperScreenInput(); initData->inventory = inventory; initData->hopper = hopper; initData->iPad = iPad; if (app.GetLocalPlayerCount() > 1) initData->bSplitscreen = true; else initData->bSplitscreen = false; success = ui.NavigateToScene(iPad, eUIScene_HopperMenu, initData); return success; } bool Game::LoadHopperMenu(int iPad, std::shared_ptr inventory, std::shared_ptr hopper) { bool success = true; HopperScreenInput* initData = new HopperScreenInput(); initData->inventory = inventory; initData->hopper = std::dynamic_pointer_cast(hopper); initData->iPad = iPad; if (app.GetLocalPlayerCount() > 1) initData->bSplitscreen = true; else initData->bSplitscreen = false; success = ui.NavigateToScene(iPad, eUIScene_HopperMenu, initData); return success; } bool Game::LoadHorseMenu(int iPad, std::shared_ptr inventory, std::shared_ptr container, std::shared_ptr horse) { bool success = true; HorseScreenInput* initData = new HorseScreenInput(); initData->inventory = inventory; initData->container = container; initData->horse = horse; initData->iPad = iPad; if (app.GetLocalPlayerCount() > 1) initData->bSplitscreen = true; else initData->bSplitscreen = false; success = ui.NavigateToScene(iPad, eUIScene_HorseMenu, initData); return success; } bool Game::LoadBeaconMenu(int iPad, std::shared_ptr inventory, std::shared_ptr beacon) { bool success = true; BeaconScreenInput* initData = new BeaconScreenInput(); initData->inventory = inventory; initData->beacon = beacon; initData->iPad = iPad; if (app.GetLocalPlayerCount() > 1) initData->bSplitscreen = true; else initData->bSplitscreen = false; success = ui.NavigateToScene(iPad, eUIScene_BeaconMenu, initData); return success; } ////////////////////////////////////////////// // GAME SETTINGS ////////////////////////////////////////////// void Game::InitGameSettings() { for (int i = 0; i < XUSER_MAX_COUNT; i++) { GameSettingsA[i] = (GAME_SETTINGS*)ProfileManager.GetGameDefinedProfileData(i); // clear the flag to say the settings have changed GameSettingsA[i]->bSettingsChanged = false; // SetDefaultGameSettings(i); - done on a callback from the profile // manager // 4J-PB - adding in for Windows & PS3 to set the defaults for the // joypad #if defined(_WINDOWS64) C_4JProfile::PROFILESETTINGS* pProfileSettings = ProfileManager.GetDashboardProfileSettings(i); // clear this for now - it will come from reading the system values memset(pProfileSettings, 0, sizeof(C_4JProfile::PROFILESETTINGS)); SetDefaultOptions(pProfileSettings, i); #else // 4jcrqaft: Linux (and any other platform): profile data is // zero-initialised, so explicitly apply defaults C_4JProfile::PROFILESETTINGS* pProfileSettings = ProfileManager.GetDashboardProfileSettings(i); memset(pProfileSettings, 0, sizeof(C_4JProfile::PROFILESETTINGS)); SetDefaultOptions(pProfileSettings, i); #endif } } int Game::SetDefaultOptions(C_4JProfile::PROFILESETTINGS* pSettings, const int iPad) { SetGameSettings(iPad, eGameSetting_MusicVolume, DEFAULT_VOLUME_LEVEL); SetGameSettings(iPad, eGameSetting_SoundFXVolume, DEFAULT_VOLUME_LEVEL); SetGameSettings(iPad, eGameSetting_Gamma, 50); // 4J-PB - Don't reset the difficult level if we're in-game if (Minecraft::GetInstance()->level == nullptr) { app.DebugPrintf("SetDefaultOptions - Difficulty = 1\n"); SetGameSettings(iPad, eGameSetting_Difficulty, 1); } SetGameSettings(iPad, eGameSetting_Sensitivity_InGame, 100); SetGameSettings(iPad, eGameSetting_ViewBob, 1); SetGameSettings(iPad, eGameSetting_ControlScheme, 0); SetGameSettings(iPad, eGameSetting_ControlInvertLook, (pSettings->iYAxisInversion != 0) ? 1 : 0); SetGameSettings(iPad, eGameSetting_ControlSouthPaw, pSettings->bSwapSticks ? 1 : 0); SetGameSettings(iPad, eGameSetting_SplitScreenVertical, 0); SetGameSettings(iPad, eGameSetting_GamertagsVisible, 1); // Interim TU 1.6.6 SetGameSettings(iPad, eGameSetting_Sensitivity_InMenu, 100); SetGameSettings(iPad, eGameSetting_DisplaySplitscreenGamertags, 1); SetGameSettings(iPad, eGameSetting_Hints, 1); SetGameSettings(iPad, eGameSetting_Autosave, 2); SetGameSettings(iPad, eGameSetting_Tooltips, 1); SetGameSettings(iPad, eGameSetting_InterfaceOpacity, 80); // TU 5 SetGameSettings(iPad, eGameSetting_Clouds, 1); SetGameSettings(iPad, eGameSetting_Online, 1); SetGameSettings(iPad, eGameSetting_InviteOnly, 0); SetGameSettings(iPad, eGameSetting_FriendsOfFriends, 1); // default the update changes message to zero // 4J-PB - We'll only display the message if the profile is pre-TU5 // SetGameSettings(iPad,eGameSetting_DisplayUpdateMessage,0); // TU 6 SetGameSettings(iPad, eGameSetting_BedrockFog, 0); SetGameSettings(iPad, eGameSetting_DisplayHUD, 1); SetGameSettings(iPad, eGameSetting_DisplayHand, 1); // TU 7 SetGameSettings(iPad, eGameSetting_CustomSkinAnim, 1); // TU 9 SetGameSettings(iPad, eGameSetting_DeathMessages, 1); SetGameSettings(iPad, eGameSetting_UISize, 1); SetGameSettings(iPad, eGameSetting_UISizeSplitscreen, 2); SetGameSettings(iPad, eGameSetting_AnimatedCharacter, 1); // TU 12 GameSettingsA[iPad]->ucCurrentFavoriteSkinPos = 0; for (int i = 0; i < MAX_FAVORITE_SKINS; i++) { GameSettingsA[iPad]->uiFavoriteSkinA[i] = 0xFFFFFFFF; } // TU 13 GameSettingsA[iPad]->uiMashUpPackWorldsDisplay = 0xFFFFFFFF; // 1.6.4 app.SetGameHostOption(eGameHostOption_MobGriefing, 1); app.SetGameHostOption(eGameHostOption_KeepInventory, 0); app.SetGameHostOption(eGameHostOption_DoMobSpawning, 1); app.SetGameHostOption(eGameHostOption_DoMobLoot, 1); app.SetGameHostOption(eGameHostOption_DoTileDrops, 1); app.SetGameHostOption(eGameHostOption_NaturalRegeneration, 1); app.SetGameHostOption(eGameHostOption_DoDaylightCycle, 1); // 4J-PB - leave these in, or remove from everywhere they are referenced! // Although probably best to leave in unless we split the profile settings // into platform specific classes - having different meaning per platform // for the same bitmask could get confusing // #ifdef 0 // PS3DEC13 SetGameSettings(iPad, eGameSetting_PS3_EULA_Read, 0); // EULA not read // PS3 1.05 - added Greek // 4J-JEV: We cannot change these in-game, as they could affect localised // strings and font. XB1: Fix for #172947 - Content: Gameplay: While playing // in language different form system default one and resetting options to // their defaults in active gameplay causes in-game language to change and // HUD to disappear if (!app.GetGameStarted()) { GameSettingsA[iPad]->ucLanguage = MINECRAFT_LANGUAGE_DEFAULT; // use the system language GameSettingsA[iPad]->ucLocale = MINECRAFT_LANGUAGE_DEFAULT; // use the system locale } // #endif return 0; } int Game::DefaultOptionsCallback( void* pParam, C_4JProfile::PROFILESETTINGS* pSettings, const int iPad) { Game* pApp = (Game*)pParam; // flag the default options to be set pApp->DebugPrintf("Setting default options for player %d", iPad); pApp->SetAction(iPad, eAppAction_SetDefaultOptions, (void*)pSettings); // pApp->SetDefaultOptions(pSettings,iPad); // if the profile data has been changed, then force a profile write // It seems we're allowed to break the 5 minute rule if it's the result of a // user action // pApp->CheckGameSettingsChanged(); return 0; } int Game::OldProfileVersionCallback(void* pParam, unsigned char* pucData, const unsigned short usVersion, const int iPad) { // check what needs to be done with this version to update to the current // one switch (usVersion) { case PROFILE_VERSION_8: { GAME_SETTINGS* pGameSettings = (GAME_SETTINGS*)pucData; // reset the display new message counter pGameSettings->uiBitmaskValues |= GAMESETTING_DISPLAYUPDATEMSG; // eGameSetting_DisplayUpdateMessage // (counter) // Added a bitmask in TU13 to enable/disable display of the Mash-up // pack worlds in the saves list pGameSettings->uiMashUpPackWorldsDisplay = 0xFFFFFFFF; // PS3DEC13 pGameSettings->uiBitmaskValues &= ~GAMESETTING_PS3EULAREAD; // eGameSetting_PS3_EULA_Read - off // PS3 1.05 - added Greek pGameSettings->ucLanguage = MINECRAFT_LANGUAGE_DEFAULT; // use the system language } break; case PROFILE_VERSION_9: // PS3DEC13 { GAME_SETTINGS* pGameSettings = (GAME_SETTINGS*)pucData; pGameSettings->uiBitmaskValues |= GAMESETTING_DISPLAYUPDATEMSG; // eGameSetting_DisplayUpdateMessage // (counter) pGameSettings->uiBitmaskValues &= ~GAMESETTING_PS3EULAREAD; // eGameSetting_PS3_EULA_Read - // off // PS3 1.05 - added Greek pGameSettings->ucLanguage = MINECRAFT_LANGUAGE_DEFAULT; // use the system language } break; case PROFILE_VERSION_10: { GAME_SETTINGS* pGameSettings = (GAME_SETTINGS*)pucData; pGameSettings->uiBitmaskValues |= GAMESETTING_DISPLAYUPDATEMSG; // eGameSetting_DisplayUpdateMessage // (counter) pGameSettings->ucLanguage = MINECRAFT_LANGUAGE_DEFAULT; // use the system language } break; case PROFILE_VERSION_11: { GAME_SETTINGS* pGameSettings = (GAME_SETTINGS*)pucData; pGameSettings->uiBitmaskValues |= GAMESETTING_DISPLAYUPDATEMSG; // eGameSetting_DisplayUpdateMessage // (counter) } break; case PROFILE_VERSION_12: { GAME_SETTINGS* pGameSettings = (GAME_SETTINGS*)pucData; pGameSettings->uiBitmaskValues |= GAMESETTING_DISPLAYUPDATEMSG; // eGameSetting_DisplayUpdateMessage // (counter) } break; default: { // This might be from a version during testing of new profile // updates app.DebugPrintf( "Don't know what to do with this profile version!\n"); GAME_SETTINGS* pGameSettings = (GAME_SETTINGS*)pucData; pGameSettings->ucMenuSensitivity = 100; // eGameSetting_Sensitivity_InMenu pGameSettings->ucInterfaceOpacity = 80; // eGameSetting_Sensitivity_InMenu pGameSettings->usBitmaskValues |= 0x0200; // eGameSetting_DisplaySplitscreenGamertags - on pGameSettings->usBitmaskValues |= 0x0400; // eGameSetting_Hints - // on pGameSettings->usBitmaskValues |= 0x1000; // eGameSetting_Autosave - 2 pGameSettings->usBitmaskValues |= 0x8000; // eGameSetting_Tooltips - on pGameSettings->uiBitmaskValues = 0L; // reset pGameSettings->uiBitmaskValues |= GAMESETTING_CLOUDS; // eGameSetting_Clouds - on pGameSettings->uiBitmaskValues |= GAMESETTING_ONLINE; // eGameSetting_GameSetting_Online - on // eGameSetting_GameSetting_Invite - off pGameSettings->uiBitmaskValues |= GAMESETTING_FRIENDSOFFRIENDS; // eGameSetting_GameSetting_FriendsOfFriends // - on pGameSettings->uiBitmaskValues |= GAMESETTING_DISPLAYUPDATEMSG; // eGameSetting_DisplayUpdateMessage // (counter) pGameSettings->uiBitmaskValues &= ~GAMESETTING_BEDROCKFOG; // eGameSetting_BedrockFog - off pGameSettings->uiBitmaskValues |= GAMESETTING_DISPLAYHUD; // eGameSetting_DisplayHUD - on pGameSettings->uiBitmaskValues |= GAMESETTING_DISPLAYHAND; // eGameSetting_DisplayHand - on pGameSettings->uiBitmaskValues |= GAMESETTING_CUSTOMSKINANIM; // eGameSetting_CustomSkinAnim - on pGameSettings->uiBitmaskValues |= GAMESETTING_DEATHMESSAGES; // eGameSetting_DeathMessages - on pGameSettings->uiBitmaskValues |= (GAMESETTING_UISIZE & 0x00000800); // uisize 2 pGameSettings->uiBitmaskValues |= (GAMESETTING_UISIZE_SPLITSCREEN & 0x00004000); // splitscreen ui size 3 pGameSettings->uiBitmaskValues |= GAMESETTING_ANIMATEDCHARACTER; // eGameSetting_AnimatedCharacter // - on // TU12 // favorite skins added, but only set in TU12 - set to FFs for (int i = 0; i < MAX_FAVORITE_SKINS; i++) { pGameSettings->uiFavoriteSkinA[i] = 0xFFFFFFFF; } pGameSettings->ucCurrentFavoriteSkinPos = 0; // Added a bitmask in TU13 to enable/disable display of the Mash-up // pack worlds in the saves list pGameSettings->uiMashUpPackWorldsDisplay = 0xFFFFFFFF; // PS3DEC13 pGameSettings->uiBitmaskValues &= ~GAMESETTING_PS3EULAREAD; // eGameSetting_PS3_EULA_Read - off // PS3 1.05 - added Greek pGameSettings->ucLanguage = MINECRAFT_LANGUAGE_DEFAULT; // use the system language } break; } return 0; } void Game::ApplyGameSettingsChanged(int iPad) { ActionGameSettings(iPad, eGameSetting_MusicVolume); ActionGameSettings(iPad, eGameSetting_SoundFXVolume); ActionGameSettings(iPad, eGameSetting_Gamma); ActionGameSettings(iPad, eGameSetting_Difficulty); ActionGameSettings(iPad, eGameSetting_Sensitivity_InGame); ActionGameSettings(iPad, eGameSetting_ViewBob); ActionGameSettings(iPad, eGameSetting_ControlScheme); ActionGameSettings(iPad, eGameSetting_ControlInvertLook); ActionGameSettings(iPad, eGameSetting_ControlSouthPaw); ActionGameSettings(iPad, eGameSetting_SplitScreenVertical); ActionGameSettings(iPad, eGameSetting_GamertagsVisible); // Interim TU 1.6.6 ActionGameSettings(iPad, eGameSetting_Sensitivity_InMenu); ActionGameSettings(iPad, eGameSetting_DisplaySplitscreenGamertags); ActionGameSettings(iPad, eGameSetting_Hints); ActionGameSettings(iPad, eGameSetting_InterfaceOpacity); ActionGameSettings(iPad, eGameSetting_Tooltips); ActionGameSettings(iPad, eGameSetting_Clouds); ActionGameSettings(iPad, eGameSetting_BedrockFog); ActionGameSettings(iPad, eGameSetting_DisplayHUD); ActionGameSettings(iPad, eGameSetting_DisplayHand); ActionGameSettings(iPad, eGameSetting_CustomSkinAnim); ActionGameSettings(iPad, eGameSetting_DeathMessages); ActionGameSettings(iPad, eGameSetting_UISize); ActionGameSettings(iPad, eGameSetting_UISizeSplitscreen); ActionGameSettings(iPad, eGameSetting_AnimatedCharacter); ActionGameSettings(iPad, eGameSetting_PS3_EULA_Read); } void Game::ActionGameSettings(int iPad, eGameSetting eVal) { Minecraft* pMinecraft = Minecraft::GetInstance(); switch (eVal) { case eGameSetting_MusicVolume: if (iPad == ProfileManager.GetPrimaryPad()) { pMinecraft->options->set( Options::Option::MUSIC, ((float)GameSettingsA[iPad]->ucMusicVolume) / 100.0f); } break; case eGameSetting_SoundFXVolume: if (iPad == ProfileManager.GetPrimaryPad()) { pMinecraft->options->set( Options::Option::SOUND, ((float)GameSettingsA[iPad]->ucSoundFXVolume) / 100.0f); } break; case eGameSetting_Gamma: if (iPad == ProfileManager.GetPrimaryPad()) { // ucGamma range is 0-100, UpdateGamma is 0 - 32768 float fVal = ((float)GameSettingsA[iPad]->ucGamma) * 327.68f; RenderManager.UpdateGamma((unsigned short)fVal); } break; case eGameSetting_Difficulty: if (iPad == ProfileManager.GetPrimaryPad()) { pMinecraft->options->toggle( Options::Option::DIFFICULTY, GameSettingsA[iPad]->usBitmaskValues & 0x03); app.DebugPrintf("Difficulty toggle to %d\n", GameSettingsA[iPad]->usBitmaskValues & 0x03); // Update the Game Host setting app.SetGameHostOption(eGameHostOption_Difficulty, pMinecraft->options->difficulty); // send this to the other players if we are in-game bool bInGame = pMinecraft->level != nullptr; // Game Host only (and for now we can't change the diff while in // game, so this shouldn't happen) if (bInGame && g_NetworkManager.IsHost() && (iPad == ProfileManager.GetPrimaryPad())) { app.SetXuiServerAction( iPad, eXuiServerAction_ServerSettingChanged_Difficulty); } } else { app.DebugPrintf( "NOT ACTIONING DIFFICULTY - Primary pad is %d, This pad is " "%d\n", ProfileManager.GetPrimaryPad(), iPad); } break; case eGameSetting_Sensitivity_InGame: // 4J-PB - we don't use the options value // tell the input that we've changed the sensitivity - range of the // slider is 0 to 200, default is 100 pMinecraft->options->set( Options::Option::SENSITIVITY, ((float)GameSettingsA[iPad]->ucSensitivity) / 100.0f); // InputManager.SetJoypadSensitivity(iPad,((float)GameSettingsA[iPad]->ucSensitivity)/100.0f); break; case eGameSetting_ViewBob: // 4J-PB - not handled here any more - it's read from the // gamesettings per player // pMinecraft->options->toggle(Options::Option::VIEW_BOBBING,GameSettingsA[iPad]->usBitmaskValues&0x04); break; case eGameSetting_ControlScheme: InputManager.SetJoypadMapVal( iPad, (GameSettingsA[iPad]->usBitmaskValues & 0x30) >> 4); break; case eGameSetting_ControlInvertLook: // Nothing specific to do for this setting. break; case eGameSetting_ControlSouthPaw: // What is the setting? if (GameSettingsA[iPad]->usBitmaskValues & 0x80) { // Southpaw. InputManager.SetJoypadStickAxisMap(iPad, AXIS_MAP_LX, AXIS_MAP_RX); InputManager.SetJoypadStickAxisMap(iPad, AXIS_MAP_LY, AXIS_MAP_RY); InputManager.SetJoypadStickAxisMap(iPad, AXIS_MAP_RX, AXIS_MAP_LX); InputManager.SetJoypadStickAxisMap(iPad, AXIS_MAP_RY, AXIS_MAP_LY); InputManager.SetJoypadStickTriggerMap(iPad, TRIGGER_MAP_0, TRIGGER_MAP_1); InputManager.SetJoypadStickTriggerMap(iPad, TRIGGER_MAP_1, TRIGGER_MAP_0); } else { // Right handed. InputManager.SetJoypadStickAxisMap(iPad, AXIS_MAP_LX, AXIS_MAP_LX); InputManager.SetJoypadStickAxisMap(iPad, AXIS_MAP_LY, AXIS_MAP_LY); InputManager.SetJoypadStickAxisMap(iPad, AXIS_MAP_RX, AXIS_MAP_RX); InputManager.SetJoypadStickAxisMap(iPad, AXIS_MAP_RY, AXIS_MAP_RY); InputManager.SetJoypadStickTriggerMap(iPad, TRIGGER_MAP_0, TRIGGER_MAP_0); InputManager.SetJoypadStickTriggerMap(iPad, TRIGGER_MAP_1, TRIGGER_MAP_1); } break; case eGameSetting_SplitScreenVertical: if (iPad == ProfileManager.GetPrimaryPad()) { pMinecraft->updatePlayerViewportAssignments(); } break; case eGameSetting_GamertagsVisible: { bool bInGame = pMinecraft->level != nullptr; // Game Host only if (bInGame && g_NetworkManager.IsHost() && (iPad == ProfileManager.GetPrimaryPad())) { // Update the Game Host setting if you are the host and you are // in-game app.SetGameHostOption( eGameHostOption_Gamertags, ((GameSettingsA[iPad]->usBitmaskValues & 0x0008) != 0) ? 1 : 0); app.SetXuiServerAction( iPad, eXuiServerAction_ServerSettingChanged_Gamertags); PlayerList* players = MinecraftServer::getInstance()->getPlayerList(); for (auto it3 = players->players.begin(); it3 != players->players.end(); ++it3) { std::shared_ptr decorationPlayer = *it3; decorationPlayer->setShowOnMaps( (app.GetGameHostOption(eGameHostOption_Gamertags) != 0) ? true : false); } } } break; // Interim TU 1.6.6 case eGameSetting_Sensitivity_InMenu: // 4J-PB - we don't use the options value // tell the input that we've changed the sensitivity - range of the // slider is 0 to 200, default is 100 // pMinecraft->options->set(Options::Option::SENSITIVITY,((float)GameSettingsA[iPad]->ucSensitivity)/100.0f); // InputManager.SetJoypadSensitivity(iPad,((float)GameSettingsA[iPad]->ucSensitivity)/100.0f); break; case eGameSetting_DisplaySplitscreenGamertags: for (std::uint8_t idx = 0; idx < XUSER_MAX_COUNT; ++idx) { if (pMinecraft->localplayers[idx] != nullptr) { if (pMinecraft->localplayers[idx]->m_iScreenSection == C4JRender::VIEWPORT_TYPE_FULLSCREEN) { ui.DisplayGamertag(idx, false); } else { ui.DisplayGamertag(idx, true); } } } break; case eGameSetting_InterfaceOpacity: // update the tooltips display ui.RefreshTooltips(iPad); break; case eGameSetting_Hints: // nothing to do here break; case eGameSetting_Tooltips: if ((GameSettingsA[iPad]->usBitmaskValues & 0x8000) != 0) { ui.SetEnableTooltips(iPad, true); } else { ui.SetEnableTooltips(iPad, false); } break; case eGameSetting_Clouds: // nothing to do here break; case eGameSetting_Online: // nothing to do here break; case eGameSetting_InviteOnly: // nothing to do here break; case eGameSetting_FriendsOfFriends: // nothing to do here break; case eGameSetting_BedrockFog: { bool bInGame = pMinecraft->level != nullptr; // Game Host only if (bInGame && g_NetworkManager.IsHost() && (iPad == ProfileManager.GetPrimaryPad())) { // Update the Game Host setting if you are the host and you are // in-game app.SetGameHostOption( eGameHostOption_BedrockFog, GetGameSettings(iPad, eGameSetting_BedrockFog) ? 1 : 0); app.SetXuiServerAction( iPad, eXuiServerAction_ServerSettingChanged_BedrockFog); } } break; case eGameSetting_DisplayHUD: // nothing to do here break; case eGameSetting_DisplayHand: // nothing to do here break; case eGameSetting_CustomSkinAnim: // nothing to do here break; case eGameSetting_DeathMessages: // nothing to do here break; case eGameSetting_UISize: // nothing to do here break; case eGameSetting_UISizeSplitscreen: // nothing to do here break; case eGameSetting_AnimatedCharacter: // nothing to do here break; case eGameSetting_PS3_EULA_Read: // nothing to do here break; case eGameSetting_PSVita_NetworkModeAdhoc: // nothing to do here break; default: break; } } void Game::SetPlayerSkin(int iPad, const std::wstring& name) { std::uint32_t skinId = app.getSkinIdFromPath(name); SetPlayerSkin(iPad, skinId); } void Game::SetPlayerSkin(int iPad, std::uint32_t dwSkinId) { DebugPrintf("Setting skin for %d to %08X\n", iPad, dwSkinId); GameSettingsA[iPad]->dwSelectedSkin = dwSkinId; GameSettingsA[iPad]->bSettingsChanged = true; if (Minecraft::GetInstance()->localplayers[iPad] != nullptr) Minecraft::GetInstance()->localplayers[iPad]->setAndBroadcastCustomSkin( dwSkinId); } std::wstring Game::GetPlayerSkinName(int iPad) { return app.getSkinPathFromId(GameSettingsA[iPad]->dwSelectedSkin); } std::uint32_t Game::GetPlayerSkinId(int iPad) { // 4J-PB -check the user has rights to use this skin - they may have had at // some point but the entitlement has been removed. DLCPack* Pack = nullptr; DLCSkinFile* skinFile = nullptr; std::uint32_t dwSkin = GameSettingsA[iPad]->dwSelectedSkin; wchar_t chars[256]; if (GET_IS_DLC_SKIN_FROM_BITMASK(dwSkin)) { // 4J Stu - DLC skins are numbered using decimal rather than hex to make // it easier to number manually swprintf(chars, 256, L"dlcskin%08d.png", GET_DLC_SKIN_ID_FROM_BITMASK(dwSkin)); Pack = app.m_dlcManager.getPackContainingSkin(chars); if (Pack) { skinFile = Pack->getSkinFile(chars); bool bSkinIsFree = skinFile->getParameterAsBool(DLCManager::e_DLCParamType_Free); bool bLicensed = Pack->hasPurchasedFile(DLCManager::e_DLCType_Skin, skinFile->getPath()); if (bSkinIsFree || bLicensed) { return dwSkin; } else { return 0; } } } return dwSkin; } std::uint32_t Game::GetAdditionalModelParts(int iPad) { return m_dwAdditionalModelParts[iPad]; } void Game::SetPlayerCape(int iPad, const std::wstring& name) { std::uint32_t capeId = Player::getCapeIdFromPath(name); SetPlayerCape(iPad, capeId); } void Game::SetPlayerCape(int iPad, std::uint32_t dwCapeId) { DebugPrintf("Setting cape for %d to %08X\n", iPad, dwCapeId); GameSettingsA[iPad]->dwSelectedCape = dwCapeId; GameSettingsA[iPad]->bSettingsChanged = true; // SentientManager.RecordSkinChanged(iPad, // GameSettingsA[iPad]->dwSelectedSkin); if (Minecraft::GetInstance()->localplayers[iPad] != nullptr) Minecraft::GetInstance()->localplayers[iPad]->setAndBroadcastCustomCape( dwCapeId); } std::wstring Game::GetPlayerCapeName(int iPad) { return Player::getCapePathFromId(GameSettingsA[iPad]->dwSelectedCape); } std::uint32_t Game::GetPlayerCapeId(int iPad) { return GameSettingsA[iPad]->dwSelectedCape; } void Game::SetPlayerFavoriteSkin(int iPad, int iIndex, unsigned int uiSkinID) { DebugPrintf("Setting favorite skin for %d to %08X\n", iPad, uiSkinID); GameSettingsA[iPad]->uiFavoriteSkinA[iIndex] = uiSkinID; GameSettingsA[iPad]->bSettingsChanged = true; } unsigned int Game::GetPlayerFavoriteSkin(int iPad, int iIndex) { return GameSettingsA[iPad]->uiFavoriteSkinA[iIndex]; } unsigned char Game::GetPlayerFavoriteSkinsPos(int iPad) { return GameSettingsA[iPad]->ucCurrentFavoriteSkinPos; } void Game::SetPlayerFavoriteSkinsPos(int iPad, int iPos) { GameSettingsA[iPad]->ucCurrentFavoriteSkinPos = (unsigned char)iPos; GameSettingsA[iPad]->bSettingsChanged = true; } unsigned int Game::GetPlayerFavoriteSkinsCount(int iPad) { unsigned int uiCount = 0; for (int i = 0; i < MAX_FAVORITE_SKINS; i++) { if (GameSettingsA[iPad]->uiFavoriteSkinA[i] != 0xFFFFFFFF) { uiCount++; } else { break; } } return uiCount; } void Game::ValidateFavoriteSkins(int iPad) { unsigned int uiCount = GetPlayerFavoriteSkinsCount(iPad); // remove invalid skins unsigned int uiValidSkin = 0; wchar_t chars[256]; for (unsigned int i = 0; i < uiCount; i++) { // get the pack number from the skin id swprintf(chars, 256, L"dlcskin%08d.png", app.GetPlayerFavoriteSkin(iPad, i)); // Also check they haven't reverted to a trial pack DLCPack* pDLCPack = app.m_dlcManager.getPackContainingSkin(chars); if (pDLCPack != nullptr) { // 4J-PB - We should let players add the free skins to their // favourites as well! // DLCFile // *pDLCFile=pDLCPack->getFile(DLCManager::e_DLCType_Skin,chars); DLCSkinFile* pSkinFile = pDLCPack->getSkinFile(chars); if (pDLCPack->hasPurchasedFile(DLCManager::e_DLCType_Skin, L"") || (pSkinFile && pSkinFile->isFree())) { GameSettingsA[iPad]->uiFavoriteSkinA[uiValidSkin++] = GameSettingsA[iPad]->uiFavoriteSkinA[i]; } } } for (unsigned int i = uiValidSkin; i < MAX_FAVORITE_SKINS; i++) { GameSettingsA[iPad]->uiFavoriteSkinA[i] = 0xFFFFFFFF; } } // Mash-up pack worlds void Game::HideMashupPackWorld(int iPad, unsigned int iMashupPackID) { unsigned int uiPackID = iMashupPackID - 1024; // mash-up ids start at 1024 GameSettingsA[iPad]->uiMashUpPackWorldsDisplay &= ~(1 << uiPackID); GameSettingsA[iPad]->bSettingsChanged = true; } void Game::EnableMashupPackWorlds(int iPad) { GameSettingsA[iPad]->uiMashUpPackWorldsDisplay = 0xFFFFFFFF; GameSettingsA[iPad]->bSettingsChanged = true; } unsigned int Game::GetMashupPackWorlds(int iPad) { return GameSettingsA[iPad]->uiMashUpPackWorldsDisplay; } void Game::SetMinecraftLanguage(int iPad, unsigned char ucLanguage) { GameSettingsA[iPad]->ucLanguage = ucLanguage; GameSettingsA[iPad]->bSettingsChanged = true; } unsigned char Game::GetMinecraftLanguage(int iPad) { // if there are no game settings read yet, return the default language if (GameSettingsA[iPad] == nullptr) { return 0; } else { return GameSettingsA[iPad]->ucLanguage; } } void Game::SetMinecraftLocale(int iPad, unsigned char ucLocale) { GameSettingsA[iPad]->ucLocale = ucLocale; GameSettingsA[iPad]->bSettingsChanged = true; } unsigned char Game::GetMinecraftLocale(int iPad) { // if there are no game settings read yet, return the default language if (GameSettingsA[iPad] == nullptr) { return 0; } else { return GameSettingsA[iPad]->ucLocale; } } void Game::SetGameSettings(int iPad, eGameSetting eVal, unsigned char ucVal) { // Minecraft *pMinecraft=Minecraft::GetInstance(); switch (eVal) { case eGameSetting_MusicVolume: if (GameSettingsA[iPad]->ucMusicVolume != ucVal) { GameSettingsA[iPad]->ucMusicVolume = ucVal; if (iPad == ProfileManager.GetPrimaryPad()) { ActionGameSettings(iPad, eVal); } GameSettingsA[iPad]->bSettingsChanged = true; } break; case eGameSetting_SoundFXVolume: if (GameSettingsA[iPad]->ucSoundFXVolume != ucVal) { GameSettingsA[iPad]->ucSoundFXVolume = ucVal; if (iPad == ProfileManager.GetPrimaryPad()) { ActionGameSettings(iPad, eVal); } GameSettingsA[iPad]->bSettingsChanged = true; } break; case eGameSetting_Gamma: if (GameSettingsA[iPad]->ucGamma != ucVal) { GameSettingsA[iPad]->ucGamma = ucVal; if (iPad == ProfileManager.GetPrimaryPad()) { ActionGameSettings(iPad, eVal); } GameSettingsA[iPad]->bSettingsChanged = true; } break; case eGameSetting_Difficulty: if ((GameSettingsA[iPad]->usBitmaskValues & 0x03) != (ucVal & 0x03)) { GameSettingsA[iPad]->usBitmaskValues &= ~0x03; GameSettingsA[iPad]->usBitmaskValues |= ucVal & 0x03; if (iPad == ProfileManager.GetPrimaryPad()) { ActionGameSettings(iPad, eVal); } GameSettingsA[iPad]->bSettingsChanged = true; } break; case eGameSetting_Sensitivity_InGame: if (GameSettingsA[iPad]->ucSensitivity != ucVal) { GameSettingsA[iPad]->ucSensitivity = ucVal; ActionGameSettings(iPad, eVal); GameSettingsA[iPad]->bSettingsChanged = true; } break; case eGameSetting_ViewBob: if ((GameSettingsA[iPad]->usBitmaskValues & 0x0004) != ((ucVal & 0x01) << 2)) { if (ucVal != 0) { GameSettingsA[iPad]->usBitmaskValues |= 0x0004; } else { GameSettingsA[iPad]->usBitmaskValues &= ~0x0004; } ActionGameSettings(iPad, eVal); GameSettingsA[iPad]->bSettingsChanged = true; } break; case eGameSetting_ControlScheme: // bits 5 and 6 if ((GameSettingsA[iPad]->usBitmaskValues & 0x30) != ((ucVal & 0x03) << 4)) { GameSettingsA[iPad]->usBitmaskValues &= ~0x0030; if (ucVal != 0) { GameSettingsA[iPad]->usBitmaskValues |= (ucVal & 0x03) << 4; } ActionGameSettings(iPad, eVal); GameSettingsA[iPad]->bSettingsChanged = true; } break; case eGameSetting_ControlInvertLook: if ((GameSettingsA[iPad]->usBitmaskValues & 0x0040) != ((ucVal & 0x01) << 6)) { if (ucVal != 0) { GameSettingsA[iPad]->usBitmaskValues |= 0x0040; } else { GameSettingsA[iPad]->usBitmaskValues &= ~0x0040; } ActionGameSettings(iPad, eVal); GameSettingsA[iPad]->bSettingsChanged = true; } break; case eGameSetting_ControlSouthPaw: if ((GameSettingsA[iPad]->usBitmaskValues & 0x0080) != ((ucVal & 0x01) << 7)) { if (ucVal != 0) { GameSettingsA[iPad]->usBitmaskValues |= 0x0080; } else { GameSettingsA[iPad]->usBitmaskValues &= ~0x0080; } ActionGameSettings(iPad, eVal); GameSettingsA[iPad]->bSettingsChanged = true; } break; case eGameSetting_SplitScreenVertical: if ((GameSettingsA[iPad]->usBitmaskValues & 0x0100) != ((ucVal & 0x01) << 8)) { if (ucVal != 0) { GameSettingsA[iPad]->usBitmaskValues |= 0x0100; } else { GameSettingsA[iPad]->usBitmaskValues &= ~0x0100; } ActionGameSettings(iPad, eVal); GameSettingsA[iPad]->bSettingsChanged = true; } break; case eGameSetting_GamertagsVisible: if ((GameSettingsA[iPad]->usBitmaskValues & 0x0008) != ((ucVal & 0x01) << 3)) { if (ucVal != 0) { GameSettingsA[iPad]->usBitmaskValues |= 0x0008; } else { GameSettingsA[iPad]->usBitmaskValues &= ~0x0008; } ActionGameSettings(iPad, eVal); GameSettingsA[iPad]->bSettingsChanged = true; } break; // 4J-PB - Added for Interim TU for 1.6.6 case eGameSetting_Sensitivity_InMenu: if (GameSettingsA[iPad]->ucMenuSensitivity != ucVal) { GameSettingsA[iPad]->ucMenuSensitivity = ucVal; ActionGameSettings(iPad, eVal); GameSettingsA[iPad]->bSettingsChanged = true; } break; case eGameSetting_DisplaySplitscreenGamertags: if ((GameSettingsA[iPad]->usBitmaskValues & 0x0200) != ((ucVal & 0x01) << 9)) { if (ucVal != 0) { GameSettingsA[iPad]->usBitmaskValues |= 0x0200; } else { GameSettingsA[iPad]->usBitmaskValues &= ~0x0200; } ActionGameSettings(iPad, eVal); GameSettingsA[iPad]->bSettingsChanged = true; } break; case eGameSetting_Hints: if ((GameSettingsA[iPad]->usBitmaskValues & 0x0400) != ((ucVal & 0x01) << 10)) { if (ucVal != 0) { GameSettingsA[iPad]->usBitmaskValues |= 0x0400; } else { GameSettingsA[iPad]->usBitmaskValues &= ~0x0400; } ActionGameSettings(iPad, eVal); GameSettingsA[iPad]->bSettingsChanged = true; } break; case eGameSetting_Autosave: if ((GameSettingsA[iPad]->usBitmaskValues & 0x7800) != ((ucVal & 0x0F) << 11)) { GameSettingsA[iPad]->usBitmaskValues &= ~0x7800; if (ucVal != 0) { GameSettingsA[iPad]->usBitmaskValues |= (ucVal & 0x0F) << 11; } ActionGameSettings(iPad, eVal); GameSettingsA[iPad]->bSettingsChanged = true; } break; case eGameSetting_Tooltips: if ((GameSettingsA[iPad]->usBitmaskValues & 0x8000) != ((ucVal & 0x01) << 15)) { if (ucVal != 0) { GameSettingsA[iPad]->usBitmaskValues |= 0x8000; } else { GameSettingsA[iPad]->usBitmaskValues &= ~0x8000; } ActionGameSettings(iPad, eVal); GameSettingsA[iPad]->bSettingsChanged = true; } break; case eGameSetting_InterfaceOpacity: if (GameSettingsA[iPad]->ucInterfaceOpacity != ucVal) { GameSettingsA[iPad]->ucInterfaceOpacity = ucVal; ActionGameSettings(iPad, eVal); GameSettingsA[iPad]->bSettingsChanged = true; } break; case eGameSetting_Clouds: if ((GameSettingsA[iPad]->uiBitmaskValues & GAMESETTING_CLOUDS) != (ucVal & 0x01)) { if (ucVal == 1) { GameSettingsA[iPad]->uiBitmaskValues |= GAMESETTING_CLOUDS; } else { GameSettingsA[iPad]->uiBitmaskValues &= ~GAMESETTING_CLOUDS; } ActionGameSettings(iPad, eVal); GameSettingsA[iPad]->bSettingsChanged = true; } break; case eGameSetting_Online: if ((GameSettingsA[iPad]->uiBitmaskValues & GAMESETTING_ONLINE) != (ucVal & 0x01) << 1) { if (ucVal == 1) { GameSettingsA[iPad]->uiBitmaskValues |= GAMESETTING_ONLINE; } else { GameSettingsA[iPad]->uiBitmaskValues &= ~GAMESETTING_ONLINE; } ActionGameSettings(iPad, eVal); GameSettingsA[iPad]->bSettingsChanged = true; } break; case eGameSetting_InviteOnly: if ((GameSettingsA[iPad]->uiBitmaskValues & GAMESETTING_INVITEONLY) != (ucVal & 0x01) << 2) { if (ucVal == 1) { GameSettingsA[iPad]->uiBitmaskValues |= GAMESETTING_INVITEONLY; } else { GameSettingsA[iPad]->uiBitmaskValues &= ~GAMESETTING_INVITEONLY; } ActionGameSettings(iPad, eVal); GameSettingsA[iPad]->bSettingsChanged = true; } break; case eGameSetting_FriendsOfFriends: if ((GameSettingsA[iPad]->uiBitmaskValues & GAMESETTING_FRIENDSOFFRIENDS) != (ucVal & 0x01) << 3) { if (ucVal == 1) { GameSettingsA[iPad]->uiBitmaskValues |= GAMESETTING_FRIENDSOFFRIENDS; } else { GameSettingsA[iPad]->uiBitmaskValues &= ~GAMESETTING_FRIENDSOFFRIENDS; } ActionGameSettings(iPad, eVal); GameSettingsA[iPad]->bSettingsChanged = true; } break; case eGameSetting_DisplayUpdateMessage: if ((GameSettingsA[iPad]->uiBitmaskValues & GAMESETTING_DISPLAYUPDATEMSG) != (ucVal & 0x03) << 4) { GameSettingsA[iPad]->uiBitmaskValues &= ~GAMESETTING_DISPLAYUPDATEMSG; if (ucVal > 0) { GameSettingsA[iPad]->uiBitmaskValues |= (ucVal & 0x03) << 4; } ActionGameSettings(iPad, eVal); GameSettingsA[iPad]->bSettingsChanged = true; } break; case eGameSetting_BedrockFog: if ((GameSettingsA[iPad]->uiBitmaskValues & GAMESETTING_BEDROCKFOG) != (ucVal & 0x01) << 6) { if (ucVal == 1) { GameSettingsA[iPad]->uiBitmaskValues |= GAMESETTING_BEDROCKFOG; } else { GameSettingsA[iPad]->uiBitmaskValues &= ~GAMESETTING_BEDROCKFOG; } ActionGameSettings(iPad, eVal); GameSettingsA[iPad]->bSettingsChanged = true; } break; case eGameSetting_DisplayHUD: if ((GameSettingsA[iPad]->uiBitmaskValues & GAMESETTING_DISPLAYHUD) != (ucVal & 0x01) << 7) { if (ucVal == 1) { GameSettingsA[iPad]->uiBitmaskValues |= GAMESETTING_DISPLAYHUD; } else { GameSettingsA[iPad]->uiBitmaskValues &= ~GAMESETTING_DISPLAYHUD; } ActionGameSettings(iPad, eVal); GameSettingsA[iPad]->bSettingsChanged = true; } break; case eGameSetting_DisplayHand: if ((GameSettingsA[iPad]->uiBitmaskValues & GAMESETTING_DISPLAYHAND) != (ucVal & 0x01) << 8) { if (ucVal == 1) { GameSettingsA[iPad]->uiBitmaskValues |= GAMESETTING_DISPLAYHAND; } else { GameSettingsA[iPad]->uiBitmaskValues &= ~GAMESETTING_DISPLAYHAND; } ActionGameSettings(iPad, eVal); GameSettingsA[iPad]->bSettingsChanged = true; } break; case eGameSetting_CustomSkinAnim: if ((GameSettingsA[iPad]->uiBitmaskValues & GAMESETTING_CUSTOMSKINANIM) != (ucVal & 0x01) << 9) { if (ucVal == 1) { GameSettingsA[iPad]->uiBitmaskValues |= GAMESETTING_CUSTOMSKINANIM; } else { GameSettingsA[iPad]->uiBitmaskValues &= ~GAMESETTING_CUSTOMSKINANIM; } ActionGameSettings(iPad, eVal); GameSettingsA[iPad]->bSettingsChanged = true; } break; // TU9 case eGameSetting_DeathMessages: if ((GameSettingsA[iPad]->uiBitmaskValues & GAMESETTING_DEATHMESSAGES) != (ucVal & 0x01) << 10) { if (ucVal == 1) { GameSettingsA[iPad]->uiBitmaskValues |= GAMESETTING_DEATHMESSAGES; } else { GameSettingsA[iPad]->uiBitmaskValues &= ~GAMESETTING_DEATHMESSAGES; } ActionGameSettings(iPad, eVal); GameSettingsA[iPad]->bSettingsChanged = true; } break; case eGameSetting_UISize: if ((GameSettingsA[iPad]->uiBitmaskValues & GAMESETTING_UISIZE) != ((ucVal & 0x03) << 11)) { GameSettingsA[iPad]->uiBitmaskValues &= ~GAMESETTING_UISIZE; if (ucVal != 0) { GameSettingsA[iPad]->uiBitmaskValues |= (ucVal & 0x03) << 11; } ActionGameSettings(iPad, eVal); GameSettingsA[iPad]->bSettingsChanged = true; } break; case eGameSetting_UISizeSplitscreen: if ((GameSettingsA[iPad]->uiBitmaskValues & GAMESETTING_UISIZE_SPLITSCREEN) != ((ucVal & 0x03) << 13)) { GameSettingsA[iPad]->uiBitmaskValues &= ~GAMESETTING_UISIZE_SPLITSCREEN; if (ucVal != 0) { GameSettingsA[iPad]->uiBitmaskValues |= (ucVal & 0x03) << 13; } ActionGameSettings(iPad, eVal); GameSettingsA[iPad]->bSettingsChanged = true; } break; case eGameSetting_AnimatedCharacter: if ((GameSettingsA[iPad]->uiBitmaskValues & GAMESETTING_ANIMATEDCHARACTER) != (ucVal & 0x01) << 15) { if (ucVal == 1) { GameSettingsA[iPad]->uiBitmaskValues |= GAMESETTING_ANIMATEDCHARACTER; } else { GameSettingsA[iPad]->uiBitmaskValues &= ~GAMESETTING_ANIMATEDCHARACTER; } ActionGameSettings(iPad, eVal); GameSettingsA[iPad]->bSettingsChanged = true; } break; case eGameSetting_PS3_EULA_Read: if ((GameSettingsA[iPad]->uiBitmaskValues & GAMESETTING_PS3EULAREAD) != (ucVal & 0x01) << 16) { if (ucVal == 1) { GameSettingsA[iPad]->uiBitmaskValues |= GAMESETTING_PS3EULAREAD; } else { GameSettingsA[iPad]->uiBitmaskValues &= ~GAMESETTING_PS3EULAREAD; } ActionGameSettings(iPad, eVal); GameSettingsA[iPad]->bSettingsChanged = true; } break; case eGameSetting_PSVita_NetworkModeAdhoc: if ((GameSettingsA[iPad]->uiBitmaskValues & GAMESETTING_PSVITANETWORKMODEADHOC) != (ucVal & 0x01) << 17) { if (ucVal == 1) { GameSettingsA[iPad]->uiBitmaskValues |= GAMESETTING_PSVITANETWORKMODEADHOC; } else { GameSettingsA[iPad]->uiBitmaskValues &= ~GAMESETTING_PSVITANETWORKMODEADHOC; } ActionGameSettings(iPad, eVal); GameSettingsA[iPad]->bSettingsChanged = true; } break; } } unsigned char Game::GetGameSettings(eGameSetting eVal) { int iPad = ProfileManager.GetPrimaryPad(); return GetGameSettings(iPad, eVal); } unsigned char Game::GetGameSettings(int iPad, eGameSetting eVal) { switch (eVal) { case eGameSetting_MusicVolume: return GameSettingsA[iPad]->ucMusicVolume; break; case eGameSetting_SoundFXVolume: return GameSettingsA[iPad]->ucSoundFXVolume; break; case eGameSetting_Gamma: return GameSettingsA[iPad]->ucGamma; break; case eGameSetting_Difficulty: return GameSettingsA[iPad]->usBitmaskValues & 0x0003; break; case eGameSetting_Sensitivity_InGame: return GameSettingsA[iPad]->ucSensitivity; break; case eGameSetting_ViewBob: return ((GameSettingsA[iPad]->usBitmaskValues & 0x0004) >> 2); break; case eGameSetting_GamertagsVisible: return ((GameSettingsA[iPad]->usBitmaskValues & 0x0008) >> 3); break; case eGameSetting_ControlScheme: return ((GameSettingsA[iPad]->usBitmaskValues & 0x0030) >> 4); // 2 bits break; case eGameSetting_ControlInvertLook: return ((GameSettingsA[iPad]->usBitmaskValues & 0x0040) >> 6); break; case eGameSetting_ControlSouthPaw: return ((GameSettingsA[iPad]->usBitmaskValues & 0x0080) >> 7); break; case eGameSetting_SplitScreenVertical: return ((GameSettingsA[iPad]->usBitmaskValues & 0x0100) >> 8); break; // 4J-PB - Added for Interim TU for 1.6.6 case eGameSetting_Sensitivity_InMenu: return GameSettingsA[iPad]->ucMenuSensitivity; break; case eGameSetting_DisplaySplitscreenGamertags: return ((GameSettingsA[iPad]->usBitmaskValues & 0x0200) >> 9); break; case eGameSetting_Hints: return ((GameSettingsA[iPad]->usBitmaskValues & 0x0400) >> 10); break; case eGameSetting_Autosave: { unsigned char ucVal = (GameSettingsA[iPad]->usBitmaskValues & 0x7800) >> 11; return ucVal; } break; case eGameSetting_Tooltips: return ((GameSettingsA[iPad]->usBitmaskValues & 0x8000) >> 15); break; case eGameSetting_InterfaceOpacity: return GameSettingsA[iPad]->ucInterfaceOpacity; break; case eGameSetting_Clouds: return (GameSettingsA[iPad]->uiBitmaskValues & GAMESETTING_CLOUDS); break; case eGameSetting_Online: return (GameSettingsA[iPad]->uiBitmaskValues & GAMESETTING_ONLINE) >> 1; break; case eGameSetting_InviteOnly: return (GameSettingsA[iPad]->uiBitmaskValues & GAMESETTING_INVITEONLY) >> 2; break; case eGameSetting_FriendsOfFriends: return (GameSettingsA[iPad]->uiBitmaskValues & GAMESETTING_FRIENDSOFFRIENDS) >> 3; break; case eGameSetting_DisplayUpdateMessage: return (GameSettingsA[iPad]->uiBitmaskValues & GAMESETTING_DISPLAYUPDATEMSG) >> 4; break; case eGameSetting_BedrockFog: return (GameSettingsA[iPad]->uiBitmaskValues & GAMESETTING_BEDROCKFOG) >> 6; break; case eGameSetting_DisplayHUD: return (GameSettingsA[iPad]->uiBitmaskValues & GAMESETTING_DISPLAYHUD) >> 7; break; case eGameSetting_DisplayHand: return (GameSettingsA[iPad]->uiBitmaskValues & GAMESETTING_DISPLAYHAND) >> 8; break; case eGameSetting_CustomSkinAnim: return (GameSettingsA[iPad]->uiBitmaskValues & GAMESETTING_CUSTOMSKINANIM) >> 9; break; // TU9 case eGameSetting_DeathMessages: return (GameSettingsA[iPad]->uiBitmaskValues & GAMESETTING_DEATHMESSAGES) >> 10; break; case eGameSetting_UISize: { unsigned char ucVal = (GameSettingsA[iPad]->uiBitmaskValues & GAMESETTING_UISIZE) >> 11; return ucVal; } break; case eGameSetting_UISizeSplitscreen: { unsigned char ucVal = (GameSettingsA[iPad]->uiBitmaskValues & GAMESETTING_UISIZE_SPLITSCREEN) >> 13; return ucVal; } break; case eGameSetting_AnimatedCharacter: return (GameSettingsA[iPad]->uiBitmaskValues & GAMESETTING_ANIMATEDCHARACTER) >> 15; case eGameSetting_PS3_EULA_Read: return (GameSettingsA[iPad]->uiBitmaskValues & GAMESETTING_PS3EULAREAD) >> 16; case eGameSetting_PSVita_NetworkModeAdhoc: return (GameSettingsA[iPad]->uiBitmaskValues & GAMESETTING_PSVITANETWORKMODEADHOC) >> 17; } return 0; } void Game::CheckGameSettingsChanged(bool bOverride5MinuteTimer, int iPad) { // If the settings have changed, write them to the profile if (iPad == XUSER_INDEX_ANY) { for (int i = 0; i < XUSER_MAX_COUNT; i++) { if (GameSettingsA[i]->bSettingsChanged) { ProfileManager.WriteToProfile(i, true, bOverride5MinuteTimer); GameSettingsA[i]->bSettingsChanged = false; } } } else { if (GameSettingsA[iPad]->bSettingsChanged) { ProfileManager.WriteToProfile(iPad, true, bOverride5MinuteTimer); GameSettingsA[iPad]->bSettingsChanged = false; } } } void Game::ClearGameSettingsChangedFlag(int iPad) { GameSettingsA[iPad]->bSettingsChanged = false; } /////////////////////////// // // Remove the debug settings in the content package build // //////////////////////////// #if !defined(_DEBUG_MENUS_ENABLED) unsigned int Game::GetGameSettingsDebugMask( int iPad, bool bOverridePlayer) // bOverridePlayer is to force the send for // the server to get the read options { return 0; } void Game::SetGameSettingsDebugMask(int iPad, unsigned int uiVal) {} void Game::ActionDebugMask(int iPad, bool bSetAllClear) {} #else unsigned int Game::GetGameSettingsDebugMask( int iPad, bool bOverridePlayer) // bOverridePlayer is to force the send for // the server to get the read options { if (iPad == -1) { iPad = ProfileManager.GetPrimaryPad(); } if (iPad < 0) iPad = 0; std::shared_ptr player = Minecraft::GetInstance()->localplayers[iPad]; if (bOverridePlayer || player == nullptr) { return GameSettingsA[iPad]->uiDebugBitmask; } else { return player->GetDebugOptions(); } } void Game::SetGameSettingsDebugMask(int iPad, unsigned int uiVal) { #if !defined(_CONTENT_PACKAGE) GameSettingsA[iPad]->bSettingsChanged = true; GameSettingsA[iPad]->uiDebugBitmask = uiVal; // update the value so the network server can use it std::shared_ptr player = Minecraft::GetInstance()->localplayers[iPad]; if (player) { Minecraft::GetInstance()->localgameModes[iPad]->handleDebugOptions( uiVal, player); } #endif } void Game::ActionDebugMask(int iPad, bool bSetAllClear) { unsigned int ulBitmask = app.GetGameSettingsDebugMask(iPad); if (bSetAllClear) ulBitmask = 0L; // these settings should only be actioned for the primary player if (ProfileManager.GetPrimaryPad() != iPad) return; for (int i = 0; i < eDebugSetting_Max; i++) { switch (i) { case eDebugSetting_LoadSavesFromDisk: if (ulBitmask & (1 << i)) { app.SetLoadSavesFromFolderEnabled(true); } else { app.SetLoadSavesFromFolderEnabled(false); } break; case eDebugSetting_WriteSavesToDisk: if (ulBitmask & (1 << i)) { app.SetWriteSavesToFolderEnabled(true); } else { app.SetWriteSavesToFolderEnabled(false); } break; case eDebugSetting_FreezePlayers: // eDebugSetting_InterfaceOff: if (ulBitmask & (1 << i)) { app.SetFreezePlayers(true); // Turn off interface rendering. // app.SetInterfaceRenderingOff( true ); } else { app.SetFreezePlayers(false); // Turn on interface rendering. // app.SetInterfaceRenderingOff( false ); } break; case eDebugSetting_Safearea: if (ulBitmask & (1 << i)) { app.ShowSafeArea(true); } else { app.ShowSafeArea(false); } break; // case eDebugSetting_HandRenderingOff: // if(ulBitmask&(1<iPad, actionInfo->action); } void Game::HandleXuiActions(void) { eXuiAction eAction; eTMSAction eTMS; void* param; Minecraft* pMinecraft = Minecraft::GetInstance(); std::shared_ptr player; // are there any global actions to deal with? eAction = app.GetGlobalXuiAction(); if (eAction != eAppAction_Idle) { switch (eAction) { case eAppAction_DisplayLavaMessage: // Display a warning about placing lava in the spawn area { unsigned int uiIDA[1]; uiIDA[0] = IDS_CONFIRM_OK; C4JStorage::EMessageResult result = ui.RequestErrorMessage(IDS_CANT_PLACE_NEAR_SPAWN_TITLE, IDS_CANT_PLACE_NEAR_SPAWN_TEXT, uiIDA, 1, XUSER_INDEX_ANY); if (result != C4JStorage::EMessage_Busy) SetGlobalXuiAction(eAppAction_Idle); } break; default: break; } } // are there any app actions to deal with? for (int i = 0; i < XUSER_MAX_COUNT; i++) { eAction = app.GetXuiAction(i); param = m_eXuiActionParam[i]; if (eAction != eAppAction_Idle) { switch (eAction) { // // the renderer will capture a screenshot // case eAppAction_SocialPost: // if (ProfileManager.IsFullVersion()) { // // Facebook Share // if (CSocialManager::Instance() // ->IsTitleAllowedToPostImages() && // CSocialManager::Instance() // ->AreAllUsersAllowedToPostImages()) { // // disable character name tags for the shot // // m_bwasHidingGui = // pMinecraft->options->hideGui; // // // 4J Stu - Removed 1.8.2 bug fix (TU6) as // don't // // need this // pMinecraft->options->hideGui = true; // SetAction(i, eAppAction_SocialPostScreenshot); // } else { // SetAction(i, eAppAction_Idle); // } // } else { // SetAction(i, eAppAction_Idle); // } // break; // case eAppAction_SocialPostScreenshot: { // SetAction(i, eAppAction_Idle); // bool bKeepHiding = false; // for (int j = 0; j < XUSER_MAX_COUNT; ++j) { // if (app.GetXuiAction(j) == // eAppAction_SocialPostScreenshot) { // bKeepHiding = true; // break; // } // } // pMinecraft->options->hideGui = bKeepHiding; // // Facebook Share // if (app.GetLocalPlayerCount() > 1) { // ui.NavigateToScene(i, eUIScene_SocialPost); // } else { // ui.NavigateToScene(i, eUIScene_SocialPost); // } // } break; case eAppAction_SaveGame: SetAction(i, eAppAction_Idle); if (!GetChangingSessionType()) { // flag the render to capture the screenshot for the // save SetAction(i, eAppAction_SaveGameCapturedThumbnail); } break; case eAppAction_AutosaveSaveGame: { // Need to run a check to see if the save exists in order to // stop the dialog asking if we want to overwrite it coming // up on an autosave bool bSaveExists; StorageManager.DoesSaveExist(&bSaveExists); SetAction(i, eAppAction_Idle); if (!GetChangingSessionType()) { // flag the render to capture the screenshot for the // save SetAction(i, eAppAction_AutosaveSaveGameCapturedThumbnail); } } break; case eAppAction_SaveGameCapturedThumbnail: // reset the autosave timer app.SetAutosaveTimerTime(); SetAction(i, eAppAction_Idle); // Check that there is a name for the save - if we're saving // from the tutorial and this is the first save from the // tutorial, we'll not have a name /*if(StorageManager.GetSaveName()==nullptr) { app.NavigateToScene(i,eUIScene_SaveWorld); } else*/ { // turn off the gamertags in splitscreen for the primary // player, since they are about to be made fullscreen ui.HideAllGameUIElements(); // Hide the other players scenes ui.ShowOtherPlayersBaseScene( ProfileManager.GetPrimaryPad(), false); // int saveOrCheckpointId = 0; // bool validSave = // StorageManager.GetSaveUniqueNumber(&saveOrCheckpointId); // SentientManager.RecordLevelSaveOrCheckpoint(ProfileManager.GetPrimaryPad(), // saveOrCheckpointId); LoadingInputParams* loadingParams = new LoadingInputParams(); loadingParams->func = &UIScene_PauseMenu::SaveWorldThreadProc; loadingParams->lpParam = (void*)false; // 4J-JEV - PS4: Fix for #5708 - [ONLINE] - If the user // pulls their network cable out while saving the title // will hang. loadingParams->waitForThreadToDelete = true; UIFullscreenProgressCompletionData* completionData = new UIFullscreenProgressCompletionData(); completionData->bShowBackground = true; completionData->bShowLogo = true; completionData->type = e_ProgressCompletion_NavigateBackToScene; completionData->iPad = ProfileManager.GetPrimaryPad(); if (ui.IsSceneInStack(ProfileManager.GetPrimaryPad(), eUIScene_EndPoem)) { completionData->scene = eUIScene_EndPoem; } else { completionData->scene = eUIScene_PauseMenu; } loadingParams->completionData = completionData; // 4J Stu - Xbox only ui.NavigateToScene(ProfileManager.GetPrimaryPad(), eUIScene_FullscreenProgress, loadingParams, eUILayer_Fullscreen, eUIGroup_Fullscreen); } break; case eAppAction_AutosaveSaveGameCapturedThumbnail: { app.SetAutosaveTimerTime(); SetAction(i, eAppAction_Idle); // turn off the gamertags in splitscreen for the primary // player, since they are about to be made fullscreen ui.HideAllGameUIElements(); // app.CloseAllPlayersXuiScenes(); // Hide the other players scenes ui.ShowOtherPlayersBaseScene(ProfileManager.GetPrimaryPad(), false); // This just allows it to be shown if (pMinecraft ->localgameModes[ProfileManager.GetPrimaryPad()] != nullptr) pMinecraft ->localgameModes[ProfileManager.GetPrimaryPad()] ->getTutorial() ->showTutorialPopup(false); // int saveOrCheckpointId = 0; // bool validSave = // StorageManager.GetSaveUniqueNumber(&saveOrCheckpointId); // SentientManager.RecordLevelSaveOrCheckpoint(ProfileManager.GetPrimaryPad(), // saveOrCheckpointId); LoadingInputParams* loadingParams = new LoadingInputParams(); loadingParams->func = &UIScene_PauseMenu::SaveWorldThreadProc; loadingParams->lpParam = (void*)true; UIFullscreenProgressCompletionData* completionData = new UIFullscreenProgressCompletionData(); completionData->bShowBackground = true; completionData->bShowLogo = true; completionData->type = e_ProgressCompletion_AutosaveNavigateBack; completionData->iPad = ProfileManager.GetPrimaryPad(); // completionData->bAutosaveWasMenuDisplayed=ui.GetMenuDisplayed(ProfileManager.GetPrimaryPad()); loadingParams->completionData = completionData; // 4J Stu - Xbox only ui.NavigateToScene(ProfileManager.GetPrimaryPad(), eUIScene_FullscreenProgress, loadingParams, eUILayer_Fullscreen, eUIGroup_Fullscreen); } break; case eAppAction_ExitPlayer: // a secondary player has chosen to quit { int iPlayerC = g_NetworkManager.GetPlayerCount(); // Since the player is exiting, let's flush any profile // writes for them, and hope we're not breaking TCR // 136... ProfileManager.ForceQueuedProfileWrites(i); // not required - it's done within the // removeLocalPlayerIdx // if(pMinecraft->level->isClientSide) // { // // we need to // remove the qnetplayer, or this player won't be able // to get back into the game until qnet times out and // removes them // g_NetworkManager.NotifyPlayerLeaving(g_NetworkManager.GetLocalPlayerByUserIndex(i)); // } // if there are any tips showing, we need to close them pMinecraft->gui->clearMessages(i); // Make sure we've not got this player selected as // current - this shouldn't be the case anyway pMinecraft->setLocalPlayerIdx( ProfileManager.GetPrimaryPad()); pMinecraft->removeLocalPlayerIdx(i); // Wipe out the tooltips ui.SetTooltips(i, -1); // Change the presence info // Are we offline or online, and how many players are // there if (iPlayerC > 2) // one player is about to leave here // - they'll be set to idle in the // qnet manager player leave { for (int iPlayer = 0; iPlayer < XUSER_MAX_COUNT; iPlayer++) { if ((iPlayer != i) && pMinecraft->localplayers[iPlayer]) { if (g_NetworkManager.IsLocalGame()) { ProfileManager.SetCurrentGameActivity( iPlayer, CONTEXT_PRESENCE_MULTIPLAYEROFFLINE, false); } else { ProfileManager.SetCurrentGameActivity( iPlayer, CONTEXT_PRESENCE_MULTIPLAYER, false); } } } } else { for (int iPlayer = 0; iPlayer < XUSER_MAX_COUNT; iPlayer++) { if ((iPlayer != i) && pMinecraft->localplayers[iPlayer]) { if (g_NetworkManager.IsLocalGame()) { ProfileManager.SetCurrentGameActivity( iPlayer, CONTEXT_PRESENCE_MULTIPLAYER_1POFFLINE, false); } else { ProfileManager.SetCurrentGameActivity( iPlayer, CONTEXT_PRESENCE_MULTIPLAYER_1P, false); } } } } SetAction(i, eAppAction_Idle); } break; case eAppAction_ExitPlayerPreLogin: { int iPlayerC = g_NetworkManager.GetPlayerCount(); // Since the player is exiting, let's flush any profile // writes for them, and hope we're not breaking TCR 136... ProfileManager.ForceQueuedProfileWrites(i); // if there are any tips showing, we need to close them pMinecraft->gui->clearMessages(i); // Make sure we've not got this player selected as current - // this shouldn't be the case anyway pMinecraft->setLocalPlayerIdx( ProfileManager.GetPrimaryPad()); pMinecraft->removeLocalPlayerIdx(i); // Wipe out the tooltips ui.SetTooltips(i, -1); // Change the presence info // Are we offline or online, and how many players are there if (iPlayerC > 2) // one player is about to leave here - they'll be // set to idle in the qnet manager player leave { for (int iPlayer = 0; iPlayer < XUSER_MAX_COUNT; iPlayer++) { if ((iPlayer != i) && pMinecraft->localplayers[iPlayer]) { if (g_NetworkManager.IsLocalGame()) { ProfileManager.SetCurrentGameActivity( iPlayer, CONTEXT_PRESENCE_MULTIPLAYEROFFLINE, false); } else { ProfileManager.SetCurrentGameActivity( iPlayer, CONTEXT_PRESENCE_MULTIPLAYER, false); } } } } else { for (int iPlayer = 0; iPlayer < XUSER_MAX_COUNT; iPlayer++) { if ((iPlayer != i) && pMinecraft->localplayers[iPlayer]) { if (g_NetworkManager.IsLocalGame()) { ProfileManager.SetCurrentGameActivity( iPlayer, CONTEXT_PRESENCE_MULTIPLAYER_1POFFLINE, false); } else { ProfileManager.SetCurrentGameActivity( iPlayer, CONTEXT_PRESENCE_MULTIPLAYER_1P, false); } } } } SetAction(i, eAppAction_Idle); } break; case eAppAction_ExitWorld: pMinecraft->exitingWorldRightNow = true; SetAction(i, eAppAction_Idle); // If we're already leaving don't exit if (g_NetworkManager.IsLeavingGame()) { break; } pMinecraft->gui->clearMessages(); // turn off the gamertags in splitscreen for the primary // player, since they are about to be made fullscreen ui.HideAllGameUIElements(); // reset the flag stopping new dlc message being shown if // you've seen the message before DisplayNewDLCTipAgain(); // clear the autosave timer that might be on screen ui.ShowAutosaveCountdownTimer(false); // Hide the selected item text ui.HideAllGameUIElements(); // Since the player forced the exit, let's flush any profile // writes, and hope we're not breaking TCR 136... // 4J-PB - cancel any possible std::string verifications // queued with LIVE // InputManager.CancelAllVerifyInProgress(); // In a split screen, only the primary player actually // quits the game, others just remove their players if (i != ProfileManager.GetPrimaryPad()) { // Make sure we've not got this player selected as // current - this shouldn't be the case anyway pMinecraft->setLocalPlayerIdx( ProfileManager.GetPrimaryPad()); pMinecraft->removeLocalPlayerIdx(i); SetAction(i, eAppAction_Idle); return; } // flag to capture the save thumbnail SetAction(i, eAppAction_ExitWorldCapturedThumbnail, param); // Change the presence info // Are we offline or online, and how many players are there if (g_NetworkManager.GetPlayerCount() > 1) { for (int j = 0; j < XUSER_MAX_COUNT; j++) { if (pMinecraft->localplayers[j]) { if (g_NetworkManager.IsLocalGame()) { app.SetRichPresenceContext( j, CONTEXT_GAME_STATE_BLANK); ProfileManager.SetCurrentGameActivity( j, CONTEXT_PRESENCE_MULTIPLAYEROFFLINE, false); } else { app.SetRichPresenceContext( j, CONTEXT_GAME_STATE_BLANK); ProfileManager.SetCurrentGameActivity( j, CONTEXT_PRESENCE_MULTIPLAYER, false); } } } } else { app.SetRichPresenceContext(i, CONTEXT_GAME_STATE_BLANK); if (g_NetworkManager.IsLocalGame()) { ProfileManager.SetCurrentGameActivity( i, CONTEXT_PRESENCE_MULTIPLAYER_1POFFLINE, false); } else { ProfileManager.SetCurrentGameActivity( i, CONTEXT_PRESENCE_MULTIPLAYER_1P, false); } } break; case eAppAction_ExitWorldCapturedThumbnail: { SetAction(i, eAppAction_Idle); // Stop app running SetGameStarted(false); SetChangingSessionType( true); // Added to stop handling ethernet disconnects ui.CloseAllPlayersScenes(); // turn off the gamertags in splitscreen for the primary // player, since they are about to be made fullscreen ui.HideAllGameUIElements(); // 4J Stu - Fix for #12368 - Crash: Game crashes when saving // then exiting and selecting to save for (unsigned int idx = 0; idx < XUSER_MAX_COUNT; ++idx) { // 4J Stu - Fix for #13257 - CRASH: Gameplay: Title // crashed after exiting the tutorial It doesn't matter // if they were in the tutorial already pMinecraft->playerLeftTutorial(idx); } LoadingInputParams* loadingParams = new LoadingInputParams(); loadingParams->func = &UIScene_PauseMenu::ExitWorldThreadProc; loadingParams->lpParam = param; UIFullscreenProgressCompletionData* completionData = new UIFullscreenProgressCompletionData(); // If param is non-null then this is a forced exit by the // server, so make sure the player knows why 4J Stu - // Changed - Don't use the FullScreenProgressScreen for // action, use a dialog instead completionData->bRequiresUserAction = false; //(param != nullptr) ? true : false; completionData->bShowTips = (param != nullptr) ? false : true; completionData->bShowBackground = true; completionData->bShowLogo = true; completionData->type = e_ProgressCompletion_NavigateToHomeMenu; completionData->iPad = DEFAULT_XUI_MENU_USER; loadingParams->completionData = completionData; ui.NavigateToScene(ProfileManager.GetPrimaryPad(), eUIScene_FullscreenProgress, loadingParams); } break; case eAppAction_ExitWorldTrial: { SetAction(i, eAppAction_Idle); pMinecraft->gui->clearMessages(); // turn off the gamertags in splitscreen for the primary // player, since they are about to be made fullscreen ui.HideAllGameUIElements(); // Stop app running SetGameStarted(false); ui.CloseAllPlayersScenes(); // 4J Stu - Fix for #12368 - Crash: Game crashes when saving // then exiting and selecting to save for (unsigned int idx = 0; idx < XUSER_MAX_COUNT; ++idx) { // 4J Stu - Fix for #13257 - CRASH: Gameplay: Title // crashed after exiting the tutorial It doesn't matter // if they were in the tutorial already pMinecraft->playerLeftTutorial(idx); } LoadingInputParams* loadingParams = new LoadingInputParams(); loadingParams->func = &UIScene_PauseMenu::ExitWorldThreadProc; loadingParams->lpParam = param; UIFullscreenProgressCompletionData* completionData = new UIFullscreenProgressCompletionData(); completionData->bShowBackground = true; completionData->bShowLogo = true; completionData->type = e_ProgressCompletion_NavigateToHomeMenu; completionData->iPad = DEFAULT_XUI_MENU_USER; loadingParams->completionData = completionData; ui.NavigateToScene(ProfileManager.GetPrimaryPad(), eUIScene_FullscreenProgress, loadingParams); } break; case eAppAction_ExitTrial: // XLaunchNewImage(XLAUNCH_KEYWORD_DASH_ARCADE, 0); ExitGame(); break; case eAppAction_Respawn: { ConnectionProgressParams* param = new ConnectionProgressParams(); param->iPad = i; param->stringId = IDS_PROGRESS_RESPAWNING; param->showTooltips = false; param->setFailTimer = false; ui.NavigateToScene(i, eUIScene_ConnectingProgress, param); // Need to reset this incase the player has already died and // respawned pMinecraft->localplayers[i]->SetPlayerRespawned(false); SetAction(i, eAppAction_WaitForRespawnComplete); if (app.GetLocalPlayerCount() > 1) { // In split screen mode, we don't want to do any async // loading or flushing of the cache, just a simple // respawn pMinecraft->localplayers[i]->respawn(); // If the respawn requires a dimension change then the // action will have changed // if(app.GetXuiAction(i) == eAppAction_Respawn) //{ // SetAction(i,eAppAction_Idle); // CloseXuiScenes(i); //} } else { // SetAction(i,eAppAction_WaitForRespawnComplete); // LoadingInputParams *loadingParams = new // LoadingInputParams(); loadingParams->func = // &CScene_Death::RespawnThreadProc; // loadingParams->lpParam = (void*)i; // Disable game & update thread whilst we do any of this // app.SetGameStarted(false); pMinecraft->gameRenderer->DisableUpdateThread(); // 4J Stu - We don't need this on a thread in // multiplayer as respawning is asynchronous. pMinecraft->localplayers[i]->respawn(); // app.SetGameStarted(true); pMinecraft->gameRenderer->EnableUpdateThread(); // UIFullscreenProgressCompletionData *completionData = // new UIFullscreenProgressCompletionData(); // completionData->bShowBackground=true; // completionData->bShowLogo=true; // completionData->type = // e_ProgressCompletion_CloseUIScenes; // completionData->iPad = i; // loadingParams->completionData = completionData; // app.NavigateToScene(i,eUIScene_FullscreenProgress, // loadingParams, true); } } break; case eAppAction_WaitForRespawnComplete: player = pMinecraft->localplayers[i]; if (player != nullptr && player->GetPlayerRespawned()) { SetAction(i, eAppAction_Idle); if (ui.IsSceneInStack(i, eUIScene_EndPoem)) { ui.NavigateBack(i, false, eUIScene_EndPoem); } else { ui.CloseUIScenes(i); } // clear the progress messages // pMinecraft->progressRenderer->progressStart(-1); // pMinecraft->progressRenderer->progressStage(-1); } else if (!g_NetworkManager.IsInGameplay()) { SetAction(i, eAppAction_Idle); } break; case eAppAction_WaitForDimensionChangeComplete: player = pMinecraft->localplayers[i]; if (player != nullptr && player->connection && player->connection->isStarted()) { SetAction(i, eAppAction_Idle); ui.CloseUIScenes(i); } else if (!g_NetworkManager.IsInGameplay()) { SetAction(i, eAppAction_Idle); } break; case eAppAction_PrimaryPlayerSignedOut: { // SetAction(i,eAppAction_Idle); // clear the autosavetimer that might be displayed ui.ShowAutosaveCountdownTimer(false); // If the player signs out before the game started the // server can be killed a bit earlier to stop the loading or // saving of a new game continuing running while the // UI/Guide is up if (!app.GetGameStarted()) MinecraftServer::HaltServer(true); // inform the player they are being returned to the menus // because they signed out StorageManager.SetSaveDeviceSelected(i, false); // need to clear the player stats - can't assume it'll be // done in setlevel - we may not be in the game StatsCounter* pStats = Minecraft::GetInstance()->stats[i]; pStats->clear(); // 4J-PB - the libs will display the Returned to Title // screen unsigned int // uiIDA[1]; uiIDA[0]=IDS_CONFIRM_OK; // // ui.RequestMessageBox(IDS_RETURNEDTOMENU_TITLE, // IDS_RETURNEDTOTITLESCREEN_TEXT, uiIDA, 1, // i,&Game::PrimaryPlayerSignedOutReturned,this,app.GetStringTable()); if (g_NetworkManager.IsInSession()) { app.SetAction( i, eAppAction_PrimaryPlayerSignedOutReturned); } else { app.SetAction( i, eAppAction_PrimaryPlayerSignedOutReturned_Menus); MinecraftServer::resetFlags(); } } break; case eAppAction_EthernetDisconnected: { app.DebugPrintf( "Handling eAppAction_EthernetDisconnected\n"); SetAction(i, eAppAction_Idle); // 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. if (!g_NetworkManager.IsLeavingGame()) { app.DebugPrintf( "Handling eAppAction_EthernetDisconnected - Not " "leaving game\n"); // 4J-PB - not the same as a signout. We should only // leave the game if this machine is not the host. We // shouldn't get rid of the save device either. if (g_NetworkManager.IsHost()) { app.DebugPrintf( "Handling eAppAction_EthernetDisconnected - Is " "Host\n"); // If it's already a local game, then an ethernet // disconnect should have no effect if (!g_NetworkManager.IsLocalGame() && g_NetworkManager.IsInGameplay()) { // Change the session to an offline session SetAction(i, eAppAction_ChangeSessionType); } else if (!g_NetworkManager.IsLocalGame() && !g_NetworkManager.IsInGameplay()) { // There are two cases here, either: // 1. We're early enough in the // create/load game that we can do a really // minimal shutdown or // 2. We're far enough in (game has started // but the actual game started flag hasn't // been set) that we should just wait until // we're in the game and switch to offline // mode // If there's a non-null level then, for our // purposes, the game has started bool gameStarted = false; for (int j = 0; j < pMinecraft->levels.size(); j++) { if (pMinecraft->levels.data()[j] != nullptr) { gameStarted = true; break; } } if (!gameStarted) { // 1. Exit MinecraftServer::HaltServer(); // 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. // 4J Stu - Leave the session g_NetworkManager.LeaveGame(false); // need to clear the player stats - can't // assume it'll be done in setlevel - we may // not be in the game StatsCounter* pStats = Minecraft::GetInstance()->stats[i]; pStats->clear(); unsigned int uiIDA[1]; uiIDA[0] = IDS_CONFIRM_OK; ui.RequestErrorMessage( g_NetworkManager.CorrectErrorIDS( IDS_CONNECTION_LOST), g_NetworkManager.CorrectErrorIDS( IDS_CONNECTION_LOST_LIVE), uiIDA, 1, i, &Game:: EthernetDisconnectReturned, this); } else { // 2. Switch to offline SetAction(i, eAppAction_ChangeSessionType); } } } else { { app.DebugPrintf( "Handling eAppAction_EthernetDisconnected " "- Not host\n"); // need to clear the player stats - can't assume // it'll be done in setlevel - we may not be in // the game StatsCounter* pStats = Minecraft::GetInstance()->stats[i]; pStats->clear(); unsigned int uiIDA[1]; uiIDA[0] = IDS_CONFIRM_OK; ui.RequestErrorMessage( g_NetworkManager.CorrectErrorIDS( IDS_CONNECTION_LOST), g_NetworkManager.CorrectErrorIDS( IDS_CONNECTION_LOST_LIVE), uiIDA, 1, i, &Game::EthernetDisconnectReturned, this); } } } } break; // We currently handle both these returns the same way. case eAppAction_EthernetDisconnectedReturned: case eAppAction_PrimaryPlayerSignedOutReturned: { SetAction(i, eAppAction_Idle); pMinecraft->gui->clearMessages(); // turn off the gamertags in splitscreen for the primary // player, since they are about to be made fullscreen ui.HideAllGameUIElements(); // set the state back to pre-game ProfileManager.ResetProfileProcessState(); if (g_NetworkManager.IsLeavingGame()) { // 4J Stu - If we are already leaving the game, then we // just need to signal that the player signed out to // stop saves pMinecraft->progressRenderer->progressStartNoAbort( IDS_EXITING_GAME); pMinecraft->progressRenderer->progressStage(-1); // This has no effect on client machines MinecraftServer::HaltServer(true); } else { // Stop app running SetGameStarted(false); // turn off the gamertags in splitscreen for the primary // player, since they are about to be made fullscreen ui.HideAllGameUIElements(); ui.CloseAllPlayersScenes(); // 4J Stu - Fix for #12368 - Crash: Game crashes when // saving then exiting and selecting to save for (unsigned int idx = 0; idx < XUSER_MAX_COUNT; ++idx) { // 4J Stu - Fix for #13257 - CRASH: Gameplay: Title // crashed after exiting the tutorial It doesn't // matter if they were in the tutorial already pMinecraft->playerLeftTutorial(idx); } LoadingInputParams* loadingParams = new LoadingInputParams(); loadingParams->func = &Game::SignoutExitWorldThreadProc; UIFullscreenProgressCompletionData* completionData = new UIFullscreenProgressCompletionData(); completionData->bShowBackground = true; completionData->bShowLogo = true; completionData->iPad = DEFAULT_XUI_MENU_USER; completionData->type = e_ProgressCompletion_NavigateToHomeMenu; loadingParams->completionData = completionData; ui.NavigateToScene(ProfileManager.GetPrimaryPad(), eUIScene_FullscreenProgress, loadingParams); } } break; case eAppAction_PrimaryPlayerSignedOutReturned_Menus: SetAction(i, eAppAction_Idle); // set the state back to pre-game ProfileManager.ResetProfileProcessState(); // clear the save device StorageManager.SetSaveDeviceSelected(i, false); ui.UpdatePlayerBasePositions(); // there are multiple layers in the help menu, so a navigate // back isn't enough ui.NavigateToHomeMenu(); break; case eAppAction_EthernetDisconnectedReturned_Menus: SetAction(i, eAppAction_Idle); // set the state back to pre-game ProfileManager.ResetProfileProcessState(); ui.UpdatePlayerBasePositions(); // there are multiple layers in the help menu, so a navigate // back isn't enough ui.NavigateToHomeMenu(); break; case eAppAction_TrialOver: { SetAction(i, eAppAction_Idle); unsigned int uiIDA[2]; uiIDA[0] = IDS_UNLOCK_TITLE; uiIDA[1] = IDS_EXIT_GAME; ui.RequestErrorMessage( IDS_TRIALOVER_TITLE, IDS_TRIALOVER_TEXT, uiIDA, 2, i, &Game::TrialOverReturned, this); } break; // INVITES case eAppAction_DashboardTrialJoinFromInvite: { SetAction(i, eAppAction_Idle); unsigned int uiIDA[2]; uiIDA[0] = IDS_CONFIRM_OK; uiIDA[1] = IDS_CONFIRM_CANCEL; ui.RequestErrorMessage( IDS_UNLOCK_TITLE, IDS_UNLOCK_ACCEPT_INVITE, uiIDA, 2, i, &Game::UnlockFullInviteReturned, this); } break; case eAppAction_ExitAndJoinFromInvite: { unsigned int uiIDA[3]; SetAction(i, eAppAction_Idle); // Check the player really wants to do this if (!StorageManager.GetSaveDisabled() && i == ProfileManager.GetPrimaryPad() && g_NetworkManager.IsHost() && GetGameStarted()) { uiIDA[0] = IDS_CONFIRM_CANCEL; uiIDA[1] = IDS_EXIT_GAME_SAVE; uiIDA[2] = IDS_EXIT_GAME_NO_SAVE; ui.RequestAlertMessage( IDS_EXIT_GAME, IDS_CONFIRM_LEAVE_VIA_INVITE, uiIDA, 3, i, &Game:: ExitAndJoinFromInviteSaveDialogReturned, this); } else { uiIDA[0] = IDS_CONFIRM_CANCEL; uiIDA[1] = IDS_CONFIRM_OK; ui.RequestAlertMessage( IDS_EXIT_GAME, IDS_CONFIRM_LEAVE_VIA_INVITE, uiIDA, 2, i, &Game::ExitAndJoinFromInvite, this); } } break; case eAppAction_ExitAndJoinFromInviteConfirmed: { SetAction(i, eAppAction_Idle); pMinecraft->gui->clearMessages(); // turn off the gamertags in splitscreen for the primary // player, since they are about to be made fullscreen ui.HideAllGameUIElements(); // Stop app running SetGameStarted(false); ui.CloseAllPlayersScenes(); // 4J Stu - Fix for #12368 - Crash: Game crashes when saving // then exiting and selecting to save for (unsigned int idx = 0; idx < XUSER_MAX_COUNT; ++idx) { // 4J Stu - Fix for #13257 - CRASH: Gameplay: Title // crashed after exiting the tutorial It doesn't matter // if they were in the tutorial already pMinecraft->playerLeftTutorial(idx); } // 4J-PB - may have been using a texture pack with audio , // so clean up anything texture pack related here // unload any texture pack audio // if there is audio in use, clear out the audio, and // unmount the pack TexturePack* pTexPack = Minecraft::GetInstance()->skins->getSelected(); DLCTexturePack* pDLCTexPack = nullptr; if (pTexPack->hasAudio()) { // get the dlc texture pack, and store it pDLCTexPack = (DLCTexturePack*)pTexPack; } // change to the default texture pack pMinecraft->skins->selectTexturePackById( TexturePackRepository::DEFAULT_TEXTURE_PACK_ID); if (pTexPack->hasAudio()) { // need to stop the streaming audio - by playing // streaming audio from the default texture pack now // reset the streaming sounds back to the normal ones pMinecraft->soundEngine->SetStreamingSounds( eStream_Overworld_Calm1, eStream_Overworld_piano3, eStream_Nether1, eStream_Nether4, eStream_end_dragon, eStream_end_end, eStream_CD_1); pMinecraft->soundEngine->playStreaming(L"", 0, 0, 0, 1, 1); const unsigned int result = StorageManager.UnmountInstalledDLC("TPACK"); app.DebugPrintf("Unmount result is %d\n", result); } LoadingInputParams* loadingParams = new LoadingInputParams(); loadingParams->func = &CGameNetworkManager::ExitAndJoinFromInviteThreadProc; loadingParams->lpParam = (void*)&m_InviteData; UIFullscreenProgressCompletionData* completionData = new UIFullscreenProgressCompletionData(); completionData->bShowBackground = true; completionData->bShowLogo = true; completionData->iPad = DEFAULT_XUI_MENU_USER; completionData->type = e_ProgressCompletion_NoAction; loadingParams->completionData = completionData; ui.NavigateToScene(ProfileManager.GetPrimaryPad(), eUIScene_FullscreenProgress, loadingParams); } break; case eAppAction_JoinFromInvite: { SetAction(i, eAppAction_Idle); // 4J Stu - Move this state block from // IPlatformNetwork::ExitAndJoinFromInviteThreadProc, // as g_NetworkManager.JoinGameFromInviteInfo ultimately can // call NavigateToScene, /// and we should only be calling that from the main thread app.SetTutorialMode(false); g_NetworkManager.SetLocalGame(false); JoinFromInviteData* inviteData = (JoinFromInviteData*)param; // 4J-PB - clear any previous connection errors Minecraft::GetInstance()->clearConnectionFailed(); app.DebugPrintf( "Changing Primary Pad on an invite accept - pad was " "%d, and is now %d\n", ProfileManager.GetPrimaryPad(), inviteData->dwUserIndex); ProfileManager.SetLockedProfile(inviteData->dwUserIndex); ProfileManager.SetPrimaryPad(inviteData->dwUserIndex); // change the minecraft player name Minecraft::GetInstance()->user->name = convStringToWstring(ProfileManager.GetGamertag( ProfileManager.GetPrimaryPad())); bool success = g_NetworkManager.JoinGameFromInviteInfo( inviteData->dwUserIndex, // dwUserIndex inviteData->dwLocalUsersMask, // dwUserMask inviteData->pInviteInfo); // pInviteInfo if (!success) { app.DebugPrintf("Failed joining game from invite\n"); // return hr; // 4J Stu - Copied this from XUI_FullScreenProgress to // properly handle the fail case, as the thread will no // longer be failing unsigned int uiIDA[1]; uiIDA[0] = IDS_CONFIRM_OK; ui.RequestErrorMessage( IDS_CONNECTION_FAILED, IDS_CONNECTION_LOST_SERVER, uiIDA, 1, ProfileManager.GetPrimaryPad()); ui.NavigateToHomeMenu(); ui.UpdatePlayerBasePositions(); } } break; case eAppAction_ChangeSessionType: { // If we are not in gameplay yet, then wait until the server // is setup before changing the session type if (g_NetworkManager.IsInGameplay()) { // This kicks off a thread that waits for the server to // end, then closes the current session, starts a new // one and joins the local players into it SetAction(i, eAppAction_Idle); if (!GetChangingSessionType() && !g_NetworkManager.IsLocalGame()) { SetGameStarted(false); SetChangingSessionType(true); SetReallyChangingSessionType(true); // turn off the gamertags in splitscreen for the // primary player, since they are about to be made // fullscreen ui.HideAllGameUIElements(); if (!ui.IsSceneInStack( ProfileManager.GetPrimaryPad(), eUIScene_EndPoem)) { ui.CloseAllPlayersScenes(); } ui.ShowOtherPlayersBaseScene( ProfileManager.GetPrimaryPad(), true); // Remove this line to fix: // #49084 - TU5: Code: Gameplay: The title crashes // every time client navigates to 'Play game' menu // and loads/creates new game after a "Connection to // Xbox LIVE was lost" message has appeared. // app.NavigateToScene(0,eUIScene_Main); LoadingInputParams* loadingParams = new LoadingInputParams(); loadingParams->func = &CGameNetworkManager:: ChangeSessionTypeThreadProc; loadingParams->lpParam = nullptr; UIFullscreenProgressCompletionData* completionData = new UIFullscreenProgressCompletionData(); completionData->bRequiresUserAction = true; completionData->bShowBackground = true; completionData->bShowLogo = true; completionData->iPad = DEFAULT_XUI_MENU_USER; if (ui.IsSceneInStack( ProfileManager.GetPrimaryPad(), eUIScene_EndPoem)) { completionData->type = e_ProgressCompletion_NavigateBackToScene; completionData->scene = eUIScene_EndPoem; } else { completionData->type = e_ProgressCompletion_CloseAllPlayersUIScenes; } loadingParams->completionData = completionData; ui.NavigateToScene(ProfileManager.GetPrimaryPad(), eUIScene_FullscreenProgress, loadingParams); } } else if (g_NetworkManager.IsLeavingGame()) { // If we are leaving the game, then ignore the state // change SetAction(i, eAppAction_Idle); } } break; case eAppAction_SetDefaultOptions: SetAction(i, eAppAction_Idle); SetDefaultOptions((C_4JProfile::PROFILESETTINGS*)param, i); // if the profile data has been changed, then force a // profile write It seems we're allowed to break the 5 // minute rule if it's the result of a user action CheckGameSettingsChanged(true, i); break; case eAppAction_RemoteServerSave: { // If the remote server save has already finished, don't // complete the action if (GetGameStarted()) { SetAction(ProfileManager.GetPrimaryPad(), eAppAction_Idle); break; } SetAction(i, eAppAction_WaitRemoteServerSaveComplete); for (unsigned int i = 0; i < XUSER_MAX_COUNT; ++i) { ui.CloseUIScenes(i, true); } // turn off the gamertags in splitscreen for the primary // player, since they are about to be made fullscreen ui.HideAllGameUIElements(); LoadingInputParams* loadingParams = new LoadingInputParams(); loadingParams->func = &Game::RemoteSaveThreadProc; loadingParams->lpParam = nullptr; UIFullscreenProgressCompletionData* completionData = new UIFullscreenProgressCompletionData(); completionData->bRequiresUserAction = false; completionData->bShowBackground = true; completionData->bShowLogo = true; completionData->iPad = DEFAULT_XUI_MENU_USER; if (ui.IsSceneInStack(ProfileManager.GetPrimaryPad(), eUIScene_EndPoem)) { completionData->type = e_ProgressCompletion_NavigateBackToScene; completionData->scene = eUIScene_EndPoem; } else { completionData->type = e_ProgressCompletion_CloseAllPlayersUIScenes; } loadingParams->completionData = completionData; loadingParams->cancelFunc = &Game::ExitGameFromRemoteSave; loadingParams->cancelText = IDS_TOOLTIPS_EXIT; ui.NavigateToScene(ProfileManager.GetPrimaryPad(), eUIScene_FullscreenProgress, loadingParams); } break; case eAppAction_WaitRemoteServerSaveComplete: // Do nothing break; case eAppAction_FailedToJoinNoPrivileges: { unsigned int uiIDA[1]; uiIDA[0] = IDS_CONFIRM_OK; C4JStorage::EMessageResult result = ui.RequestErrorMessage( IDS_NO_MULTIPLAYER_PRIVILEGE_TITLE, IDS_NO_MULTIPLAYER_PRIVILEGE_JOIN_TEXT, uiIDA, 1, ProfileManager.GetPrimaryPad()); if (result != C4JStorage::EMessage_Busy) SetAction(i, eAppAction_Idle); } break; case eAppAction_ProfileReadError: // Return player to the main menu - code largely copied from // that for handling eAppAction_PrimaryPlayerSignedOut, // although I don't think we should have got as far as // needing to halt the server, or running the game, before // returning to the menu if (!app.GetGameStarted()) MinecraftServer::HaltServer(true); if (g_NetworkManager.IsInSession()) { app.SetAction( i, eAppAction_PrimaryPlayerSignedOutReturned); } else { app.SetAction( i, eAppAction_PrimaryPlayerSignedOutReturned_Menus); MinecraftServer::resetFlags(); } break; case eAppAction_BanLevel: { // It's possible that this state can get set after the game // has been exited (e.g. by network disconnection) so we // can't ban the level at that point if (g_NetworkManager.IsInGameplay() && !g_NetworkManager.IsLeavingGame()) { // primary player would exit the world, secondary would // exit the player if (ProfileManager.GetPrimaryPad() == i) { SetAction(i, eAppAction_ExitWorld); } else { SetAction(i, eAppAction_ExitPlayer); } } } break; case eAppAction_LevelInBanLevelList: { unsigned int uiIDA[2]; uiIDA[0] = IDS_BUTTON_REMOVE_FROM_BAN_LIST; uiIDA[1] = IDS_EXIT_GAME; // pass in the gamertag format std::string wchar_t wchFormat[40]; INetworkPlayer* player = g_NetworkManager.GetLocalPlayerByUserIndex(i); // If not the primary player, but the primary player has // banned this level and decided not to unban then we may // have left the game by now if (player) { swprintf(wchFormat, 40, L"%ls\n\n%%ls", player->GetOnlineName()); C4JStorage::EMessageResult result = ui.RequestErrorMessage( IDS_BANNED_LEVEL_TITLE, IDS_PLAYER_BANNED_LEVEL, uiIDA, 2, i, &Game::BannedLevelDialogReturned, this, wchFormat); if (result != C4JStorage::EMessage_Busy) SetAction(i, eAppAction_Idle); } else { SetAction(i, eAppAction_Idle); } } break; case eAppAction_DebugText: // launch the xui for text entry { SetAction(i, eAppAction_Idle); } break; case eAppAction_ReloadTexturePack: { SetAction(i, eAppAction_Idle); Minecraft* pMinecraft = Minecraft::GetInstance(); pMinecraft->textures->reloadAll(); pMinecraft->skins->updateUI(); if (!pMinecraft->skins->isUsingDefaultSkin()) { TexturePack* pTexturePack = pMinecraft->skins->getSelected(); DLCPack* pDLCPack = pTexturePack->getDLCPack(); bool purchased = false; // do we have a license? if (pDLCPack && pDLCPack->hasPurchasedFile( DLCManager::e_DLCType_Texture, L"")) { purchased = true; } } // 4J-PB - If the texture pack has audio, we need to switch // to this if (pMinecraft->skins->getSelected()->hasAudio()) { Minecraft::GetInstance()->soundEngine->playStreaming( L"", 0, 0, 0, 1, 1); } } break; case eAppAction_ReloadFont: { app.DebugPrintf( "[Consoles_App] eAppAction_ReloadFont, ingame='%s'.\n", app.GetGameStarted() ? "Yes" : "No"); SetAction(i, eAppAction_Idle); ui.SetTooltips(i, -1); ui.ReloadSkin(); ui.StartReloadSkinThread(); ui.setCleanupOnReload(); } break; case eAppAction_TexturePackRequired: { unsigned int uiIDA[2]; uiIDA[0] = IDS_TEXTUREPACK_FULLVERSION; uiIDA[1] = IDS_TEXTURE_PACK_TRIALVERSION; // Give the player a warning about the texture pack missing ui.RequestErrorMessage( IDS_DLC_TEXTUREPACK_NOT_PRESENT_TITLE, IDS_DLC_TEXTUREPACK_NOT_PRESENT, uiIDA, 2, ProfileManager.GetPrimaryPad(), &Game::TexturePackDialogReturned, this); SetAction(i, eAppAction_Idle); } break; default: break; } } // Any TMS actions? eTMS = app.GetTMSAction(i); if (eTMS != eTMSAction_Idle) { switch (eTMS) { // TMS++ actions case eTMSAction_TMSPP_RetrieveFiles_CreateLoad_SignInReturned: case eTMSAction_TMSPP_RetrieveFiles_RunPlayGame: SetTMSAction(i, eTMSAction_TMSPP_UserFileList); break; case eTMSAction_TMSPP_UserFileList: // retrieve the file list first SetTMSAction(i, eTMSAction_TMSPP_XUIDSFile); break; case eTMSAction_TMSPP_XUIDSFile: SetTMSAction(i, eTMSAction_TMSPP_DLCFile); break; case eTMSAction_TMSPP_DLCFile: SetTMSAction(i, eTMSAction_TMSPP_BannedListFile); break; case eTMSAction_TMSPP_BannedListFile: // If we have one in TMSPP, then we can assume we can ignore // TMS SetTMSAction(i, eTMSAction_TMS_RetrieveFiles_Complete); break; // SPECIAL CASE - where the user goes directly in to Help & // Options from the main menu case eTMSAction_TMSPP_RetrieveFiles_HelpAndOptions: case eTMSAction_TMSPP_RetrieveFiles_DLCMain: // retrieve the file list first SetTMSAction(i, eTMSAction_TMSPP_DLCFileOnly); break; case eTMSAction_TMSPP_RetrieveUserFilelist_DLCFileOnly: SetTMSAction(i, eTMSAction_TMSPP_DLCFileOnly); break; case eTMSAction_TMSPP_DLCFileOnly: SetTMSAction(i, eTMSAction_TMSPP_RetrieveFiles_Complete); break; case eTMSAction_TMSPP_RetrieveFiles_Complete: SetTMSAction(i, eTMSAction_Idle); break; // TMS files /* case eTMSAction_TMS_RetrieveFiles_CreateLoad_SignInReturned: case eTMSAction_TMS_RetrieveFiles_RunPlayGame: #ifdef 0 SetTMSAction(i,eTMSAction_TMS_XUIDSFile_Waiting); // pass in the next app action on the call or callback completing app.ReadXuidsFileFromTMS(i,eTMSAction_TMS_DLCFile,true); #else SetTMSAction(i,eTMSAction_TMS_DLCFile); #endif break; case eTMSAction_TMS_DLCFile: SetTMSAction(i,eTMSAction_TMS_BannedListFile); break; case eTMSAction_TMS_RetrieveFiles_HelpAndOptions: case eTMSAction_TMS_RetrieveFiles_DLCMain: SetTMSAction(i,eTMSAction_Idle); break; case eTMSAction_TMS_BannedListFile: break; */ case eTMSAction_TMS_RetrieveFiles_Complete: SetTMSAction(i, eTMSAction_Idle); // if(StorageManager.SetSaveDevice(&CScene_Main::DeviceSelectReturned,pClass)) // { // // save device already // selected // // ensure we've applied // this player's settings // app.ApplyGameSettingsChanged(ProfileManager.GetPrimaryPad()); // app.NavigateToScene(ProfileManager.GetPrimaryPad(),eUIScene_MultiGameJoinLoad); // } break; default: break; } } } } int Game::BannedLevelDialogReturned( void* pParam, int iPad, const C4JStorage::EMessageResult result) { Game* pApp = (Game*)pParam; // Minecraft *pMinecraft=Minecraft::GetInstance(); if (result == C4JStorage::EMessage_ResultAccept) { } else { if (iPad == ProfileManager.GetPrimaryPad()) { pApp->SetAction(iPad, eAppAction_ExitWorld); } else { pApp->SetAction(iPad, eAppAction_ExitPlayer); } } return 0; } void Game::loadMediaArchive() { std::wstring mediapath = L""; #if _WINDOWS64 mediapath = L"Common\\Media\\MediaWindows64.arc"; #elif __linux__ mediapath = L"app/common/Media/MediaLinux.arc"; #endif if (!mediapath.empty()) { // boom headshot #if defined(__linux__) std::wstring exeDirW = PlatformFileIO.getBasePath().wstring(); std::wstring candidate = exeDirW + File::pathSeparator + mediapath; if (File(candidate).exists()) { m_mediaArchive = new ArchiveFile(File(candidate)); } else { m_mediaArchive = new ArchiveFile(File(mediapath)); } #else m_mediaArchive = new ArchiveFile(File(mediapath)); #endif } } void Game::loadStringTable() { if (m_stringTable != nullptr) { // we need to unload the current std::string table, this is a reload delete m_stringTable; } std::wstring localisationFile = L"languages.loc"; if (m_mediaArchive->hasFile(localisationFile)) { std::vector locFile = m_mediaArchive->getFile(localisationFile); m_stringTable = new StringTable(locFile.data(), locFile.size()); } else { m_stringTable = nullptr; assert(false); // AHHHHHHHHH. } } int Game::PrimaryPlayerSignedOutReturned( void* pParam, int iPad, const C4JStorage::EMessageResult) { // Game* pApp = (Game*)pParam; // Minecraft *pMinecraft=Minecraft::GetInstance(); // if the player is null, we're in the menus // if(Minecraft::GetInstance()->player!=nullptr) // We always create a session before kicking of any of the game code, so // even though we may still be joining/creating a game at this point we want // to handle it differently from just being in a menu if (g_NetworkManager.IsInSession()) { app.SetAction(iPad, eAppAction_PrimaryPlayerSignedOutReturned); } else { app.SetAction(iPad, eAppAction_PrimaryPlayerSignedOutReturned_Menus); } return 0; } int Game::EthernetDisconnectReturned( void* pParam, int iPad, const C4JStorage::EMessageResult) { // Game* pApp = (Game*)pParam; Minecraft* pMinecraft = Minecraft::GetInstance(); // if the player is null, we're in the menus if (Minecraft::GetInstance()->player != nullptr) { app.SetAction(pMinecraft->player->GetXboxPad(), eAppAction_EthernetDisconnectedReturned); } else { // 4J-PB - turn off the PSN store icon just in case this happened when // we were in one of the DLC menus app.SetAction(iPad, eAppAction_EthernetDisconnectedReturned_Menus); } return 0; } int Game::SignoutExitWorldThreadProc(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); Minecraft* pMinecraft = Minecraft::GetInstance(); int exitReasonStringId = -1; bool saveStats = false; if (pMinecraft->isClientSide() || g_NetworkManager.IsInSession()) { if (lpParameter != nullptr) { 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; break; case DisconnectPacket::eDisconnect_NoUGC_Single_Local: exitReasonStringId = IDS_NO_USER_CREATED_CONTENT_PRIVILEGE_SINGLE_LOCAL; break; case DisconnectPacket::eDisconnect_NoFlying: exitReasonStringId = IDS_DISCONNECTED_FLYING; break; case DisconnectPacket::eDisconnect_OutdatedServer: exitReasonStringId = IDS_DISCONNECTED_SERVER_OLD; break; case DisconnectPacket::eDisconnect_OutdatedClient: exitReasonStringId = IDS_DISCONNECTED_CLIENT_OLD; break; default: exitReasonStringId = IDS_DISCONNECTED; } pMinecraft->progressRenderer->progressStartNoAbort( exitReasonStringId); // 4J - Force a disconnection, this handles the situation that the // server has already disconnected if (pMinecraft->levels[0] != nullptr) pMinecraft->levels[0]->disconnect(false); if (pMinecraft->levels[1] != nullptr) pMinecraft->levels[1]->disconnect(false); } else { exitReasonStringId = IDS_EXITING_GAME; pMinecraft->progressRenderer->progressStartNoAbort( IDS_EXITING_GAME); if (pMinecraft->levels[0] != nullptr) pMinecraft->levels[0]->disconnect(); if (pMinecraft->levels[1] != nullptr) pMinecraft->levels[1]->disconnect(); } // 4J Stu - This only does something if we actually have a server, so // don't need to do any other checks MinecraftServer::HaltServer(true); // We need to call the stats & leaderboards save before we exit the // session // pMinecraft->forceStatsSave(); saveStats = false; // 4J Stu - Leave the session once the disconnect packet has been sent g_NetworkManager.LeaveGame(false); } else { if (lpParameter != nullptr) { 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; break; case DisconnectPacket::eDisconnect_NoUGC_Single_Local: exitReasonStringId = IDS_NO_USER_CREATED_CONTENT_PRIVILEGE_SINGLE_LOCAL; break; case DisconnectPacket::eDisconnect_OutdatedServer: exitReasonStringId = IDS_DISCONNECTED_SERVER_OLD; break; case DisconnectPacket::eDisconnect_OutdatedClient: exitReasonStringId = IDS_DISCONNECTED_CLIENT_OLD; default: exitReasonStringId = IDS_DISCONNECTED; } pMinecraft->progressRenderer->progressStartNoAbort( exitReasonStringId); } } pMinecraft->setLevel(nullptr, exitReasonStringId, nullptr, saveStats, true); // 4J-JEV: Fix for #106402 - TCR #014 BAS Debug Output: // TU12: Mass Effect Mash-UP: Save file "Default_DisplayName" is created on // all storage devices after signing out from a re-launched pre-generated // world app.m_gameRules.unloadCurrentGameRules(); // MinecraftServer::resetFlags(); // 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)); } return 0; } int Game::UnlockFullInviteReturned(void* pParam, int iPad, C4JStorage::EMessageResult result) { // Game* pApp = (Game*)pParam; Minecraft* pMinecraft = Minecraft::GetInstance(); bool bNoPlayer; // bug 11285 - TCR 001: BAS Game Stability: CRASH - When trying to join a // full version game with a trial version, the trial crashes 4J-PB - we may // be in the main menus here, and we don't have a pMinecraft->player if (pMinecraft->player == nullptr) { bNoPlayer = true; } return 0; } int Game::UnlockFullSaveReturned(void* pParam, int iPad, C4JStorage::EMessageResult result) { return 0; } int Game::UnlockFullExitReturned(void* pParam, int iPad, C4JStorage::EMessageResult result) { Game* pApp = (Game*)pParam; Minecraft* pMinecraft = Minecraft::GetInstance(); if (result != C4JStorage::EMessage_ResultAccept) { pApp->SetAction(pMinecraft->player->GetXboxPad(), eAppAction_ExitWorldTrial); } return 0; } int Game::TrialOverReturned(void* pParam, int iPad, C4JStorage::EMessageResult result) { Game* pApp = (Game*)pParam; Minecraft* pMinecraft = Minecraft::GetInstance(); if (result != C4JStorage::EMessage_ResultAccept) { pApp->SetAction(pMinecraft->player->GetXboxPad(), eAppAction_ExitTrial); } return 0; } void Game::ProfileReadErrorCallback(void* pParam) { Game* pApp = (Game*)pParam; int iPrimaryPlayer = ProfileManager.GetPrimaryPad(); pApp->SetAction(iPrimaryPlayer, eAppAction_ProfileReadError); } void Game::ClearSignInChangeUsersMask() { // 4J-PB - When in the main menu, the user is on pad 0, and any change they // make to their profile will be to pad 0 data If they then go in as a // secondary player to a splitscreen game, their profile will not be read // again on pad 1 if they were previously in a splitscreen game This is // because m_uiLastSignInData remembers they were in previously, and doesn't // read the profile data for them again Fix this by resetting the // m_uiLastSignInData on pressing play game for secondary users. The Primary // user does a read profile on play game anyway int iPrimaryPlayer = ProfileManager.GetPrimaryPad(); if (m_uiLastSignInData != 0) { if (iPrimaryPlayer >= 0) { m_uiLastSignInData = 1 << iPrimaryPlayer; } else { m_uiLastSignInData = 0; } } } void Game::SignInChangeCallback(void* pParam, bool bPrimaryPlayerChanged, unsigned int uiSignInData) { Game* pApp = (Game*)pParam; // check if the primary player signed out int iPrimaryPlayer = ProfileManager.GetPrimaryPad(); if ((ProfileManager.GetLockedProfile() != -1) && iPrimaryPlayer != -1) { if (((uiSignInData & (1 << iPrimaryPlayer)) == 0) || bPrimaryPlayerChanged) { // Primary Player gone or there's been a sign out and sign in of the // primary player, so kick them out pApp->SetAction(iPrimaryPlayer, eAppAction_PrimaryPlayerSignedOut); // 4J-PB - invalidate their banned level list pApp->InvalidateBannedList(iPrimaryPlayer); // need to ditch any DLCOffers info StorageManager.ClearDLCOffers(); pApp->ClearAndResetDLCDownloadQueue(); pApp->ClearDLCInstalled(); } else { unsigned int uiChangedPlayers = uiSignInData ^ m_uiLastSignInData; if (g_NetworkManager.IsInSession()) { bool hasGuestIdChanged = false; for (unsigned int i = 0; i < XUSER_MAX_COUNT; ++i) { unsigned int guestNumber = 0; if (ProfileManager.IsSignedIn(i)) { XUSER_SIGNIN_INFO info; XUserGetSigninInfo( i, XUSER_GET_SIGNIN_INFO_OFFLINE_XUID_ONLY, &info); pApp->DebugPrintf( "Player at index %d has guest number %d\n", i, info.dwGuestNumber); guestNumber = info.dwGuestNumber; } if (pApp->m_currentSigninInfo[i].dwGuestNumber != 0 && guestNumber != 0 && pApp->m_currentSigninInfo[i].dwGuestNumber != guestNumber) { hasGuestIdChanged = true; } } if (hasGuestIdChanged) { unsigned int uiIDA[1]; uiIDA[0] = IDS_CONFIRM_OK; ui.RequestErrorMessage(IDS_GUEST_ORDER_CHANGED_TITLE, IDS_GUEST_ORDER_CHANGED_TEXT, uiIDA, 1, ProfileManager.GetPrimaryPad()); } // 4J Stu - On PS4 we can also cause to exit players if they are // signed out here, but we shouldn't do that if we are going to // switch to an offline game as it will likely crash due to // incompatible parallel processes bool switchToOffline = false; // If it's an online game, and the primary profile is no longer // signed into LIVE then we act as if disconnected if (!ProfileManager.IsSignedInLive( ProfileManager.GetLockedProfile()) && !g_NetworkManager.IsLocalGame()) { switchToOffline = true; } // printf("Old: %x, New: %x, Changed: %x\n", m_ulLastSignInData, // ulSignInData, changedPlayers); for (unsigned int i = 0; i < XUSER_MAX_COUNT; ++i) { // Primary player shouldn't be subjected to these checks, // and shouldn't call ExitPlayer if (i == iPrimaryPlayer) continue; // A guest a signed in or out, out of order which // invalidates all the guest players we have in the game if (hasGuestIdChanged && pApp->m_currentSigninInfo[i].dwGuestNumber != 0 && g_NetworkManager.GetLocalPlayerByUserIndex(i) != nullptr) { pApp->DebugPrintf( "Recommending removal of player at index %d " "because their guest id changed\n", i); pApp->SetAction(i, eAppAction_ExitPlayer); } else { XUSER_SIGNIN_INFO info; XUserGetSigninInfo( i, XUSER_GET_SIGNIN_INFO_OFFLINE_XUID_ONLY, &info); // 4J Stu - Also need to detect the case where the sign // in mask is the same, but the player has swapped users // (eg still signed in but xuid different) Fix for // #48451 - TU5: Code: UI: Splitscreen: Title crashes // when switching to a profile previously signed out via // splitscreen profile selection // 4J-PB - compiler complained about if below ('&&' // within '||') - making it easier to read bool bPlayerChanged = (uiChangedPlayers & (1 << i)) == (1 << i); bool bPlayerSignedIn = ((uiSignInData & (1 << i)) != 0); if (bPlayerChanged && (!bPlayerSignedIn || (bPlayerSignedIn && !ProfileManager.AreXUIDSEqual( pApp->m_currentSigninInfo[i].xuid, info.xuid)))) { // 4J-PB - invalidate their banned level list pApp->DebugPrintf( "Player at index %d Left - invalidating their " "banned list\n", i); pApp->InvalidateBannedList(i); // 4J-HG: If either the player is in the network // manager or in the game, need to exit player // TODO: Do we need to check the network manager? if (g_NetworkManager.GetLocalPlayerByUserIndex(i) != nullptr || Minecraft::GetInstance()->localplayers[i] != nullptr) { pApp->DebugPrintf("Player %d signed out\n", i); pApp->SetAction(i, eAppAction_ExitPlayer); } } } } // If it's an online game, and the primary profile is no longer // signed into LIVE then we act as if disconnected if (switchToOffline) { pApp->SetAction(iPrimaryPlayer, eAppAction_EthernetDisconnected); } g_NetworkManager.HandleSignInChange(); } // Some menus require the player to be signed in to live, so if this // callback happens and the primary player is no longer signed in // then nav back else if (pApp->GetLiveLinkRequired() && !ProfileManager.IsSignedInLive( ProfileManager.GetLockedProfile())) { { pApp->SetAction(iPrimaryPlayer, eAppAction_EthernetDisconnected); } } } m_uiLastSignInData = uiSignInData; } else if (iPrimaryPlayer != -1) { // make sure the TMS banned list data is ditched - the player may have // gone in to help & options, backed out, and signed out pApp->InvalidateBannedList(iPrimaryPlayer); // need to ditch any DLCOffers info StorageManager.ClearDLCOffers(); pApp->ClearAndResetDLCDownloadQueue(); pApp->ClearDLCInstalled(); } // Update the guest numbers to the current state for (unsigned int i = 0; i < XUSER_MAX_COUNT; ++i) { if (FAILED(XUserGetSigninInfo(i, XUSER_GET_SIGNIN_INFO_OFFLINE_XUID_ONLY, &pApp->m_currentSigninInfo[i]))) { pApp->m_currentSigninInfo[i].xuid = INVALID_XUID; pApp->m_currentSigninInfo[i].dwGuestNumber = 0; } app.DebugPrintf("Player at index %d has guest number %d\n", i, pApp->m_currentSigninInfo[i].dwGuestNumber); } } void Game::NotificationsCallback(void* pParam, std::uint32_t dwNotification, unsigned int uiParam) { Game* pClass = (Game*)pParam; // push these on to the notifications to be handled in qnet's dowork PNOTIFICATION pNotification = new NOTIFICATION; pNotification->dwNotification = dwNotification; pNotification->uiParam = uiParam; switch (dwNotification) { case XN_SYS_SIGNINCHANGED: { pClass->DebugPrintf("Signing changed - %d\n", uiParam); } break; case XN_SYS_INPUTDEVICESCHANGED: if (app.GetGameStarted() && g_NetworkManager.IsInSession()) { for (unsigned int i = 0; i < XUSER_MAX_COUNT; ++i) { if (!InputManager.IsPadConnected(i) && Minecraft::GetInstance()->localplayers[i] != nullptr && !ui.IsPauseMenuDisplayed(i) && !ui.IsSceneInStack(i, eUIScene_EndPoem)) { ui.CloseUIScenes(i); ui.NavigateToScene(i, eUIScene_PauseMenu); } } } break; case XN_LIVE_CONTENT_INSTALLED: // Need to inform xuis that we've possibly had DLC installed { // app.m_dlcManager.SetNeedsUpdated(true); // Clear the DLC installed flag to cause a GetDLC to run if // it's called app.ClearDLCInstalled(); ui.HandleDLCInstalled(ProfileManager.GetPrimaryPad()); } break; case XN_SYS_STORAGEDEVICESCHANGED: { } break; } pClass->m_vNotifications.push_back(pNotification); } #if defined(_DEBUG_MENUS_ENABLED) bool Game::DebugArtToolsOn() { return DebugSettingsOn() && (GetGameSettingsDebugMask(ProfileManager.GetPrimaryPad()) & (1L << eDebugSetting_ArtTools)) != 0; } #endif void Game::SetDebugSequence(const char* pchSeq) { InputManager.SetDebugSequence(pchSeq, [this]() -> int { // printf("sequence matched\n"); m_bDebugOptions = !m_bDebugOptions; for (int i = 0; i < XUSER_MAX_COUNT; i++) { if (app.DebugSettingsOn()) { app.ActionDebugMask(i); } else { // force debug mask off app.ActionDebugMask(i, true); } } return 0; }); } int Game::GetLocalPlayerCount(void) { int iPlayerC = 0; Minecraft* pMinecraft = Minecraft::GetInstance(); for (int i = 0; i < XUSER_MAX_COUNT; i++) { if (pMinecraft != nullptr && pMinecraft->localplayers[i] != nullptr) { iPlayerC++; } } return iPlayerC; } int Game::MarketplaceCountsCallback( void* pParam, C4JStorage::DLC_TMS_DETAILS* pTMSDetails, int iPad) { app.DebugPrintf("Marketplace Counts= New - %d Total - %d\n", pTMSDetails->dwNewOffers, pTMSDetails->dwTotalOffers); if (pTMSDetails->dwNewOffers > 0) { app.m_bNewDLCAvailable = true; app.m_bSeenNewDLCTip = false; } else { app.m_bNewDLCAvailable = false; app.m_bSeenNewDLCTip = true; } return 0; } bool Game::StartInstallDLCProcess(int iPad) { app.DebugPrintf("--- Game::StartInstallDLCProcess: pad=%i.\n", iPad); // If there is already a call to this in progress, then do nothing // If the app says dlc is installed, then there has been no new system // message to tell us there's new DLC since the last call to // StartInstallDLCProcess if ((app.DLCInstallProcessCompleted() == false) && (m_bDLCInstallPending == false)) { app.m_dlcManager.resetUnnamedCorruptCount(); m_bDLCInstallPending = true; m_iTotalDLC = 0; m_iTotalDLCInstalled = 0; app.DebugPrintf( "--- Game::StartInstallDLCProcess - " "StorageManager.GetInstalledDLC\n"); StorageManager.GetInstalledDLC( iPad, [this](int iInstalledC, int pad) { return dlcInstalledCallback(iInstalledC, pad); }); return true; } else { app.DebugPrintf( "--- Game::StartInstallDLCProcess - nothing to do\n"); return false; } } // Installed DLC callback int Game::dlcInstalledCallback(int iInstalledC, int iPad) { DebugPrintf( "--- Game::dlcInstalledCallback: totalDLC=%i, pad=%i.\n", iInstalledC, iPad); m_iTotalDLC = iInstalledC; MountNextDLC(iPad); return 0; } void Game::MountNextDLC(int iPad) { app.DebugPrintf("--- Game::MountNextDLC: pad=%i.\n", iPad); if (m_iTotalDLCInstalled < m_iTotalDLC) { // Mount it // We also need to match the ones the user wants to mount with the // installed DLC We're supposed to use a generic save game as a cache of // these to do this, with XUSER_ANY if (StorageManager.MountInstalledDLC( iPad, m_iTotalDLCInstalled, [this](int pad, std::uint32_t dwErr, std::uint32_t dwLicenceMask) { return dlcMountedCallback(pad, dwErr, dwLicenceMask); }) != ERROR_IO_PENDING) { // corrupt DLC app.DebugPrintf("Failed to mount DLC %d for pad %d\n", m_iTotalDLCInstalled, iPad); ++m_iTotalDLCInstalled; app.MountNextDLC(iPad); } else { app.DebugPrintf("StorageManager.MountInstalledDLC ok\n"); } } else { /* Removed - now loading these on demand instead of as each pack is mounted if(m_iTotalDLCInstalled > 0) { Minecraft *pMinecraft=Minecraft::GetInstance(); pMinecraft->levelRenderer->AddDLCSkinsToMemTextures(); } */ m_bDLCInstallPending = false; m_bDLCInstallProcessCompleted = true; ui.HandleDLCMountingComplete(); } } // 4J-JEV: For the sake of clarity in DLCMountedCallback. #if defined(_WINDOWS64) #define CONTENT_DATA_DISPLAY_NAME(a) (a.szDisplayName) #else #define CONTENT_DATA_DISPLAY_NAME(a) (a.wszDisplayName) #endif int Game::dlcMountedCallback(int iPad, std::uint32_t dwErr, std::uint32_t dwLicenceMask) { #if defined(_WINDOWS64) DebugPrintf("--- Game::dlcMountedCallback\n"); if (dwErr != ERROR_SUCCESS) { // corrupt DLC app.DebugPrintf("Failed to mount DLC for pad %d: %u\n", iPad, dwErr); app.m_dlcManager.incrementUnnamedCorruptCount(); } else { XCONTENT_DATA ContentData = StorageManager.GetDLC(app.m_iTotalDLCInstalled); DLCPack* pack = app.m_dlcManager.getPack(CONTENT_DATA_DISPLAY_NAME(ContentData)); if (pack != nullptr && pack->IsCorrupt()) { app.DebugPrintf( "Pack '%ls' is corrupt, removing it from the DLC Manager.\n", CONTENT_DATA_DISPLAY_NAME(ContentData)); app.m_dlcManager.removePack(pack); pack = nullptr; } if (pack == nullptr) { app.DebugPrintf("Pack \"%ls\" is not installed, so adding it\n", CONTENT_DATA_DISPLAY_NAME(ContentData)); #if defined(_WINDOWS64) pack = new DLCPack(ContentData.szDisplayName, dwLicenceMask); #else pack = new DLCPack(ContentData.wszDisplayName, dwLicenceMask); #endif pack->SetDLCMountIndex(app.m_iTotalDLCInstalled); pack->SetDLCDeviceID(ContentData.DeviceID); app.m_dlcManager.addPack(pack); app.HandleDLC(pack); if (pack->getDLCItemsCount(DLCManager::e_DLCType_Texture) > 0) { Minecraft::GetInstance()->skins->addTexturePackFromDLC( pack, pack->GetPackId()); } } else { app.DebugPrintf( "Pack \"%ls\" is already installed. Updating license to %u\n", CONTENT_DATA_DISPLAY_NAME(ContentData), dwLicenceMask); pack->SetDLCMountIndex(app.m_iTotalDLCInstalled); pack->SetDLCDeviceID(ContentData.DeviceID); pack->updateLicenseMask(dwLicenceMask); } StorageManager.UnmountInstalledDLC(); } ++app.m_iTotalDLCInstalled; app.MountNextDLC(iPad); #endif return 0; } #undef CONTENT_DATA_DISPLAY_NAME // void Game::InstallDefaultCape() // { // if(!m_bDefaultCapeInstallAttempted) // { // // we only attempt to install the cape once per launch of the // game m_bDefaultCapeInstallAttempted=true; // // std::wstring wTemp=L"Default_Cape.png"; // bool bRes=app.IsFileInMemoryTextures(wTemp); // // if the file is not already in the memory textures, then read // it from TMS if(!bRes) // { // std::uint8_t *pBuffer=nullptr; // std::uint32_t dwSize=0; // // 4J-PB - out for now for DaveK so he doesn't get the // birthday cape #ifdef _CONTENT_PACKAGE // C4JStorage::ETMSStatus eTMSStatus; // eTMSStatus=StorageManager.ReadTMSFile(ProfileManager.GetPrimaryPad(),C4JStorage::eGlobalStorage_Title,C4JStorage::eTMS_FileType_Graphic, // L"Default_Cape.png",&pBuffer, &dwSize); // if(eTMSStatus==C4JStorage::ETMSStatus_Idle) // { // app.AddMemoryTextureFile(wTemp,pBuffer,dwSize); // } // #endif // } // } // } void Game::HandleDLC(DLCPack* pack) { unsigned int dwFilesProcessed = 0; #if defined(_WINDOWS64) || defined(__linux__) std::vector dlcFilenames; #endif StorageManager.GetMountedDLCFileList("DLCDrive", dlcFilenames); for (int i = 0; i < dlcFilenames.size(); i++) { m_dlcManager.readDLCDataFile(dwFilesProcessed, dlcFilenames[i], pack); } if (dwFilesProcessed == 0) m_dlcManager.removePack(pack); } // int Game::DLCReadCallback(void* // pParam,C4JStorage::DLC_FILE_DETAILS *pDLCData) // { // // // return 0; // } //------------------------------------------------------------------------------------- // Name: InitTime() // Desc: Initializes the timer variables //------------------------------------------------------------------------------------- void Game::InitTime() { // Save the start time m_Time.qwTime = time_util::clock::now(); // Zero out the elapsed and total time m_Time.qwAppTime = {}; m_Time.fAppTime = 0.0f; m_Time.fElapsedTime = 0.0f; } //------------------------------------------------------------------------------------- // Name: UpdateTime() // Desc: Updates the elapsed time since our last frame. //------------------------------------------------------------------------------------- void Game::UpdateTime() { auto qwNewTime = time_util::clock::now(); auto qwDeltaTime = qwNewTime - m_Time.qwTime; m_Time.qwAppTime += qwDeltaTime; m_Time.qwTime = qwNewTime; m_Time.fElapsedTime = std::chrono::duration(qwDeltaTime).count(); m_Time.fAppTime = std::chrono::duration(m_Time.qwAppTime).count(); } bool Game::isXuidNotch(PlayerUID xuid) { if (m_xuidNotch != INVALID_XUID && xuid != INVALID_XUID) { return ProfileManager.AreXUIDSEqual(xuid, m_xuidNotch); } return false; } bool Game::isXuidDeadmau5(PlayerUID xuid) { auto it = MojangData.find(xuid); // 4J Stu - The .at and [] accessors // insert elements if they don't exist if (it != MojangData.end()) { MOJANG_DATA* pMojangData = MojangData[xuid]; if (pMojangData && pMojangData->eXuid == eXUID_Deadmau5) { return true; } } return false; } void Game::AddMemoryTextureFile(const std::wstring& wName, std::uint8_t* pbData, unsigned int byteCount) { std::lock_guard lock(csMemFilesLock); // check it's not already in PMEMDATA pData = nullptr; auto it = m_MEM_Files.find(wName); if (it != m_MEM_Files.end()) { #if !defined(_CONTENT_PACKAGE) wprintf(L"Incrementing the memory texture file count for %ls\n", wName.c_str()); #endif pData = (*it).second; if (pData->byteCount == 0 && byteCount != 0) { // This should never be nullptr if dwBytes is 0 if (pData->pbData != nullptr) delete[] pData->pbData; pData->pbData = pbData; pData->byteCount = byteCount; } ++pData->ucRefCount; return; } // this is a texture (png) file // add this texture to the list of memory texture files - it will then be // picked up by the level renderer's AddEntity pData = new MEMDATA(); pData->pbData = pbData; pData->byteCount = byteCount; pData->ucRefCount = 1; // use the xuid to access the skin data m_MEM_Files[wName] = pData; } void Game::RemoveMemoryTextureFile(const std::wstring& wName) { std::lock_guard lock(csMemFilesLock); auto it = m_MEM_Files.find(wName); if (it != m_MEM_Files.end()) { #if !defined(_CONTENT_PACKAGE) wprintf(L"Decrementing the memory texture file count for %ls\n", wName.c_str()); #endif PMEMDATA pData = (*it).second; --pData->ucRefCount; if (pData->ucRefCount <= 0) { #if !defined(_CONTENT_PACKAGE) wprintf(L"Erasing the memory texture file data for %ls\n", wName.c_str()); #endif delete pData; m_MEM_Files.erase(wName); } } } bool Game::DefaultCapeExists() { std::wstring wTex = L"Special_Cape.png"; bool val = false; { std::lock_guard lock(csMemFilesLock); auto it = m_MEM_Files.find(wTex); if (it != m_MEM_Files.end()) val = true; } return val; } bool Game::IsFileInMemoryTextures(const std::wstring& wName) { bool val = false; { std::lock_guard lock(csMemFilesLock); auto it = m_MEM_Files.find(wName); if (it != m_MEM_Files.end()) val = true; } return val; } void Game::GetMemFileDetails(const std::wstring& wName, std::uint8_t** ppbData, unsigned int* pByteCount) { std::lock_guard lock(csMemFilesLock); auto it = m_MEM_Files.find(wName); if (it != m_MEM_Files.end()) { PMEMDATA pData = (*it).second; *ppbData = pData->pbData; *pByteCount = pData->byteCount; } } void Game::AddMemoryTPDFile(int iConfig, std::uint8_t* pbData, unsigned int byteCount) { std::lock_guard lock(csMemTPDLock); // check it's not already in PMEMDATA pData = nullptr; auto it = m_MEM_TPD.find(iConfig); if (it == m_MEM_TPD.end()) { pData = new MEMDATA(); pData->pbData = pbData; pData->byteCount = byteCount; pData->ucRefCount = 1; m_MEM_TPD[iConfig] = pData; } } void Game::RemoveMemoryTPDFile(int iConfig) { std::lock_guard lock(csMemTPDLock); // check it's not already in PMEMDATA pData = nullptr; auto it = m_MEM_TPD.find(iConfig); if (it != m_MEM_TPD.end()) { pData = m_MEM_TPD[iConfig]; delete pData; m_MEM_TPD.erase(iConfig); } } #if defined(_WINDOWS64) int Game::GetTPConfigVal(wchar_t* pwchDataFile) { return -1; } #endif bool Game::IsFileInTPD(int iConfig) { bool val = false; { std::lock_guard lock(csMemTPDLock); auto it = m_MEM_TPD.find(iConfig); if (it != m_MEM_TPD.end()) val = true; } return val; } void Game::GetTPD(int iConfig, std::uint8_t** ppbData, unsigned int* pByteCount) { std::lock_guard lock(csMemTPDLock); auto it = m_MEM_TPD.find(iConfig); if (it != m_MEM_TPD.end()) { PMEMDATA pData = (*it).second; *ppbData = pData->pbData; *pByteCount = pData->byteCount; } } // bool Game::UploadFileToGlobalStorage(int iQuadrant, // C4JStorage::eGlobalStorage eStorageFacility, std::wstring *wsFile ) // { // bool bRes=false; // #ifndef _CONTENT_PACKAGE // // read the local file // File gtsFile( wsFile->c_str() ); // // int64_t fileSize = gtsFile.length(); // // if(fileSize!=0) // { // FileInputStream fis(gtsFile); // std::vector ba((int)fileSize); // fis.read(ba); // fis.close(); // // bRes=StorageManager.WriteTMSFile(iQuadrant,eStorageFacility,(wchar_t // *)wsFile->c_str(),ba.data(), ba.size()); // // } // #endif // return bRes; // } void Game::StoreLaunchData() {} void Game::ExitGame() {} // Invites void Game::ProcessInvite(std::uint32_t dwUserIndex, std::uint32_t dwLocalUsersMask, const INVITE_INFO* pInviteInfo) { m_InviteData.dwUserIndex = dwUserIndex; m_InviteData.dwLocalUsersMask = dwLocalUsersMask; m_InviteData.pInviteInfo = pInviteInfo; // memcpy(&m_InviteData,pJoinData,sizeof(JoinFromInviteData)); SetAction(dwUserIndex, eAppAction_ExitAndJoinFromInvite); } int Game::ExitAndJoinFromInvite(void* pParam, int iPad, C4JStorage::EMessageResult result) { Game* pApp = (Game*)pParam; // Minecraft *pMinecraft=Minecraft::GetInstance(); // buttons are swapped on this menu if (result == C4JStorage::EMessage_ResultDecline) { pApp->SetAction(iPad, eAppAction_ExitAndJoinFromInviteConfirmed); } return 0; } int Game::ExitAndJoinFromInviteSaveDialogReturned( void* pParam, int iPad, C4JStorage::EMessageResult result) { Game* pClass = (Game*)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 { // Check they have the full texture pack if they are using one // 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(); DLCPack* pDLCPack = tPack->getDLCPack(); if (!pDLCPack->hasPurchasedFile(DLCManager::e_DLCType_Texture, L"")) { // upsell // get the dlc texture pack 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.RequestErrorMessage( IDS_WARNING_DLC_TRIALTEXTUREPACK_TITLE, IDS_WARNING_DLC_TRIALTEXTUREPACK_TEXT, uiIDA, 2, iPad, &Game::WarningTrialTexturePackReturned, pClass); return 0; } } // 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.RequestErrorMessage( IDS_TITLE_SAVE_GAME, IDS_CONFIRM_SAVE_GAME, uiIDA, 2, ProfileManager.GetPrimaryPad(), &Game::ExitAndJoinFromInviteAndSaveReturned, pClass); 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.RequestErrorMessage( IDS_TITLE_DECLINE_SAVE_GAME, IDS_CONFIRM_DECLINE_SAVE_GAME, uiIDA, 2, ProfileManager.GetPrimaryPad(), &Game::ExitAndJoinFromInviteDeclineSaveReturned, pClass); return 0; } app.SetAction(ProfileManager.GetPrimaryPad(), eAppAction_ExitAndJoinFromInviteConfirmed); } return 0; } int Game::WarningTrialTexturePackReturned( void* pParam, int iPad, C4JStorage::EMessageResult result) { // 4J Stu - I added this in when fixing an X1 bug. We should probably add // this as well but I don't have time to test all platforms atm return 0; } int Game::ExitAndJoinFromInviteAndSaveReturned( void* pParam, int iPad, C4JStorage::EMessageResult result) { // Game* pClass = (Game*)pParam; // results switched for this dialog if (result == C4JStorage::EMessage_ResultDecline) { int saveOrCheckpointId = 0; // Check they have the full texture pack if they are using one // 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(); DLCPack* pDLCPack = tPack->getDLCPack(); if (!pDLCPack->hasPurchasedFile(DLCManager::e_DLCType_Texture, L"")) { // upsell // get the dlc texture pack 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.RequestErrorMessage( IDS_WARNING_DLC_TRIALTEXTUREPACK_TITLE, IDS_WARNING_DLC_TRIALTEXTUREPACK_TEXT, uiIDA, 2, iPad, &Game::WarningTrialTexturePackReturned, nullptr); return 0; } } // bool validSave = // StorageManager.GetSaveUniqueNumber(&saveOrCheckpointId); // SentientManager.RecordLevelSaveOrCheckpoint(ProfileManager.GetPrimaryPad(), // saveOrCheckpointId); MinecraftServer::getInstance()->setSaveOnExit(true); // flag a app action of exit and join game from invite app.SetAction(iPad, eAppAction_ExitAndJoinFromInviteConfirmed); } return 0; } int Game::ExitAndJoinFromInviteDeclineSaveReturned( 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 and join game from invite app.SetAction(iPad, eAppAction_ExitAndJoinFromInviteConfirmed); } return 0; } ////////////////////////////////////////////////////////////////////////// // // FatalLoadError // // This is called when we can't load one of the required files at startup // It tends to mean the files have been corrupted. // We have to assume that we've not been able to load the text for the game. // ////////////////////////////////////////////////////////////////////////// void Game::FatalLoadError() {} TIPSTRUCT Game::m_GameTipA[MAX_TIPS_GAMETIP] = { {0, IDS_TIPS_GAMETIP_1}, {0, IDS_TIPS_GAMETIP_2}, {0, IDS_TIPS_GAMETIP_3}, {0, IDS_TIPS_GAMETIP_4}, {0, IDS_TIPS_GAMETIP_5}, {0, IDS_TIPS_GAMETIP_6}, {0, IDS_TIPS_GAMETIP_7}, {0, IDS_TIPS_GAMETIP_8}, {0, IDS_TIPS_GAMETIP_9}, {0, IDS_TIPS_GAMETIP_10}, {0, IDS_TIPS_GAMETIP_11}, {0, IDS_TIPS_GAMETIP_12}, {0, IDS_TIPS_GAMETIP_13}, {0, IDS_TIPS_GAMETIP_14}, {0, IDS_TIPS_GAMETIP_15}, {0, IDS_TIPS_GAMETIP_16}, {0, IDS_TIPS_GAMETIP_17}, {0, IDS_TIPS_GAMETIP_18}, {0, IDS_TIPS_GAMETIP_19}, {0, IDS_TIPS_GAMETIP_20}, {0, IDS_TIPS_GAMETIP_21}, {0, IDS_TIPS_GAMETIP_22}, {0, IDS_TIPS_GAMETIP_23}, {0, IDS_TIPS_GAMETIP_24}, {0, IDS_TIPS_GAMETIP_25}, {0, IDS_TIPS_GAMETIP_26}, {0, IDS_TIPS_GAMETIP_27}, {0, IDS_TIPS_GAMETIP_28}, {0, IDS_TIPS_GAMETIP_29}, {0, IDS_TIPS_GAMETIP_30}, {0, IDS_TIPS_GAMETIP_31}, {0, IDS_TIPS_GAMETIP_32}, {0, IDS_TIPS_GAMETIP_33}, {0, IDS_TIPS_GAMETIP_34}, {0, IDS_TIPS_GAMETIP_35}, {0, IDS_TIPS_GAMETIP_36}, {0, IDS_TIPS_GAMETIP_37}, {0, IDS_TIPS_GAMETIP_38}, {0, IDS_TIPS_GAMETIP_39}, {0, IDS_TIPS_GAMETIP_40}, {0, IDS_TIPS_GAMETIP_41}, {0, IDS_TIPS_GAMETIP_42}, {0, IDS_TIPS_GAMETIP_43}, {0, IDS_TIPS_GAMETIP_44}, {0, IDS_TIPS_GAMETIP_45}, {0, IDS_TIPS_GAMETIP_46}, {0, IDS_TIPS_GAMETIP_47}, {0, IDS_TIPS_GAMETIP_48}, {0, IDS_TIPS_GAMETIP_49}, {0, IDS_TIPS_GAMETIP_50}, }; TIPSTRUCT Game::m_TriviaTipA[MAX_TIPS_TRIVIATIP] = { {0, IDS_TIPS_TRIVIA_1}, {0, IDS_TIPS_TRIVIA_2}, {0, IDS_TIPS_TRIVIA_3}, {0, IDS_TIPS_TRIVIA_4}, {0, IDS_TIPS_TRIVIA_5}, {0, IDS_TIPS_TRIVIA_6}, {0, IDS_TIPS_TRIVIA_7}, {0, IDS_TIPS_TRIVIA_8}, {0, IDS_TIPS_TRIVIA_9}, {0, IDS_TIPS_TRIVIA_10}, {0, IDS_TIPS_TRIVIA_11}, {0, IDS_TIPS_TRIVIA_12}, {0, IDS_TIPS_TRIVIA_13}, {0, IDS_TIPS_TRIVIA_14}, {0, IDS_TIPS_TRIVIA_15}, {0, IDS_TIPS_TRIVIA_16}, {0, IDS_TIPS_TRIVIA_17}, {0, IDS_TIPS_TRIVIA_18}, {0, IDS_TIPS_TRIVIA_19}, {0, IDS_TIPS_TRIVIA_20}, }; Random* Game::TipRandom = new Random(); int Game::TipsSortFunction(const void* a, const void* b) { // 4jcraft, scince the sortvalues can be negative, i changed it // to a three way comparison, // scince subtracting of signed integers can cause overflow. int s1 = ((TIPSTRUCT*)a)->iSortValue; int s2 = ((TIPSTRUCT*)b)->iSortValue; if (s1 > s2) { return 1; } else if (s1 == s2) { return 0; } return -1; } void Game::InitialiseTips() { // We'll randomise the tips at start up based on their priority memset(m_TipIDA, 0, sizeof(m_TipIDA)); // Make the first tip tell you that you can play splitscreen in HD modes if // you are in SD if (!RenderManager.IsHiDef()) { m_GameTipA[0].uiStringID = IDS_TIPS_GAMETIP_0; } // randomise then quicksort // going to leave the multiplayer tip so it is always first // Only randomise the content package build #if defined(_CONTENT_PACKAGE) for (int i = 1; i < MAX_TIPS_GAMETIP; i++) { m_GameTipA[i].iSortValue = TipRandom->nextInt(); } qsort(&m_GameTipA[1], MAX_TIPS_GAMETIP - 1, sizeof(TIPSTRUCT), TipsSortFunction); #endif for (int i = 0; i < MAX_TIPS_TRIVIATIP; i++) { m_TriviaTipA[i].iSortValue = TipRandom->nextInt(); } qsort(m_TriviaTipA, MAX_TIPS_TRIVIATIP, sizeof(TIPSTRUCT), TipsSortFunction); int iCurrentGameTip = 0; int iCurrentTriviaTip = 0; for (int i = 0; i < MAX_TIPS_GAMETIP + MAX_TIPS_TRIVIATIP; i++) { // Add a trivia one every third tip (if there are any left) if ((i % 3 == 2) && (iCurrentTriviaTip < MAX_TIPS_TRIVIATIP)) { // Add a trivia one m_TipIDA[i] = m_TriviaTipA[iCurrentTriviaTip++].uiStringID; } else { if (iCurrentGameTip < MAX_TIPS_GAMETIP) { // Add a gametip m_TipIDA[i] = m_GameTipA[iCurrentGameTip++].uiStringID; } else { // Add a trivia one m_TipIDA[i] = m_TriviaTipA[iCurrentTriviaTip++].uiStringID; } } if (m_TipIDA[i] == 0) { // the m_TriviaTipA or the m_GameTipA are out of sync #if !defined(_CONTENT_PACKAGE) __debugbreak(); #endif } } m_uiCurrentTip = 0; } int Game::GetNextTip() { static bool bShowSkinDLCTip = true; if (app.GetNewDLCAvailable() && app.DisplayNewDLCTip()) { return IDS_TIPS_GAMETIP_NEWDLC; } else { if (bShowSkinDLCTip) { bShowSkinDLCTip = false; if (app.DLCInstallProcessCompleted()) { if (app.m_dlcManager.getPackCount(DLCManager::e_DLCType_Skin) == 0) { return IDS_TIPS_GAMETIP_SKINPACKS; } } else { return IDS_TIPS_GAMETIP_SKINPACKS; } } } if (m_uiCurrentTip == MAX_TIPS_GAMETIP + MAX_TIPS_TRIVIATIP) m_uiCurrentTip = 0; return m_TipIDA[m_uiCurrentTip++]; } int Game::GetHTMLColour(eMinecraftColour colour) { Minecraft* pMinecraft = Minecraft::GetInstance(); return pMinecraft->skins->getSelected()->getColourTable()->getColour( colour); } int Game::GetHTMLFontSize(EHTMLFontSize size) { return s_iHTMLFontSizesA[size]; } std::wstring Game::FormatHTMLString( int iPad, const std::wstring& desc, int shadowColour /*= 0xFFFFFFFF*/) { std::wstring text(desc); wchar_t replacements[64]; // We will also insert line breaks here as couldn't figure out how to get // them to come through from strings.resx ! text = replaceAll(text, L"{*B*}", L"
"); swprintf(replacements, 64, L"", GetHTMLColour(eHTMLColor_T1)); text = replaceAll(text, L"{*T1*}", replacements); swprintf(replacements, 64, L"", GetHTMLColour(eHTMLColor_T2)); text = replaceAll(text, L"{*T2*}", replacements); swprintf(replacements, 64, L"", GetHTMLColour(eHTMLColor_T3)); text = replaceAll(text, L"{*T3*}", replacements); // for How To Play swprintf(replacements, 64, L"", GetHTMLColour(eHTMLColor_Black)); text = replaceAll(text, L"{*ETB*}", replacements); swprintf(replacements, 64, L"", GetHTMLColour(eHTMLColor_White)); text = replaceAll(text, L"{*ETW*}", replacements); text = replaceAll(text, L"{*EF*}", L""); swprintf(replacements, 64, L"", GetHTMLColour(eHTMLColor_0), shadowColour); text = replaceAll(text, L"{*C0*}", replacements); swprintf(replacements, 64, L"", GetHTMLColour(eHTMLColor_1), shadowColour); text = replaceAll(text, L"{*C1*}", replacements); swprintf(replacements, 64, L"", GetHTMLColour(eHTMLColor_2), shadowColour); text = replaceAll(text, L"{*C2*}", replacements); swprintf(replacements, 64, L"", GetHTMLColour(eHTMLColor_3), shadowColour); text = replaceAll(text, L"{*C3*}", replacements); swprintf(replacements, 64, L"", GetHTMLColour(eHTMLColor_4), shadowColour); text = replaceAll(text, L"{*C4*}", replacements); swprintf(replacements, 64, L"", GetHTMLColour(eHTMLColor_5), shadowColour); text = replaceAll(text, L"{*C5*}", replacements); swprintf(replacements, 64, L"", GetHTMLColour(eHTMLColor_6), shadowColour); text = replaceAll(text, L"{*C6*}", replacements); swprintf(replacements, 64, L"", GetHTMLColour(eHTMLColor_7), shadowColour); text = replaceAll(text, L"{*C7*}", replacements); swprintf(replacements, 64, L"", GetHTMLColour(eHTMLColor_8), shadowColour); text = replaceAll(text, L"{*C8*}", replacements); swprintf(replacements, 64, L"", GetHTMLColour(eHTMLColor_9), shadowColour); text = replaceAll(text, L"{*C9*}", replacements); swprintf(replacements, 64, L"", GetHTMLColour(eHTMLColor_a), shadowColour); text = replaceAll(text, L"{*CA*}", replacements); swprintf(replacements, 64, L"", GetHTMLColour(eHTMLColor_b), shadowColour); text = replaceAll(text, L"{*CB*}", replacements); swprintf(replacements, 64, L"", GetHTMLColour(eHTMLColor_c), shadowColour); text = replaceAll(text, L"{*CC*}", replacements); swprintf(replacements, 64, L"", GetHTMLColour(eHTMLColor_d), shadowColour); text = replaceAll(text, L"{*CD*}", replacements); swprintf(replacements, 64, L"", GetHTMLColour(eHTMLColor_e), shadowColour); text = replaceAll(text, L"{*CE*}", replacements); swprintf(replacements, 64, L"", GetHTMLColour(eHTMLColor_f), shadowColour); text = replaceAll(text, L"{*CF*}", replacements); // Swap for southpaw. if (app.GetGameSettings(iPad, eGameSetting_ControlSouthPaw)) { text = replaceAll(text, L"{*CONTROLLER_ACTION_MOVE*}", GetActionReplacement(iPad, MINECRAFT_ACTION_LOOK_RIGHT)); text = replaceAll(text, L"{*CONTROLLER_ACTION_LOOK*}", GetActionReplacement(iPad, MINECRAFT_ACTION_RIGHT)); text = replaceAll(text, L"{*CONTROLLER_MENU_NAVIGATE*}", GetVKReplacement(VK_PAD_RTHUMB_LEFT)); } else // Normal right handed. { text = replaceAll(text, L"{*CONTROLLER_ACTION_MOVE*}", GetActionReplacement(iPad, MINECRAFT_ACTION_RIGHT)); text = replaceAll(text, L"{*CONTROLLER_ACTION_LOOK*}", GetActionReplacement(iPad, MINECRAFT_ACTION_LOOK_RIGHT)); text = replaceAll(text, L"{*CONTROLLER_MENU_NAVIGATE*}", GetVKReplacement(VK_PAD_LTHUMB_LEFT)); } text = replaceAll(text, L"{*CONTROLLER_ACTION_JUMP*}", GetActionReplacement(iPad, MINECRAFT_ACTION_JUMP)); text = replaceAll(text, L"{*CONTROLLER_ACTION_SNEAK*}", GetActionReplacement(iPad, MINECRAFT_ACTION_SNEAK_TOGGLE)); text = replaceAll(text, L"{*CONTROLLER_ACTION_USE*}", GetActionReplacement(iPad, MINECRAFT_ACTION_USE)); text = replaceAll(text, L"{*CONTROLLER_ACTION_ACTION*}", GetActionReplacement(iPad, MINECRAFT_ACTION_ACTION)); text = replaceAll(text, L"{*CONTROLLER_ACTION_LEFT_SCROLL*}", GetActionReplacement(iPad, MINECRAFT_ACTION_LEFT_SCROLL)); text = replaceAll(text, L"{*CONTROLLER_ACTION_RIGHT_SCROLL*}", GetActionReplacement(iPad, MINECRAFT_ACTION_RIGHT_SCROLL)); text = replaceAll(text, L"{*CONTROLLER_ACTION_INVENTORY*}", GetActionReplacement(iPad, MINECRAFT_ACTION_INVENTORY)); text = replaceAll(text, L"{*CONTROLLER_ACTION_CRAFTING*}", GetActionReplacement(iPad, MINECRAFT_ACTION_CRAFTING)); text = replaceAll(text, L"{*CONTROLLER_ACTION_DROP*}", GetActionReplacement(iPad, MINECRAFT_ACTION_DROP)); text = replaceAll( text, L"{*CONTROLLER_ACTION_CAMERA*}", GetActionReplacement(iPad, MINECRAFT_ACTION_RENDER_THIRD_PERSON)); text = replaceAll(text, L"{*CONTROLLER_ACTION_MENU_PAGEDOWN*}", GetActionReplacement(iPad, ACTION_MENU_PAGEDOWN)); text = replaceAll(text, L"{*CONTROLLER_ACTION_DISMOUNT*}", GetActionReplacement(iPad, MINECRAFT_ACTION_SNEAK_TOGGLE)); text = replaceAll(text, L"{*CONTROLLER_VK_A*}", GetVKReplacement(VK_PAD_A)); text = replaceAll(text, L"{*CONTROLLER_VK_B*}", GetVKReplacement(VK_PAD_B)); text = replaceAll(text, L"{*CONTROLLER_VK_X*}", GetVKReplacement(VK_PAD_X)); text = replaceAll(text, L"{*CONTROLLER_VK_Y*}", GetVKReplacement(VK_PAD_Y)); text = replaceAll(text, L"{*CONTROLLER_VK_LB*}", GetVKReplacement(VK_PAD_LSHOULDER)); text = replaceAll(text, L"{*CONTROLLER_VK_RB*}", GetVKReplacement(VK_PAD_RSHOULDER)); text = replaceAll(text, L"{*CONTROLLER_VK_LS*}", GetVKReplacement(VK_PAD_LTHUMB_UP)); text = replaceAll(text, L"{*CONTROLLER_VK_RS*}", GetVKReplacement(VK_PAD_RTHUMB_UP)); text = replaceAll(text, L"{*CONTROLLER_VK_LT*}", GetVKReplacement(VK_PAD_LTRIGGER)); text = replaceAll(text, L"{*CONTROLLER_VK_RT*}", GetVKReplacement(VK_PAD_RTRIGGER)); text = replaceAll(text, L"{*ICON_SHANK_01*}", GetIconReplacement(XZP_ICON_SHANK_01)); text = replaceAll(text, L"{*ICON_SHANK_03*}", GetIconReplacement(XZP_ICON_SHANK_03)); text = replaceAll(text, L"{*CONTROLLER_ACTION_DPAD_UP*}", GetActionReplacement(iPad, MINECRAFT_ACTION_DPAD_UP)); text = replaceAll(text, L"{*CONTROLLER_ACTION_DPAD_DOWN*}", GetActionReplacement(iPad, MINECRAFT_ACTION_DPAD_DOWN)); text = replaceAll(text, L"{*CONTROLLER_ACTION_DPAD_RIGHT*}", GetActionReplacement(iPad, MINECRAFT_ACTION_DPAD_RIGHT)); text = replaceAll(text, L"{*CONTROLLER_ACTION_DPAD_LEFT*}", GetActionReplacement(iPad, MINECRAFT_ACTION_DPAD_LEFT)); // Fix for #8903 - UI: Localization: KOR/JPN/CHT: Button Icons are rendered // with padding space, which looks no good std::uint32_t dwLanguage = XGetLanguage(); switch (dwLanguage) { case XC_LANGUAGE_KOREAN: case XC_LANGUAGE_JAPANESE: case XC_LANGUAGE_TCHINESE: text = replaceAll(text, L" ", L""); break; } return text; } std::wstring Game::GetActionReplacement(int iPad, unsigned char ucAction) { unsigned int input = InputManager.GetGameJoypadMaps( InputManager.GetJoypadMapVal(iPad), ucAction); std::wstring replacement = L""; // 4J Stu - Some of our actions can be mapped to multiple physical buttons, // so replaces the switch that was here if (input & _360_JOY_BUTTON_A) replacement = L"ButtonA"; else if (input & _360_JOY_BUTTON_B) replacement = L"ButtonB"; else if (input & _360_JOY_BUTTON_X) replacement = L"ButtonX"; else if (input & _360_JOY_BUTTON_Y) replacement = L"ButtonY"; else if ((input & _360_JOY_BUTTON_LSTICK_UP) || (input & _360_JOY_BUTTON_LSTICK_DOWN) || (input & _360_JOY_BUTTON_LSTICK_LEFT) || (input & _360_JOY_BUTTON_LSTICK_RIGHT)) { replacement = L"ButtonLeftStick"; } else if ((input & _360_JOY_BUTTON_RSTICK_LEFT) || (input & _360_JOY_BUTTON_RSTICK_RIGHT) || (input & _360_JOY_BUTTON_RSTICK_UP) || (input & _360_JOY_BUTTON_RSTICK_DOWN)) { replacement = L"ButtonRightStick"; } else if (input & _360_JOY_BUTTON_DPAD_LEFT) replacement = L"ButtonDpadL"; else if (input & _360_JOY_BUTTON_DPAD_RIGHT) replacement = L"ButtonDpadR"; else if (input & _360_JOY_BUTTON_DPAD_UP) replacement = L"ButtonDpadU"; else if (input & _360_JOY_BUTTON_DPAD_DOWN) replacement = L"ButtonDpadD"; else if (input & _360_JOY_BUTTON_LT) replacement = L"ButtonLeftTrigger"; else if (input & _360_JOY_BUTTON_RT) replacement = L"ButtonRightTrigger"; else if (input & _360_JOY_BUTTON_RB) replacement = L"ButtonRightBumper"; else if (input & _360_JOY_BUTTON_LB) replacement = L"ButtonLeftBumper"; else if (input & _360_JOY_BUTTON_BACK) replacement = L"ButtonBack"; else if (input & _360_JOY_BUTTON_START) replacement = L"ButtonStart"; else if (input & _360_JOY_BUTTON_RTHUMB) replacement = L"ButtonRS"; else if (input & _360_JOY_BUTTON_LTHUMB) replacement = L"ButtonLS"; wchar_t string[128]; #if defined(_WIN64) int size = 45; if (ui.getScreenWidth() < 1920) size = 30; #else int size = 45; #endif swprintf(string, 128, L"", replacement.c_str(), size, size); return string; } std::wstring Game::GetVKReplacement(unsigned int uiVKey) { std::wstring replacement = L""; switch (uiVKey) { case VK_PAD_A: replacement = L"ButtonA"; break; case VK_PAD_B: replacement = L"ButtonB"; break; case VK_PAD_X: replacement = L"ButtonX"; break; case VK_PAD_Y: replacement = L"ButtonY"; break; case VK_PAD_LSHOULDER: replacement = L"ButtonLeftBumper"; break; case VK_PAD_RSHOULDER: replacement = L"ButtonRightBumper"; break; case VK_PAD_LTRIGGER: replacement = L"ButtonLeftTrigger"; break; case VK_PAD_RTRIGGER: replacement = L"ButtonRightTrigger"; break; case VK_PAD_LTHUMB_UP: case VK_PAD_LTHUMB_DOWN: case VK_PAD_LTHUMB_RIGHT: case VK_PAD_LTHUMB_LEFT: case VK_PAD_LTHUMB_UPLEFT: case VK_PAD_LTHUMB_UPRIGHT: case VK_PAD_LTHUMB_DOWNRIGHT: case VK_PAD_LTHUMB_DOWNLEFT: replacement = L"ButtonLeftStick"; break; case VK_PAD_RTHUMB_UP: case VK_PAD_RTHUMB_DOWN: case VK_PAD_RTHUMB_RIGHT: case VK_PAD_RTHUMB_LEFT: case VK_PAD_RTHUMB_UPLEFT: case VK_PAD_RTHUMB_UPRIGHT: case VK_PAD_RTHUMB_DOWNRIGHT: case VK_PAD_RTHUMB_DOWNLEFT: replacement = L"ButtonRightStick"; break; default: break; } wchar_t string[128]; #if defined(_WIN64) int size = 45; if (ui.getScreenWidth() < 1920) size = 30; #else int size = 45; #endif swprintf(string, 128, L"", replacement.c_str(), size, size); return string; } std::wstring Game::GetIconReplacement(unsigned int uiIcon) { wchar_t string[128]; #if defined(_WIN64) int size = 33; if (ui.getScreenWidth() < 1920) size = 22; #else int size = 33; #endif swprintf(string, 128, L"", size, size); std::wstring result = L""; switch (uiIcon) { case XZP_ICON_SHANK_01: result = string; break; case XZP_ICON_SHANK_03: result.append(string).append(string).append(string); break; default: break; } return result; } std::unordered_map Game::MojangData; std::unordered_map Game::DLCTextures_PackID; std::unordered_map Game::DLCInfo_Trial; std::unordered_map Game::DLCInfo_Full; std::unordered_map Game::DLCInfo_SkinName; int32_t Game::RegisterMojangData(wchar_t* pXuidName, PlayerUID xuid, wchar_t* pSkin, wchar_t* pCape) { int32_t hr = 0; eXUID eTempXuid = eXUID_Undefined; MOJANG_DATA* pMojangData = nullptr; // ignore the names if we don't recognize them if (pXuidName != nullptr) { if (wcscmp(pXuidName, L"XUID_NOTCH") == 0) { eTempXuid = eXUID_Notch; // might be needed for the apple at some point } else if (wcscmp(pXuidName, L"XUID_DEADMAU5") == 0) { eTempXuid = eXUID_Deadmau5; // Needed for the deadmau5 ears } else { eTempXuid = eXUID_NoName; } } if (eTempXuid != eXUID_Undefined) { pMojangData = new MOJANG_DATA; memset(pMojangData, 0, sizeof(MOJANG_DATA)); pMojangData->eXuid = eTempXuid; wcsncpy(pMojangData->wchSkin, pSkin, MAX_CAPENAME_SIZE); wcsncpy(pMojangData->wchCape, pCape, MAX_CAPENAME_SIZE); MojangData[xuid] = pMojangData; } return hr; } MOJANG_DATA* Game::GetMojangDataForXuid(PlayerUID xuid) { return MojangData[xuid]; } int32_t Game::RegisterConfigValues(wchar_t* pType, int iValue) { int32_t hr = 0; // #ifdef 0 // if(pType!=nullptr) // { // if(wcscmp(pType,L"XboxOneTransfer")==0) // { // if(iValue>0) // { // app.m_bTransferSavesToXboxOne=true; // } // else // { // app.m_bTransferSavesToXboxOne=false; // } // } // else if(wcscmp(pType,L"TransferSlotCount")==0) // { // app.m_uiTransferSlotC=iValue; // } // // } // #endif return hr; } #if defined(_WINDOWS64) int32_t Game::RegisterDLCData(wchar_t* pType, wchar_t* pBannerName, int iGender, uint64_t ullOfferID_Full, uint64_t ullOfferID_Trial, wchar_t* pFirstSkin, unsigned int uiSortIndex, int iConfig, wchar_t* pDataFile) { int32_t hr = 0; DLC_INFO* pDLCData = new DLC_INFO; memset(pDLCData, 0, sizeof(DLC_INFO)); pDLCData->ullOfferID_Full = ullOfferID_Full; pDLCData->ullOfferID_Trial = ullOfferID_Trial; pDLCData->eDLCType = e_DLC_NotDefined; pDLCData->iGender = iGender; pDLCData->uiSortIndex = uiSortIndex; pDLCData->iConfig = iConfig; // ignore the names if we don't recognize them if (pBannerName != L"") { wcsncpy_s(pDLCData->wchBanner, pBannerName, MAX_BANNERNAME_SIZE); } if (pDataFile[0] != 0) { wcsncpy_s(pDLCData->wchDataFile, pDataFile, MAX_BANNERNAME_SIZE); } if (pType != nullptr) { if (wcscmp(pType, L"Skin") == 0) { pDLCData->eDLCType = e_DLC_SkinPack; } else if (wcscmp(pType, L"Gamerpic") == 0) { pDLCData->eDLCType = e_DLC_Gamerpics; } else if (wcscmp(pType, L"Theme") == 0) { pDLCData->eDLCType = e_DLC_Themes; } else if (wcscmp(pType, L"Avatar") == 0) { pDLCData->eDLCType = e_DLC_AvatarItems; } else if (wcscmp(pType, L"MashUpPack") == 0) { pDLCData->eDLCType = e_DLC_MashupPacks; DLCTextures_PackID[pDLCData->iConfig] = ullOfferID_Full; } else if (wcscmp(pType, L"TexturePack") == 0) { pDLCData->eDLCType = e_DLC_TexturePacks; DLCTextures_PackID[pDLCData->iConfig] = ullOfferID_Full; } } if (ullOfferID_Trial != 0ll) DLCInfo_Trial[ullOfferID_Trial] = pDLCData; if (ullOfferID_Full != 0ll) DLCInfo_Full[ullOfferID_Full] = pDLCData; if (pFirstSkin[0] != 0) DLCInfo_SkinName[pFirstSkin] = ullOfferID_Full; return hr; } #elif defined(__linux__) int32_t Game::RegisterDLCData(wchar_t* pType, wchar_t* pBannerName, int iGender, uint64_t ullOfferID_Full, uint64_t ullOfferID_Trial, wchar_t* pFirstSkin, unsigned int uiSortIndex, int iConfig, wchar_t* pDataFile) { fprintf(stderr, "warning: Game::RegisterDLCData unimplemented for " "platform `__linux__`\n"); return 0; } #else int32_t Game::RegisterDLCData(char* pchDLCName, unsigned int uiSortIndex, char* pchImageURL) { // on PS3 we get all the required info from the name char chDLCType[3]; int32_t hr = 0; DLC_INFO* pDLCData = new DLC_INFO; memset(pDLCData, 0, sizeof(DLC_INFO)); chDLCType[0] = pchDLCName[0]; chDLCType[1] = pchDLCName[1]; chDLCType[2] = 0; pDLCData->iConfig = app.GetiConfigFromName(pchDLCName); pDLCData->uiSortIndex = uiSortIndex; pDLCData->eDLCType = app.GetDLCTypeFromName(pchDLCName); strcpy(pDLCData->chImageURL, pchImageURL); // bool bIsTrialDLC = app.GetTrialFromName(pchDLCName); switch (pDLCData->eDLCType) { case e_DLC_TexturePacks: { char* pchName = (char*)malloc(strlen(pchDLCName) + 1); strcpy(pchName, pchDLCName); DLCTextures_PackID[pDLCData->iConfig] = pchName; } break; case e_DLC_MashupPacks: { char* pchName = (char*)malloc(strlen(pchDLCName) + 1); strcpy(pchName, pchDLCName); DLCTextures_PackID[pDLCData->iConfig] = pchName; } break; default: break; } app.DebugPrintf(5, "Adding DLC - %s\n", pchDLCName); DLCInfo[pchDLCName] = pDLCData; // if(ullOfferID_Trial!=0ll) DLCInfo_Trial[ullOfferID_Trial]=pDLCData; // if(ullOfferID_Full!=0ll) DLCInfo_Full[ullOfferID_Full]=pDLCData; // if(pFirstSkin[0]!=0) DLCInfo_SkinName[pFirstSkin]=ullOfferID_Full; // DLCInfo[ullOfferID_Trial]=pDLCData; return hr; } #endif bool Game::GetDLCFullOfferIDForSkinID(const std::wstring& FirstSkin, uint64_t* pullVal) { auto it = DLCInfo_SkinName.find(FirstSkin); if (it == DLCInfo_SkinName.end()) { return false; } else { *pullVal = (uint64_t)it->second; return true; } } bool Game::GetDLCFullOfferIDForPackID(const int iPackID, uint64_t* pullVal) { auto it = DLCTextures_PackID.find(iPackID); if (it == DLCTextures_PackID.end()) { *pullVal = (uint64_t)0; return false; } else { *pullVal = (uint64_t)it->second; return true; } } DLC_INFO* Game::GetDLCInfoForTrialOfferID(uint64_t ullOfferID_Trial) { // DLC_INFO *pDLCInfo=NULL; if (DLCInfo_Trial.size() > 0) { auto it = DLCInfo_Trial.find(ullOfferID_Trial); if (it == DLCInfo_Trial.end()) { // nothing for this return nullptr; } else { return it->second; } } else return nullptr; } DLC_INFO* Game::GetDLCInfoTrialOffer(int iIndex) { std::unordered_map::iterator it = DLCInfo_Trial.begin(); for (int i = 0; i < iIndex; i++) { ++it; } return it->second; } DLC_INFO* Game::GetDLCInfoFullOffer(int iIndex) { std::unordered_map::iterator it = DLCInfo_Full.begin(); for (int i = 0; i < iIndex; i++) { ++it; } return it->second; } uint64_t Game::GetDLCInfoTexturesFullOffer(int iIndex) { std::unordered_map::iterator it = DLCTextures_PackID.begin(); for (int i = 0; i < iIndex; i++) { ++it; } return it->second; } DLC_INFO* Game::GetDLCInfoForFullOfferID(uint64_t ullOfferID_Full) { if (DLCInfo_Full.size() > 0) { auto it = DLCInfo_Full.find(ullOfferID_Full); if (it == DLCInfo_Full.end()) { // nothing for this return nullptr; } else { return it->second; } } else return nullptr; } void Game::lockSaveNotification() { std::lock_guard lock(m_saveNotificationMutex); if (m_saveNotificationDepth++ == 0) { if (g_NetworkManager .IsInSession()) // this can be triggered from the front end if // we're downloading a save { MinecraftServer::getInstance()->broadcastStartSavingPacket(); if (g_NetworkManager.IsLocalGame() && g_NetworkManager.GetPlayerCount() == 1) { app.SetXuiServerAction(ProfileManager.GetPrimaryPad(), eXuiServerAction_PauseServer, (void*)true); } } } } void Game::unlockSaveNotification() { std::lock_guard lock(m_saveNotificationMutex); if (--m_saveNotificationDepth == 0) { if (g_NetworkManager .IsInSession()) // this can be triggered from the front end if // we're downloading a save { MinecraftServer::getInstance()->broadcastStopSavingPacket(); if (g_NetworkManager.IsLocalGame() && g_NetworkManager.GetPlayerCount() == 1) { app.SetXuiServerAction(ProfileManager.GetPrimaryPad(), eXuiServerAction_PauseServer, (void*)false); } } } } int Game::RemoteSaveThreadProc(void* lpParameter) { // The game should be stopped while we are doing this, but the connections // ticks may try to create some AABB's or Vec3's Compression::UseDefaultThreadStorage(); // 4J-PB - Xbox 360 - 163153 - [CRASH] TU17: Code: Multiplayer: During the // Autosave in an online Multiplayer session, the game occasionally crashes // for one or more Clients callstack - > if(tls->tileId != this->id) // updateDefaultShape(); callstack - > // default.exe!WaterlilyTile::getAABB(Level * level, int x, int y, int z) // line 38 + 8 bytes C++ // ... // default.exe!Game::RemoteSaveThreadProc(void * // lpParameter) line 6694 C++ // host autosave, and the clients can crash on receiving handleMoveEntity // when it's a tile within this thread, so need to do the tls for tiles Tile::CreateNewThreadStorage(); Minecraft* pMinecraft = Minecraft::GetInstance(); pMinecraft->progressRenderer->progressStartNoAbort( IDS_PROGRESS_HOST_SAVING); pMinecraft->progressRenderer->progressStage(-1); pMinecraft->progressRenderer->progressStagePercentage(0); while (!app.GetGameStarted() && app.GetXuiAction(ProfileManager.GetPrimaryPad()) == eAppAction_WaitRemoteServerSaveComplete) { // Tick all the games connections pMinecraft->tickAllConnections(); std::this_thread::sleep_for(std::chrono::milliseconds(100)); } if (app.GetXuiAction(ProfileManager.GetPrimaryPad()) != eAppAction_WaitRemoteServerSaveComplete) { // Something cancelled us? return ERROR_CANCELLED; } app.SetAction(ProfileManager.GetPrimaryPad(), eAppAction_Idle); ui.UpdatePlayerBasePositions(); Tile::ReleaseThreadStorage(); return 0; } void Game::ExitGameFromRemoteSave(void* lpParameter) { int primaryPad = ProfileManager.GetPrimaryPad(); unsigned int uiIDA[3]; uiIDA[0] = IDS_CONFIRM_CANCEL; uiIDA[1] = IDS_CONFIRM_OK; ui.RequestAlertMessage( IDS_EXIT_GAME, IDS_CONFIRM_EXIT_GAME, uiIDA, 2, primaryPad, &Game::ExitGameFromRemoteSaveDialogReturned, nullptr); } int Game::ExitGameFromRemoteSaveDialogReturned( void* pParam, int iPad, C4JStorage::EMessageResult result) { // CScene_Pause* pClass = (CScene_Pause*)pParam; // results switched for this dialog if (result == C4JStorage::EMessage_ResultDecline) { app.SetAction(iPad, eAppAction_ExitWorld); } else { // Inform fullscreen progress scene that it's not being cancelled after // all UIScene_FullscreenProgress* pScene = (UIScene_FullscreenProgress*)ui.FindScene( eUIScene_FullscreenProgress); if (pScene != nullptr) { pScene->SetWasCancelled(false); } } return 0; } void Game::SetSpecialTutorialCompletionFlag(int iPad, int index) { if (index >= 0 && index < 32 && GameSettingsA[iPad] != nullptr) { GameSettingsA[iPad]->uiSpecialTutorialBitmask |= (1 << index); } } // BANNED LIST FUNCTIONS void Game::SetUniqueMapName(char* pszUniqueMapName) { memcpy(m_pszUniqueMapName, pszUniqueMapName, 14); } char* Game::GetUniqueMapName(void) { return m_pszUniqueMapName; } void Game::InvalidateBannedList(int iPad) { if (m_bRead_BannedListA[iPad] == true) { m_bRead_BannedListA[iPad] = false; SetBanListCheck(iPad, false); m_vBannedListA[iPad]->clear(); if (BannedListA[iPad].pBannedList) { delete[] BannedListA[iPad].pBannedList; BannedListA[iPad].pBannedList = nullptr; } } } void Game::AddLevelToBannedLevelList(int iPad, PlayerUID xuid, char* pszLevelName, bool bWriteToTMS) { // we will have retrieved the banned level list from TMS, so add this one to // it and write it back to TMS BANNEDLISTDATA* pBannedListData = new BANNEDLISTDATA; memset(pBannedListData, 0, sizeof(BANNEDLISTDATA)); memcpy(&pBannedListData->xuid, &xuid, sizeof(PlayerUID)); strcpy(pBannedListData->pszLevelName, pszLevelName); m_vBannedListA[iPad]->push_back(pBannedListData); if (bWriteToTMS) { const std::size_t bannedListCount = m_vBannedListA[iPad]->size(); const unsigned int dataBytes = static_cast(sizeof(BANNEDLISTDATA) * bannedListCount); PBANNEDLISTDATA pBannedList = new BANNEDLISTDATA[bannedListCount]; int iCount = 0; for (auto it = m_vBannedListA[iPad]->begin(); it != m_vBannedListA[iPad]->end(); ++it) { PBANNEDLISTDATA pData = *it; memcpy(&pBannedList[iCount++], pData, sizeof(BANNEDLISTDATA)); } // 4J-PB - write to TMS++ now // bool // bRes=StorageManager.WriteTMSFile(iPad,C4JStorage::eGlobalStorage_TitleUser,L"BannedList",(std::uint8_t*)pBannedList, // dwDataBytes); delete[] pBannedList; } // update telemetry too } bool Game::IsInBannedLevelList(int iPad, PlayerUID xuid, char* pszLevelName) { for (auto it = m_vBannedListA[iPad]->begin(); it != m_vBannedListA[iPad]->end(); ++it) { PBANNEDLISTDATA pData = *it; if (IsEqualXUID(pData->xuid, xuid) && (strcmp(pData->pszLevelName, pszLevelName) == 0)) { return true; } } return false; } void Game::RemoveLevelFromBannedLevelList(int iPad, PlayerUID xuid, char* pszLevelName) { // bool bFound=false; // bool bRes; // we will have retrieved the banned level list from TMS, so remove this one // from it and write it back to TMS for (auto it = m_vBannedListA[iPad]->begin(); it != m_vBannedListA[iPad]->end();) { PBANNEDLISTDATA pBannedListData = *it; if (pBannedListData != nullptr) { if (IsEqualXUID(pBannedListData->xuid, xuid) && (strcmp(pBannedListData->pszLevelName, pszLevelName) == 0)) { // match found, so remove this entry it = m_vBannedListA[iPad]->erase(it); } else { ++it; } } else { ++it; } } const std::size_t bannedListCount = m_vBannedListA[iPad]->size(); const unsigned int dataBytes = static_cast(sizeof(BANNEDLISTDATA) * bannedListCount); if (dataBytes == 0) { // wipe the file } else { PBANNEDLISTDATA pBannedList = (BANNEDLISTDATA*)(new std::uint8_t[dataBytes]); for (std::size_t i = 0; i < bannedListCount; ++i) { PBANNEDLISTDATA pBannedListData = m_vBannedListA[iPad]->at(i); memcpy(&pBannedList[i], pBannedListData, sizeof(BANNEDLISTDATA)); } delete[] pBannedList; } // update telemetry too } // function to add credits for the DLC packs void Game::AddCreditText(const wchar_t* lpStr) { DebugPrintf("ADDING CREDIT - %ls\n", lpStr); // add a std::string from the DLC to a credits std::vector SCreditTextItemDef* pCreditStruct = new SCreditTextItemDef; pCreditStruct->m_eType = eSmallText; pCreditStruct->m_iStringID[0] = NO_TRANSLATED_STRING; pCreditStruct->m_iStringID[1] = NO_TRANSLATED_STRING; pCreditStruct->m_Text = new wchar_t[wcslen(lpStr) + 1]; wcscpy((wchar_t*)pCreditStruct->m_Text, lpStr); vDLCCredits.push_back(pCreditStruct); } bool Game::AlreadySeenCreditText(const std::wstring& wstemp) { for (unsigned int i = 0; i < m_vCreditText.size(); i++) { std::wstring temp = m_vCreditText.at(i); // if they are the same, break out of the case if (temp.compare(wstemp) == 0) { return true; } } // add this text m_vCreditText.push_back((wchar_t*)wstemp.c_str()); return false; } unsigned int Game::GetDLCCreditsCount() { return (unsigned int)vDLCCredits.size(); } SCreditTextItemDef* Game::GetDLCCredits(int iIndex) { return vDLCCredits.at(iIndex); } // Game Host options void Game::SetGameHostOption(eGameHostOption eVal, unsigned int uiVal) { SetGameHostOption(m_uiGameHostSettings, eVal, uiVal); } void Game::SetGameHostOption(unsigned int& uiHostSettings, eGameHostOption eVal, unsigned int uiVal) { switch (eVal) { case eGameHostOption_FriendsOfFriends: if (uiVal != 0) { uiHostSettings |= GAME_HOST_OPTION_BITMASK_FRIENDSOFFRIENDS; } else { // off uiHostSettings &= ~GAME_HOST_OPTION_BITMASK_FRIENDSOFFRIENDS; } break; case eGameHostOption_Difficulty: // clear the difficulty first uiHostSettings &= ~GAME_HOST_OPTION_BITMASK_DIFFICULTY; uiHostSettings |= (GAME_HOST_OPTION_BITMASK_DIFFICULTY & uiVal); break; case eGameHostOption_Gamertags: if (uiVal != 0) { uiHostSettings |= GAME_HOST_OPTION_BITMASK_GAMERTAGS; } else { // off uiHostSettings &= ~GAME_HOST_OPTION_BITMASK_GAMERTAGS; } break; case eGameHostOption_GameType: // clear the game type first uiHostSettings &= ~GAME_HOST_OPTION_BITMASK_GAMETYPE; uiHostSettings |= (GAME_HOST_OPTION_BITMASK_GAMETYPE & (uiVal << 4)); break; case eGameHostOption_LevelType: if (uiVal != 0) { uiHostSettings |= GAME_HOST_OPTION_BITMASK_LEVELTYPE; } else { // off uiHostSettings &= ~GAME_HOST_OPTION_BITMASK_LEVELTYPE; } break; case eGameHostOption_Structures: if (uiVal != 0) { uiHostSettings |= GAME_HOST_OPTION_BITMASK_STRUCTURES; } else { // off uiHostSettings &= ~GAME_HOST_OPTION_BITMASK_STRUCTURES; } break; case eGameHostOption_BonusChest: if (uiVal != 0) { uiHostSettings |= GAME_HOST_OPTION_BITMASK_BONUSCHEST; } else { // off uiHostSettings &= ~GAME_HOST_OPTION_BITMASK_BONUSCHEST; } break; case eGameHostOption_HasBeenInCreative: if (uiVal != 0) { uiHostSettings |= GAME_HOST_OPTION_BITMASK_BEENINCREATIVE; } else { // off uiHostSettings &= ~GAME_HOST_OPTION_BITMASK_BEENINCREATIVE; } break; case eGameHostOption_PvP: if (uiVal != 0) { uiHostSettings |= GAME_HOST_OPTION_BITMASK_PVP; } else { // off uiHostSettings &= ~GAME_HOST_OPTION_BITMASK_PVP; } break; case eGameHostOption_TrustPlayers: if (uiVal != 0) { uiHostSettings |= GAME_HOST_OPTION_BITMASK_TRUSTPLAYERS; } else { // off uiHostSettings &= ~GAME_HOST_OPTION_BITMASK_TRUSTPLAYERS; } break; case eGameHostOption_TNT: if (uiVal != 0) { uiHostSettings |= GAME_HOST_OPTION_BITMASK_TNT; } else { // off uiHostSettings &= ~GAME_HOST_OPTION_BITMASK_TNT; } break; case eGameHostOption_FireSpreads: if (uiVal != 0) { uiHostSettings |= GAME_HOST_OPTION_BITMASK_FIRESPREADS; } else { // off uiHostSettings &= ~GAME_HOST_OPTION_BITMASK_FIRESPREADS; } break; case eGameHostOption_CheatsEnabled: if (uiVal != 0) { uiHostSettings |= GAME_HOST_OPTION_BITMASK_HOSTFLY; uiHostSettings |= GAME_HOST_OPTION_BITMASK_HOSTHUNGER; uiHostSettings |= GAME_HOST_OPTION_BITMASK_HOSTINVISIBLE; } else { // off uiHostSettings &= ~GAME_HOST_OPTION_BITMASK_HOSTFLY; uiHostSettings &= ~GAME_HOST_OPTION_BITMASK_HOSTHUNGER; uiHostSettings &= ~GAME_HOST_OPTION_BITMASK_HOSTINVISIBLE; } break; case eGameHostOption_HostCanFly: if (uiVal != 0) { uiHostSettings |= GAME_HOST_OPTION_BITMASK_HOSTFLY; } else { // off uiHostSettings &= ~GAME_HOST_OPTION_BITMASK_HOSTFLY; } break; case eGameHostOption_HostCanChangeHunger: if (uiVal != 0) { uiHostSettings |= GAME_HOST_OPTION_BITMASK_HOSTHUNGER; } else { // off uiHostSettings &= ~GAME_HOST_OPTION_BITMASK_HOSTHUNGER; } break; case eGameHostOption_HostCanBeInvisible: if (uiVal != 0) { uiHostSettings |= GAME_HOST_OPTION_BITMASK_HOSTINVISIBLE; } else { // off uiHostSettings &= ~GAME_HOST_OPTION_BITMASK_HOSTINVISIBLE; } break; case eGameHostOption_BedrockFog: if (uiVal != 0) { uiHostSettings |= GAME_HOST_OPTION_BITMASK_BEDROCKFOG; } else { // off uiHostSettings &= ~GAME_HOST_OPTION_BITMASK_BEDROCKFOG; } break; case eGameHostOption_DisableSaving: if (uiVal != 0) { uiHostSettings |= GAME_HOST_OPTION_BITMASK_DISABLESAVE; } else { // off uiHostSettings &= ~GAME_HOST_OPTION_BITMASK_DISABLESAVE; } break; case eGameHostOption_WasntSaveOwner: if (uiVal != 0) { uiHostSettings |= GAME_HOST_OPTION_BITMASK_NOTOWNER; } else { // off uiHostSettings &= ~GAME_HOST_OPTION_BITMASK_NOTOWNER; } break; case eGameHostOption_MobGriefing: if (uiVal != 1) { uiHostSettings |= GAME_HOST_OPTION_BITMASK_MOBGRIEFING; } else { // off uiHostSettings &= ~GAME_HOST_OPTION_BITMASK_MOBGRIEFING; } break; case eGameHostOption_KeepInventory: if (uiVal != 0) { uiHostSettings |= GAME_HOST_OPTION_BITMASK_KEEPINVENTORY; } else { // off uiHostSettings &= ~GAME_HOST_OPTION_BITMASK_KEEPINVENTORY; } break; case eGameHostOption_DoMobSpawning: if (uiVal != 1) { uiHostSettings |= GAME_HOST_OPTION_BITMASK_DOMOBSPAWNING; } else { // off uiHostSettings &= ~GAME_HOST_OPTION_BITMASK_DOMOBSPAWNING; } break; case eGameHostOption_DoMobLoot: if (uiVal != 1) { uiHostSettings |= GAME_HOST_OPTION_BITMASK_DOMOBLOOT; } else { // off uiHostSettings &= ~GAME_HOST_OPTION_BITMASK_DOMOBLOOT; } break; case eGameHostOption_DoTileDrops: if (uiVal != 1) { uiHostSettings |= GAME_HOST_OPTION_BITMASK_DOTILEDROPS; } else { // off uiHostSettings &= ~GAME_HOST_OPTION_BITMASK_DOTILEDROPS; } break; case eGameHostOption_NaturalRegeneration: if (uiVal != 1) { uiHostSettings |= GAME_HOST_OPTION_BITMASK_NATURALREGEN; } else { // off uiHostSettings &= ~GAME_HOST_OPTION_BITMASK_NATURALREGEN; } break; case eGameHostOption_DoDaylightCycle: if (uiVal != 1) { uiHostSettings |= GAME_HOST_OPTION_BITMASK_DODAYLIGHTCYCLE; } else { // off uiHostSettings &= ~GAME_HOST_OPTION_BITMASK_DODAYLIGHTCYCLE; } break; case eGameHostOption_WorldSize: // clear the difficulty first uiHostSettings &= ~GAME_HOST_OPTION_BITMASK_WORLDSIZE; uiHostSettings |= (GAME_HOST_OPTION_BITMASK_WORLDSIZE & (uiVal << GAME_HOST_OPTION_BITMASK_WORLDSIZE_BITSHIFT)); break; case eGameHostOption_All: uiHostSettings = uiVal; break; default: break; } } unsigned int Game::GetGameHostOption(eGameHostOption eVal) { return GetGameHostOption(m_uiGameHostSettings, eVal); } unsigned int Game::GetGameHostOption(unsigned int uiHostSettings, eGameHostOption eVal) { // unsigned int uiVal=0; switch (eVal) { case eGameHostOption_FriendsOfFriends: return (uiHostSettings & GAME_HOST_OPTION_BITMASK_FRIENDSOFFRIENDS); break; case eGameHostOption_Difficulty: return (uiHostSettings & GAME_HOST_OPTION_BITMASK_DIFFICULTY); break; case eGameHostOption_Gamertags: return (uiHostSettings & GAME_HOST_OPTION_BITMASK_GAMERTAGS); break; case eGameHostOption_GameType: return (uiHostSettings & GAME_HOST_OPTION_BITMASK_GAMETYPE) >> 4; break; case eGameHostOption_All: return (uiHostSettings & GAME_HOST_OPTION_BITMASK_ALL); break; case eGameHostOption_Tutorial: // special case - tutorial is offline, but we want the gamertag // option, and set Easy mode, structures on, fire on, tnt on, pvp // on, trust players on return ((uiHostSettings & GAME_HOST_OPTION_BITMASK_GAMERTAGS) | GAME_HOST_OPTION_BITMASK_TRUSTPLAYERS | GAME_HOST_OPTION_BITMASK_FIRESPREADS | GAME_HOST_OPTION_BITMASK_TNT | GAME_HOST_OPTION_BITMASK_PVP | GAME_HOST_OPTION_BITMASK_STRUCTURES | 1); break; case eGameHostOption_LevelType: return (uiHostSettings & GAME_HOST_OPTION_BITMASK_LEVELTYPE); break; case eGameHostOption_Structures: return (uiHostSettings & GAME_HOST_OPTION_BITMASK_STRUCTURES); break; case eGameHostOption_BonusChest: return (uiHostSettings & GAME_HOST_OPTION_BITMASK_BONUSCHEST); break; case eGameHostOption_HasBeenInCreative: return (uiHostSettings & GAME_HOST_OPTION_BITMASK_BEENINCREATIVE); break; case eGameHostOption_PvP: return (uiHostSettings & GAME_HOST_OPTION_BITMASK_PVP); break; case eGameHostOption_TrustPlayers: return (uiHostSettings & GAME_HOST_OPTION_BITMASK_TRUSTPLAYERS); break; case eGameHostOption_TNT: return (uiHostSettings & GAME_HOST_OPTION_BITMASK_TNT); break; case eGameHostOption_FireSpreads: return (uiHostSettings & GAME_HOST_OPTION_BITMASK_FIRESPREADS); break; case eGameHostOption_CheatsEnabled: return (uiHostSettings & (GAME_HOST_OPTION_BITMASK_HOSTFLY | GAME_HOST_OPTION_BITMASK_HOSTHUNGER | GAME_HOST_OPTION_BITMASK_HOSTINVISIBLE)); break; case eGameHostOption_HostCanFly: return (uiHostSettings & GAME_HOST_OPTION_BITMASK_HOSTFLY); break; case eGameHostOption_HostCanChangeHunger: return (uiHostSettings & GAME_HOST_OPTION_BITMASK_HOSTHUNGER); break; case eGameHostOption_HostCanBeInvisible: return (uiHostSettings & GAME_HOST_OPTION_BITMASK_HOSTINVISIBLE); break; case eGameHostOption_BedrockFog: return (uiHostSettings & GAME_HOST_OPTION_BITMASK_BEDROCKFOG); break; case eGameHostOption_DisableSaving: return (uiHostSettings & GAME_HOST_OPTION_BITMASK_DISABLESAVE); break; case eGameHostOption_WasntSaveOwner: return (uiHostSettings & GAME_HOST_OPTION_BITMASK_NOTOWNER); case eGameHostOption_WorldSize: return (uiHostSettings & GAME_HOST_OPTION_BITMASK_WORLDSIZE) >> GAME_HOST_OPTION_BITMASK_WORLDSIZE_BITSHIFT; case eGameHostOption_MobGriefing: return !(uiHostSettings & GAME_HOST_OPTION_BITMASK_MOBGRIEFING); case eGameHostOption_KeepInventory: return (uiHostSettings & GAME_HOST_OPTION_BITMASK_KEEPINVENTORY); case eGameHostOption_DoMobSpawning: return !(uiHostSettings & GAME_HOST_OPTION_BITMASK_DOMOBSPAWNING); case eGameHostOption_DoMobLoot: return !(uiHostSettings & GAME_HOST_OPTION_BITMASK_DOMOBLOOT); case eGameHostOption_DoTileDrops: return !(uiHostSettings & GAME_HOST_OPTION_BITMASK_DOTILEDROPS); case eGameHostOption_NaturalRegeneration: return !(uiHostSettings & GAME_HOST_OPTION_BITMASK_NATURALREGEN); case eGameHostOption_DoDaylightCycle: return !(uiHostSettings & GAME_HOST_OPTION_BITMASK_DODAYLIGHTCYCLE); break; default: return 0; } return false; } bool Game::CanRecordStatsAndAchievements() { bool isTutorial = Minecraft::GetInstance() != nullptr && Minecraft::GetInstance()->isTutorial(); // 4J Stu - All of these options give the host player some advantage, so // should not allow achievements return !(app.GetGameHostOption(eGameHostOption_HasBeenInCreative) || app.GetGameHostOption(eGameHostOption_HostCanBeInvisible) || app.GetGameHostOption(eGameHostOption_HostCanChangeHunger) || app.GetGameHostOption(eGameHostOption_HostCanFly) || app.GetGameHostOption(eGameHostOption_WasntSaveOwner) || !app.GetGameHostOption(eGameHostOption_MobGriefing) || app.GetGameHostOption(eGameHostOption_KeepInventory) || !app.GetGameHostOption(eGameHostOption_DoMobSpawning) || (!app.GetGameHostOption(eGameHostOption_DoDaylightCycle) && !isTutorial)); } void Game::processSchematics(LevelChunk* levelChunk) { m_gameRules.processSchematics(levelChunk); } void Game::processSchematicsLighting(LevelChunk* levelChunk) { m_gameRules.processSchematicsLighting(levelChunk); } void Game::loadDefaultGameRules() { m_gameRules.loadDefaultGameRules(); } void Game::setLevelGenerationOptions( LevelGenerationOptions* levelGen) { m_gameRules.setLevelGenerationOptions(levelGen); } const wchar_t* Game::GetGameRulesString(const std::wstring& key) { return m_gameRules.GetGameRulesString(key); } unsigned char Game::m_szPNG[8] = {137, 80, 78, 71, 13, 10, 26, 10}; #define PNG_TAG_tEXt 0x74455874 unsigned int Game::FromBigEndian(unsigned int uiValue) { unsigned int uiReturn = ((uiValue >> 24) & 0x000000ff) | ((uiValue >> 8) & 0x0000ff00) | ((uiValue << 8) & 0x00ff0000) | ((uiValue << 24) & 0xff000000); return uiReturn; } void Game::GetImageTextData(std::uint8_t* imageData, unsigned int imageBytes, unsigned char* seedText, unsigned int& uiHostOptions, bool& bHostOptionsRead, std::uint32_t& uiTexturePack) { auto readPngUInt32 = [](const std::uint8_t* data) -> unsigned int { unsigned int value = 0; std::memcpy(&value, data, sizeof(value)); return value; }; std::uint8_t* ucPtr = imageData; unsigned int uiCount = 0; unsigned int uiChunkLen; unsigned int uiChunkType; unsigned int uiCRC; char szKeyword[80]; // check it's a png for (int i = 0; i < 8; i++) { if (m_szPNG[i] != ucPtr[i]) return; } uiCount += 8; while (uiCount < imageBytes) { uiChunkLen = FromBigEndian(readPngUInt32(&ucPtr[uiCount])); uiCount += sizeof(int); uiChunkType = FromBigEndian(readPngUInt32(&ucPtr[uiCount])); uiCount += sizeof(int); if (uiChunkType == PNG_TAG_tEXt) // tEXt { // check that it's the 4J text unsigned char* pszKeyword = &ucPtr[uiCount]; while (pszKeyword < ucPtr + uiCount + uiChunkLen) { memset(szKeyword, 0, 80); unsigned int uiKeywordC = 0; while (*pszKeyword != 0) { szKeyword[uiKeywordC++] = *pszKeyword; pszKeyword++; } pszKeyword++; if (strcmp(szKeyword, "4J_SEED") == 0) { // read the seed value unsigned int uiValueC = 0; while (*pszKeyword != 0 && (pszKeyword < ucPtr + uiCount + uiChunkLen)) { seedText[uiValueC++] = *pszKeyword; pszKeyword++; } // memcpy(seedText,pszKeyword,uiChunkLen-8); } else if (strcmp(szKeyword, "4J_HOSTOPTIONS") == 0) { bHostOptionsRead = true; // read the host options value unsigned int uiValueC = 0; unsigned char pszHostOptions[9]; // Hex representation of // unsigned int memset(&pszHostOptions, 0, 9); while (*pszKeyword != 0 && (pszKeyword < ucPtr + uiCount + uiChunkLen) && uiValueC < 8) { pszHostOptions[uiValueC++] = *pszKeyword; pszKeyword++; } uiHostOptions = 0; std::stringstream ss; ss << pszHostOptions; ss >> std::hex >> uiHostOptions; } else if (strcmp(szKeyword, "4J_TEXTUREPACK") == 0) { // read the texture pack value unsigned int uiValueC = 0; unsigned char pszTexturePack[9]; // Hex representation of // unsigned int memset(&pszTexturePack, 0, 9); while (*pszKeyword != 0 && (pszKeyword < ucPtr + uiCount + uiChunkLen) && uiValueC < 8) { pszTexturePack[uiValueC++] = *pszKeyword; pszKeyword++; } std::stringstream ss; ss << pszTexturePack; ss >> std::hex >> uiTexturePack; } } } uiCount += uiChunkLen; uiCRC = FromBigEndian(readPngUInt32(&ucPtr[uiCount])); uiCount += sizeof(int); } return; } unsigned int Game::CreateImageTextData(std::uint8_t* textMetadata, int64_t seed, bool hasSeed, unsigned int uiHostOptions, unsigned int uiTexturePackId) { int iTextMetadataBytes = 0; if (hasSeed) { strcpy((char*)textMetadata, "4J_SEED"); snprintf((char*)&textMetadata[8], 42, "%lld", (long long)seed); // get the length iTextMetadataBytes += 8; while (textMetadata[iTextMetadataBytes] != 0) iTextMetadataBytes++; ++iTextMetadataBytes; // Add a null terminator at the end of the seed // value } // Save the host options that this world was last played with strcpy((char*)&textMetadata[iTextMetadataBytes], "4J_HOSTOPTIONS"); snprintf((char*)&textMetadata[iTextMetadataBytes + 15], 9, "%X", uiHostOptions); iTextMetadataBytes += 15; while (textMetadata[iTextMetadataBytes] != 0) iTextMetadataBytes++; ++iTextMetadataBytes; // Add a null terminator at the end of the host // options value // Save the texture pack id strcpy((char*)&textMetadata[iTextMetadataBytes], "4J_TEXTUREPACK"); snprintf((char*)&textMetadata[iTextMetadataBytes + 15], 9, "%X", uiHostOptions); iTextMetadataBytes += 15; while (textMetadata[iTextMetadataBytes] != 0) iTextMetadataBytes++; return iTextMetadataBytes; } void Game::AddTerrainFeaturePosition(_eTerrainFeatureType eFeatureType, int x, int z) { // check we don't already have this in for (auto it = m_vTerrainFeatures.begin(); it < m_vTerrainFeatures.end(); ++it) { FEATURE_DATA* pFeatureData = *it; if ((pFeatureData->eTerrainFeature == eFeatureType) && (pFeatureData->x == x) && (pFeatureData->z == z)) return; } FEATURE_DATA* pFeatureData = new FEATURE_DATA; pFeatureData->eTerrainFeature = eFeatureType; pFeatureData->x = x; pFeatureData->z = z; m_vTerrainFeatures.push_back(pFeatureData); } _eTerrainFeatureType Game::IsTerrainFeature(int x, int z) { for (auto it = m_vTerrainFeatures.begin(); it < m_vTerrainFeatures.end(); ++it) { FEATURE_DATA* pFeatureData = *it; if ((pFeatureData->x == x) && (pFeatureData->z == z)) return pFeatureData->eTerrainFeature; } return eTerrainFeature_None; } bool Game::GetTerrainFeaturePosition(_eTerrainFeatureType eType, int* pX, int* pZ) { for (auto it = m_vTerrainFeatures.begin(); it < m_vTerrainFeatures.end(); ++it) { FEATURE_DATA* pFeatureData = *it; if (pFeatureData->eTerrainFeature == eType) { *pX = pFeatureData->x; *pZ = pFeatureData->z; return true; } } return false; } void Game::ClearTerrainFeaturePosition() { FEATURE_DATA* pFeatureData; while (m_vTerrainFeatures.size() > 0) { pFeatureData = m_vTerrainFeatures.back(); m_vTerrainFeatures.pop_back(); delete pFeatureData; } } void Game::UpdatePlayerInfo(std::uint8_t networkSmallId, int16_t playerColourIndex, unsigned int playerGamePrivileges) { for (unsigned int i = 0; i < MINECRAFT_NET_MAX_PLAYERS; ++i) { if (m_playerColours[i] == networkSmallId) { m_playerColours[i] = 0; m_playerGamePrivileges[i] = 0; } } if (playerColourIndex >= 0 && playerColourIndex < MINECRAFT_NET_MAX_PLAYERS) { m_playerColours[playerColourIndex] = networkSmallId; m_playerGamePrivileges[playerColourIndex] = playerGamePrivileges; } } short Game::GetPlayerColour(std::uint8_t networkSmallId) { short index = -1; for (unsigned int i = 0; i < MINECRAFT_NET_MAX_PLAYERS; ++i) { if (m_playerColours[i] == networkSmallId) { index = i; break; } } return index; } unsigned int Game::GetPlayerPrivileges(std::uint8_t networkSmallId) { unsigned int privileges = 0; for (unsigned int i = 0; i < MINECRAFT_NET_MAX_PLAYERS; ++i) { if (m_playerColours[i] == networkSmallId) { privileges = m_playerGamePrivileges[i]; break; } } return privileges; } std::wstring Game::getEntityName(eINSTANCEOF type) { switch (type) { case eTYPE_WOLF: return app.GetString(IDS_WOLF); case eTYPE_CREEPER: return app.GetString(IDS_CREEPER); case eTYPE_SKELETON: return app.GetString(IDS_SKELETON); case eTYPE_SPIDER: return app.GetString(IDS_SPIDER); case eTYPE_ZOMBIE: return app.GetString(IDS_ZOMBIE); case eTYPE_PIGZOMBIE: return app.GetString(IDS_PIGZOMBIE); case eTYPE_ENDERMAN: return app.GetString(IDS_ENDERMAN); case eTYPE_SILVERFISH: return app.GetString(IDS_SILVERFISH); case eTYPE_CAVESPIDER: return app.GetString(IDS_CAVE_SPIDER); case eTYPE_GHAST: return app.GetString(IDS_GHAST); case eTYPE_SLIME: return app.GetString(IDS_SLIME); case eTYPE_ARROW: return app.GetString(IDS_ITEM_ARROW); case eTYPE_ENDERDRAGON: return app.GetString(IDS_ENDERDRAGON); case eTYPE_BLAZE: return app.GetString(IDS_BLAZE); case eTYPE_LAVASLIME: return app.GetString(IDS_LAVA_SLIME); // 4J-PB - fix for #107167 - Customer Encountered: TU12: Content: // UI: There is no information what killed Player after being slain // by Iron Golem. case eTYPE_VILLAGERGOLEM: return app.GetString(IDS_IRONGOLEM); case eTYPE_HORSE: return app.GetString(IDS_HORSE); case eTYPE_WITCH: return app.GetString(IDS_WITCH); case eTYPE_WITHERBOSS: return app.GetString(IDS_WITHER); case eTYPE_BAT: return app.GetString(IDS_BAT); default: break; }; return L""; } std::uint32_t Game::m_dwContentTypeA[e_Marketplace_MAX] = { XMARKETPLACE_OFFERING_TYPE_CONTENT, // e_DLC_SkinPack, e_DLC_TexturePacks, // e_DLC_MashupPacks XMARKETPLACE_OFFERING_TYPE_THEME, // e_DLC_Themes XMARKETPLACE_OFFERING_TYPE_AVATARITEM, // e_DLC_AvatarItems XMARKETPLACE_OFFERING_TYPE_TILE, // e_DLC_Gamerpics }; unsigned int Game::AddDLCRequest(eDLCMarketplaceType eType, bool bPromote) { // lock access { std::lock_guard lock(csDLCDownloadQueue); // If it's already in there, promote it to the top of the list int iPosition = 0; for (auto it = m_DLCDownloadQueue.begin(); it != m_DLCDownloadQueue.end(); ++it) { DLCRequest* pCurrent = *it; if (pCurrent->dwType == m_dwContentTypeA[eType]) { // already got this in the list if (pCurrent->eState == e_DLC_ContentState_Retrieving || pCurrent->eState == e_DLC_ContentState_Retrieved) { // already retrieved this return 0; } else { // promote if (bPromote) { m_DLCDownloadQueue.erase(m_DLCDownloadQueue.begin() + iPosition); m_DLCDownloadQueue.insert(m_DLCDownloadQueue.begin(), pCurrent); } return 0; } } iPosition++; } DLCRequest* pDLCreq = new DLCRequest; pDLCreq->dwType = m_dwContentTypeA[eType]; pDLCreq->eState = e_DLC_ContentState_Idle; m_DLCDownloadQueue.push_back(pDLCreq); m_bAllDLCContentRetrieved = false; } app.DebugPrintf("[Consoles_App] Added DLC request.\n"); return 1; } unsigned int Game::AddTMSPPFileTypeRequest(eDLCContentType eType, bool bPromote) { // lock access std::lock_guard lock(csTMSPPDownloadQueue); // If it's already in there, promote it to the top of the list int iPosition = 0; // ignore promoting for now /* bool bPromoted=false; for(auto it = m_TMSPPDownloadQueue.begin(); it != m_TMSPPDownloadQueue.end(); ++it) { TMSPPRequest *pCurrent = *it; if(pCurrent->eType==eType) { if(!(pCurrent->eState == e_TMS_ContentState_Retrieving || pCurrent->eState == e_TMS_ContentState_Retrieved)) { // promote if(bPromote) { m_TMSPPDownloadQueue.erase(m_TMSPPDownloadQueue.begin()+iPosition); m_TMSPPDownloadQueue.insert(m_TMSPPDownloadQueue.begin(),pCurrent); bPromoted=true; } } } iPosition++; } if(bPromoted) { // re-ordered the list, so leave now return 0; } */ // special case for data files (not image files) if (eType == e_DLC_TexturePackData) { int iCount = GetDLCInfoFullOffersCount(); for (int i = 0; i < iCount; i++) { DLC_INFO* pDLC = GetDLCInfoFullOffer(i); if ((pDLC->eDLCType == e_DLC_TexturePacks) || (pDLC->eDLCType == e_DLC_MashupPacks)) { // first check if the image is already in the memory textures, // since we might be loading some from the Title Update // partition if (pDLC->wchDataFile[0] != 0) { // wchar_t *cString = pDLC->wchDataFile; // 4J-PB - shouldn't check this here - let the TMS files // override it, so if they are on TMS, we'll take them // first // int iIndex = // app.GetLocalTMSFileIndex(pDLC->wchDataFile,true); // if(iIndex!=-1) { bool bPresent = app.IsFileInTPD(pDLC->iConfig); if (!bPresent) { // this may already be present in the vector because // of a previous trial/full offer bool bAlreadyInQueue = false; for (auto it = m_TMSPPDownloadQueue.begin(); it != m_TMSPPDownloadQueue.end(); ++it) { TMSPPRequest* pCurrent = *it; if (wcscmp(pDLC->wchDataFile, pCurrent->wchFilename) == 0) { bAlreadyInQueue = true; break; } } if (!bAlreadyInQueue) { TMSPPRequest* pTMSPPreq = new TMSPPRequest; pTMSPPreq->CallbackFunc = &Game::TMSPPFileReturned; pTMSPPreq->lpCallbackParam = this; pTMSPPreq->eStorageFacility = C4JStorage::eGlobalStorage_Title; pTMSPPreq->eFileTypeVal = C4JStorage::TMS_FILETYPE_BINARY; memcpy(pTMSPPreq->wchFilename, pDLC->wchDataFile, sizeof(wchar_t) * MAX_BANNERNAME_SIZE); pTMSPPreq->eType = e_DLC_TexturePackData; pTMSPPreq->eState = e_TMS_ContentState_Queued; m_bAllTMSContentRetrieved = false; m_TMSPPDownloadQueue.push_back(pTMSPPreq); } } else { app.DebugPrintf( "Texture data already present in the TPD\n"); } } } } } } else { // for all the files of type eType, add them to the download list // run through the trial offers first, then the full offers. Any // duplicates won't be added to the download queue int iCount; // and the full offers iCount = GetDLCInfoFullOffersCount(); for (int i = 0; i < iCount; i++) { DLC_INFO* pDLC = GetDLCInfoFullOffer(i); // if(wcscmp(pDLC->wchType,wchDLCTypeNames[eType])==0) if (pDLC->eDLCType == eType) { // first check if the image is already in the memory textures, // since we might be loading some from the Title Update // partition wchar_t* cString = pDLC->wchBanner; // 4J-PB - shouldn't check this here - let the TMS files // override it, so if they are on TMS, we'll take them first // int iIndex = app.GetLocalTMSFileIndex(cString,true); // if(iIndex!=-1) { bool bPresent = app.IsFileInMemoryTextures(cString); if (!bPresent) { // this may already be present in the vector because of // a previous trial/full offer bool bAlreadyInQueue = false; for (auto it = m_TMSPPDownloadQueue.begin(); it != m_TMSPPDownloadQueue.end(); ++it) { TMSPPRequest* pCurrent = *it; if (wcscmp(pDLC->wchBanner, pCurrent->wchFilename) == 0) { bAlreadyInQueue = true; break; } } if (!bAlreadyInQueue) { // app.DebugPrintf("Adding a request to the TMSPP // download queue - %ls\n",pDLC->wchBanner); TMSPPRequest* pTMSPPreq = new TMSPPRequest; memset(pTMSPPreq, 0, sizeof(TMSPPRequest)); pTMSPPreq->CallbackFunc = &Game::TMSPPFileReturned; pTMSPPreq->lpCallbackParam = this; // 4J-PB - testing for now // pTMSPPreq->eStorageFacility=C4JStorage::eGlobalStorage_TitleUser; pTMSPPreq->eStorageFacility = C4JStorage::eGlobalStorage_Title; pTMSPPreq->eFileTypeVal = C4JStorage::TMS_FILETYPE_BINARY; // wcstombs(pTMSPPreq->szFilename,pDLC->wchBanner,MAX_TMSFILENAME_SIZE); memcpy(pTMSPPreq->wchFilename, pDLC->wchBanner, sizeof(wchar_t) * MAX_BANNERNAME_SIZE); pTMSPPreq->eType = eType; pTMSPPreq->eState = e_TMS_ContentState_Queued; m_bAllTMSContentRetrieved = false; m_TMSPPDownloadQueue.push_back(pTMSPPreq); app.DebugPrintf( "===m_TMSPPDownloadQueue Adding %ls, q size is " "%d\n", pTMSPPreq->wchFilename, m_TMSPPDownloadQueue.size()); } } } } } } return 1; } bool Game::CheckTMSDLCCanStop() { std::lock_guard lock(csTMSPPDownloadQueue); for (auto it = m_TMSPPDownloadQueue.begin(); it != m_TMSPPDownloadQueue.end(); ++it) { TMSPPRequest* pCurrent = *it; if (pCurrent->eState == e_TMS_ContentState_Retrieving) { return false; } } return true; } bool Game::RetrieveNextDLCContent() { // If there's already a retrieve in progress, quit // we may have re-ordered the list, so need to check every item // is there a primary player and a network connection? int primPad = ProfileManager.GetPrimaryPad(); if (primPad == -1 || !ProfileManager.IsSignedInLive(primPad)) { return true; // 4J-JEV: We need to wait until the primary player is // online. } { std::lock_guard lock(csDLCDownloadQueue); for (auto it = m_DLCDownloadQueue.begin(); it != m_DLCDownloadQueue.end(); ++it) { DLCRequest* pCurrent = *it; if (pCurrent->eState == e_DLC_ContentState_Retrieving) { return true; } } // Now look for the next retrieval for (auto it = m_DLCDownloadQueue.begin(); it != m_DLCDownloadQueue.end(); ++it) { DLCRequest* pCurrent = *it; if (pCurrent->eState == e_DLC_ContentState_Idle) { #if defined(_DEBUG) app.DebugPrintf("RetrieveNextDLCContent - type = %d\n", pCurrent->dwType); #endif C4JStorage::EDLCStatus status = StorageManager.GetDLCOffers( ProfileManager.GetPrimaryPad(), [this](int iOfferC, std::uint32_t dwType, int pad) { return dlcOffersReturned(iOfferC, dwType, pad); }, pCurrent->dwType); if (status == C4JStorage::EDLC_Pending) { pCurrent->eState = e_DLC_ContentState_Retrieving; } else { // no content of this type, or some other problem app.DebugPrintf("RetrieveNextDLCContent - PROBLEM\n"); pCurrent->eState = e_DLC_ContentState_Retrieved; } return true; } } } app.DebugPrintf("[Consoles_App] Finished downloading dlc content.\n"); return false; } int Game::TMSPPFileReturned(void* pParam, int iPad, int iUserData, C4JStorage::PTMSPP_FILEDATA pFileData, const char* szFilename) { Game* pClass = (Game*)pParam; // find the right one in the vector { std::lock_guard lock(pClass->csTMSPPDownloadQueue); for (auto it = pClass->m_TMSPPDownloadQueue.begin(); it != pClass->m_TMSPPDownloadQueue.end(); ++it) { TMSPPRequest* pCurrent = *it; #if defined(_WINDOWS64) char szFile[MAX_TMSFILENAME_SIZE]; wcstombs(szFile, pCurrent->wchFilename, MAX_TMSFILENAME_SIZE); if (strcmp(szFilename, szFile) == 0) #endif { // set this to retrieved whether it found it or not pCurrent->eState = e_TMS_ContentState_Retrieved; if (pFileData != nullptr) { switch (pCurrent->eType) { case e_DLC_TexturePackData: { app.DebugPrintf("--- Got texturepack data %ls\n", pCurrent->wchFilename); // get the config value for the texture pack int iConfig = app.GetTPConfigVal(pCurrent->wchFilename); app.AddMemoryTPDFile(iConfig, pFileData->pbData, pFileData->size); } break; default: app.DebugPrintf("--- Got image data - %ls\n", pCurrent->wchFilename); app.AddMemoryTextureFile(pCurrent->wchFilename, pFileData->pbData, pFileData->size); break; } } else { app.DebugPrintf("TMSImageReturned failed (%s)...\n", szFilename); } break; } } } return 0; } bool Game::RetrieveNextTMSPPContent() { return false; } void Game::TickDLCOffersRetrieved() { if (!m_bAllDLCContentRetrieved) { if (!app.RetrieveNextDLCContent()) { app.DebugPrintf("[Consoles_App] All content retrieved.\n"); m_bAllDLCContentRetrieved = true; } } } void Game::ClearAndResetDLCDownloadQueue() { app.DebugPrintf("[Consoles_App] Clear and reset download queue.\n"); int iPosition = 0; { std::lock_guard lock(csTMSPPDownloadQueue); for (auto it = m_DLCDownloadQueue.begin(); it != m_DLCDownloadQueue.end(); ++it) { DLCRequest* pCurrent = *it; delete pCurrent; iPosition++; } m_DLCDownloadQueue.clear(); m_bAllDLCContentRetrieved = true; } } void Game::TickTMSPPFilesRetrieved() { if (m_bTickTMSDLCFiles && !m_bAllTMSContentRetrieved) { if (app.RetrieveNextTMSPPContent() == false) { m_bAllTMSContentRetrieved = true; } } } void Game::ClearTMSPPFilesRetrieved() { int iPosition = 0; { std::lock_guard lock(csTMSPPDownloadQueue); for (auto it = m_TMSPPDownloadQueue.begin(); it != m_TMSPPDownloadQueue.end(); ++it) { TMSPPRequest* pCurrent = *it; delete pCurrent; iPosition++; } m_TMSPPDownloadQueue.clear(); m_bAllTMSContentRetrieved = true; } } int Game::dlcOffersReturned(int iOfferC, std::uint32_t dwType, int iPad) { // find the right one in the vector { std::lock_guard lock(csTMSPPDownloadQueue); for (auto it = m_DLCDownloadQueue.begin(); it != m_DLCDownloadQueue.end(); ++it) { DLCRequest* pCurrent = *it; // avatar items are coming back as type Content, so we can't trust // the type setting if (pCurrent->dwType == static_cast(dwType)) { m_iDLCOfferC = iOfferC; DebugPrintf( "DLCOffersReturned - type %u, count %d - setting to " "retrieved\n", dwType, iOfferC); pCurrent->eState = e_DLC_ContentState_Retrieved; break; } } } return 0; } eDLCContentType Game::Find_eDLCContentType(std::uint32_t dwType) { for (int i = 0; i < e_DLC_MAX; i++) { if (m_dwContentTypeA[i] == dwType) { return (eDLCContentType)i; } } return (eDLCContentType)0; } bool Game::DLCContentRetrieved(eDLCMarketplaceType eType) { // If there's already a retrieve in progress, quit // we may have re-ordered the list, so need to check every item std::lock_guard lock(csDLCDownloadQueue); for (auto it = m_DLCDownloadQueue.begin(); it != m_DLCDownloadQueue.end(); ++it) { DLCRequest* pCurrent = *it; if ((pCurrent->dwType == m_dwContentTypeA[eType]) && (pCurrent->eState == e_DLC_ContentState_Retrieved)) { return true; } } return false; } void Game::SetAdditionalSkinBoxes(std::uint32_t dwSkinID, SKIN_BOX* SkinBoxA, unsigned int dwSkinBoxC) { EntityRenderer* renderer = EntityRenderDispatcher::instance->getRenderer(eTYPE_PLAYER); Model* pModel = renderer->getModel(); std::vector* pvModelPart = new std::vector; std::vector* pvSkinBoxes = new std::vector; { std::lock_guard lock_mp(csAdditionalModelParts); std::lock_guard lock_sb(csAdditionalSkinBoxes); app.DebugPrintf( "*** SetAdditionalSkinBoxes - Inserting model parts for skin %d " "from " "array of Skin Boxes\n", dwSkinID & 0x0FFFFFFF); // convert the skin boxes into model parts, and add to the humanoid // model for (unsigned int i = 0; i < dwSkinBoxC; i++) { if (pModel) { ModelPart* pModelPart = pModel->AddOrRetrievePart(&SkinBoxA[i]); pvModelPart->push_back(pModelPart); pvSkinBoxes->push_back(&SkinBoxA[i]); } } m_AdditionalModelParts.insert( std::pair*>(dwSkinID, pvModelPart)); m_AdditionalSkinBoxes.insert( std::pair*>(dwSkinID, pvSkinBoxes)); } } std::vector* Game::SetAdditionalSkinBoxes( std::uint32_t dwSkinID, std::vector* pvSkinBoxA) { EntityRenderer* renderer = EntityRenderDispatcher::instance->getRenderer(eTYPE_PLAYER); Model* pModel = renderer->getModel(); std::vector* pvModelPart = new std::vector; { std::lock_guard lock_mp(csAdditionalModelParts); std::lock_guard lock_sb(csAdditionalSkinBoxes); app.DebugPrintf( "*** SetAdditionalSkinBoxes - Inserting model parts for skin %d " "from " "array of Skin Boxes\n", dwSkinID & 0x0FFFFFFF); // convert the skin boxes into model parts, and add to the humanoid // model for (auto it = pvSkinBoxA->begin(); it != pvSkinBoxA->end(); ++it) { if (pModel) { ModelPart* pModelPart = pModel->AddOrRetrievePart(*it); pvModelPart->push_back(pModelPart); } } m_AdditionalModelParts.insert( std::pair*>(dwSkinID, pvModelPart)); m_AdditionalSkinBoxes.insert( std::pair*>(dwSkinID, pvSkinBoxA)); } return pvModelPart; } std::vector* Game::GetAdditionalModelParts( std::uint32_t dwSkinID) { std::lock_guard lock(csAdditionalModelParts); std::vector* pvModelParts = nullptr; if (m_AdditionalModelParts.size() > 0) { auto it = m_AdditionalModelParts.find(dwSkinID); if (it != m_AdditionalModelParts.end()) { pvModelParts = (*it).second; } } return pvModelParts; } std::vector* Game::GetAdditionalSkinBoxes( std::uint32_t dwSkinID) { std::lock_guard lock(csAdditionalSkinBoxes); std::vector* pvSkinBoxes = nullptr; if (m_AdditionalSkinBoxes.size() > 0) { auto it = m_AdditionalSkinBoxes.find(dwSkinID); if (it != m_AdditionalSkinBoxes.end()) { pvSkinBoxes = (*it).second; } } return pvSkinBoxes; } unsigned int Game::GetAnimOverrideBitmask(std::uint32_t dwSkinID) { std::lock_guard lock(csAnimOverrideBitmask); unsigned int uiAnimOverrideBitmask = 0L; if (m_AnimOverrides.size() > 0) { auto it = m_AnimOverrides.find(dwSkinID); if (it != m_AnimOverrides.end()) { uiAnimOverrideBitmask = (*it).second; } } return uiAnimOverrideBitmask; } void Game::SetAnimOverrideBitmask(std::uint32_t dwSkinID, unsigned int uiAnimOverrideBitmask) { // Make thread safe std::lock_guard lock(csAnimOverrideBitmask); if (m_AnimOverrides.size() > 0) { auto it = m_AnimOverrides.find(dwSkinID); if (it != m_AnimOverrides.end()) { return; // already in here } } m_AnimOverrides.insert(std::pair( dwSkinID, uiAnimOverrideBitmask)); } std::uint32_t Game::getSkinIdFromPath(const std::wstring& skin) { bool dlcSkin = false; unsigned int skinId = 0; if (skin.size() >= 14) { dlcSkin = skin.substr(0, 3).compare(L"dlc") == 0; std::wstring skinValue = skin.substr(7, skin.size()); skinValue = skinValue.substr(0, skinValue.find_first_of(L'.')); std::wstringstream ss; // 4J Stu - dlc skins are numbered using decimal to make it easier for // artists/people to number manually Everything else is numbered using // hex if (dlcSkin) ss << std::dec << skinValue.c_str(); else ss << std::hex << skinValue.c_str(); ss >> skinId; skinId = MAKE_SKIN_BITMASK(dlcSkin, skinId); } return skinId; } std::wstring Game::getSkinPathFromId(std::uint32_t skinId) { // 4J Stu - This function maps the encoded uint32_t we store in the player // profile to a filename that is stored as a memory texture and shared // between systems in game wchar_t chars[256]; if (GET_IS_DLC_SKIN_FROM_BITMASK(skinId)) { // 4J Stu - DLC skins are numbered using decimal rather than hex to make // it easier to number manually swprintf(chars, 256, L"dlcskin%08d.png", GET_DLC_SKIN_ID_FROM_BITMASK(skinId)); } else { std::uint32_t ugcSkinIndex = GET_UGC_SKIN_ID_FROM_BITMASK(skinId); std::uint32_t defaultSkinIndex = GET_DEFAULT_SKIN_ID_FROM_BITMASK(skinId); if (ugcSkinIndex == 0) { swprintf(chars, 256, L"defskin%08X.png", defaultSkinIndex); } else { swprintf(chars, 256, L"ugcskin%08X.png", ugcSkinIndex); } } return chars; } int Game::TexturePackDialogReturned( void* pParam, int iPad, C4JStorage::EMessageResult result) { return 0; } int Game::getArchiveFileSize(const std::wstring& filename) { TexturePack* tPack = nullptr; Minecraft* pMinecraft = Minecraft::GetInstance(); if (pMinecraft && pMinecraft->skins) tPack = pMinecraft->skins->getSelected(); if (tPack && tPack->hasData() && tPack->getArchiveFile() && tPack->getArchiveFile()->hasFile(filename)) { return tPack->getArchiveFile()->getFileSize(filename); } else return m_mediaArchive->getFileSize(filename); } bool Game::hasArchiveFile(const std::wstring& filename) { TexturePack* tPack = nullptr; Minecraft* pMinecraft = Minecraft::GetInstance(); if (pMinecraft && pMinecraft->skins) tPack = pMinecraft->skins->getSelected(); if (tPack && tPack->hasData() && tPack->getArchiveFile() && tPack->getArchiveFile()->hasFile(filename)) return true; else return m_mediaArchive->hasFile(filename); } std::vector Game::getArchiveFile( const std::wstring& filename) { TexturePack* tPack = nullptr; Minecraft* pMinecraft = Minecraft::GetInstance(); if (pMinecraft && pMinecraft->skins) tPack = pMinecraft->skins->getSelected(); if (tPack && tPack->hasData() && tPack->getArchiveFile() && tPack->getArchiveFile()->hasFile(filename)) { return tPack->getArchiveFile()->getFile(filename); } else return m_mediaArchive->getFile(filename); } // DLC int Game::GetDLCInfoTrialOffersCount() { return (int)DLCInfo_Trial.size(); } int Game::GetDLCInfoFullOffersCount() { return (int)DLCInfo_Full.size(); } int Game::GetDLCInfoTexturesOffersCount() { return (int)DLCTextures_PackID.size(); } // AUTOSAVE void Game::SetAutosaveTimerTime(void) { int settingValue = GetGameSettings(ProfileManager.GetPrimaryPad(), eGameSetting_Autosave); m_uiAutosaveTimer = time_util::clock::now() + std::chrono::minutes(settingValue * 15); } // value x 15 to get mins bool Game::AutosaveDue(void) { return (time_util::clock::now() > m_uiAutosaveTimer); } int64_t Game::SecondsToAutosave() { return std::chrono::duration_cast(m_uiAutosaveTimer - time_util::clock::now()).count(); } void Game::SetTrialTimerStart(void) { m_fTrialTimerStart = m_Time.fAppTime; mfTrialPausedTime = 0.0f; } float Game::getTrialTimer(void) { return m_Time.fAppTime - m_fTrialTimerStart - mfTrialPausedTime; } bool Game::IsLocalMultiplayerAvailable() { unsigned int connectedControllers = 0; for (unsigned int i = 0; i < XUSER_MAX_COUNT; ++i) { if (InputManager.IsPadConnected(i) || ProfileManager.IsSignedIn(i)) ++connectedControllers; } bool available = RenderManager.IsHiDef() && connectedControllers > 1; return available; // Found this in GameNetworkManager? // #ifdef 0 // iOtherConnectedControllers = // InputManager.GetConnectedGamepadCount(); // if((InputManager.IsPadConnected(userIndex) || // ProfileManager.IsSignedIn(userIndex))) // { // --iOtherConnectedControllers; // } // #else // for(unsigned int i = 0; i < XUSER_MAX_COUNT; ++i) // { // if( (i!=userIndex) && (InputManager.IsPadConnected(i) || // ProfileManager.IsSignedIn(i)) ) // { // iOtherConnectedControllers++; // } // } // #endif } // 4J-PB - language and locale function void Game::getLocale(std::vector& vecWstrLocales) { std::vector locales; const unsigned int systemLanguage = XGetLanguage(); // 4J-PB - restrict the 360 language until we're ready to have them in switch (systemLanguage) { case XC_LANGUAGE_ENGLISH: switch (XGetLocale()) { case XC_LOCALE_AUSTRALIA: case XC_LOCALE_CANADA: case XC_LOCALE_CZECH_REPUBLIC: case XC_LOCALE_GREECE: case XC_LOCALE_HONG_KONG: case XC_LOCALE_HUNGARY: case XC_LOCALE_INDIA: case XC_LOCALE_IRELAND: case XC_LOCALE_ISRAEL: case XC_LOCALE_NEW_ZEALAND: case XC_LOCALE_SAUDI_ARABIA: case XC_LOCALE_SINGAPORE: case XC_LOCALE_SLOVAK_REPUBLIC: case XC_LOCALE_SOUTH_AFRICA: case XC_LOCALE_UNITED_ARAB_EMIRATES: case XC_LOCALE_GREAT_BRITAIN: locales.push_back(eMCLang_enGB); break; default: // XC_LOCALE_UNITED_STATES break; } break; case XC_LANGUAGE_JAPANESE: locales.push_back(eMCLang_jaJP); break; case XC_LANGUAGE_GERMAN: switch (XGetLocale()) { case XC_LOCALE_AUSTRIA: locales.push_back(eMCLang_deAT); break; case XC_LOCALE_SWITZERLAND: locales.push_back(eMCLang_deCH); break; default: // XC_LOCALE_GERMANY: break; } locales.push_back(eMCLang_deDE); break; case XC_LANGUAGE_FRENCH: switch (XGetLocale()) { case XC_LOCALE_BELGIUM: locales.push_back(eMCLang_frBE); break; case XC_LOCALE_CANADA: locales.push_back(eMCLang_frCA); break; case XC_LOCALE_SWITZERLAND: locales.push_back(eMCLang_frCH); break; default: // XC_LOCALE_FRANCE: break; } locales.push_back(eMCLang_frFR); break; case XC_LANGUAGE_SPANISH: switch (XGetLocale()) { case XC_LOCALE_MEXICO: case XC_LOCALE_ARGENTINA: case XC_LOCALE_CHILE: case XC_LOCALE_COLOMBIA: case XC_LOCALE_UNITED_STATES: case XC_LOCALE_LATIN_AMERICA: locales.push_back(eMCLang_laLAS); locales.push_back(eMCLang_esMX); break; default: // XC_LOCALE_SPAIN break; } locales.push_back(eMCLang_esES); break; case XC_LANGUAGE_ITALIAN: locales.push_back(eMCLang_itIT); break; case XC_LANGUAGE_KOREAN: locales.push_back(eMCLang_koKR); break; case XC_LANGUAGE_TCHINESE: switch (XGetLocale()) { case XC_LOCALE_HONG_KONG: locales.push_back(eMCLang_zhHK); locales.push_back(eMCLang_zhTW); break; case XC_LOCALE_TAIWAN: locales.push_back(eMCLang_zhTW); locales.push_back(eMCLang_zhHK); default: break; } locales.push_back(eMCLang_hant); locales.push_back(eMCLang_zhCHT); break; case XC_LANGUAGE_PORTUGUESE: if (XGetLocale() == XC_LOCALE_BRAZIL) { locales.push_back(eMCLang_ptBR); } locales.push_back(eMCLang_ptPT); break; case XC_LANGUAGE_POLISH: locales.push_back(eMCLang_plPL); break; case XC_LANGUAGE_RUSSIAN: locales.push_back(eMCLang_ruRU); break; case XC_LANGUAGE_SWEDISH: locales.push_back(eMCLang_svSV); locales.push_back(eMCLang_svSE); break; case XC_LANGUAGE_TURKISH: locales.push_back(eMCLang_trTR); break; case XC_LANGUAGE_BNORWEGIAN: locales.push_back(eMCLang_nbNO); locales.push_back(eMCLang_noNO); locales.push_back(eMCLang_nnNO); break; case XC_LANGUAGE_DUTCH: switch (XGetLocale()) { case XC_LOCALE_BELGIUM: locales.push_back(eMCLang_nlBE); break; default: break; } locales.push_back(eMCLang_nlNL); break; case XC_LANGUAGE_SCHINESE: switch (XGetLocale()) { case XC_LOCALE_SINGAPORE: locales.push_back(eMCLang_zhSG); break; default: break; } locales.push_back(eMCLang_hans); locales.push_back(eMCLang_csCS); locales.push_back(eMCLang_zhCN); break; } locales.push_back(eMCLang_enUS); locales.push_back(eMCLang_null); for (int i = 0; i < locales.size(); i++) { eMCLang lang = locales.at(i); vecWstrLocales.push_back(m_localeA[lang]); } } int Game::get_eMCLang(wchar_t* pwchLocale) { return m_eMCLangA[pwchLocale]; } int Game::get_xcLang(wchar_t* pwchLocale) { return m_xcLangA[pwchLocale]; } void Game::LocaleAndLanguageInit() { m_localeA[eMCLang_zhCHT] = L"zh-CHT"; m_localeA[eMCLang_csCS] = L"cs-CS"; m_localeA[eMCLang_laLAS] = L"la-LAS"; m_localeA[eMCLang_null] = L"en-EN"; m_localeA[eMCLang_enUS] = L"en-US"; m_localeA[eMCLang_enGB] = L"en-GB"; m_localeA[eMCLang_enIE] = L"en-IE"; m_localeA[eMCLang_enAU] = L"en-AU"; m_localeA[eMCLang_enNZ] = L"en-NZ"; m_localeA[eMCLang_enCA] = L"en-CA"; m_localeA[eMCLang_jaJP] = L"ja-JP"; m_localeA[eMCLang_deDE] = L"de-DE"; m_localeA[eMCLang_deAT] = L"de-AT"; m_localeA[eMCLang_frFR] = L"fr-FR"; m_localeA[eMCLang_frCA] = L"fr-CA"; m_localeA[eMCLang_esES] = L"es-ES"; m_localeA[eMCLang_esMX] = L"es-MX"; m_localeA[eMCLang_itIT] = L"it-IT"; m_localeA[eMCLang_koKR] = L"ko-KR"; m_localeA[eMCLang_ptPT] = L"pt-PT"; m_localeA[eMCLang_ptBR] = L"pt-BR"; m_localeA[eMCLang_ruRU] = L"ru-RU"; m_localeA[eMCLang_nlNL] = L"nl-NL"; m_localeA[eMCLang_fiFI] = L"fi-FI"; m_localeA[eMCLang_svSV] = L"sv-SV"; m_localeA[eMCLang_daDA] = L"da-DA"; m_localeA[eMCLang_noNO] = L"no-NO"; m_localeA[eMCLang_plPL] = L"pl-PL"; m_localeA[eMCLang_trTR] = L"tr-TR"; m_localeA[eMCLang_elEL] = L"el-EL"; m_localeA[eMCLang_zhSG] = L"zh-SG"; m_localeA[eMCLang_zhCN] = L"zh-CN"; m_localeA[eMCLang_zhHK] = L"zh-HK"; m_localeA[eMCLang_zhTW] = L"zh-TW"; m_localeA[eMCLang_nlBE] = L"nl-BE"; m_localeA[eMCLang_daDK] = L"da-DK"; m_localeA[eMCLang_frBE] = L"fr-BE"; m_localeA[eMCLang_frCH] = L"fr-CH"; m_localeA[eMCLang_deCH] = L"de-CH"; m_localeA[eMCLang_nbNO] = L"nb-NO"; m_localeA[eMCLang_enGR] = L"en-GR"; m_localeA[eMCLang_enHK] = L"en-HK"; m_localeA[eMCLang_enSA] = L"en-SA"; m_localeA[eMCLang_enHU] = L"en-HU"; m_localeA[eMCLang_enIN] = L"en-IN"; m_localeA[eMCLang_enIL] = L"en-IL"; m_localeA[eMCLang_enSG] = L"en-SG"; m_localeA[eMCLang_enSK] = L"en-SK"; m_localeA[eMCLang_enZA] = L"en-ZA"; m_localeA[eMCLang_enCZ] = L"en-CZ"; m_localeA[eMCLang_enAE] = L"en-AE"; m_localeA[eMCLang_esAR] = L"es-AR"; m_localeA[eMCLang_esCL] = L"es-CL"; m_localeA[eMCLang_esCO] = L"es-CO"; m_localeA[eMCLang_esUS] = L"es-US"; m_localeA[eMCLang_svSE] = L"sv-SE"; m_localeA[eMCLang_csCZ] = L"cs-CZ"; m_localeA[eMCLang_elGR] = L"el-GR"; m_localeA[eMCLang_nnNO] = L"nn-NO"; m_localeA[eMCLang_skSK] = L"sk-SK"; m_localeA[eMCLang_hans] = L"zh-HANS"; m_localeA[eMCLang_hant] = L"zh-HANT"; m_eMCLangA[L"zh-CHT"] = eMCLang_zhCHT; m_eMCLangA[L"cs-CS"] = eMCLang_csCS; m_eMCLangA[L"la-LAS"] = eMCLang_laLAS; m_eMCLangA[L"en-EN"] = eMCLang_null; m_eMCLangA[L"en-US"] = eMCLang_enUS; m_eMCLangA[L"en-GB"] = eMCLang_enGB; m_eMCLangA[L"en-IE"] = eMCLang_enIE; m_eMCLangA[L"en-AU"] = eMCLang_enAU; m_eMCLangA[L"en-NZ"] = eMCLang_enNZ; m_eMCLangA[L"en-CA"] = eMCLang_enCA; m_eMCLangA[L"ja-JP"] = eMCLang_jaJP; m_eMCLangA[L"de-DE"] = eMCLang_deDE; m_eMCLangA[L"de-AT"] = eMCLang_deAT; m_eMCLangA[L"fr-FR"] = eMCLang_frFR; m_eMCLangA[L"fr-CA"] = eMCLang_frCA; m_eMCLangA[L"es-ES"] = eMCLang_esES; m_eMCLangA[L"es-MX"] = eMCLang_esMX; m_eMCLangA[L"it-IT"] = eMCLang_itIT; m_eMCLangA[L"ko-KR"] = eMCLang_koKR; m_eMCLangA[L"pt-PT"] = eMCLang_ptPT; m_eMCLangA[L"pt-BR"] = eMCLang_ptBR; m_eMCLangA[L"ru-RU"] = eMCLang_ruRU; m_eMCLangA[L"nl-NL"] = eMCLang_nlNL; m_eMCLangA[L"fi-FI"] = eMCLang_fiFI; m_eMCLangA[L"sv-SV"] = eMCLang_svSV; m_eMCLangA[L"da-DA"] = eMCLang_daDA; m_eMCLangA[L"no-NO"] = eMCLang_noNO; m_eMCLangA[L"pl-PL"] = eMCLang_plPL; m_eMCLangA[L"tr-TR"] = eMCLang_trTR; m_eMCLangA[L"el-EL"] = eMCLang_elEL; m_eMCLangA[L"zh-SG"] = eMCLang_zhSG; m_eMCLangA[L"zh-CN"] = eMCLang_zhCN; m_eMCLangA[L"zh-HK"] = eMCLang_zhHK; m_eMCLangA[L"zh-TW"] = eMCLang_zhTW; m_eMCLangA[L"nl-BE"] = eMCLang_nlBE; m_eMCLangA[L"da-DK"] = eMCLang_daDK; m_eMCLangA[L"fr-BE"] = eMCLang_frBE; m_eMCLangA[L"fr-CH"] = eMCLang_frCH; m_eMCLangA[L"de-CH"] = eMCLang_deCH; m_eMCLangA[L"nb-NO"] = eMCLang_nbNO; m_eMCLangA[L"en-GR"] = eMCLang_enGR; m_eMCLangA[L"en-HK"] = eMCLang_enHK; m_eMCLangA[L"en-SA"] = eMCLang_enSA; m_eMCLangA[L"en-HU"] = eMCLang_enHU; m_eMCLangA[L"en-IN"] = eMCLang_enIN; m_eMCLangA[L"en-IL"] = eMCLang_enIL; m_eMCLangA[L"en-SG"] = eMCLang_enSG; m_eMCLangA[L"en-SK"] = eMCLang_enSK; m_eMCLangA[L"en-ZA"] = eMCLang_enZA; m_eMCLangA[L"en-CZ"] = eMCLang_enCZ; m_eMCLangA[L"en-AE"] = eMCLang_enAE; m_eMCLangA[L"es-AR"] = eMCLang_esAR; m_eMCLangA[L"es-CL"] = eMCLang_esCL; m_eMCLangA[L"es-CO"] = eMCLang_esCO; m_eMCLangA[L"es-US"] = eMCLang_esUS; m_eMCLangA[L"sv-SE"] = eMCLang_svSE; m_eMCLangA[L"cs-CZ"] = eMCLang_csCZ; m_eMCLangA[L"el-GR"] = eMCLang_elGR; m_eMCLangA[L"nn-NO"] = eMCLang_nnNO; m_eMCLangA[L"sk-SK"] = eMCLang_skSK; m_eMCLangA[L"zh-HANS"] = eMCLang_hans; m_eMCLangA[L"zh-HANT"] = eMCLang_hant; m_xcLangA[L"zh-CHT"] = XC_LOCALE_CHINA; m_xcLangA[L"cs-CS"] = XC_LOCALE_CHINA; m_xcLangA[L"en-EN"] = XC_LOCALE_UNITED_STATES; m_xcLangA[L"en-US"] = XC_LOCALE_UNITED_STATES; m_xcLangA[L"en-GB"] = XC_LOCALE_GREAT_BRITAIN; m_xcLangA[L"en-IE"] = XC_LOCALE_IRELAND; m_xcLangA[L"en-AU"] = XC_LOCALE_AUSTRALIA; m_xcLangA[L"en-NZ"] = XC_LOCALE_NEW_ZEALAND; m_xcLangA[L"en-CA"] = XC_LOCALE_CANADA; m_xcLangA[L"ja-JP"] = XC_LOCALE_JAPAN; m_xcLangA[L"de-DE"] = XC_LOCALE_GERMANY; m_xcLangA[L"de-AT"] = XC_LOCALE_AUSTRIA; m_xcLangA[L"fr-FR"] = XC_LOCALE_FRANCE; m_xcLangA[L"fr-CA"] = XC_LOCALE_CANADA; m_xcLangA[L"es-ES"] = XC_LOCALE_SPAIN; m_xcLangA[L"es-MX"] = XC_LOCALE_MEXICO; m_xcLangA[L"it-IT"] = XC_LOCALE_ITALY; m_xcLangA[L"ko-KR"] = XC_LOCALE_KOREA; m_xcLangA[L"pt-PT"] = XC_LOCALE_PORTUGAL; m_xcLangA[L"pt-BR"] = XC_LOCALE_BRAZIL; m_xcLangA[L"ru-RU"] = XC_LOCALE_RUSSIAN_FEDERATION; m_xcLangA[L"nl-NL"] = XC_LOCALE_NETHERLANDS; m_xcLangA[L"fi-FI"] = XC_LOCALE_FINLAND; m_xcLangA[L"sv-SV"] = XC_LOCALE_SWEDEN; m_xcLangA[L"da-DA"] = XC_LOCALE_DENMARK; m_xcLangA[L"no-NO"] = XC_LOCALE_NORWAY; m_xcLangA[L"pl-PL"] = XC_LOCALE_POLAND; m_xcLangA[L"tr-TR"] = XC_LOCALE_TURKEY; m_xcLangA[L"el-EL"] = XC_LOCALE_GREECE; m_xcLangA[L"la-LAS"] = XC_LOCALE_LATIN_AMERICA; // New ones for Xbox One m_xcLangA[L"zh-SG"] = XC_LOCALE_SINGAPORE; m_xcLangA[L"Zh-CN"] = XC_LOCALE_CHINA; m_xcLangA[L"zh-HK"] = XC_LOCALE_HONG_KONG; m_xcLangA[L"zh-TW"] = XC_LOCALE_TAIWAN; m_xcLangA[L"nl-BE"] = XC_LOCALE_BELGIUM; m_xcLangA[L"da-DK"] = XC_LOCALE_DENMARK; m_xcLangA[L"fr-BE"] = XC_LOCALE_BELGIUM; m_xcLangA[L"fr-CH"] = XC_LOCALE_SWITZERLAND; m_xcLangA[L"de-CH"] = XC_LOCALE_SWITZERLAND; m_xcLangA[L"nb-NO"] = XC_LOCALE_NORWAY; m_xcLangA[L"en-GR"] = XC_LOCALE_GREECE; m_xcLangA[L"en-HK"] = XC_LOCALE_HONG_KONG; m_xcLangA[L"en-SA"] = XC_LOCALE_SAUDI_ARABIA; m_xcLangA[L"en-HU"] = XC_LOCALE_HUNGARY; m_xcLangA[L"en-IN"] = XC_LOCALE_INDIA; m_xcLangA[L"en-IL"] = XC_LOCALE_ISRAEL; m_xcLangA[L"en-SG"] = XC_LOCALE_SINGAPORE; m_xcLangA[L"en-SK"] = XC_LOCALE_SLOVAK_REPUBLIC; m_xcLangA[L"en-ZA"] = XC_LOCALE_SOUTH_AFRICA; m_xcLangA[L"en-CZ"] = XC_LOCALE_CZECH_REPUBLIC; m_xcLangA[L"en-AE"] = XC_LOCALE_UNITED_ARAB_EMIRATES; m_xcLangA[L"ja-IP"] = XC_LOCALE_JAPAN; m_xcLangA[L"es-AR"] = XC_LOCALE_ARGENTINA; m_xcLangA[L"es-CL"] = XC_LOCALE_CHILE; m_xcLangA[L"es-CO"] = XC_LOCALE_COLOMBIA; m_xcLangA[L"es-US"] = XC_LOCALE_UNITED_STATES; m_xcLangA[L"sv-SE"] = XC_LOCALE_SWEDEN; m_xcLangA[L"cs-CZ"] = XC_LOCALE_CZECH_REPUBLIC; m_xcLangA[L"el-GR"] = XC_LOCALE_GREECE; m_xcLangA[L"sk-SK"] = XC_LOCALE_SLOVAK_REPUBLIC; m_xcLangA[L"zh-HANS"] = XC_LOCALE_CHINA; m_xcLangA[L"zh-HANT"] = XC_LOCALE_CHINA; } void Game::SetTickTMSDLCFiles(bool bVal) { // 4J-PB - we need to stop the retrieval of minecraft store images from TMS // when we aren't in the DLC, since going in to Play Game will change the // title id group m_bTickTMSDLCFiles = bVal; } std::wstring Game::getFilePath(std::uint32_t packId, std::wstring filename, bool bAddDataFolder, std::wstring mountPoint) { std::wstring path = getRootPath(packId, true, bAddDataFolder, mountPoint) + filename; File f(path); if (f.exists()) { return path; } return getRootPath(packId, false, true, mountPoint) + filename; } enum ETitleUpdateTexturePacks { // eTUTP_MassEffect = 0x400, // eTUTP_Skyrim = 0x401, // eTUTP_Halo = 0x402, // eTUTP_Festive = 0x405, // eTUTP_Plastic = 0x801, // eTUTP_Candy = 0x802, // eTUTP_Fantasy = 0x803, eTUTP_Halloween = 0x804, // eTUTP_Natural = 0x805, // eTUTP_City = 0x01000806, // 4J Stu - The released City pack had a // sub-pack ID eTUTP_Cartoon = 0x807, eTUTP_Steampunk = 0x01000808, // 4J // Stu - The released Steampunk pack had a sub-pack ID }; #if defined(_WINDOWS64) std::wstring titleUpdateTexturePackRoot = L"Windows64\\DLC\\"; #else std::wstring titleUpdateTexturePackRoot = L"CU\\DLC\\"; #endif std::wstring Game::getRootPath(std::uint32_t packId, bool allowOverride, bool bAddDataFolder, std::wstring mountPoint) { std::wstring path = mountPoint; if (allowOverride) { switch (packId) { case eTUTP_Halloween: path = titleUpdateTexturePackRoot + L"Halloween Texture Pack"; break; }; File folder(path); if (!folder.exists()) { path = mountPoint; } } if (bAddDataFolder) { return path + L"\\Data\\"; } else { return path + L"\\"; } }