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

404 lines
14 KiB
C++

/////////////////////////////////////////////////////////////////////////////////
//
// FILE : LandingPageController.cpp
// PURPOSE : Main access point to the modern landing page
//
// AUTHOR : stephen.phillips/james.strain
// STARTED : October 2020
//
/////////////////////////////////////////////////////////////////////////////////
#include "LandingPageController.h"
#if GEN9_LANDING_PAGE_ENABLED
// rage
#include "core/core_channel.h"
#include "system/param.h"
// framework
#include "fwsys/fileExts.h"
#include "fwsys/timer.h"
// game
#include "control/ScriptRouterLink.h"
#include "frontend/career_builder/items/CareerBuilderShoppingCartItem.h"
#include "frontend/career_builder/messages/uiCareerBuilderMessages.h"
#include "frontend/save_migration/messages/uiMPMigrationMessages.h"
#include "SaveMigration/SaveMigration.h"
#include "frontend/loadingscreens.h"
#include "frontend/landing_page/LandingPage.h"
#include "frontend/landing_page/messages/uiLandingPageMessages.h"
#include "frontend/page_deck/messages/uiPageDeckMessages.h"
#include "frontend/MousePointer.h"
#include "frontend/UIContexts.h"
#include "Peds/CriminalCareer/CriminalCareerService.h"
#include "network/live/NetworkTelemetry.h"
#include "network/SocialClubServices/SocialClubFeedTilesMgr.h"
#include "system/controlMgr.h"
#include "system/param.h"
#define LANDING_PAGE_DATA_DEFAULT "platform://data/ui/landing_page_deck." META_FILE_EXT
void CLandingPageController::Launch( LandingPageConfig::eEntryPoint const entryPoint )
{
if( !IsActive() )
{
m_entryType = entryPoint;
CNetworkTelemetry::LandingPageEnter();
// Inject our own render functor here in place of the loadingscreens render path on boot and game render phases thereafter
m_pausedRenderFunc = gRenderThreadInterface.GetRenderFunction();
gRenderThreadInterface.SetRenderFunction(MakeFunctor(CLandingPageController::RenderLandingPage));
gRenderThreadInterface.Flush();
// If someone carelessly left the pause menu open, we want to ensure it is shut-down
if( CPauseMenu::IsActive())
{
CPauseMenu::Shutdown(SHUTDOWN_SESSION);
}
if (entryPoint != LandingPageConfig::eEntryPoint::ENTRY_FROM_BOOT)
{
// Suspend script updates until we return to the game. This is not called on boot so landing_pre_startup.sc
// can handle any pending script router link from an external source (e.g. a console Activity).
scrThread::SetIsBlocked(true);
}
uiEntrypointId const c_entryPointId = GetEntryPointId( entryPoint );
m_pageProvider.LaunchToPage( c_entryPointId );
}
}
void CLandingPageController::Dismiss()
{
if( IsActive() )
{
m_pageProvider.Dismiss();
// Restore the render functor we replaced
gRenderThreadInterface.SetRenderFunction(m_pausedRenderFunc);
gRenderThreadInterface.Flush();
scrThread::SetIsBlocked(false);
CSocialClubFeedTilesMgr::Get().ClearFeedsContent(false);
CNetworkTelemetry::LandingPageExit();
m_entryType = LandingPageConfig::eEntryPoint::ENTRY_COUNT;
}
}
void CLandingPageController::Update()
{
if ( IsActive() )
{
float const c_deltaMs = (float)fwTimer::GetTimeStepInMilliseconds_NonPausedNonScaledClipped();
m_pageProvider.Update( c_deltaMs );
// dismiss landing page if an invite has been accepted or confirmed
InviteMgr& inviteMgr = CLiveManager::GetInviteMgr();
if (inviteMgr.HasAcceptedOrConfirmed())
{
CLandingPage::SetShouldDismiss();
}
CNetworkTelemetry::LandingPageUpdate();
}
}
CLandingPageController::CLandingPageController()
: m_entryType( LandingPageConfig::eEntryPoint::ENTRY_COUNT )
, m_initialized( false )
{
}
CLandingPageController::~CLandingPageController()
{
Shutdown();
}
void CLandingPageController::Initialize( IPageViewHost& viewHost )
{
if( !IsInitialized())
{
parSettings settings = PARSER.Settings();
settings.SetFlag( parSettings::CULL_OTHER_PLATFORM_DATA, true );
char const * const c_pageDataPath = GetPageDataPath();
ASSERT_ONLY( bool const c_success = ) PARSER.LoadObject( c_pageDataPath, nullptr, m_pageProvider, &settings );
uiFatalAssertf( c_success, "Failed to load Landing Page data from '%s'", c_pageDataPath );
m_pageProvider.PostLoadInitialize( viewHost );
m_initialized = true;
}
}
bool CLandingPageController::IsInitialized() const
{
return m_initialized;
}
char const * CLandingPageController::GetPageDataPath() const
{
return LANDING_PAGE_DATA_DEFAULT;
}
void CLandingPageController::Shutdown()
{
m_pageProvider.Shutdown();
m_initialized = false;
}
bool CLandingPageController::HandleMessage( uiPageDeckMessageBase& msg )
{
bool result = false;
FWUI_MESSAGE_BIND_REF_RESULT( uiPageDeckCanBackOutMessage, msg, CanBackOutCurrentPage, result );
FWUI_MESSAGE_CALL_REF_SUCCESS( uiLandingPage_GoToStoryMode, msg, EnterStoryMode, result );
FWUI_MESSAGE_BIND_REF_RESULT_SUCCESS_CONST( uiLandingPage_GoToOnlineMode, msg, EnterOnlineMode, result );
FWUI_MESSAGE_CALL_REF_SUCCESS( uiLandingPage_GoToEditorMode, msg, EnterEditorMode, result );
FWUI_MESSAGE_CALL_REF_SUCCESS( uiLandingPage_Dismiss, msg, Dismiss, result );
FWUI_MESSAGE_BIND_REF_RESULT_SUCCESS_CONST( uiGoToPageMessage, msg, HandleTransitionRequestMessage, result );
FWUI_MESSAGE_BIND_REF_RESULT_SUCCESS_CONST( uiSelectCareerMessage, msg, SetCriminalCareer, result );
FWUI_MESSAGE_BIND_REF_RESULT( uiSelectCareerItemMessage, msg, SelectCriminalCareerShoppingCartItem, result );
FWUI_MESSAGE_BIND_REF_RESULT_SUCCESS_CONST( uiStartMPMigrationMessage, msg, StartMPAccountMigration, result);
FWUI_MESSAGE_BIND_REF_RESULT_SUCCESS_CONST(uiSelectMpCharacterSlotMessage, msg, EnterCareerBuilder, result);
CNetworkTelemetry::LandingPageTrackMessage( msg, result );
return result;
}
void CLandingPageController::HandleTransitionRequestMessage( uiGoToPageMessage const& transitionMessage )
{
bool processAsTransition = true;
// If we got a back message and were launched from pause, we need to swap to a dismiss
// message if we are at the root page and can only back out of the menu
// Stephen.Phillips asked me to disable this for now as current designs have launching to
// landing from pause menu as a destructive action
/*if( transitionMessage.GetIsClass<uiPageDeckBackMessage>() && WasLaunchedFromPause() )
{
bool const c_hasBackoutTarget = m_pageProvider.CanBackOut();
if( !c_hasBackoutTarget )
{
processAsTransition = c_hasBackoutTarget;
Dismiss();
}
}*/
if( processAsTransition )
{
uiPageLink const& c_linkInfo = transitionMessage.GetLinkInfo();
m_pageProvider.RequestTransition( c_linkInfo );
}
}
void CLandingPageController::EnterStoryMode()
{
SetScriptRouterLink(ScriptRouterContextData(SRCS_NATIVE_LANDING_PAGE, SRCM_STORY));
CLandingPage::SetShouldDismiss();
}
void CLandingPageController::EnterEditorMode()
{
SetScriptRouterLink(ScriptRouterContextData(SRCS_NATIVE_LANDING_PAGE, SRCM_EDITOR));
CLandingPage::SetShouldDismiss();
}
void CLandingPageController::EnterOnlineMode( uiLandingPage_GoToOnlineMode const& GoToOnlineModeMessage )
{
// validate online mode type
uiAssertf(GoToOnlineModeMessage.GetScriptRouterOnlineModeType() != SRCM_STORY, "uiLandingPage_GoToOnlineMode: Script Router Mode is invalid (SRCM_STORY).");
if( GoToOnlineModeMessage.GetScriptRouterOnlineModeType() != SRCM_STORY )
{
// set script router link from GoToOnlineModeMessage
SetScriptRouterLink(ScriptRouterContextData(SRCS_NATIVE_LANDING_PAGE,
GoToOnlineModeMessage.GetScriptRouterOnlineModeType(),
GoToOnlineModeMessage.GetScriptRouterArgType(),
GoToOnlineModeMessage.GetScriptRouterArg()));
CLandingPage::SetShouldDismiss();
}
}
void CLandingPageController::SetCriminalCareer( const uiSelectCareerMessage& selectCareerMessage )
{
// Update career choice
CCriminalCareerService& criminalCareerService = SCriminalCareerService::GetInstance();
const CriminalCareerDefs::CareerIdentifier& c_careerId = selectCareerMessage.GetCareerIdentifier();
criminalCareerService.SetChosenCareerIdentifier(c_careerId);
// Then navigate to Career shop
uiPageLink const& c_linkInfo = selectCareerMessage.GetLinkInfo();
m_pageProvider.RequestTransition( c_linkInfo );
}
bool CLandingPageController::SelectCriminalCareerShoppingCartItem( const uiSelectCareerItemMessage& selectItemMessage )
{
// Update shopping cart
CCriminalCareerService& criminalCareerService = SCriminalCareerService::GetInstance();
const CriminalCareerDefs::ItemIdentifier& itemId = selectItemMessage.GetItemIdentifier();
const CCriminalCareerItem* p_item = criminalCareerService.TryGetItemWithIdentifier(itemId);
if( uiVerifyf( p_item != nullptr, "Failed to retrieve CriminalCareerItem with ItemIdentifier " HASHFMT, HASHOUT(itemId) ) )
{
const CCriminalCareerItem& c_item = *p_item;
const bool c_isAlwaysInShoppingCart = c_item.GetFlags().IsSet(CriminalCareerDefs::AlwaysInShoppingCart);
if( !c_isAlwaysInShoppingCart )
{
const bool c_wasInShoppingCart = criminalCareerService.IsItemInShoppingCart(c_item);
if( c_wasInShoppingCart )
{
criminalCareerService.RemoveItemFromShoppingCart(c_item);
}
else
{
criminalCareerService.AddItemToShoppingCart(c_item);
}
return true;
}
}
return false;
}
void CLandingPageController::StartMPAccountMigration(uiStartMPMigrationMessage const & MPMigrationMessage)
{
rlSaveMigrationMPAccount chosenAccount = CSaveMigration::GetMultiplayer().GetChosenAccount();
eSaveMigrationStatus currentMigrationStatus = CSaveMigration::GetMultiplayer().GetMigrationStatus();
if (uiVerifyf(currentMigrationStatus == SM_STATUS_NONE, "Tried to migrate but migration status is: %d", currentMigrationStatus))
{
CSaveMigration::GetMultiplayer().MigrateAccount(chosenAccount.m_AccountId, chosenAccount.m_Platform);
uiPageLink const& c_linkInfo = MPMigrationMessage.GetLinkInfo();
m_pageProvider.RequestTransition( c_linkInfo );
}
}
void CLandingPageController::EnterCareerBuilder(const uiSelectMpCharacterSlotMessage& selectMpCharacterSlotMessage)
{
// Update chosen character slot
const int c_chosenMpCharacterSlot = selectMpCharacterSlotMessage.GetChosenMpCharacterSlot();
CSaveMigration::GetMultiplayer().SetChosenMpCharacterSlot(c_chosenMpCharacterSlot);
// Then navigate to the career builder
uiPageLink const& c_linkInfo = selectMpCharacterSlotMessage.GetLinkInfo();
m_pageProvider.RequestTransition( c_linkInfo );
}
void CLandingPageController::SetScriptRouterLink( const ScriptRouterContextData& srcData )
{
// We set the link in response to user input, any existing link should be cleared.
if( ScriptRouterLink::HasPendingScriptRouterLink() )
{
ScriptRouterLink::ClearScriptRouterLink();
}
// Once the ScriptRouterLink has been set, it is processed by MainTransition.sc
// and redirects us to the correct game mode, dismissing the Landing Page.
// If this occurs pre-boot, it is processed by landing_pre_startup.sc instead.
ScriptRouterLink::SetScriptRouterLink(srcData);
}
bool CLandingPageController::CanBackOutCurrentPage( uiPageDeckCanBackOutMessage& backoutMsg ) const
{
bool canBackOut = false;
// If we were launched from pause, we can back out to the pause menu
// Stephen.Phillips asked me to disable this for now as current designs have launching to
// landing from pause menu as a destructive action
/*canBackOut = WasLaunchedFromPause();
if( !canBackOut )*/
{
// ...otherwise we need to see if we have a page we can back out to
canBackOut = m_pageProvider.CanBackOut();
}
backoutMsg.SetResult( canBackOut );
return true;
}
uiEntrypointId CLandingPageController::GetEntryPointId( LandingPageConfig::eEntryPoint const entryPoint )
{
uiEntrypointId result;
switch( entryPoint )
{
case LandingPageConfig::eEntryPoint::ENTRY_FROM_BOOT:
{
result = uiEntrypointId( ATSTRINGHASH( "fromBoot", 0x636A4812 ) );
break;
}
case LandingPageConfig::eEntryPoint::ENTRY_FROM_PAUSE:
{
result = uiEntrypointId( ATSTRINGHASH( "fromPauseMenu", 0xD174B801 ) );
break;
}
case LandingPageConfig::eEntryPoint::SINGLEPLAYER_MIGRATION:
{
result = uiEntrypointId( ATSTRINGHASH( "spMigration", 0xA5CE14E8 ) );
break;
}
case LandingPageConfig::eEntryPoint::MULTIPLAYER_REVIEW_CHARACTERS:
{
result = uiEntrypointId( ATSTRINGHASH( "mpReviewCharacters", 0x5E3BB166 ) );
break;
}
case LandingPageConfig::eEntryPoint::STORYMODE_UPSELL:
{
result = uiEntrypointId( ATSTRINGHASH( "spUpsell", 0x8DE577DC ) );
break;
}
default:
uiFatalAssertf( false, "Unsupported value %u requested", (u32)entryPoint );
}
return result;
}
void CLandingPageController::RenderLandingPage()
{
PF_FRAMEINIT_TIMEBARS(0);
CSystem::BeginRender();
CRenderTargets::LockUIRenderTargets();
#if IS_GEN9_PLATFORM
sga::g_GraphicsContext->BeginRenderPassAuto();
#endif // IS_GEN9_PLATFORM
const grcViewport* pVp = grcViewport::GetDefaultScreen();
GRCDEVICE.Clear(true, Color32(0, 0, 0), false, 0, false, 0);
grcViewport::SetCurrent(pVp);
grcLightState::SetEnabled(false);
grcStateBlock::Default();
grcWorldIdentity();
CLandingPage::Render();
if( CWarningScreen::IsActive() )
{
CWarningScreen::Render();
}
#if IS_GEN9_PLATFORM
sga::g_GraphicsContext->EndRenderPass();
#endif // IS_GEN9_PLATFORM
CRenderTargets::UnlockUIRenderTargets();
#if IS_GEN9_PLATFORM
//Apply UI with scaled brightness based on UI text white point
if (HDRReconstruction::GetInstance()->IsHDRReconstructionEnabled())
{
HDRReconstruction::GetInstance()->ReconstructLoadingScreen(CRenderTargets::GetUIBackBuffer());
}
#else
grcViewport::SetCurrent(NULL);
#endif // IS_GEN9_PLATFORM
CSystem::EndRender();
}
#endif // GEN9_LANDING_PAGE_ENABLED