
#include "stdafx.h"

#include "..\..\Minecraft.World\Recipy.h"
#include "..\..\Minecraft.Client\Options.h"
#include "..\..\Minecraft.World\AABB.h"
#include "..\..\Minecraft.World\Vec3.h"
#include "..\MinecraftServer.h"
#include "..\MultiPlayerLevel.h"
#include "..\GameRenderer.h"
#include "..\ProgressRenderer.h"
#include "..\..\Minecraft.Client\LevelRenderer.h"
#include "..\..\Minecraft.Client\MobSkinMemTextureProcessor.h"
#include "..\..\Minecraft.Client\Minecraft.h"
#include "..\ClientConnection.h"
#include "..\MultiPlayerLocalPlayer.h"
#include "..\..\Minecraft.Client\LocalPlayer.h"
#include "..\..\Minecraft.World\Player.h"
#include "..\..\Minecraft.World\Inventory.h"
#include "..\..\Minecraft.World\Level.h"
#include "..\..\Minecraft.World\FurnaceTileEntity.h"
#include "..\..\Minecraft.World\Container.h"
#include "..\..\Minecraft.World\DispenserTileEntity.h"
#include "..\..\Minecraft.World\SignTileEntity.h"
#include "..\..\Minecraft.Client\StatsCounter.h"
#include "..\GameMode.h"
#include "..\Xbox\Social\SocialManager.h"
#include "Tutorial\TutorialMode.h"
#if defined _XBOX || defined _WINDOWS64
#include "..\..\Minecraft.Client\Xbox\XML\ATGXmlParser.h"
#include "..\..\Minecraft.Client\Xbox\XML\xmlFilesCallback.h"
#endif
#include "Minecraft_Macros.h"
#include "..\..\Minecraft.Client\PlayerList.h"
#include "..\..\Minecraft.Client\ServerPlayer.h"
#include "GameRules\ConsoleGameRules.h"
#include "GameRules\ConsoleSchematicFile.h"
#include "..\..\Minecraft.World\InputOutputStream.h"
#include "..\..\Minecraft.World\LevelSettings.h"
#include "..\User.h"
#include "..\..\Minecraft.World\LevelData.h"
#include "..\..\Minecraft.World\net.minecraft.world.entity.player.h"
#include "..\..\Minecraft.Client\EntityRenderDispatcher.h"
#include "..\..\Minecraft.World\compression.h"
#include "..\TexturePackRepository.h"
#include "..\DLCTexturePack.h"
#include "DLC\DLCPack.h"
#include "..\StringTable.h"
#ifndef _XBOX
#include "..\ArchiveFile.h"
#endif
#include "..\Minecraft.h"
#ifdef _XBOX
#include "..\Xbox\GameConfig\Minecraft.spa.h"
#include "..\Xbox\Network\NetworkPlayerXbox.h"
#include "XUI\XUI_TextEntry.h"
#include "XUI\XUI_XZP_Icons.h"
#include "XUI\XUI_PauseMenu.h"
#else
#include "UI\UI.h"
#include "UI\UIScene_PauseMenu.h"
#endif
#ifdef __PS3__
#include <sys/tty.h>
#endif
#ifdef __ORBIS__
#include <save_data_dialog.h>
#endif

#include "..\Common\Leaderboards\LeaderboardManager.h"

//CMinecraftApp app;
unsigned int CMinecraftApp::m_uiLastSignInData = 0;

const float CMinecraftApp::fSafeZoneX = 64.0f; // 5% of 1280
const float CMinecraftApp::fSafeZoneY = 36.0f; // 5% of 720

int CMinecraftApp::s_iHTMLFontSizesA[eHTMLSize_COUNT] =
{
#ifdef _XBOX
	14,12,14,24
#else
	//20,15,20,24
	20,13,20,26
#endif
};


CMinecraftApp::CMinecraftApp()
{
	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);
#ifndef _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] = NULL;
		//m_dwAdditionalModelParts[i] = 0;

		if(FAILED(XUserGetSigninInfo(i,XUSER_GET_SIGNIN_INFO_OFFLINE_XUID_ONLY ,&m_currentSigninInfo[i])))
		{
			m_currentSigninInfo[i].xuid = INVALID_XUID;
			m_currentSigninInfo[i].dwGuestNumber = 0;
		}
		DebugPrintf("Player at index %d has guest number %d\n", i,m_currentSigninInfo[i].dwGuestNumber );

		m_bRead_BannedListA[i]=false;
		SetBanListCheck(i,false);

		m_uiOpacityCountDown[i]=0;

	}
	m_eGlobalXuiAction=eAppAction_Idle;
	m_eGlobalXuiServerAction=eXuiServerAction_Idle;

	m_bResourcesLoaded=false;
	m_bGameStarted=false;
	m_bIsAppPaused=false;
	//m_bSplitScreenEnabled = false;


	m_bIntroRunning=false;
	m_eGameMode=eMode_Singleplayer;
	m_bLoadSavesFromFolderEnabled = false;
	m_bWriteSavesToFolderEnabled = false;
	//m_bInterfaceRenderingOff = false;
	//m_bHandRenderingOff = false;
	m_bTutorialMode = false;
	m_disconnectReason = DisconnectPacket::eDisconnect_None;
	m_bLiveLinkRequired = false;
	m_bChangingSessionType = false;
	m_bReallyChangingSessionType = false;

#ifdef _DEBUG_MENUS_ENABLED

#ifdef _CONTENT_PACKAGE
	m_bDebugOptions=false; // make them off by default in a content package build
#else
	m_bDebugOptions=true;
#endif
#else
	m_bDebugOptions=false;
#endif

	//ZeroMemory(m_PreviewBuffer,sizeof(XSOCIAL_PREVIEWIMAGE)*XUSER_MAX_COUNT);

	m_xuidNotch = INVALID_XUID;

	ZeroMemory(&m_InviteData,sizeof(JoinFromInviteData) );

// 	m_bRead_TMS_XUIDS_XML=false;
// 	m_bRead_TMS_DLCINFO_XML=false;

	m_pDLCFileBuffer=NULL;
	m_dwDLCFileSize=0;
	m_pBannedListFileBuffer=NULL;
	m_dwBannedListFileSize=0;

	m_bDefaultCapeInstallAttempted=false;
	m_bDLCInstallProcessCompleted=false;
	m_bDLCInstallPending=false;
	m_iTotalDLC = 0;
	m_iTotalDLCInstalled = 0;
	mfTrialPausedTime=0.0f;
	m_uiAutosaveTimer=0;
	ZeroMemory(m_pszUniqueMapName,14);


	m_bNewDLCAvailable=false;
	m_bSeenNewDLCTip=false;

	m_uiGameHostSettings=0;

	ZeroMemory(m_playerColours,MINECRAFT_NET_MAX_PLAYERS);

	m_iDLCOfferC=0;
	m_bAllDLCContentRetrieved=true;
	InitializeCriticalSection(&csDLCDownloadQueue);
	m_bAllTMSContentRetrieved=true;
	m_bTickTMSDLCFiles=true;
	InitializeCriticalSection(&csTMSPPDownloadQueue);
	InitializeCriticalSection(&csAdditionalModelParts);
	InitializeCriticalSection(&csAdditionalSkinBoxes);
	InitializeCriticalSection(&csAnimOverrideBitmask);
	InitializeCriticalSection(&csMemFilesLock);
	InitializeCriticalSection(&csMemTPDLock);

	InitializeCriticalSection(&m_saveNotificationCriticalSection);
	m_saveNotificationDepth = 0;

	m_dwRequiredTexturePackID=0;

	m_bResetNether=false;
	
#ifdef _XBOX
//	m_bTransferSavesToXboxOne=false;
//	m_uiTransferSlotC=5;
#endif	

#if (defined _CONTENT_PACAKGE) || (defined _XBOX)
	m_bUseDPadForDebug = false;
#else
	m_bUseDPadForDebug = true;
#endif

#if ( defined __PS3__ || defined __ORBIS__ || defined _DURANGO  || defined __PSVITA__)
	for(int i=0;i<XUSER_MAX_COUNT;i++)
	{
		m_eOptionsStatusA[i]=C4JStorage::eOptions_Callback_Idle;
	}
#endif

	for(int i=0;i<XUSER_MAX_COUNT;i++)
	{
		m_vBannedListA[i] = new vector<PBANNEDLISTDATA>;	
	}

	LocaleAndLanguageInit();

#ifdef _XBOX_ONE
	m_hasReachedMainMenu = false;
#endif
}



void CMinecraftApp::DebugPrintf(const char *szFormat, ...)
{

#ifndef _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 CMinecraftApp::DebugPrintf(int user, const char *szFormat, ...)
{
#ifndef _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);
#ifdef __PS3__
	unsigned int writelen;
	sys_tty_write(SYS_TTYP_USER1 + ( user - 1 ), buf, strlen(buf), &writelen );
#elif defined __PSVITA__
	switch(user)
	{
	case 0:
		{
			SceUID tty2 = sceIoOpen("tty2:", SCE_O_WRONLY, 0);
			if(tty2>=0)
			{					
				std::string string1(buf);
				sceIoWrite(tty2, string1.c_str(), string1.length());
				sceIoClose(tty2);
			}
		}
		break;
	case 1:
		{
			SceUID tty3 = sceIoOpen("tty3:", SCE_O_WRONLY, 0);
			if(tty3>=0)
			{			
				std::string string1(buf);
				sceIoWrite(tty3, string1.c_str(), string1.length());
				sceIoClose(tty3);
			}
		}
		break;
	default:
		OutputDebugStringA(buf);
		break;
	}
#else
	OutputDebugStringA(buf);
#endif
#ifndef _XBOX
	if(user == USER_UI)
	{
		ui.logDebugString(buf);
	}
#endif
#endif
}

LPCWSTR CMinecraftApp::GetString(int iID)
{
	//return L"Değişiklikler ve Yenilikler";
	//return L"ÕÕÕÕÖÖÖÖ";
	return app.m_stringTable->getString(iID);
}

void CMinecraftApp::SetAction(int iPad, eXuiAction action, LPVOID param)
{
	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 CMinecraftApp::IsAppPaused()
{
#if defined(_XBOX_ONE) || defined(__ORBIS__)
	bool paused = m_bIsAppPaused;
	EnterCriticalSection(&m_saveNotificationCriticalSection);
	if( g_NetworkManager.IsLocalGame() && g_NetworkManager.GetPlayerCount() == 1 )
	{
		paused |= m_saveNotificationDepth > 0;
	}
	LeaveCriticalSection(&m_saveNotificationCriticalSection);
	return paused;
#else
	return m_bIsAppPaused;
#endif
}

void CMinecraftApp::SetAppPaused(bool val)
{
	m_bIsAppPaused = val;
}

void CMinecraftApp::HandleButtonPresses()
{
	for(int i=0;i<4;i++)
	{
		HandleButtonPresses(i);
	}
}

void CMinecraftApp::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 CMinecraftApp::LoadInventoryMenu(int iPad,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 CMinecraftApp::LoadCreativeMenu(int iPad,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 CMinecraftApp::LoadCrafting2x2Menu(int iPad,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 CMinecraftApp::LoadCrafting3x3Menu(int iPad,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 CMinecraftApp::LoadEnchantingMenu(int iPad,shared_ptr<Inventory> inventory, int x, int y, int z, Level *level)
{
	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;

	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 CMinecraftApp::LoadFurnaceMenu(int iPad,shared_ptr<Inventory> inventory, 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 CMinecraftApp::LoadBrewingStandMenu(int iPad,shared_ptr<Inventory> inventory, 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 CMinecraftApp::LoadContainerMenu(int iPad,shared_ptr<Container> inventory, 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 CMinecraftApp::LoadTrapMenu(int iPad,shared_ptr<Container> inventory, 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 CMinecraftApp::LoadSignEntryMenu(int iPad,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 CMinecraftApp::LoadRepairingMenu(int iPad,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 CMinecraftApp::LoadTradingMenu(int iPad, shared_ptr<Inventory> inventory, shared_ptr<Merchant> trader, Level *level)
{
	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;
}


//////////////////////////////////////////////
// GAME SETTINGS
//////////////////////////////////////////////
void CMinecraftApp::InitGameSettings()
{
	for(int i=0;i<XUSER_MAX_COUNT;i++)
	{
#if (defined __PS3__ || defined __ORBIS__ || defined _DURANGO  || defined __PSVITA__)
		GameSettingsA[i]=(GAME_SETTINGS *)StorageManager.GetGameDefinedProfileData(i);
#else
		GameSettingsA[i]=(GAME_SETTINGS *)ProfileManager.GetGameDefinedProfileData(i);
#endif
		// 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// || defined __PSVITA__
		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);
#elif defined __PS3__ || defined __ORBIS__ || defined _DURANGO  || defined __PSVITA__
		C4JStorage::PROFILESETTINGS *pProfileSettings=StorageManager.GetDashboardProfileSettings(i);
		// 4J-PB - don't cause an options write to happen here
		SetDefaultOptions(pProfileSettings,i,false);

#endif
	}
}

#if (defined __PS3__ || defined __ORBIS__ || defined _DURANGO  || defined __PSVITA__)
int CMinecraftApp::SetDefaultOptions(C4JStorage::PROFILESETTINGS *pSettings,const int iPad,bool bWriteProfile)
#else
int CMinecraftApp::SetDefaultOptions(C_4JProfile::PROFILESETTINGS *pSettings,const int iPad)
#endif
{
	SetGameSettings(iPad,eGameSetting_MusicVolume,DEFAULT_VOLUME_LEVEL);
	SetGameSettings(iPad,eGameSetting_SoundFXVolume,DEFAULT_VOLUME_LEVEL);
	SetGameSettings(iPad,eGameSetting_Gamma,100);

	// 4J-PB - Don't reset the difficult level if we're in-game
	if(Minecraft::GetInstance()->level==NULL)
	{
		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;

	// 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 __PS3__
	// PS3DEC13
	SetGameSettings(iPad,eGameSetting_PS3_EULA_Read,0); // EULA not read

	// PS3 1.05 - added Greek
	GameSettingsA[iPad]->ucLanguage = MINECRAFT_LANGUAGE_DEFAULT; // use the system language
//#endif

#if (defined __PS3__ || defined __ORBIS__ || defined _DURANGO  || defined __PSVITA__)
	GameSettingsA[iPad]->bSettingsChanged=bWriteProfile;
#endif

	return 0;
}

#if ( defined  __PS3__  || defined __ORBIS__ || defined _DURANGO  || defined __PSVITA__)
int CMinecraftApp::DefaultOptionsCallback(LPVOID pParam,C4JStorage::PROFILESETTINGS *pSettings, const int iPad)
#else
int CMinecraftApp::DefaultOptionsCallback(LPVOID pParam,C_4JProfile::PROFILESETTINGS *pSettings, const int iPad)
#endif
{
	CMinecraftApp *pApp=(CMinecraftApp *)pParam;

	// flag the default options to be set

	pApp->DebugPrintf("Setting default options for player %d", iPad);
	pApp->SetAction(iPad,eAppAction_SetDefaultOptions, (LPVOID)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;
}

#if ( defined  __PS3__  || defined __ORBIS__ || defined _DURANGO  || defined __PSVITA__)

#ifdef __ORBIS__
int CMinecraftApp::OptionsDataCallback(LPVOID pParam,int iPad,unsigned short usVersion,C4JStorage::eOptionsCallback eStatus,int iBlocksRequired)
{
	CMinecraftApp *pApp=(CMinecraftApp *)pParam;
	pApp->m_eOptionsStatusA[iPad]=eStatus;
	pApp->m_eOptionsBlocksRequiredA[iPad]=iBlocksRequired;
	return 0;
}

int CMinecraftApp::GetOptionsBlocksRequired(int iPad)
{
	return m_eOptionsBlocksRequiredA[iPad];
}

#else
int CMinecraftApp::OptionsDataCallback(LPVOID pParam,int iPad,unsigned short usVersion,C4JStorage::eOptionsCallback eStatus)
{
	CMinecraftApp *pApp=(CMinecraftApp *)pParam;
	pApp->m_eOptionsStatusA[iPad]=eStatus;
	return 0;
}
#endif

C4JStorage::eOptionsCallback CMinecraftApp::GetOptionsCallbackStatus(int iPad)
{
	return m_eOptionsStatusA[iPad];
}

void CMinecraftApp::SetOptionsCallbackStatus(int iPad, C4JStorage::eOptionsCallback eStatus)
{
	m_eOptionsStatusA[iPad]=eStatus;
}
#endif

int CMinecraftApp::OldProfileVersionCallback(LPVOID 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)
	{
#ifdef _XBOX
	case PROFILE_VERSION_1:
	case PROFILE_VERSION_2:
		// need to fill in values for the new profile data. No need to save the profile - that'll happen if they get changed, or if the auto save for the profile kicks in
		{	
			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

			// 4J-PB - Let's also award all the achievements they have again because of the profile bug that seemed to stop the awards of some
			// Changing this to check the system achievements at sign-in and award any that the game says we have and the system says we haven't
			//ProfileManager.ReAwardAchievements(iPad);

			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)
			// TU6
			pGameSettings->uiBitmaskValues&=~GAMESETTING_BEDROCKFOG;			//eGameSetting_BedrockFog - off
			pGameSettings->uiBitmaskValues|=GAMESETTING_DISPLAYHUD;				//eGameSetting_DisplayHUD - on
			pGameSettings->uiBitmaskValues|=GAMESETTING_DISPLAYHAND;			//eGameSetting_DisplayHand - on
			// TU7
			pGameSettings->uiBitmaskValues|=GAMESETTING_CUSTOMSKINANIM;			//eGameSetting_CustomSkinAnim - on
			// TU9
			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;

			// PS3 1.05 - added Greek
			pGameSettings->ucLanguage = MINECRAFT_LANGUAGE_DEFAULT; // use the system language
		}
		break;
	case PROFILE_VERSION_3:

		{	
			GAME_SETTINGS *pGameSettings=(GAME_SETTINGS *)pucData;
			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)
			// TU6
			pGameSettings->uiBitmaskValues&=~GAMESETTING_BEDROCKFOG;	//eGameSetting_BedrockFog - off
			pGameSettings->uiBitmaskValues|=GAMESETTING_DISPLAYHUD;		//eGameSetting_DisplayHUD - on
			pGameSettings->uiBitmaskValues|=GAMESETTING_DISPLAYHAND;		//eGameSetting_DisplayHand - on
			// TU7
			pGameSettings->uiBitmaskValues|=GAMESETTING_CUSTOMSKINANIM;		//eGameSetting_CustomSkinAnim - on
			// TU9
			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;

			// PS3 1.05 - added Greek
			pGameSettings->ucLanguage = MINECRAFT_LANGUAGE_DEFAULT; // use the system language

		}
		break;
	case PROFILE_VERSION_4:
		{
			GAME_SETTINGS *pGameSettings=(GAME_SETTINGS *)pucData;
		
			pGameSettings->uiBitmaskValues&=~GAMESETTING_BEDROCKFOG;	//eGameSetting_BedrockFog - off
			pGameSettings->uiBitmaskValues|=GAMESETTING_DISPLAYHUD;		//eGameSetting_DisplayHUD - on
			pGameSettings->uiBitmaskValues|=GAMESETTING_DISPLAYHAND;		//eGameSetting_DisplayHand - on
			// TU7
			pGameSettings->uiBitmaskValues|=GAMESETTING_CUSTOMSKINANIM;		//eGameSetting_CustomSkinAnim - on
			// TU9
			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

			// Set the online flag to on, so it's not saved if a game starts offline when the user didn't change it to be offline (xbox disconnected from LIVE)
			pGameSettings->uiBitmaskValues|=GAMESETTING_ONLINE;					//eGameSetting_GameSetting_Online - 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;

			// PS3 1.05 - added Greek
			pGameSettings->ucLanguage = MINECRAFT_LANGUAGE_DEFAULT; // use the system language

		}

		break;
	case PROFILE_VERSION_5:
		{
			GAME_SETTINGS *pGameSettings=(GAME_SETTINGS *)pucData;

			// reset the display new message counter
			pGameSettings->uiBitmaskValues|=GAMESETTING_DISPLAYUPDATEMSG;		//eGameSetting_DisplayUpdateMessage (counter)
			// TU7
			pGameSettings->uiBitmaskValues|=GAMESETTING_CUSTOMSKINANIM;		//eGameSetting_CustomSkinAnim - on
			// TU9
			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
			// Set the online flag to on, so it's not saved if a game starts offline when the user didn't change it to be offline (xbox disconnected from LIVE)
			pGameSettings->uiBitmaskValues|=GAMESETTING_ONLINE;					//eGameSetting_GameSetting_Online - 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;

			// PS3 1.05 - added Greek
			pGameSettings->ucLanguage = MINECRAFT_LANGUAGE_DEFAULT; // use the system language


		}

		break;
	case PROFILE_VERSION_6:
		{
			GAME_SETTINGS *pGameSettings=(GAME_SETTINGS *)pucData;

			// Added gui size for splitscreen and fullscreen
			// Added death messages toggle

			// reset the display new message counter
			pGameSettings->uiBitmaskValues|=GAMESETTING_DISPLAYUPDATEMSG;		//eGameSetting_DisplayUpdateMessage (counter)
			// TU9
			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
			// Set the online flag to on, so it's not saved if a game starts offline when the user didn't change it to be offline (xbox disconnected from LIVE)
			pGameSettings->uiBitmaskValues|=GAMESETTING_ONLINE;					//eGameSetting_GameSetting_Online - 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;

			// PS3 1.05 - added Greek
			pGameSettings->ucLanguage = MINECRAFT_LANGUAGE_DEFAULT; // use the system language


		}

		break;

	case PROFILE_VERSION_7:
		{		
			GAME_SETTINGS *pGameSettings=(GAME_SETTINGS *)pucData;
			// reset the display new message counter
			pGameSettings->uiBitmaskValues|=GAMESETTING_DISPLAYUPDATEMSG;		//eGameSetting_DisplayUpdateMessage (counter)

			// 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;

			// PS3 1.05 - added Greek
			pGameSettings->ucLanguage = MINECRAFT_LANGUAGE_DEFAULT; // use the system language


		}
		break;
#endif
	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_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->ucLanguage = MINECRAFT_LANGUAGE_DEFAULT; // use the system language
		}
		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");
	#ifndef _CONTENT_PACKAGE
	//		__debugbreak();
	#endif

			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 CMinecraftApp::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 CMinecraftApp::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);
#ifdef _WINDOWS64
			extern void Windows64_UpdateGamma(unsigned short);
			Windows64_UpdateGamma((unsigned short)fVal);
#endif
		}				

		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!=NULL;

			// 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!=NULL;

			// 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_VAR(it3, players->players.begin()); it3 != players->players.end(); ++it3)
				{
					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( BYTE idx = 0; idx < XUSER_MAX_COUNT; ++idx)
		{
			if(pMinecraft->localplayers[idx] != NULL)
			{
				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!=NULL;

			// 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;
	}
}

void CMinecraftApp::SetPlayerSkin(int iPad,const wstring &name)
{
	DWORD skinId = app.getSkinIdFromPath(name);

	SetPlayerSkin(iPad,skinId);
}

void CMinecraftApp::SetPlayerSkin(int iPad,DWORD dwSkinId)
{
	DebugPrintf("Setting skin for %d to %08X\n", iPad, dwSkinId);

	GameSettingsA[iPad]->dwSelectedSkin = dwSkinId;
	GameSettingsA[iPad]->bSettingsChanged = true;

	TelemetryManager->RecordSkinChanged(iPad, GameSettingsA[iPad]->dwSelectedSkin);

	if(Minecraft::GetInstance()->localplayers[iPad]!=NULL) Minecraft::GetInstance()->localplayers[iPad]->setAndBroadcastCustomSkin(dwSkinId);
}


wstring CMinecraftApp::GetPlayerSkinName(int iPad)
{
	return app.getSkinPathFromId(GameSettingsA[iPad]->dwSelectedSkin);
}

DWORD CMinecraftApp::GetPlayerSkinId(int iPad)
{
	// 4J-PB -check the user has rights to use this skin - they may have had at some point but the entitlement has been removed.
	DLCPack *Pack=NULL;
	DLCSkinFile *skinFile=NULL;
	DWORD dwSkin=GameSettingsA[iPad]->dwSelectedSkin;
	wchar_t chars[256];

	if( GET_IS_DLC_SKIN_FROM_BITMASK(dwSkin) )
	{
		// 4J Stu - DLC skins are numbered using decimal rather than hex to make it easier to number manually
		swprintf(chars, 256, L"dlcskin%08d.png", GET_DLC_SKIN_ID_FROM_BITMASK(dwSkin));
	
		Pack=app.m_dlcManager.getPackContainingSkin(chars);	

		if(Pack)
		{
			skinFile = Pack->getSkinFile(chars);

			bool bSkinIsFree = skinFile->getParameterAsBool( DLCManager::e_DLCParamType_Free );
			bool bLicensed = Pack->hasPurchasedFile( DLCManager::e_DLCType_Skin, skinFile->getPath() );

			if(bSkinIsFree || bLicensed)
			{
				return dwSkin;
			}
			else
			{
				return 0;
			}
		}
	}


	return dwSkin;
}

 DWORD CMinecraftApp::GetAdditionalModelParts(int iPad)
 {
	return m_dwAdditionalModelParts[iPad];
 }


void CMinecraftApp::SetPlayerCape(int iPad,const wstring &name)
{
	DWORD capeId = Player::getCapeIdFromPath(name);

	SetPlayerCape(iPad,capeId);
}

void CMinecraftApp::SetPlayerCape(int iPad,DWORD dwCapeId)
{
	DebugPrintf("Setting cape for %d to %08X\n", iPad, dwCapeId);

	GameSettingsA[iPad]->dwSelectedCape = dwCapeId;
	GameSettingsA[iPad]->bSettingsChanged = true;

	//SentientManager.RecordSkinChanged(iPad, GameSettingsA[iPad]->dwSelectedSkin);

	if(Minecraft::GetInstance()->localplayers[iPad]!=NULL) Minecraft::GetInstance()->localplayers[iPad]->setAndBroadcastCustomCape(dwCapeId);
}

wstring CMinecraftApp::GetPlayerCapeName(int iPad)
{
	return Player::getCapePathFromId(GameSettingsA[iPad]->dwSelectedCape);
}

DWORD CMinecraftApp::GetPlayerCapeId(int iPad)
{
	return GameSettingsA[iPad]->dwSelectedCape;
}

void CMinecraftApp::SetPlayerFavoriteSkin(int iPad, int iIndex,unsigned int uiSkinID)
{
	DebugPrintf("Setting favorite skin for %d to %08X\n", iPad, uiSkinID);

	GameSettingsA[iPad]->uiFavoriteSkinA[iIndex] = uiSkinID;
	GameSettingsA[iPad]->bSettingsChanged = true;
}

unsigned int CMinecraftApp::GetPlayerFavoriteSkin(int iPad,int iIndex)
{
	return GameSettingsA[iPad]->uiFavoriteSkinA[iIndex];
}

unsigned char CMinecraftApp::GetPlayerFavoriteSkinsPos(int iPad)
{
	return GameSettingsA[iPad]->ucCurrentFavoriteSkinPos;
}

void CMinecraftApp::SetPlayerFavoriteSkinsPos(int iPad, int iPos)
{
	GameSettingsA[iPad]->ucCurrentFavoriteSkinPos=(unsigned char)iPos;
	GameSettingsA[iPad]->bSettingsChanged = true;
}

unsigned int CMinecraftApp::GetPlayerFavoriteSkinsCount(int iPad)
{
	unsigned int uiCount=0;
	for(int i=0;i<MAX_FAVORITE_SKINS;i++)
	{
		if(GameSettingsA[iPad]->uiFavoriteSkinA[i]!=0xFFFFFFFF)
		{
			uiCount++;
		}
		else
		{
			break;
		}
	}
	return uiCount;
}

void CMinecraftApp::ValidateFavoriteSkins(int iPad)
{
	unsigned int uiCount=GetPlayerFavoriteSkinsCount(iPad);
	
	// remove invalid skins
	unsigned int uiValidSkin=0;
	wchar_t chars[256];

	for(unsigned int i=0;i<uiCount;i++)
	{
		// get the pack number from the skin id
		swprintf(chars, 256, L"dlcskin%08d.png", app.GetPlayerFavoriteSkin(iPad,i));

		// Also check they haven't reverted to a trial pack
		DLCPack *pDLCPack=app.m_dlcManager.getPackContainingSkin(chars);

		if(pDLCPack!=NULL)
		{
			// 4J-PB - We should let players add the free skins to their favourites as well!
			//DLCFile *pDLCFile=pDLCPack->getFile(DLCManager::e_DLCType_Skin,chars);
			DLCSkinFile *pSkinFile = pDLCPack->getSkinFile(chars);

			if( pDLCPack->hasPurchasedFile(DLCManager::e_DLCType_Skin, L"") || (pSkinFile && pSkinFile->isFree()))
			{
				GameSettingsA[iPad]->uiFavoriteSkinA[uiValidSkin++]=GameSettingsA[iPad]->uiFavoriteSkinA[i];			
			}
		}
	}

	for(unsigned int i=uiValidSkin;i<MAX_FAVORITE_SKINS;i++)
	{
		GameSettingsA[iPad]->uiFavoriteSkinA[i]=0xFFFFFFFF;
	}
}

// Mash-up pack worlds
void CMinecraftApp::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 CMinecraftApp::SetMinecraftLanguage(int iPad, unsigned char ucLanguage)
{
	GameSettingsA[iPad]->ucLanguage = ucLanguage; 
	GameSettingsA[iPad]->bSettingsChanged = true;
}

void CMinecraftApp::EnableMashupPackWorlds(int iPad)
{
	GameSettingsA[iPad]->uiMashUpPackWorldsDisplay=0xFFFFFFFF;
	GameSettingsA[iPad]->bSettingsChanged = true;
}

unsigned int CMinecraftApp::GetMashupPackWorlds(int iPad)
{
	return GameSettingsA[iPad]->uiMashUpPackWorldsDisplay;
}

unsigned char CMinecraftApp::GetMinecraftLanguage(int iPad)
{
	// if there are no game settings read yet, return the default language
	if(GameSettingsA[iPad]==NULL)
	{
		return 0;
	}
	else
	{
		return GameSettingsA[iPad]->ucLanguage;
	}
}

void CMinecraftApp::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 CMinecraftApp::GetGameSettings(eGameSetting eVal)
{
	int iPad=ProfileManager.GetPrimaryPad();

	return GetGameSettings(iPad,eVal);
}

unsigned char CMinecraftApp::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 CMinecraftApp::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)
			{
#if ( defined __PS3__ || defined __ORBIS__ || defined _DURANGO || defined __PSVITA__ )
				StorageManager.WriteToProfile(i,true, bOverride5MinuteTimer);
#else
				ProfileManager.WriteToProfile(i,true, bOverride5MinuteTimer);
#endif
				GameSettingsA[i]->bSettingsChanged=false;
			}
		}
	}
	else
	{
		if(GameSettingsA[iPad]->bSettingsChanged)
		{
#if ( defined  __PS3__ || defined __ORBIS__ || defined _DURANGO || defined __PSVITA__)
			StorageManager.WriteToProfile(iPad,true, bOverride5MinuteTimer);
#else
			ProfileManager.WriteToProfile(iPad,true, bOverride5MinuteTimer);
#endif
			GameSettingsA[iPad]->bSettingsChanged=false;
		}
	}
}

void CMinecraftApp::ClearGameSettingsChangedFlag(int iPad)
{
	GameSettingsA[iPad]->bSettingsChanged=false;
}

///////////////////////////
//
// Remove the debug settings in the content package build
//
////////////////////////////
#ifndef _DEBUG_MENUS_ENABLED
unsigned int CMinecraftApp::GetGameSettingsDebugMask(int iPad,bool bOverridePlayer) //bOverridePlayer is to force the send for the server to get the read options
{
	return 0;
}

void CMinecraftApp::SetGameSettingsDebugMask(int iPad, unsigned int uiVal)
{
}

void CMinecraftApp::ActionDebugMask(int iPad,bool bSetAllClear)
{
}

#else

unsigned int CMinecraftApp::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;

	shared_ptr<Player> player = Minecraft::GetInstance()->localplayers[iPad];

	if(bOverridePlayer || player==NULL)
	{
		return  GameSettingsA[iPad]->uiDebugBitmask;
	}
	else
	{
		return player->GetDebugOptions();
	}
}


void CMinecraftApp::SetGameSettingsDebugMask(int iPad, unsigned int uiVal)
{
#ifndef _CONTENT_PACKAGE
	GameSettingsA[iPad]->bSettingsChanged=true;
	GameSettingsA[iPad]->uiDebugBitmask=uiVal;

	// update the value so the network server can use it
	shared_ptr<Player> player = Minecraft::GetInstance()->localplayers[iPad];

	if(player)
	{
		Minecraft::GetInstance()->localgameModes[iPad]->handleDebugOptions(uiVal,player);
	}
#endif
}

void CMinecraftApp::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 CMinecraftApp::DisplaySavingMessage(void *pParam, C4JStorage::ESavingMessage eVal, int iPad)
{
	//CMinecraftApp* pClass = (CMinecraftApp*)pParam;

	ui.ShowSavingMessage(iPad, eVal);

	return 0;
}

void CMinecraftApp::SetActionConfirmed(LPVOID param)
{
	XuiActionParam *actionInfo = (XuiActionParam *)param;
	app.SetAction(actionInfo->iPad, actionInfo->action);
}


void CMinecraftApp::HandleXuiActions(void)
{
	eXuiAction eAction;
	eTMSAction eTMS;
	LPVOID param;
	Minecraft *pMinecraft=Minecraft::GetInstance();
	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
			{
				UINT uiIDA[1];
				uiIDA[0]=IDS_CONFIRM_OK;
				C4JStorage::EMessageResult result = ui.RequestMessageBox( IDS_CANT_PLACE_NEAR_SPAWN_TITLE, IDS_CANT_PLACE_NEAR_SPAWN_TEXT, uiIDA,1,XUSER_INDEX_ANY,NULL,NULL, app.GetStringTable());
				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())
				{
					// If this is the trial game, do an upsell
					if(ProfileManager.IsFullVersion())
					{

						// flag the render to capture the screenshot for the save
						SetAction(i,eAppAction_SaveGameCapturedThumbnail);
					}
					else
					{
						// ask the player if they would like to upgrade, or they'll lose the level
					
						UINT uiIDA[2];
						uiIDA[0]=IDS_CONFIRM_OK;
						uiIDA[1]=IDS_CONFIRM_CANCEL;
						ui.RequestMessageBox(IDS_UNLOCK_TITLE, IDS_UNLOCK_TOSAVE_TEXT, uiIDA, 2,i,&CMinecraftApp::UnlockFullSaveReturned,this,app.GetStringTable());
					}
				}

				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()==NULL)
				{
					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 = (LPVOID)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
#ifdef _XBOX
					// Temporarily make this scene fullscreen
					CXuiSceneBase::SetPlayerBaseScenePosition( ProfileManager.GetPrimaryPad(), CXuiSceneBase::e_BaseScene_Fullscreen );
#endif

					ui.NavigateToScene(ProfileManager.GetPrimaryPad(),eUIScene_FullscreenProgress, loadingParams , eUILayer_Fullscreen, eUIGroup_Fullscreen);

				}
				break;
			case eAppAction_AutosaveSaveGameCapturedThumbnail:

				{				
					app.SetAutosaveTimerTime();
					SetAction(i,eAppAction_Idle);

#if defined(_XBOX_ONE) || defined(__ORBIS__)
					app.SetXuiServerAction(ProfileManager.GetPrimaryPad(),eXuiServerAction_AutoSaveGame);

					if(app.GetGameHostOption(eGameHostOption_DisableSaving)) StorageManager.SetSaveDisabled(true);
#else
					// 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()] != NULL) 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 = (LPVOID)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
#ifdef _XBOX
					// Temporarily make this scene fullscreen
					CXuiSceneBase::SetPlayerBaseScenePosition( ProfileManager.GetPrimaryPad(), CXuiSceneBase::e_BaseScene_Fullscreen );
#endif

					ui.NavigateToScene(ProfileManager.GetPrimaryPad(),eUIScene_FullscreenProgress, loadingParams , eUILayer_Fullscreen, eUIGroup_Fullscreen);
#endif
				}
				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...
#if (defined __PS3__ || defined __ORBIS__ || defined _DURANGO  || defined __PSVITA__)
					StorageManager.ForceQueuedProfileWrites(i);
					LeaderboardManager::Instance()->OpenSession();
					for (int j = 0; j < XUSER_MAX_COUNT; j++)
					{
						if( ProfileManager.IsSignedIn(j) )
						{
							app.DebugPrintf("Stats save for an offline game for the player at index %d\n", 0);
							Minecraft::GetInstance()->forceStatsSave(j);
						}
					}
					LeaderboardManager::Instance()->CloseSession();
#else
					ProfileManager.ForceQueuedProfileWrites(i);
#endif

					// 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);

#ifdef _XBOX
					// tell the xui scenes a splitscreen player left - has to come after removeLocalPlayerIdx which calls updatePlayerViewportAssignments
					XUIMessage xuiMsg;
					CustomMessage_Splitscreenplayer_Struct myMsgData;
					CustomMessage_Splitscreenplayer( &xuiMsg, &myMsgData, false);

					// send the message
					for(int idx=0;idx<XUSER_MAX_COUNT;idx++)
					{
						if((i!=idx) && (pMinecraft->localplayers[idx]!=NULL))
						{
							XuiBroadcastMessage( CXuiSceneBase::GetPlayerBaseScene(idx), &xuiMsg );
						}
					}
#endif

#ifndef _XBOX
					// Wipe out the tooltips
					ui.SetTooltips(i, -1);
#endif

					// 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);
								}
							}
						}
					}
				
#ifdef _DURANGO
					ProfileManager.RemoveGamepadFromGame(i);
#endif	
				
					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...
#if (defined __PS3__ || defined __ORBIS__ || defined _DURANGO  || defined __PSVITA__)
					StorageManager.ForceQueuedProfileWrites(i);
#else
					ProfileManager.ForceQueuedProfileWrites(i);
#endif	
					// 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);

#ifdef _XBOX
					// tell the xui scenes a splitscreen player left - has to come after removeLocalPlayerIdx which calls updatePlayerViewportAssignments
					XUIMessage xuiMsg;
					CustomMessage_Splitscreenplayer_Struct myMsgData;
					CustomMessage_Splitscreenplayer( &xuiMsg, &myMsgData, false);

					// send the message
					for(int idx=0;idx<XUSER_MAX_COUNT;idx++)
					{
						if((i!=idx) && (pMinecraft->localplayers[idx]!=NULL))
						{
							XuiBroadcastMessage( CXuiSceneBase::GetPlayerBaseScene(idx), &xuiMsg );
						}
					}
#endif

#ifndef _XBOX
					// Wipe out the tooltips
					ui.SetTooltips(i, -1);
#endif

					// 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;

#ifdef __ORBIS__
			case eAppAction_OptionsSaveNoSpace:
				{
					SetAction(i,eAppAction_Idle);

					SceSaveDataDialogParam param;
					SceSaveDataDialogSystemMessageParam sysParam;
					SceSaveDataDialogItems items;
					SceSaveDataDirName dirName;

					sceSaveDataDialogParamInitialize(&param);
					param.mode = SCE_SAVE_DATA_DIALOG_MODE_SYSTEM_MSG;
					param.dispType = SCE_SAVE_DATA_DIALOG_TYPE_SAVE;
					memset(&sysParam,0,sizeof(sysParam));
					param.sysMsgParam = &sysParam;
					param.sysMsgParam->sysMsgType = SCE_SAVE_DATA_DIALOG_SYSMSG_TYPE_NOSPACE_CONTINUABLE;
					param.sysMsgParam->value = app.GetOptionsBlocksRequired(i);
					memset(&items, 0, sizeof(items));
					param.items = &items;
					param.items->userId = ProfileManager.getUserID(i);

					int ret = sceSaveDataDialogInitialize();
					ret = sceSaveDataDialogOpen(&param);

					app.SetOptionsSaveDataDialogRunning(true);//m_bOptionsSaveDataDialogRunning = true;
					//pClass->m_eSaveIncompleteType = saveIncompleteType;

					//StorageManager.SetSaveDisabled(true);
					//pClass->EnterSaveNotificationSection();

				}
				break;
#endif

			case eAppAction_ExitWorld:

				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...
#if (defined __PS3__ || defined __ORBIS__  || defined _DURANGO  || defined __PSVITA__)
				StorageManager.ForceQueuedProfileWrites();
				LeaderboardManager::Instance()->OpenSession();
				for (int j = 0; j < XUSER_MAX_COUNT; j++)
				{
					if( ProfileManager.IsSignedIn(j) )
					{
						app.DebugPrintf("Stats save for an offline game for the player at index %d\n", 0);
						Minecraft::GetInstance()->forceStatsSave(j);
					}
				}
				LeaderboardManager::Instance()->CloseSession(); 
#elif (defined _XBOX)
				ProfileManager.ForceQueuedProfileWrites();
#endif

				// 4J-PB - cancel any possible string verifications queued with LIVE
				//InputManager.CancelAllVerifyInProgress();

				if(ProfileManager.IsFullVersion())
				{

					// 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);

#ifdef _DURANGO
						ProfileManager.RemoveGamepadFromGame(i);
#endif	
						SetAction(i,eAppAction_Idle);
						return;
					}
					// flag to capture the save thumbnail
					SetAction(i,eAppAction_ExitWorldCapturedThumbnail, param);
				}
				else
				{
					// ask the player if they would like to upgrade, or they'll lose the level
					UINT uiIDA[2];
					uiIDA[0]=IDS_CONFIRM_OK;
					uiIDA[1]=IDS_CONFIRM_CANCEL;
					ui.RequestMessageBox(IDS_UNLOCK_TITLE, IDS_UNLOCK_TOSAVE_TEXT, uiIDA, 2, i,&CMinecraftApp::UnlockFullExitReturned,this,app.GetStringTable());
				}

				// 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);
							}
							TelemetryManager->RecordLevelExit(j, eSen_LevelExitStatus_Exited);
						}
					}
				}
				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);
					}
					TelemetryManager->RecordLevelExit(i, eSen_LevelExitStatus_Exited);
				}
				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)
					{
#ifdef _XBOX
						app.TutorialSceneNavigateBack(idx,true);
#endif
						
						// 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 != NULL) ? TRUE : FALSE;
					completionData->bShowTips = (param != NULL) ? 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)
					{
#ifdef _XBOX
						app.TutorialSceneNavigateBack(idx,true);
#endif
						
						// 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 = (LPVOID)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 != NULL && 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 != NULL && 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
// 					UINT uiIDA[1];
// 					uiIDA[0]=IDS_CONFIRM_OK;
// 
// 					ui.RequestMessageBox(IDS_RETURNEDTOMENU_TITLE, IDS_RETURNEDTOTITLESCREEN_TEXT, uiIDA, 1, i,&CMinecraftApp::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 i = 0; i < pMinecraft->levels.length; i++)
								{
									if (pMinecraft->levels.data[i] != 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();
									UINT uiIDA[1];
									uiIDA[0]=IDS_CONFIRM_OK;

									ui.RequestMessageBox(g_NetworkManager.CorrectErrorIDS(IDS_CONNECTION_LOST), g_NetworkManager.CorrectErrorIDS(IDS_CONNECTION_LOST_LIVE), uiIDA, 1, i,&CMinecraftApp::EthernetDisconnectReturned,this, app.GetStringTable());
								}
								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();
							UINT uiIDA[1];
							uiIDA[0]=IDS_CONFIRM_OK;

							ui.RequestMessageBox(g_NetworkManager.CorrectErrorIDS(IDS_CONNECTION_LOST), g_NetworkManager.CorrectErrorIDS(IDS_CONNECTION_LOST_LIVE), uiIDA, 1, i,&CMinecraftApp::EthernetDisconnectReturned,this, app.GetStringTable());
						}
					}
				}
				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)
						{
#ifdef _XBOX
							app.TutorialSceneNavigateBack(idx,true);
#endif
						
							// 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 = &CMinecraftApp::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);
					UINT uiIDA[2];
					uiIDA[0]=IDS_UNLOCK_TITLE;
					uiIDA[1]=IDS_EXIT_GAME;

					ui.RequestMessageBox(IDS_TRIALOVER_TITLE, IDS_TRIALOVER_TEXT, uiIDA, 2, i,&CMinecraftApp::TrialOverReturned,this,app.GetStringTable());
				}
				break;

				// INVITES
			case eAppAction_DashboardTrialJoinFromInvite:
				{						
					TelemetryManager->RecordUpsellPresented(i, eSen_UpsellID_Full_Version_Of_Game, app.m_dwOfferID);

					SetAction(i,eAppAction_Idle);
					UINT uiIDA[2];
					uiIDA[0]=IDS_CONFIRM_OK;
					uiIDA[1]=IDS_CONFIRM_CANCEL;

					ui.RequestMessageBox(IDS_UNLOCK_TITLE, IDS_UNLOCK_ACCEPT_INVITE, uiIDA, 2, i,&CMinecraftApp::UnlockFullInviteReturned,this,app.GetStringTable());
				}
				break;
			case eAppAction_ExitAndJoinFromInvite:
				{					
					UINT uiIDA[3];

					SetAction(i,eAppAction_Idle);
					// Check the player really wants to do this

#if defined(_XBOX_ONE) || defined(__ORBIS__)
					// Show save option is saves ARE disabled
					if(ProfileManager.IsFullVersion() && 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.RequestMessageBox(IDS_EXIT_GAME, IDS_CONFIRM_LEAVE_VIA_INVITE, uiIDA, 3, i,&CMinecraftApp::ExitAndJoinFromInviteSaveDialogReturned,this, app.GetStringTable(), 0, 0, false);
					}
					else
#else
					if(ProfileManager.IsFullVersion() && !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.RequestMessageBox(IDS_EXIT_GAME, IDS_CONFIRM_LEAVE_VIA_INVITE, uiIDA, 3, i,&CMinecraftApp::ExitAndJoinFromInviteSaveDialogReturned,this, app.GetStringTable(), 0, 0, false);
					}
					else
#endif
					{
						if(!ProfileManager.IsFullVersion())
						{
							TelemetryManager->RecordUpsellPresented(i, eSen_UpsellID_Full_Version_Of_Game, app.m_dwOfferID);

							// upsell
							uiIDA[0]=IDS_CONFIRM_OK;
							uiIDA[1]=IDS_CONFIRM_CANCEL;
							ui.RequestMessageBox(IDS_UNLOCK_TITLE, IDS_UNLOCK_ACCEPT_INVITE, uiIDA, 2, i,&CMinecraftApp::UnlockFullInviteReturned,this,app.GetStringTable());
						}
						else
						{						
							uiIDA[0]=IDS_CONFIRM_CANCEL;
							uiIDA[1]=IDS_CONFIRM_OK;
							ui.RequestMessageBox(IDS_EXIT_GAME, IDS_CONFIRM_LEAVE_VIA_INVITE, uiIDA, 2,i,&CMinecraftApp::ExitAndJoinFromInvite,this,app.GetStringTable(), 0, 0, false);
						}
					}
				}
				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)
					{
#ifdef _XBOX
						app.TutorialSceneNavigateBack(idx,true);
#endif
						
						// 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=NULL;

					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
#ifndef _XBOX
						pMinecraft->soundEngine->SetStreamingSounds(eStream_Overworld_Calm1,eStream_Overworld_piano3,
							eStream_Nether1,eStream_Nether4,
							eStream_end_dragon,eStream_end_end,
							eStream_CD_1);
#endif
						pMinecraft->soundEngine->playStreaming(L"", 0, 0, 0, 1, 1);

#ifdef _XBOX
						if(pDLCTexPack->m_pStreamedWaveBank!=NULL)
						{
							pDLCTexPack->m_pStreamedWaveBank->Destroy();
						}
						if(pDLCTexPack->m_pSoundBank!=NULL)
						{
							pDLCTexPack->m_pSoundBank->Destroy();
						}
#endif
#ifdef _DURANGO
						DWORD result = StorageManager.UnmountInstalledDLC(L"TPACK");
#else
						DWORD result = StorageManager.UnmountInstalledDLC("TPACK");
#endif
						app.DebugPrintf("Unmount result is %d\n",result);
					}

