搬了lyra的hudlayout

This commit is contained in:
2023-08-28 03:38:23 +08:00
parent b9666b7fe7
commit c90b2d2956
343 changed files with 10665 additions and 2 deletions

View File

@@ -0,0 +1,51 @@
// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "Engine/CancellableAsyncAction.h"
#include "UObject/SoftObjectPtr.h"
#include "AsyncAction_CreateWidgetAsync.generated.h"
class APlayerController;
class UGameInstance;
class UUserWidget;
class UWorld;
struct FFrame;
struct FStreamableHandle;
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FCreateWidgetAsyncDelegate, UUserWidget*, UserWidget);
/**
* Load the widget class asynchronously, the instance the widget after the loading completes, and return it on OnComplete.
*/
UCLASS(BlueprintType)
class COMMONGAME_API UAsyncAction_CreateWidgetAsync : public UCancellableAsyncAction
{
GENERATED_UCLASS_BODY()
public:
virtual void Cancel() override;
UFUNCTION(BlueprintCallable, BlueprintCosmetic, meta=(WorldContext = "WorldContextObject", BlueprintInternalUseOnly="true"))
static UAsyncAction_CreateWidgetAsync* CreateWidgetAsync(UObject* WorldContextObject, TSoftClassPtr<UUserWidget> UserWidgetSoftClass, APlayerController* OwningPlayer, bool bSuspendInputUntilComplete = true);
virtual void Activate() override;
public:
UPROPERTY(BlueprintAssignable)
FCreateWidgetAsyncDelegate OnComplete;
private:
void OnWidgetLoaded();
FName SuspendInputToken;
TWeakObjectPtr<APlayerController> OwningPlayer;
TWeakObjectPtr<UWorld> World;
TWeakObjectPtr<UGameInstance> GameInstance;
bool bSuspendInputUntilComplete;
TSoftClassPtr<UUserWidget> UserWidgetSoftClass;
TSharedPtr<FStreamableHandle> StreamingHandle;
};

View File

@@ -0,0 +1,51 @@
// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "Engine/CancellableAsyncAction.h"
#include "GameplayTagContainer.h"
#include "UObject/SoftObjectPtr.h"
#include "AsyncAction_PushContentToLayerForPlayer.generated.h"
class APlayerController;
class UCommonActivatableWidget;
class UObject;
struct FFrame;
struct FStreamableHandle;
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FPushContentToLayerForPlayerAsyncDelegate, UCommonActivatableWidget*, UserWidget);
/**
*
*/
UCLASS(BlueprintType)
class COMMONGAME_API UAsyncAction_PushContentToLayerForPlayer : public UCancellableAsyncAction
{
GENERATED_UCLASS_BODY()
public:
virtual void Cancel() override;
UFUNCTION(BlueprintCallable, BlueprintCosmetic, meta=(WorldContext = "WorldContextObject", BlueprintInternalUseOnly="true"))
static UAsyncAction_PushContentToLayerForPlayer* PushContentToLayerForPlayer(APlayerController* OwningPlayer, UPARAM(meta = (AllowAbstract=false)) TSoftClassPtr<UCommonActivatableWidget> WidgetClass, UPARAM(meta = (Categories = "UI.Layer")) FGameplayTag LayerName, bool bSuspendInputUntilComplete = true);
virtual void Activate() override;
public:
UPROPERTY(BlueprintAssignable)
FPushContentToLayerForPlayerAsyncDelegate BeforePush;
UPROPERTY(BlueprintAssignable)
FPushContentToLayerForPlayerAsyncDelegate AfterPush;
private:
FGameplayTag LayerName;
bool bSuspendInputUntilComplete = false;
TWeakObjectPtr<APlayerController> OwningPlayerPtr;
TSoftClassPtr<UCommonActivatableWidget> WidgetClass;
TSharedPtr<FStreamableHandle> StreamingHandle;
};

View File

