Files
UnrealEngine/Engine/Source/Editor/BlueprintGraph/Public/BlueprintActionDatabase.h
2025-05-18 13:04:45 +08:00

279 lines
9.7 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "Containers/Array.h"
#include "Containers/Map.h"
#include "Containers/UnrealString.h"
#include "CoreMinimal.h"
#include "Delegates/Delegate.h"
#include "HAL/Platform.h"
#include "HAL/PlatformCrt.h"
#include "Misc/NamePermissionList.h"
#include "Stats/Stats.h"
#include "Tickable.h"
#include "TickableEditorObject.h"
#include "UObject/GCObject.h"
#include "UObject/NameTypes.h"
#include "UObject/Object.h"
#include "UObject/ObjectKey.h"
#include "UObject/SoftObjectPath.h"
#include "UObject/TopLevelAssetPath.h"
class FBlueprintActionDatabaseRegistrar;
class FReferenceCollector;
class UBlueprint;
class UBlueprintNodeSpawner;
class UClass;
class UEnum;
class UField;
class UFunction;
class UObject;
class UScriptStruct;
struct FEdGraphPinType;
/**
* Serves as a container for all available blueprint actions (no matter the
* type of blueprint/graph they belong in). The actions stored here are not tied
* to a specific ui menu; each action is a UBlueprintNodeSpawner which is
* charged with spawning a specific node type. Should be set up in a way where
* class specific actions are refreshed when the associated class is regenerated.
*
* @TODO: Hook up to handle class recompile events, along with enum/struct asset creation events.
*/
class BLUEPRINTGRAPH_API FBlueprintActionDatabase : public FGCObject, public FTickableEditorObject
{
public:
DECLARE_MULTICAST_DELEGATE_OneParam(FOnDatabaseEntryUpdated, UObject*);
typedef TMap<FObjectKey, int32> FPrimingQueue;
typedef TArray<TObjectPtr<UBlueprintNodeSpawner>> FActionList;
typedef TMap<FObjectKey, FActionList> FActionRegistry;
typedef TMap<FSoftObjectPath, FActionList> FUnloadedActionRegistry;
public:
/** Destructor */
virtual ~FBlueprintActionDatabase();
/**
* Getter to access the database singleton. Will populate the database first
* if this is the first time accessing it.
*
* @return The singleton instance of FBlueprintActionDatabase.
*/
static FBlueprintActionDatabase& Get();
/** Getter to access the datbase singleton, will return null if the database has not been initialized */
static FBlueprintActionDatabase* TryGet();
// FTickableEditorObject interface
virtual void Tick(float DeltaTime) override;
virtual ETickableTickType GetTickableTickType() const override { return ETickableTickType::Always; }
virtual TStatId GetStatId() const override;
// End FTickableEditorObject interface
// FGCObject interface
virtual void AddReferencedObjects(FReferenceCollector& Collector) override;
virtual FString GetReferencerName() const override;
// End FGCObject interface
/**
* Will populate the database first if it hasn't been created yet, and then
* returns it in its entirety.
*
* Each node spawner is categorized by a class orasset. A spawner that
* corresponds to a specific class field (like a function, property, enum,
* etc.) will be listed under that field's class owner. Remaining spawners
* that can't be categorized this way will be registered by asset or node
* type.
*
* @return The entire action database, which maps specific objects to arrays of associated node-spawners.
*/
FActionRegistry const& GetAllActions();
/**
* Populates the action database from scratch. Loops over every known class
* and records a set of node-spawners associated with each.
*/
void RefreshAll();
/**
* Populates the action database with all level script actions from all active editor worlds.
*/
void RefreshWorlds();
/**
* Removes the entry with the given key on the next tick.
*/
void DeferredRemoveEntry(FObjectKey const& InKey);
/**
* Finds the database entry for the specified class and wipes it,
* repopulating it with a fresh set of associated node-spawners.
*
* @param Class The class entry you want rebuilt.
*/
void RefreshClassActions(UClass* const Class);
/**
* Finds the database entry for the specified asset and wipes it,
* repopulating it with a fresh set of associated node-spawners.
*
* @param AssetObject The asset entry you want rebuilt.
*/
void RefreshAssetActions(UObject* const AssetObject);
/**
* Updates all component related actions
*/
void RefreshComponentActions();
/**
* Finds the database entry for the specified object and wipes it. The entry
* won't be rebuilt, unless RefreshAssetActions() is explicitly called after.
*
* @param AssetObject
* @return True if an entry was found and removed.
*/
bool ClearAssetActions(UObject* const AssetObject);
/**
* Finds the database entry for the specified object and wipes it. The entry
* won't be rebuilt, unless RefreshAssetActions() is explicitly called after.
*
* @param AssetObjectKey
* @return True if an entry was found and removed.
*/
bool ClearAssetActions(const FObjectKey& AssetObjectKey);
/**
* Finds the database entry for the specified unloaded asset and wipes it.
* The entry won't be rebuilt, unless RefreshAssetActions() is explicitly called after.
*
* @param ObjectPath Object's path to lookup into the database
*/
void ClearUnloadedAssetActions(const FSoftObjectPath& ObjectPath);
/**
* Moves the unloaded asset actions from one location to another
*
* @param SourceObjectPath The object path that the data can currently be found under
* @param TargetObjectPath The object path that the data should be moved to
*/
void MoveUnloadedAssetActions(const FSoftObjectPath& SourceObjectPath, const FSoftObjectPath& TargetObjectPath);
/** */
FOnDatabaseEntryUpdated& OnEntryUpdated() { return EntryRefreshDelegate; }
/** */
FOnDatabaseEntryUpdated& OnEntryRemoved() { return EntryRemovedDelegate; }
/**
* Field visibility is different depending on context, this enum differentiates between the different
* contexts that fields can be present in
*/
enum class EPermissionsContext
{
/** A property on a class - from a user perspective a variable in the My Blueprint tab */
Property,
/** An asset - e.g. an anim blueprint asset player or skeleton notify */
Asset,
/** A K2 node in a graph - e.g. a function call */
Node,
/** An exposed pin on a K2 node */
Pin
};
/** Check whether the global filter applies to this class */
static bool IsClassAllowed(UClass const* InClass, EPermissionsContext InContext);
static bool IsClassAllowed(const FTopLevelAssetPath& InClassPath, EPermissionsContext InContext);
/** Check whether we have any class filtering applied */
static bool HasClassFiltering();
/** Check whether permissions allow this field */
static bool IsFieldAllowed(UField const* InField, EPermissionsContext InContext);
/** Check whether permissions allow this function */
static bool IsFunctionAllowed(UFunction const* InFunction, EPermissionsContext InContext);
/** Check whether permissions allow this enum */
static bool IsEnumAllowed(UEnum const* InEnum, EPermissionsContext InContext);
static bool IsEnumAllowed(const FTopLevelAssetPath& InEnumPath, EPermissionsContext InContext);
/** Check whether permissions allow this struct */
static bool IsStructAllowed(UScriptStruct const* InStruct, EPermissionsContext InContext);
static bool IsStructAllowed(const FTopLevelAssetPath& InStructPath, EPermissionsContext InContext);
/** Check whether permissions allow this pin type. InUnloadedAssetPath will be used in the case where a InPinType.PinSubCategoryObject is unable to be resolved. */
static bool IsPinTypeAllowed(const FEdGraphPinType& InPinType, const FTopLevelAssetPath& InUnloadedAssetPath = FTopLevelAssetPath());
private:
/** Private constructor for singleton purposes. */
FBlueprintActionDatabase();
void Init();
/**
*
*
* @param Registrar
*/
void RegisterAllNodeActions(FBlueprintActionDatabaseRegistrar& Registrar);
/**
* This exists only because we need a pointer to associate our delegates with
*/
void OnBlueprintChanged( UBlueprint* );
/** Refresh other systems before a full or partial refresh */
void PreRefresh(bool bRefreshAll);
private:
/**
* A map of associated node-spawners for each class/asset. A spawner that
* corresponds to a specific class field (like a function, property, enum,
* etc.) will be mapped under that field's class outer. Other spawners (that
* can't be associated with a class outer), will be filed under the desired
* node's type, or an associated asset.
*/
FActionRegistry ActionRegistry;
/**
* A map of associated object paths for each node-class that is associated
* with it. This is used for unloaded assets that will need to be replaced
* after the asset is loaded with the final (and more complete) nodespawner.
*/
FUnloadedActionRegistry UnloadedActionRegistry;
/**
* References newly allocated actions that need to be "primed". Priming is
* something we do on Tick() aimed at speeding up performance (like pre-
* caching each spawner's template-node, etc.).
*/
FPrimingQueue ActionPrimingQueue;
/** List of action keys to be removed on the next tick. */
TArray<FObjectKey> ActionRemoveQueue;
/** */
FOnDatabaseEntryUpdated EntryRefreshDelegate;
FOnDatabaseEntryUpdated EntryRemovedDelegate;
/** Handles to registered delegates. */
FDelegateHandle OnAssetLoadedDelegateHandle;
FDelegateHandle OnAssetAddedDelegateHandle;
FDelegateHandle OnAssetRemovedDelegateHandle;
FDelegateHandle OnAssetRenamedDelegateHandle;
FDelegateHandle OnAssetsPreDeleteDelegateHandle;
FDelegateHandle OnBlueprintUnloadedDelegateHandle;
FDelegateHandle OnWorldAddedDelegateHandle;
FDelegateHandle OnWorldDestroyedDelegateHandle;
FDelegateHandle RefreshLevelScriptActionsDelegateHandle;
FDelegateHandle OnModulesChangedDelegateHandle;
FDelegateHandle OnReloadCompleteDelegateHandle;
/** Pointer to the shared list of currently existing component types */
const TArray<struct FComponentTypeEntry>* ComponentTypes;
};