// Copyright Epic Games, Inc. All Rights Reserved. #pragma once #include "Containers/Array.h" #include "Containers/Map.h" #include "Containers/Queue.h" #include "Containers/Set.h" #include "Containers/UnrealString.h" #include "CoreMinimal.h" #include "Delegates/Delegate.h" #include "Dom/JsonObject.h" #include "Engine/Blueprint.h" #include "HAL/CriticalSection.h" #include "HAL/Platform.h" #include "HAL/PlatformCrt.h" #include "HAL/Runnable.h" #include "HAL/RunnableThread.h" #include "HAL/ThreadSafeCounter.h" #include "Input/Reply.h" #include "Internationalization/Text.h" #include "Logging/LogMacros.h" #include "Misc/EnumClassFlags.h" #include "ProfilingDebugging/CsvProfiler.h" #include "SlateFwd.h" #include "Stats/Stats.h" #include "Templates/Atomic.h" #include "Templates/SharedPointer.h" #include "Templates/UniquePtr.h" #include "TickableEditorObject.h" #include "Types/WidgetActiveTimerDelegate.h" #include "UObject/NameTypes.h" #include "UObject/ObjectMacros.h" #include "UObject/UObjectGlobals.h" #include "UObject/UnrealNames.h" #include "UObject/WeakObjectPtr.h" #include "UObject/WeakObjectPtrTemplates.h" #include "FindInBlueprintManager.generated.h" class FArchive; class SDockTab; class SWidget; class UBlueprint; class UClass; class UObject; struct FTopLevelAssetPath; DECLARE_LOG_CATEGORY_EXTERN(LogFindInBlueprint, Warning, All); /** CSV stats profiling category */ CSV_DECLARE_CATEGORY_EXTERN(FindInBlueprint); class FFindInBlueprintsResult; class FImaginaryBlueprint; class FImaginaryFiBData; class FSpawnTabArgs; class SFindInBlueprints; struct FAssetData; // Shared pointers to cached imaginary data (must be declared as thread-safe). typedef TWeakPtr FImaginaryFiBDataWeakPtr; typedef TSharedPtr FImaginaryFiBDataSharedPtr; #define MAX_GLOBAL_FIND_RESULTS 4 /** *Const values for Find-in-Blueprints to tag searchable data */ struct KISMET_API FFindInBlueprintSearchTags { /** Properties tag, for Blueprint variables */ static const FText FiB_Properties; /** Components tags */ static const FText FiB_Components; static const FText FiB_IsSCSComponent; /** End Components tags */ /** Nodes tag */ static const FText FiB_Nodes; /** Schema Name tag, to identify the schema that a graph uses */ static const FText FiB_SchemaName; /** Uber graphs tag */ static const FText FiB_UberGraphs; /** Function graph tag */ static const FText FiB_Functions; /** Macro graph tag */ static const FText FiB_Macros; /** Sub graph tag, for any sub-graphs in a Blueprint */ static const FText FiB_SubGraphs; /** Extension graph tag, for any graphs in a Blueprint Extension */ static const FText FiB_ExtensionGraphs; /** Blueprint extension tag. */ static const FText FiB_Extensions; /** Name tag */ static const FText FiB_Name; /** Native Name tag */ static const FText FiB_NativeName; /** Class Name tag */ static const FText FiB_ClassName; /** NodeGuid tag */ static const FText FiB_NodeGuid; /** Default value */ static const FText FiB_DefaultValue; /** Tooltip tag */ static const FText FiB_Tooltip; /** Description tag */ static const FText FiB_Description; /** Comment tag */ static const FText FiB_Comment; /** Path tag */ static const FText FiB_Path; /** Parent Class tag */ static const FText FiB_ParentClass; /** Interfaces tag */ static const FText FiB_Interfaces; /** Class that originally defined the function tag */ static const FText FiB_FuncOriginClass; /** Pin type tags */ /** Pins tag */ static const FText FiB_Pins; /** Pin Category tag */ static const FText FiB_PinCategory; /** Pin Sub-Category tag */ static const FText FiB_PinSubCategory; /** Pin object class tag */ static const FText FiB_ObjectClass; /** Pin IsArray tag */ static const FText FiB_IsArray; /** Pin IsReference tag */ static const FText FiB_IsReference; /** Glyph icon tag */ static const FText FiB_Glyph; /** Style set the glyph belongs to */ static const FText FiB_GlyphStyleSet; /** Glyph icon color tag */ static const FText FiB_GlyphColor; // Identifier for metadata storage, completely unsearchable tag static const FText FiBMetaDataTag; /** End const values for Find-in-Blueprint */ }; /** FiB data versioning */ UENUM() enum EFiBVersion : int { FIB_VER_NONE = -1, // Unknown version (not set) FIB_VER_BASE = 0, // All Blueprints prior to versioning will automatically be assumed to be at 0 if they have FiB data collected FIB_VER_VARIABLE_REFERENCE, // Variable references (FMemberReference) is collected in FiB FIB_VER_INTERFACE_GRAPHS, // Implemented Interface Graphs is collected in FiB FIB_VER_FUNC_CALL_SITES, // Hidden target pins and function origin class are collected in FiB for improved function call site searchability // ------------------------------------------------------ FIB_VER_PLUS_ONE, FIB_VER_LATEST = FIB_VER_PLUS_ONE - 1 // Always the last version, we want Blueprints to be at latest }; /** Consolidated version info for a Blueprint search data entry */ struct FSearchDataVersionInfo { /** FiB asset registry tag data version */ int32 FiBDataVersion = EFiBVersion::FIB_VER_NONE; /** Editor object version used to serialize values in the JSON string lookup table */ int32 EditorObjectVersion = -1; /** Current version info */ static FSearchDataVersionInfo Current; }; /** State flags for search database entries */ enum class ESearchDataStateFlags : uint8 { None = 0, /** Set when this search database entry has been fully indexed, which is completed asynchronously */ IsIndexed = 1 << 0, /** Cached to determine if the Blueprint is seen as no longer valid, allows it to be cleared out next save to disk */ WasRemoved = 1 << 1, }; ENUM_CLASS_FLAGS(ESearchDataStateFlags); /** Tracks data relevant to a Blueprint for searches */ struct FSearchData { /** The Blueprint this search data points to, if available */ TWeakObjectPtr Blueprint; /** The full asset path this search data is associated with of the form /Game/Path/To/Package.Package */ FSoftObjectPath AssetPath; /** Encoded search data block for the Blueprint, this will not always be set if it's already been parsed */ FString Value; /** Key to use to look up the encoded search data from an FAssetData, if this is set Value will probably be empty */ FName AssetKeyForValue; /** Parent Class */ FString ParentClass; /** Interfaces implemented by the Blueprint */ TArray Interfaces; /** Cached ImaginaryBlueprint data for the searchable content, prevents having to re-parse every search */ FImaginaryFiBDataSharedPtr ImaginaryBlueprint; /** Data versioning */ FSearchDataVersionInfo VersionInfo; /** State flags (see enum) */ ESearchDataStateFlags StateFlags; FSearchData() : Blueprint(nullptr) , StateFlags(ESearchDataStateFlags::None) { } /** True if this represents a valid asset */ bool IsValid() const { return !AssetPath.IsNull(); } /** True if this has an encoded value that has yet to be parsed */ bool HasEncodedValue() const { return !Value.IsEmpty() || !AssetKeyForValue.IsNone(); } /** Clear the encoded value after parsing or getting new data */ void ClearEncodedValue() { Value.Reset(); AssetKeyForValue = NAME_None; } bool IsIndexingCompleted() const { return EnumHasAllFlags(StateFlags, ESearchDataStateFlags::IsIndexed); } bool IsMarkedForDeletion() const { return EnumHasAllFlags(StateFlags, ESearchDataStateFlags::WasRemoved); } }; /** Filters are used by functions for searching to decide whether items can call certain functions or match the requirements of a function */ enum ESearchQueryFilter { BlueprintFilter = 0, GraphsFilter, UberGraphsFilter, FunctionsFilter, MacrosFilter, NodesFilter, PinsFilter, PropertiesFilter, VariablesFilter, ComponentsFilter, AllFilter, // Will search all items, when used inside of another filter it will search all sub-items of that filter }; /** Used for external gather functions to add Key/Value pairs to be placed into Json */ struct FSearchTagDataPair { FSearchTagDataPair(FText InKey, FText InValue) : Key(InKey) , Value(InValue) {} FText Key; FText Value; }; struct KISMET_API FFiBMD { static const FString FiBSearchableMD; static const FString FiBSearchableShallowMD; static const FString FiBSearchableExplicitMD; static const FString FiBSearchableHiddenExplicitMD; static const FString FiBSearchableFormatVersionMD; }; /** Which assets to index for caching */ enum class EFiBCacheOpType { CachePendingAssets, CacheUnindexedAssets }; /** Flags to control the UX while caching */ enum class EFiBCacheOpFlags { None = 0, /** Whether to show progress */ ShowProgress = 1 << 0, /** Whether to hide toast popups */ HideNotifications = 1 << 1, /** Whether to allow users to cancel */ AllowUserCancel = 1 << 2, /** Set if the user wants to check out and save (applies to unindexed caching only) */ CheckOutAndSave = 1 << 3, /** Whether to hide progress bar widgets */ HideProgressBars = 1 << 4, /** Whether to allow users to hide/close progress */ AllowUserCloseProgress = 1 << 5, /** Set if we are caching assets from the discovery stage */ IsCachingDiscoveredAssets = 1 << 6, /** Whether to keep progress visible on completion */ KeepProgressVisibleOnCompletion = 1 << 7, /** Index deferred assets on the main thread only (used for debugging) */ ExecuteOnMainThread = 1 << 8, /** Don't index multiple assets in parallel (used to assist with profiling) */ ExecuteOnSingleThread = 1 << 9, /** Only execute the gather phase (used to help minimize memory usage on editor/tab open) */ ExecuteGatherPhaseOnly = 1 << 10, }; ENUM_CLASS_FLAGS(EFiBCacheOpFlags); /** Options to configure the bulk caching task */ struct KISMET_API FFindInBlueprintCachingOptions { /** Type of caching operation */ EFiBCacheOpType OpType = EFiBCacheOpType::CachePendingAssets; /** Initial set of control flags */ EFiBCacheOpFlags OpFlags = EFiBCacheOpFlags::None; /** Callback for when caching is finished */ FSimpleDelegate OnFinished; /** Minimum version requirement for caching, any Blueprints below this version will be re-indexed */ EFiBVersion MinimiumVersionRequirement = EFiBVersion::FIB_VER_LATEST; }; /** Options for FFindInBlueprintSearchManager::AddOrUpdateBlueprintSearchMetadata() */ enum class EAddOrUpdateBlueprintSearchMetadataFlags { None = 0, /** Forces the Blueprint to be recache'd, regardless of what data it believes exists */ ForceRecache = 1 << 0, /** Clear any cached data value for this Blueprint */ ClearCachedValue = 1 << 1, }; ENUM_CLASS_FLAGS(EAddOrUpdateBlueprintSearchMetadataFlags); //////////////////////////////////// // FFindInBlueprintsResult /* Item that matched the search results */ class KISMET_API FFindInBlueprintsResult : public TSharedFromThis< FFindInBlueprintsResult > { public: FFindInBlueprintsResult() = default; virtual ~FFindInBlueprintsResult() = default; /* Create a root */ explicit FFindInBlueprintsResult(const FText& InDisplayText); /* Called when user clicks on the search item */ virtual FReply OnClick(); /* Get Category for this search result */ virtual FText GetCategory() const; /* Create an icon to represent the result */ virtual TSharedRef CreateIcon() const; /** Finalizes any content for the search data that was unsafe to do on a separate thread */ virtual void FinalizeSearchData() {}; /* Gets the comment on this node if any */ FString GetCommentText() const; /** gets the blueprint housing all these search results */ UBlueprint* GetParentBlueprint() const; /** * Parses search info for specific data important for displaying the search result in an easy to understand format * * @param InTokens The search tokens to check results against * @param InKey This is the tag for the data, describing what it is so special handling can occur if needed * @param InValue Compared against search query to see if it passes the filter, sometimes data is rejected because it is deemed unsearchable * @param InParent The parent search result */ virtual void ParseSearchInfo(FText InKey, FText InValue) {}; /** Returns the Object represented by this search information give the Blueprint it can be found in */ virtual UObject* GetObject(UBlueprint* InBlueprint) const; /** Returns the display string for the row */ FText GetDisplayString() const; public: /*Any children listed under this category */ TArray< TSharedPtr > Children; /*If it exists it is the blueprint*/ TWeakPtr Parent; /*The display text for this item */ FText DisplayText; /** Display text for comment information */ FString CommentText; }; typedef TSharedPtr FSearchResult; //////////////////////////////////// // FStreamSearch struct KISMET_API FStreamSearchOptions { /** Filter to limit the FilteredImaginaryResults to */ enum ESearchQueryFilter ImaginaryDataFilter; /** When searching, any Blueprint below this version will be considered out-of-date */ EFiBVersion MinimiumVersionRequirement; /** Default constructor. */ FStreamSearchOptions() :ImaginaryDataFilter(ESearchQueryFilter::AllFilter) ,MinimiumVersionRequirement(EFiBVersion::FIB_VER_LATEST) { } }; /** * Async task for searching Blueprints */ class KISMET_API FStreamSearch : public FRunnable { public: /** Constructor */ FStreamSearch(const FString& InSearchValue, const FStreamSearchOptions& InSearchOptions = FStreamSearchOptions()); /** Begin FRunnable Interface */ virtual bool Init() override; virtual uint32 Run() override; virtual void Stop() override; virtual void Exit() override; /** End FRunnable Interface */ /** Brings the thread to a safe stop before continuing. */ void EnsureCompletion(); /** Returns TRUE if the thread is done with it's work. */ bool IsComplete() const; /** Returns TRUE if Stop() was called while work is still pending. */ bool WasStopped() const; /** * Appends the items filtered through the search filter to the passed array * * @param OutItemsFound All the items found since last queried */ void GetFilteredItems(TArray>& OutItemsFound); /** Helper function to query the percent complete this search is */ float GetPercentComplete() const; /** Returns the Out-of-Date Blueprint count */ int32 GetOutOfDateCount() const { return BlueprintCountBelowVersion; } /** Returns the FilteredImaginaryResults from the search query, these results have been filtered by the ImaginaryDataFilter. */ void GetFilteredImaginaryResults(TArray& OutFilteredImaginaryResults); public: /** Thread to run the cleanup FRunnable on */ TUniquePtr Thread; /** A list of items found, cleared whenever the main thread pulls them to display to screen */ TArray> ItemsFound; /** The search value to filter results by */ FString SearchValue; /** Options for setting up the search */ FStreamSearchOptions SearchOptions; /** Prevents searching while other threads are pulling search results */ FCriticalSection SearchCriticalSection; /** Filtered (ImaginaryDataFilter) list of imaginary data results that met the search requirements. Must be declared as thread-safe since imaginary data is a shared resource. */ TArray FilteredImaginaryResults; /** A going count of all Blueprints below the MinimiumVersionRequirement */ int32 BlueprintCountBelowVersion; // Whether the thread has finished running bool bThreadCompleted; private: /** Unique identifier for this search (used with benchmarking) */ int32 SearchId; /** > 0 if we've been asked to abort work in progress at the next opportunity */ FThreadSafeCounter StopTaskCounter; }; //////////////////////////////////// // FFindInBlueprintSearchManager /** Singleton manager for handling all Blueprint searches, helps to manage the going progress of Blueprints, and is thread-safe. */ class KISMET_API FFindInBlueprintSearchManager : public FTickableEditorObject { public: static FFindInBlueprintSearchManager* Instance; static FFindInBlueprintSearchManager& Get(); FFindInBlueprintSearchManager(); ~FFindInBlueprintSearchManager(); //~ Begin FTickableObject Interface virtual void Tick(float DeltaTime) override; virtual bool IsTickable() const override; virtual TStatId GetStatId() const override; //~ End FTickableObject Interface /** * Applies the given search data to a matching entry in the database. Optionally adds a new entry if a match is not found. * * @param InSearchData Search data to be applied * @param bAllowNewEntry Whether to allow a new entry to be added if a match is not found */ void ApplySearchDataToDatabase(FSearchData InSearchData, bool bAllowNewEntry = false); /** * Given an asset path, locate and return a copy of its matching search data in the index cache. * * @param InAssetPath Asset path (search index key). * @return Matching search data from the index cache. Will return invalid (empty) search data if a matching entry was not found. */ FSearchData GetSearchDataForAssetPath(const FSoftObjectPath& InAssetPath); /** * Gathers the Blueprint's search metadata and adds or updates it in the cache * * @param InBlueprint Blueprint to cache the searchable data for * @param InFlags Flags to assist with controlling this function's behavior * @param InVersion Allows the caller to override the format version to use for caching */ void AddOrUpdateBlueprintSearchMetadata(UBlueprint* InBlueprint, EAddOrUpdateBlueprintSearchMetadataFlags InFlags = EAddOrUpdateBlueprintSearchMetadataFlags::None, EFiBVersion InVersion = EFiBVersion::FIB_VER_NONE); /** * Starts a search query, the FiB manager handles where the thread is at in the search query at all times so that post-save of the cache to disk it can correct the index * * @param InSearchOriginator Pointer to the thread object that the query originates from */ void BeginSearchQuery(const class FStreamSearch* InSearchOriginator); /** * Continues a search query, returning a single piece of search data * * @param InSearchOriginator Pointer to the thread object that the query originates from * @param OutSearchData Result of the search, if there is any Blueprint search data still available to query * @return TRUE if the search was successful, FALSE if the search is complete */ bool ContinueSearchQuery(const class FStreamSearch* InSearchOriginator, FSearchData& OutSearchData); /** * This function ensures that the passed in search query ends in a safe manner. The search will no longer be valid to this manager, though it does not destroy any objects. * Use this whenever the search is finished or canceled. * * @param InSearchOriginator Identifying search stream to be stopped */ void EnsureSearchQueryEnds(const class FStreamSearch* InSearchOriginator); /** * Query how far along a search thread is * * @param OutSearchData Result of the search, if there is any Blueprint search data still available to query * @return Percent along the search thread is */ float GetPercentComplete(const class FStreamSearch* InSearchOriginator) const; /** * Query for a single, specific Blueprint's search data. * * @param InBlueprint The Blueprint to search for * @param bInRebuildSearchData When TRUE the search data will be freshly collected * @return The search data, or invalid (empty) search data if not found */ FSearchData QuerySingleBlueprint(UBlueprint* InBlueprint, bool bInRebuildSearchData); /** Processes the encoded string value in the SearchData into the intermediate format, return true if string and version were valid */ bool ProcessEncodedValueForUnloadedBlueprint(FSearchData& SearchData); /** Returns the number of unindexed Blueprints, either due to not having been indexed before, or AR data being out-of-date */ int32 GetNumberUnindexedAssets() const; /** Returns the number of uncached assets during an active indexing operation */ int32 GetNumberUncachedAssets() const; /** * Starts a task to cache Blueprints at a rate of 1 per tick * * @param InSourceWidget The source FindInBlueprints widget, this widget will be informed when caching is complete * @param InCachingOptions Options to configure the caching task */ void CacheAllAssets(TWeakPtr< class SFindInBlueprints > InSourceWidget, const FFindInBlueprintCachingOptions& InCachingOptions); /** * Exports a list of all unindexed assets to Saved/FindInBlueprints_OutdatedAssetList.txt */ void ExportOutdatedAssetList(); /** * Starts the actual caching process * * @param bInSourceControlActive TRUE if source control is active * @param bInCheckoutAndSave TRUE if the system should checkout and save all assets that need to be reindexed */ void OnCacheAllUnindexedAssets(bool bInSourceControlActive, bool bInCheckoutAndSave); /** Stops the caching process where it currently is at, the rest can be continued later */ void CancelCacheAll(SFindInBlueprints* InFindInBlueprintWidget); /** Returns the current index in the caching */ int32 GetCurrentCacheIndex() const; /** Returns the path of the current Blueprint being cached */ FSoftObjectPath GetCurrentCacheBlueprintPath() const; /** Returns the progress complete on the caching */ float GetCacheProgress() const; /** Returns the list of Blueprint paths that failed to cache */ TSet GetFailedToCachePathList() const { return FailedToCachePaths; } /** Returns the number of Blueprints that failed to cache */ int32 GetFailedToCacheCount() const { return FailedToCachePaths.Num(); } /** Returns TRUE if caching failed */ bool HasCachingFailed() const { return FailedToCachePaths.Num() > 0; }; /** Callback to note that Blueprint caching is started */ void StartedCachingBlueprints(EFiBCacheOpType InCacheOpType, EFiBCacheOpFlags InCacheOpFlags); /** * Callback to note that Blueprint caching is complete * * @param InNumberCached The number of Blueprints cached, to be chopped off the existing array so the rest (if any) can be finished later */ void FinishedCachingBlueprints(EFiBCacheOpType InCacheOpType, EFiBCacheOpFlags InCacheOpFlags, int32 InNumberCached, TSet& InFailedToCacheList); /** Returns TRUE if Blueprints are being cached. */ bool IsCacheInProgress() const; /** Returns TRUE if unindexed Blueprints are being cached (since this can block the UI) */ bool IsUnindexedCacheInProgress() const; /** Returns TRUE if we're still inside the initial asset discovery and registration stage */ bool IsAssetDiscoveryInProgress() const; /** Returns TRUE if there are one or more active asynchronous search queries */ bool IsAsyncSearchQueryInProgress() const; /** Returns a weak reference to the widget that initiated the current caching operation */ TWeakPtr GetSourceCachingWidget() const { return SourceCachingWidget; } void EnableGatheringData(bool bInEnableGatheringData) { bEnableGatheringData = bInEnableGatheringData; } bool IsGatheringDataEnabled() const { return bEnableGatheringData; } /** If TRUE, the developer menu tool commands will be shown in the 'Developer' section of the Blueprint Editor's menu bar */ bool ShouldEnableDeveloperMenuTools() const { return bEnableDeveloperMenuTools; } /** If TRUE, search result meta will be gathered once and stored in a template. Avoids doing this work redundantly at search time. */ bool ShouldEnableSearchResultTemplates() const { return !bDisableSearchResultTemplates; } /** Find or create the global find results widget */ TSharedPtr GetGlobalFindResults(); /** Enable or disable the global find results tab feature */ void EnableGlobalFindResults(bool bEnable); /** Close any orphaned global find results tabs for a particular tab manager */ void CloseOrphanedGlobalFindResultsTabs(TSharedPtr TabManager); /** Returns true if a global find results tab is currently open */ bool IsGlobalFindResultsOpen() const { return GlobalFindResults.Num() > 0; } void GlobalFindResultsClosed(const TSharedRef& FindResults); /** Dumps the full index cache to the given stream (for debugging purposes) */ void DumpCache(FArchive& Ar); /** Randomly initiates a partial rebuild of the index cache (for debugging purposes) */ void DoRandomIndexCacheRebuild(); public: /** Converts a string of hex characters, previously converted by ConvertFTextToHexString, to an FText. */ static FText ConvertHexStringToFText(FString InHexString); /** Serializes an FText to memory and converts the memory into a string of hex characters */ static FString ConvertFTextToHexString(FText InValue); /** Given a fully constructed Find-in-Blueprint FString of searchable data, will parse and construct a JsonObject */ static TSharedPtr< class FJsonObject > ConvertJsonStringToObject(FSearchDataVersionInfo InVersionInfo, const FString& InJsonString, TMap& OutFTextLookupTable); /** Generates a human-readable search index for the given Blueprint (for debugging purposes) */ static FString GenerateSearchIndexForDebugging(UBlueprint* InBlueprint); private: /** Initializes the FiB manager */ void Initialize(); /** Callback hook during pre-garbage collection, pauses all processing searches so that the GC can do it's job */ void PauseFindInBlueprintSearch(); /** Callback hook during post-garbage collection, saves the cache to disk and unpauses all processing searches */ void UnpauseFindInBlueprintSearch(); /** Callback hook from the Asset Registry when an asset is added */ void OnAssetAdded(const struct FAssetData& InAssetData); /** Callback hook from the Asset Registry, marks the asset for deletion from the cache */ void OnAssetRemoved(const struct FAssetData& InAssetData); /** Callback hook from the Asset Registry, marks the asset for deletion from the cache */ void OnAssetRenamed(const struct FAssetData& InAssetData, const FString& InOldName); /** Callback hook from the Asset Registry, signals that the initial asset discovery stage has been completed */ void OnAssetRegistryFilesLoaded(); /** Callback hook from the Asset Registry when an asset is loaded */ void OnAssetLoaded(class UObject* InAsset); /** Callback from Kismet when a Blueprint is unloaded */ void OnBlueprintUnloaded(class UBlueprint* InBlueprint); /** Callback hook from the Reload manager that indicates that a module has been reloaded */ void OnReloadComplete(EReloadCompleteReason Reason); /** Returns a copy of the search data that's cached at the given index. Will return invalid (empty) search data if the index is out of range */ FSearchData GetSearchDataForIndex(int32 CacheIndex); /** Cleans the cache of any excess data from Blueprints that have been moved, renamed, or deleted. Occurs during post-garbage collection */ void CleanCache(); /** Builds the cache from all available Blueprint assets that the asset registry has discovered at the time of this function. Occurs on startup */ void BuildCache(); /** * Helper to properly add a Blueprint's SearchData to the database * * @param InSearchData Data to add to the database * @return Index into the SearchArray for looking up the added item */ int32 AddSearchDataToDatabase(FSearchData InSearchData); /** Removes a Blueprint from being managed by the FiB system by passing in the UBlueprint's path */ void RemoveBlueprintByPath(const FSoftObjectPath& InPath); /** Adds a new search database entry for unloaded asset data */ void AddUnloadedBlueprintSearchMetadata(const FAssetData& InAssetData); /** Begins the process of extracting FiB data from an unloaded asset */ void ExtractUnloadedFiBData(const FAssetData& InAssetData, FString* InFiBData, FName InKeyForFiBData, EFiBVersion InFiBDataVersion); /** Determines the global find results tab label */ FText GetGlobalFindResultsTabLabel(int32 TabIdx); /** Handler for a request to spawn a new global find results tab */ TSharedRef SpawnGlobalFindResultsTab(const FSpawnTabArgs& SpawnTabArgs, int32 TabIdx); /** Creates and opens a new global find results tab */ TSharedPtr OpenGlobalFindResultsTab(); protected: /** Contains info about an active search query */ struct FActiveSearchQuery { /** Current search array index */ TAtomic NextIndex; /** Current count of assets searched */ TAtomic SearchCount; /** Asset paths for which searching was deferred due to being indexed */ TQueue DeferredAssetPaths; FActiveSearchQuery() :NextIndex(0) ,SearchCount(0) { } }; typedef TSharedPtr FActiveSearchQueryPtr; /** Thread-safe access to the active search query that's mapped to the given stream search */ FActiveSearchQueryPtr FindSearchQuery(const class FStreamSearch* InSearchOriginator) const; /** Returns the next pending search data for the given query and advances the index to the next entry */ FSearchData GetNextSearchDataForQuery(const FStreamSearch* InSearchOriginator, FActiveSearchQueryPtr InSearchQueryPtr, bool bCheckDeferredList); /** If searches are paused, blocks the calling thread until searching is resumed */ void BlockSearchQueryIfPaused(); private: /** Maps the Blueprint paths to their index in the SearchArray */ TMap SearchMap; /** Stores the Blueprint search data and is used to iterate over in small chunks */ TArray SearchArray; /** Counter of active searches */ FThreadSafeCounter ActiveSearchCounter; /** A mapping of active search queries and where they are currently at in the search data */ TMap ActiveSearchQueries; /** Critical section to safely add, remove, and find data in ActiveSearchQueries */ mutable FCriticalSection SafeQueryModifyCriticalSection; /** Critical section to lock threads during the pausing procedure */ FCriticalSection PauseThreadsCriticalSection; /** Critical section to safely modify cached data */ FCriticalSection SafeModifyCacheCriticalSection; /** Because we are unable to query for the module on another thread, cache it for use later */ class FAssetRegistryModule* AssetRegistryModule; /** FindInBlueprints widget that started the cache process */ TWeakPtr SourceCachingWidget; /** Asset paths that were discovered, loaded or modified and now require indexing (or re-indexing) */ TSet PendingAssets; /** Asset paths that have not been cached for searching due to lack of FiB data, this means that they are either older Blueprints, or the DDC cannot find the data */ TSet UnindexedAssets; /** List of paths for Blueprints that failed to cache */ TSet FailedToCachePaths; /** List of paths that require a full index pass during the first global search */ TSet AssetsToIndexOnFirstSearch; /** Tickable object that does the caching of uncached Blueprints at a rate of once per tick */ TUniquePtr CachingObject; /** Stores the type of caching operation that's currently in progress */ EFiBCacheOpType CurrentCacheOpType; /** Mapping between a class name and its UClass instance - used for faster look up in FFindInBlueprintSearchManager::OnAssetAdded */ TMap> CachedAssetClasses; /** The tab identifier/instance name for global find results */ FName GlobalFindResultsTabIDs[MAX_GLOBAL_FIND_RESULTS]; /** Array of open global find results widgets */ TArray> GlobalFindResults; /** Global Find Results workspace menu item */ TSharedPtr GlobalFindResultsMenuItem; /** Size of a single async indexing task batch; zero or negative means that a caching operation will consist of a single batch */ int32 AsyncTaskBatchSize; /** TRUE when the the FiB manager wants to pause all searches, helps manage the pausing procedure */ TAtomic bIsPausing; /** Currently used to delay the full indexing pass until the first search in order to control memory usage */ TAtomic bHasFirstSearchOccurred; /** Tells if gathering data is currently allowed */ bool bEnableGatheringData; /** If true, search metadata will be regenerated for loaded assets on the main thread immediately at discovery or load time. By default, this work is deferred to avoid hitching. */ bool bDisableDeferredIndexing; /** If true, and if deferred indexing is not disabled, search metadata will be regenerated for loaded assets on the main thread at a rate of one asset per tick. Additional indexing work will be deferred to the search thread. By default, all indexing work is deferred to a background thread and both loaded and unloaded assets are fully indexed asynchronously. */ bool bDisableThreadedIndexing; /** Whether CSV profiling has been enabled (default=false) */ bool bEnableCSVStatsProfiling; /** Whether to enable Blueprint editor developer menu tools */ bool bEnableDeveloperMenuTools; /** Disable the use of search result templates. Setting this to TRUE will slightly decrease overall memory usage, but will also increase global search times */ bool bDisableSearchResultTemplates; /** Defers the cost to extract metadata for each discovered asset during the initial asset registry scan into a single pass over the full asset registry once the scan is complete. */ bool bDisableImmediateAssetDiscovery; }; struct KISMET_API FDisableGatheringDataOnScope { bool bOriginallyEnabled; FDisableGatheringDataOnScope() : bOriginallyEnabled(FFindInBlueprintSearchManager::Get().IsGatheringDataEnabled()) { FFindInBlueprintSearchManager::Get().EnableGatheringData(false); } ~FDisableGatheringDataOnScope() { FFindInBlueprintSearchManager::Get().EnableGatheringData(bOriginallyEnabled); } };