288 lines
10 KiB
C
288 lines
10 KiB
C
|
// Copyright Epic Games, Inc. All Rights Reserved.
|
||
|
|
||
|
#pragma once
|
||
|
|
||
|
#include "UObject/SoftObjectPtr.h"
|
||
|
#include "UObject/StrongObjectPtr.h"
|
||
|
#include "UObject/WeakInterfacePtr.h"
|
||
|
#include "UObject/Interface.h"
|
||
|
#include "GameplayTagContainer.h"
|
||
|
#include "Templates/SubclassOf.h"
|
||
|
#include "Subsystems/LocalPlayerSubsystem.h"
|
||
|
#include "Subsystems/WorldSubsystem.h"
|
||
|
#include "Subsystems/GameInstanceSubsystem.h"
|
||
|
#include "Kismet/BlueprintFunctionLibrary.h"
|
||
|
|
||
|
#include "UIExtensionSystem.generated.h"
|
||
|
|
||
|
class ULevel;
|
||
|
class UWorld;
|
||
|
class UUIExtension;
|
||
|
struct FUIExtension;
|
||
|
struct FUIExtensionHandle;
|
||
|
struct FUIExtensionRequest;
|
||
|
class UUIExtensionSubsystem;
|
||
|
|
||
|
// Match rule for extension points
|
||
|
UENUM(BlueprintType)
|
||
|
enum class EUIExtensionPointMatch : uint8
|
||
|
{
|
||
|
// An exact match will only receive extensions with exactly the same point
|
||
|
// (e.g., registering for "A.B" will match a broadcast of A.B but not A.B.C)
|
||
|
ExactMatch,
|
||
|
|
||
|
// A partial match will receive any extensions rooted in the same point
|
||
|
// (e.g., registering for "A.B" will match a broadcast of A.B as well as A.B.C)
|
||
|
PartialMatch
|
||
|
};
|
||
|
|
||
|
// Match rule for extension points
|
||
|
UENUM(BlueprintType)
|
||
|
enum class EUIExtensionAction : uint8
|
||
|
{
|
||
|
Added,
|
||
|
Removed
|
||
|
};
|
||
|
|
||
|
DECLARE_DELEGATE_TwoParams(FExtendExtensionPointDelegate, EUIExtensionAction Action, const FUIExtensionRequest& Request);
|
||
|
|
||
|
/**
|
||
|
*
|
||
|
*/
|
||
|
struct FUIExtensionPoint : TSharedFromThis<FUIExtensionPoint>
|
||
|
{
|
||
|
public:
|
||
|
FGameplayTag ExtensionPointTag;
|
||
|
TWeakObjectPtr<UObject> ContextObject;
|
||
|
EUIExtensionPointMatch ExtensionPointTagMatchType = EUIExtensionPointMatch::ExactMatch;
|
||
|
TArray<UClass*> AllowedDataClasses;
|
||
|
FExtendExtensionPointDelegate Callback;
|
||
|
|
||
|
// Tests if the extension and the extension point match up, if they do then this extension point should learn
|
||
|
// about this extension.
|
||
|
bool DoesExtensionPassContract(const FUIExtension* Extension) const;
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
*
|
||
|
*/
|
||
|
USTRUCT(BlueprintType)
|
||
|
struct UIEXTENSION_API FUIExtensionPointHandle
|
||
|
{
|
||
|
GENERATED_BODY()
|
||
|
|
||
|
public:
|
||
|
FUIExtensionPointHandle() {}
|
||
|
|
||
|
void Unregister();
|
||
|
|
||
|
bool IsValid() const { return DataPtr.IsValid(); }
|
||
|
|
||
|
bool operator==(const FUIExtensionPointHandle& Other) const { return DataPtr == Other.DataPtr; }
|
||
|
bool operator!=(const FUIExtensionPointHandle& Other) const { return !operator==(Other); }
|
||
|
|
||
|
friend uint32 GetTypeHash(const FUIExtensionPointHandle& Handle)
|
||
|
{
|
||
|
return PointerHash(Handle.DataPtr.Get());
|
||
|
}
|
||
|
|
||
|
private:
|
||
|
TWeakObjectPtr<UUIExtensionSubsystem> ExtensionSource;
|
||
|
|
||
|
TSharedPtr<FUIExtensionPoint> DataPtr;
|
||
|
|
||
|
friend UUIExtensionSubsystem;
|
||
|
|
||
|
FUIExtensionPointHandle(UUIExtensionSubsystem* InExtensionSource, const TSharedPtr<FUIExtensionPoint>& InDataPtr) : ExtensionSource(InExtensionSource), DataPtr(InDataPtr) {}
|
||
|
};
|
||
|
|
||
|
template<>
|
||
|
struct TStructOpsTypeTraits<FUIExtensionPointHandle> : public TStructOpsTypeTraitsBase2<FUIExtensionPointHandle>
|
||
|
{
|
||
|
enum
|
||
|
{
|
||
|
WithCopy = true, // This ensures the opaque type is copied correctly in BPs
|
||
|
WithIdenticalViaEquality = true,
|
||
|
};
|
||
|
};
|
||
|
|
||
|
/*
|
||
|
*
|
||
|
*/
|
||
|
struct FUIExtension : TSharedFromThis<FUIExtension>
|
||
|
{
|
||
|
public:
|
||
|
/** The extension point this extension is intended for. */
|
||
|
FGameplayTag ExtensionPointTag;
|
||
|
int32 Priority = INDEX_NONE;
|
||
|
TWeakObjectPtr<UObject> ContextObject;
|
||
|
//Kept alive by UUIExtensionSubsystem::AddReferencedObjects
|
||
|
UObject* Data = nullptr;
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
*
|
||
|
*/
|
||
|
USTRUCT(BlueprintType)
|
||
|
struct UIEXTENSION_API FUIExtensionHandle
|
||
|
{
|
||
|
GENERATED_BODY()
|
||
|
|
||
|
public:
|
||
|
FUIExtensionHandle() {}
|
||
|
|
||
|
void Unregister();
|
||
|
|
||
|
bool IsValid() const { return DataPtr.IsValid(); }
|
||
|
|
||
|
bool operator==(const FUIExtensionHandle& Other) const { return DataPtr == Other.DataPtr; }
|
||
|
bool operator!=(const FUIExtensionHandle& Other) const { return !operator==(Other); }
|
||
|
|
||
|
friend FORCEINLINE uint32 GetTypeHash(FUIExtensionHandle Handle)
|
||
|
{
|
||
|
return PointerHash(Handle.DataPtr.Get());
|
||
|
}
|
||
|
|
||
|
private:
|
||
|
TWeakObjectPtr<UUIExtensionSubsystem> ExtensionSource;
|
||
|
|
||
|
TSharedPtr<FUIExtension> DataPtr;
|
||
|
|
||
|
friend UUIExtensionSubsystem;
|
||
|
|
||
|
FUIExtensionHandle(UUIExtensionSubsystem* InExtensionSource, const TSharedPtr<FUIExtension>& InDataPtr) : ExtensionSource(InExtensionSource), DataPtr(InDataPtr) {}
|
||
|
};
|
||
|
|
||
|
template<>
|
||
|
struct TStructOpsTypeTraits<FUIExtensionHandle> : public TStructOpsTypeTraitsBase2<FUIExtensionHandle>
|
||
|
{
|
||
|
enum
|
||
|
{
|
||
|
WithCopy = true, // This ensures the opaque type is copied correctly in BPs
|
||
|
WithIdenticalViaEquality = true,
|
||
|
};
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
*
|
||
|
*/
|
||
|
USTRUCT(BlueprintType)
|
||
|
struct FUIExtensionRequest
|
||
|
{
|
||
|
GENERATED_BODY()
|
||
|
|
||
|
public:
|
||
|
UPROPERTY(EditAnywhere, BlueprintReadOnly)
|
||
|
FUIExtensionHandle ExtensionHandle;
|
||
|
|
||
|
UPROPERTY(EditAnywhere, BlueprintReadOnly)
|
||
|
FGameplayTag ExtensionPointTag;
|
||
|
|
||
|
UPROPERTY(EditAnywhere, BlueprintReadOnly)
|
||
|
int32 Priority = INDEX_NONE;
|
||
|
|
||
|
UPROPERTY(EditAnywhere, BlueprintReadOnly)
|
||
|
UObject* Data = nullptr;
|
||
|
|
||
|
UPROPERTY(EditAnywhere, BlueprintReadOnly)
|
||
|
UObject* ContextObject = nullptr;
|
||
|
};
|
||
|
|
||
|
DECLARE_DYNAMIC_DELEGATE_TwoParams(FExtendExtensionPointDynamicDelegate, EUIExtensionAction, Action, const FUIExtensionRequest&, ExtensionRequest);
|
||
|
|
||
|
/**
|
||
|
*
|
||
|
*/
|
||
|
UCLASS()
|
||
|
class UIEXTENSION_API UUIExtensionSubsystem : public UWorldSubsystem
|
||
|
{
|
||
|
GENERATED_BODY()
|
||
|
|
||
|
public:
|
||
|
FUIExtensionPointHandle RegisterExtensionPoint(const FGameplayTag& ExtensionPointTag, EUIExtensionPointMatch ExtensionPointTagMatchType, const TArray<UClass*>& AllowedDataClasses, FExtendExtensionPointDelegate ExtensionCallback);
|
||
|
FUIExtensionPointHandle RegisterExtensionPointForContext(const FGameplayTag& ExtensionPointTag, UObject* ContextObject, EUIExtensionPointMatch ExtensionPointTagMatchType, const TArray<UClass*>& AllowedDataClasses, FExtendExtensionPointDelegate ExtensionCallback);
|
||
|
|
||
|
FUIExtensionHandle RegisterExtensionAsWidget(const FGameplayTag& ExtensionPointTag, TSubclassOf<UUserWidget> WidgetClass, int32 Priority);
|
||
|
FUIExtensionHandle RegisterExtensionAsWidgetForContext(const FGameplayTag& ExtensionPointTag, UObject* ContextObject, TSubclassOf<UUserWidget> WidgetClass, int32 Priority);
|
||
|
FUIExtensionHandle RegisterExtensionAsData(const FGameplayTag& ExtensionPointTag, UObject* ContextObject, UObject* Data, int32 Priority);
|
||
|
|
||
|
UFUNCTION(BlueprintCallable, BlueprintCosmetic, Category = "UI Extension")
|
||
|
void UnregisterExtension(const FUIExtensionHandle& ExtensionHandle);
|
||
|
|
||
|
UFUNCTION(BlueprintCallable, BlueprintCosmetic, Category = "UI Extension")
|
||
|
void UnregisterExtensionPoint(const FUIExtensionPointHandle& ExtensionPointHandle);
|
||
|
|
||
|
static void AddReferencedObjects(UObject* InThis, FReferenceCollector& Collector);
|
||
|
|
||
|
protected:
|
||
|
virtual void Initialize(FSubsystemCollectionBase& Collection) override;
|
||
|
virtual void Deinitialize() override;
|
||
|
|
||
|
void NotifyExtensionPointOfExtensions(TSharedPtr<FUIExtensionPoint>& ExtensionPoint);
|
||
|
void NotifyExtensionPointsOfExtension(EUIExtensionAction Action, TSharedPtr<FUIExtension>& Extension);
|
||
|
|
||
|
UFUNCTION(BlueprintCallable, BlueprintCosmetic, Category="UI Extension", meta = (DisplayName = "Register Extension Point"))
|
||
|
FUIExtensionPointHandle K2_RegisterExtensionPoint(FGameplayTag ExtensionPointTag, EUIExtensionPointMatch ExtensionPointTagMatchType, const TArray<UClass*>& AllowedDataClasses, FExtendExtensionPointDynamicDelegate ExtensionCallback);
|
||
|
|
||
|
UFUNCTION(BlueprintCallable, BlueprintCosmetic, Category = "UI Extension", meta = (DisplayName = "Register Extension (Widget)"))
|
||
|
FUIExtensionHandle K2_RegisterExtensionAsWidget(FGameplayTag ExtensionPointTag, TSubclassOf<UUserWidget> WidgetClass, int32 Priority = -1);
|
||
|
|
||
|
/**
|
||
|
* Registers the widget (as data) for a specific player. This means the extension points will receive a UIExtensionForPlayer data object
|
||
|
* that they can look at to determine if it's for whatever they consider their player.
|
||
|
*/
|
||
|
UFUNCTION(BlueprintCallable, BlueprintCosmetic, Category = "UI Extension", meta = (DisplayName = "Register Extension (Widget For Context)"))
|
||
|
FUIExtensionHandle K2_RegisterExtensionAsWidgetForContext(FGameplayTag ExtensionPointTag, TSubclassOf<UUserWidget> WidgetClass, UObject* ContextObject, int32 Priority = -1);
|
||
|
|
||
|
/**
|
||
|
* Registers the extension as data for any extension point that can make use of it.
|
||
|
*/
|
||
|
UFUNCTION(BlueprintCallable, BlueprintCosmetic, Category="UI Extension", meta = (DisplayName = "Register Extension (Data)"))
|
||
|
FUIExtensionHandle K2_RegisterExtensionAsData(FGameplayTag ExtensionPointTag, UObject* Data, int32 Priority = -1);
|
||
|
|
||
|
/**
|
||
|
* Registers the extension as data for any extension point that can make use of it.
|
||
|
*/
|
||
|
UFUNCTION(BlueprintCallable, BlueprintCosmetic, Category="UI Extension", meta = (DisplayName = "Register Extension (Data For Context)"))
|
||
|
FUIExtensionHandle K2_RegisterExtensionAsDataForContext(FGameplayTag ExtensionPointTag, UObject* ContextObject, UObject* Data, int32 Priority = -1);
|
||
|
|
||
|
FUIExtensionRequest CreateExtensionRequest(const TSharedPtr<FUIExtension>& Extension);
|
||
|
|
||
|
private:
|
||
|
typedef TArray<TSharedPtr<FUIExtensionPoint>> FExtensionPointList;
|
||
|
TMap<FGameplayTag, FExtensionPointList> ExtensionPointMap;
|
||
|
|
||
|
typedef TArray<TSharedPtr<FUIExtension>> FExtensionList;
|
||
|
TMap<FGameplayTag, FExtensionList> ExtensionMap;
|
||
|
};
|
||
|
|
||
|
|
||
|
UCLASS()
|
||
|
class UIEXTENSION_API UUIExtensionHandleFunctions : public UBlueprintFunctionLibrary
|
||
|
{
|
||
|
GENERATED_BODY()
|
||
|
|
||
|
public:
|
||
|
UUIExtensionHandleFunctions() { }
|
||
|
|
||
|
UFUNCTION(BlueprintCallable, BlueprintCosmetic, Category = "UI Extension")
|
||
|
static void Unregister(UPARAM(ref) FUIExtensionHandle& Handle);
|
||
|
|
||
|
UFUNCTION(BlueprintCallable, BlueprintCosmetic, Category = "UI Extension")
|
||
|
static bool IsValid(UPARAM(ref) FUIExtensionHandle& Handle);
|
||
|
};
|
||
|
|
||
|
UCLASS()
|
||
|
class UIEXTENSION_API UUIExtensionPointHandleFunctions : public UBlueprintFunctionLibrary
|
||
|
{
|
||
|
GENERATED_BODY()
|
||
|
|
||
|
public:
|
||
|
UUIExtensionPointHandleFunctions() { }
|
||
|
|
||
|
UFUNCTION(BlueprintCallable, BlueprintCosmetic, Category = "UI Extension")
|
||
|
static void Unregister(UPARAM(ref) FUIExtensionPointHandle& Handle);
|
||
|
|
||
|
UFUNCTION(BlueprintCallable, BlueprintCosmetic, Category = "UI Extension")
|
||
|
static bool IsValid(UPARAM(ref) FUIExtensionPointHandle& Handle);
|
||
|
};
|