2022-05-23 18:41:30 +00:00
// Copyright Epic Games, Inc. All Rights Reserved.
# include "GameUIPolicy.h"
# include "CommonActivatableWidget.h"
# include "Engine/LocalPlayer.h"
# include "GameUIManagerSubsystem.h"
# include "CommonLocalPlayer.h"
# include "PrimaryGameLayout.h"
# include "Engine/Engine.h"
# include "LogCommonGame.h"
2022-09-13 07:18:28 +00:00
# include "Widgets/CommonActivatableWidgetContainer.h"
2022-05-23 18:41:30 +00:00
// Static
UGameUIPolicy * UGameUIPolicy : : GetGameUIPolicy ( const UObject * WorldContextObject )
{
if ( UWorld * World = GEngine - > GetWorldFromContextObject ( WorldContextObject , EGetWorldErrorMode : : LogAndReturnNull ) )
{
if ( UGameInstance * GameInstance = World - > GetGameInstance ( ) )
{
if ( UGameUIManagerSubsystem * UIManager = UGameInstance : : GetSubsystem < UGameUIManagerSubsystem > ( GameInstance ) )
{
return UIManager - > GetCurrentUIPolicy ( ) ;
}
}
}
return nullptr ;
}
UGameUIManagerSubsystem * UGameUIPolicy : : GetOwningUIManager ( ) const
{
return CastChecked < UGameUIManagerSubsystem > ( GetOuter ( ) ) ;
}
UWorld * UGameUIPolicy : : GetWorld ( ) const
{
return GetOwningUIManager ( ) - > GetGameInstance ( ) - > GetWorld ( ) ;
}
UPrimaryGameLayout * UGameUIPolicy : : GetRootLayout ( const UCommonLocalPlayer * LocalPlayer ) const
{
const FRootViewportLayoutInfo * LayoutInfo = RootViewportLayouts . FindByKey ( LocalPlayer ) ;
return LayoutInfo ? LayoutInfo - > RootLayout : nullptr ;
}
void UGameUIPolicy : : NotifyPlayerAdded ( UCommonLocalPlayer * LocalPlayer )
{
LocalPlayer - > OnPlayerControllerSet . AddWeakLambda ( this , [ this ] ( UCommonLocalPlayer * LocalPlayer , APlayerController * PlayerController )
{
NotifyPlayerRemoved ( LocalPlayer ) ;
if ( FRootViewportLayoutInfo * LayoutInfo = RootViewportLayouts . FindByKey ( LocalPlayer ) )
{
AddLayoutToViewport ( LocalPlayer , LayoutInfo - > RootLayout ) ;
LayoutInfo - > bAddedToViewport = true ;
}
else
{
CreateLayoutWidget ( LocalPlayer ) ;
}
} ) ;
if ( FRootViewportLayoutInfo * LayoutInfo = RootViewportLayouts . FindByKey ( LocalPlayer ) )
{
AddLayoutToViewport ( LocalPlayer , LayoutInfo - > RootLayout ) ;
LayoutInfo - > bAddedToViewport = true ;
}
else
{
CreateLayoutWidget ( LocalPlayer ) ;
}
}
void UGameUIPolicy : : NotifyPlayerRemoved ( UCommonLocalPlayer * LocalPlayer )
{
if ( FRootViewportLayoutInfo * LayoutInfo = RootViewportLayouts . FindByKey ( LocalPlayer ) )
{
RemoveLayoutFromViewport ( LocalPlayer , LayoutInfo - > RootLayout ) ;
LayoutInfo - > bAddedToViewport = false ;
if ( LocalMultiplayerInteractionMode = = ELocalMultiplayerInteractionMode : : SingleToggle & & ! LocalPlayer - > IsPrimaryPlayer ( ) )
{
UPrimaryGameLayout * RootLayout = LayoutInfo - > RootLayout ;
if ( RootLayout & & ! RootLayout - > IsDormant ( ) )
{
// We're removing a secondary player's root while it's in control - transfer control back to the primary player's root
RootLayout - > SetIsDormant ( true ) ;
for ( const FRootViewportLayoutInfo & RootLayoutInfo : RootViewportLayouts )
{
if ( RootLayoutInfo . LocalPlayer - > IsPrimaryPlayer ( ) )
{
if ( UPrimaryGameLayout * PrimaryRootLayout = RootLayoutInfo . RootLayout )
{
PrimaryRootLayout - > SetIsDormant ( false ) ;
}
}
}
}
}
}
}
void UGameUIPolicy : : NotifyPlayerDestroyed ( UCommonLocalPlayer * LocalPlayer )
{
NotifyPlayerRemoved ( LocalPlayer ) ;
LocalPlayer - > OnPlayerControllerSet . RemoveAll ( this ) ;
const int32 LayoutInfoIdx = RootViewportLayouts . IndexOfByKey ( LocalPlayer ) ;
if ( LayoutInfoIdx ! = INDEX_NONE )
{
UPrimaryGameLayout * Layout = RootViewportLayouts [ LayoutInfoIdx ] . RootLayout ;
RootViewportLayouts . RemoveAt ( LayoutInfoIdx ) ;
RemoveLayoutFromViewport ( LocalPlayer , Layout ) ;
OnRootLayoutReleased ( LocalPlayer , Layout ) ;
}
}
void UGameUIPolicy : : AddLayoutToViewport ( UCommonLocalPlayer * LocalPlayer , UPrimaryGameLayout * Layout )
{
UE_LOG ( LogCommonGame , Log , TEXT ( " [%s] is adding player [%s]'s root layout [%s] to the viewport " ) , * GetName ( ) , * GetNameSafe ( LocalPlayer ) , * GetNameSafe ( Layout ) ) ;
Layout - > SetPlayerContext ( FLocalPlayerContext ( LocalPlayer ) ) ;
Layout - > AddToPlayerScreen ( 1000 ) ;
OnRootLayoutAddedToViewport ( LocalPlayer , Layout ) ;
}
void UGameUIPolicy : : RemoveLayoutFromViewport ( UCommonLocalPlayer * LocalPlayer , UPrimaryGameLayout * Layout )
{
TWeakPtr < SWidget > LayoutSlateWidget = Layout - > GetCachedWidget ( ) ;
if ( LayoutSlateWidget . IsValid ( ) )
{
UE_LOG ( LogCommonGame , Log , TEXT ( " [%s] is removing player [%s]'s root layout [%s] from the viewport " ) , * GetName ( ) , * GetNameSafe ( LocalPlayer ) , * GetNameSafe ( Layout ) ) ;
Layout - > RemoveFromViewport ( ) ;
if ( LayoutSlateWidget . IsValid ( ) )
{
UE_LOG ( LogCommonGame , Log , TEXT ( " Player [%s]'s root layout [%s] has been removed from the viewport, but other references to its underlying Slate widget still exist. Noting in case we leak it. " ) , * GetNameSafe ( LocalPlayer ) , * GetNameSafe ( Layout ) ) ;
}
OnRootLayoutRemovedFromViewport ( LocalPlayer , Layout ) ;
}
}
void UGameUIPolicy : : OnRootLayoutAddedToViewport ( UCommonLocalPlayer * LocalPlayer , UPrimaryGameLayout * Layout )
{
# if WITH_EDITOR
if ( GIsEditor & & LocalPlayer - > IsPrimaryPlayer ( ) )
{
// So our controller will work in PIE without needing to click in the viewport
FSlateApplication : : Get ( ) . SetUserFocusToGameViewport ( 0 ) ;
}
# endif
}
void UGameUIPolicy : : OnRootLayoutRemovedFromViewport ( UCommonLocalPlayer * LocalPlayer , UPrimaryGameLayout * Layout )
{
}
void UGameUIPolicy : : OnRootLayoutReleased ( UCommonLocalPlayer * LocalPlayer , UPrimaryGameLayout * Layout )
{
}
void UGameUIPolicy : : RequestPrimaryControl ( UPrimaryGameLayout * Layout )
{
if ( LocalMultiplayerInteractionMode = = ELocalMultiplayerInteractionMode : : SingleToggle & & Layout - > IsDormant ( ) )
{
for ( const FRootViewportLayoutInfo & LayoutInfo : RootViewportLayouts )
{
UPrimaryGameLayout * RootLayout = LayoutInfo . RootLayout ;
if ( RootLayout & & ! RootLayout - > IsDormant ( ) )
{
RootLayout - > SetIsDormant ( true ) ;
break ;
}
}
Layout - > SetIsDormant ( false ) ;
}
}
void UGameUIPolicy : : CreateLayoutWidget ( UCommonLocalPlayer * LocalPlayer )
{
if ( APlayerController * PlayerController = LocalPlayer - > GetPlayerController ( GetWorld ( ) ) )
{
TSubclassOf < UPrimaryGameLayout > LayoutWidgetClass = GetLayoutWidgetClass ( LocalPlayer ) ;
if ( ensure ( LayoutWidgetClass & & ! LayoutWidgetClass - > HasAnyClassFlags ( CLASS_Abstract ) ) )
{
UPrimaryGameLayout * NewLayoutObject = CreateWidget < UPrimaryGameLayout > ( PlayerController , LayoutWidgetClass ) ;
RootViewportLayouts . Emplace ( LocalPlayer , NewLayoutObject , true ) ;
AddLayoutToViewport ( LocalPlayer , NewLayoutObject ) ;
}
}
}
TSubclassOf < UPrimaryGameLayout > UGameUIPolicy : : GetLayoutWidgetClass ( UCommonLocalPlayer * LocalPlayer )
{
return LayoutClass . LoadSynchronous ( ) ;
}