@@ -0,0 +1,60 @@
// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "Kismet/BlueprintAsyncActionBase.h"
#include "UObject/ObjectPtr.h"
#include "AsyncAction_ShowConfirmation.generated.h"
enum class ECommonMessagingResult : uint8;
class FText;
class UCommonGameDialogDescriptor;
class ULocalPlayer;
struct FFrame;
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FCommonMessagingResultMCDelegate, ECommonMessagingResult, Result);
/**
* Allows easily triggering an async confirmation dialog in blueprints that you can then wait on the result.
*/
UCLASS()
class UAsyncAction_ShowConfirmation : public UBlueprintAsyncActionBase
{
GENERATED_UCLASS_BODY()
public:
UFUNCTION(BlueprintCallable, BlueprintCosmetic, meta = (BlueprintInternalUseOnly = "true", WorldContext = "InWorldContextObject"))
static UAsyncAction_ShowConfirmation* ShowConfirmationYesNo(
UObject* InWorldContextObject, FText Title, FText Message
);
UFUNCTION(BlueprintCallable, BlueprintCosmetic, meta = (BlueprintInternalUseOnly = "true", WorldContext = "InWorldContextObject"))
static UAsyncAction_ShowConfirmation* ShowConfirmationOkCancel(
UObject* InWorldContextObject, FText Title, FText Message
);
UFUNCTION(BlueprintCallable, BlueprintCosmetic, meta = (BlueprintInternalUseOnly = "true", WorldContext = "InWorldContextObject"))
static UAsyncAction_ShowConfirmation* ShowConfirmationCustom(
UObject* InWorldContextObject, UCommonGameDialogDescriptor* Descriptor
);
virtual void Activate() override;
public:
UPROPERTY(BlueprintAssignable)
FCommonMessagingResultMCDelegate OnResult;
private:
void HandleConfirmationResult(ECommonMessagingResult ConfirmationResult);
UPROPERTY(Transient)
TObjectPtr<UObject> WorldContextObject;
UPROPERTY(Transient)
TObjectPtr<ULocalPlayer> TargetLocalPlayer;
UPROPERTY(Transient)
TObjectPtr<UCommonGameDialogDescriptor> Descriptor;
};

View File

@@ -0,0 +1,72 @@
// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "Engine/GameInstance.h"
#include "CommonGameInstance.generated.h"
enum class ECommonUserAvailability : uint8;
enum class ECommonUserPrivilege : uint8;
class FText;
class UCommonUserInfo;
class UCommonSession_SearchResult;
struct FOnlineResultInformation;
class ULocalPlayer;
class USocialManager;
class UObject;
struct FFrame;
struct FGameplayTag;
UCLASS(Abstract, Config = Game)
class COMMONGAME_API UCommonGameInstance : public UGameInstance
{
GENERATED_BODY()
public:
UCommonGameInstance(const FObjectInitializer& ObjectInitializer);
/** Handles errors/warnings from CommonUser, can be overridden per game */
UFUNCTION()
virtual void HandleSystemMessage(FGameplayTag MessageType, FText Title, FText Message);
UFUNCTION()
virtual void HandlePrivilegeChanged(const UCommonUserInfo* UserInfo, ECommonUserPrivilege Privilege, ECommonUserAvailability OldAvailability, ECommonUserAvailability NewAvailability);
/** Call to reset user and session state, usually because a player has been disconnected */
virtual void ResetUserAndSessionState();
/**
* Requested Session Flow
* Something requests the user to join a specific session (for example, a platform overlay via OnUserRequestedSession).
* This request is handled in SetRequestedSession.
* Check if we can join the requested session immediately (CanJoinRequestedSession). If we can, join the requested session (JoinRequestedSession)
* If not, cache the requested session and instruct the game to get into a state where the session can be joined (ResetGameAndJoinRequestedSession)
*/
/** Handles user accepting a session invite from an external source (for example, a platform overlay). Intended to be overridden per game. */
virtual void OnUserRequestedSession(const FPlatformUserId& PlatformUserId, UCommonSession_SearchResult* InRequestedSession, const FOnlineResultInformation& RequestedSessionResult);
/** Get the requested session */
UCommonSession_SearchResult* GetRequestedSession() const { return RequestedSession; }
/** Set (or clear) the requested session. When this is set, the requested session flow begins. */
virtual void SetRequestedSession(UCommonSession_SearchResult* InRequestedSession);
/** Checks if the requested session can be joined. Can be overridden per game. */
virtual bool CanJoinRequestedSession() const;
/** Join the requested session */
virtual void JoinRequestedSession();
/** Get the game into a state to join the requested session */
virtual void ResetGameAndJoinRequestedSession();
virtual int32 AddLocalPlayer(ULocalPlayer* NewPlayer, FPlatformUserId UserId) override;
virtual bool RemoveLocalPlayer(ULocalPlayer* ExistingPlayer) override;
virtual void Init() override;
virtual void ReturnToMainMenu() override;
private:
/** This is the primary player*/
TWeakObjectPtr<ULocalPlayer> PrimaryPlayer;
/** Session the player has requested to join */
UPROPERTY()
TObjectPtr<UCommonSession_SearchResult> RequestedSession;
};

View File

