Repository: heyomidk/HardReferenceFinder Branch: master Commit: 2aacee46427c Files: 15 Total size: 51.5 KB Directory structure: gitextract_ra60czo9/ ├── .gitignore ├── HardReferenceFinder.uplugin ├── LICENSE ├── README.md └── Source/ └── HardReferenceFinder/ ├── HardReferenceFinder.Build.cs ├── Private/ │ ├── HardReferenceFinder.cpp │ ├── HardReferenceFinderSearchData.cpp │ ├── HardReferenceFinderStyle.cpp │ ├── HardReferenceFinderSummoner.cpp │ └── SHardReferenceFinderWindow.cpp └── Public/ ├── HardReferenceFinder.h ├── HardReferenceFinderSearchData.h ├── HardReferenceFinderStyle.h ├── HardReferenceFinderSummoner.h └── SHardReferenceFinderWindow.h ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ Binaries DerivedDataCache Intermediate Saved .vscode .vs *.VC.db *.opensdf *.opendb *.sdf *.sln *.suo *.xcodeproj *.xcworkspace .idea/ *.uproject.DotSettings.user Plugins/Developer/ Plugins/HoudiniEngine/ *_bak[0-9].hiplc *_bak[0-9][0-9].hiplc *_bak[0-9].hdalc *_bak[0-9][0-9].hdalc *.tga~ *.kra~ *.png~ *.blend1 .autosave/ *.resources/ Content/Asian_Village/maps/Asian_Village_Demo_BuiltData.uasset Content/Japanese_Temple/maps/Japanese_Temple_Demo_BuiltData.uasset Content/stylized_castle/maps/stylized_castle_demo_BuiltData.uasset Content/Underworld/Maps/Underworld_demo_BuiltData.uasset ================================================ FILE: HardReferenceFinder.uplugin ================================================ { "FileVersion": 3, "Version": 1, "VersionName": "0.4.0", "FriendlyName": "HardReferenceFinder", "Description": "Plugin that shows hard referencing nodes in a blueprint graph.", "Category": "Other", "CreatedBy": "Omid Kiarostami", "CreatedByURL": "", "DocsURL": "", "MarketplaceURL": "", "SupportURL": "", "CanContainContent": false, "IsBetaVersion": false, "IsExperimentalVersion": false, "Installed": false, "Modules": [ { "Name": "HardReferenceFinder", "Type": "Editor", "LoadingPhase": "PostEngineInit" } ] } ================================================ FILE: LICENSE ================================================ Creative Commons Legal Code CC0 1.0 Universal CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED HEREUNDER. Statement of Purpose The laws of most jurisdictions throughout the world automatically confer exclusive Copyright and Related Rights (defined below) upon the creator and subsequent owner(s) (each and all, an "owner") of an original work of authorship and/or a database (each, a "Work"). Certain owners wish to permanently relinquish those rights to a Work for the purpose of contributing to a commons of creative, cultural and scientific works ("Commons") that the public can reliably and without fear of later claims of infringement build upon, modify, incorporate in other works, reuse and redistribute as freely as possible in any form whatsoever and for any purposes, including without limitation commercial purposes. These owners may contribute to the Commons to promote the ideal of a free culture and the further production of creative, cultural and scientific works, or to gain reputation or greater distribution for their Work in part through the use and efforts of others. For these and/or other purposes and motivations, and without any expectation of additional consideration or compensation, the person associating CC0 with a Work (the "Affirmer"), to the extent that he or she is an owner of Copyright and Related Rights in the Work, voluntarily elects to apply CC0 to the Work and publicly distribute the Work under its terms, with knowledge of his or her Copyright and Related Rights in the Work and the meaning and intended legal effect of CC0 on those rights. 1. Copyright and Related Rights. A Work made available under CC0 may be protected by copyright and related or neighboring rights ("Copyright and Related Rights"). Copyright and Related Rights include, but are not limited to, the following: i. the right to reproduce, adapt, distribute, perform, display, communicate, and translate a Work; ii. moral rights retained by the original author(s) and/or performer(s); iii. publicity and privacy rights pertaining to a person's image or likeness depicted in a Work; iv. rights protecting against unfair competition in regards to a Work, subject to the limitations in paragraph 4(a), below; v. rights protecting the extraction, dissemination, use and reuse of data in a Work; vi. database rights (such as those arising under Directive 96/9/EC of the European Parliament and of the Council of 11 March 1996 on the legal protection of databases, and under any national implementation thereof, including any amended or successor version of such directive); and vii. other similar, equivalent or corresponding rights throughout the world based on applicable law or treaty, and any national implementations thereof. 2. Waiver. To the greatest extent permitted by, but not in contravention of, applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and unconditionally waives, abandons, and surrenders all of Affirmer's Copyright and Related Rights and associated claims and causes of action, whether now known or unknown (including existing as well as future claims and causes of action), in the Work (i) in all territories worldwide, (ii) for the maximum duration provided by applicable law or treaty (including future time extensions), (iii) in any current or future medium and for any number of copies, and (iv) for any purpose whatsoever, including without limitation commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each member of the public at large and to the detriment of Affirmer's heirs and successors, fully intending that such Waiver shall not be subject to revocation, rescission, cancellation, termination, or any other legal or equitable action to disrupt the quiet enjoyment of the Work by the public as contemplated by Affirmer's express Statement of Purpose. 3. Public License Fallback. Should any part of the Waiver for any reason be judged legally invalid or ineffective under applicable law, then the Waiver shall be preserved to the maximum extent permitted taking into account Affirmer's express Statement of Purpose. In addition, to the extent the Waiver is so judged Affirmer hereby grants to each affected person a royalty-free, non transferable, non sublicensable, non exclusive, irrevocable and unconditional license to exercise Affirmer's Copyright and Related Rights in the Work (i) in all territories worldwide, (ii) for the maximum duration provided by applicable law or treaty (including future time extensions), (iii) in any current or future medium and for any number of copies, and (iv) for any purpose whatsoever, including without limitation commercial, advertising or promotional purposes (the "License"). The License shall be deemed effective as of the date CC0 was applied by Affirmer to the Work. Should any part of the License for any reason be judged legally invalid or ineffective under applicable law, such partial invalidity or ineffectiveness shall not invalidate the remainder of the License, and in such case Affirmer hereby affirms that he or she will not (i) exercise any of his or her remaining Copyright and Related Rights in the Work or (ii) assert any associated claims and causes of action with respect to the Work, in either case contrary to Affirmer's express Statement of Purpose. 4. Limitations and Disclaimers. a. No trademark or patent rights held by Affirmer are waived, abandoned, surrendered, licensed or otherwise affected by this document. b. Affirmer offers the Work as-is and makes no representations or warranties of any kind concerning the Work, express, implied, statutory or otherwise, including without limitation warranties of title, merchantability, fitness for a particular purpose, non infringement, or the absence of latent or other defects, accuracy, or the present or absence of errors, whether or not discoverable, all to the greatest extent permissible under applicable law. c. Affirmer disclaims responsibility for clearing rights of other persons that may apply to the Work or any use thereof, including without limitation any person's Copyright and Related Rights in the Work. Further, Affirmer disclaims responsibility for obtaining any necessary consents, permissions or other rights required for any use of the Work. d. Affirmer understands and acknowledges that Creative Commons is not a party to this document and has no duty or obligation with respect to this CC0 or use of the Work. ================================================ FILE: README.md ================================================ # Hard Reference Finder An open-source editor plugin for Unreal Engine 5 that identifies hard references in a blueprint graph. The plugin allows you to summon a window which links to the various function calls, variables, graph pins, etc that are causing hard package references to other assets. Results are grouped by package and sorted by size, from largest to smallest. Compatible with Unreal Engine versions 5.3, 5.2, 5.1, 5.0 and 4.27. ![Image showing plugin usage in an example blueprint](Documentation/main-image.png) # Installation - Download the zip and unpack it (or clone this repository) to your projects *Plugins* folder. - Build the game with the plugin. - If necessary, enable the plugin from the plugins windows. # Usage Open any blueprint with a graph or function view, then select *Window -> Hard References* from the toolbar. ![Image showing how to summon the hard references viewport](Documentation/usage-guide.png) # Known Issues - After modifying a blueprint, you have to compile/save it before 'Refresh' will display the updated list of references. - Isn't identifying references from: - function arguments - properties nested in a struct - Note: This is still an initial version; the tool is unable to identify the source of some package references in a blueprint. Bug reports/pull requests/methods for detecting unidentified references are appreciated. ================================================ FILE: Source/HardReferenceFinder/HardReferenceFinder.Build.cs ================================================ // Copyright Epic Games, Inc. All Rights Reserved. using UnrealBuildTool; public class HardReferenceFinder : ModuleRules { public HardReferenceFinder(ReadOnlyTargetRules Target) : base(Target) { PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs; PublicIncludePaths.AddRange( new string[] { // ... add public include paths required here ... } ); PrivateIncludePaths.AddRange( new string[] { // ... add other private include paths required here ... } ); PublicDependencyModuleNames.AddRange( new string[] { "Core", // ... add other public dependencies that you statically link with here ... } ); PrivateDependencyModuleNames.AddRange( new string[] { "Projects", "InputCore", "UnrealEd", "ToolMenus", "CoreUObject", "Engine", "Slate", "SlateCore", "Kismet", "AssetRegistry", "BlueprintGraph", "AssetTools", } ); if (Target.Version.MajorVersion >= 5) { PrivateDependencyModuleNames.AddRange( new string[] { "SubobjectEditor", }); } if (Target.Version.MajorVersion < 5 || Target.Version.MajorVersion == 5 && Target.Version.MinorVersion < 1) { PrivateDependencyModuleNames.AddRange( new string[] { "EditorStyle", // only used in ("Kismet"); BlueprintEditorModule.OnRegisterTabsForEditor().AddRaw(this, &FHardReferenceFinderModule::RegisterBlueprintTabs); } void FHardReferenceFinderModule::ShutdownModule() { FHardReferenceFinderStyle::Shutdown(); FBlueprintEditorModule& BlueprintEditorModule = FModuleManager::LoadModuleChecked("Kismet"); BlueprintEditorModule.OnRegisterTabsForEditor().RemoveAll(this); } void FHardReferenceFinderModule::RegisterBlueprintTabs(FWorkflowAllowedTabSet& TabFactory, FName ModeName, TSharedPtr InBlueprintEditor) const { TabFactory.RegisterFactory(MakeShareable(new FHardReferenceFinderSummoner(InBlueprintEditor))); } #undef LOCTEXT_NAMESPACE IMPLEMENT_MODULE(FHardReferenceFinderModule, HardReferenceFinder) ================================================ FILE: Source/HardReferenceFinder/Private/HardReferenceFinderSearchData.cpp ================================================ #include "HardReferenceFinderSearchData.h" #include "AssetToolsModule.h" #include "AssetRegistry/AssetRegistryModule.h" #include "BlueprintEditor.h" #include "EdGraph/EdGraph.h" #include "K2Node_CallFunction.h" #include "K2Node_DynamicCast.h" #include "K2Node_FunctionEntry.h" #include "Kismet2/BlueprintEditorUtils.h" #include "Misc/EngineVersionComparison.h" #include "Styling/SlateIconFinder.h" #if ENGINE_MAJOR_VERSION < 5 #include "SSCSEditor.h" #else #include "SSubobjectEditor.h" #endif #define LOCTEXT_NAMESPACE "FHardReferenceFinderModule" TArray FHardReferenceFinderSearchData::GatherSearchData(TWeakPtr BlueprintEditor) { Reset(); TMap DependentPackageMap; FAssetRegistryModule& AssetRegistryModule = FModuleManager::Get().LoadModuleChecked(TEXT("AssetRegistry")); // Get this blueprints package dependencies from the blueprint editor TArray BlueprintDependencies; GetBlueprintDependencies(BlueprintDependencies, AssetRegistryModule, BlueprintEditor); // Populate display information from package dependencies { TMap DependencyToAssetDataMap; GetAssetForPackages(BlueprintDependencies, DependencyToAssetDataMap); for (auto MapIt = DependencyToAssetDataMap.CreateConstIterator(); MapIt; ++MapIt) { const FName& PathName = MapIt.Key(); const FAssetData& AssetData = MapIt.Value(); FString AssetTypeName = GetAssetTypeName(AssetData); FString FileName = FPaths::GetCleanFilename(PathName.ToString()); FAssetPackageData AssetPackageData; TryGetAssetPackageData(PathName, AssetPackageData, AssetRegistryModule); if( FHRFTreeViewItemPtr Header = MakeShared() ) { Header->bIsHeader = true; Header->PackageId = PathName; Header->Tooltip = FText::FromName(PathName); Header->Name = FText::FromString(FileName); Header->SizeOnDisk = GatherAssetSizeByName(PathName, AssetRegistryModule); Header->SlateIcon = FSlateIcon("EditorStyle", FName( *("ClassIcon." + AssetTypeName))); FAssetToolsModule& AssetToolsModule = FModuleManager::LoadModuleChecked(TEXT("AssetTools")); if (UClass* AssetClass = AssetData.GetClass()) { TWeakPtr AssetTypeActions = AssetToolsModule.Get().GetAssetTypeActionsForClass(AssetData.GetClass()); if(AssetTypeActions.IsValid()) { Header->IconColor = AssetTypeActions.Pin()->GetTypeColor(); } } DependentPackageMap.Add(PathName, Header); TreeView.Add(Header); } } } { // Search through blueprint nodes for references to the dependent packages if( UBlueprint* Blueprint = BlueprintEditor.Pin()->GetBlueprintObj() ) { SearchGraphNodes(DependentPackageMap, AssetRegistryModule, Blueprint->UbergraphPages); SearchFunctionReferences(DependentPackageMap, AssetRegistryModule, Blueprint); SearchBlueprintClassProperties(DependentPackageMap, AssetRegistryModule, Blueprint); SearchSimpleConstructionScript(DependentPackageMap, AssetRegistryModule, Blueprint); } } // If we didn't discover any references to a package make a note for(FHRFTreeViewItemPtr HeaderItem : TreeView) { if(HeaderItem->Children.Num() <= 0) { FHRFTreeViewItemPtr ChildItem = MakeShared(); HeaderItem->Children.Add(ChildItem); ChildItem->Name = LOCTEXT("UnknownSource", "Unidentified source"); ChildItem->Tooltip = LOCTEXT("UnknownSourceTooltip", "This package is being referenced but the plugin is unable to identify its source."); } } // sort from largest to smallest TreeView.Sort([](FHRFTreeViewItemPtr Lhs, FHRFTreeViewItemPtr Rhs) { return Lhs->SizeOnDisk > Rhs->SizeOnDisk; }); return TreeView; } void FHardReferenceFinderSearchData::Reset() { TreeView.Reset(); } UObject* FHardReferenceFinderSearchData::GetObjectContext(TWeakPtr BlueprintEditor) const { if(!BlueprintEditor.IsValid()) { return nullptr; } class BlueprintEditorEditingObject_AccessHack : public FBlueprintEditor { public: UObject* GetEditingObject_Expose() const { return GetEditingObject(); } }; return static_cast(BlueprintEditor.Pin().Get())->GetEditingObject_Expose(); } void FHardReferenceFinderSearchData::GetBlueprintDependencies(TArray& OutPackageDependencies, FAssetRegistryModule& AssetRegistryModule, TWeakPtr BlueprintEditor) const { UObject* Object = GetObjectContext(BlueprintEditor); if(Object == nullptr) { return; } FAssetData ExistingAsset = GetAssetDataForObject(Object); UE::AssetRegistry::FDependencyQuery Flags(UE::AssetRegistry::EDependencyQuery::Hard); AssetRegistryModule.GetDependencies(ExistingAsset.PackageName, OutPackageDependencies, UE::AssetRegistry::EDependencyCategory::Package, Flags); } void FHardReferenceFinderSearchData::SearchGraphNodes(TMap& OutPackageMap, const FAssetRegistryModule& AssetRegistryModule, const FEdGraphArray& EdGraphList) const { for(UEdGraph* Graph : EdGraphList) { if(Graph) { for (UEdGraphNode* Node : Graph->Nodes) { const UPackage* FunctionPackage = nullptr; if(const UK2Node_CallFunction* CallFunctionNode = Cast(Node)) { FunctionPackage = CallFunctionNode->FunctionReference.GetMemberParentPackage(); } else if(const UK2Node_DynamicCast* CastNode = Cast(Node)) { if(CastNode->TargetType) { FunctionPackage = CastNode->TargetType->GetPackage(); } } if( const FHRFTreeViewItemPtr Result = CheckAddPackageResult(OutPackageMap, AssetRegistryModule, FunctionPackage) ) { Result->Name = Node->GetNodeTitle(ENodeTitleType::ListView); Result->NodeGuid = Node->NodeGuid; Result->SlateIcon = Node->GetIconAndTint(Result->IconColor); } // Also search the pins of this node for any references to other packages, e.g. the 'Class' pin of a SpawnActor node. SearchNodePins(OutPackageMap, AssetRegistryModule, Node); } } } } void FHardReferenceFinderSearchData::SearchNodePins(TMap& OutPackageMap, const FAssetRegistryModule& AssetRegistryModule, const UEdGraphNode* Node) const { if(Node == nullptr) { return; } for(const UEdGraphPin* Pin : Node->Pins) { if(Pin->bHidden) { // skip hidden pins continue; } if(Pin->Direction == EGPD_Input) { if(const UObject* PinObject = Pin->DefaultObject) { const UPackage* FunctionPackage = PinObject->GetPackage(); if( const FHRFTreeViewItemPtr Result = CheckAddPackageResult(OutPackageMap, AssetRegistryModule, FunctionPackage) ) { Result->Name = FText::Format(LOCTEXT("FunctionInput","{0} ({1})"), FText::FromString(Pin->GetName()), Node->GetNodeTitle(ENodeTitleType::ListView)); Result->NodeGuid = Node->NodeGuid; if( const UEdGraphSchema* Schema = Pin->GetSchema() ) { Result->IconColor = Schema->GetPinTypeColor(Pin->PinType); } Result->SlateIcon = FSlateIcon("EditorStyle", "Graph.Pin.Disconnected_VarA"); } } } } } void FHardReferenceFinderSearchData::SearchFunctionReferences(TMap& OutPackageMap, const FAssetRegistryModule& AssetRegistryModule, const UBlueprint* Blueprint) const { // @heyomidk This method is still imperfect as there are a number of ways references can be formed from functions // 1. From graph nodes inside the function (Cast, etc) // 2. From Local Variables inside the function // a. Due to the variables type (ex: class is Blueprint) // b. Due to the default value (ie Subclass of UObject but points to a Blueprint) // 3. From arguments to a function // a. Due to the type of an input argument // b. Due to the type of an output argument // c. Due to the default value of an output argument // // Note that the UFunction* provided by a TFieldRange iterator accounts for reference types 2a/2b, while the cached // UFunction* in an EdGraphNode finds 2a but not 2b // // Note that neither method identifies all type 3 references so this approach may need to be amended/revised // This gathers type 1/3c references and creates links to the associated graph nodes. SearchGraphNodes(OutPackageMap, AssetRegistryModule, Blueprint->FunctionGraphs); // This gathers type 2 references and links them to the function entry node for( UFunction* Function : TFieldRange(Blueprint->GeneratedClass, EFieldIteratorFlags::ExcludeSuper) ) { const UK2Node_FunctionEntry* GraphEntryNode = FindGraphNodeForFunction(Blueprint, Function); if(GraphEntryNode) { for( const UObject* ReferencedObject : Function->ScriptAndPropertyObjectReferences) { const UPackage* Package = ReferencedObject->GetPackage(); if( const FHRFTreeViewItemPtr Result = CheckAddPackageResult(OutPackageMap, AssetRegistryModule, Package) ) { Result->Name = FText::Format(LOCTEXT("FunctionReference","{0}"), GraphEntryNode->GetNodeTitle(ENodeTitleType::ListView)); Result->NodeGuid = GraphEntryNode->NodeGuid; Result->SlateIcon = GraphEntryNode->GetIconAndTint(Result->IconColor); } } } } } void FHardReferenceFinderSearchData::SearchSimpleConstructionScript(TMap& OutPackageMap, const FAssetRegistryModule& AssetRegistryModule, const UBlueprint* Blueprint) const { const USimpleConstructionScript* SimpleConstructionScript = Blueprint->SimpleConstructionScript; if(SimpleConstructionScript == nullptr) { return; } const TArray& RootNodes = SimpleConstructionScript->GetAllNodes(); for(const USCS_Node* SCSNode : RootNodes) { if(SCSNode == nullptr) { continue; } const FName VarName = SCSNode->GetVariableName(); TSet OutReferencedPackages; FindPackagesInSCSNode(OutReferencedPackages, SCSNode); for(const UPackage* Package : OutReferencedPackages) { if(const FHRFTreeViewItemPtr Result = CheckAddPackageResult(OutPackageMap, AssetRegistryModule, Package)) { Result->SlateIcon = FSlateIconFinder::FindIconForClass(SCSNode->ComponentClass, TEXT("SCS.Component")); Result->Name = FText::Format(LOCTEXT("ComponentReference", "{0}"), FText::FromName(VarName)); Result->SCSIdentifier = SCSNode->GetFName(); } } } } UK2Node_FunctionEntry* FHardReferenceFinderSearchData::FindGraphNodeForFunction(const UBlueprint* Blueprint, UFunction* FunctionToFind) const { if(Blueprint == nullptr) { return nullptr; } if(FunctionToFind == nullptr) { return nullptr; } // search functions in the Graph for(UEdGraph* Graph : Blueprint->FunctionGraphs) { // find the entry point for the function in the graph UK2Node_FunctionEntry* GraphEntryNode = nullptr; for(UEdGraphNode* Node : Graph->Nodes) { GraphEntryNode = Cast(Node); if(GraphEntryNode != nullptr) { break; } } if(GraphEntryNode) { // See if this matches the provided UFunction const TSharedPtr NodeFunctionVarCache = GraphEntryNode->GetFunctionVariableCache(); if( NodeFunctionVarCache.IsValid() ) { if( const UFunction* NodeFunction = Cast(NodeFunctionVarCache->GetStruct()) ) { const FName NodeFunctionName = NodeFunction->GetFName(); const FName TargetFunctionName = FunctionToFind->GetFName(); if(NodeFunctionName == TargetFunctionName) { return GraphEntryNode; } } } } } return nullptr; } void FHardReferenceFinderSearchData::FindPackagesInSCSNode(TSet& OutReferencedPackages, const USCS_Node* SCSNode) const { if(SCSNode==nullptr || SCSNode->ComponentClass == nullptr) { return; } if( UPackage* NodePackage = SCSNode->ComponentClass->GetPackage() ) { if(NodePackage) { OutReferencedPackages.Add(NodePackage); } } for( const FProperty* Property : TFieldRange(SCSNode->ComponentClass, EFieldIteratorFlags::IncludeSuper)) { FSlateIcon VariableTypeIcon; TArray ReferencedPackages = FindPackagesForProperty(VariableTypeIcon, SCSNode->ComponentTemplate, Property ); for(UPackage* Package : ReferencedPackages) { OutReferencedPackages.Add(Package); } } } TArray FHardReferenceFinderSearchData::FindPackagesForProperty(FSlateIcon& OutResultIcon, const UObject* ContainerPtr, const FProperty* TargetProperty) const { TArray FoundPackages; if(TargetProperty == nullptr) { return FoundPackages; } if(ContainerPtr != nullptr) { TArray EncounteredStructProps; const EPropertyObjectReferenceType ReferenceType = EPropertyObjectReferenceType::Strong; const bool bHasStrongReferences = TargetProperty->ContainsObjectReference(EncounteredStructProps, ReferenceType); if(bHasStrongReferences) { const void* TargetPropertyAddress = TargetProperty->ContainerPtrToValuePtr(ContainerPtr); struct PropertyAndAddressTuple { const FProperty* Property = nullptr; const void* ValueAddress = nullptr; }; TArray PropertiesToExamine; if(const FArrayProperty* ArrayProperty = CastField(TargetProperty)) { OutResultIcon = FSlateIcon("EditorStyle", "Kismet.VariableList.ArrayTypeIcon"); FScriptArrayHelper ArrayHelper(ArrayProperty, TargetPropertyAddress); for(int i=0; iInner, ArrayHelper.GetRawPtr(i)}); } } else if(const FSetProperty* SetProperty = CastField(TargetProperty)) { OutResultIcon = FSlateIcon("EditorStyle", "Kismet.VariableList.SetTypeIcon"); FScriptSetHelper SetHelper(SetProperty, TargetPropertyAddress); for(int i=0; i(TargetProperty)) { OutResultIcon = FSlateIcon("EditorStyle", "Kismet.VariableList.MapValueTypeIcon"); FScriptMapHelper MapHelper(MapProperty, TargetPropertyAddress); for(int i=0; i(Tuple.Property) ) { if(const UObject* Object = ObjectProperty->GetObjectPropertyValue(Tuple.ValueAddress)) { if(UPackage* Package = Object->GetPackage()) { FoundPackages.AddUnique(Package); } } } } } } #if UE_VERSION_OLDER_THAN(5,3,0) typedef const TArray* FObjectArray; #else typedef const TArray>* FObjectArray; #endif FObjectArray ScriptAndPropertyObjectReferences = nullptr; if(const FObjectPropertyBase* ObjectProperty = CastField(TargetProperty)) { ScriptAndPropertyObjectReferences = &ObjectProperty->PropertyClass->ScriptAndPropertyObjectReferences; if(ObjectProperty->PropertyClass) { if(UPackage* Package = ObjectProperty->PropertyClass->GetPackage()) { FoundPackages.AddUnique(Package); } } } else if(const FStructProperty* StructProperty = CastField(TargetProperty)) { ScriptAndPropertyObjectReferences = &StructProperty->Struct->ScriptAndPropertyObjectReferences; } if(ScriptAndPropertyObjectReferences) { for(const UObject* ObjectReference : *ScriptAndPropertyObjectReferences) { if(ObjectReference) { if(UPackage* Package = ObjectReference->GetPackage()) { FoundPackages.AddUnique(Package); } } } } return FoundPackages; } void FHardReferenceFinderSearchData::SearchBlueprintClassProperties(TMap& OutPackageMap, const FAssetRegistryModule& AssetRegistryModule, UBlueprint* Blueprint) const { for( FProperty* Property : TFieldRange(Blueprint->GeneratedClass, EFieldIteratorFlags::ExcludeSuper)) { UBlueprint* FoundBlueprint = nullptr; const FName VarName = Property->GetFName(); const int32 VarIndex = FBlueprintEditorUtils::FindNewVariableIndexAndBlueprint(Blueprint, VarName, FoundBlueprint); const bool bIsVar = VarIndex != INDEX_NONE; bool bSkipProperty = false; if(!bIsVar) { if(const FObjectPropertyBase* ObjectProperty = CastField(Property)) { const bool bIsActorComponentClass = ObjectProperty->PropertyClass->IsChildOf(UActorComponent::StaticClass()); if(bIsActorComponentClass) { // Actor components aren't initialized in the CDO so parsing them here isn't exhaustive. // SearchSimpleConstructionScript() handles these, so skip these properties here. bSkipProperty = true; } } } if(!bSkipProperty) { FSlateIcon ResultIcon; TArray ReferencedPackages = FindPackagesForProperty(ResultIcon, Blueprint->GeneratedClass->GetDefaultObject(), Property); for(const UPackage* Package : ReferencedPackages) { if(const FHRFTreeViewItemPtr Result = CheckAddPackageResult(OutPackageMap, AssetRegistryModule, Package)) { if(bIsVar) { const FBPVariableDescription& Description = Blueprint->NewVariables[VarIndex]; if( UEdGraphSchema_K2 const* Schema = GetDefault() ) { Result->IconColor = Schema->GetPinTypeColor(Description.VarType); } Result->SlateIcon = ResultIcon; Result->Name = FText::Format(LOCTEXT("MemberVariable","{0} (Member Variable)"), FText::FromName(Description.VarName)); Result->Tooltip = LOCTEXT("MemberVariableTooltip","Blueprint member variable"); } else { Result->SlateIcon = ResultIcon; Result->Name = FText::Format(LOCTEXT("OtherPropertyName", "{0}"), FText::FromName(VarName)); } } } } } } FHRFTreeViewItemPtr FHardReferenceFinderSearchData::CheckAddPackageResult(TMap& OutPackageMap, const FAssetRegistryModule& AssetRegistryModule, const UPackage* Package) const { if( Package ) { const FName PackageName = Package->GetFName(); if(const FHRFTreeViewItemPtr* FoundHeader = OutPackageMap.Find(PackageName)) { const FHRFTreeViewItemPtr Header = *FoundHeader; FAssetPackageData AssetPackageData; const bool bExists = TryGetAssetPackageData(PackageName, AssetPackageData, AssetRegistryModule); if(ensure(bExists)) { FHRFTreeViewItemPtr Link = MakeShared(); Header->Children.Add(Link); return Link; } } } return nullptr; } void FHardReferenceFinderSearchData::GetAssetForPackages(const TArray& PackageNames, TMap& OutPackageToAssetData) const { #if ENGINE_MAJOR_VERSION < 5 FAssetRegistryModule& AssetRegistryModule = FModuleManager::Get().LoadModuleChecked(TEXT("AssetRegistry")); FARFilter Filter; for ( auto PackageIt = PackageNames.CreateConstIterator(); PackageIt; ++PackageIt ) { const FString& PackageName = (*PackageIt).ToString(); Filter.PackageNames.Add(*PackageIt); } TArray AssetDataList; AssetRegistryModule.Get().GetAssets(Filter, AssetDataList); for ( auto AssetIt = AssetDataList.CreateConstIterator(); AssetIt; ++AssetIt ) { OutPackageToAssetData.Add((*AssetIt).PackageName, *AssetIt); } #else UE::AssetRegistry::GetAssetForPackages(PackageNames, OutPackageToAssetData); #endif } bool FHardReferenceFinderSearchData::TryGetAssetPackageData(FName PathName, FAssetPackageData& OutPackageData, const FAssetRegistryModule& AssetRegistryModule) const { #if UE_VERSION_OLDER_THAN(5, 0, 0) if(const FAssetPackageData* pAssetPackageData = AssetRegistryModule.Get().GetAssetPackageData(PathName)) { OutPackageData = *pAssetPackageData; return true; } #elif UE_VERSION_OLDER_THAN(5, 1, 0) const TOptional pAssetPackageData = AssetRegistryModule.Get().GetAssetPackageDataCopy(PathName); if (pAssetPackageData.IsSet()) { OutPackageData = pAssetPackageData.GetValue(); return true; } #else const UE::AssetRegistry::EExists Result = AssetRegistryModule.TryGetAssetPackageData(PathName, OutPackageData); if(Result == UE::AssetRegistry::EExists::Exists) { return true; } #endif return false; } FString FHardReferenceFinderSearchData::GetAssetTypeName(const FAssetData& AssetData) const { #if UE_VERSION_OLDER_THAN(5, 1, 0) return AssetData.AssetClass.ToString(); #else return AssetData.AssetClassPath.GetAssetName().ToString(); #endif } FAssetData FHardReferenceFinderSearchData::GetAssetDataForObject(const UObject* Object) const { FAssetRegistryModule& AssetRegistryModule = FModuleManager::Get().LoadModuleChecked(TEXT("AssetRegistry")); FString ObjectPath = Object->GetPathName(); #if UE_VERSION_OLDER_THAN(5, 1, 0) return AssetRegistryModule.Get().GetAssetByObjectPath(*ObjectPath); #else return AssetRegistryModule.Get().GetAssetByObjectPath(FSoftObjectPath(ObjectPath)); #endif } int64 FHardReferenceFinderSearchData::GatherAssetSizeByName(const FName& AssetName, FAssetRegistryModule& AssetRegistryModule) const { TSet Visited; const int64 Size = GatherAssetSizeRecursive(AssetName, Visited, AssetRegistryModule); return Size; } int64 FHardReferenceFinderSearchData::GatherAssetSizeRecursive(const FName& AssetName, TSet& OutVisited, FAssetRegistryModule& AssetRegistryModule) const { const bool bAlreadyVisited = OutVisited.Contains(AssetName); if(bAlreadyVisited) { return 0; } OutVisited.Add(AssetName); int64 AssetSize = 0; FAssetPackageData AssetPackageData; if( TryGetAssetPackageData(AssetName, AssetPackageData, AssetRegistryModule) ) { AssetSize += AssetPackageData.DiskSize; } TArray Dependencies; const UE::AssetRegistry::FDependencyQuery Flags(UE::AssetRegistry::EDependencyQuery::Hard); AssetRegistryModule.GetDependencies(AssetName, Dependencies, UE::AssetRegistry::EDependencyCategory::Package, Flags); int64 DependencySize = 0; for(const FName& DependencyName : Dependencies) { DependencySize += GatherAssetSizeRecursive(DependencyName, OutVisited, AssetRegistryModule); } const int64 TotalSize = AssetSize + DependencySize; return TotalSize; } #undef LOCTEXT_NAMESPACE ================================================ FILE: Source/HardReferenceFinder/Private/HardReferenceFinderStyle.cpp ================================================ // Copyright Epic Games, Inc. All Rights Reserved. #include "HardReferenceFinderStyle.h" #include "Styling/SlateStyleRegistry.h" #include "Framework/Application/SlateApplication.h" #include "Slate/SlateGameResources.h" #include "Interfaces/IPluginManager.h" #define RootToContentDir Style->RootToContentDir TSharedPtr FHardReferenceFinderStyle::StyleInstance = nullptr; void FHardReferenceFinderStyle::Initialize() { if (!StyleInstance.IsValid()) { StyleInstance = Create(); FSlateStyleRegistry::RegisterSlateStyle(*StyleInstance); } } void FHardReferenceFinderStyle::Shutdown() { FSlateStyleRegistry::UnRegisterSlateStyle(*StyleInstance); ensure(StyleInstance.IsUnique()); StyleInstance.Reset(); } FName FHardReferenceFinderStyle::GetStyleSetName() { static FName StyleSetName(TEXT("HardReferenceFinderStyle")); return StyleSetName; } const FVector2D Icon16x16(16.0f, 16.0f); const FVector2D Icon20x20(20.0f, 20.0f); TSharedRef< FSlateStyleSet > FHardReferenceFinderStyle::Create() { TSharedRef< FSlateStyleSet > Style = MakeShareable(new FSlateStyleSet("HardReferenceFinderStyle")); Style->SetContentRoot(IPluginManager::Get().FindPlugin("HardReferenceFinder")->GetBaseDir() / TEXT("Resources")); return Style; } void FHardReferenceFinderStyle::ReloadTextures() { if (FSlateApplication::IsInitialized()) { FSlateApplication::Get().GetRenderer()->ReloadTextureResources(); } } const ISlateStyle& FHardReferenceFinderStyle::Get() { return *StyleInstance; } ================================================ FILE: Source/HardReferenceFinder/Private/HardReferenceFinderSummoner.cpp ================================================ // Copyright Epic Games, Inc. All Rights Reserved. #include "HardReferenceFinderSummoner.h" #include "HardReferenceFinderStyle.h" #include "BlueprintEditor.h" #include "SHardReferenceFinderWindow.h" #define LOCTEXT_NAMESPACE "FHardReferenceFinderModule" static const FName HardReferenceFinderID( TEXT( "HardReferenceFinder") ); FHardReferenceFinderSummoner::FHardReferenceFinderSummoner(TSharedPtr InHostingApp) : FWorkflowTabFactory(HardReferenceFinderID, InHostingApp) { TabLabel = LOCTEXT("HardReferenceFinderTabTitle", "Hard References"); TabIcon = FSlateIcon("EditorStyle","ContentBrowser.ReferenceViewer"); bIsSingleton = true; ViewMenuDescription = LOCTEXT("HardReferenceFinderView", "Hard Reference Viewer"); ViewMenuTooltip = LOCTEXT("HardReferenceFinderView_ToolTip", "Shows hard referencing nodes associated with this Blueprint"); } TSharedRef FHardReferenceFinderSummoner::CreateTabBody(const FWorkflowTabSpawnInfo& Info) const { const TSharedPtr BlueprintEditorPtr = StaticCastSharedPtr(HostingApp.Pin()); return SNew(SHardReferenceFinderWindow, BlueprintEditorPtr); } FText FHardReferenceFinderSummoner::GetTabToolTipText(const FWorkflowTabSpawnInfo& Info) const { return LOCTEXT("TabTooltip", "Shows the hard referencing nodes in this Blueprint"); } #undef LOCTEXT_NAMESPACE ================================================ FILE: Source/HardReferenceFinder/Private/SHardReferenceFinderWindow.cpp ================================================  #include "SHardReferenceFinderWindow.h" #include "BlueprintEditor.h" #include "BlueprintEditorTabs.h" #include "GraphEditorSettings.h" #include "HardReferenceFinderSearchData.h" #include "Engine/SCS_Node.h" #include "Engine/SimpleConstructionScript.h" #include "Kismet2/BlueprintEditorUtils.h" #include "Kismet2/KismetEditorUtilities.h" #include "Misc/EngineVersionComparison.h" #include "Widgets/Input/SButton.h" #if UE_VERSION_OLDER_THAN(5, 1, 0) #include "EditorStyleSet.h" #endif #define LOCTEXT_NAMESPACE "FHardReferenceFinderModule" namespace HardReferenceInternals { static FText MakeBestSizeString(const SIZE_T SizeInBytes) { FText SizeText; if (SizeInBytes < 1000) { // We ended up with bytes, so show a decimal number SizeText = FText::AsMemory(SizeInBytes, EMemoryUnitStandard::SI); } else { // Show a fractional number with the best possible units FNumberFormattingOptions NumberFormattingOptions; NumberFormattingOptions.MaximumFractionalDigits = 1; NumberFormattingOptions.MinimumFractionalDigits = 0; NumberFormattingOptions.MinimumIntegralDigits = 1; SizeText = FText::AsMemory(SizeInBytes, &NumberFormattingOptions, nullptr, EMemoryUnitStandard::SI); } return SizeText; } } void SHardReferenceFinderWindow::Construct(const FArguments& InArgs, TSharedPtr InBlueprintGraph) { BlueprintGraph = InBlueprintGraph; ChildSlot[ SNew(SVerticalBox) + SVerticalBox::Slot() .AutoHeight() .Padding(10.f) [ SNew(SHorizontalBox) +SHorizontalBox::Slot() .Padding(8.f,4.f) .VAlign(VAlign_Center) [ SAssignNew(HeaderText, STextBlock) ] +SHorizontalBox::Slot() .AutoWidth() .HAlign(HAlign_Right) .Padding(0.f, 0.0f) [ SNew(SButton) .OnClicked(this, &SHardReferenceFinderWindow::OnRefreshClicked) [ SNew(SHorizontalBox) + SHorizontalBox::Slot() .HAlign(HAlign_Center) .VAlign(VAlign_Center) .Padding(0.,3.f) .AutoWidth() [ SNew(SImage) .Image(GetBrush_RefreshIcon()) ] + SHorizontalBox::Slot() .Padding(FMargin(8., 0, 0, 0)) .VAlign(VAlign_Center) .AutoWidth() [ SNew(STextBlock) .Text(LOCTEXT("Refresh", "Refresh")) ] ] ] ] + SVerticalBox::Slot() [ SNew(SBorder) .BorderImage(GetBrush_MenuBackground()) .Padding(FMargin(8.f, 8.f, 4.f, 0.f)) [ SAssignNew(TreeView, SHRFTreeType) .TreeItemsSource(&TreeViewData) .OnGetChildren(this, &SHardReferenceFinderWindow::OnGetChildren) .OnGenerateRow(this, &SHardReferenceFinderWindow::OnGenerateRow) .OnMouseButtonDoubleClick(this, &SHardReferenceFinderWindow::OnDoubleClickTreeEntry) ] ] ]; InitiateSearch(); } TSet SHardReferenceFinderWindow::GetCollapsedPackages() const { TSet ExpandedItems; TreeView->GetExpandedItems(ExpandedItems); TSet CollapsedPackages; for(const FHRFTreeViewItemPtr Item : TreeViewData) { if(!ExpandedItems.Contains(Item)) { CollapsedPackages.Add(Item->PackageId); } } return CollapsedPackages; } void SHardReferenceFinderWindow::InitiateSearch() { if(TreeView.IsValid()) { TSet UserCollapsedPackages = GetCollapsedPackages(); TreeViewData = SearchData.GatherSearchData(BlueprintGraph); TreeView->RebuildList(); // expand new items by default, unless they were intentionally collapsed. for(const FHRFTreeViewItemPtr Item : TreeViewData) { const bool bWasCollapsed = UserCollapsedPackages.Contains(Item->PackageId); const bool bShouldExpandItem = !bWasCollapsed; TreeView->SetItemExpansion(Item, bShouldExpandItem); } } const FText SummaryText = FText::Format(LOCTEXT("SummaryMessage", "This blueprint makes {0} references to other packages."), SearchData.GetNumPackagesReferenced()); HeaderText->SetText(SummaryText); } FReply SHardReferenceFinderWindow::OnRefreshClicked() { InitiateSearch(); return FReply::Handled(); } bool SHardReferenceFinderWindow::BringAttentionToSCSNode(const FName& SCSIdentifier) const { if(!SCSIdentifier.IsValid()) { return false; } if(!BlueprintGraph.IsValid()) { return false; } const UBlueprint* Blueprint = BlueprintGraph.Pin()->GetBlueprintObj(); if(Blueprint == nullptr) { return false; } if(Blueprint->SimpleConstructionScript == nullptr) { return false; } UBlueprintGeneratedClass* GeneratedClass = Cast(Blueprint->GeneratedClass); if(GeneratedClass == nullptr) { return false; } // Open Viewport Tab BlueprintGraph.Pin()->FocusWindow(); BlueprintGraph.Pin()->GetTabManager()->TryInvokeTab(FBlueprintEditorTabs::SCSViewportID); // Find and Select the Component in the Viewport tab view const TArray& Nodes = Blueprint->SimpleConstructionScript->GetAllNodes(); for (USCS_Node* Node : Nodes) { if (Node->GetFName() == SCSIdentifier) { if (const UActorComponent* Component = Node->GetActualComponentTemplate(GeneratedClass)) { #if ENGINE_MAJOR_VERSION < 5 BlueprintGraph.Pin()->FindAndSelectSCSEditorTreeNode(Component, false); #else BlueprintGraph.Pin()->FindAndSelectSubobjectEditorTreeNode(Component, false); #endif } return true; } } return false; } void SHardReferenceFinderWindow::OnDoubleClickTreeEntry(TSharedPtr Item) const { if(Item.IsValid() && BlueprintGraph.IsValid()) { if( UBlueprint* BlueprintObj = BlueprintGraph.Pin()->GetBlueprintObj() ) { if( const UEdGraphNode* GraphNode = FBlueprintEditorUtils::GetNodeByGUID(BlueprintObj, Item->NodeGuid) ) { FKismetEditorUtilities::BringKismetToFocusAttentionOnObject(GraphNode); } else if(Item->SCSIdentifier.IsValid()) { BringAttentionToSCSNode(Item->SCSIdentifier); } } } } void SHardReferenceFinderWindow::OnGetChildren(FHRFTreeViewItemPtr InItem, TArray& OutChildren) const { OutChildren += InItem->Children; } TSharedRef SHardReferenceFinderWindow::OnGenerateRow(FHRFTreeViewItemPtr Item, const TSharedRef& TableViewBase) const { if(Item->bIsHeader) { const FText SizeText = HardReferenceInternals::MakeBestSizeString(Item->SizeOnDisk); const FText CategoryHeaderText = FText::Format(LOCTEXT("CategoryHeader", "{1} ({0})"), SizeText, Item->Name); return SNew(STableRow>, TableViewBase) .Style( GetStyle_HeaderRow() ) .Padding(FMargin(2.f, 3.f, 2.f, 3.f)) .ToolTipText(Item->Tooltip) [ SNew(SHorizontalBox) +SHorizontalBox::Slot() .VAlign(VAlign_Center) .Padding(FMargin(0.f, 0.f, 8.f, 0.f)) .AutoWidth() [ SNew(SImage) .Image(Item->SlateIcon.GetOptionalIcon()) .ColorAndOpacity(Item->IconColor) ] +SHorizontalBox::Slot() .AutoWidth() .VAlign(VAlign_Center) .Padding(2.f) [ SNew(STextBlock).Text(CategoryHeaderText) ] ]; } else { return SNew(STableRow>, TableViewBase) .ToolTipText(Item->Tooltip) [ SNew(SHorizontalBox) +SHorizontalBox::Slot() .VAlign(VAlign_Center) .Padding(FMargin(0.f, 0.f, 8.f, 0.f)) .AutoWidth() [ SNew(SImage) .Image(Item->SlateIcon.GetOptionalIcon()) .ColorAndOpacity(Item->IconColor) ] +SHorizontalBox::Slot() .AutoWidth() .VAlign(VAlign_Center) .Padding(2.f) [ SNew(STextBlock).Text(Item->Name) ] ]; } } const FSlateBrush* SHardReferenceFinderWindow::GetBrush_MenuBackground() const { #if UE_VERSION_OLDER_THAN(5, 1, 0) return FEditorStyle::GetBrush("Menu.Background"); #else return FAppStyle::Get().GetBrush("Brushes.Recessed"); #endif } const FSlateBrush* SHardReferenceFinderWindow::GetBrush_RefreshIcon() const { #if UE_VERSION_OLDER_THAN(5, 1, 0) return FEditorStyle::GetBrush("Icons.Refresh"); #else return FAppStyle::GetBrush("Icons.Refresh"); #endif } const FTableRowStyle* SHardReferenceFinderWindow::GetStyle_HeaderRow() const { #if UE_VERSION_OLDER_THAN(5, 1, 0) return &FCoreStyle::Get().GetWidgetStyle("TableView.Row"); #else return &FAppStyle::Get().GetWidgetStyle("ShowParentsTableView.Row"); #endif } #undef LOCTEXT_NAMESPACE ================================================ FILE: Source/HardReferenceFinder/Public/HardReferenceFinder.h ================================================ // Copyright Epic Games, Inc. All Rights Reserved. #pragma once #include "CoreMinimal.h" #include "Modules/ModuleManager.h" class FWorkflowAllowedTabSet; class FBlueprintEditor; class FHardReferenceFinderModule : public IModuleInterface { public: /** IModuleInterface implementation */ virtual void StartupModule() override; virtual void ShutdownModule() override; private: void RegisterBlueprintTabs(FWorkflowAllowedTabSet& TabManager, FName ModeName, TSharedPtr InBlueprintEditor) const; }; ================================================ FILE: Source/HardReferenceFinder/Public/HardReferenceFinderSearchData.h ================================================ #pragma once #include "CoreMinimal.h" #include "AssetRegistry/AssetRegistryModule.h" #include "Templates/SharedPointer.h" #include "Textures/SlateIcon.h" class FBlueprintEditor; class UEdGraph; class UEdGraphNode; class UK2Node_FunctionEntry; class USCS_Node; class FHRFTreeViewItem : public TSharedFromThis { public: bool bIsHeader = false; int SizeOnDisk = 0; FName PackageId = NAME_None; FText Name; FText Tooltip; FGuid NodeGuid; FName SCSIdentifier = NAME_None; FSlateIcon SlateIcon; FLinearColor IconColor = FLinearColor::White; TArray> Children; }; typedef TSharedPtr FHRFTreeViewItemPtr; #if ENGINE_MAJOR_VERSION < 5 typedef const TArray FEdGraphArray; #else typedef const TArray> FEdGraphArray; #endif class FHardReferenceFinderSearchData { public: TArray GatherSearchData(TWeakPtr BlueprintEditor); int GetNumPackagesReferenced() const { return TreeView.Num(); } private: void Reset(); UObject* GetObjectContext(TWeakPtr BlueprintEditor) const; void GetBlueprintDependencies(TArray& OutPackageDependencies, FAssetRegistryModule& AssetRegistryModule, TWeakPtr BlueprintEditor) const; void SearchGraphNodes(TMap& OutPackageMap, const FAssetRegistryModule& AssetRegistryModule, const FEdGraphArray& EdGraphList) const; void SearchNodePins(TMap& OutPackageMap, const FAssetRegistryModule& AssetRegistryModule, const UEdGraphNode* Node) const; void SearchBlueprintClassProperties(TMap& OutPackageMap, const FAssetRegistryModule& AssetRegistryModule, UBlueprint* Blueprint) const; void SearchFunctionReferences(TMap& OutPackageMap, const FAssetRegistryModule& AssetRegistryModule, const UBlueprint* Blueprint) const; void SearchSimpleConstructionScript(TMap& OutPackageMap, const FAssetRegistryModule& AssetRegistryModule, const UBlueprint* Blueprint) const; UK2Node_FunctionEntry* FindGraphNodeForFunction(const UBlueprint* Blueprint, UFunction* FunctionToFind) const; void FindPackagesInSCSNode(TSet& OutReferencedPackages,const USCS_Node* SCSNode) const; TArray FindPackagesForProperty(FSlateIcon& OutResultIcon, const UObject* ContainerPtr, const FProperty* TargetProperty) const; FHRFTreeViewItemPtr CheckAddPackageResult(TMap& OutPackageMap, const FAssetRegistryModule& AssetRegistryModule, const UPackage* Package) const; void GetAssetForPackages(const TArray& PackageNames, TMap& OutPackageToAssetData) const; bool TryGetAssetPackageData(FName PathName, FAssetPackageData& OutPackageData, const FAssetRegistryModule& AssetRegistryModule) const; FString GetAssetTypeName(const FAssetData& AssetData) const; FAssetData GetAssetDataForObject(const UObject* Object) const; int64 GatherAssetSizeByName(const FName& AssetName, FAssetRegistryModule& AssetRegistryModule) const; int64 GatherAssetSizeRecursive(const FName& OutFrontier, TSet& OutVisited, FAssetRegistryModule& AssetRegistryModule) const; TArray TreeView; }; ================================================ FILE: Source/HardReferenceFinder/Public/HardReferenceFinderStyle.h ================================================ // Copyright Epic Games, Inc. All Rights Reserved. #pragma once #include "CoreMinimal.h" #include "Styling/SlateStyle.h" /** */ class FHardReferenceFinderStyle { public: static void Initialize(); static void Shutdown(); /** reloads textures used by slate renderer */ static void ReloadTextures(); /** @return The Slate style set for the Shooter game */ static const ISlateStyle& Get(); static FName GetStyleSetName(); private: static TSharedRef< class FSlateStyleSet > Create(); private: static TSharedPtr< class FSlateStyleSet > StyleInstance; }; ================================================ FILE: Source/HardReferenceFinder/Public/HardReferenceFinderSummoner.h ================================================ // Copyright Epic Games, Inc. All Rights Reserved. #pragma once #include "CoreMinimal.h" #include "WorkflowOrientedApp/WorkflowTabFactory.h" struct FHardReferenceFinderSummoner : public FWorkflowTabFactory { FHardReferenceFinderSummoner(TSharedPtr InHostingApp); virtual TSharedRef CreateTabBody(const FWorkflowTabSpawnInfo& Info) const override; virtual FText GetTabToolTipText(const FWorkflowTabSpawnInfo& Info) const override; }; ================================================ FILE: Source/HardReferenceFinder/Public/SHardReferenceFinderWindow.h ================================================ #pragma once #include "CoreMinimal.h" #include "HardReferenceFinderSearchData.h" #include "Widgets/SCompoundWidget.h" #include "Widgets/Views/STableViewBase.h" #include "Widgets/Views/STableRow.h" #include "Widgets/Views/STreeView.h" class FBlueprintEditor; class SHardReferenceFinderWindow : public SCompoundWidget { SLATE_BEGIN_ARGS(SHardReferenceFinderWindow) {}; SLATE_END_ARGS() void Construct(const FArguments& InArgs, TSharedPtr InBlueprintGraph); private: typedef STreeView SHRFTreeType; TSet GetCollapsedPackages() const; void InitiateSearch(); FReply OnRefreshClicked(); bool BringAttentionToSCSNode(const FName& SCSIdentifier) const; void OnDoubleClickTreeEntry(TSharedPtr Item) const; void OnGetChildren(FHRFTreeViewItemPtr InItem, TArray< FHRFTreeViewItemPtr >& OutChildren) const; TSharedRef OnGenerateRow(FHRFTreeViewItemPtr Item, const TSharedRef& TableViewBase) const; const FSlateBrush* GetBrush_MenuBackground() const; const FSlateBrush* GetBrush_RefreshIcon() const; const FTableRowStyle* GetStyle_HeaderRow() const; /* The graph this window is operating on */ TWeakPtr BlueprintGraph; /* Stores the data from searching the graph for references*/ FHardReferenceFinderSearchData SearchData; /* Stores the list of items dispalyed by the tree view widget */ TArray> TreeViewData; /* Holds a reference to the header widget */ TSharedPtr HeaderText; /* Holds a reference to the tree view*/ TSharedPtr TreeView; };