#ifdef _XBOX_ONE
					// 4J Stu - It's possible that we can sign in/remove players between the mask initially being set and this point
					m_InviteData.dwLocalUsersMask = 0;
					for(unsigned int index = 0; index < XUSER_MAX_COUNT; ++index)
					{
						if(ProfileManager.IsSignedIn(index) )
						{
							if(index==i || pMinecraft->localplayers[index]!=NULL )
							{	
								m_InviteData.dwLocalUsersMask |= g_NetworkManager.GetLocalPlayerMask( index );
							}
						}
					}
#endif

					LoadingInputParams *loadingParams = new LoadingInputParams();
					loadingParams->func = &CGameNetworkManager::ExitAndJoinFromInviteThreadProc;
					loadingParams->lpParam = (LPVOID)&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 CPlatformNetworkManager::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);

#ifdef _XBOX_ONE
					// 4J Stu - If a player is signed in (i.e. locked) but not in the mask, unlock them
					for(unsigned int index = 0; index < XUSER_MAX_COUNT; ++index)
					{
						if( index != inviteData->dwUserIndex && ProfileManager.IsSignedIn(index) )
						{
							if( (m_InviteData.dwLocalUsersMask & g_NetworkManager.GetLocalPlayerMask( index ) ) == 0 )
							{	
								ProfileManager.RemoveGamepadFromGame(index);
							}
						}
					}
#endif

					// 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
						UINT uiIDA[1];
						uiIDA[0]=IDS_CONFIRM_OK;
						ui.RequestMessageBox( IDS_CONNECTION_FAILED, IDS_CONNECTION_LOST_SERVER, uiIDA,1,ProfileManager.GetPrimaryPad(),NULL,NULL, app.GetStringTable());
			
						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 = NULL;			

							UIFullscreenProgressCompletionData *completionData = new UIFullscreenProgressCompletionData();
#ifdef __PS3__
							completionData->bRequiresUserAction=FALSE;
#else
							completionData->bRequiresUserAction=TRUE;
#endif
							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);
					}
#if 0
					// 4J-HG - Took this out since ChangeSessionType is only set in two places (both in EthernetDisconnected) and this case is handled there, plus this breaks
					// this if statements original purpose (to allow us to wait for IsInGameplay before actioning switching to offline

					// QNet must do this kind of thing automatically by itself, but on PS3 at least, we need the disconnection to definitely end up with us out of the game one way or another,
					// and the other two cases above don't catch the case where we are just starting the game and get a disconnection during the loading/creation
					else
					{
						if( g_NetworkManager.IsInSession() )
						{
							g_NetworkManager._LeaveGame();
						}
					}
#endif
				}
				break;
			case eAppAction_SetDefaultOptions:
				SetAction(i,eAppAction_Idle);
#if ( defined __PS3__ || defined __ORBIS__ || defined _DURANGO || defined __PSVITA__)
				SetDefaultOptions((C4JStorage::PROFILESETTINGS *)param,i);		
#else
				SetDefaultOptions((C_4JProfile::PROFILESETTINGS *)param,i);		
#endif

				// 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 = &CMinecraftApp::RemoteSaveThreadProc;
					loadingParams->lpParam = NULL;			

					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 = &CMinecraftApp::ExitGameFromRemoteSave;
					loadingParams->cancelText = IDS_TOOLTIPS_EXIT;

					ui.NavigateToScene(ProfileManager.GetPrimaryPad(),eUIScene_FullscreenProgress, loadingParams);
				}
				break;
			case eAppAction_WaitRemoteServerSaveComplete:
				// Do nothing
				break;
			case eAppAction_FailedToJoinNoPrivileges:
				{
					UINT uiIDA[1];
					uiIDA[0]=IDS_CONFIRM_OK;
					C4JStorage::EMessageResult result = ui.RequestMessageBox( IDS_NO_MULTIPLAYER_PRIVILEGE_TITLE, IDS_NO_MULTIPLAYER_PRIVILEGE_JOIN_TEXT, uiIDA,1,ProfileManager.GetPrimaryPad(),NULL,NULL, app.GetStringTable());
					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())
					{
						TelemetryManager->RecordBanLevel(i);

#if defined _XBOX 
						INetworkPlayer *pHost=g_NetworkManager.GetHostPlayer();					
						// write the level to the banned level list, and exit the world
						AddLevelToBannedLevelList(i,((NetworkPlayerXbox *)pHost)->GetUID(),GetUniqueMapName(),true);
#elif defined _XBOX_ONE
						INetworkPlayer *pHost=g_NetworkManager.GetHostPlayer();	
						AddLevelToBannedLevelList(i,pHost->GetUID(),GetUniqueMapName(),true);
#endif
						// 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:
				{			
					UINT uiIDA[2];
					uiIDA[0]=IDS_BUTTON_REMOVE_FROM_BAN_LIST;
					uiIDA[1]=IDS_EXIT_GAME;

					// pass in the gamertag format string
					WCHAR 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.RequestMessageBox( IDS_BANNED_LEVEL_TITLE, IDS_PLAYER_BANNED_LEVEL, uiIDA,2,i,&CMinecraftApp::BannedLevelDialogReturned,this, app.GetStringTable(),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
				{
#ifdef _XBOX
					CScene_TextEntry::XuiTextInputParams *pDebugTextParams= new CScene_TextEntry::XuiTextInputParams;
					pDebugTextParams->iPad=i;
					pDebugTextParams->wch=(WCHAR)param;

					app.NavigateToScene(i,eUIScene_TextEntry,pDebugTextParams);
#endif
					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;
						}
#ifdef _XBOX
						TelemetryManager->RecordTexturePackLoaded(i, pTexturePack->getId(), purchased?1:0);
#endif
					}

					// 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_TexturePackRequired:
				{
#ifdef _XBOX
					ULONGLONG ullOfferID_Full;
					app.GetDLCFullOfferIDForPackID(app.GetRequiredTexturePackID(),&ullOfferID_Full);

					TelemetryManager->RecordUpsellPresented(ProfileManager.GetPrimaryPad(), eSet_UpsellID_Texture_DLC, ullOfferID_Full & 0xFFFFFFFF);
#endif
					UINT uiIDA[2];

					uiIDA[0]=IDS_TEXTUREPACK_FULLVERSION;
					uiIDA[1]=IDS_TEXTURE_PACK_TRIALVERSION;

					// Give the player a warning about the texture pack missing
					ui.RequestMessageBox(IDS_DLC_TEXTUREPACK_NOT_PRESENT_TITLE, IDS_DLC_TEXTUREPACK_NOT_PRESENT, uiIDA, 2, ProfileManager.GetPrimaryPad(),&CMinecraftApp::TexturePackDialogReturned,this,app.GetStringTable());
					SetAction(i,eAppAction_Idle);
				}

				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:
#ifdef _XBOX
				app.TMSPP_SetTitleGroupID(GROUP_ID);
				SetTMSAction(i,eTMSAction_TMSPP_GlobalFileList);
#elif defined _XBOX_ONE
				SetTMSAction(i,eTMSAction_TMSPP_GlobalFileList_Waiting);
				app.TMSPP_RetrieveFileList(i,C4JStorage::eGlobalStorage_Title,eTMSAction_TMSPP_UserFileList);
#else
				SetTMSAction(i,eTMSAction_TMSPP_UserFileList);
 #endif
				break;

#ifdef _XBOX
			case eTMSAction_TMSPP_GlobalFileList:
				SetTMSAction(i,eTMSAction_TMSPP_GlobalFileList_Waiting);
				app.TMSPP_RetrieveFileList(i,C4JStorage::eGlobalStorage_Title,"\\",eTMSAction_TMSPP_UserFileList);
				break;
#endif
			case eTMSAction_TMSPP_UserFileList:
				// retrieve the file list first
#if defined _XBOX 
				SetTMSAction(i,eTMSAction_TMSPP_UserFileList_Waiting);
				app.TMSPP_RetrieveFileList(i,C4JStorage::eGlobalStorage_TitleUser,"\\",eTMSAction_TMSPP_XUIDSFile);
#elif defined _XBOX_ONE
				SetTMSAction(i,eTMSAction_TMSPP_UserFileList_Waiting);
				app.TMSPP_RetrieveFileList(i,C4JStorage::eGlobalStorage_TitleUser,eTMSAction_TMSPP_DLCFile);
#else
				SetTMSAction(i,eTMSAction_TMSPP_XUIDSFile);
#endif
				break;
			case eTMSAction_TMSPP_XUIDSFile:
#ifdef _XBOX
				SetTMSAction(i,eTMSAction_TMSPP_XUIDSFile_Waiting);
				// pass in the next app action on the call or callback completing
				app.TMSPP_ReadXuidsFile(i,eTMSAction_TMSPP_DLCFile);
#else
				SetTMSAction(i,eTMSAction_TMSPP_DLCFile);
#endif

				break;			
			case eTMSAction_TMSPP_DLCFile:
#if defined _XBOX || defined _XBOX_ONE
				SetTMSAction(i,eTMSAction_TMSPP_DLCFile_Waiting);
				// pass in the next app action on the call or callback completing
				app.TMSPP_ReadDLCFile(i,eTMSAction_TMSPP_BannedListFile);
#else
				SetTMSAction(i,eTMSAction_TMSPP_BannedListFile);
#endif
				break;
			case eTMSAction_TMSPP_BannedListFile:
				// If we have one in TMSPP, then we can assume we can ignore TMS
#if defined _XBOX
				SetTMSAction(i,eTMSAction_TMSPP_BannedListFile_Waiting);
				// pass in the next app action on the call or callback completing
				if(app.TMSPP_ReadBannedList(i,eTMSAction_TMS_RetrieveFiles_Complete)==false)
				{
					// we don't have a banned list in TMSPP, so we should check TMS
					app.ReadBannedList(i, eTMSAction_TMS_RetrieveFiles_Complete,true);
				}
#elif defined _XBOX_ONE
				SetTMSAction(i,eTMSAction_TMSPP_BannedListFile_Waiting);
				// pass in the next app action on the call or callback completing
				app.TMSPP_ReadBannedList(i,eTMSAction_TMS_RetrieveFiles_Complete);

#else
				SetTMSAction(i,eTMSAction_TMS_RetrieveFiles_Complete);
#endif
				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
#if defined _XBOX 
				// pass in the next app action on the call or callback completing
				SetTMSAction(i,eTMSAction_TMSPP_XUIDSFile_Waiting);
				app.TMSPP_RetrieveFileList(i,C4JStorage::eGlobalStorage_Title,"\\",eTMSAction_TMSPP_DLCFileOnly);
#elif defined _XBOX_ONE
				SetTMSAction(i,eTMSAction_TMSPP_GlobalFileList_Waiting);
				app.TMSPP_RetrieveFileList(i,C4JStorage::eGlobalStorage_Title,eTMSAction_TMSPP_RetrieveUserFilelist_DLCFileOnly);
#else
				SetTMSAction(i,eTMSAction_TMSPP_DLCFileOnly);
#endif
				break;
			case eTMSAction_TMSPP_RetrieveUserFilelist_DLCFileOnly:
#if defined _XBOX 
				SetTMSAction(i,eTMSAction_TMSPP_UserFileList_Waiting);
				app.TMSPP_RetrieveFileList(i,C4JStorage::eGlobalStorage_TitleUser,"\\",eTMSAction_TMSPP_XUIDSFile);
#elif defined _XBOX_ONE
				//StorageManager.TMSPP_DeleteFile(i,C4JStorage::eGlobalStorage_TitleUser,C4JStorage::TMS_FILETYPE_BINARY,L"TP06.png",NULL,NULL, 0);
				SetTMSAction(i,eTMSAction_TMSPP_UserFileList_Waiting);
				app.TMSPP_RetrieveFileList(i,C4JStorage::eGlobalStorage_TitleUser,eTMSAction_TMSPP_DLCFileOnly);
#else
				SetTMSAction(i,eTMSAction_TMSPP_DLCFileOnly);
#endif

				break;

			case eTMSAction_TMSPP_DLCFileOnly:
#if defined _XBOX || defined _XBOX_ONE
				SetTMSAction(i,eTMSAction_TMSPP_DLCFile_Waiting);
				// pass in the next app action on the call or callback completing
				app.TMSPP_ReadDLCFile(i,eTMSAction_TMSPP_RetrieveFiles_Complete);
#else
				SetTMSAction(i,eTMSAction_TMSPP_RetrieveFiles_Complete);
#endif
				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 _XBOX
				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:
#ifdef _XBOX
				SetTMSAction(i,eTMSAction_TMS_DLCFile_Waiting);
				// pass in the next app action on the call or callback completing
				app.ReadDLCFileFromTMS(i,eTMSAction_TMS_BannedListFile,true);
#else
				SetTMSAction(i,eTMSAction_TMS_BannedListFile);
#endif

				break;

			case eTMSAction_TMS_RetrieveFiles_HelpAndOptions:
			case eTMSAction_TMS_RetrieveFiles_DLCMain:
#ifdef _XBOX
				SetTMSAction(i,eTMSAction_TMS_DLCFile_Waiting);
				// pass in the next app action on the call or callback completing
				app.ReadDLCFileFromTMS(i,eTMSAction_Idle,true);
#else
				SetTMSAction(i,eTMSAction_Idle);
#endif

				break;
			case eTMSAction_TMS_BannedListFile:
#ifdef _XBOX
				SetTMSAction(i,eTMSAction_TMS_BannedListFile_Waiting);
				// pass in the next app action on the call or callback completing
				app.ReadBannedList(i, eTMSAction_TMS_RetrieveFiles_Complete,true);
#else
				SetTMSAction(i,eTMSAction_TMS_RetrieveFiles_Complete);
#endif

				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;
			}
		}

	}
}