@@ -0,0 +1,51 @@
// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "Engine/LocalPlayer.h"
#include "CommonLocalPlayer.generated.h"
class APawn;
class APlayerController;
class APlayerState;
class FViewport;
class UObject;
class UPrimaryGameLayout;
struct FSceneViewProjectionData;
UCLASS(config=Engine, transient)
class COMMONGAME_API UCommonLocalPlayer : public ULocalPlayer
{
GENERATED_BODY()
public:
UCommonLocalPlayer();
/** Called when the local player is assigned a player controller */
DECLARE_MULTICAST_DELEGATE_TwoParams(FPlayerControllerSetDelegate, UCommonLocalPlayer* LocalPlayer, APlayerController* PlayerController);
FPlayerControllerSetDelegate OnPlayerControllerSet;
/** Called when the local player is assigned a player state */
DECLARE_MULTICAST_DELEGATE_TwoParams(FPlayerStateSetDelegate, UCommonLocalPlayer* LocalPlayer, APlayerState* PlayerState);
FPlayerStateSetDelegate OnPlayerStateSet;
/** Called when the local player is assigned a player pawn */
DECLARE_MULTICAST_DELEGATE_TwoParams(FPlayerPawnSetDelegate, UCommonLocalPlayer* LocalPlayer, APawn* Pawn);
FPlayerPawnSetDelegate OnPlayerPawnSet;
FDelegateHandle CallAndRegister_OnPlayerControllerSet(FPlayerControllerSetDelegate::FDelegate Delegate);
FDelegateHandle CallAndRegister_OnPlayerStateSet(FPlayerStateSetDelegate::FDelegate Delegate);
FDelegateHandle CallAndRegister_OnPlayerPawnSet(FPlayerPawnSetDelegate::FDelegate Delegate);
public:
virtual bool GetProjectionData(FViewport* Viewport, FSceneViewProjectionData& ProjectionData, int32 StereoViewIndex) const override;
bool IsPlayerViewEnabled() const { return bIsPlayerViewEnabled; }
void SetIsPlayerViewEnabled(bool bInIsPlayerViewEnabled) { bIsPlayerViewEnabled = bInIsPlayerViewEnabled; }
UPrimaryGameLayout* GetRootUILayout() const;
private:
bool bIsPlayerViewEnabled = true;
};

View File

@@ -0,0 +1,27 @@
// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "ModularPlayerController.h"
#include "CommonPlayerController.generated.h"
class APawn;
class UObject;
UCLASS(config=Game)
class COMMONGAME_API ACommonPlayerController : public AModularPlayerController
{
GENERATED_BODY()
public:
ACommonPlayerController(const FObjectInitializer& ObjectInitializer = FObjectInitializer::Get());
virtual void ReceivedPlayer() override;
virtual void SetPawn(APawn* InPawn) override;
virtual void OnPossess(class APawn* APawn) override;
virtual void OnUnPossess() override;
protected:
virtual void OnRep_PlayerState() override;
};

View File

