Files
GTASource/game/frontend/Store/StoreScreenMgr.cpp
expvintl 419f2e4752 init
2025-02-23 17:40:52 +08:00

1204 lines
35 KiB
C++

#include "Frontend/Store/StoreScreenMgr.h"
#include "Frontend/BusySpinner.h"
#include "Frontend/MiniMap.h"
#include "Frontend/NewHud.h"
#include "Frontend/Store/StoreAdvertScreen.h"
#include "Frontend/Store/StoreMainScreen.h"
#include "Frontend/Store/StoreTextureManager.h"
#include "Frontend/Store/StoreUIChannel.h"
#include "frontend/landing_page/LandingPage.h"
#include "Game/User.h"
#include "Network/Live/NetworkTelemetry.h"
#include "Network/Live/livemanager.h"
#include "Network/Sessions/NetworkSession.h"
#include "System/controlMgr.h"
#include "Text/TextConversion.h"
#include "Vfx/Misc/MovieManager.h"
#include "fwcommerce/CommerceUtil.h"
#include "optimisations.h"
#include "peds/ped.h"
#include "scene/world/GameWorld.h"
#include "Stats/MoneyInterface.h"
#include "Stats/StatsInterface.h"
#include "streaming/defragmentation.h"
#include "streaming/streaming.h"
#include "system/FileMgr.h"
#include "text/messages.h"
#include "Network/NetworkInterface.h"
PARAM(leavempforstore, "The store will cause the player to leave mp sessions.");
PARAM(storeInitialProductId, "Initial Item to Highlight in the Store");
FRONTEND_STORE_OPTIMISATIONS()
#if __XENON
#include <xbox.h>
#endif
#if __BANK
#include "bank/bkmgr.h"
#endif // __BANK
cStoreMainScreen* cStoreScreenMgr::mp_StoreMainScreen = NULL;
bool cStoreScreenMgr::m_IsInitialised = false;
int cStoreScreenMgr::m_ExitRequestedFrameCount = -1;
bool cStoreScreenMgr::m_bStoreIsOpen = false;
CSprite2d cStoreScreenMgr::sm_BackgroundGradient;
bool cStoreScreenMgr::m_LoadingBgSprite = false;
atString cStoreScreenMgr::m_BaseCategory;
atString cStoreScreenMgr::m_InitialProductID;
bool cStoreScreenMgr::m_InitialProductCheckout = false;
//These defaults are just the last values used before we shifted to the frontend.xml
float cStoreScreenMgr::m_MovieXPos = 0.13632f;
float cStoreScreenMgr::m_MovieYPos = 0.075693f;
float cStoreScreenMgr::m_MovieWidth = 0.728903f;
float cStoreScreenMgr::m_MovieHeight = 0.831947f;
bool cStoreScreenMgr::m_HasXMLBeenRead = false;
int cStoreScreenMgr::m_CurrentStoreBranding = 0;
grcBlendStateHandle cStoreScreenMgr::ms_StandardSpriteBlendStateHandle = grcStateBlock::BS_Invalid;
bool cStoreScreenMgr::m_ReturnToPauseMenu = false;
GEN9_STANDALONE_ONLY(bool cStoreScreenMgr::m_LaunchLandingPageOnClose = false);
cStoreTextureManager cStoreScreenMgr::m_StoreTextureManager;
bool cStoreScreenMgr::m_WasOpenedFromNetworkGame = false;
bool cStoreScreenMgr::m_PendingSessionShutdownToOpen = false;
const int DEFAULT_NUM_ITEMS_PER_COLUMN = 2;
int cStoreScreenMgr::m_StoreItemNumPerColumn = DEFAULT_NUM_ITEMS_PER_COLUMN;
int cStoreScreenMgr::m_ResetPauseRenderPhasesFrameCount = 0;
int cStoreScreenMgr::m_TogglePauseRenderPhasesFrameCount = 0;
const int FRAMES_TO_DELAY_RENDER_PHASE_RESET = 5;
const int FRAMES_TO_DELAY_RENDER_PHASE_TOGGLE = 8;
const char* COMMERCE_SORT_TAG_MP = "MP";
bool cStoreScreenMgr::m_StoreEnabled = true;
bool cStoreScreenMgr::m_PermitCashProducts = true;
bool cStoreScreenMgr::m_ShouldShowCashProducts = true;
int cStoreScreenMgr::m_StoreOpenFrameDelay = 0;
s64 cStoreScreenMgr::m_WalletCashAmountForDisplay = 0;
s64 cStoreScreenMgr::m_BankCashAmountForDisplay = 0;
atString cStoreScreenMgr::m_PlayerNameForDisplay;
#define STOREMENU_TXD_PATH ("platform:/textures/frontend")
#define FRONTEND_XML_FILENAME "common:/data/ui/frontend.xml"
#define COMMERCE_NODE "CommerceStore"
const int MP_STORE_FRAME_DELAY = 3;
RAGE_DEFINE_CHANNEL(storeUI)
namespace rage {
extern char *XEX_TITLE_ID; // defined in gta5\src\dev\game\Core\main.cpp
}
void cStoreScreenMgr::Init(unsigned initMode)
{
if ( INIT_CORE == initMode )
{
storeUIAssert(!m_IsInitialised);
m_IsInitialised = true;
REGISTER_FRONTEND_XML(cStoreScreenMgr::HandleXML, COMMERCE_NODE);
}
m_bStoreIsOpen = false;
m_CurrentStoreBranding = 0;
m_StoreItemNumPerColumn = DEFAULT_NUM_ITEMS_PER_COLUMN;
m_StoreEnabled = true;
m_PlayerNameForDisplay.Reset();
m_WalletCashAmountForDisplay = 0;
m_BankCashAmountForDisplay = 0;
//Setup the state block
// stateblocks
grcBlendStateDesc bsd;
// The remaining BlendStates should all have these two flags set
bsd.BlendRTDesc[0].BlendEnable = true;
bsd.BlendRTDesc[0].SrcBlend = grcRSV::BLEND_SRCALPHA;
bsd.BlendRTDesc[0].DestBlend = grcRSV::BLEND_INVSRCALPHA;
bsd.BlendRTDesc[0].BlendOp = grcRSV::BLENDOP_ADD;
bsd.BlendRTDesc[0].SrcBlendAlpha = grcRSV::BLEND_SRCALPHA;
bsd.BlendRTDesc[0].DestBlendAlpha = grcRSV::BLEND_INVSRCALPHA;
bsd.BlendRTDesc[0].BlendOpAlpha = grcRSV::BLENDOP_ADD;
bsd.BlendRTDesc[0].RenderTargetWriteMask = grcRSV::COLORWRITEENABLE_ALL;
ms_StandardSpriteBlendStateHandle = grcStateBlock::CreateBlendState(bsd);
m_ReturnToPauseMenu = false;
m_StoreOpenFrameDelay = 0;
m_BaseCategory = "TOP_DEFAULT";
m_InitialProductID.Reset();
m_InitialProductCheckout = false;
m_ShouldShowCashProducts = true;
}
void cStoreScreenMgr::Shutdown(unsigned shutdownMode)
{
if ( SHUTDOWN_CORE == shutdownMode )
{
storeUIAssert(m_IsInitialised);
m_IsInitialised = false;
if ( mp_StoreMainScreen )
{
delete mp_StoreMainScreen;
mp_StoreMainScreen = NULL;
}
m_InitialProductID.Reset();
m_InitialProductCheckout = false;
}
}
void cStoreScreenMgr::Update()
{
if ( !m_IsInitialised )
{
return;
}
PF_AUTO_PUSH_TIMEBAR("cStoreScreenMgr Update");
if ( mp_StoreMainScreen )
{
mp_StoreMainScreen->Update();
}
// added check to stop any potential loop around
if (m_ExitRequestedFrameCount > 0)
--m_ExitRequestedFrameCount;
if ( m_ExitRequestedFrameCount == 0 )
{
storeUIDebugf1("Exit Request Complete, Closing...");
m_ExitRequestedFrameCount = -1;
if (!Close())
{
//Because MS abort function can stall. Thanks MS.
m_ExitRequestedFrameCount = 1;
return;
}
}
if ( IsMPGameReadyToOpenStore() )
{
storeUIDebugf1("Opening MP store");
m_PendingSessionShutdownToOpen = false;
m_ShouldShowCashProducts = true;
if (CPauseMenu::IsActive())
{
CPauseMenu::TriggerStore();
}
else
{
char cHtmlFormattedBusyString[256];
char* html = CTextConversion::TextToHtml(TheText.Get("STORE_LOADING"),cHtmlFormattedBusyString,sizeof(cHtmlFormattedBusyString));
CBusySpinner::On( html, SPINNER_ICON_LOADING, SPINNER_SOURCE_STORE_LOADING );
Open(false);
}
// PM_ActiveFlags pauseMenuActiveFlags = PM_SkipStore;
// if (CPauseMenu::IsActive(pauseMenuActiveFlags))
// {
// CPauseMenu::Close();
// }
}
if ( m_StoreOpenFrameDelay > 0 )
{
m_StoreOpenFrameDelay--;
}
m_StoreTextureManager.Update();
if (m_ResetPauseRenderPhasesFrameCount > 0)
{
--m_ResetPauseRenderPhasesFrameCount;
if (m_ResetPauseRenderPhasesFrameCount == 0)
{
CPauseMenu::ResetPauseRenderPhases();
}
}
if (m_TogglePauseRenderPhasesFrameCount > 0)
{
--m_TogglePauseRenderPhasesFrameCount;
if (m_TogglePauseRenderPhasesFrameCount == 0)
{
//This matches the call we have in cStoreManager::OpenInternal()
CPauseMenu::TogglePauseRenderPhases(true, OWNER_STORE, __FUNCTION__ );
}
}
}
void cStoreScreenMgr::Render()
{
if ( !m_IsInitialised )
{
return;
}
if ( !m_bStoreIsOpen )
{
return;
}
/* B* 1083542: No more store gradient
grcStateBlock::SetRasterizerState(grcStateBlock::RS_NoBackfaceCull);
grcStateBlock::SetDepthStencilState(grcStateBlock::DSS_IgnoreDepth);
grcStateBlock::SetBlendState(ms_StandardSpriteBlendStateHandle);
RenderBackground();
*/
grcStateBlock::SetRasterizerState(grcStateBlock::RS_Default);
grcStateBlock::SetDepthStencilState(grcStateBlock::DSS_Default);
grcStateBlock::SetBlendState(grcStateBlock::BS_Default);
CSprite2d::ClearRenderState();
CShaderLib::SetGlobalEmissiveScale(1.0f,true);
if ( mp_StoreMainScreen )
{
mp_StoreMainScreen->Render();
}
}
void cStoreScreenMgr::DisplayAdScreen()
{
}
void cStoreScreenMgr::Open(bool closeToPauseMenu GEN9_STANDALONE_ONLY(, bool launchLandingPageOnClose))
{
#if GEN9_STANDALONE_ENABLED
m_LaunchLandingPageOnClose = launchLandingPageOnClose;
#endif
#if RSG_PC
(void)closeToPauseMenu;
OpenPC();
return;
#else
m_ReturnToPauseMenu = closeToPauseMenu;
//Do not allow the store to be opened if the open is already in progress
if (m_PendingSessionShutdownToOpen)
{
return;
}
// atString baseCat("COMPAT_PACKS");
// cStoreScreenMgr::SetBaseCategory(baseCat);
//If we are in a network game get out
if ( NetworkInterface::IsGameInProgress() && PARAM_leavempforstore.Get())
{
// we don't leave multiplayer anymore
}
else
{
if ( m_WasOpenedFromNetworkGame || NetworkInterface::IsGameInProgress())
{
m_ShouldShowCashProducts = true;
}
else
{
m_ShouldShowCashProducts = false;
}
if ( m_WasOpenedFromNetworkGame )
{
m_ReturnToPauseMenu = false;
}
else
{
//Use this opportunity to store values for display in the store.
PopulateDisplayValues();
}
#if !RSG_FINAL
const char* initialProductId = nullptr;
if(PARAM_storeInitialProductId.Get(initialProductId))
{
storeUIDebugf1("Open :: Command Line InitialProductId: %s", initialProductId);
m_InitialProductID = initialProductId;
}
#endif
OpenInternal();
}
#endif //RSG_PC
}
bool cStoreScreenMgr::IsLoadingAssets()
{
bool const c_result = mp_StoreMainScreen && mp_StoreMainScreen->IsLoadingAssets();
return c_result;
}
bool cStoreScreenMgr::RequestMPStore()
{
storeUIDebugf1("RequestMPStore :: IsGameInProgress: %s", NetworkInterface::IsGameInProgress() ? "True" : "False");
//If we are in a network game get out
if (NetworkInterface::IsGameInProgress() && PARAM_leavempforstore.Get() )
{
// we don't leave multiplayer anymore
}
else
{
Open(true);
}
// might not be the case if !NetworkInterface::IsGameInProgress() but
// taking small steps for now
return true;
}
void cStoreScreenMgr::ResetNetworkGameTracking()
{
storeUIDebugf1("ResetNetworkGameTracking :: FromNetworkGame: %s", m_WasOpenedFromNetworkGame ? "True" : "False");
if(m_WasOpenedFromNetworkGame)
{
// we need to check for a full network close here as we only run a partial close when entering the store to
// avoid a long load on entry and exit within multiplayer
CNetwork::CloseNetwork(true);
#if RSG_DURANGO
CNetwork::GetNetworkSession().RemoveFromParty(false);
#endif // RSG_DURANGO
m_WasOpenedFromNetworkGame = false;
}
}
void cStoreScreenMgr::OpenInternal()
{
// NOTE: PS3 marketplace has to page out 17MB of memory to system virtual in order to load the commerce data.
// This CANNOT happen during the Update function otherwise performance will go to shit. To get around this,
// we wait until the beginning of the next Update frame via a call to ContainerReserveStore (via game.cpp).
#if COMMERCE_CONTAINER
CLiveManager::GetCommerceMgr().ContainerReserveStore();
}
void cStoreScreenMgr::OpenInternalPhase2()
{
#endif
if (!NetworkInterface::IsGameInProgress())
CPauseMenu::TogglePauseRenderPhases(false, OWNER_STORE, __FUNCTION__ );
LoadXmlData();
char cHtmlFormattedBusyString[256];
char* html = CTextConversion::TextToHtml(TheText.Get("STORE_LOADING"),cHtmlFormattedBusyString,sizeof(cHtmlFormattedBusyString));
CBusySpinner::On( html, SPINNER_ICON_LOADING, SPINNER_SOURCE_STORE_LOADING );
storeUIAssert( mp_StoreMainScreen == NULL );
if ( mp_StoreMainScreen != NULL )
{
return;
}
mp_StoreMainScreen = rage_new cStoreMainScreen;
mp_StoreMainScreen->Init();
//No longer used.
//CNetworkTelemetry::EnterIngameStore();
if (CGameWorld::FindLocalPlayer() && CGameWorld::FindLocalPlayer()->GetPlayerInfo())
{
CGameWorld::FindLocalPlayer()->GetPlayerInfo()->DisableControlsFrontend();
}
//Check for the RoS cash permission here.
if (NetworkInterface::GetLocalGamerIndex() == -1 || !rlRos::HasPrivilege(NetworkInterface::GetLocalGamerIndex(), RLROS_PRIVILEGEID_PURCHASEVC) || !MoneyInterface::CanBuyCash(0, 0.0f))
{
storeUIDebugf1("OpenInternal :: Cash Products Not Allowed: HasPrivilege: %s, CanBuyCash: %s",
rlRos::HasPrivilege(NetworkInterface::GetLocalGamerIndex(), RLROS_PRIVILEGEID_PURCHASEVC) ? "True" : "False",
MoneyInterface::CanBuyCash(0, 0.0f) ? "True" : "False");
SetCashProductsAllowed(false);
}
else
{
storeUIDebugf1("OpenInternal :: Cash Products Allowed");
SetCashProductsAllowed(true);
}
//Start the commerce util
CLiveManager::GetCommerceMgr().CreateCommerceUtil();
bool isInitialized = CLiveManager::GetCommerceMgr().InitialiseCommerceUtil();
#if RSG_GEN9
// url:bugstar:7422191 - Gen9 - Story mode / SP upgrade is available on US Disk SKU(in - game and preview store). Story mode is already included on Disk versions of the game.
// Suppress the Story Mode item if running a version built against Disk SKU. The story mode item id was obtained from RageCommerceData used to populate the store.
if (SUserEntitlementService::GetInstance().GetGameEntitlementMedium() == UserEntitlementMedium::UEM_DISC)
{
storeUIDebugf1("OpenInternal :: Suppressing SPUpgrade: Already entitled");
CLiveManager::GetCommerceMgr().GetCommerceUtil()->SuppressItemId("SPUpgrade");
}
#endif //RSG_GEN9
//We now limit cash products to only within MP games. In the TU I will change this to be based on the commerce data,
//but since this is going into the main branch I am keeping it simple.
if ( !m_ShouldShowCashProducts || StatsInterface::GetBlockSaveRequests() || !MoneyInterface::SavegameCanBuyCashProducts() )
{
//Suppress cash if required
CLiveManager::GetCommerceMgr().GetCommerceUtil()->SuppressItemId("Cash");
//Suppress packs as well
CLiveManager::GetCommerceMgr().GetCommerceUtil()->SuppressItemId("Packs");
#if RSG_GEN9
//This is being effectively treated as the "suppress if not in MP" section now. Ideally migrate to a data driven solution, but for now add GTA+ cash cards and the story upgrade
if(!CLandingPage::IsActive())
{
CLiveManager::GetCommerceMgr().GetCommerceUtil()->SuppressItemId("SPUpgrade"); //Removes story mode upgrade from SP
}
CLiveManager::GetCommerceMgr().GetCommerceUtil()->SuppressItemId("GTA+Cash"); //Removes GTA+ specific cash from SP
CLiveManager::GetCommerceMgr().GetCommerceUtil()->SuppressItemId("GTAPlus"); //Removes GTA+ specific cash from SP
#endif
storeUIDebugf1("OpenInternal :: Suppressing Cash/Packs: ShouldShowCashProducts: %s, GetBlockSaveRequests: %s, SavegameCanBuyCashProducts: %s",
m_ShouldShowCashProducts ? "True" : "False",
StatsInterface::GetBlockSaveRequests() ? "True" : "False",
MoneyInterface::SavegameCanBuyCashProducts() ? "True" : "False");
}
else if (CLiveManager::GetCommerceMgr().IsEntitledToPremiumPack() || CLiveManager::GetCommerceMgr().IsEntitledToStarterPack())
{
storeUIDebugf1("OpenInternal :: Suppressing Packs: IsEntitledToPremiumPack: %s, IsEntitledToStarterPack: %s",
CLiveManager::GetCommerceMgr().IsEntitledToPremiumPack() ? "True" : "False",
CLiveManager::GetCommerceMgr().IsEntitledToStarterPack() ? "True" : "False");
CLiveManager::GetCommerceMgr().GetCommerceUtil()->SuppressItemId("Packs");
}
//Show the GonD category if appropriate
if (!CFileMgr::IsDownloadableVersion())
{
storeUIDebugf1("OpenInternal :: Suppressing GOND");
CLiveManager::GetCommerceMgr().GetCommerceUtil()->SuppressItemId("GOND");
}
#if NET_ENABLE_MEMBERSHIP_FUNCTIONALITY
// Add relevant subscription Ids
if (rlScMembership::HasMembership(NetworkInterface::GetLocalGamerIndex()))
{
storeUIDebugf1("OpenInternal :: AddSubscriptionId: %s", rlScMembership::GetSubscriptionId());
CLiveManager::GetCommerceMgr().GetCommerceUtil()->AddSubscriptionId(rlScMembership::GetSubscriptionId());
}
#endif
if (isInitialized)
{
storeUIDebugf1("OpenInternal :: Fetching Data...");
CLiveManager::GetCommerceMgr().FetchData();
}
if (!NetworkInterface::IsGameInProgress())
CPauseMenu::SetupCodeForPause();
CMiniMap::SetVisible(false);
CLiveManager::GetCommerceMgr().SetAutoConsumePaused(true);
//sm_BackgroundGradient.Delete();
//RequestSprites();
m_LoadingBgSprite = true;
m_bStoreIsOpen = true;
if (m_ShouldShowCashProducts && CLiveManager::GetCommerceMgr().GetCommerceUtil())
{
//MP is the arbitrary sorting tag we use for designating a store source of online.
storeUIDebugf1("OpenInternal :: Setting Sorting Tag: %s", COMMERCE_SORT_TAG_MP);
CLiveManager::GetCommerceMgr().GetCommerceUtil()->SetSortingTag(COMMERCE_SORT_TAG_MP);
}
#if __XENON
XBackgroundDownloadSetMode(XBACKGROUND_DOWNLOAD_MODE_ALWAYS_ALLOW);
#endif
// Don't allow Share Play or Live Stream while modifying Social Club account details
#if RSG_ORBIS
NetworkInterface::EnableSharePlay(false);
#elif RSG_NP
g_rlNp.GetNpLiveStream().BeginDisableSharePlay();
#endif
//Start up the loading spinner
//CBusySpinner::On( "Loading the store", CSavingGameMessage::SAVEGAME_ICON_STYLE_WORKING, SPINNER_SOURCE_STORE_LOADING );
}
bool cStoreScreenMgr::Close()
{
#if RSG_PC
//On PC everything is handled SCUI side, so we can just return out from here.
return true;
#else
storeUIDebugf1("Close");
if ( CLiveManager::GetCommerceMgr().GetCommerceUtil() && CLiveManager::GetCommerceMgr().GetCommerceUtil()->IsInDataFetchState() )
{
CLiveManager::GetCommerceMgr().GetCommerceUtil()->AbortDataFetch();
if (CLiveManager::GetCommerceMgr().GetCommerceUtil()->IsAbortInProgress())
{
return false;
}
}
CMiniMap::SetVisible(true);
if (CGameWorld::FindLocalPlayer() && CGameWorld::FindLocalPlayer()->GetPlayerInfo())
{
CGameWorld::FindLocalPlayer()->GetPlayerInfo()->EnableControlsFrontend();
}
if ( mp_StoreMainScreen != NULL )
{
CNetworkTelemetry::ExitIngameStore(mp_StoreMainScreen->HasUserBeenInCheckout(), mp_StoreMainScreen->GetTimeSinceInputEnabled());
#if RSG_GEN9
// Append the nav-out metric. Will be skipped internally if SaInNav hasn't been called.
CNetworkTelemetry::AppendSaOutNav();
#endif
delete mp_StoreMainScreen;
mp_StoreMainScreen = NULL;
}
//RemoveSprites();
CLiveManager::GetCommerceMgr().DestroyCommerceUtil();
CPauseMenu::SetupCodeForUnPause();
CLiveManager::GetCommerceMgr().SetAutoConsumePaused(false);
//This call to CPauseMenu::TogglePauseRenderPhases(true) is needed since CPauseMenu::TogglePauseRenderPhases(false) is Called
//albeit indirectly by CPauseMenu::SetupCodeForPause, but CPauseMenu::TogglePauseRenderPhases(true) is not called withing SetupCodeForUnpause
//Will have a chat with the pause menu guys and see if we can sort.
CPauseMenu::TogglePauseRenderPhases(true, OWNER_PAUSEMENU, __FUNCTION__ );
if (m_ReturnToPauseMenu)
{
//Clear out the downloaded textures in this case
ResetStoreTextureManager();
if ( NetworkInterface::IsGameInProgress() )
{
CPauseMenu::Open(FE_MENU_VERSION_MP_PAUSE,true,MENU_UNIQUE_ID_STORE);
}
else
{
CPauseMenu::Open(FE_MENU_VERSION_SP_PAUSE,true,MENU_UNIQUE_ID_STORE);
}
}
if (m_WasOpenedFromNetworkGame)
{
m_WasOpenedFromNetworkGame = false;
if (NetworkInterface::IsLocalPlayerOnline())
{
storeUIDebugf1("Rejoining multiplayer from store");
//If we have confirmed an invite, join that instead. Otherwise, return to previous session.
//Indicate, using JoinFailureAction::JFA_Quickmatch, that we should join a random freemode if the
//previous session is no longer available
if (CLiveManager::GetInviteMgr().HasConfirmedAcceptedInvite())
{
CNetwork::GetNetworkSession().JoinInvite();
}
else if (CLiveManager::GetInviteMgr().HasPendingAcceptedInvite())
{
CNetwork::GetNetworkSession().WaitForInvite(JoinFailureAction::JFA_Quickmatch, MultiplayerGameMode::GameMode_Freeroam);
}
else
{
//Default the failure action, for a previous session join, this will work out
//what we should fall back to
CNetwork::GetNetworkSession().JoinPreviousSession(JoinFailureAction::JFA_None);
}
//Display the script network spinner early so there isn't a gap while MM is reestablished
CBusySpinner::On(TheText.Get("PM_INF_PLLT01"),SPINNER_ICON_LOADING,SPINNER_SOURCE_SCRIPT);
}
else
{
//No longer signed in, bail from multiplayer.
CNetwork::Bail(sBailParameters(BAIL_PROFILE_CHANGE, BAIL_CTX_PROFILE_CHANGE_FROM_STORE));
}
}
if ( m_ReturnToPauseMenu )
{
m_TogglePauseRenderPhasesFrameCount = FRAMES_TO_DELAY_RENDER_PHASE_TOGGLE;
}
else
{
//We do not do this immediately so the grey background caused by the memory container doesn't cause a flash
m_ResetPauseRenderPhasesFrameCount = FRAMES_TO_DELAY_RENDER_PHASE_RESET;
}
#if GEN9_STANDALONE_ENABLED
if (m_LaunchLandingPageOnClose)
{
CLandingPage::SetShouldLaunch( LandingPageConfig::eEntryPoint::ENTRY_FROM_PAUSE );
}
#endif
#if __XENON
XBackgroundDownloadSetMode(XBACKGROUND_DOWNLOAD_MODE_AUTO);
#endif
//Make sure the store spinner does not leak.
CBusySpinner::Off( SPINNER_SOURCE_STORE_LOADING );
m_bStoreIsOpen = false;
#if RSG_ORBIS
NetworkInterface::EnableSharePlay(true);
#elif RSG_NP
g_rlNp.GetNpLiveStream().EndDisableSharePlay();
#endif
return true;
#endif
}
void cStoreScreenMgr::SetStoreBgScrollSpeed( int speed )
{
if ( m_bStoreIsOpen && mp_StoreMainScreen )
{
mp_StoreMainScreen->SetBgScrollSpeed( speed );
}
}
#if __BANK
int cStoreScreenMgr::ms_StoreAnimatedBgSpeed = 240;
void StoreScreenWidgetTestTMDownload()
{
atString texturePath("store/images/store_test_image_content_1.DDS");
//atString texturePath("news/en/img/socialclub_avatar.dds");
cStoreScreenMgr::GetTextureManager()->RequestTexture(texturePath);
}
void StoreScreenWidgetTestTMRelease()
{
atString texturePath("store/images/store_test_image_content_1.DDS");
//atString texturePath("news/en/img/socialclub_avatar.dds");
cStoreScreenMgr::GetTextureManager()->ReleaseTexture(texturePath);
}
void StoreScreenMgrWidgetLoadXML()
{
//Force a reload of the XML data.
cStoreScreenMgr::LoadXmlData(true);
}
void StoreScreenMgrWidgetApplyScreenAnimation()
{
cStoreScreenMgr::SetStoreBgScrollSpeed(cStoreScreenMgr::ms_StoreAnimatedBgSpeed);
}
/*
void StoreScreenWidgetFetchAdvertData()
{
cStoreScreenMgr::FetchAdvertData();
}
*/
void StoreScreenMgrWidgetSetCashEnabled()
{
cStoreScreenMgr::SetCashProductsAllowed(true);
}
void StoreScreenMgrWidgetSetCashDisabled()
{
cStoreScreenMgr::SetCashProductsAllowed(false);
}
void cStoreScreenMgr::InitWidgets()
{
bkBank *pBank = BANKMGR.FindBank(UI_DEBUG_BANK_NAME);
if (!pBank) // create the bank if not found
{
pBank = &BANKMGR.CreateBank(UI_DEBUG_BANK_NAME);
}
if (pBank)
{
pBank->AddButton("Create Store Menu widgets", &cStoreScreenMgr::CreateBankWidgets);
}
}
void cStoreScreenMgr::CreateBankWidgets()
{
static bool bStoreScreenBankCreated = false;
bkBank *bank = BANKMGR.FindBank(UI_DEBUG_BANK_NAME);
if ((!bStoreScreenBankCreated) && (bank))
{
bank->PushGroup("Store Menu");
bank->AddButton("Store Menu Active", &cStoreScreenMgr::SwitchOnOff);
//bank->AddButton("Parse advert data", &StoreScreenWidgetFetchAdvertData);
bank->AddButton("Force XML reload", &StoreScreenMgrWidgetLoadXML);
bank->AddButton("Start TM DL", &StoreScreenWidgetTestTMDownload);
bank->AddButton("Start TM Release", &StoreScreenWidgetTestTMRelease);
bank->AddSeparator();
bank->AddSlider("Set Num Store Items in column (power of 2) (require store exit)",&m_StoreItemNumPerColumn,0,2,DEFAULT_NUM_ITEMS_PER_COLUMN);
bank->AddSlider("Set store BG scroll speed", &ms_StoreAnimatedBgSpeed,10,400,1);
bank->AddButton("Apply store BG scroll speed",&StoreScreenMgrWidgetApplyScreenAnimation);
bank->AddButton("Set Cash Enabled", &StoreScreenMgrWidgetSetCashEnabled);
bank->AddButton("Set Cash Disabled", &StoreScreenMgrWidgetSetCashDisabled);
bank->PopGroup();
bStoreScreenBankCreated = true;
}
}
void cStoreScreenMgr::SwitchOnOff()
{
if ( mp_StoreMainScreen )
{
Close();
}
else
{
Open();
}
}
#endif
void cStoreScreenMgr::CheckIncomingFunctions(atHashWithStringBank methodName, const GFxValue* args)
{
//Uncomment when the enum is fixed.
/*
if ((eSCALEFORM_BASE_CLASS)(s32)args[0].GetNumber() != SF_BASE_CLASS_STOREMENU)
return;
*/
if ( mp_StoreMainScreen )
{
mp_StoreMainScreen->CheckIncomingFunctions(methodName, args);
}
}
void cStoreScreenMgr::RequestExit()
{
if(m_ExitRequestedFrameCount < 0)
{
storeUIDebugf1("RequestExit");
m_ExitRequestedFrameCount = EXIT_REQUEST_FRAME_DELAY;
}
}
void cStoreScreenMgr::OnSignOffline()
{
storeUIDebugf1("OnSignOffline");
ResetNetworkGameTracking();
}
void cStoreScreenMgr::OnSignOut()
{
storeUIDebugf1("OnSignOut");
ResetNetworkGameTracking();
}
void cStoreScreenMgr::OnMembershipGained()
{
#if NET_ENABLE_MEMBERSHIP_FUNCTIONALITY
storeUIDebugf1("OnMembershipGained :: Open: %s, MainScreen: %s",
m_bStoreIsOpen ? "True" : "False",
mp_StoreMainScreen ? "Valid" : "Invalid");
if(m_bStoreIsOpen && mp_StoreMainScreen != nullptr)
{
// Add relevant subscription Ids
storeUIDebugf1("OnMembershipGained :: AddSubscriptionId: %s", rlScMembership::GetSubscriptionId());
CLiveManager::GetCommerceMgr().GetCommerceUtil()->AddSubscriptionId(rlScMembership::GetSubscriptionId());
// this flags a refresh
mp_StoreMainScreen->OnMembershipGained();
}
#endif
}
void cStoreScreenMgr::DumpDebugInfo()
{
}
/*
bool cStoreScreenMgr::FetchAdvertData()
{
storeUIAssertf( mp_StoreAdvertData, "mp_StoreAdvertData is NULL. make sure you call cStoreScreenMgr::Init before opening" );
if ( mp_StoreAdvertData == NULL )
{
return false;
}
int localUserIndex = 0;
const rlGamerInfo* localGamer = NetworkInterface::GetActiveGamerInfo();
if (!localGamer )
{
storeUIAssertf(false, "Local gamer currently is NULL");
return false;
}
else if ( !localGamer->IsValid() )
{
storeUIAssertf(false, "Local gamer currently isn't valid");
return false;
}
else if ( !localGamer->IsOnline() )
{
storeUIAssertf(false, "Local gamer currently isn't online");
return false;
}
else
{
localUserIndex = localGamer->GetLocalIndex();
}
mp_StoreAdvertData->SetLocalUserIndex( localUserIndex );
mp_StoreAdvertData->StartDataFetch();
return true;
}
*/
/////////////////////////////////////////////////////////////////////////////////////
// NAME: cStoreScreenMgr::RequestSprites()
// PURPOSE: requests the sprite txd to stream
/////////////////////////////////////////////////////////////////////////////////////
void cStoreScreenMgr::RequestSprites()
{
if (!sm_BackgroundGradient.GetTexture())
{
strLocalIndex iTxdId = g_TxdStore.FindSlot(STOREMENU_TXD_PATH);
if (iTxdId != -1)
{
g_TxdStore.StreamingRequest(iTxdId, (STRFLAG_FORCE_LOAD | STRFLAG_PRIORITY_LOAD | STRFLAG_DONTDELETE));
CStreaming::SetDoNotDefrag(iTxdId, g_TxdStore.GetStreamingModuleId());
}
}
}
/////////////////////////////////////////////////////////////////////////////////////
// NAME: cStoreScreenMgr::SetupSprites()
// PURPOSE: checks if the sprites are loaded and then set them up if it has
/////////////////////////////////////////////////////////////////////////////////////
void cStoreScreenMgr::SetupSprites()
{
if (!sm_BackgroundGradient.GetTexture())
{
strLocalIndex iTxdId = strLocalIndex(g_TxdStore.FindSlot(STOREMENU_TXD_PATH));
if (iTxdId != -1)
{
// This should not be a blocking load
if (g_TxdStore.HasObjectLoaded(iTxdId))
{
g_TxdStore.AddRef(iTxdId, REF_OTHER);
g_TxdStore.PushCurrentTxd();
g_TxdStore.SetCurrentTxd(iTxdId);
if (Verifyf(fwTxd::GetCurrent(), "Current Texture Dictionary (id %u) is NULL ",iTxdId.Get()))
{
sm_BackgroundGradient.SetTexture("gradient_background");
}
g_TxdStore.PopCurrentTxd();
}
}
}
}
/////////////////////////////////////////////////////////////////////////////////////
// NAME: cStoreScreenMgr::RemoveSprites()
// PURPOSE: removes the sprites
/////////////////////////////////////////////////////////////////////////////////////
void cStoreScreenMgr::RemoveSprites()
{
if (sm_BackgroundGradient.GetTexture())
{
sm_BackgroundGradient.Delete();
}
strLocalIndex iTxdId = strLocalIndex(g_TxdStore.FindSlot(STOREMENU_TXD_PATH));
if (iTxdId != -1)
{
g_TxdStore.RemoveRef(iTxdId, REF_OTHER);
}
}
/////////////////////////////////////////////////////////////////////////////////////
// NAME: cStoreScreenMgr::RenderBackground()
// PURPOSE: Renders the background gradiant image
/////////////////////////////////////////////////////////////////////////////////////
void cStoreScreenMgr::RenderBackground()
{
if (sm_BackgroundGradient.GetTexture() && sm_BackgroundGradient.GetShader())
{
sm_BackgroundGradient.SetRenderState();
Vector2 vPos(0.136f, 0.145f);
Vector2 vSize(0.728f, 0.733f);
Vector2 v[4], uv[4];
v[0] = Vector2(vPos.x,vPos.y+vSize.y);
v[1] = Vector2(vPos.x,vPos.y);
v[2] = Vector2(vPos.x+vSize.x,vPos.y+vSize.y);
v[3] = Vector2(vPos.x+vSize.x,vPos.y);
#define __UV_OFFSET (0.002f)
uv[0] = Vector2(__UV_OFFSET,1.0f-__UV_OFFSET);
uv[1] = Vector2(__UV_OFFSET,__UV_OFFSET);
uv[2] = Vector2(1.0f-__UV_OFFSET,1.0f-__UV_OFFSET);
uv[3] = Vector2(1.0f-__UV_OFFSET,__UV_OFFSET);
MULTI_MONITOR_ONLY( sm_BackgroundGradient.MoveToScreenGUI(v) );
sm_BackgroundGradient.Draw(v[0], v[1], v[2], v[3], uv[0], uv[1], uv[2], uv[3], CRGBA(255,255,255,255));
}
}
bool cStoreScreenMgr::IsBgSpriteLoaded()
{
bool bSpriteLoaded = false;
strLocalIndex iTxdId = g_TxdStore.FindSlot(STOREMENU_TXD_PATH);
if (iTxdId != -1)
{
// This should not be a blocking load
bSpriteLoaded = g_TxdStore.HasObjectLoaded(iTxdId);
}
return bSpriteLoaded;
}
atString & cStoreScreenMgr::GetBaseCategory()
{
return m_BaseCategory;
}
void cStoreScreenMgr::SetBaseCategory( atString &newBaseCat )
{
m_BaseCategory = newBaseCat;
}
atString & cStoreScreenMgr::GetInitialItemID()
{
return m_InitialProductID;
}
void cStoreScreenMgr::SetInitialItemID( const atString &newInitialItemID )
{
m_InitialProductID = newInitialItemID;
}
bool cStoreScreenMgr::GetCheckoutInitialItem()
{
return m_InitialProductCheckout;
}
void cStoreScreenMgr::SetCheckoutInitialItem(const bool checkoutInitialItem)
{
m_InitialProductCheckout = checkoutInitialItem;
}
void cStoreScreenMgr::HandleXML( parTreeNode* pCommerceStoreNode )
{
parTreeNode* pNode = NULL;
char cBaseCoordsNode[100];
if (CHudTools::GetWideScreen())
{
safecpy(cBaseCoordsNode, "baseCoords_16_9", NELEM(cBaseCoordsNode));
}
else
{
safecpy(cBaseCoordsNode, "baseCoords_4_3", NELEM(cBaseCoordsNode));
}
while( (pNode = pCommerceStoreNode->FindChildWithName(cBaseCoordsNode, pNode) ) != NULL)
{
if (pNode->GetElement().FindAttribute("posX"))
{
m_MovieXPos = (float)atof(pNode->GetElement().FindAttributeAnyCase("posX")->GetStringValue());
}
if (pNode->GetElement().FindAttribute("posY"))
{
m_MovieYPos = (float)atof(pNode->GetElement().FindAttributeAnyCase("posY")->GetStringValue());
}
if (pNode->GetElement().FindAttribute("sizeX"))
{
m_MovieWidth = (float)atof(pNode->GetElement().FindAttributeAnyCase("sizeX")->GetStringValue());
}
if (pNode->GetElement().FindAttribute("sizeY"))
{
m_MovieHeight = (float)atof(pNode->GetElement().FindAttributeAnyCase("sizeY")->GetStringValue());
}
}
m_HasXMLBeenRead = true;
}
void cStoreScreenMgr::LoadXmlData( bool forceReload )
{
CFrontendXMLMgr::LoadXML(forceReload);
}
void cStoreScreenMgr::ResetStoreTextureManager()
{
m_StoreTextureManager.Shutdown();
m_StoreTextureManager.Init();
}
void cStoreScreenMgr::DelayStoreOpen()
{
m_StoreOpenFrameDelay += MP_STORE_FRAME_DELAY;
}
void cStoreScreenMgr::PopulateDisplayValues()
{
// get the cash:
if ( (CGameWorld::FindLocalPlayer()) && (!CMiniMap::GetInPrologue()) )
{
if(NetworkInterface::IsInFreeMode())
{
m_WalletCashAmountForDisplay = MoneyInterface::GetVCWalletBalance( );
}
else
{
m_WalletCashAmountForDisplay = StatsInterface::GetIntStat(STAT_TOTAL_CASH.GetStatId());
}
if (NetworkInterface::IsGameInProgress()) // for 1438910
{
m_BankCashAmountForDisplay = 0;
if (!StatsInterface::CloudFileLoadPending(0)) // we want to default to 0 if this fails and not assert to match script
{
m_BankCashAmountForDisplay = MoneyInterface::GetVCBankBalance();
}
}
}
if (NetworkInterface::IsGameInProgress())
{
CNetGamePlayer* pNetPlayer = NetworkInterface::GetLocalPlayer();
if (pNetPlayer)
{
if (pNetPlayer->GetGamerInfo().HasDisplayName())
m_PlayerNameForDisplay = pNetPlayer->GetGamerInfo().GetDisplayName();
else
m_PlayerNameForDisplay = pNetPlayer->GetGamerInfo().GetName();
}
}
else
{
CMiniMapBlip *pBlip = CMiniMap::GetBlip(CMiniMap::GetUniqueCentreBlipId());
if (pBlip)
{
m_PlayerNameForDisplay = CMiniMap::GetBlipNameValue(pBlip);
}
}
}
void cStoreScreenMgr::CheckoutCommerceProduct(const char* productID, int location GEN9_STANDALONE_ONLY(, bool launchLandingPageOnClose))
{
atString baseCat("TOP_DEFAULT");
SetBaseCategory(baseCat);
atString productIDString(productID);
SetInitialItemID(productIDString);
SetCheckoutInitialItem(true);
PopulateDisplayValues();
CNetworkTelemetry::GetPurchaseMetricInformation().SaveCurrentCash();
CNetworkTelemetry::GetPurchaseMetricInformation().SetFromLocation((eStorePurchaseLocation)location);
Open(false GEN9_STANDALONE_ONLY(, launchLandingPageOnClose));
}
bool cStoreScreenMgr::IsMPGameReadyToOpenStore()
{
//Moved here as this check is becoming unwieldy with all of the different save and profile tests.
CStatsSavesMgr& saveMgr = CStatsMgr::GetStatsDataMgr().GetSavesMgr();
bool readyToOpenStore = ( m_PendingSessionShutdownToOpen
&& !NetworkInterface::IsSessionActive()
&& m_StoreOpenFrameDelay == 0
&& !saveMgr.IsSaveInProgress()
&& !saveMgr.PendingSaveRequests()
&& !CLiveManager::GetProfileStatsMgr().PendingFlush()
&& !CLiveManager::GetProfileStatsMgr().PendingMultiplayerFlushRequest() );
return readyToOpenStore;
}
#if RSG_PC
void cStoreScreenMgr::OpenPC()
{
g_rlPc.GetCommerceManager()->ShowCommerceStore(NULL,NULL);
}
#endif
bool cStoreScreenMgr::IsStoreMenuOpen()
{
#if RSG_PC
//There is no current way to query for a specific SCUI panel, so I will treat the SCUI in general as being the store
return g_rlPc.IsUiShowing();
#else
return m_bStoreIsOpen;
#endif
}