int CMinecraftApp::BannedLevelDialogReturned(void *pParam,int iPad,const C4JStorage::EMessageResult result)
{
	CMinecraftApp* pApp = (CMinecraftApp*)pParam;
	//Minecraft *pMinecraft=Minecraft::GetInstance();

	if(result==C4JStorage::EMessage_ResultAccept)
	{
#if defined _XBOX || defined _XBOX_ONE
		INetworkPlayer *pHost = g_NetworkManager.GetHostPlayer();
		// unban the level
		if (pHost != NULL)
		{
#if defined _XBOX
			pApp->RemoveLevelFromBannedLevelList(iPad,((NetworkPlayerXbox *)pHost)->GetUID(),pApp->GetUniqueMapName());
#else
			pApp->RemoveLevelFromBannedLevelList(iPad,pHost->GetUID(),pApp->GetUniqueMapName());
#endif
		}
#endif
	}
	else
	{
		if( iPad == ProfileManager.GetPrimaryPad() )
		{
			pApp->SetAction(iPad,eAppAction_ExitWorld);
		}
		else
		{
			pApp->SetAction(iPad,eAppAction_ExitPlayer);
		}
	}

	return 0;
}

void CMinecraftApp::loadMediaArchive()
{
	wstring mediapath = L"";

#ifdef __PS3__
	mediapath = L"Common\\Media\\MediaPS3.arc";
#elif _WINDOWS64
	mediapath = L"Common\\Media\\MediaWindows64.arc";
#elif __ORBIS__
	mediapath = L"Common\\Media\\MediaOrbis.arc";
#elif _DURANGO
	mediapath = L"Common\\Media\\MediaDurango.arc";
#elif __PSVITA__
	mediapath = L"Common\\Media\\MediaPSVita.arc";
#endif

	if (!mediapath.empty()) 
	{
		m_mediaArchive = new ArchiveFile( File(mediapath) );
	}
#if 0
	string path = "Common\\media.arc";
	HANDLE hFile = CreateFile(	path.c_str(),
								GENERIC_READ,
								FILE_SHARE_READ,
								NULL,
								OPEN_EXISTING,
								FILE_FLAG_SEQUENTIAL_SCAN,
								NULL );

	if( hFile != INVALID_HANDLE_VALUE )
	{
		File fileHelper(convStringToWstring(path));
		DWORD dwFileSize = fileHelper.length();

		// Initialize memory.
		PBYTE m_fBody = new BYTE[ dwFileSize ];
		ZeroMemory(m_fBody, dwFileSize);

		DWORD m_fSize = 0;
		BOOL hr = ReadFile(	hFile,
							m_fBody,
							dwFileSize,
							&m_fSize,
							NULL	);

		assert( m_fSize == dwFileSize );

		CloseHandle( hFile );

		m_mediaArchive = new ArchiveFile(m_fBody, m_fSize);
	}
	else
	{
		assert( false );
		// AHHHHHHHHHHHH
		m_mediaArchive = NULL;
	}
#endif
}

void CMinecraftApp::loadStringTable()
{
#ifndef _XBOX

	if(m_stringTable!=NULL)
	{
		// we need to unload the current string table, this is a reload
		delete m_stringTable;
	}
	wstring localisationFile = L"languages.loc";
	if (m_mediaArchive->hasFile(localisationFile))
	{
		byteArray locFile = m_mediaArchive->getFile(localisationFile);
		m_stringTable = new StringTable(locFile.data, locFile.length);
		delete locFile.data;
	}
	else
	{
		m_stringTable = NULL;
		assert(false);
		// AHHHHHHHHH.
	}
#endif
}

int CMinecraftApp::PrimaryPlayerSignedOutReturned(void *pParam,int iPad,const C4JStorage::EMessageResult)
{
	//CMinecraftApp* pApp = (CMinecraftApp*)pParam;
	//Minecraft *pMinecraft=Minecraft::GetInstance();

	// if the player is null, we're in the menus
	//if(Minecraft::GetInstance()->player!=NULL)

	// 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 CMinecraftApp::EthernetDisconnectReturned(void *pParam,int iPad,const C4JStorage::EMessageResult)
{
	//CMinecraftApp* pApp = (CMinecraftApp*)pParam;
	Minecraft *pMinecraft=Minecraft::GetInstance();

	// if the player is null, we're in the menus
	if(Minecraft::GetInstance()->player!=NULL)
	{	
		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
#ifdef __ORBIS__
		sceNpCommerceHidePsStoreIcon();
#elif defined __PSVITA__
		sceNpCommerce2HidePsStoreIcon();
#endif
		app.SetAction(iPad,eAppAction_EthernetDisconnectedReturned_Menus);
	}
	return 0;
}

int CMinecraftApp::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
	AABB::UseDefaultThreadStorage();
	Vec3::UseDefaultThreadStorage();
	Compression::UseDefaultThreadStorage();

	//app.SetGameStarted(false);

	Minecraft *pMinecraft=Minecraft::GetInstance();

	int exitReasonStringId = -1;

	bool saveStats = false;
	if (pMinecraft->isClientSide() || g_NetworkManager.IsInSession() )
	{
		if(lpParameter != NULL )
		{
			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;
#ifdef _XBOX
			case DisconnectPacket::eDisconnect_NoUGC_Remote:
				exitReasonStringId = IDS_NO_USER_CREATED_CONTENT_PRIVILEGE_REMOTE;
				break;
#endif
			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] != NULL ) pMinecraft->levels[0]->disconnect(false);
			if( pMinecraft->levels[1] != NULL ) pMinecraft->levels[1]->disconnect(false);
		}
		else
		{
			exitReasonStringId = IDS_EXITING_GAME;
			pMinecraft->progressRenderer->progressStartNoAbort( IDS_EXITING_GAME );

			if( pMinecraft->levels[0] != NULL ) pMinecraft->levels[0]->disconnect();
			if( pMinecraft->levels[1] != NULL ) pMinecraft->levels[1]->disconnect();
		}

		// 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 != NULL )
		{
			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;
#if defined(__PS3__) || defined(__ORBIS__) || defined (__PSVITA__)
			case DisconnectPacket::eDisconnect_ContentRestricted_AllLocal:
				exitReasonStringId = IDS_CONTENT_RESTRICTION_MULTIPLAYER;
				break;
			case DisconnectPacket::eDisconnect_ContentRestricted_Single_Local:
				exitReasonStringId = IDS_CONTENT_RESTRICTION;
				break;
#endif
#ifdef _XBOX
			case DisconnectPacket::eDisconnect_NoUGC_Remote:
				exitReasonStringId = IDS_NO_USER_CREATED_CONTENT_PRIVILEGE_REMOTE;
				break;
#endif
			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(NULL,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() )
	{
		Sleep(1);
	}

	return S_OK;
}

int CMinecraftApp::UnlockFullInviteReturned(void *pParam,int iPad,C4JStorage::EMessageResult result)
{
	//CMinecraftApp* pApp = (CMinecraftApp*)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==NULL)
	{
		bNoPlayer=true;
	}

	if(result==C4JStorage::EMessage_ResultAccept)
	{
		if(ProfileManager.IsSignedInLive(iPad))
		{
			// 4J-PB - need to check this user can access the store
#if defined(__PS3__) || defined(__PSVITA__)
			bool bContentRestricted;
			ProfileManager.GetChatAndContentRestrictions(ProfileManager.GetPrimaryPad(),true,NULL,&bContentRestricted,NULL);
			if(bContentRestricted)
			{
				UINT uiIDA[1];
				uiIDA[0]=IDS_CONFIRM_OK;
				ui.RequestMessageBox(IDS_ONLINE_SERVICE_TITLE, IDS_CONTENT_RESTRICTION, uiIDA, 1, ProfileManager.GetPrimaryPad(),NULL,&app, app.GetStringTable());
			}
			else
#endif
			{
				ProfileManager.DisplayFullVersionPurchase(false,iPad,eSen_UpsellID_Full_Version_Of_Game);
			}
		}
#if defined(__PS3__)
		else
		{
			// you're not signed in to PSN!
			UINT uiIDA[2];
			uiIDA[0]=IDS_PRO_NOTONLINE_ACCEPT;
			uiIDA[1]=IDS_PRO_NOTONLINE_DECLINE;
			ui.RequestMessageBox(IDS_PRO_NOTONLINE_TITLE, IDS_PRO_NOTONLINE_TEXT, uiIDA, 2, ProfileManager.GetPrimaryPad(),&CMinecraftApp::MustSignInFullVersionPurchaseReturned,&app, app.GetStringTable());

		}
#endif
	}
	else
	{
		TelemetryManager->RecordUpsellResponded(iPad, eSen_UpsellID_Full_Version_Of_Game, app.m_dwOfferID, eSen_UpsellOutcome_Declined);
	}

	return 0;
}

int CMinecraftApp::UnlockFullSaveReturned(void *pParam,int iPad,C4JStorage::EMessageResult result)
{
	//CMinecraftApp* pApp = (CMinecraftApp*)pParam;
	Minecraft *pMinecraft=Minecraft::GetInstance();

	if(result==C4JStorage::EMessage_ResultAccept)
	{
		if(ProfileManager.IsSignedInLive(pMinecraft->player->GetXboxPad()))
		{
			// 4J-PB - need to check this user can access the store
#if defined(__PS3__) || defined(__PSVITA__)
			bool bContentRestricted;
			ProfileManager.GetChatAndContentRestrictions(ProfileManager.GetPrimaryPad(),true,NULL,&bContentRestricted,NULL);
			if(bContentRestricted)
			{
				UINT uiIDA[1];
				uiIDA[0]=IDS_CONFIRM_OK;
				ui.RequestMessageBox(IDS_ONLINE_SERVICE_TITLE, IDS_CONTENT_RESTRICTION, uiIDA, 1, ProfileManager.GetPrimaryPad(),NULL,&app, app.GetStringTable());
			}
			else
#endif
			{
				ProfileManager.DisplayFullVersionPurchase(false,pMinecraft->player->GetXboxPad(),eSen_UpsellID_Full_Version_Of_Game);
			}
		}
#if defined(__PS3__)
		else
		{
			// you're not signed in to PSN!
			UINT uiIDA[2];
			uiIDA[0]=IDS_PRO_NOTONLINE_ACCEPT;
			uiIDA[1]=IDS_PRO_NOTONLINE_DECLINE;
			ui.RequestMessageBox(IDS_PRO_NOTONLINE_TITLE, IDS_PRO_NOTONLINE_TEXT, uiIDA, 2, ProfileManager.GetPrimaryPad(),&CMinecraftApp::MustSignInFullVersionPurchaseReturned,&app, app.GetStringTable());
		}
#elif defined(__ORBIS__)
		else
		{		
			// Determine why they're not "signed in live"
			if (ProfileManager.isSignedInPSN(iPad))
			{
				// Signed in to PSN but not connected (no internet access)
				assert(!ProfileManager.isConnectedToPSN(iPad));

				UINT uiIDA[1];
				uiIDA[0] = IDS_OK;
				ui.RequestMessageBox( IDS_ERROR_NETWORK_TITLE, IDS_ERROR_NETWORK, uiIDA, 1, iPad, NULL, NULL, app.GetStringTable());
			}
			else
			{		
				// Not signed in to PSN
				UINT uiIDA[1];
				uiIDA[0] = IDS_PRO_NOTONLINE_ACCEPT;
				ui.RequestMessageBox( IDS_PRO_NOTONLINE_TITLE, IDS_PRO_NOTONLINE_TEXT, uiIDA, 1, iPad, &CMinecraftApp::MustSignInFullVersionPurchaseReturned,&app, app.GetStringTable(), NULL, 0, false);
			}
		}
#endif
	}
	else
	{
		TelemetryManager->RecordUpsellResponded(iPad, eSen_UpsellID_Full_Version_Of_Game, app.m_dwOfferID, eSen_UpsellOutcome_Declined);
	}

	return 0;
}

int CMinecraftApp::UnlockFullExitReturned(void *pParam,int iPad,C4JStorage::EMessageResult result)
{
	CMinecraftApp* pApp = (CMinecraftApp*)pParam;
	Minecraft *pMinecraft=Minecraft::GetInstance();

	if(result==C4JStorage::EMessage_ResultAccept)
	{
		if(ProfileManager.IsSignedInLive(pMinecraft->player->GetXboxPad()))
		{
			// 4J-PB - need to check this user can access the store
#if defined(__PS3__) || defined(__PSVITA__)
			bool bContentRestricted;
			ProfileManager.GetChatAndContentRestrictions(ProfileManager.GetPrimaryPad(),true,NULL,&bContentRestricted,NULL);
			if(bContentRestricted)
			{
				UINT uiIDA[1];
				uiIDA[0]=IDS_CONFIRM_OK;
				ui.RequestMessageBox(IDS_ONLINE_SERVICE_TITLE, IDS_CONTENT_RESTRICTION, uiIDA, 1, ProfileManager.GetPrimaryPad(),NULL,&app, app.GetStringTable());
			}
			else
#endif
			{
				ProfileManager.DisplayFullVersionPurchase(false,pMinecraft->player->GetXboxPad(),eSen_UpsellID_Full_Version_Of_Game);
#if defined __ORBIS__ || defined __PS3__ || defined __PSVITA__
				// still need to exit the trial or we'll be in the Pause menu with input ignored
				pApp->SetAction(pMinecraft->player->GetXboxPad(),eAppAction_ExitWorldTrial);
#endif
			}
		}
#if defined(__PS3__) || defined __PSVITA__
		else
		{
			// you're not signed in to PSN!
			UINT uiIDA[2];
			uiIDA[0]=IDS_PRO_NOTONLINE_ACCEPT;
			uiIDA[1]=IDS_PRO_NOTONLINE_DECLINE;
			ui.RequestMessageBox(IDS_PRO_NOTONLINE_TITLE, IDS_PRO_NOTONLINE_TEXT, uiIDA, 2, ProfileManager.GetPrimaryPad(),&CMinecraftApp::MustSignInFullVersionPurchaseReturnedExitTrial,&app, app.GetStringTable());
		}
#elif defined(__ORBIS__)
		else
		{		
			// Determine why they're not "signed in live"
			if (ProfileManager.isSignedInPSN(iPad))
			{
				// Signed in to PSN but not connected (no internet access)
				assert(!ProfileManager.isConnectedToPSN(iPad));

				UINT uiIDA[1];
				uiIDA[0] = IDS_OK;
				ui.RequestMessageBox( IDS_ERROR_NETWORK_TITLE, IDS_ERROR_NETWORK, uiIDA, 1, iPad, NULL, NULL, app.GetStringTable());
				// still need to exit the trial or we'll be in the Pause menu with input ignored
				pApp->SetAction(pMinecraft->player->GetXboxPad(),eAppAction_ExitWorldTrial);
			}
			else
			{		
				// Not signed in to PSN
				UINT uiIDA[1];
				uiIDA[0] = IDS_PRO_NOTONLINE_ACCEPT;
				ui.RequestMessageBox( IDS_PRO_NOTONLINE_TITLE, IDS_PRO_NOTONLINE_TEXT, uiIDA, 1, iPad, &CMinecraftApp::MustSignInFullVersionPurchaseReturnedExitTrial,&app, app.GetStringTable(), NULL, 0, false);
			}
		}
#endif
	}
	else
	{
		TelemetryManager->RecordUpsellResponded(iPad, eSen_UpsellID_Full_Version_Of_Game, app.m_dwOfferID, eSen_UpsellOutcome_Declined);
		pApp->SetAction(pMinecraft->player->GetXboxPad(),eAppAction_ExitWorldTrial);
	}

	return 0;
}

int CMinecraftApp::TrialOverReturned(void *pParam,int iPad,C4JStorage::EMessageResult result)
{
	CMinecraftApp* pApp = (CMinecraftApp*)pParam;
	Minecraft *pMinecraft=Minecraft::GetInstance();

	if(result==C4JStorage::EMessage_ResultAccept)
	{
		// we need a signed in user for the unlock
		if(ProfileManager.IsSignedInLive(pMinecraft->player->GetXboxPad()))
		{
			// 4J-PB - need to check this user can access the store
#if defined(__PS3__) || defined(__PSVITA__)
			bool bContentRestricted;
			ProfileManager.GetChatAndContentRestrictions(ProfileManager.GetPrimaryPad(),true,NULL,&bContentRestricted,NULL);
			if(bContentRestricted)
			{
				UINT uiIDA[1];
				uiIDA[0]=IDS_CONFIRM_OK;
				ui.RequestMessageBox(IDS_ONLINE_SERVICE_TITLE, IDS_CONTENT_RESTRICTION, uiIDA, 1, ProfileManager.GetPrimaryPad(),NULL,&app, app.GetStringTable());
			}
			else
#endif
			{
				ProfileManager.DisplayFullVersionPurchase(false,pMinecraft->player->GetXboxPad(),eSen_UpsellID_Full_Version_Of_Game);
			}
		}
		else
		{
#if defined(__PS3__)

			// you're not signed in to PSN!
			UINT uiIDA[2];
			uiIDA[0]=IDS_PRO_NOTONLINE_ACCEPT;
			uiIDA[1]=IDS_PRO_NOTONLINE_DECLINE;
			ui.RequestMessageBox(IDS_PRO_NOTONLINE_TITLE, IDS_PRO_NOTONLINE_TEXT, uiIDA, 2, ProfileManager.GetPrimaryPad(),&CMinecraftApp::MustSignInFullVersionPurchaseReturned,&app, app.GetStringTable());

			// 4J Stu - We can't actually exit the game, so just exit back to the main menu
			//pApp->SetAction(pMinecraft->player->GetXboxPad(),eAppAction_ExitWorldTrial);
#else
			pApp->SetAction(pMinecraft->player->GetXboxPad(),eAppAction_ExitTrial);
#endif
		}
	}
	else
	{
		TelemetryManager->RecordUpsellResponded(iPad, eSen_UpsellID_Full_Version_Of_Game, app.m_dwOfferID, eSen_UpsellOutcome_Declined);

#if defined(__PS3__) || defined(__ORBIS__)
		// 4J Stu - We can't actually exit the game, so just exit back to the main menu
		pApp->SetAction(pMinecraft->player->GetXboxPad(),eAppAction_ExitWorldTrial);
#else
		pApp->SetAction(pMinecraft->player->GetXboxPad(),eAppAction_ExitTrial);
#endif
	}

	return 0;
}

void CMinecraftApp::ProfileReadErrorCallback(void *pParam)
{
	CMinecraftApp *pApp=(CMinecraftApp *)pParam;
	int iPrimaryPlayer=ProfileManager.GetPrimaryPad();
	pApp->SetAction(iPrimaryPlayer, eAppAction_ProfileReadError);
}

void CMinecraftApp::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 CMinecraftApp::SignInChangeCallback(LPVOID pParam,bool bPrimaryPlayerChanged,unsigned int uiSignInData)
{
#ifdef __PS3__
	// this is normally set in the main menu, but we can go online in the create world screens, and the primary player name isn't updated
	Minecraft::GetInstance()->user->name = convStringToWstring( ProfileManager.GetGamertag(ProfileManager.GetPrimaryPad()));
#endif

	CMinecraftApp *pApp=(CMinecraftApp *)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)
				{
					DWORD 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 )
				{
					UINT uiIDA[1];
					uiIDA[0]=IDS_CONFIRM_OK;
					ui.RequestMessageBox(IDS_GUEST_ORDER_CHANGED_TITLE, IDS_GUEST_ORDER_CHANGED_TEXT, uiIDA, 1, ProfileManager.GetPrimaryPad(),NULL,NULL,app.GetStringTable());
				}

				// 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)!=NULL)
					{
						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);

							if(g_NetworkManager.GetLocalPlayerByUserIndex(i)!=NULL)
							{
								pApp->DebugPrintf("Player %d signed out\n", i);
								pApp->SetAction(i,eAppAction_ExitPlayer);
							}
						}
					}
#ifdef __ORBIS__
					// check if any of the addition players have signed out of PSN (primary player is handled below)
					if(!switchToOffline && i != ProfileManager.GetLockedProfile() && !g_NetworkManager.IsLocalGame())
					{
						if(g_NetworkManager.GetLocalPlayerByUserIndex(i)!=NULL)
						{
							if(ProfileManager.IsSignedInLive(i) == false)
							{
								pApp->DebugPrintf("Recommending removal of player at index %d because they're no longer signed into PSNd\n",i);
								pApp->SetAction(i,eAppAction_ExitPlayer);
							}
						}
					}
#endif
				}

				// 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);
			}

#if ( defined __PS3__ || defined __ORBIS__ || defined _DURANGO  || defined __PSVITA__ )
			// 4J-JEV: Need to kick of loading of profile data for sub-sign in players.
			for(unsigned int i = 0; i < XUSER_MAX_COUNT; ++i)
			{
				if( i != iPrimaryPlayer 
					&& ( uiChangedPlayers & (1<<i) )
					&& ( uiSignInData & (1<<i) )
					)
				{
					StorageManager.ReadFromProfile(i);
				}
			}
#endif
		}
		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 CMinecraftApp::NotificationsCallback(LPVOID pParam,DWORD dwNotification, unsigned int uiParam)
{
	CMinecraftApp* pClass = (CMinecraftApp*)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] != NULL &&
					!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:
		{
#ifdef _XBOX
			// If the devices have changed, and we've got a dlc pack with audio selected, and that pack's content device is no longer valid... then pull the plug on
			// audio streaming, as if we leave this until later xact gets locked up attempting to destroy the streamed wave bank.
			TexturePack *pTexPack=Minecraft::GetInstance()->skins->getSelected();
			if(pTexPack->hasAudio())
			{
				DLCTexturePack *pDLCTexPack=(DLCTexturePack *)pTexPack;
				XCONTENTDEVICEID deviceID = pDLCTexPack->GetDLCDeviceID();
				if( XContentGetDeviceState( deviceID, NULL ) != ERROR_SUCCESS )
				{
					// Set texture pack flag so that it is now considered as not having audio - this is critical so that the next playStreaming does what it is meant to do,
					// and also so that we don't try and unmount this again, or play any sounds from it in the future
					pTexPack->setHasAudio(false);
					// need to stop the streaming audio - by playing streaming audio from the default texture pack now
					Minecraft::GetInstance()->soundEngine->playStreaming(L"", 0, 0, 0, 0, 0);

					if(pDLCTexPack->m_pStreamedWaveBank!=NULL)
					{
						pDLCTexPack->m_pStreamedWaveBank->Destroy();
					}
					if(pDLCTexPack->m_pSoundBank!=NULL)
					{
						pDLCTexPack->m_pSoundBank->Destroy();
					}
					DWORD result = StorageManager.UnmountInstalledDLC("TPACK");
					app.DebugPrintf("Unmount result is %d\n",result);
				}
			}
#endif
		}
		break;
	}

	pClass->m_vNotifications.push_back(pNotification);
}

#if defined __PS3__ || defined __PSVITA__ || defined __ORBIS__
int CMinecraftApp::MustSignInFullVersionPurchaseReturned(void *pParam,int iPad,C4JStorage::EMessageResult result)
{
	if(result==C4JStorage::EMessage_ResultAccept) 
	{
#ifdef __PS3__
		SQRNetworkManager_PS3::AttemptPSNSignIn(&CMinecraftApp::NowDisplayFullVersionPurchase, &app,true);
#elif defined __PSVITA__
		SQRNetworkManager_Vita::AttemptPSNSignIn(&CMinecraftApp::NowDisplayFullVersionPurchase, &app,true);
#else // __PS4__
		SQRNetworkManager_Orbis::AttemptPSNSignIn(&CMinecraftApp::NowDisplayFullVersionPurchase, &app,true);
#endif
	}

	return 0;
}

#if defined __PS3__ || defined __PSVITA__ || defined __ORBIS__
int CMinecraftApp::MustSignInFullVersionPurchaseReturnedExitTrial(void *pParam,int iPad,C4JStorage::EMessageResult result)
{
	if(result==C4JStorage::EMessage_ResultAccept) 
	{
#ifdef __PS3__
		SQRNetworkManager_PS3::AttemptPSNSignIn(&CMinecraftApp::NowDisplayFullVersionPurchase, &app,true);
#elif defined __PSVITA__
		SQRNetworkManager_Vita::AttemptPSNSignIn(&CMinecraftApp::NowDisplayFullVersionPurchase, &app,true);
#else // __PS4__
		SQRNetworkManager_Orbis::AttemptPSNSignIn(&CMinecraftApp::NowDisplayFullVersionPurchase, &app,true);
#endif
	}

	//4J-PB - we need to exit the trial, or we'll be in the pause menu with ignore input true
	app.SetAction(iPad,eAppAction_ExitWorldTrial);	

	return 0;
}
#endif