@@ -0,0 +1,228 @@
// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "CommonUserWidget.h"
#include "Fonts/SlateFontInfo.h"
#include "CommonPlayerInputKey.generated.h"
enum class ECommonInputType : uint8;
class APlayerController;
class FPaintArgs;
class FSlateRect;
class FSlateWindowElementList;
class FWidgetStyle;
class UCommonLocalPlayer;
class UMaterialInstanceDynamic;
class UObject;
struct FFrame;
struct FGeometry;
UENUM(BlueprintType)
enum class ECommonKeybindForcedHoldStatus : uint8
{
NoForcedHold,
ForcedHold,
NeverShowHold
};
USTRUCT()
struct FMeasuredText
{
GENERATED_BODY()
public:
FText GetText() const { return CachedText; }
void SetText(const FText& InText);
FVector2D GetTextSize() const { return CachedTextSize; }
FVector2D UpdateTextSize(const FSlateFontInfo &InFontInfo, float FontScale = 1.0f) const;
private:
FText CachedText;
mutable FVector2D CachedTextSize;
mutable bool bTextDirty = true;
};
UCLASS(Abstract, BlueprintType, Blueprintable, meta = (DisableNativeTick))
class COMMONGAME_API UCommonPlayerInputKey : public UCommonUserWidget
{
GENERATED_BODY()
public:
UCommonPlayerInputKey(const FObjectInitializer& ObjectInitializer);
/** Update the key and associated display based on our current Boundaction */
UFUNCTION(BlueprintCallable, Category = "Keybind Widget")
void UpdateKeybindWidget();
/** Set the bound key for our keybind */
UFUNCTION(BlueprintCallable, Category = "Keybind Widget")
void SetBoundKey(FKey NewBoundAction);
/** Set the bound action for our keybind */
UFUNCTION(BlueprintCallable, Category = "Keybind Widget")
void SetBoundAction(FName NewBoundAction);
/** Force this keybind to be a hold keybind */
UFUNCTION(BlueprintCallable, Category = "Keybind Widget", meta=(DeprecatedFunction, DeprecationMessage = "Use SetForcedHoldKeybindStatus instead"))
void SetForcedHoldKeybind(bool InForcedHoldKeybind);
/** Force this keybind to be a hold keybind */
UFUNCTION(BlueprintCallable, Category = "Keybind Widget")
void SetForcedHoldKeybindStatus(ECommonKeybindForcedHoldStatus InForcedHoldKeybindStatus);
/** Force this keybind to be a hold keybind */
UFUNCTION(BlueprintCallable, Category = "Keybind Widget")
void SetShowProgressCountDown(bool bShow);
/** Set the axis scale value for this keybind */
UFUNCTION(BlueprintCallable, Category = "Keybind Widget")
void SetAxisScale(const float NewValue) { AxisScale = NewValue; }
/** Set the preset name override value for this keybind. */
UFUNCTION(BlueprintCallable, Category = "Keybind Widget")
void SetPresetNameOverride(const FName NewValue) { PresetNameOverride = NewValue; }
/** Our current BoundAction */
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Keybind Widget")
FName BoundAction;
/** Scale to read when using an axis Mapping */
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Keybind Widget")
float AxisScale;
/** Key this widget is bound to set directly in blueprint. Used when we want to reference a specific key instead of an action. */
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Keybind Widget")
FKey BoundKeyFallback;
/** Allows us to set the input type explicitly for the keybind widget. */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Keybind Widget")
ECommonInputType InputTypeOverride;
/** Allows us to set the preset name explicitly for the keybind widget. */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Keybind Widget")
FName PresetNameOverride;
/** Setting that can show this keybind as a hold or never show it as a hold (even if it is) */
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Keybind Widget")
ECommonKeybindForcedHoldStatus ForcedHoldKeybindStatus;
/** Called through a delegate when we start hold progress */
UFUNCTION()
void StartHoldProgress(FName HoldActionName, float HoldDuration);
/** Called through a delegate when we stop hold progress */
UFUNCTION()
void StopHoldProgress(FName HoldActionName, bool bCompletedSuccessfully);
/** Get whether this keybind is a hold action. */
UFUNCTION(BlueprintCallable, Category = "Keybind Widget")
bool IsHoldKeybind() const { return bIsHoldKeybind; }
UFUNCTION()
bool IsBoundKeyValid() const { return BoundKey.IsValid(); }
protected:
virtual void NativePreConstruct() override;
virtual void NativeConstruct() override;
virtual int32 NativePaint(const FPaintArgs& Args, const FGeometry& AllottedGeometry, const FSlateRect& MyCullingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle, bool bParentEnabled) const override;
void RecalculateDesiredSize();
/** Overridden to destroy our MID */
virtual void NativeDestruct() override;
/** Whether or not this keybind widget is currently set to be a hold keybind */
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Keybind Widget", meta=(ScriptName = "IsHoldKeybindValue"))
bool bIsHoldKeybind;
/** */
UPROPERTY(Transient)
bool bShowKeybindBorder;
UPROPERTY(Transient)
FVector2D FrameSize;
UPROPERTY(BlueprintReadOnly, Category = "Keybind Widget")
bool bShowTimeCountDown;
/** Derived Key this widget is bound to */
UPROPERTY(BlueprintReadOnly, Category = "Keybind Widget")
FKey BoundKey;
/** Material for showing Progress */
UPROPERTY(EditDefaultsOnly, Category = "Keybind Widget")
FSlateBrush HoldProgressBrush;
/** The key bind text border. */
UPROPERTY(EditDefaultsOnly, Category = "Keybind Widget")
FSlateBrush KeyBindTextBorder;
/** Should this keybinding widget display information that it is currently unbound? */
UPROPERTY(EditAnywhere, Category = "Keybind Widget")
bool bShowUnboundStatus = false;
/** The font to apply at each size */
UPROPERTY(EditDefaultsOnly, Category = "Font")
FSlateFontInfo KeyBindTextFont;
/** The font to apply at each size */
UPROPERTY(EditDefaultsOnly, Category = "Font")
FSlateFontInfo CountdownTextFont;
UPROPERTY(Transient)
FMeasuredText CountdownText;
UPROPERTY(Transient)
FMeasuredText KeybindText;
UPROPERTY(Transient)
FMargin KeybindTextPadding;
UPROPERTY(Transient)
FVector2D KeybindFrameMinimumSize;
/** The material parameter name for hold percentage in the HoldKeybindImage */
UPROPERTY(EditDefaultsOnly, Category = "Keybind Widget")
FName PercentageMaterialParameterName;
/** MID for the progress percentage */
UPROPERTY(Transient)
TObjectPtr<UMaterialInstanceDynamic> ProgressPercentageMID;
virtual void NativeOnInitialized() override;
private:
/**
* Synchronizes the hold progress to whatever is currently set in the
* owning player controller.
*/
void SyncHoldProgress();
/** Called for updating the HoldKeybindImage during a hold keybind */
void UpdateHoldProgress();
/** Called when we want to set up this keybind widget as a hold keybind */
void SetupHoldKeybind();
void ShowHoldBackPlate();
void HandlePlayerControllerSet(UCommonLocalPlayer* LocalPlayer, APlayerController* PlayerController);
/** Time when we started using a hold keybind */
float HoldKeybindStartTime = 0;
/** How long, in seconds, we will be doing a hold keybind */
float HoldKeybindDuration = 0;
bool bDrawProgress = false;
bool bDrawBrushForKey = false;
bool bDrawCountdownText = false;
bool bWaitingForPlayerController = false;
UPROPERTY(Transient)
FSlateBrush CachedKeyBrush;
};

