RealtimeStyleTransferRuntime/Plugins/CommonGame/Source/Private/GameUIPolicy.cpp

202 lines
6.5 KiB
C++
Raw Permalink Normal View History

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