int CMinecraftApp::NowDisplayFullVersionPurchase(void *pParam, bool bContinue, int iPad)
{
	app.m_bDisplayFullVersionPurchase=true;
	return 0;
}
#endif
void CMinecraftApp::UpsellReturnedCallback(LPVOID pParam, eUpsellType type, eUpsellResponse result, int iUserData)
{
	ESen_UpsellID senType;
	ESen_UpsellOutcome senResponse;
#ifdef __PS3__
	UINT uiIDA[2];
#endif

	// Map the eUpsellResponse to the enum we use for sentient
	switch(result)
	{
	case eUpsellResponse_Accepted_NoPurchase:
		senResponse = eSen_UpsellOutcome_Went_To_Guide;
		break;
	case eUpsellResponse_Accepted_Purchase:
		senResponse = eSen_UpsellOutcome_Accepted;
		break;
#ifdef __PS3__
		// special case for people who are not signed in to the PSN while playing the trial game
	case eUpsellResponse_UserNotSignedInPSN:
		
		uiIDA[0]=IDS_PRO_NOTONLINE_ACCEPT;
		uiIDA[1]=IDS_PRO_NOTONLINE_DECLINE;
		ui.RequestMessageBox(IDS_PRO_NOTONLINE_TITLE, IDS_PRO_NOTONLINE_TEXT, uiIDA, 2, ProfileManager.GetPrimaryPad(),&CMinecraftApp::MustSignInFullVersionPurchaseReturned,&app, app.GetStringTable());

		return;

	case eUpsellResponse_NotAllowedOnline: // On earning a trophy in the trial version, where the user is underage and can't go online to buy the game, but they selected to buy the game on the trophy upsell
		uiIDA[0]=IDS_CONFIRM_OK;
		ui.RequestMessageBox(IDS_ONLINE_SERVICE_TITLE, IDS_CONTENT_RESTRICTION, uiIDA, 1, ProfileManager.GetPrimaryPad(),NULL,&app, app.GetStringTable());
		break;
#endif	
	case eUpsellResponse_Declined:
	default:		
		senResponse = eSen_UpsellOutcome_Declined;
		break;
	};

	// Map the eUpsellType to the enum we use for sentient
	switch(type)
	{
	case eUpsellType_Custom:
		senType = eSen_UpsellID_Full_Version_Of_Game;
		break;
	default:
		senType = eSen_UpsellID_Undefined;
		break;
	};

	// Always the primary pad that gets an upsell	
	TelemetryManager->RecordUpsellResponded(ProfileManager.GetPrimaryPad(), eSen_UpsellID_Full_Version_Of_Game, app.m_dwOfferID, senResponse);
}

void CMinecraftApp::SetDebugSequence(const char *pchSeq)
{
	InputManager.SetDebugSequence(pchSeq,&CMinecraftApp::DebugInputCallback,this);
}
int CMinecraftApp::DebugInputCallback(LPVOID pParam)
{
	CMinecraftApp* pClass = (CMinecraftApp*)pParam;
	//printf("sequence matched\n");
	pClass->m_bDebugOptions=!pClass->m_bDebugOptions;

	for(int i=0;i<XUSER_MAX_COUNT;i++)
	{
		if(app.DebugSettingsOn())
		{
			app.ActionDebugMask(i);		
		}
		else
		{
			// force debug mask off
			app.ActionDebugMask(i,true);
		}
	}

	return 0;
}

int CMinecraftApp::GetLocalPlayerCount(void)
{
	int iPlayerC=0;
	Minecraft *pMinecraft = Minecraft::GetInstance();
	for(int i=0;i<XUSER_MAX_COUNT;i++)
	{
		if(pMinecraft != NULL && pMinecraft->localplayers[i] != NULL)
		{
			iPlayerC++;
		}
	}

	return iPlayerC;
}