View File

@@ -0,0 +1,62 @@
// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "Kismet/BlueprintFunctionLibrary.h"
#include "UObject/SoftObjectPtr.h"
#include "CommonUIExtensions.generated.h"
enum class ECommonInputType : uint8;
template <typename T> class TSubclassOf;
class APlayerController;
class UCommonActivatableWidget;
class ULocalPlayer;
class UObject;
class UUserWidget;
struct FFrame;
struct FGameplayTag;
UCLASS()
class COMMONGAME_API UCommonUIExtensions : public UBlueprintFunctionLibrary
{
GENERATED_BODY()
public:
UCommonUIExtensions() { }
UFUNCTION(BlueprintPure, BlueprintCosmetic, Category = "Global UI Extensions", meta = (WorldContext = "WidgetContextObject"))
static ECommonInputType GetOwningPlayerInputType(const UUserWidget* WidgetContextObject);
UFUNCTION(BlueprintPure, BlueprintCosmetic, Category = "Global UI Extensions", meta = (WorldContext = "WidgetContextObject"))
static bool IsOwningPlayerUsingTouch(const UUserWidget* WidgetContextObject);
UFUNCTION(BlueprintPure, BlueprintCosmetic, Category = "Global UI Extensions", meta = (WorldContext = "WidgetContextObject"))
static bool IsOwningPlayerUsingGamepad(const UUserWidget* WidgetContextObject);
UFUNCTION(BlueprintCallable, BlueprintCosmetic, Category = "Global UI Extensions")
static UCommonActivatableWidget* PushContentToLayer_ForPlayer(const ULocalPlayer* LocalPlayer, UPARAM(meta = (Categories = "UI.Layer")) FGameplayTag LayerName, UPARAM(meta = (AllowAbstract = false)) TSubclassOf<UCommonActivatableWidget> WidgetClass);
UFUNCTION(BlueprintCallable, BlueprintCosmetic, Category = "Global UI Extensions")
static void PushStreamedContentToLayer_ForPlayer(const ULocalPlayer* LocalPlayer, UPARAM(meta = (Categories = "UI.Layer")) FGameplayTag LayerName, UPARAM(meta = (AllowAbstract = false)) TSoftClassPtr<UCommonActivatableWidget> WidgetClass);
UFUNCTION(BlueprintCallable, BlueprintCosmetic, Category = "Global UI Extensions")
static void PopContentFromLayer(UCommonActivatableWidget* ActivatableWidget);
UFUNCTION(BlueprintCallable, BlueprintCosmetic, Category = "Global UI Extensions")
static ULocalPlayer* GetLocalPlayerFromController(APlayerController* PlayerController);
UFUNCTION(BlueprintCallable, BlueprintCosmetic, Category = "Global UI Extensions")
static FName SuspendInputForPlayer(APlayerController* PlayerController, FName SuspendReason);
static FName SuspendInputForPlayer(ULocalPlayer* LocalPlayer, FName SuspendReason);
UFUNCTION(BlueprintCallable, BlueprintCosmetic, Category = "Global UI Extensions")
static void ResumeInputForPlayer(APlayerController* PlayerController, FName SuspendToken);
static void ResumeInputForPlayer(ULocalPlayer* LocalPlayer, FName SuspendToken);
private:
static int32 InputSuspensions;
};

View File

@@ -0,0 +1,50 @@
// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "Subsystems/GameInstanceSubsystem.h"
#include "UObject/SoftObjectPtr.h"
#include "GameUIManagerSubsystem.generated.h"
class FSubsystemCollectionBase;
class UCommonLocalPlayer;
class UGameUIPolicy;
class UObject;
/**
* This manager is intended to be replaced by whatever your game needs to
* actually create, so this class is abstract to prevent it from being created.
*
* If you just need the basic functionality you will start by sublcassing this
* subsystem in your own game.
*/
UCLASS(Abstract, config = Game)
class COMMONGAME_API UGameUIManagerSubsystem : public UGameInstanceSubsystem
{
GENERATED_BODY()
public:
UGameUIManagerSubsystem() { }
virtual void Initialize(FSubsystemCollectionBase& Collection) override;
virtual void Deinitialize() override;
virtual bool ShouldCreateSubsystem(UObject* Outer) const override;
const UGameUIPolicy* GetCurrentUIPolicy() const { return CurrentPolicy; }
UGameUIPolicy* GetCurrentUIPolicy() { return CurrentPolicy; }
virtual void NotifyPlayerAdded(UCommonLocalPlayer* LocalPlayer);
virtual void NotifyPlayerRemoved(UCommonLocalPlayer* LocalPlayer);
virtual void NotifyPlayerDestroyed(UCommonLocalPlayer* LocalPlayer);
protected:
void SwitchToPolicy(UGameUIPolicy* InPolicy);
private:
UPROPERTY(Transient)
TObjectPtr<UGameUIPolicy> CurrentPolicy = nullptr;
UPROPERTY(config, EditAnywhere)
TSoftClassPtr<UGameUIPolicy> DefaultUIPolicyClass;
};

