RealtimeStyleTransferRuntime/Plugins/UIExtension/Source/Public/UIExtensionSystem.h

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