int CMinecraftApp::MarketplaceCountsCallback(LPVOID 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 CMinecraftApp::StartInstallDLCProcess(int iPad)
{
	app.DebugPrintf("--- CMinecraftApp::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("--- CMinecraftApp::StartInstallDLCProcess - StorageManager.GetInstalledDLC\n");

		StorageManager.GetInstalledDLC(iPad,&CMinecraftApp::DLCInstalledCallback,this);
		return true;
	}
	else
	{
		app.DebugPrintf("--- CMinecraftApp::StartInstallDLCProcess - nothing to do\n");

		return false;
	}

}

// Installed DLC callback
int CMinecraftApp::DLCInstalledCallback(LPVOID pParam,int iInstalledC,int iPad)
{
	app.DebugPrintf("--- CMinecraftApp::DLCInstalledCallback: totalDLC=%i, pad=%i.\n", iInstalledC, iPad);
	app.m_iTotalDLC = iInstalledC;
	app.MountNextDLC(iPad);
	return 0;
}

void CMinecraftApp::MountNextDLC(int iPad)
{
	app.DebugPrintf("--- CMinecraftApp::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,&CMinecraftApp::DLCMountedCallback,this)!=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();

#if defined(_XBOX_ONE) || defined(__ORBIS__)
		// Check if the current texture pack is now installed
		if(!Minecraft::GetInstance()->skins->isUsingDefaultSkin())
		{
			TexturePack *tPack = Minecraft::GetInstance()->skins->getSelected();
			DLCTexturePack *pDLCTexPack=(DLCTexturePack *)tPack;

			DLCPack *pParentPack=pDLCTexPack->getDLCInfoParentPack();//tPack->getDLCPack();

			if(pParentPack->hasPurchasedFile( DLCManager::e_DLCType_Texture, L"" ))
			{
				StorageManager.SetSaveDisabled(false);
			}
		}
#endif
	}
}

// 4J-JEV: For the sake of clarity in DLCMountedCallback.
#if defined(_XBOX) || defined(__PS3__) || defined(_WINDOWS64)
#define CONTENT_DATA_DISPLAY_NAME(a) (a.szDisplayName)
#else
#define CONTENT_DATA_DISPLAY_NAME(a) (a.wszDisplayName)
#endif

int CMinecraftApp::DLCMountedCallback(LPVOID pParam,int iPad,DWORD dwErr,DWORD dwLicenceMask)
{
#if defined(_XBOX) || defined(_DURANGO) || defined(__PS3__) || defined(__ORBIS__) || defined(_WINDOWS64)  || defined (__PSVITA__) //Chris TODO
	app.DebugPrintf("--- CMinecraftApp::DLCMountedCallback\n");

	if(dwErr!=ERROR_SUCCESS)
	{
		// corrupt DLC
		app.DebugPrintf("Failed to mount DLC for pad %d: %d\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 != NULL && 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 = NULL;
		}
		
		if(pack == NULL)
		{
			app.DebugPrintf("Pack \"%ls\" is not installed, so adding it\n", CONTENT_DATA_DISPLAY_NAME(ContentData));

#if defined(_XBOX) || defined(__PS3__) || defined(_WINDOWS64)
			pack = new DLCPack(ContentData.szDisplayName,dwLicenceMask);
#elif defined _XBOX_ONE
			pack = new DLCPack(ContentData.wszDisplayName,ContentData.wszProductID,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 %d\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 // __PSVITA__
	return 0;
}
#undef CONTENT_DATA_DISPLAY_NAME

//  void CMinecraftApp::InstallDefaultCape()
//  {
// 	 if(!m_bDefaultCapeInstallAttempted)
// 	 { 
// 		 // we only attempt to install the cape once per launch of the game
// 		 m_bDefaultCapeInstallAttempted=true;
// 
// 		 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)
// 		 {	
// 			 BYTE *pBuffer=NULL;
// 			 DWORD 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 CMinecraftApp::HandleDLC(DLCPack *pack)	
 {
	 DWORD dwFilesProcessed = 0;
#ifndef _XBOX
#if defined(__PS3__) || defined(__ORBIS__) || defined(_WINDOWS64) || defined (__PSVITA__)
	 std::vector<std::string> dlcFilenames;
#elif defined _DURANGO
	 std::vector<std::wstring> dlcFilenames;
#endif
	 StorageManager.GetMountedDLCFileList("DLCDrive", dlcFilenames);
	 for(int i=0; i<dlcFilenames.size();i++)
	 {
		 m_dlcManager.readDLCDataFile(dwFilesProcessed, dlcFilenames[i], pack);
	 }
#else
	WIN32_FIND_DATA wfd;
	HANDLE hFind;

	char szPath[] = "DLCDrive:\\";
	char szFullFilename[256];
	strcpy(szFullFilename,szPath);
	strcat(szFullFilename,"*");

	// Start the find and check for failure.
	hFind = FindFirstFile( szFullFilename, &wfd );

	if( INVALID_HANDLE_VALUE == hFind )
	{
		app.DebugPrintf( "FindFirstFile failed." );
	}
	else
	{
		// Display each file and ask for the next.
		do
		{
			strcpy(szFullFilename,szPath);
			strcat(szFullFilename,wfd.cFileName);
				
			if(( GetFileAttributes( szFullFilename ) & FILE_ATTRIBUTE_DIRECTORY) != FILE_ATTRIBUTE_DIRECTORY)
			{
#ifdef _XBOX
				DWORD dwPackID=m_dlcManager.retrievePackIDFromDLCDataFile(szFullFilename,pack);

				// Do we need to override the TexturePack.pck with an updated version in a TU?
				wstring wsTemp=getFilePath(dwPackID, wstring(L"TexturePack.pck"),false );
				File texturePCKPath(wsTemp );
				if(texturePCKPath.exists())
				{
					app.DebugPrintf("Found a replacement .pck\n");		
					m_dlcManager.readDLCDataFile(dwFilesProcessed, wsTemp,pack);
				}	
				else
				{
					m_dlcManager.readDLCDataFile(dwFilesProcessed, szFullFilename,pack);
				}
#else
				m_dlcManager.readDLCDataFile(dwFilesProcessed, szFullFilename,pack);

#endif
			}
		} 
		while( FindNextFile( hFind, &wfd ) );

		// Close the find handle.
		FindClose( hFind );
	}
#endif // __PS3__ || __ORBIS__

	if( dwFilesProcessed == 0 ) m_dlcManager.removePack(pack);
 }

//  int CMinecraftApp::DLCReadCallback(LPVOID pParam,C4JStorage::DLC_FILE_DETAILS *pDLCData)
//  {
// 
// 
// 	 return 0;
//  }

 //-------------------------------------------------------------------------------------
 // Name: InitTime()
 // Desc: Initializes the timer variables
 //-------------------------------------------------------------------------------------
 void CMinecraftApp::InitTime()
 {    

	 // Get the frequency of the timer
	 LARGE_INTEGER qwTicksPerSec;
	 QueryPerformanceFrequency( &qwTicksPerSec );
	 m_Time.fSecsPerTick = 1.0f / (float)qwTicksPerSec.QuadPart;

	 // Save the start time
	 QueryPerformanceCounter( &m_Time.qwTime );

	 // Zero out the elapsed and total time
	 m_Time.qwAppTime.QuadPart = 0;
	 m_Time.fAppTime = 0.0f; 
	 m_Time.fElapsedTime = 0.0f;    
 }

 //-------------------------------------------------------------------------------------
 // Name: UpdateTime()
 // Desc: Updates the elapsed time since our last frame.
 //-------------------------------------------------------------------------------------
 void CMinecraftApp::UpdateTime()
 {
	 LARGE_INTEGER qwNewTime;
	 LARGE_INTEGER qwDeltaTime;

	 QueryPerformanceCounter( &qwNewTime );    
	 qwDeltaTime.QuadPart = qwNewTime.QuadPart - m_Time.qwTime.QuadPart;

	 m_Time.qwAppTime.QuadPart += qwDeltaTime.QuadPart;    
	 m_Time.qwTime.QuadPart     = qwNewTime.QuadPart;

	 m_Time.fElapsedTime      = m_Time.fSecsPerTick * ((FLOAT)(qwDeltaTime.QuadPart));
	 m_Time.fAppTime          = m_Time.fSecsPerTick * ((FLOAT)(m_Time.qwAppTime.QuadPart));    
 }







bool CMinecraftApp::isXuidNotch(PlayerUID xuid)
{
	if(m_xuidNotch != INVALID_XUID && xuid != INVALID_XUID)
	{
		return ProfileManager.AreXUIDSEqual(xuid, m_xuidNotch) == TRUE;
	}
	return false;
}

bool CMinecraftApp::isXuidDeadmau5(PlayerUID xuid)
{
	AUTO_VAR(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 CMinecraftApp::AddMemoryTextureFile(const wstring &wName,PBYTE pbData,DWORD dwBytes)	
{	
	EnterCriticalSection(&csMemFilesLock);
	// check it's not already in
	PMEMDATA pData=NULL;
	AUTO_VAR(it, m_MEM_Files.find(wName));
	if(it != m_MEM_Files.end())
	{
#ifndef _CONTENT_PACKAGE
			wprintf(L"Incrementing the memory texture file count for %ls\n", wName.c_str());
#endif
		pData = (*it).second;

		if(pData->dwBytes == 0 && dwBytes != 0)
		{
			// This should never be NULL if dwBytes is 0
			if(pData->pbData!=NULL) delete [] pData->pbData;

			pData->pbData=pbData;
			pData->dwBytes=dwBytes;
		}

		++pData->ucRefCount;
		LeaveCriticalSection(&csMemFilesLock);
		return;
	}

#ifndef _CONTENT_PACKAGE
			//wprintf(L"Adding the memory texture file data for %ls\n", wName.c_str());
#endif
	// this is a texture (png) file

	// add this texture to the list of memory texture files - it will then be picked up by the level renderer's AddEntity

	pData = (PMEMDATA)new BYTE[sizeof(MEMDATA)];
	ZeroMemory( pData, sizeof(MEMDATA) );
	pData->pbData=pbData;
	pData->dwBytes=dwBytes;
	pData->ucRefCount = 1;

	// use the xuid to access the skin data
	m_MEM_Files[wName]=pData;

	LeaveCriticalSection(&csMemFilesLock);
}

void CMinecraftApp::RemoveMemoryTextureFile(const wstring &wName)
{
	EnterCriticalSection(&csMemFilesLock);
	
	AUTO_VAR(it, m_MEM_Files.find(wName));
	if(it != m_MEM_Files.end())
	{
#ifndef _CONTENT_PACKAGE
			wprintf(L"Decrementing the memory texture file count for %ls\n", wName.c_str());
#endif
		PMEMDATA pData = (*it).second;
		--pData->ucRefCount;
		if(pData->ucRefCount <= 0)
		{
#ifndef _CONTENT_PACKAGE
			wprintf(L"Erasing the memory texture file data for %ls\n", wName.c_str());
#endif
			delete [] pData;
			m_MEM_Files.erase(wName);
		}
	}
	LeaveCriticalSection(&csMemFilesLock);
}

bool CMinecraftApp::DefaultCapeExists()
{
	wstring wTex=L"Special_Cape.png";
	bool val = false;

	EnterCriticalSection(&csMemFilesLock);
	AUTO_VAR(it, m_MEM_Files.find(wTex));
	if(it != m_MEM_Files.end()) val = true;	
	LeaveCriticalSection(&csMemFilesLock);

	return val;
}

bool CMinecraftApp::IsFileInMemoryTextures(const wstring &wName)
{
	bool val = false;

	EnterCriticalSection(&csMemFilesLock);
	AUTO_VAR(it, m_MEM_Files.find(wName));
	if(it != m_MEM_Files.end()) val = true;	
	LeaveCriticalSection(&csMemFilesLock);

	return val;
}

void CMinecraftApp::GetMemFileDetails(const wstring &wName,PBYTE *ppbData,DWORD *pdwBytes)
{
	EnterCriticalSection(&csMemFilesLock);
	AUTO_VAR(it, m_MEM_Files.find(wName));
	if(it != m_MEM_Files.end())
	{
		PMEMDATA pData = (*it).second;
		*ppbData=pData->pbData;
		*pdwBytes=pData->dwBytes;
	}
	LeaveCriticalSection(&csMemFilesLock);
}

void CMinecraftApp::AddMemoryTPDFile(int iConfig,PBYTE pbData,DWORD dwBytes)	
{	
	EnterCriticalSection(&csMemTPDLock);
	// check it's not already in
	PMEMDATA pData=NULL;
	AUTO_VAR(it, m_MEM_TPD.find(iConfig));
	if(it == m_MEM_TPD.end())
	{	
		pData = (PMEMDATA)new BYTE[sizeof(MEMDATA)];
		ZeroMemory( pData, sizeof(MEMDATA) );
		pData->pbData=pbData;
		pData->dwBytes=dwBytes;
		pData->ucRefCount = 1;

		m_MEM_TPD[iConfig]=pData;
	}

	LeaveCriticalSection(&csMemTPDLock);
}

void CMinecraftApp::RemoveMemoryTPDFile(int iConfig)	
{	
	EnterCriticalSection(&csMemTPDLock);
	// check it's not already in
	PMEMDATA pData=NULL;
	AUTO_VAR(it, m_MEM_TPD.find(iConfig));
	if(it != m_MEM_TPD.end())
	{
		pData=m_MEM_TPD[iConfig];
		delete [] pData;
		m_MEM_TPD.erase(iConfig);
	}

	LeaveCriticalSection(&csMemTPDLock);
}

#ifdef _XBOX
int CMinecraftApp::GetTPConfigVal(WCHAR *pwchDataFile)
{
	DLC_INFO *pDLCInfo=NULL;
	// run through the DLC info to find the right texture pack/mash-up pack
	for(unsigned int i = 0; i < app.GetDLCInfoTexturesOffersCount(); ++i)
	{
		ULONGLONG ull=app.GetDLCInfoTexturesFullOffer(i);
		pDLCInfo=app.GetDLCInfoForFullOfferID(ull);

		if(wcscmp(pwchDataFile,pDLCInfo->wchDataFile)==0)
		{
			return pDLCInfo->iConfig;
		}
	}

	return -1;
}
#elif defined _XBOX_ONE
int CMinecraftApp::GetTPConfigVal(WCHAR *pwchDataFile)
{
	DLC_INFO *pDLCInfo=NULL;
	// run through the DLC info to find the right texture pack/mash-up pack
	for(unsigned int i = 0; i < app.GetDLCInfoTexturesOffersCount(); ++i)
	{
		pDLCInfo=app.GetDLCInfoForFullOfferID((WCHAR *)app.GetDLCInfoTexturesFullOffer(i).c_str());

		if(wcscmp(pwchDataFile,pDLCInfo->wchDataFile)==0)
		{
			return pDLCInfo->iConfig;
		}
	}

	return -1;
}
#elif defined _WINDOWS64
int CMinecraftApp::GetTPConfigVal(WCHAR *pwchDataFile)
{
	return -1;
}
#endif
bool CMinecraftApp::IsFileInTPD(int iConfig)
{
	bool val = false;

	EnterCriticalSection(&csMemTPDLock);
	AUTO_VAR(it, m_MEM_TPD.find(iConfig));
	if(it != m_MEM_TPD.end()) val = true;	
	LeaveCriticalSection(&csMemTPDLock);

	return val;
}

void CMinecraftApp::GetTPD(int iConfig,PBYTE *ppbData,DWORD *pdwBytes)
{
	EnterCriticalSection(&csMemTPDLock);
	AUTO_VAR(it, m_MEM_TPD.find(iConfig));
	if(it != m_MEM_TPD.end())
	{
		PMEMDATA pData = (*it).second;
		*ppbData=pData->pbData;
		*pdwBytes=pData->dwBytes;
	}
	LeaveCriticalSection(&csMemTPDLock);
}


// bool CMinecraftApp::UploadFileToGlobalStorage(int iQuadrant, C4JStorage::eGlobalStorage eStorageFacility, wstring *wsFile  )
// {
// 	bool bRes=false;
// #ifndef _CONTENT_PACKAGE
// 	// read the local file
// 	File gtsFile( wsFile->c_str() );
// 
// 	__int64 fileSize = gtsFile.length();
// 
// 	if(fileSize!=0)
// 	{
// 		FileInputStream fis(gtsFile);
// 		byteArray ba((int)fileSize);
// 		fis.read(ba);
// 		fis.close();
// 
// 		bRes=StorageManager.WriteTMSFile(iQuadrant,eStorageFacility,(WCHAR *)wsFile->c_str(),ba.data, ba.length);
// 
// 	}
// #endif
// 	return bRes;
// }






void CMinecraftApp::StoreLaunchData()
{

}

void CMinecraftApp::ExitGame()
{
}

// Invites

void CMinecraftApp::ProcessInvite(DWORD dwUserIndex, DWORD 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 CMinecraftApp::ExitAndJoinFromInvite(void *pParam,int iPad,C4JStorage::EMessageResult result)
{
	CMinecraftApp* pApp = (CMinecraftApp*)pParam;
	//Minecraft *pMinecraft=Minecraft::GetInstance();

	// buttons are swapped on this menu
	if(result==C4JStorage::EMessage_ResultDecline)
	{
		pApp->SetAction(iPad,eAppAction_ExitAndJoinFromInviteConfirmed);
	}

	return 0;
}

int CMinecraftApp::ExitAndJoinFromInviteSaveDialogReturned(void *pParam,int iPad,C4JStorage::EMessageResult result)
{
	CMinecraftApp *pClass = (CMinecraftApp *)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

#ifdef _XBOX
					DLCTexturePack *pDLCTexPack=(DLCTexturePack *)tPack;
					ULONGLONG ullOfferID_Full;
					app.GetDLCFullOfferIDForPackID(pDLCTexPack->getDLCParentPackId(),&ullOfferID_Full);

					// tell sentient about the upsell of the full version of the skin pack
					TelemetryManager->RecordUpsellPresented(iPad, eSet_UpsellID_Texture_DLC, ullOfferID_Full & 0xFFFFFFFF);
#endif

					UINT uiIDA[2];
					uiIDA[0]=IDS_CONFIRM_OK;
					uiIDA[1]=IDS_CONFIRM_CANCEL;

					// Give the player a warning about the trial version of the texture pack
					ui.RequestMessageBox(IDS_WARNING_DLC_TRIALTEXTUREPACK_TITLE, IDS_WARNING_DLC_TRIALTEXTUREPACK_TEXT, uiIDA, 2, iPad,&CMinecraftApp::WarningTrialTexturePackReturned,pClass,app.GetStringTable());

					return S_OK;					
				}
			}
#ifndef _XBOX_ONE
			// 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)
			{
				UINT uiIDA[2];
				uiIDA[0]=IDS_CONFIRM_CANCEL;
				uiIDA[1]=IDS_CONFIRM_OK;
				ui.RequestMessageBox(IDS_TITLE_SAVE_GAME, IDS_CONFIRM_SAVE_GAME, uiIDA, 2, ProfileManager.GetPrimaryPad(),&CMinecraftApp::ExitAndJoinFromInviteAndSaveReturned,pClass, app.GetStringTable());
				return 0;
			}
			else
#endif
			{
#if defined(_XBOX_ONE) || defined(__ORBIS__)
				StorageManager.SetSaveDisabled(false);
#endif
				MinecraftServer::getInstance()->setSaveOnExit( true );
			}
		}
		else
		{
			// been a few requests for a confirm on exit without saving
			UINT uiIDA[2];
			uiIDA[0]=IDS_CONFIRM_CANCEL;
			uiIDA[1]=IDS_CONFIRM_OK;
			ui.RequestMessageBox(IDS_TITLE_DECLINE_SAVE_GAME, IDS_CONFIRM_DECLINE_SAVE_GAME, uiIDA, 2, ProfileManager.GetPrimaryPad(),&CMinecraftApp::ExitAndJoinFromInviteDeclineSaveReturned,pClass, app.GetStringTable());
			return 0;
		}

		app.SetAction(ProfileManager.GetPrimaryPad(),eAppAction_ExitAndJoinFromInviteConfirmed);
	}
	return 0;
}

int CMinecraftApp::WarningTrialTexturePackReturned(void *pParam,int iPad,C4JStorage::EMessageResult result)
{
#ifdef _XBOX

	CMinecraftApp* pClass = (CMinecraftApp*)pParam;

	TexturePack *tPack = Minecraft::GetInstance()->skins->getSelected();
	// get the dlc texture pack
	DLCTexturePack *pDLCTexPack=(DLCTexturePack *)tPack;
	ULONGLONG ullIndexA[1];

	// Need to get the parent packs id, since this may be one of many child packs with their own ids
	app.GetDLCFullOfferIDForPackID(pDLCTexPack->getDLCParentPackId(),&ullIndexA[0]);

	if(result==C4JStorage::EMessage_ResultAccept)
	{
		if(ProfileManager.IsSignedIn(iPad))
		{	
			// need to allow downloads here, or the player would need to quit the game to let the download of a texture pack happen. This might affect the network traffic, since the download could take all the bandwidth...
			XBackgroundDownloadSetMode(XBACKGROUND_DOWNLOAD_MODE_ALWAYS_ALLOW);

			StorageManager.InstallOffer(1,ullIndexA,NULL,NULL);
		}
	}
	else
	{
		TelemetryManager->RecordUpsellResponded(iPad, eSet_UpsellID_Texture_DLC, ( ullIndexA[0] & 0xFFFFFFFF ), eSen_UpsellOutcome_Declined);
	}
#endif
	return 0;
}

int CMinecraftApp::ExitAndJoinFromInviteAndSaveReturned(void *pParam,int iPad,C4JStorage::EMessageResult result)
{
	//CMinecraftApp* pClass = (CMinecraftApp*)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

#ifdef _XBOX
				DLCTexturePack *pDLCTexPack=(DLCTexturePack *)tPack;
				ULONGLONG ullOfferID_Full;
				app.GetDLCFullOfferIDForPackID(pDLCTexPack->getDLCParentPackId(),&ullOfferID_Full);

				// tell sentient about the upsell of the full version of the skin pack
				TelemetryManager->RecordUpsellPresented(iPad, eSet_UpsellID_Texture_DLC, ullOfferID_Full & 0xFFFFFFFF);
#endif

				UINT uiIDA[2];
				uiIDA[0]=IDS_CONFIRM_OK;
				uiIDA[1]=IDS_CONFIRM_CANCEL;

				// Give the player a warning about the trial version of the texture pack
				ui.RequestMessageBox(IDS_WARNING_DLC_TRIALTEXTUREPACK_TITLE, IDS_WARNING_DLC_TRIALTEXTUREPACK_TEXT, uiIDA, 2, iPad,&CMinecraftApp::WarningTrialTexturePackReturned,NULL,app.GetStringTable());

				return S_OK;					
			}
		}
		//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 CMinecraftApp::ExitAndJoinFromInviteDeclineSaveReturned(void *pParam,int iPad,C4JStorage::EMessageResult result)
{
	// results switched for this dialog
	if(result==C4JStorage::EMessage_ResultDecline) 
	{
#if defined(_XBOX_ONE) || defined(__ORBIS__)
				StorageManager.SetSaveDisabled(false);
#endif
		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 CMinecraftApp::FatalLoadError()
{

}

TIPSTRUCT CMinecraftApp::m_GameTipA[MAX_TIPS_GAMETIP]=
{
	{ 0, IDS_TIPS_GAMETIP_1},
	{ 0, IDS_TIPS_GAMETIP_2},
	{ 0, IDS_TIPS_GAMETIP_3},
	{ 0, IDS_TIPS_GAMETIP_4},
	{ 0, IDS_TIPS_GAMETIP_5},
	{ 0, IDS_TIPS_GAMETIP_6},
	{ 0, IDS_TIPS_GAMETIP_7},
	{ 0, IDS_TIPS_GAMETIP_8},
	{ 0, IDS_TIPS_GAMETIP_9},
	{ 0, IDS_TIPS_GAMETIP_10},
	{ 0, IDS_TIPS_GAMETIP_11},
	{ 0, IDS_TIPS_GAMETIP_12},
	{ 0, IDS_TIPS_GAMETIP_13},
	{ 0, IDS_TIPS_GAMETIP_14},
	{ 0, IDS_TIPS_GAMETIP_15},
	{ 0, IDS_TIPS_GAMETIP_16},
	{ 0, IDS_TIPS_GAMETIP_17},
	{ 0, IDS_TIPS_GAMETIP_18},
	{ 0, IDS_TIPS_GAMETIP_19},
	{ 0, IDS_TIPS_GAMETIP_20},
	{ 0, IDS_TIPS_GAMETIP_21},
	{ 0, IDS_TIPS_GAMETIP_22},
	{ 0, IDS_TIPS_GAMETIP_23},
	{ 0, IDS_TIPS_GAMETIP_24},
	{ 0, IDS_TIPS_GAMETIP_25},
	{ 0, IDS_TIPS_GAMETIP_26},
	{ 0, IDS_TIPS_GAMETIP_27},
	{ 0, IDS_TIPS_GAMETIP_28},
	{ 0, IDS_TIPS_GAMETIP_29},
	{ 0, IDS_TIPS_GAMETIP_30},
	{ 0, IDS_TIPS_GAMETIP_31},
	{ 0, IDS_TIPS_GAMETIP_32},
	{ 0, IDS_TIPS_GAMETIP_33},
	{ 0, IDS_TIPS_GAMETIP_34},
	{ 0, IDS_TIPS_GAMETIP_35},
	{ 0, IDS_TIPS_GAMETIP_36},
	{ 0, IDS_TIPS_GAMETIP_37},
	{ 0, IDS_TIPS_GAMETIP_38},
	{ 0, IDS_TIPS_GAMETIP_39},
	{ 0, IDS_TIPS_GAMETIP_40},
	{ 0, IDS_TIPS_GAMETIP_41},
	{ 0, IDS_TIPS_GAMETIP_42},
	{ 0, IDS_TIPS_GAMETIP_43},
	{ 0, IDS_TIPS_GAMETIP_44},
	{ 0, IDS_TIPS_GAMETIP_45},
	{ 0, IDS_TIPS_GAMETIP_46},
	{ 0, IDS_TIPS_GAMETIP_47},
	{ 0, IDS_TIPS_GAMETIP_48},
	{ 0, IDS_TIPS_GAMETIP_49},
	{ 0, IDS_TIPS_GAMETIP_50},
};

TIPSTRUCT CMinecraftApp::m_TriviaTipA[MAX_TIPS_TRIVIATIP]=
{
	{ 0, IDS_TIPS_TRIVIA_1},
	{ 0, IDS_TIPS_TRIVIA_2},
	{ 0, IDS_TIPS_TRIVIA_3},
	{ 0, IDS_TIPS_TRIVIA_4},
	{ 0, IDS_TIPS_TRIVIA_5},
	{ 0, IDS_TIPS_TRIVIA_6},
	{ 0, IDS_TIPS_TRIVIA_7},
	{ 0, IDS_TIPS_TRIVIA_8},
	{ 0, IDS_TIPS_TRIVIA_9},
	{ 0, IDS_TIPS_TRIVIA_10},
	{ 0, IDS_TIPS_TRIVIA_11},
	{ 0, IDS_TIPS_TRIVIA_12},
	{ 0, IDS_TIPS_TRIVIA_13},
	{ 0, IDS_TIPS_TRIVIA_14},
	{ 0, IDS_TIPS_TRIVIA_15},
	{ 0, IDS_TIPS_TRIVIA_16},
	{ 0, IDS_TIPS_TRIVIA_17},
	{ 0, IDS_TIPS_TRIVIA_18},
	{ 0, IDS_TIPS_TRIVIA_19},
	{ 0, IDS_TIPS_TRIVIA_20},
};

Random *CMinecraftApp::TipRandom = new Random();

int CMinecraftApp::TipsSortFunction(const void* a, const void* b)
{
	return ((TIPSTRUCT*)a)->iSortValue - ((TIPSTRUCT*)b)->iSortValue;
}

void CMinecraftApp::InitialiseTips()
{
	// We'll randomise the tips at start up based on their priority

	ZeroMemory(m_TipIDA,sizeof(UINT)*MAX_TIPS_GAMETIP+MAX_TIPS_TRIVIATIP);

	// Make the first tip tell you that you can play splitscreen in HD modes if you are in SD
	if(!RenderManager.IsHiDef())
	{
		m_GameTipA[0].uiStringID=IDS_TIPS_GAMETIP_0;
	}
	// randomise then quicksort
	// going to leave the multiplayer tip so it is always first

// Only randomise the content package build
#ifdef _CONTENT_PACKAGE
	
	for(int i=1;i<MAX_TIPS_GAMETIP;i++)
	{
		m_GameTipA[i].iSortValue=TipRandom->nextInt();
	}
	qsort( &m_GameTipA[1], MAX_TIPS_GAMETIP-1, sizeof(TIPSTRUCT), TipsSortFunction );
#endif

	for(int i=0;i<MAX_TIPS_TRIVIATIP;i++)
	{
		m_TriviaTipA[i].iSortValue=TipRandom->nextInt();
	}
	qsort( m_TriviaTipA, MAX_TIPS_TRIVIATIP, sizeof(TIPSTRUCT), TipsSortFunction );


	int iCurrentGameTip=0;
	int iCurrentTriviaTip=0;

	for(int i=0;i<MAX_TIPS_GAMETIP+MAX_TIPS_TRIVIATIP;i++)
	{
		// Add a trivia one every third tip (if there are any left)
		if((i%3==2) && (iCurrentTriviaTip<MAX_TIPS_TRIVIATIP))
		{
			// Add a trivia one
			m_TipIDA[i]=m_TriviaTipA[iCurrentTriviaTip++].uiStringID;
		}
		else
		{
			if(iCurrentGameTip<MAX_TIPS_GAMETIP)
			{
				// Add a gametip
				m_TipIDA[i]=m_GameTipA[iCurrentGameTip++].uiStringID;
			}
			else
			{
				// Add a trivia one
				m_TipIDA[i]=m_TriviaTipA[iCurrentTriviaTip++].uiStringID;
			}
		}

		if(m_TipIDA[i]==0)
		{
			// the m_TriviaTipA or the m_GameTipA are out of sync
#ifndef _CONTENT_PACKAGE
			__debugbreak();
#endif
		}
	}

	m_uiCurrentTip=0;
}

UINT CMinecraftApp::GetNextTip()
{
	static bool bShowSkinDLCTip=true;
	// don't display the DLC tip in the trial game
	if(ProfileManager.IsFullVersion() && app.GetNewDLCAvailable() && app.DisplayNewDLCTip())
	{
		return IDS_TIPS_GAMETIP_NEWDLC;
	}
	else
	{
		if(bShowSkinDLCTip && ProfileManager.IsFullVersion()) 
		{
			bShowSkinDLCTip=false;
			if( app.DLCInstallProcessCompleted() )
			{
				if(app.m_dlcManager.getPackCount(DLCManager::e_DLCType_Skin)==0)
				{
					return IDS_TIPS_GAMETIP_SKINPACKS;
				}
			}
			else
			{
				return IDS_TIPS_GAMETIP_SKINPACKS;
			}
		}
	}

	if(m_uiCurrentTip==MAX_TIPS_GAMETIP+MAX_TIPS_TRIVIATIP) m_uiCurrentTip=0;

	return m_TipIDA[m_uiCurrentTip++];
}

int CMinecraftApp::GetHTMLColour(eMinecraftColour colour)
{
	Minecraft *pMinecraft = Minecraft::GetInstance();
	return pMinecraft->skins->getSelected()->getColourTable()->getColour(colour);
}

int CMinecraftApp::GetHTMLFontSize(EHTMLFontSize size)
{
	return s_iHTMLFontSizesA[size];
}

wstring CMinecraftApp::FormatHTMLString(int iPad, const wstring &desc, int shadowColour /*= 0xFFFFFFFF*/)
{
	wstring text(desc);
	
	wchar_t replacements[64];
	// We will also insert line breaks here as couldn't figure out how to get them to come through from strings.resx !
	text = replaceAll(text, L"{*B*}", L"<br />" );
	swprintf(replacements,64,L"<font color=\"#%08x\">", GetHTMLColour(eHTMLColor_T1));
	text = replaceAll(text, L"{*T1*}", replacements );
	swprintf(replacements,64,L"<font color=\"#%08x\">", GetHTMLColour(eHTMLColor_T2));
	text = replaceAll(text, L"{*T2*}", replacements );
	swprintf(replacements,64,L"<font color=\"#%08x\">", GetHTMLColour(eHTMLColor_T3));
	text = replaceAll(text, L"{*T3*}", replacements ); // for How To Play
	swprintf(replacements,64,L"</font><font color=\"#%08x\">", GetHTMLColour(eHTMLColor_Black));
	text = replaceAll(text, L"{*ETB*}", replacements );
	swprintf(replacements,64,L"</font><font color=\"#%08x\">", GetHTMLColour(eHTMLColor_White));
	text = replaceAll(text, L"{*ETW*}", replacements );
	text = replaceAll(text, L"{*EF*}", L"</font>" );

	swprintf(replacements,64,L"<font color=\"#%08x\" shadowcolor=\"#%08x\">", GetHTMLColour(eHTMLColor_0), shadowColour);
	text = replaceAll(text, L"{*C0*}", replacements );
	swprintf(replacements,64,L"<font color=\"#%08x\" shadowcolor=\"#%08x\">", GetHTMLColour(eHTMLColor_1), shadowColour);
	text = replaceAll(text, L"{*C1*}", replacements );
	swprintf(replacements,64,L"<font color=\"#%08x\" shadowcolor=\"#%08x\">", GetHTMLColour(eHTMLColor_2), shadowColour);
	text = replaceAll(text, L"{*C2*}", replacements );
	swprintf(replacements,64,L"<font color=\"#%08x\" shadowcolor=\"#%08x\">", GetHTMLColour(eHTMLColor_3), shadowColour);
	text = replaceAll(text, L"{*C3*}", replacements );
	swprintf(replacements,64,L"<font color=\"#%08x\" shadowcolor=\"#%08x\">", GetHTMLColour(eHTMLColor_4), shadowColour);
	text = replaceAll(text, L"{*C4*}", replacements );
	swprintf(replacements,64,L"<font color=\"#%08x\" shadowcolor=\"#%08x\">", GetHTMLColour(eHTMLColor_5), shadowColour);
	text = replaceAll(text, L"{*C5*}", replacements );
	swprintf(replacements,64,L"<font color=\"#%08x\" shadowcolor=\"#%08x\">", GetHTMLColour(eHTMLColor_6), shadowColour);
	text = replaceAll(text, L"{*C6*}", replacements );
	swprintf(replacements,64,L"<font color=\"#%08x\" shadowcolor=\"#%08x\">", GetHTMLColour(eHTMLColor_7), shadowColour);
	text = replaceAll(text, L"{*C7*}", replacements );
	swprintf(replacements,64,L"<font color=\"#%08x\" shadowcolor=\"#%08x\">", GetHTMLColour(eHTMLColor_8), shadowColour);
	text = replaceAll(text, L"{*C8*}", replacements );
	swprintf(replacements,64,L"<font color=\"#%08x\" shadowcolor=\"#%08x\">", GetHTMLColour(eHTMLColor_9), shadowColour);
	text = replaceAll(text, L"{*C9*}", replacements );
	swprintf(replacements,64,L"<font color=\"#%08x\" shadowcolor=\"#%08x\">", GetHTMLColour(eHTMLColor_a), shadowColour);
	text = replaceAll(text, L"{*CA*}", replacements );
	swprintf(replacements,64,L"<font color=\"#%08x\" shadowcolor=\"#%08x\">", GetHTMLColour(eHTMLColor_b), shadowColour);
	text = replaceAll(text, L"{*CB*}", replacements );
	swprintf(replacements,64,L"<font color=\"#%08x\" shadowcolor=\"#%08x\">", GetHTMLColour(eHTMLColor_c), shadowColour);
	text = replaceAll(text, L"{*CC*}", replacements );
	swprintf(replacements,64,L"<font color=\"#%08x\" shadowcolor=\"#%08x\">", GetHTMLColour(eHTMLColor_d), shadowColour);
	text = replaceAll(text, L"{*CD*}", replacements );
	swprintf(replacements,64,L"<font color=\"#%08x\" shadowcolor=\"#%08x\">", GetHTMLColour(eHTMLColor_e), shadowColour);
	text = replaceAll(text, L"{*CE*}", replacements );
	swprintf(replacements,64,L"<font color=\"#%08x\" shadowcolor=\"#%08x\">", GetHTMLColour(eHTMLColor_f), shadowColour);
	text = replaceAll(text, L"{*CF*}", replacements );

	// Swap for southpaw.
	if ( app.GetGameSettings(iPad,eGameSetting_ControlSouthPaw) )
	{
		text = replaceAll(text, L"{*CONTROLLER_ACTION_MOVE*}",			GetActionReplacement(iPad,MINECRAFT_ACTION_LOOK_RIGHT		) );
		text = replaceAll(text, L"{*CONTROLLER_ACTION_LOOK*}",			GetActionReplacement(iPad,MINECRAFT_ACTION_RIGHT	) );

		text = replaceAll(text, L"{*CONTROLLER_MENU_NAVIGATE*}",		GetVKReplacement(VK_PAD_RTHUMB_LEFT) );
	}
	else // Normal right handed.
	{
		text = replaceAll(text, L"{*CONTROLLER_ACTION_MOVE*}",			GetActionReplacement(iPad,MINECRAFT_ACTION_RIGHT		) );
		text = replaceAll(text, L"{*CONTROLLER_ACTION_LOOK*}",			GetActionReplacement(iPad,MINECRAFT_ACTION_LOOK_RIGHT	) );

		text = replaceAll(text, L"{*CONTROLLER_MENU_NAVIGATE*}",		GetVKReplacement(VK_PAD_LTHUMB_LEFT) );
	}

	text = replaceAll(text, L"{*CONTROLLER_ACTION_JUMP*}",			GetActionReplacement(iPad,MINECRAFT_ACTION_JUMP			) );
	text = replaceAll(text, L"{*CONTROLLER_ACTION_SNEAK*}",			GetActionReplacement(iPad,MINECRAFT_ACTION_SNEAK_TOGGLE			) );
	text = replaceAll(text, L"{*CONTROLLER_ACTION_USE*}",			GetActionReplacement(iPad,MINECRAFT_ACTION_USE			) );
	text = replaceAll(text, L"{*CONTROLLER_ACTION_ACTION*}",		GetActionReplacement(iPad,MINECRAFT_ACTION_ACTION		) );
	text = replaceAll(text, L"{*CONTROLLER_ACTION_LEFT_SCROLL*}",	GetActionReplacement(iPad,MINECRAFT_ACTION_LEFT_SCROLL	) );
	text = replaceAll(text, L"{*CONTROLLER_ACTION_RIGHT_SCROLL*}",	GetActionReplacement(iPad,MINECRAFT_ACTION_RIGHT_SCROLL ) );
	text = replaceAll(text, L"{*CONTROLLER_ACTION_INVENTORY*}",		GetActionReplacement(iPad,MINECRAFT_ACTION_INVENTORY	) );
	text = replaceAll(text, L"{*CONTROLLER_ACTION_CRAFTING*}",		GetActionReplacement(iPad,MINECRAFT_ACTION_CRAFTING		) );
	text = replaceAll(text, L"{*CONTROLLER_ACTION_DROP*}",			GetActionReplacement(iPad,MINECRAFT_ACTION_DROP			) );
	text = replaceAll(text, L"{*CONTROLLER_ACTION_CAMERA*}",		GetActionReplacement(iPad,MINECRAFT_ACTION_RENDER_THIRD_PERSON	) );
	text = replaceAll(text, L"{*CONTROLLER_VK_A*}",					GetVKReplacement(VK_PAD_A) );
	text = replaceAll(text, L"{*CONTROLLER_VK_B*}",					GetVKReplacement(VK_PAD_B) );
	text = replaceAll(text, L"{*CONTROLLER_VK_X*}",					GetVKReplacement(VK_PAD_X) );
	text = replaceAll(text, L"{*CONTROLLER_VK_Y*}",					GetVKReplacement(VK_PAD_Y) );
	text = replaceAll(text, L"{*CONTROLLER_VK_LB*}",				GetVKReplacement(VK_PAD_LSHOULDER) );
	text = replaceAll(text, L"{*CONTROLLER_VK_RB*}",				GetVKReplacement(VK_PAD_RSHOULDER) );
	text = replaceAll(text, L"{*CONTROLLER_VK_LS*}",				GetVKReplacement(VK_PAD_LTHUMB_UP) );
	text = replaceAll(text, L"{*CONTROLLER_VK_RS*}",				GetVKReplacement(VK_PAD_RTHUMB_UP) );
	text = replaceAll(text, L"{*CONTROLLER_VK_LT*}",				GetVKReplacement(VK_PAD_LTRIGGER) );
	text = replaceAll(text, L"{*CONTROLLER_VK_RT*}",				GetVKReplacement(VK_PAD_RTRIGGER) );
	text = replaceAll(text, L"{*ICON_SHANK_01*}",					GetIconReplacement(XZP_ICON_SHANK_01) );
	text = replaceAll(text, L"{*ICON_SHANK_03*}",					GetIconReplacement(XZP_ICON_SHANK_03) );
	text = replaceAll(text, L"{*CONTROLLER_ACTION_DPAD_UP*}",		GetActionReplacement(iPad,MINECRAFT_ACTION_DPAD_UP			) );
	text = replaceAll(text, L"{*CONTROLLER_ACTION_DPAD_DOWN*}",		GetActionReplacement(iPad,MINECRAFT_ACTION_DPAD_DOWN		) );
	text = replaceAll(text, L"{*CONTROLLER_ACTION_DPAD_RIGHT*}",	GetActionReplacement(iPad,MINECRAFT_ACTION_DPAD_RIGHT		) );	
	text = replaceAll(text, L"{*CONTROLLER_ACTION_DPAD_LEFT*}",		GetActionReplacement(iPad,MINECRAFT_ACTION_DPAD_LEFT		) );
#if defined _XBOX_ONE || defined __PSVITA__
	text = replaceAll(text, L"{*CONTROLLER_VK_START*}",			GetVKReplacement(VK_PAD_START		) );
	text = replaceAll(text, L"{*CONTROLLER_VK_BACK*}",			GetVKReplacement(VK_PAD_BACK		) );
#endif

#ifdef _XBOX
	wstring imageRoot = L"";

	Minecraft *pMinecraft = Minecraft::GetInstance();
	imageRoot = pMinecraft->skins->getSelected()->getXuiRootPath();

	text = replaceAll(text, L"{*IMAGEROOT*}", imageRoot);
#endif // _XBOX

	// Fix for #8903 - UI: Localization: KOR/JPN/CHT: Button Icons are rendered with padding space, which looks no good	
	DWORD dwLanguage = XGetLanguage( );
	switch(dwLanguage)
	{
	case XC_LANGUAGE_KOREAN:	
	case XC_LANGUAGE_JAPANESE:
	case XC_LANGUAGE_TCHINESE:		
		text = replaceAll(text, L"&nbsp;", L"" );
		break;
	}

	return text;
}

wstring CMinecraftApp::GetActionReplacement(int iPad, unsigned char ucAction)
{
	unsigned int input = InputManager.GetGameJoypadMaps(InputManager.GetJoypadMapVal(iPad) ,ucAction);

#ifdef _XBOX
	switch(input)
	{
	case _360_JOY_BUTTON_A:
		return app.GetString( IDS_CONTROLLER_A );
	case _360_JOY_BUTTON_B:
		return app.GetString( IDS_CONTROLLER_B );
	case _360_JOY_BUTTON_X:
		return app.GetString( IDS_CONTROLLER_X );
	case _360_JOY_BUTTON_Y:
		return app.GetString( IDS_CONTROLLER_Y );
	case _360_JOY_BUTTON_LSTICK_UP:
	case _360_JOY_BUTTON_LSTICK_DOWN:
	case _360_JOY_BUTTON_LSTICK_LEFT:
	case _360_JOY_BUTTON_LSTICK_RIGHT:
		return app.GetString( IDS_CONTROLLER_LEFT_STICK );
	case _360_JOY_BUTTON_RSTICK_LEFT:
	case _360_JOY_BUTTON_RSTICK_RIGHT:
	case _360_JOY_BUTTON_RSTICK_UP:
	case _360_JOY_BUTTON_RSTICK_DOWN:
		return app.GetString( IDS_CONTROLLER_RIGHT_STICK );
	case _360_JOY_BUTTON_LT:
		return app.GetString( IDS_CONTROLLER_LEFT_TRIGGER );
	case _360_JOY_BUTTON_RT:
		return app.GetString( IDS_CONTROLLER_RIGHT_TRIGGER );
	case _360_JOY_BUTTON_RB:
		return app.GetString( IDS_CONTROLLER_RIGHT_BUMPER );
	case _360_JOY_BUTTON_LB:
		return app.GetString( IDS_CONTROLLER_LEFT_BUMPER );
	case _360_JOY_BUTTON_BACK:
		return app.GetString( IDS_CONTROLLER_BACK );
	case _360_JOY_BUTTON_START:
		return app.GetString( IDS_CONTROLLER_START );
	case _360_JOY_BUTTON_RTHUMB:
		return app.GetString( IDS_CONTROLLER_RIGHT_THUMBSTICK );
	case _360_JOY_BUTTON_LTHUMB:
		return app.GetString( IDS_CONTROLLER_LEFT_THUMBSTICK );
	case _360_JOY_BUTTON_DPAD_LEFT:
		return app.GetString( IDS_CONTROLLER_DPAD_L );
	case _360_JOY_BUTTON_DPAD_RIGHT:
		return app.GetString( IDS_CONTROLLER_DPAD_R );
	case _360_JOY_BUTTON_DPAD_UP:
		return app.GetString( IDS_CONTROLLER_DPAD_U );
	case _360_JOY_BUTTON_DPAD_DOWN:
		return app.GetString( IDS_CONTROLLER_DPAD_D );
	};
	return L"";
#else
	wstring replacement = L"";

	// 4J Stu - Some of our actions can be mapped to multiple physical buttons, so replaces the switch that was here
	if (input & _360_JOY_BUTTON_A) replacement = L"ButtonA";
	else if(input &_360_JOY_BUTTON_B) replacement = L"ButtonB";
	else if(input &_360_JOY_BUTTON_X) replacement = L"ButtonX";
	else if(input &_360_JOY_BUTTON_Y) replacement = L"ButtonY";
	else if(
			(input &_360_JOY_BUTTON_LSTICK_UP) ||
			(input &_360_JOY_BUTTON_LSTICK_DOWN) ||
			(input &_360_JOY_BUTTON_LSTICK_LEFT) ||
			(input &_360_JOY_BUTTON_LSTICK_RIGHT)
			)
	{
		replacement = L"ButtonLeftStick";
	}
	else if(
			(input &_360_JOY_BUTTON_RSTICK_LEFT) ||
			(input &_360_JOY_BUTTON_RSTICK_RIGHT) ||
			(input &_360_JOY_BUTTON_RSTICK_UP) ||
			(input &_360_JOY_BUTTON_RSTICK_DOWN)
			)
	{
		replacement = L"ButtonRightStick";
	}
	else if(input &_360_JOY_BUTTON_DPAD_LEFT) replacement = L"ButtonDpadL";
	else if(input &_360_JOY_BUTTON_DPAD_RIGHT) replacement = L"ButtonDpadR";
	else if(input &_360_JOY_BUTTON_DPAD_UP) replacement = L"ButtonDpadU";
	else if(input &_360_JOY_BUTTON_DPAD_DOWN) replacement = L"ButtonDpadD";
	else if(input &_360_JOY_BUTTON_LT) replacement = L"ButtonLeftTrigger";
	else if(input &_360_JOY_BUTTON_RT) replacement = L"ButtonRightTrigger";
	else if(input &_360_JOY_BUTTON_RB) replacement = L"ButtonRightBumper";
	else if(input &_360_JOY_BUTTON_LB) replacement = L"ButtonLeftBumper";
	else if(input &_360_JOY_BUTTON_BACK) replacement = L"ButtonBack";
	else if(input &_360_JOY_BUTTON_START) replacement = L"ButtonStart";
	else if(input &_360_JOY_BUTTON_RTHUMB) replacement = L"ButtonRS";
	else if(input &_360_JOY_BUTTON_LTHUMB) replacement = L"ButtonLS";

	wchar_t string[128];

#ifdef __PS3__
	int size = 30;
#elif defined _WIN64
	int size = 45;
	if(ui.getScreenWidth() < 1920) size = 30;
#else
	int size = 45;
#endif

	swprintf(string,128,L"<img src=\"%ls\" align=\"middle\" height=\"%d\" width=\"%d\"/>", replacement.c_str(), size, size);

	return string;
#endif
}

wstring CMinecraftApp::GetVKReplacement(unsigned int uiVKey)
{
#ifdef _XBOX
	switch(uiVKey)
	{
	case VK_PAD_A:
		return app.GetString( IDS_CONTROLLER_A );
	case VK_PAD_B:
		return app.GetString( IDS_CONTROLLER_B );
	case VK_PAD_X:
		return app.GetString( IDS_CONTROLLER_X );
	case VK_PAD_Y:
		return app.GetString( IDS_CONTROLLER_Y );
	case VK_PAD_LSHOULDER:
		return app.GetString( IDS_CONTROLLER_LEFT_BUMPER );
	case VK_PAD_RSHOULDER:
		return app.GetString( IDS_CONTROLLER_RIGHT_BUMPER );
	case VK_PAD_LTRIGGER:
		return app.GetString( IDS_CONTROLLER_LEFT_TRIGGER );
	case VK_PAD_RTRIGGER:
		return app.GetString( IDS_CONTROLLER_RIGHT_TRIGGER );
	case VK_PAD_LTHUMB_UP       :
	case VK_PAD_LTHUMB_DOWN     :
	case VK_PAD_LTHUMB_RIGHT    :
	case VK_PAD_LTHUMB_LEFT     :
	case VK_PAD_LTHUMB_UPLEFT   :
	case VK_PAD_LTHUMB_UPRIGHT  :
	case VK_PAD_LTHUMB_DOWNRIGHT:
	case VK_PAD_LTHUMB_DOWNLEFT :	
		return app.GetString( IDS_CONTROLLER_LEFT_STICK );
	case VK_PAD_RTHUMB_UP       :
	case VK_PAD_RTHUMB_DOWN     :
	case VK_PAD_RTHUMB_RIGHT    :
	case VK_PAD_RTHUMB_LEFT     :
	case VK_PAD_RTHUMB_UPLEFT   :
	case VK_PAD_RTHUMB_UPRIGHT  :
	case VK_PAD_RTHUMB_DOWNRIGHT:
	case VK_PAD_RTHUMB_DOWNLEFT :	
		return app.GetString( IDS_CONTROLLER_RIGHT_STICK );
	default:
		break;
	}
	return NULL;
#else
	wstring replacement = L"";
	switch(uiVKey)
	{
	case VK_PAD_A:
#if defined(__PS3__) || defined(__ORBIS__) || defined (__PSVITA__)
		if( InputManager.IsCircleCrossSwapped() ) replacement = L"ButtonB";
		else replacement = L"ButtonA";
#else
		replacement = L"ButtonA";
#endif
		break;
	case VK_PAD_B:
#if defined(__PS3__) || defined(__ORBIS__) || defined (__PSVITA__)
		if( InputManager.IsCircleCrossSwapped() ) replacement = L"ButtonA";
		else replacement = L"ButtonB";
#else
		replacement = L"ButtonB";
#endif
		break;
	case VK_PAD_X:
		replacement = L"ButtonX";
		break;
	case VK_PAD_Y:
		replacement = L"ButtonY";
		break;
	case VK_PAD_LSHOULDER:
		replacement = L"ButtonLeftBumper";
		break;
	case VK_PAD_RSHOULDER:
		replacement = L"ButtonRightBumper";
		break;
	case VK_PAD_LTRIGGER:
		replacement = L"ButtonLeftTrigger";
		break;
	case VK_PAD_RTRIGGER:
		replacement = L"ButtonRightTrigger";
		break;
	case VK_PAD_LTHUMB_UP       :
	case VK_PAD_LTHUMB_DOWN     :
	case VK_PAD_LTHUMB_RIGHT    :
	case VK_PAD_LTHUMB_LEFT     :
	case VK_PAD_LTHUMB_UPLEFT   :
	case VK_PAD_LTHUMB_UPRIGHT  :
	case VK_PAD_LTHUMB_DOWNRIGHT:
	case VK_PAD_LTHUMB_DOWNLEFT :
		replacement = L"ButtonLeftStick";
		break;
	case VK_PAD_RTHUMB_UP       :
	case VK_PAD_RTHUMB_DOWN     :
	case VK_PAD_RTHUMB_RIGHT    :
	case VK_PAD_RTHUMB_LEFT     :
	case VK_PAD_RTHUMB_UPLEFT   :
	case VK_PAD_RTHUMB_UPRIGHT  :
	case VK_PAD_RTHUMB_DOWNRIGHT:
	case VK_PAD_RTHUMB_DOWNLEFT :
		replacement = L"ButtonRightStick";
		break;
#if defined _XBOX_ONE || defined __PSVITA__
	case VK_PAD_START:
		replacement = L"ButtonStart";
		break;
	case VK_PAD_BACK:
		replacement = L"ButtonBack";
		break;
#endif
	default:
		break;
	}
	wchar_t string[128];

#ifdef __PS3__
	int size = 30;
#elif defined _WIN64
	int size = 45;
	if(ui.getScreenWidth() < 1920) size = 30;
#else
	int size = 45;
#endif

	swprintf(string,128,L"<img src=\"%ls\" align=\"middle\" height=\"%d\" width=\"%d\"/>", replacement.c_str(), size, size);

	return string;
#endif
}

wstring CMinecraftApp::GetIconReplacement(unsigned int uiIcon)
{
#ifdef _XBOX
	switch(uiIcon)
	{
	case XZP_ICON_SHANK_01:
		return app.GetString( IDS_ICON_SHANK_01 );
	case XZP_ICON_SHANK_03:
		return app.GetString( IDS_ICON_SHANK_03 );
	default:
		break;
	}
	return NULL;
#else
	wchar_t string[128];

#ifdef __PS3__
	int size = 22;
#elif defined _WIN64
	int size = 33;
	if(ui.getScreenWidth() < 1920) size = 22;
#else
	int size = 33;
#endif

	swprintf(string,128,L"<img src=\"Icon_Shank\" align=\"middle\" height=\"%d\" width=\"%d\"/>", size, size);
	wstring result = L"";
	switch(uiIcon)
	{
	case XZP_ICON_SHANK_01:
		result = string;
		break;
	case XZP_ICON_SHANK_03:
		result.append(string).append(string).append(string);
		break;
	default:
		break;
	}
	return result;
#endif
}

#if defined(__PS3__) || defined(__ORBIS__) || defined (__PSVITA__)
unordered_map<PlayerUID, MOJANG_DATA *, PlayerUID::Hash> CMinecraftApp::MojangData;
unordered_map<int, char * >  CMinecraftApp::DLCTextures_PackID;
unordered_map<string, DLC_INFO * >  CMinecraftApp::DLCInfo;
unordered_map<wstring, ULONGLONG >  CMinecraftApp::DLCInfo_SkinName;
#elif defined(_DURANGO)
unordered_map<PlayerUID,MOJANG_DATA *, PlayerUID::Hash > CMinecraftApp::MojangData;
unordered_map<int, wstring >  CMinecraftApp::DLCTextures_PackID; // for mash-up packs & texture packs
//unordered_map<ULONGLONG,DLC_INFO * > CMinecraftApp::DLCInfo_Trial; // full offerid, dlc_info
unordered_map<wstring,DLC_INFO * > CMinecraftApp::DLCInfo_Full; // full offerid, dlc_info
unordered_map<wstring, wstring >  CMinecraftApp::DLCInfo_SkinName; // skin name, full offer id
#else
unordered_map<PlayerUID, MOJANG_DATA *> CMinecraftApp::MojangData;
unordered_map<int, ULONGLONG >  CMinecraftApp::DLCTextures_PackID;
unordered_map<ULONGLONG, DLC_INFO * >  CMinecraftApp::DLCInfo_Trial;
unordered_map<ULONGLONG, DLC_INFO * >  CMinecraftApp::DLCInfo_Full;
unordered_map<wstring, ULONGLONG >  CMinecraftApp::DLCInfo_SkinName;
#endif



HRESULT CMinecraftApp::RegisterMojangData(WCHAR *pXuidName, PlayerUID xuid, WCHAR *pSkin, WCHAR *pCape)
{
	HRESULT hr=S_OK;
	eXUID eTempXuid=eXUID_Undefined;
	MOJANG_DATA *pMojangData=NULL;

	// ignore the names if we don't recognize them
	if(pXuidName!=NULL)
	{	
		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;
		ZeroMemory(pMojangData,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 *CMinecraftApp::GetMojangDataForXuid(PlayerUID xuid)
{
	return MojangData[xuid];
}

HRESULT CMinecraftApp::RegisterConfigValues(WCHAR *pType, int iValue)
{
	HRESULT hr=S_OK;

// #ifdef _XBOX
// 	if(pType!=NULL)
// 	{	
// 		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 _XBOX || defined _WINDOWS64)
HRESULT CMinecraftApp::RegisterDLCData(WCHAR *pType, WCHAR *pBannerName, int iGender, __uint64 ullOfferID_Full, __uint64 ullOfferID_Trial, WCHAR *pFirstSkin, unsigned int uiSortIndex, int iConfig, WCHAR *pDataFile)
{
	HRESULT hr=S_OK;
	DLC_INFO *pDLCData=new DLC_INFO;
	ZeroMemory(pDLCData,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;

#ifndef __ORBIS__
	// 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);
	}
#endif

	if(pType!=NULL)
	{	
		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 _XBOX_ONE

unordered_map<wstring,DLC_INFO * > *CMinecraftApp::GetDLCInfo()
{
	return &DLCInfo_Full;
}

HRESULT CMinecraftApp::RegisterDLCData(eDLCContentType eType, WCHAR *pwchBannerName,WCHAR *pwchProductId, WCHAR *pwchProductName, WCHAR *pwchFirstSkin, int iConfig, unsigned int uiSortIndex)
{
	HRESULT hr=S_OK;
	// 4J-PB - need to convert the product id to uppercase because the catalog calls come back with upper case
	WCHAR wchUppercaseProductID[64];
	if(pwchProductId[0]!=0)
	{
		for(int i=0;i<64;i++)
		{
			wchUppercaseProductID[i]=towupper((wchar_t)pwchProductId[i]);
		}
	}

	// check if we already have this info from the local DLC file
	wstring wsTemp=wchUppercaseProductID;

	AUTO_VAR(it, DLCInfo_Full.find(wsTemp));
	if( it == DLCInfo_Full.end() )
	{
		// Not found

		DLC_INFO *pDLCData=new DLC_INFO;
		ZeroMemory(pDLCData,sizeof(DLC_INFO));

		pDLCData->eDLCType=e_DLC_NotDefined;
		pDLCData->uiSortIndex=uiSortIndex;
		pDLCData->iConfig=iConfig;

		if(pwchProductId[0]!=0)
		{
			pDLCData->wsProductId=wchUppercaseProductID;
		}

		// ignore the names if we don't recognize them
		if(pwchBannerName!=L"")
		{	
			wcsncpy_s( pDLCData->wchBanner, pwchBannerName, MAX_BANNERNAME_SIZE);
		}

		if(pwchProductName[0]!=0)
		{	
			pDLCData->wsDisplayName=pwchProductName;
		}

		pDLCData->eDLCType=eType;

		switch(eType)
		{
		case e_DLC_MashupPacks:
		case e_DLC_TexturePacks:
				DLCTextures_PackID[iConfig]=pDLCData->wsProductId;
			break;
		}

		if(pwchFirstSkin[0]!=0) DLCInfo_SkinName[pwchFirstSkin]=pDLCData->wsProductId;

	#ifdef _XBOX_ONE
		// ignore the names, and use the product id instead
		DLCInfo_Full[pDLCData->wsProductId]=pDLCData;
	#else
		DLCInfo_Full[pDLCData->wsDisplayName]=pDLCData;
	#endif
	}
	app.DebugPrintf("DLCInfo - type - %d, productID - %ls, name - %ls , banner - %ls, iconfig - %d, sort index - %d\n",eType,pwchProductId, pwchProductName,pwchBannerName, iConfig, uiSortIndex);
	return hr;
}
#else

HRESULT CMinecraftApp::RegisterDLCData(char *pchDLCName, unsigned int uiSortIndex,char *pchImageURL)
{
	// on PS3 we get all the required info from the name
	char chDLCType[3];
	HRESULT hr=S_OK;
	DLC_INFO *pDLCData=new DLC_INFO;
	ZeroMemory(pDLCData,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



#if defined( __PS3__) || defined(__ORBIS__) || defined(__PSVITA__)
bool CMinecraftApp::GetDLCFullOfferIDForSkinID(const wstring &FirstSkin,ULONGLONG *pullVal)
{
	AUTO_VAR(it, DLCInfo_SkinName.find(FirstSkin));
	if( it == DLCInfo_SkinName.end() )
	{
		return false;
	}
	else
	{
		*pullVal=(ULONGLONG)it->second;
		return true;
	}
}
bool CMinecraftApp::GetDLCNameForPackID(const int iPackID,char **ppchKeyID)
{
	AUTO_VAR(it, DLCTextures_PackID.find(iPackID));
	if( it == DLCTextures_PackID.end() )
	{
		*ppchKeyID=NULL;
		return false;
	}
	else
	{
		*ppchKeyID=(char *)it->second;
		return true;
	}
}
DLC_INFO *CMinecraftApp::GetDLCInfo(char *pchDLCName)
{
	string tempString=pchDLCName;

	if(DLCInfo.size()>0)
	{	
		AUTO_VAR(it, DLCInfo.find(tempString));

		if( it == DLCInfo.end() )
		{
			// nothing for this
			return NULL;
		}
		else
		{
			return it->second;
		}
	}
	else return NULL;
}

DLC_INFO *CMinecraftApp::GetDLCInfoFromTPackID(int iTPID)
{
	unordered_map<string, DLC_INFO *>::iterator it= DLCInfo.begin();

	for(int i=0;i<DLCInfo.size();i++)
	{
		if(((DLC_INFO *)it->second)->iConfig==iTPID)
		{
			return it->second;
		}
		++it;
	}
	return NULL;
}

DLC_INFO *CMinecraftApp::GetDLCInfo(int iIndex)
{
	unordered_map<string, DLC_INFO *>::iterator it= DLCInfo.begin();

	for(int i=0;i<iIndex;i++)
	{
		++it;
	}

	return it->second;
}

char *CMinecraftApp::GetDLCInfoTextures(int iIndex)
{
	unordered_map<int, char * >::iterator it= DLCTextures_PackID.begin();

	for(int i=0;i<iIndex;i++)
	{
		++it;
	}

	return it->second;
}

#elif defined _XBOX_ONE
bool CMinecraftApp::GetDLCFullOfferIDForSkinID(const wstring &FirstSkin,wstring &ProductId)
{
	AUTO_VAR(it, DLCInfo_SkinName.find(FirstSkin));
	if( it == DLCInfo_SkinName.end() )
	{
		return false;
	}
	else
	{
		ProductId=it->second;
		return true;
	}
}
bool CMinecraftApp::GetDLCFullOfferIDForPackID(const int iPackID,wstring &ProductId)
{
	AUTO_VAR(it, DLCTextures_PackID.find(iPackID));
	if( it == DLCTextures_PackID.end() )
	{		
		return false;
	}
	else
	{
		ProductId=it->second;
		return true;
	}
}
// DLC_INFO *CMinecraftApp::GetDLCInfoForTrialOfferID(wstring &ProductId)
// {
// 	return NULL;
// }

DLC_INFO *CMinecraftApp::GetDLCInfoTrialOffer(int iIndex)
{
	return NULL;
}
DLC_INFO *CMinecraftApp::GetDLCInfoFullOffer(int iIndex)
{
	unordered_map<wstring, DLC_INFO *>::iterator it= DLCInfo_Full.begin();

	for(int i=0;i<iIndex;i++)
	{
		++it;
	}

	return it->second;
}
wstring CMinecraftApp::GetDLCInfoTexturesFullOffer(int iIndex)
{
	unordered_map<int, wstring >::iterator it= DLCTextures_PackID.begin();

	for(int i=0;i<iIndex;i++)
	{
		++it;
	}

	return it->second;
}
#else
bool CMinecraftApp::GetDLCFullOfferIDForSkinID(const wstring &FirstSkin,ULONGLONG *pullVal)
{
	AUTO_VAR(it, DLCInfo_SkinName.find(FirstSkin));
	if( it == DLCInfo_SkinName.end() )
	{
		return false;
	}
	else
	{
		*pullVal=(ULONGLONG)it->second;
		return true;
	}
}
bool CMinecraftApp::GetDLCFullOfferIDForPackID(const int iPackID,ULONGLONG *pullVal)
{
	AUTO_VAR(it, DLCTextures_PackID.find(iPackID));
	if( it == DLCTextures_PackID.end() )
	{
		*pullVal=(ULONGLONG)0;
		return false;
	}
	else
	{
		*pullVal=(ULONGLONG)it->second;
		return true;
	}
}
DLC_INFO *CMinecraftApp::GetDLCInfoForTrialOfferID(ULONGLONG ullOfferID_Trial)
{
	//DLC_INFO *pDLCInfo=NULL;
	if(DLCInfo_Trial.size()>0)
	{	
		AUTO_VAR(it, DLCInfo_Trial.find(ullOfferID_Trial));

		if( it == DLCInfo_Trial.end() )
		{
			// nothing for this
			return NULL;
		}
		else
		{
			return it->second;
		}
	}
	else return NULL;
}

DLC_INFO *CMinecraftApp::GetDLCInfoTrialOffer(int iIndex)
{
	unordered_map<ULONGLONG, DLC_INFO *>::iterator it= DLCInfo_Trial.begin();

	for(int i=0;i<iIndex;i++)
	{
		++it;
	}

	return it->second;
}
DLC_INFO *CMinecraftApp::GetDLCInfoFullOffer(int iIndex)
{
	unordered_map<ULONGLONG, DLC_INFO *>::iterator it= DLCInfo_Full.begin();

	for(int i=0;i<iIndex;i++)
	{
		++it;
	}

	return it->second;
}
ULONGLONG CMinecraftApp::GetDLCInfoTexturesFullOffer(int iIndex)
{
	unordered_map<int, ULONGLONG >::iterator it= DLCTextures_PackID.begin();

	for(int i=0;i<iIndex;i++)
	{
		++it;
	}

	return it->second;
}
#endif

#ifdef _XBOX_ONE

DLC_INFO *CMinecraftApp::GetDLCInfoForFullOfferID(WCHAR *pwchProductID)
{
	wstring wsTemp = pwchProductID;
	if(DLCInfo_Full.size()>0)
	{	
		AUTO_VAR(it, DLCInfo_Full.find(wsTemp));

		if( it == DLCInfo_Full.end() )
		{
			// nothing for this
			return NULL;
		}
		else
		{
			return it->second;
		}
	}
	else return NULL;
}
DLC_INFO *CMinecraftApp::GetDLCInfoForProductName(WCHAR *pwchProductName)
{
	unordered_map<wstring, DLC_INFO *>::iterator it= DLCInfo_Full.begin();
	wstring wsProductName=pwchProductName;

	for(int i=0;i<DLCInfo_Full.size();i++)
	{
		DLC_INFO *pDLCInfo=(DLC_INFO *)it->second;
		if(wsProductName==pDLCInfo->wsDisplayName)
		{
			return pDLCInfo;
		}
		++it;
	}
	
	return NULL;
}

#elif defined(__PS3__) || defined(__ORBIS__) || defined (__PSVITA__)
#else

DLC_INFO *CMinecraftApp::GetDLCInfoForFullOfferID(ULONGLONG ullOfferID_Full)
{

	if(DLCInfo_Full.size()>0)
	{	
		AUTO_VAR(it, DLCInfo_Full.find(ullOfferID_Full));

		if( it == DLCInfo_Full.end() )
		{
			// nothing for this
			return NULL;
		}
		else
		{
			return it->second;
		}
	}
	else return NULL;
}
#endif

void CMinecraftApp::EnterSaveNotificationSection()
{
	EnterCriticalSection(&m_saveNotificationCriticalSection);
	if( m_saveNotificationDepth++ == 0 )
	{
		MinecraftServer::getInstance()->broadcastStartSavingPacket();

		if( g_NetworkManager.IsLocalGame() && g_NetworkManager.GetPlayerCount() == 1 )
		{
			app.SetXuiServerAction(ProfileManager.GetPrimaryPad(),eXuiServerAction_PauseServer,(void *)TRUE);
		}
	}
	LeaveCriticalSection(&m_saveNotificationCriticalSection);
}

void CMinecraftApp::LeaveSaveNotificationSection()
{
	EnterCriticalSection(&m_saveNotificationCriticalSection);
	if( --m_saveNotificationDepth == 0 )
	{
		MinecraftServer::getInstance()->broadcastStopSavingPacket();

		if( g_NetworkManager.IsLocalGame() && g_NetworkManager.GetPlayerCount() == 1 )
		{
			app.SetXuiServerAction(ProfileManager.GetPrimaryPad(),eXuiServerAction_PauseServer,(void *)FALSE);
		}
	}
	LeaveCriticalSection(&m_saveNotificationCriticalSection);
}


int CMinecraftApp::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
	AABB::UseDefaultThreadStorage();
	Vec3::UseDefaultThreadStorage();
	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!CMinecraftApp::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();
		Sleep( 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 S_OK;
}

void CMinecraftApp::ExitGameFromRemoteSave( LPVOID lpParameter )
{
	int primaryPad = ProfileManager.GetPrimaryPad();
	
	UINT uiIDA[3];
	uiIDA[0]=IDS_CONFIRM_CANCEL;
	uiIDA[1]=IDS_CONFIRM_OK;

	ui.RequestMessageBox(IDS_EXIT_GAME, IDS_CONFIRM_EXIT_GAME, uiIDA, 2, primaryPad,&CMinecraftApp::ExitGameFromRemoteSaveDialogReturned,NULL, app.GetStringTable(), 0, 0, false);
}

int CMinecraftApp::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 
	{
#ifndef _XBOX
		// Inform fullscreen progress scene that it's not being cancelled after all
		UIScene_FullscreenProgress *pScene = (UIScene_FullscreenProgress *)ui.FindScene(eUIScene_FullscreenProgress);
#ifdef __PS3__
		if(pScene!=NULL)
#else
		if (pScene != nullptr)
#endif
		{
			pScene->SetWasCancelled(false);
		}
#else
		// Don't have to worry about this on Xbox
#endif
	}
	return 0;
}

void CMinecraftApp::SetSpecialTutorialCompletionFlag(int iPad, int index)
{
	if(index >= 0 && index < 32 && GameSettingsA[iPad] != NULL)
	{
		GameSettingsA[iPad]->uiSpecialTutorialBitmask |= (1<<index);
	}
}

// BANNED LIST FUNCTIONS

void CMinecraftApp::SetUniqueMapName(char *pszUniqueMapName)
{
	memcpy(m_pszUniqueMapName,pszUniqueMapName,14);
}

char *CMinecraftApp::GetUniqueMapName(void)
{
	return m_pszUniqueMapName;
}

void CMinecraftApp::InvalidateBannedList(int iPad)
{
	if(m_bRead_BannedListA[iPad]==true)
	{
		m_bRead_BannedListA[iPad]=false;
		SetBanListCheck(iPad,false);
		m_vBannedListA[iPad]->clear();

		if(BannedListA[iPad].pBannedList)
		{
			delete [] BannedListA[iPad].pBannedList;
			BannedListA[iPad].pBannedList=NULL;
		}
	}
}

#ifdef _XBOX_ONE
void CMinecraftApp::AddLevelToBannedLevelList(int iPad, PBANNEDLISTDATA pBannedListData, bool bWriteToTMS)
{
	PlayerUID xuid= pBannedListData->wchPlayerUID;

	AddLevelToBannedLevelList(iPad,xuid,pBannedListData->pszLevelName,bWriteToTMS);
}
#endif

void CMinecraftApp::AddLevelToBannedLevelList(int iPad, PlayerUID xuid, char *pszLevelName, bool bWriteToTMS)
{
	// we will have retrieved the banned level list from TMS, so add this one to it and write it back to TMS

	BANNEDLISTDATA *pBannedListData = new BANNEDLISTDATA;
	memset(pBannedListData,0,sizeof(BANNEDLISTDATA));

#ifdef _DURANGO
	memcpy(&pBannedListData->wchPlayerUID, xuid.toString().c_str(), sizeof(WCHAR)*64);
#else
	memcpy(&pBannedListData->xuid, &xuid, sizeof(PlayerUID));
#endif
	strcpy(pBannedListData->pszLevelName,pszLevelName);
	m_vBannedListA[iPad]->push_back(pBannedListData);

	if(bWriteToTMS)
	{	
		DWORD dwDataBytes=(DWORD)(sizeof(BANNEDLISTDATA)*m_vBannedListA[iPad]->size());
		PBANNEDLISTDATA pBannedList = (BANNEDLISTDATA *)(new CHAR [dwDataBytes]);
		int iCount=0;
		for(AUTO_VAR(it, m_vBannedListA[iPad]->begin()); it != m_vBannedListA[iPad]->end(); ++it)
		{
			PBANNEDLISTDATA pData=*it;
			memcpy(&pBannedList[iCount++],pData,sizeof(BANNEDLISTDATA));
		}

		// 4J-PB - write to TMS++ now

		//bool bRes=StorageManager.WriteTMSFile(iPad,C4JStorage::eGlobalStorage_TitleUser,L"BannedList",(PBYTE)pBannedList, dwDataBytes);
#ifdef _XBOX
		StorageManager.TMSPP_WriteFile(iPad,C4JStorage::eGlobalStorage_TitleUser,C4JStorage::TMS_FILETYPE_BINARY,C4JStorage::TMS_UGCTYPE_NONE,"BannedList",(PCHAR) pBannedList, dwDataBytes,NULL,NULL, 0);
#elif defined _XBOX_ONE
		StorageManager.TMSPP_WriteFile(iPad,C4JStorage::eGlobalStorage_TitleUser,C4JStorage::TMS_FILETYPE_BINARY,L"BannedList",(PBYTE) pBannedList, dwDataBytes,NULL,NULL, 0);
#endif
	}
	// update telemetry too
}

bool CMinecraftApp::IsInBannedLevelList(int iPad, PlayerUID xuid, char *pszLevelName)
{
	for(AUTO_VAR(it, m_vBannedListA[iPad]->begin()); it != m_vBannedListA[iPad]->end(); ++it)
	{
		PBANNEDLISTDATA pData=*it;
#ifdef _XBOX_ONE
		PlayerUID bannedPlayerUID = pData->wchPlayerUID;
		if(IsEqualXUID (bannedPlayerUID,xuid) && (strcmp(pData->pszLevelName,pszLevelName)==0))
#else		
		if(IsEqualXUID (pData->xuid,xuid) && (strcmp(pData->pszLevelName,pszLevelName)==0))
#endif
		{
			return true;
		}
	}

	return false;
}

void CMinecraftApp::RemoveLevelFromBannedLevelList(int iPad, PlayerUID xuid, char *pszLevelName)
{
	//bool bFound=false;
	//bool bRes;
	
	// we will have retrieved the banned level list from TMS, so remove this one from it and write it back to TMS
	for(AUTO_VAR(it, m_vBannedListA[iPad]->begin()); it != m_vBannedListA[iPad]->end(); )
	{
		PBANNEDLISTDATA pBannedListData = *it;
		
		if(pBannedListData!=NULL)
		{
#ifdef _XBOX_ONE
			PlayerUID bannedPlayerUID = pBannedListData->wchPlayerUID;
			if(IsEqualXUID (bannedPlayerUID,xuid) && (strcmp(pBannedListData->pszLevelName,pszLevelName)==0))
#else
			if(IsEqualXUID (pBannedListData->xuid,xuid) && (strcmp(pBannedListData->pszLevelName,pszLevelName)==0))
#endif
			{
				TelemetryManager->RecordUnBanLevel(iPad);

				// match found, so remove this entry
				it = m_vBannedListA[iPad]->erase(it);
			}
			else
			{
				++it;
			}
		}
		else
		{
			++it;
		}
	}

	DWORD dwDataBytes=(DWORD)(sizeof(BANNEDLISTDATA)*m_vBannedListA[iPad]->size());
	if(dwDataBytes==0)
	{
		// wipe the file
#ifdef _XBOX
		StorageManager.DeleteTMSFile(iPad,C4JStorage::eGlobalStorage_TitleUser,L"BannedList");
#elif defined _XBOX_ONE
		StorageManager.TMSPP_DeleteFile(iPad,C4JStorage::eGlobalStorage_TitleUser,C4JStorage::TMS_FILETYPE_BINARY,L"BannedList",NULL,NULL, 0);
#endif
	}
	else
	{
		PBANNEDLISTDATA pBannedList = (BANNEDLISTDATA *)(new BYTE [dwDataBytes]);

		int iSize=(int)m_vBannedListA[iPad]->size();
		for(int i=0;i<iSize;i++)
		{
			PBANNEDLISTDATA pBannedListData =m_vBannedListA[iPad]->at(i);

			memcpy(&pBannedList[i],pBannedListData,sizeof(BANNEDLISTDATA));
		}
#ifdef _XBOX
		StorageManager.WriteTMSFile(iPad,C4JStorage::eGlobalStorage_TitleUser,L"BannedList",(PBYTE)pBannedList, dwDataBytes);
#elif defined _XBOX_ONE
		StorageManager.TMSPP_WriteFile(iPad,C4JStorage::eGlobalStorage_TitleUser,C4JStorage::TMS_FILETYPE_BINARY,L"BannedList",(PBYTE) pBannedList, dwDataBytes,NULL,NULL, 0);
#endif
		delete [] pBannedList;
	}

	// update telemetry too
}

// function to add credits for the DLC packs
void CMinecraftApp::AddCreditText(LPCWSTR lpStr)
{
	DebugPrintf("ADDING CREDIT - %ls\n",lpStr);
	// add a string from the DLC to a credits 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 [wcslen(lpStr)+1];
	wcscpy((WCHAR *)pCreditStruct->m_Text,lpStr);

	vDLCCredits.push_back(pCreditStruct);
}

bool CMinecraftApp::AlreadySeenCreditText(const wstring &wstemp)
{

	for(unsigned int i=0;i<m_vCreditText.size();i++)
	{
		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 * )wstemp.c_str());
	return false;
}

unsigned int CMinecraftApp::GetDLCCreditsCount()
{
	return (unsigned int)vDLCCredits.size();
}

SCreditTextItemDef * CMinecraftApp::GetDLCCredits(int iIndex)
{
	return vDLCCredits.at(iIndex);
}

// Game Host options

void CMinecraftApp::SetGameHostOption(eGameHostOption eVal,unsigned int uiVal)
{
	SetGameHostOption(m_uiGameHostSettings,eVal,uiVal);
}


void CMinecraftApp::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_All:
		uiHostSettings=uiVal;
		break;
	}
}

unsigned int CMinecraftApp::GetGameHostOption(eGameHostOption eVal)
{
	return GetGameHostOption(m_uiGameHostSettings, eVal);
}

unsigned int CMinecraftApp::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;		
	}

	return false;
}

bool CMinecraftApp::CanRecordStatsAndAchievements()
{
	// 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));
}

void CMinecraftApp::processSchematics(LevelChunk *levelChunk)
{
	m_gameRules.processSchematics(levelChunk);
}

void CMinecraftApp::processSchematicsLighting(LevelChunk *levelChunk)
{
	m_gameRules.processSchematicsLighting(levelChunk);
}

void CMinecraftApp::loadDefaultGameRules()
{
	m_gameRules.loadDefaultGameRules();
}

void CMinecraftApp::setLevelGenerationOptions(LevelGenerationOptions *levelGen)
{
	m_gameRules.setLevelGenerationOptions(levelGen);
}

LPCWSTR	CMinecraftApp::GetGameRulesString(const wstring &key)
{
	return m_gameRules.GetGameRulesString(key);
}

unsigned char CMinecraftApp::m_szPNG[8]=
{
	137,80,78,71,13,10,26,10
};

#define PNG_TAG_tEXt 0x74455874

unsigned int CMinecraftApp::FromBigEndian(unsigned int uiValue)
{
#if defined(__PS3__) || defined(_XBOX)
	// Keep it in big endian
	return uiValue;
#else
	unsigned int uiReturn = ( ( uiValue >> 24 ) & 0x000000ff ) | 
		( ( uiValue >> 8 )  & 0x0000ff00 ) |
		( ( uiValue << 8 )  & 0x00ff0000 ) |
		( ( uiValue << 24 ) & 0xff000000 );
	return uiReturn;
#endif
}

void CMinecraftApp::GetImageTextData(PBYTE pbImageData, DWORD dwImageBytes,unsigned char *pszSeed,unsigned int &uiHostOptions,bool &bHostOptionsRead,DWORD &uiTexturePack)
{
	unsigned char *ucPtr=pbImageData;
	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<dwImageBytes)
	{	
		uiChunkLen=*(unsigned int *)&ucPtr[uiCount];
		uiChunkLen=FromBigEndian(uiChunkLen);
		uiCount+=sizeof(int);
		uiChunkType=*(unsigned int *)&ucPtr[uiCount];
		uiChunkType=FromBigEndian(uiChunkType);
		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)
			{
				ZeroMemory(szKeyword,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) )
					{
						pszSeed[uiValueC++]=*pszKeyword;
						pszKeyword++;
					}
					//memcpy(pszSeed,pszKeyword,uiChunkLen-8);
				}
				else if(strcmp(szKeyword,"4J_HOSTOPTIONS")==0)
				{
					bHostOptionsRead = true;
					// read the host options value					
					unsigned int uiValueC=0;
					unsigned char pszHostOptions[8]; // Hex representation of unsigned int
					ZeroMemory(&pszHostOptions,8);
					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[8]; // Hex representation of unsigned int
					ZeroMemory(&pszTexturePack,8);
					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=*(unsigned int*)&ucPtr[uiCount];
		uiCRC=FromBigEndian(uiCRC);
		uiCount+=sizeof(int);
	}

	return;
}

unsigned int CMinecraftApp::CreateImageTextData(PBYTE bTextMetadata, __int64 seed, bool hasSeed, unsigned int uiHostOptions, unsigned int uiTexturePackId)
{
	int iTextMetadataBytes = 0;
	if(hasSeed)
	{
		strcpy((char *)bTextMetadata,"4J_SEED");
		_i64toa_s(seed,(char *)&bTextMetadata[8],42,10);

		// get the length
		iTextMetadataBytes+=8;
		while(bTextMetadata[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 *)&bTextMetadata[iTextMetadataBytes],"4J_HOSTOPTIONS");
	_itoa_s(uiHostOptions,(char *)&bTextMetadata[iTextMetadataBytes+15],9,16);

	iTextMetadataBytes += 15;
	while(bTextMetadata[iTextMetadataBytes]!=0) iTextMetadataBytes++;
	++iTextMetadataBytes; // Add a null terminator at the end of the host options value

	// Save the texture pack id
	strcpy((char *)&bTextMetadata[iTextMetadataBytes],"4J_TEXTUREPACK");
	_itoa_s(uiTexturePackId,(char *)&bTextMetadata[iTextMetadataBytes+15],9,16);

	iTextMetadataBytes += 15;
	while(bTextMetadata[iTextMetadataBytes]!=0) iTextMetadataBytes++;

	return iTextMetadataBytes;
}

void CMinecraftApp::AddTerrainFeaturePosition(_eTerrainFeatureType eFeatureType,int x,int z)
{
	// check we don't already have this in
	for(AUTO_VAR(it, m_vTerrainFeatures.begin()); it < m_vTerrainFeatures.end(); ++it)
	{
		FEATURE_DATA *pFeatureData=*it;

		if((pFeatureData->eTerrainFeature==eFeatureType) &&(pFeatureData->x==x) && (pFeatureData->z==z)) return;
	}

	FEATURE_DATA *pFeatureData= new FEATURE_DATA;
	pFeatureData->eTerrainFeature=eFeatureType;
	pFeatureData->x=x;
	pFeatureData->z=z;

	m_vTerrainFeatures.push_back(pFeatureData);
}

_eTerrainFeatureType CMinecraftApp::IsTerrainFeature(int x,int z)
{
	for(AUTO_VAR(it, m_vTerrainFeatures.begin()); it < m_vTerrainFeatures.end(); ++it)
	{
		FEATURE_DATA *pFeatureData=*it;

		if((pFeatureData->x==x) && (pFeatureData->z==z)) return pFeatureData->eTerrainFeature;
	}

	return eTerrainFeature_None;
}

bool CMinecraftApp::GetTerrainFeaturePosition(_eTerrainFeatureType eType,int *pX, int *pZ)
{
	for(AUTO_VAR(it, m_vTerrainFeatures.begin()); it < m_vTerrainFeatures.end(); ++it)
	{
		FEATURE_DATA *pFeatureData=*it;
		
		if(pFeatureData->eTerrainFeature==eType)
		{
			*pX=pFeatureData->x;
			*pZ=pFeatureData->z;
			return true;
		}		
	}

	return false;
}

void CMinecraftApp::ClearTerrainFeaturePosition()
{
	FEATURE_DATA *pFeatureData;
	while(m_vTerrainFeatures.size()>0)
	{
		pFeatureData = m_vTerrainFeatures.back();
		m_vTerrainFeatures.pop_back();
		delete pFeatureData;
	}
}

void CMinecraftApp::UpdatePlayerInfo(BYTE networkSmallId, SHORT 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 CMinecraftApp::GetPlayerColour(BYTE 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 CMinecraftApp::GetPlayerPrivileges(BYTE 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;
}

wstring CMinecraftApp::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);

	};

	return L"";
}

DWORD CMinecraftApp::m_dwContentTypeA[e_Marketplace_MAX]=
{
	XMARKETPLACE_OFFERING_TYPE_CONTENT,		// e_DLC_SkinPack, e_DLC_TexturePacks, e_DLC_MashupPacks
#ifndef _XBOX_ONE
	XMARKETPLACE_OFFERING_TYPE_THEME,		// e_DLC_Themes
	XMARKETPLACE_OFFERING_TYPE_AVATARITEM,	// e_DLC_AvatarItems
	XMARKETPLACE_OFFERING_TYPE_TILE,		// e_DLC_Gamerpics
#endif
};

unsigned int CMinecraftApp::AddDLCRequest(eDLCMarketplaceType eType, bool bPromote)
{
	// lock access
	EnterCriticalSection(&csDLCDownloadQueue);

	// If it's already in there, promote it to the top of the list
	int iPosition=0;
	for(AUTO_VAR(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
				LeaveCriticalSection(&csDLCDownloadQueue);
				return 0;
			}
			else
			{
				// promote
				if(bPromote)
				{			
					m_DLCDownloadQueue.erase(m_DLCDownloadQueue.begin()+iPosition);
					m_DLCDownloadQueue.insert(m_DLCDownloadQueue.begin(),pCurrent);
				}
				LeaveCriticalSection(&csDLCDownloadQueue);
				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;
	LeaveCriticalSection(&csDLCDownloadQueue);

	app.DebugPrintf("[Consoles_App] Added DLC request.\n");
	return 1;
}

unsigned int CMinecraftApp::AddTMSPPFileTypeRequest(eDLCContentType eType, bool bPromote)
{
#if !defined(__PS3__) && !defined(__ORBIS__) && !defined(__PSVITA__)
	// lock access
	EnterCriticalSection(&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_VAR(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
		LeaveCriticalSection(&csTMSPPDownloadQueue);
		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 *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_VAR(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=&CMinecraftApp::TMSPPFileReturned;
								pTMSPPreq->lpCallbackParam=this;
								pTMSPPreq->eStorageFacility=C4JStorage::eGlobalStorage_Title;
								pTMSPPreq->eFileTypeVal=C4JStorage::TMS_FILETYPE_BINARY;
								memcpy(pTMSPPreq->wchFilename,pDLC->wchDataFile,sizeof(WCHAR)*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;
#ifdef _XBOX // Only trial offers on Xbox 360
		iCount=GetDLCInfoTrialOffersCount();
		for(int i=0;i<iCount;i++)
		{
			DLC_INFO *pDLC=GetDLCInfoTrialOffer(i);

			// is this the right type?
			if(pDLC->eDLCType==eType)
			{	

				WCHAR *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
				// is the file in the TMS XZP?	 
				//int iIndex = app.GetLocalTMSFileIndex(cString,true);

				//if(iIndex!=-1)
				{			
					bool bPresent = app.IsFileInMemoryTextures(cString);		

					if(!bPresent) // retrieve it from TMSPP
					{		
						bool bAlreadyInQueue=false;
						for(AUTO_VAR(it, m_TMSPPDownloadQueue.begin()); it != m_TMSPPDownloadQueue.end(); ++it)
						{
							TMSPPRequest  *pCurrent = *it;

							if(wcscmp(pDLC->wchBanner,pCurrent->wchFilename)==0)
							{
								bAlreadyInQueue=true;
								break;
							}
						}

						if(!bAlreadyInQueue)
						{			
							TMSPPRequest *pTMSPPreq = new TMSPPRequest;

							pTMSPPreq->CallbackFunc=&CMinecraftApp::TMSPPFileReturned;
							pTMSPPreq->lpCallbackParam=this;
							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)*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());
						}
					}
				}
			}
		}
#endif
		// 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 *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_VAR(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;
							ZeroMemory(pTMSPPreq,sizeof(TMSPPRequest));

							pTMSPPreq->CallbackFunc=&CMinecraftApp::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)*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());
						}	
					}
				}
			}
		}
	}

	LeaveCriticalSection(&csTMSPPDownloadQueue);
#endif
	return 1;
}