View File

@@ -0,0 +1,103 @@
// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "Engine/World.h"
#include "GameUIPolicy.generated.h"
class UCommonLocalPlayer;
class UGameUIManagerSubsystem;
class ULocalPlayer;
class UPrimaryGameLayout;
/**
*
*/
UENUM()
enum class ELocalMultiplayerInteractionMode : uint8
{
// Fullscreen viewport for the primary player only, regardless of the other player's existence
PrimaryOnly,
// Fullscreen viewport for one player, but players can swap control over who's is displayed and who's is dormant
SingleToggle,
// Viewports displayed simultaneously for both players
Simultaneous
};
USTRUCT()
struct FRootViewportLayoutInfo
{
GENERATED_BODY()
public:
UPROPERTY(Transient)
TObjectPtr<ULocalPlayer> LocalPlayer = nullptr;
UPROPERTY(Transient)
TObjectPtr<UPrimaryGameLayout> RootLayout = nullptr;
UPROPERTY(Transient)
bool bAddedToViewport = false;
FRootViewportLayoutInfo() {}
FRootViewportLayoutInfo(ULocalPlayer* InLocalPlayer, UPrimaryGameLayout* InRootLayout, bool bIsInViewport)
: LocalPlayer(InLocalPlayer)
, RootLayout(InRootLayout)
, bAddedToViewport(bIsInViewport)
{}
bool operator==(const ULocalPlayer* OtherLocalPlayer) const { return LocalPlayer == OtherLocalPlayer; }
};
UCLASS(Abstract, Blueprintable, Within = GameUIManagerSubsystem)
class COMMONGAME_API UGameUIPolicy : public UObject
{
GENERATED_BODY()
public:
template <typename GameUIPolicyClass = UGameUIPolicy>
static GameUIPolicyClass* GetGameUIPolicyAs(const UObject* WorldContextObject)
{
return Cast<GameUIPolicyClass>(GetGameUIPolicy(WorldContextObject));
}
static UGameUIPolicy* GetGameUIPolicy(const UObject* WorldContextObject);
public:
virtual UWorld* GetWorld() const override;
UGameUIManagerSubsystem* GetOwningUIManager() const;
UPrimaryGameLayout* GetRootLayout(const UCommonLocalPlayer* LocalPlayer) const;
ELocalMultiplayerInteractionMode GetLocalMultiplayerInteractionMode() const { return LocalMultiplayerInteractionMode; }
void RequestPrimaryControl(UPrimaryGameLayout* Layout);
protected:
void AddLayoutToViewport(UCommonLocalPlayer* LocalPlayer, UPrimaryGameLayout* Layout);
void RemoveLayoutFromViewport(UCommonLocalPlayer* LocalPlayer, UPrimaryGameLayout* Layout);
virtual void OnRootLayoutAddedToViewport(UCommonLocalPlayer* LocalPlayer, UPrimaryGameLayout* Layout);
virtual void OnRootLayoutRemovedFromViewport(UCommonLocalPlayer* LocalPlayer, UPrimaryGameLayout* Layout);
virtual void OnRootLayoutReleased(UCommonLocalPlayer* LocalPlayer, UPrimaryGameLayout* Layout);
void CreateLayoutWidget(UCommonLocalPlayer* LocalPlayer);
TSubclassOf<UPrimaryGameLayout> GetLayoutWidgetClass(UCommonLocalPlayer* LocalPlayer);
private:
ELocalMultiplayerInteractionMode LocalMultiplayerInteractionMode = ELocalMultiplayerInteractionMode::PrimaryOnly;
UPROPERTY(EditAnywhere)
TSoftClassPtr<UPrimaryGameLayout> LayoutClass;
UPROPERTY(Transient)
TArray<FRootViewportLayoutInfo> RootViewportLayouts;
private:
void NotifyPlayerAdded(UCommonLocalPlayer* LocalPlayer);
void NotifyPlayerRemoved(UCommonLocalPlayer* LocalPlayer);
void NotifyPlayerDestroyed(UCommonLocalPlayer* LocalPlayer);
friend class UGameUIManagerSubsystem;
};

View File

