4jcraft/targets/app/common/Game.cpp

5970 lines
234 KiB
C++

#include "minecraft/GameHostOptions.h"
#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/Console_Debug_enum.h"
#include "app/common/DLC/DLCManager.h"
#include "app/common/DLC/DLCSkinFile.h"
#include "app/common/GameRules/GameRuleManager.h"
#include "app/common/Network/GameNetworkManager.h"
#include "app/common/Network/NetworkPlayerInterface.h"
#include "app/common/Tutorial/Tutorial.h"
#include "app/common/UI/All Platforms/UIEnums.h"
#include "app/common/UI/All Platforms/UIStructs.h"
#include "app/common/UI/Scenes/UIScene_FullscreenProgress.h"
#include "app/linux/LinuxGame.h"
#include "app/linux/Linux_UIController.h"
#include "app/linux/Stubs/winapi_stubs.h"
#include "platform/NetTypes.h"
#include "minecraft/client/SkinBox.h"
#include "platform/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 <assert.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <wchar.h>
#include <chrono>
#include <compare>
#include <cstdint>
#include <cstring>
#include <memory>
#include <mutex>
#include <sstream>
#include <string>
#include <thread>
#include <unordered_map>
#include <utility>
#include <vector>
#include "platform/sdl2/Input.h"
#include "app/common/Audio/SoundEngine.h"
#include "app/common/Colours/ColourTable.h"
#include "app/common/DLC/DLCPack.h"
#include "app/common/Localisation/StringTable.h"
#include "app/common/UI/All Platforms/ArchiveFile.h"
#include "app/common/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
Game::Game() {
GameHostOptions::init(&m_uiGameHostSettings);
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_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_bInterfaceRenderingOff = false;
// m_bHandRenderingOff = false;
m_bTutorialMode = false;
m_disconnectReason = DisconnectPacket::eDisconnect_None;
m_bLiveLinkRequired = false;
m_bChangingSessionType = false;
m_bReallyChangingSessionType = false;
// memset(m_PreviewBuffer, 0, sizeof(XSOCIAL_PREVIEWIMAGE)*XUSER_MAX_COUNT);
// m_xuidNotch moved to SkinManager
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_bDefaultCapeInstallAttempted = false;
m_bDLCInstallProcessCompleted = false;
m_bDLCInstallPending = false;
m_iTotalDLC = 0;
m_iTotalDLCInstalled = 0;
mfTrialPausedTime = 0.0f;
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_bResetNether = false;
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);
OutputDebugStringA(buf);
#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);
OutputDebugStringA(buf);
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_localizationManager.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<GAME_DEFINED_PROFILE_DATA_BYTES;i++)
// {
// pchData[i]=0xBC;
// //if(iCount==255) iCount = 0;
// }
// ProfileManager.WriteToProfile(iPad,true);
}
bool Game::LoadInventoryMenu(int iPad,
std::shared_ptr<LocalPlayer> 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<LocalPlayer> 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<LocalPlayer> 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<LocalPlayer> 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<LocalPlayer> 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> 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> inventory,
std::shared_ptr<FurnaceTileEntity> 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> inventory,
std::shared_ptr<BrewingStandTileEntity> 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<Container> inventory,
std::shared_ptr<Container> 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<Container> inventory,
std::shared_ptr<DispenserTileEntity> 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<SignTileEntity> 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> 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> inventory,
std::shared_ptr<Merchant> 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> inventory,
std::shared_ptr<HopperTileEntity> 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> inventory,
std::shared_ptr<MinecartHopper> hopper) {
bool success = true;
HopperScreenInput* initData = new HopperScreenInput();
initData->inventory = inventory;
initData->hopper = std::dynamic_pointer_cast<Container>(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> inventory,
std::shared_ptr<Container> container,
std::shared_ptr<EntityHorse> 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> inventory,
std::shared_ptr<BeaconTileEntity> 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<ServerPlayer> 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;
}
}
// Skin/Cape/FavoriteSkin methods moved to SkinManager
// 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> 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> 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<<i))
// {
// // Turn off hand rendering.
// //app.SetHandRenderingOff( true );
// }
// else
// {
// // Turn on hand rendering.
// //app.SetHandRenderingOff( false );
// }
// break;
case eDebugSetting_ShowUIConsole:
if (ulBitmask & (1 << i)) {
ui.ShowUIDebugConsole(true);
} else {
ui.ShowUIDebugConsole(false);
}
break;
case eDebugSetting_ShowUIMarketingGuide:
if (ulBitmask & (1 << i)) {
ui.ShowUIDebugMarketingGuide(true);
} else {
ui.ShowUIDebugMarketingGuide(false);
}
break;
case eDebugSetting_MobsDontAttack:
if (ulBitmask & (1 << i)) {
app.SetMobsDontAttackEnabled(true);
} else {
app.SetMobsDontAttackEnabled(false);
}
break;
case eDebugSetting_UseDpadForDebug:
if (ulBitmask & (1 << i)) {
app.SetUseDPadForDebug(true);
} else {
app.SetUseDPadForDebug(false);
}
break;
case eDebugSetting_MobsDontTick:
if (ulBitmask & (1 << i)) {
app.SetMobsDontTickEnabled(true);
} else {
app.SetMobsDontTickEnabled(false);
}
break;
}
}
}
#endif
int Game::displaySavingMessage(C4JStorage::ESavingMessage eVal,
int iPad) {
ui.ShowSavingMessage(iPad, eVal);
return 0;
}
void Game::SetActionConfirmed(void* param) {
XuiActionParam* actionInfo = (XuiActionParam*)param;
app.SetAction(actionInfo->iPad, actionInfo->action);
}
void Game::HandleXuiActions(void) {
eXuiAction eAction;
eTMSAction eTMS;
void* param;
Minecraft* pMinecraft = Minecraft::GetInstance();
std::shared_ptr<MultiplayerLocalPlayer> 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;
}
// loadMediaArchive and loadStringTable moved to ArchiveManager/LocalizationManager
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 m_debugOptions.debugArtToolsOn(
GetGameSettingsDebugMask(ProfileManager.GetPrimaryPad()));
}
#endif
void Game::SetDebugSequence(const char* pchSeq) {
InputManager.SetDebugSequence(pchSeq, [this]() -> int {
// printf("sequence matched\n");
m_debugOptions.setDebugOptions(!m_debugOptions.settingsOn());
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<std::string> 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<float>(qwDeltaTime).count();
m_Time.fAppTime = std::chrono::duration<float>(m_Time.qwAppTime).count();
}
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::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() {}
void Game::SetSpecialTutorialCompletionFlag(int iPad, int index) {
if (index >= 0 && index < 32 && GameSettingsA[iPad] != nullptr) {
GameSettingsA[iPad]->uiSpecialTutorialBitmask |= (1 << index);
}
}
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) {
GameHostOptions::set(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 GameHostOptions::get(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::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
};
int Game::TexturePackDialogReturned(
void* pParam, int iPad, C4JStorage::EMessageResult result) {
return 0;
}
std::unordered_map<PlayerUID, MOJANG_DATA*> Game::MojangData;
std::unordered_map<int, uint64_t> Game::DLCTextures_PackID;
std::unordered_map<uint64_t, DLC_INFO*> Game::DLCInfo_Trial;
std::unordered_map<uint64_t, DLC_INFO*> Game::DLCInfo_Full;
std::unordered_map<std::wstring, uint64_t> 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<uint64_t, DLC_INFO*>::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<uint64_t, DLC_INFO*>::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<int, uint64_t>::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;
}
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;
}
unsigned int Game::AddDLCRequest(eDLCMarketplaceType eType,
bool bPromote) {
// lock access
{
std::lock_guard<std::mutex> 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<std::mutex> 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<std::mutex> 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<std::mutex> 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<std::mutex> 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<std::mutex> 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<std::mutex> 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<std::mutex> 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<std::uint32_t>(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<std::mutex> 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;
}
// 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_saveManager.setAutosaveTimerTime(settingValue);
}
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
// (moved to manager class)
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"\\";
}
}