bool CMinecraftApp::CheckTMSDLCCanStop()
{
	EnterCriticalSection(&csTMSPPDownloadQueue);
	for(AUTO_VAR(it, m_TMSPPDownloadQueue.begin()); it != m_TMSPPDownloadQueue.end(); ++it)
	{
		TMSPPRequest  *pCurrent = *it;

		if(pCurrent->eState==e_TMS_ContentState_Retrieving)
		{
			LeaveCriticalSection(&csTMSPPDownloadQueue);
			return false;
		}
	}
	LeaveCriticalSection(&csTMSPPDownloadQueue);

	return true;
}


bool CMinecraftApp::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.
	}

	EnterCriticalSection(&csDLCDownloadQueue);
	for(AUTO_VAR(it, m_DLCDownloadQueue.begin()); it != m_DLCDownloadQueue.end(); ++it)
	{
		DLCRequest  *pCurrent = *it;

		if(pCurrent->eState==e_DLC_ContentState_Retrieving)
		{
			LeaveCriticalSection(&csDLCDownloadQueue);
			return true;
		}
	}

	// Now look for the next retrieval
	for(AUTO_VAR(it, m_DLCDownloadQueue.begin()); it != m_DLCDownloadQueue.end(); ++it)
	{
		DLCRequest  *pCurrent = *it;

		if(pCurrent->eState==e_DLC_ContentState_Idle)
		{
#ifdef _DEBUG
			app.DebugPrintf("RetrieveNextDLCContent - type = %d\n",pCurrent->dwType);
#endif

			C4JStorage::EDLCStatus status = StorageManager.GetDLCOffers(ProfileManager.GetPrimaryPad(), &CMinecraftApp::DLCOffersReturned, this, 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;
			}
			LeaveCriticalSection(&csDLCDownloadQueue);
			return true;
		}
	}
	LeaveCriticalSection(&csDLCDownloadQueue);

	app.DebugPrintf("[Consoles_App] Finished downloading dlc content.\n");
	return false;
}