@@ -0,0 +1,68 @@
// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "CommonActivatableWidget.h"
#include "CommonMessagingSubsystem.h"
#include "CommonGameDialog.generated.h"
USTRUCT(BlueprintType)
struct FConfirmationDialogAction
{
GENERATED_BODY()
public:
/** Required: The dialog option to provide. */
UPROPERTY(EditAnywhere, BlueprintReadWrite)
ECommonMessagingResult Result = ECommonMessagingResult::Unknown;
/** Optional: Display Text to use instead of the action name associated with the result. */
UPROPERTY(EditAnywhere, BlueprintReadWrite)
FText OptionalDisplayText;
bool operator==(const FConfirmationDialogAction& Other) const
{
return Result == Other.Result &&
OptionalDisplayText.EqualTo(Other.OptionalDisplayText);
}
};
UCLASS()
class COMMONGAME_API UCommonGameDialogDescriptor : public UObject
{
GENERATED_BODY()
public:
static UCommonGameDialogDescriptor* CreateConfirmationOk(const FText& Header, const FText& Body);
static UCommonGameDialogDescriptor* CreateConfirmationOkCancel(const FText& Header, const FText& Body);
static UCommonGameDialogDescriptor* CreateConfirmationYesNo(const FText& Header, const FText& Body);
static UCommonGameDialogDescriptor* CreateConfirmationYesNoCancel(const FText& Header, const FText& Body);
public:
/** The header of the message to display */
UPROPERTY(EditAnywhere, BlueprintReadWrite)
FText Header;
/** The body of the message to display */
UPROPERTY(EditAnywhere, BlueprintReadWrite)
FText Body;
/** The confirm button's input action to use. */
UPROPERTY(BlueprintReadWrite)
TArray<FConfirmationDialogAction> ButtonActions;
};
UCLASS(Abstract)
class COMMONGAME_API UCommonGameDialog : public UCommonActivatableWidget
{
GENERATED_BODY()
public:
UCommonGameDialog();
virtual void SetupDialog(UCommonGameDialogDescriptor* Descriptor, FCommonMessagingResultDelegate ResultCallback);
virtual void KillDialog();
};

View File

@@ -0,0 +1,50 @@
// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "Subsystems/LocalPlayerSubsystem.h"
#include "CommonMessagingSubsystem.generated.h"
class FSubsystemCollectionBase;
class UCommonGameDialogDescriptor;
class UObject;
/** Possible results from a dialog */
UENUM(BlueprintType)
enum class ECommonMessagingResult : uint8
{
/** The "yes" button was pressed */
Confirmed,
/** The "no" button was pressed */
Declined,
/** The "ignore/cancel" button was pressed */
Cancelled,
/** The dialog was explicitly killed (no user input) */
Killed,
Unknown UMETA(Hidden)
};
DECLARE_DELEGATE_OneParam(FCommonMessagingResultDelegate, ECommonMessagingResult /* Result */);
/**
*
*/
UCLASS(config = Game)
class COMMONGAME_API UCommonMessagingSubsystem : public ULocalPlayerSubsystem
{
GENERATED_BODY()
public:
UCommonMessagingSubsystem() { }
virtual void Initialize(FSubsystemCollectionBase& Collection) override;
virtual void Deinitialize() override;
virtual bool ShouldCreateSubsystem(UObject* Outer) const override;
virtual void ShowConfirmation(UCommonGameDialogDescriptor* DialogDescriptor, FCommonMessagingResultDelegate ResultCallback = FCommonMessagingResultDelegate());
virtual void ShowError(UCommonGameDialogDescriptor* DialogDescriptor, FCommonMessagingResultDelegate ResultCallback = FCommonMessagingResultDelegate());
private:
};

View File

@@ -0,0 +1,137 @@
// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "CommonActivatableWidget.h"
#include "CommonUIExtensions.h"
#include "Engine/AssetManager.h"
#include "Engine/StreamableManager.h"
#include "GameplayTagContainer.h"
#include "Widgets/CommonActivatableWidgetContainer.h" // IWYU pragma: keep
#include "PrimaryGameLayout.generated.h"
class APlayerController;
class UClass;
class UCommonActivatableWidgetContainerBase;
class ULocalPlayer;
class UObject;
struct FFrame;
/**
* The state of an async load operation for the UI.
*/
enum class EAsyncWidgetLayerState : uint8
{
Canceled,
Initialize,
AfterPush
};
/**
* The primary game UI layout of your game. This widget class represents how to layout, push and display all layers
* of the UI for a single player. Each player in a split-screen game will receive their own primary game layout.
*/
UCLASS(Abstract, meta = (DisableNativeTick))
class COMMONGAME_API UPrimaryGameLayout : public UCommonUserWidget
{
GENERATED_BODY()
public:
static UPrimaryGameLayout* GetPrimaryGameLayoutForPrimaryPlayer(const UObject* WorldContextObject);
static UPrimaryGameLayout* GetPrimaryGameLayout(APlayerController* PlayerController);
static UPrimaryGameLayout* GetPrimaryGameLayout(ULocalPlayer* LocalPlayer);
public:
UPrimaryGameLayout(const FObjectInitializer& ObjectInitializer);
/** A dormant root layout is collapsed and responds only to persistent actions registered by the owning player */
void SetIsDormant(bool Dormant);
bool IsDormant() const { return bIsDormant; }
public:
template <typename ActivatableWidgetT = UCommonActivatableWidget>
TSharedPtr<FStreamableHandle> PushWidgetToLayerStackAsync(FGameplayTag LayerName, bool bSuspendInputUntilComplete, TSoftClassPtr<UCommonActivatableWidget> ActivatableWidgetClass)
{
return PushWidgetToLayerStackAsync<ActivatableWidgetT>(LayerName, bSuspendInputUntilComplete, ActivatableWidgetClass, [](EAsyncWidgetLayerState, ActivatableWidgetT*) {});
}
template <typename ActivatableWidgetT = UCommonActivatableWidget>
TSharedPtr<FStreamableHandle> PushWidgetToLayerStackAsync(FGameplayTag LayerName, bool bSuspendInputUntilComplete, TSoftClassPtr<UCommonActivatableWidget> ActivatableWidgetClass, TFunction<void(EAsyncWidgetLayerState, ActivatableWidgetT*)> StateFunc)
{
static_assert(TIsDerivedFrom<ActivatableWidgetT, UCommonActivatableWidget>::IsDerived, "Only CommonActivatableWidgets can be used here");
static FName NAME_PushingWidgetToLayer("PushingWidgetToLayer");
const FName SuspendInputToken = bSuspendInputUntilComplete ? UCommonUIExtensions::SuspendInputForPlayer(GetOwningPlayer(), NAME_PushingWidgetToLayer) : NAME_None;
FStreamableManager& StreamableManager = UAssetManager::Get().GetStreamableManager();
TSharedPtr<FStreamableHandle> StreamingHandle = StreamableManager.RequestAsyncLoad(ActivatableWidgetClass.ToSoftObjectPath(), FStreamableDelegate::CreateWeakLambda(this,
[this, LayerName, ActivatableWidgetClass, StateFunc, SuspendInputToken]()
{
UCommonUIExtensions::ResumeInputForPlayer(GetOwningPlayer(), SuspendInputToken);
ActivatableWidgetT* Widget = PushWidgetToLayerStack<ActivatableWidgetT>(LayerName, ActivatableWidgetClass.Get(), [StateFunc](ActivatableWidgetT& WidgetToInit) {
StateFunc(EAsyncWidgetLayerState::Initialize, &WidgetToInit);
});
StateFunc(EAsyncWidgetLayerState::AfterPush, Widget);
})
);
// Setup a cancel delegate so that we can resume input if this handler is canceled.
StreamingHandle->BindCancelDelegate(FStreamableDelegate::CreateWeakLambda(this,
[this, StateFunc, SuspendInputToken]()
{
UCommonUIExtensions::ResumeInputForPlayer(GetOwningPlayer(), SuspendInputToken);
StateFunc(EAsyncWidgetLayerState::Canceled, nullptr);
})
);
return StreamingHandle;
}
template <typename ActivatableWidgetT = UCommonActivatableWidget>
ActivatableWidgetT* PushWidgetToLayerStack(FGameplayTag LayerName, UClass* ActivatableWidgetClass)
{
return PushWidgetToLayerStack<ActivatableWidgetT>(LayerName, ActivatableWidgetClass, [](ActivatableWidgetT&) {});
}
template <typename ActivatableWidgetT = UCommonActivatableWidget>
ActivatableWidgetT* PushWidgetToLayerStack(FGameplayTag LayerName, UClass* ActivatableWidgetClass, TFunctionRef<void(ActivatableWidgetT&)> InitInstanceFunc)
{
static_assert(TIsDerivedFrom<ActivatableWidgetT, UCommonActivatableWidget>::IsDerived, "Only CommonActivatableWidgets can be used here");
if (UCommonActivatableWidgetContainerBase* Layer = GetLayerWidget(LayerName))
{
return Layer->AddWidget<ActivatableWidgetT>(ActivatableWidgetClass, InitInstanceFunc);
}
return nullptr;
}
// Find the widget if it exists on any of the layers and remove it from the layer.
void FindAndRemoveWidgetFromLayer(UCommonActivatableWidget* ActivatableWidget);
// Get the layer widget for the given layer tag.
UCommonActivatableWidgetContainerBase* GetLayerWidget(FGameplayTag LayerName);
protected:
/** Register a layer that widgets can be pushed onto. */
UFUNCTION(BlueprintCallable, Category="Layer")
void RegisterLayer(UPARAM(meta = (Categories = "UI.Layer")) FGameplayTag LayerTag, UCommonActivatableWidgetContainerBase* LayerWidget);
virtual void OnIsDormantChanged();
void OnWidgetStackTransitioning(UCommonActivatableWidgetContainerBase* Widget, bool bIsTransitioning);
private:
bool bIsDormant = false;
// Lets us keep track of all suspended input tokens so that multiple async UIs can be loading and we correctly suspend
// for the duration of all of them.
TArray<FName> SuspendInputTokens;
// The registered layers for the primary layout.
UPROPERTY(Transient, meta = (Categories = "UI.Layer"))
TMap<FGameplayTag, TObjectPtr<UCommonActivatableWidgetContainerBase>> Layers;
};