#if !defined(__PS3__) && !defined(__ORBIS__) && !defined(__PSVITA__)
#ifdef _XBOX_ONE
int CMinecraftApp::TMSPPFileReturned(LPVOID pParam,int iPad,int iUserData,LPVOID lpvData, WCHAR* wchFilename)
{
	C4JStorage::PTMSPP_FILEDATA pFileData=(C4JStorage::PTMSPP_FILEDATA)lpvData;
#else
int CMinecraftApp::TMSPPFileReturned(LPVOID pParam,int iPad,int iUserData,C4JStorage::PTMSPP_FILEDATA pFileData, LPCSTR szFilename)
{
#endif

	CMinecraftApp* pClass = (CMinecraftApp *) pParam;

	// find the right one in the vector
	EnterCriticalSection(&pClass->csTMSPPDownloadQueue);
	for(AUTO_VAR(it, pClass->m_TMSPPDownloadQueue.begin()); it != pClass->m_TMSPPDownloadQueue.end(); ++it)
	{
		TMSPPRequest  *pCurrent = *it;
#if defined(_XBOX) || defined(_WINDOWS64)
		char szFile[MAX_TMSFILENAME_SIZE];
		wcstombs(szFile,pCurrent->wchFilename,MAX_TMSFILENAME_SIZE);
	

		if(strcmp(szFilename,szFile)==0)
#elif _XBOX_ONE
		if(wcscmp(wchFilename,pCurrent->wchFilename)==0)
#endif
		{
			// set this to retrieved whether it found it or not
			pCurrent->eState=e_TMS_ContentState_Retrieved;

			if(pFileData!=NULL)
			{	

#ifdef _XBOX_ONE
				

				switch(pCurrent->eType)
				{
				case e_DLC_TexturePackData:
					{					
						// 4J-PB - we need to allocate memory for the file data and copy into it, since the current data is a reference into the blob download memory
						PBYTE pbData = new BYTE [pFileData->dwSize];
						memcpy(pbData,pFileData->pbData,pFileData->dwSize);

						pClass->m_vTMSPPData.push_back(pbData);
						app.DebugPrintf("Got texturepack data\n");
						// get the config value for the texture pack
						int iConfig=app.GetTPConfigVal(pCurrent->wchFilename);
						app.AddMemoryTPDFile(iConfig, pbData, pFileData->dwSize);					
					}
					break;
				default:
					// 4J-PB - check the data is an image
					if(pFileData->pbData[0]==0x89)
					{				
						// 4J-PB - we need to allocate memory for the file data and copy into it, since the current data is a reference into the blob download memory
 						PBYTE pbData = new BYTE [pFileData->dwSize];
 						memcpy(pbData,pFileData->pbData,pFileData->dwSize);
 
 						pClass->m_vTMSPPData.push_back(pbData);
						app.DebugPrintf("Got image data - %ls\n",pCurrent->wchFilename);
						app.AddMemoryTextureFile(pCurrent->wchFilename, pbData, pFileData->dwSize);
					}
					else
					{
						app.DebugPrintf("Got image data, but it's not a png - %ls\n",pCurrent->wchFilename);
					}
					break;
				}

#else
				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->dwSize);					
					}
					break;
				default:
					app.DebugPrintf("--- Got image data - %ls\n",pCurrent->wchFilename);
					app.AddMemoryTextureFile(pCurrent->wchFilename, pFileData->pbData, pFileData->dwSize);
					break;
				}
#endif
			}
			else
			{
#ifdef _XBOX_ONE
				app.DebugPrintf("TMSImageReturned failed (%ls)...\n",wchFilename);
#else
				app.DebugPrintf("TMSImageReturned failed (%s)...\n",szFilename);
#endif
			}
			break;
		}
		
	}
	LeaveCriticalSection(&pClass->csTMSPPDownloadQueue);

	return 0;
}
#endif

bool CMinecraftApp::RetrieveNextTMSPPContent()
{
#if defined _XBOX || defined _XBOX_ONE
	// 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?
	if(ProfileManager.GetPrimaryPad()==-1) return false;

	if(ProfileManager.IsSignedInLive(ProfileManager.GetPrimaryPad())==false) return false;

	EnterCriticalSection(&csTMSPPDownloadQueue);
	for(AUTO_VAR(it, m_TMSPPDownloadQueue.begin()); it != m_TMSPPDownloadQueue.end(); ++it)
	{
		TMSPPRequest  *pCurrent = *it;

		if(pCurrent->eState==e_TMS_ContentState_Retrieving)
		{
			app.DebugPrintf(".");
			LeaveCriticalSection(&csTMSPPDownloadQueue);
			return true;
		}
	}

	// Now look for the next retrieval
	for(AUTO_VAR(it, m_TMSPPDownloadQueue.begin()); it != m_TMSPPDownloadQueue.end(); ++it)
	{
		TMSPPRequest  *pCurrent = *it;

		if(pCurrent->eState==e_TMS_ContentState_Queued)
		{
			// 4J-PB - the file may be in the local TMS files, but try to retrieve it from the remote TMS in case it's been changed. If it's not in the list of TMS files, this will
			// return right away with a ETMSStatus_Fail_ReadDetailsNotRetrieved
#ifdef _XBOX
			char szFilename[MAX_TMSFILENAME_SIZE];
			wcstombs(szFilename,pCurrent->wchFilename,MAX_TMSFILENAME_SIZE);

			app.DebugPrintf("\nRetrieveNextTMSPPContent - type = %d, %s\n",pCurrent->eType,szFilename);

			C4JStorage::ETMSStatus status=StorageManager.TMSPP_ReadFile(ProfileManager.GetPrimaryPad(),pCurrent->eStorageFacility,pCurrent->eFileTypeVal,szFilename,pCurrent->CallbackFunc,this);
			switch(status)
			{
			case C4JStorage::ETMSStatus_Pending:
				pCurrent->eState=e_TMS_ContentState_Retrieving;
				break;
			case C4JStorage::ETMSStatus_Idle:
				pCurrent->eState=e_TMS_ContentState_Retrieved;
				break;
			case C4JStorage::ETMSStatus_Fail_ReadInProgress:
			case C4JStorage::ETMSStatus_ReadInProgress:
				pCurrent->eState=e_TMS_ContentState_Retrieving;
				if(pCurrent->eState==C4JStorage::ETMSStatus_Fail_ReadInProgress)
				{
					app.DebugPrintf("TMSPP_ReadFile failed - read in progress\n");
					Sleep(50);
					LeaveCriticalSection(&csTMSPPDownloadQueue);
					return false;
				}
				break;
			default:
				pCurrent->eState=e_TMS_ContentState_Retrieved;
				break;
			}
#else
			eTitleStorageState status;
			app.DebugPrintf("RetrieveNextTMSPPContent - type = %d, %ls\n",pCurrent->eType,pCurrent->wchFilename);
			//eTitleStorageState status=StorageManager.TMSPP_ReadFile(ProfileManager.GetPrimaryPad(),pCurrent->eStorageFacility,pCurrent->eFileTypeVal,pCurrent->wchFilename,pCurrent->CallbackFunc,this,0);
			if(0)//wcscmp(pCurrent->wchFilename,L"TP01.png")==0)
			{
				// TP01 fails because the blob size returned is bigger than the global metadata says it should be
				status=eTitleStorage_readerror;
			}
			else
			{
				status=StorageManager.TMSPP_ReadFile(ProfileManager.GetPrimaryPad(),pCurrent->eStorageFacility,pCurrent->eFileTypeVal,pCurrent->wchFilename,pCurrent->CallbackFunc,this,0);
			}
			switch(status)
			{
			case eTitleStorage_pending:
				pCurrent->eState=e_TMS_ContentState_Retrieving;
				break;
			case eTitleStorage_idle:
				pCurrent->eState=e_TMS_ContentState_Retrieved;
				break;
			case eTitleStorage_busy:
				// try again next time
				{
					app.DebugPrintf("@@@@@@@@@@@@@@@@@ TMSPP_ReadFile failed - busy (probably reading already)\n");
					Sleep(50);
					LeaveCriticalSection(&csTMSPPDownloadQueue);
					return false;
				}
				break;
			default:
				pCurrent->eState=e_TMS_ContentState_Retrieved;
				break;
			}
#endif



			LeaveCriticalSection(&csTMSPPDownloadQueue);
			return true;
		}
	}

	LeaveCriticalSection(&csTMSPPDownloadQueue);

#endif
	return false;
}

void CMinecraftApp::TickDLCOffersRetrieved()
{
	if(!m_bAllDLCContentRetrieved)
	{
		if (!app.RetrieveNextDLCContent())
		{
			app.DebugPrintf("[Consoles_App] All content retrieved.\n");
			m_bAllDLCContentRetrieved=true;
		}
	}
}
void  CMinecraftApp::ClearAndResetDLCDownloadQueue()
{
	app.DebugPrintf("[Consoles_App] Clear and reset download queue.\n");

	int iPosition=0;
	EnterCriticalSection(&csTMSPPDownloadQueue);
	for(AUTO_VAR(it, m_DLCDownloadQueue.begin()); it != m_DLCDownloadQueue.end(); ++it)
	{
		DLCRequest  *pCurrent = *it;

		delete pCurrent;
		iPosition++;
	}
	m_DLCDownloadQueue.clear();
	m_bAllDLCContentRetrieved=true;
	LeaveCriticalSection(&csTMSPPDownloadQueue);
}

void CMinecraftApp::TickTMSPPFilesRetrieved()
{
	if(m_bTickTMSDLCFiles && !m_bAllTMSContentRetrieved)
	{
		if(app.RetrieveNextTMSPPContent()==false)
		{
			m_bAllTMSContentRetrieved=true;
		}
	}
}
void  CMinecraftApp::ClearTMSPPFilesRetrieved()
{
	int iPosition=0;
	EnterCriticalSection(&csTMSPPDownloadQueue);
	for(AUTO_VAR(it, m_TMSPPDownloadQueue.begin()); it != m_TMSPPDownloadQueue.end(); ++it)
	{
		TMSPPRequest  *pCurrent = *it;

		delete pCurrent;
		iPosition++;
	}
	m_TMSPPDownloadQueue.clear();
	m_bAllTMSContentRetrieved=true;
	LeaveCriticalSection(&csTMSPPDownloadQueue);
}

int CMinecraftApp::DLCOffersReturned(void *pParam, int iOfferC, DWORD dwType, int iPad)
{
	CMinecraftApp* pClass = (CMinecraftApp *) pParam;

	// find the right one in the vector
	EnterCriticalSection(&pClass->csTMSPPDownloadQueue);
	for(AUTO_VAR(it, pClass->m_DLCDownloadQueue.begin()); it != pClass->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==dwType)
		{
			pClass->m_iDLCOfferC = iOfferC;
			app.DebugPrintf("DLCOffersReturned - type %d, count %d - setting to retrieved\n",dwType,iOfferC);
			pCurrent->eState=e_DLC_ContentState_Retrieved;
			break;
		}
	}
	LeaveCriticalSection(&pClass->csTMSPPDownloadQueue);
	return 0;
}

eDLCContentType CMinecraftApp::Find_eDLCContentType(DWORD dwType)
{
	for(int i=0;i<e_DLC_MAX;i++)
	{
		if(m_dwContentTypeA[i]==dwType)
		{
			return (eDLCContentType)i;
		}
	}
	return (eDLCContentType)0;
}
bool CMinecraftApp::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
	EnterCriticalSection(&csDLCDownloadQueue);
	for(AUTO_VAR(it, m_DLCDownloadQueue.begin()); it != m_DLCDownloadQueue.end(); ++it)
	{
		DLCRequest  *pCurrent = *it;

		if((pCurrent->dwType==m_dwContentTypeA[eType]) && (pCurrent->eState==e_DLC_ContentState_Retrieved))
		{
			LeaveCriticalSection(&csDLCDownloadQueue);
			return true;
		}
	}
	LeaveCriticalSection(&csDLCDownloadQueue);
	return false;
}

void CMinecraftApp::SetAdditionalSkinBoxes(DWORD dwSkinID, SKIN_BOX *SkinBoxA, DWORD dwSkinBoxC)
{
	EntityRenderer *renderer = EntityRenderDispatcher::instance->getRenderer(eTYPE_PLAYER);
	Model *pModel = renderer->getModel();
	vector<ModelPart *> *pvModelPart = new vector<ModelPart *>;
	vector<SKIN_BOX *> *pvSkinBoxes = new vector<SKIN_BOX *>;

	EnterCriticalSection( &csAdditionalModelParts );
	EnterCriticalSection( &csAdditionalSkinBoxes );

	app.DebugPrintf("*** SetAdditionalSkinBoxes - Inserting model parts for skin %d from array of Skin Boxes\n",dwSkinID&0x0FFFFFFF);

	// convert the skin boxes into model parts, and add to the humanoid model
	for(unsigned int i=0;i<dwSkinBoxC;i++)
	{
		if(pModel)
		{			
			ModelPart *pModelPart=pModel->AddOrRetrievePart(&SkinBoxA[i]);
			pvModelPart->push_back(pModelPart);
			pvSkinBoxes->push_back(&SkinBoxA[i]);
		}
	}


	m_AdditionalModelParts.insert( std::pair<DWORD, vector<ModelPart *> *>(dwSkinID, pvModelPart) );
	m_AdditionalSkinBoxes.insert( std::pair<DWORD, vector<SKIN_BOX *> *>(dwSkinID, pvSkinBoxes) );
	
	LeaveCriticalSection( &csAdditionalSkinBoxes );
	LeaveCriticalSection( &csAdditionalModelParts );

}

vector<ModelPart *> * CMinecraftApp::SetAdditionalSkinBoxes(DWORD dwSkinID, vector<SKIN_BOX *> *pvSkinBoxA)
{
	EntityRenderer *renderer = EntityRenderDispatcher::instance->getRenderer(eTYPE_PLAYER);
	Model *pModel = renderer->getModel();
	vector<ModelPart *> *pvModelPart = new vector<ModelPart *>;

	EnterCriticalSection( &csAdditionalModelParts );
	EnterCriticalSection( &csAdditionalSkinBoxes );
	app.DebugPrintf("*** SetAdditionalSkinBoxes - Inserting model parts for skin %d from array of Skin Boxes\n",dwSkinID&0x0FFFFFFF);

	// convert the skin boxes into model parts, and add to the humanoid model
	for(AUTO_VAR(it, pvSkinBoxA->begin());it != pvSkinBoxA->end(); ++it)
	{
		if(pModel)
		{			
			ModelPart *pModelPart=pModel->AddOrRetrievePart(*it);
			pvModelPart->push_back(pModelPart);
		}
	}

	m_AdditionalModelParts.insert( std::pair<DWORD, vector<ModelPart *> *>(dwSkinID, pvModelPart) );
	m_AdditionalSkinBoxes.insert( std::pair<DWORD, vector<SKIN_BOX *> *>(dwSkinID, pvSkinBoxA) );

	LeaveCriticalSection( &csAdditionalSkinBoxes );
	LeaveCriticalSection( &csAdditionalModelParts );
	return pvModelPart;
}


vector<ModelPart *> *CMinecraftApp::GetAdditionalModelParts(DWORD dwSkinID)
{
	EnterCriticalSection( &csAdditionalModelParts );
	vector<ModelPart *> *pvModelParts=NULL;
	if(m_AdditionalModelParts.size()>0)
	{
		AUTO_VAR(it, m_AdditionalModelParts.find(dwSkinID));
		if(it!=m_AdditionalModelParts.end())
		{
			pvModelParts = (*it).second;
		}
	}

	LeaveCriticalSection( &csAdditionalModelParts );
	return pvModelParts;
}

vector<SKIN_BOX *> *CMinecraftApp::GetAdditionalSkinBoxes(DWORD dwSkinID)
{
	EnterCriticalSection( &csAdditionalSkinBoxes );
	vector<SKIN_BOX *> *pvSkinBoxes=NULL;
	if(m_AdditionalSkinBoxes.size()>0)
	{
		AUTO_VAR(it,m_AdditionalSkinBoxes.find(dwSkinID));
		if(it!=m_AdditionalSkinBoxes.end())
		{
			pvSkinBoxes = (*it).second;
		}
	}
	
	LeaveCriticalSection( &csAdditionalSkinBoxes );
	return pvSkinBoxes;
}

unsigned int CMinecraftApp::GetAnimOverrideBitmask(DWORD dwSkinID)
{
	EnterCriticalSection( &csAnimOverrideBitmask );
	unsigned int uiAnimOverrideBitmask=0L;

	if(m_AnimOverrides.size()>0)
	{
		AUTO_VAR(it, m_AnimOverrides.find(dwSkinID));
		if(it!=m_AnimOverrides.end())
		{
			uiAnimOverrideBitmask = (*it).second;
		}
	}

	LeaveCriticalSection( &csAnimOverrideBitmask );
	return uiAnimOverrideBitmask;
}

void CMinecraftApp::SetAnimOverrideBitmask(DWORD dwSkinID,unsigned int uiAnimOverrideBitmask)
{
	// Make thread safe
	EnterCriticalSection( &csAnimOverrideBitmask );

	if(m_AnimOverrides.size()>0)
	{
		AUTO_VAR(it, m_AnimOverrides.find(dwSkinID));
		if(it!=m_AnimOverrides.end())
		{
			LeaveCriticalSection( &csAnimOverrideBitmask );
			return; // already in here
		}
	}
	m_AnimOverrides.insert( std::pair<DWORD, unsigned long>(dwSkinID, uiAnimOverrideBitmask) );
	LeaveCriticalSection( &csAnimOverrideBitmask );
}

DWORD CMinecraftApp::getSkinIdFromPath(const wstring &skin)
{
	bool dlcSkin = false; 
	unsigned int skinId = 0;
	
	if(skin.size() >= 14)
	{
		dlcSkin = skin.substr(0,3).compare(L"dlc") == 0;

		wstring skinValue = skin.substr(7,skin.size());
		skinValue = skinValue.substr(0,skinValue.find_first_of(L'.'));
 
		std::wstringstream ss;
		// 4J Stu - dlc skins are numbered using decimal to make it easier for artists/people to number manually
		// Everything else is numbered using hex
		if(dlcSkin)
			ss << std::dec << skinValue.c_str();
		else
			ss << std::hex << skinValue.c_str();
		ss >> skinId;

		skinId = MAKE_SKIN_BITMASK(dlcSkin, skinId);
	}
	return skinId;
}

wstring CMinecraftApp::getSkinPathFromId(DWORD skinId)
{
	// 4J Stu - This function maps the encoded DWORD we store in the player profile
	// to a filename that is stored as a memory texture and shared between systems in game
	wchar_t chars[256];
	if( GET_IS_DLC_SKIN_FROM_BITMASK(skinId) )
	{
		// 4J Stu - DLC skins are numbered using decimal rather than hex to make it easier to number manually
		swprintf(chars, 256, L"dlcskin%08d.png", GET_DLC_SKIN_ID_FROM_BITMASK(skinId));
	
	}
	else
	{
		DWORD ugcSkinIndex = GET_UGC_SKIN_ID_FROM_BITMASK(skinId);
		DWORD defaultSkinIndex = GET_DEFAULT_SKIN_ID_FROM_BITMASK(skinId);
		if( ugcSkinIndex == 0 )
		{
			swprintf(chars, 256, L"defskin%08X.png",defaultSkinIndex);
		}
		else
		{
			swprintf(chars, 256, L"ugcskin%08X.png",ugcSkinIndex);
		}
	}
	return chars;
}


int CMinecraftApp::TexturePackDialogReturned(void *pParam,int iPad,C4JStorage::EMessageResult result)
{
#ifdef _XBOX
	if(result!=C4JStorage::EMessage_Cancelled)
	{
		if(app.GetRequiredTexturePackID()!=0)
		{	
			// we need to enable background downloading for the DLC
			XBackgroundDownloadSetMode(XBACKGROUND_DOWNLOAD_MODE_ALWAYS_ALLOW);

			ULONGLONG ullOfferID_Full;
			ULONGLONG ullIndexA[1];
			app.GetDLCFullOfferIDForPackID(app.GetRequiredTexturePackID(),&ullOfferID_Full);

			if( result==C4JStorage::EMessage_ResultAccept ) // Full version
			{
				ullIndexA[0]=ullOfferID_Full;
				StorageManager.InstallOffer(1,ullIndexA,NULL,NULL);
			}
			else // trial version
			{
				DLC_INFO *pDLCInfo=app.GetDLCInfoForFullOfferID(ullOfferID_Full);
				ullIndexA[0]=pDLCInfo->ullOfferID_Trial;
				StorageManager.InstallOffer(1,ullIndexA,NULL,NULL);
			}	
		}
	}
#endif
	return 0;
}

int CMinecraftApp::getArchiveFileSize(const wstring &filename)
{
	TexturePack *tPack = NULL;
	Minecraft *pMinecraft = Minecraft::GetInstance();
	if(pMinecraft && pMinecraft->skins) tPack = pMinecraft->skins->getSelected();
	if(tPack && tPack->hasData() && tPack->getArchiveFile() && tPack->getArchiveFile()->hasFile(filename))
	{
		return tPack->getArchiveFile()->getFileSize(filename);
	}
	else return m_mediaArchive->getFileSize(filename);
}

bool CMinecraftApp::hasArchiveFile(const wstring &filename)
{
	TexturePack *tPack = NULL;
	Minecraft *pMinecraft = Minecraft::GetInstance();
	if(pMinecraft && pMinecraft->skins) tPack = pMinecraft->skins->getSelected();
	if(tPack && tPack->hasData() && tPack->getArchiveFile() && tPack->getArchiveFile()->hasFile(filename)) return true;
	else return m_mediaArchive->hasFile(filename);
}

byteArray CMinecraftApp::getArchiveFile(const wstring &filename)
{
	TexturePack *tPack = NULL;
	Minecraft *pMinecraft = Minecraft::GetInstance();
	if(pMinecraft && pMinecraft->skins) tPack = pMinecraft->skins->getSelected();
	if(tPack && tPack->hasData() && tPack->getArchiveFile() && tPack->getArchiveFile()->hasFile(filename))
	{
		return tPack->getArchiveFile()->getFile(filename);
	}
	else return m_mediaArchive->getFile(filename);
}

// DLC

#if defined(__PS3__) || defined(__ORBIS__) || defined (__PSVITA__)
int CMinecraftApp::GetDLCInfoCount() 
{ 
	return (int)DLCInfo.size();
}
#elif defined _XBOX_ONE
int CMinecraftApp::GetDLCInfoTrialOffersCount() 
{ 
	return 0;
}

int CMinecraftApp::GetDLCInfoFullOffersCount() 
{ 
	return (int)DLCInfo_Full.size();
}
#else
int CMinecraftApp::GetDLCInfoTrialOffersCount() 
{ 
	return (int)DLCInfo_Trial.size();
}

int CMinecraftApp::GetDLCInfoFullOffersCount() 
{ 
	return (int)DLCInfo_Full.size();
}
#endif

int CMinecraftApp::GetDLCInfoTexturesOffersCount() 
{ 
	return (int)DLCTextures_PackID.size();
}

// AUTOSAVE
void CMinecraftApp::SetAutosaveTimerTime(void)				
{
#if defined(_XBOX_ONE) || defined(__ORBIS__)
	m_uiAutosaveTimer= GetTickCount()+1000*60;
#else
	m_uiAutosaveTimer= GetTickCount()+GetGameSettings(ProfileManager.GetPrimaryPad(),eGameSetting_Autosave)*1000*60*15;
#endif
}// value x 15 to get mins, x60 for secs

bool CMinecraftApp::AutosaveDue(void)						
{ 
	return (GetTickCount()>m_uiAutosaveTimer);
}

unsigned int CMinecraftApp::SecondsToAutosave()			
{ 
	return (m_uiAutosaveTimer - GetTickCount() ) / 1000; 
}

void CMinecraftApp::SetTrialTimerStart(void)	
{
	m_fTrialTimerStart=m_Time.fAppTime; mfTrialPausedTime=0.0f;
}

float CMinecraftApp::getTrialTimer(void)		
{ 
	return m_Time.fAppTime-m_fTrialTimerStart-mfTrialPausedTime;
}

bool CMinecraftApp::IsLocalMultiplayerAvailable()
{
	DWORD 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;

#ifdef __ORBIS__
	// Check for remote play
	available = available && InputManager.IsLocalMultiplayerAvailable();
#endif

	return available;

	// Found this in GameNetworkManager?
	//#ifdef _DURANGO
	//		iOtherConnectedControllers = InputManager.GetConnectedGamepadCount();
	//		if((InputManager.IsPadConnected(userIndex) || ProfileManager.IsSignedIn(userIndex)))
	//		{
	//			--iOtherConnectedControllers;
	//		}
	//#else
	//		for(unsigned int i = 0; i < XUSER_MAX_COUNT; ++i)
	//		{
	//			if( (i!=userIndex) && (InputManager.IsPadConnected(i) || ProfileManager.IsSignedIn(i)) ) 
	//			{
	//				iOtherConnectedControllers++;
	//			}
	//		}
	//#endif
}


// 4J-PB - language and locale function

void CMinecraftApp::getLocale(vector<wstring> &vecWstrLocales)
{
	vector<eMCLang> locales;
	
	DWORD dwSystemLanguage = XGetLanguage( );

	// 4J-PB - restrict the 360 language until we're ready to have them in

#ifdef _XBOX
	switch(dwSystemLanguage)
	{
	case XC_LANGUAGE_FRENCH             :
		locales.push_back(eMCLang_frFR);
		break;
	case XC_LANGUAGE_ITALIAN            :
		locales.push_back(eMCLang_itIT);
		break;
	case XC_LANGUAGE_GERMAN             :
		locales.push_back(eMCLang_deDE);
		break;
	case XC_LANGUAGE_SPANISH            :
		locales.push_back(eMCLang_esES);
		break;
	case XC_LANGUAGE_PORTUGUESE         :
		if(XGetLocale()==XC_LOCALE_BRAZIL)
		{
			locales.push_back(eMCLang_ptBR);
		}
		locales.push_back(eMCLang_ptPT);
		break;
	case XC_LANGUAGE_JAPANESE           :
		locales.push_back(eMCLang_jaJP);
		break;
	case XC_LANGUAGE_KOREAN             :
		locales.push_back(eMCLang_koKR);
		break;
	case XC_LANGUAGE_TCHINESE           :
		locales.push_back(eMCLang_zhCHT);
		break;
	}
#else
	switch(dwSystemLanguage)
	{

	case XC_LANGUAGE_ENGLISH:
		switch(XGetLocale())
		{
		case XC_LOCALE_AUSTRALIA:
		case XC_LOCALE_CANADA:
		case XC_LOCALE_CZECH_REPUBLIC:
		case XC_LOCALE_GREECE:
		case XC_LOCALE_HONG_KONG:
		case XC_LOCALE_HUNGARY:
		case XC_LOCALE_INDIA:
		case XC_LOCALE_IRELAND:
		case XC_LOCALE_ISRAEL:
		case XC_LOCALE_NEW_ZEALAND:
		case XC_LOCALE_SAUDI_ARABIA:
		case XC_LOCALE_SINGAPORE:
		case XC_LOCALE_SLOVAK_REPUBLIC:
		case XC_LOCALE_SOUTH_AFRICA:
		case XC_LOCALE_UNITED_ARAB_EMIRATES:
		case XC_LOCALE_GREAT_BRITAIN:
			locales.push_back(eMCLang_enGB);
			break;	
		default: //XC_LOCALE_UNITED_STATES
			break;
		}
		break;
	case XC_LANGUAGE_JAPANESE           :
		locales.push_back(eMCLang_jaJP);
		break;
	case XC_LANGUAGE_GERMAN             :
		switch(XGetLocale())
		{
		case XC_LOCALE_AUSTRIA:
			locales.push_back(eMCLang_deAT);
			break;
		case XC_LOCALE_SWITZERLAND:
			locales.push_back(eMCLang_deCH);
			break;
		default:// XC_LOCALE_GERMANY:
			break;
		}
		locales.push_back(eMCLang_deDE);
		break;
	case XC_LANGUAGE_FRENCH             :
		switch(XGetLocale())
		{
		case XC_LOCALE_BELGIUM:
			locales.push_back(eMCLang_frBE);
			break;
		case XC_LOCALE_CANADA:
			locales.push_back(eMCLang_frCA);
			break;
		case XC_LOCALE_SWITZERLAND:
			locales.push_back(eMCLang_frCH);
			break;
		default:// XC_LOCALE_FRANCE:
			break;
		}
		locales.push_back(eMCLang_frFR);
		break;
	case XC_LANGUAGE_SPANISH            :
		switch(XGetLocale())
		{
		case XC_LOCALE_MEXICO:
		case XC_LOCALE_ARGENTINA:
		case XC_LOCALE_CHILE:
		case XC_LOCALE_COLOMBIA:
		case XC_LOCALE_UNITED_STATES:
			locales.push_back(eMCLang_esMX);
			break;
		default://XC_LOCALE_SPAIN
			break;
		}
		locales.push_back(eMCLang_esES);
		break;
	case XC_LANGUAGE_ITALIAN            :
		locales.push_back(eMCLang_itIT);
		break;
	case XC_LANGUAGE_KOREAN             :
		locales.push_back(eMCLang_koKR);
		break;
	case XC_LANGUAGE_TCHINESE           :
		switch(XGetLocale())
		{
		case XC_LOCALE_HONG_KONG:
			locales.push_back(eMCLang_zhHK);
			locales.push_back(eMCLang_zhTW);
			break;
		case XC_LOCALE_TAIWAN:
			locales.push_back(eMCLang_zhTW);
			locales.push_back(eMCLang_zhHK);
		default:
			break;
		}
		locales.push_back(eMCLang_zhCHT);
		break;
	case XC_LANGUAGE_PORTUGUESE         :
		if(XGetLocale()==XC_LOCALE_BRAZIL)
		{
			locales.push_back(eMCLang_ptBR);
		}
		locales.push_back(eMCLang_ptPT);
		break;
	case XC_LANGUAGE_POLISH             :
		locales.push_back(eMCLang_plPL);
		break;
	case XC_LANGUAGE_RUSSIAN            :
		locales.push_back(eMCLang_ruRU);
		break;
	case XC_LANGUAGE_SWEDISH            :
		locales.push_back(eMCLang_svSV);
		locales.push_back(eMCLang_svSE);
		break;
	case XC_LANGUAGE_TURKISH            :
		locales.push_back(eMCLang_trTR);
		break;
	case XC_LANGUAGE_BNORWEGIAN         :
		locales.push_back(eMCLang_nbNO);
		locales.push_back(eMCLang_noNO);	
		locales.push_back(eMCLang_nnNO);
		break;
	case XC_LANGUAGE_DUTCH              :
		switch(XGetLocale())
		{
		case XC_LOCALE_BELGIUM:
			locales.push_back(eMCLang_nlBE);
			break;
		default:
			break;
		}
		locales.push_back(eMCLang_nlNL);
		break;
	case XC_LANGUAGE_SCHINESE           :
		switch(XGetLocale())
		{
		case XC_LOCALE_SINGAPORE:
			locales.push_back(eMCLang_zhSG);
		break;
		default:
			break;
		}
		locales.push_back(eMCLang_zhCHS);
		locales.push_back(eMCLang_zhCN);
		break;


#if defined __PS3__ || defined __ORBIS__ || defined __PSVITA__ || defined _DURANGO
	case XC_LANGUAGE_DANISH:
		locales.push_back(eMCLang_daDA);
		locales.push_back(eMCLang_daDK);
		break;

	case XC_LANGUAGE_LATINAMERICANSPANISH:
		locales.push_back(eMCLang_laLAS);
		locales.push_back(eMCLang_esES);
		break;

	case XC_LANGUAGE_FINISH				:
		locales.push_back(eMCLang_fiFI);
		break;

	case XC_LANGUAGE_CZECH				:
		locales.push_back(eMCLang_csCZ);
		locales.push_back(eMCLang_enCZ);
		break;

	case XC_LANGUAGE_SLOVAK				:
		locales.push_back(eMCLang_skSK);
		locales.push_back(eMCLang_enSK);
		break;

	case XC_LANGUAGE_GREEK				:
		locales.push_back(eMCLang_elEL);
		locales.push_back(eMCLang_elGR);
		locales.push_back(eMCLang_enGR);
		locales.push_back(eMCLang_enGB);
		break;
#endif
	}
#endif

	locales.push_back(eMCLang_enUS);
	locales.push_back(eMCLang_null);

	for (int i=0; i<locales.size(); i++)
	{
		eMCLang lang = locales.at(i);
		vecWstrLocales.push_back( m_localeA[lang] );
	}
}

DWORD CMinecraftApp::get_eMCLang(WCHAR *pwchLocale)
{
	return m_eMCLangA[pwchLocale];
}


DWORD CMinecraftApp::get_xcLang(WCHAR *pwchLocale)
{
	return m_xcLangA[pwchLocale];
}

void CMinecraftApp::LocaleAndLanguageInit()
{
	m_localeA[eMCLang_zhCHT]	=L"zh-CHT";
	m_localeA[eMCLang_zhCHS]	=L"zh-CHS";
	m_localeA[eMCLang_laLAS]	=L"la-LAS";
	m_localeA[eMCLang_null]		=L"en-EN";
	m_localeA[eMCLang_enUS]		=L"en-US";
	m_localeA[eMCLang_enGB]		=L"en-GB";
	m_localeA[eMCLang_enIE]		=L"en-IE";
	m_localeA[eMCLang_enAU]		=L"en-AU";
	m_localeA[eMCLang_enNZ]		=L"en-NZ";
	m_localeA[eMCLang_enCA]		=L"en-CA";
	m_localeA[eMCLang_jaJP]		=L"ja-JP";
	m_localeA[eMCLang_deDE]		=L"de-DE";
	m_localeA[eMCLang_deAT]		=L"de-AT";
	m_localeA[eMCLang_frFR]		=L"fr-FR";
	m_localeA[eMCLang_frCA]		=L"fr-CA";
	m_localeA[eMCLang_esES]		=L"es-ES";
	m_localeA[eMCLang_esMX]		=L"es-MX";
	m_localeA[eMCLang_itIT]		=L"it-IT";
	m_localeA[eMCLang_koKR]		=L"ko-KR";
	m_localeA[eMCLang_ptPT]		=L"pt-PT";
	m_localeA[eMCLang_ptBR]		=L"pt-BR";
	m_localeA[eMCLang_ruRU]		=L"ru-RU";
	m_localeA[eMCLang_nlNL]		=L"nl-NL";
	m_localeA[eMCLang_fiFI]		=L"fi-FI";
	m_localeA[eMCLang_svSV]		=L"sv-SV";
	m_localeA[eMCLang_daDA]		=L"da-DA";
	m_localeA[eMCLang_noNO]		=L"no-NO";
	m_localeA[eMCLang_plPL]		=L"pl-PL";
	m_localeA[eMCLang_trTR]		=L"tr-TR";
	m_localeA[eMCLang_elEL]		=L"el-EL";

	m_localeA[eMCLang_zhSG]		=L"zh-SG";
	m_localeA[eMCLang_zhCN]		=L"zh-CN";
	m_localeA[eMCLang_zhHK]		=L"zh-HK";
	m_localeA[eMCLang_zhTW]		=L"zh-TW";
	m_localeA[eMCLang_nlBE]		=L"nl-BE";
	m_localeA[eMCLang_daDK]		=L"da-DK";
	m_localeA[eMCLang_frBE]		=L"fr-BE";
	m_localeA[eMCLang_frCH]		=L"fr-CH";
	m_localeA[eMCLang_deCH]		=L"de-CH";
	m_localeA[eMCLang_nbNO]		=L"nb-NO";
	m_localeA[eMCLang_enGR]		=L"en-GR";
	m_localeA[eMCLang_enHK]		=L"en-HK";
	m_localeA[eMCLang_enSA]		=L"en-SA";
	m_localeA[eMCLang_enHU]		=L"en-HU";
	m_localeA[eMCLang_enIN]		=L"en-IN";
	m_localeA[eMCLang_enIL]		=L"en-IL";
	m_localeA[eMCLang_enSG]		=L"en-SG";
	m_localeA[eMCLang_enSK]		=L"en-SK";
	m_localeA[eMCLang_enZA]		=L"en-ZA";
	m_localeA[eMCLang_enCZ]		=L"en-CZ";
	m_localeA[eMCLang_enAE]		=L"en-AE";
	m_localeA[eMCLang_esAR]		=L"es-AR";
	m_localeA[eMCLang_esCL]		=L"es-CL";
	m_localeA[eMCLang_esCO]		=L"es-CO";
	m_localeA[eMCLang_esUS]		=L"es-US";
	m_localeA[eMCLang_svSE]		=L"sv-SE";
	
	m_localeA[eMCLang_csCZ]		=L"cs-CZ";
	m_localeA[eMCLang_elGR]		=L"el-GR";
	m_localeA[eMCLang_nnNO]		=L"nn-NO";
	m_localeA[eMCLang_skSK]		=L"sk-SK";

	m_eMCLangA[L"zh-CHT"]		=eMCLang_zhCHS;
	m_eMCLangA[L"zh-CHS"]		=eMCLang_zhCHT;
	m_eMCLangA[L"la-LAS"]		=eMCLang_laLAS;
	m_eMCLangA[L"en-EN"]		=eMCLang_null;
	m_eMCLangA[L"en-US"]		=eMCLang_enUS;
	m_eMCLangA[L"en-GB"]		=eMCLang_enGB;
	m_eMCLangA[L"en-IE"]		=eMCLang_enIE;
	m_eMCLangA[L"en-AU"]		=eMCLang_enAU;
	m_eMCLangA[L"en-NZ"]		=eMCLang_enNZ;
	m_eMCLangA[L"en-CA"]		=eMCLang_enCA;
	m_eMCLangA[L"ja-JP"]		=eMCLang_jaJP;
	m_eMCLangA[L"de-DE"]		=eMCLang_deDE;
	m_eMCLangA[L"de-AT"]		=eMCLang_deAT;
	m_eMCLangA[L"fr-FR"]		=eMCLang_frFR;
	m_eMCLangA[L"fr-CA"]		=eMCLang_frCA;
	m_eMCLangA[L"es-ES"]		=eMCLang_esES;
	m_eMCLangA[L"es-MX"]		=eMCLang_esMX;
	m_eMCLangA[L"it-IT"]		=eMCLang_itIT;
	m_eMCLangA[L"ko-KR"]		=eMCLang_koKR;
	m_eMCLangA[L"pt-PT"]		=eMCLang_ptPT;
	m_eMCLangA[L"pt-BR"]		=eMCLang_ptBR;
	m_eMCLangA[L"ru-RU"]		=eMCLang_ruRU;
	m_eMCLangA[L"nl-NL"]		=eMCLang_nlNL;
	m_eMCLangA[L"fi-FI"]		=eMCLang_fiFI;
	m_eMCLangA[L"sv-SV"]		=eMCLang_svSV;
	m_eMCLangA[L"da-DA"]		=eMCLang_daDA;
	m_eMCLangA[L"no-NO"]		=eMCLang_noNO;
	m_eMCLangA[L"pl-PL"]		=eMCLang_plPL;
	m_eMCLangA[L"tr-TR"]		=eMCLang_trTR;
	m_eMCLangA[L"el-EL"]		=eMCLang_elEL;

	m_eMCLangA[L"zh-SG"]		=eMCLang_zhSG;
	m_eMCLangA[L"zh-CN"]		=eMCLang_zhCN;
	m_eMCLangA[L"zh-HK"]		=eMCLang_zhHK;
	m_eMCLangA[L"zh-TW"]		=eMCLang_zhTW;
	m_eMCLangA[L"nl-BE"]		=eMCLang_nlBE;
	m_eMCLangA[L"da-DK"]		=eMCLang_daDK;
	m_eMCLangA[L"fr-BE"]		=eMCLang_frBE;
	m_eMCLangA[L"fr-CH"]		=eMCLang_frCH;
	m_eMCLangA[L"de-CH"]		=eMCLang_deCH;
	m_eMCLangA[L"nb-NO"]		=eMCLang_nbNO;
	m_eMCLangA[L"en-GR"]		=eMCLang_enGR;
	m_eMCLangA[L"en-HK"]		=eMCLang_enHK;
	m_eMCLangA[L"en-SA"]		=eMCLang_enSA;
	m_eMCLangA[L"en-HU"]		=eMCLang_enHU;
	m_eMCLangA[L"en-IN"]		=eMCLang_enIN;
	m_eMCLangA[L"en-IL"]		=eMCLang_enIL;
	m_eMCLangA[L"en-SG"]		=eMCLang_enSG;
	m_eMCLangA[L"en-SK"]		=eMCLang_enSK;
	m_eMCLangA[L"en-ZA"]		=eMCLang_enZA;
	m_eMCLangA[L"en-CZ"]		=eMCLang_enCZ;
	m_eMCLangA[L"en-AE"]		=eMCLang_enAE;
	m_eMCLangA[L"es-AR"]		=eMCLang_esAR;
	m_eMCLangA[L"es-CL"]		=eMCLang_esCL;
	m_eMCLangA[L"es-CO"]		=eMCLang_esCO;
	m_eMCLangA[L"es-US"]		=eMCLang_esUS;
	m_eMCLangA[L"sv-SE"]		=eMCLang_svSE;

	m_eMCLangA[L"cs-CZ"]		=eMCLang_csCZ;
	m_eMCLangA[L"el-GR"]		=eMCLang_elGR;
	m_eMCLangA[L"nn-NO"]		=eMCLang_nnNO;
	m_eMCLangA[L"sk-SK"]		=eMCLang_skSK;

	m_xcLangA[L"zh-CHT"]		=XC_LOCALE_CHINA;
	m_xcLangA[L"zh-CHS"]		=XC_LOCALE_CHINA;
	m_xcLangA[L"en-EN"]			=XC_LOCALE_UNITED_STATES;
	m_xcLangA[L"en-US"]			=XC_LOCALE_UNITED_STATES;
	m_xcLangA[L"en-GB"]			=XC_LOCALE_GREAT_BRITAIN;
	m_xcLangA[L"en-IE"]			=XC_LOCALE_IRELAND;
	m_xcLangA[L"en-AU"]			=XC_LOCALE_AUSTRALIA;
	m_xcLangA[L"en-NZ"]			=XC_LOCALE_NEW_ZEALAND;
	m_xcLangA[L"en-CA"]			=XC_LOCALE_CANADA;
	m_xcLangA[L"ja-JP"]			=XC_LOCALE_JAPAN;
	m_xcLangA[L"de-DE"]			=XC_LOCALE_GERMANY;
	m_xcLangA[L"de-AT"]			=XC_LOCALE_AUSTRIA;
	m_xcLangA[L"fr-FR"]			=XC_LOCALE_FRANCE;
	m_xcLangA[L"fr-CA"]			=XC_LOCALE_CANADA;
	m_xcLangA[L"es-ES"]			=XC_LOCALE_SPAIN;
	m_xcLangA[L"es-MX"]			=XC_LOCALE_MEXICO;
	m_xcLangA[L"it-IT"]			=XC_LOCALE_ITALY;
	m_xcLangA[L"ko-KR"]			=XC_LOCALE_KOREA;
	m_xcLangA[L"pt-PT"]			=XC_LOCALE_PORTUGAL;
	m_xcLangA[L"pt-BR"]			=XC_LOCALE_BRAZIL;
	m_xcLangA[L"ru-RU"]			=XC_LOCALE_RUSSIAN_FEDERATION;
	m_xcLangA[L"nl-NL"]			=XC_LOCALE_NETHERLANDS;
	m_xcLangA[L"fi-FI"]			=XC_LOCALE_FINLAND;
	m_xcLangA[L"sv-SV"]			=XC_LOCALE_SWEDEN;
	m_xcLangA[L"da-DA"]			=XC_LOCALE_DENMARK;
	m_xcLangA[L"no-NO"]			=XC_LOCALE_NORWAY;
	m_xcLangA[L"pl-PL"]			=XC_LOCALE_POLAND;
	m_xcLangA[L"tr-TR"]			=XC_LOCALE_TURKEY;
	m_xcLangA[L"el-EL"]			=XC_LOCALE_GREECE;
#ifndef _XBOX
	m_xcLangA[L"la-LAS"]		=XC_LOCALE_LATIN_AMERICA;
#endif

	// New ones for Xbox One
	m_xcLangA[L"zh-SG"]			=XC_LOCALE_SINGAPORE;
	m_xcLangA[L"Zh-CN"]			=XC_LOCALE_CHINA;
	m_xcLangA[L"zh-HK"]			=XC_LOCALE_HONG_KONG;
	m_xcLangA[L"zh-TW"]			=XC_LOCALE_TAIWAN;
	m_xcLangA[L"nl-BE"]			=XC_LOCALE_BELGIUM;
	m_xcLangA[L"da-DK"]			=XC_LOCALE_DENMARK;
	m_xcLangA[L"fr-BE"]			=XC_LOCALE_BELGIUM;
	m_xcLangA[L"fr-CH"]			=XC_LOCALE_SWITZERLAND;
	m_xcLangA[L"de-CH"]			=XC_LOCALE_SWITZERLAND;
	m_xcLangA[L"nb-NO"]			=XC_LOCALE_NORWAY;
	m_xcLangA[L"en-GR"]			=XC_LOCALE_GREECE;
	m_xcLangA[L"en-HK"]			=XC_LOCALE_HONG_KONG;
	m_xcLangA[L"en-SA"]			=XC_LOCALE_SAUDI_ARABIA;
	m_xcLangA[L"en-HU"]			=XC_LOCALE_HUNGARY;
	m_xcLangA[L"en-IN"]			=XC_LOCALE_INDIA;
	m_xcLangA[L"en-IL"]			=XC_LOCALE_ISRAEL;
	m_xcLangA[L"en-SG"]			=XC_LOCALE_SINGAPORE;
	m_xcLangA[L"en-SK"]			=XC_LOCALE_SLOVAK_REPUBLIC;
	m_xcLangA[L"en-ZA"]			=XC_LOCALE_SOUTH_AFRICA;
	m_xcLangA[L"en-CZ"]			=XC_LOCALE_CZECH_REPUBLIC;
	m_xcLangA[L"en-AE"]			=XC_LOCALE_UNITED_ARAB_EMIRATES;
	m_xcLangA[L"ja-IP"]			=XC_LOCALE_JAPAN;
	m_xcLangA[L"es-AR"]			=XC_LOCALE_ARGENTINA;
	m_xcLangA[L"es-CL"]			=XC_LOCALE_CHILE;
	m_xcLangA[L"es-CO"]			=XC_LOCALE_COLOMBIA;
	m_xcLangA[L"es-US"]			=XC_LOCALE_UNITED_STATES;
	m_xcLangA[L"sv-SE"]			=XC_LOCALE_SWEDEN;

	m_xcLangA[L"cs-CZ"]			=XC_LOCALE_CZECH_REPUBLIC;
	m_xcLangA[L"el-GR"]			=XC_LOCALE_GREECE;
	m_xcLangA[L"sk-SK"]			=XC_LOCALE_SLOVAK_REPUBLIC;
}

void CMinecraftApp::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;
}

wstring CMinecraftApp::getFilePath(DWORD packId, wstring filename, bool bAddDataFolder)
{
#ifdef _XBOX
	wstring path = getRootPath(packId, true, bAddDataFolder) + filename;
	File f(path);
	if(f.exists())
	{
		return path;
	}
#endif
	return getRootPath(packId, false, true) + filename;
}

#ifdef _XBOX
// Texture packs that have their data in the TU data
enum ETitleUpdateTexturePacks
{
	eTUTP_MassEffect = 0x400,
	eTUTP_Skyrim = 0x401,
	eTUTP_Halo = 0x402,

	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
};

#ifdef _TU_BUILD
wstring titleUpdateTexturePackRoot = L"UPDATE:\\res\\DLC\\";
#else
wstring titleUpdateTexturePackRoot = L"GAME:\\res\\TitleUpdate\\DLC\\";
#endif
#endif

wstring CMinecraftApp::getRootPath(DWORD packId, bool allowOverride, bool bAddDataFolder)
{
	wstring path = L"TPACK:";
#ifdef _XBOX
	if(allowOverride)
	{
		switch(packId)
		{
		case eTUTP_MassEffect:
			path = titleUpdateTexturePackRoot + L"MassEffect";
			break;
		case eTUTP_Skyrim:
			path = titleUpdateTexturePackRoot + L"Skyrim";
			break;
		case eTUTP_Halo:
			path = titleUpdateTexturePackRoot + L"Halo";
			break;
		case eTUTP_Plastic:
			path = titleUpdateTexturePackRoot + L"Plastic";
			break;
		case eTUTP_Candy:
			path = titleUpdateTexturePackRoot + L"Candy";
			break;
		case eTUTP_Fantasy:
			path = titleUpdateTexturePackRoot + L"Fantasy";
			break;
		case eTUTP_Halloween:
			path = titleUpdateTexturePackRoot + L"Halloween";
			break;
		case eTUTP_Natural:
			path = titleUpdateTexturePackRoot + L"Natural";
			break;
		case eTUTP_City:
			path = titleUpdateTexturePackRoot + L"City";
			break;
		};
		File folder(path);
		if(!folder.exists())
		{
			path = L"TPACK:";
		}
	}
#endif

	if(bAddDataFolder)
	{
		return path + L"\\Data\\";
	}
	else
	{
		return path + L"\\";
	}
}

#ifdef _XBOX_ONE
void CMinecraftApp::SetReachedMainMenu()
{
	m_hasReachedMainMenu = true;
}

bool CMinecraftApp::HasReachedMainMenu()
{
	return m_hasReachedMainMenu;
}
#endif