Files
UnrealEngineUWP/Engine/Source/Editor/ReferenceViewer/Private/EdGraph_ReferenceViewer.cpp
Ben Marsh 4ba423868f Copying //UE4/Dev-Build to //UE4/Dev-Main (Source: //UE4/Dev-Build @ 3209340)
#lockdown Nick.Penwarden
#rb none

==========================
MAJOR FEATURES + CHANGES
==========================

Change 3209340 on 2016/11/23 by Ben.Marsh

	Convert UE4 codebase to an "include what you use" model - where every header just includes the dependencies it needs, rather than every source file including large monolithic headers like Engine.h and UnrealEd.h.

	Measured full rebuild times around 2x faster using XGE on Windows, and improvements of 25% or more for incremental builds and full rebuilds on most other platforms.

	  * Every header now includes everything it needs to compile.
	        * There's a CoreMinimal.h header that gets you a set of ubiquitous types from Core (eg. FString, FName, TArray, FVector, etc...). Most headers now include this first.
	        * There's a CoreTypes.h header that sets up primitive UE4 types and build macros (int32, PLATFORM_WIN64, etc...). All headers in Core include this first, as does CoreMinimal.h.
	  * Every .cpp file includes its matching .h file first.
	        * This helps validate that each header is including everything it needs to compile.
	  * No engine code includes a monolithic header such as Engine.h or UnrealEd.h any more.
	        * You will get a warning if you try to include one of these from the engine. They still exist for compatibility with game projects and do not produce warnings when included there.
	        * There have only been minor changes to our internal games down to accommodate these changes. The intent is for this to be as seamless as possible.
	  * No engine code explicitly includes a precompiled header any more.
	        * We still use PCHs, but they're force-included on the compiler command line by UnrealBuildTool instead. This lets us tune what they contain without breaking any existing include dependencies.
	        * PCHs are generated by a tool to get a statistical amount of coverage for the source files using it, and I've seeded the new shared PCHs to contain any header included by > 15% of source files.

	Tool used to generate this transform is at Engine\Source\Programs\IncludeTool.

[CL 3209342 by Ben Marsh in Main branch]
2016-11-23 15:48:37 -05:00

498 lines
14 KiB
C++

// Copyright 1998-2016 Epic Games, Inc. All Rights Reserved.
#include "EdGraph_ReferenceViewer.h"
#include "EdGraph/EdGraphPin.h"
#include "EdGraphNode_Reference.h"
#include "ARFilter.h"
#include "AssetRegistryModule.h"
#include "AssetThumbnail.h"
UEdGraph_ReferenceViewer::UEdGraph_ReferenceViewer(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer)
{
AssetThumbnailPool = MakeShareable( new FAssetThumbnailPool(1024) );
MaxSearchDepth = 1;
MaxSearchBreadth = 15;
bLimitSearchDepth = true;
bLimitSearchBreadth = true;
bIsShowSoftReferences = true;
bIsShowHardReferences = true;
bIsShowSearchableNames = false;
bIsShowNativePackages = false;
}
void UEdGraph_ReferenceViewer::BeginDestroy()
{
if ( AssetThumbnailPool.IsValid() )
{
AssetThumbnailPool->ReleaseResources();
AssetThumbnailPool.Reset();
}
Super::BeginDestroy();
}
void UEdGraph_ReferenceViewer::SetGraphRoot(const TArray<FAssetIdentifier>& GraphRootIdentifiers, const FIntPoint& GraphRootOrigin)
{
CurrentGraphRootIdentifiers = GraphRootIdentifiers;
CurrentGraphRootOrigin = GraphRootOrigin;
// If we're focused on a searchable name, enable that flag
for (const FAssetIdentifier& AssetId : GraphRootIdentifiers)
{
if (AssetId.IsValue())
{
bIsShowSearchableNames = true;
}
}
}
const TArray<FAssetIdentifier>& UEdGraph_ReferenceViewer::GetCurrentGraphRootIdentifiers() const
{
return CurrentGraphRootIdentifiers;
}
UEdGraphNode_Reference* UEdGraph_ReferenceViewer::RebuildGraph()
{
RemoveAllNodes();
UEdGraphNode_Reference* NewRootNode = ConstructNodes(CurrentGraphRootIdentifiers, CurrentGraphRootOrigin);
NotifyGraphChanged();
return NewRootNode;
}
bool UEdGraph_ReferenceViewer::IsSearchDepthLimited() const
{
return bLimitSearchDepth;
}
bool UEdGraph_ReferenceViewer::IsSearchBreadthLimited() const
{
return bLimitSearchBreadth;
}
bool UEdGraph_ReferenceViewer::IsShowSoftReferences() const
{
return bIsShowSoftReferences;
}
bool UEdGraph_ReferenceViewer::IsShowHardReferences() const
{
return bIsShowHardReferences;
}
bool UEdGraph_ReferenceViewer::IsShowSearchableNames() const
{
return bIsShowSearchableNames;
}
bool UEdGraph_ReferenceViewer::IsShowNativePackages() const
{
return bIsShowNativePackages;
}
void UEdGraph_ReferenceViewer::SetSearchDepthLimitEnabled(bool newEnabled)
{
bLimitSearchDepth = newEnabled;
}
void UEdGraph_ReferenceViewer::SetSearchBreadthLimitEnabled(bool newEnabled)
{
bLimitSearchBreadth = newEnabled;
}
void UEdGraph_ReferenceViewer::SetShowSoftReferencesEnabled(bool newEnabled)
{
bIsShowSoftReferences = newEnabled;
}
void UEdGraph_ReferenceViewer::SetShowHardReferencesEnabled(bool newEnabled)
{
bIsShowHardReferences = newEnabled;
}
void UEdGraph_ReferenceViewer::SetShowSearchableNames(bool newEnabled)
{
bIsShowSearchableNames = newEnabled;
}
void UEdGraph_ReferenceViewer::SetShowNativePackages(bool newEnabled)
{
bIsShowNativePackages = newEnabled;
}
int32 UEdGraph_ReferenceViewer::GetSearchDepthLimit() const
{
return MaxSearchDepth;
}
int32 UEdGraph_ReferenceViewer::GetSearchBreadthLimit() const
{
return MaxSearchBreadth;
}
void UEdGraph_ReferenceViewer::SetSearchDepthLimit(int32 NewDepthLimit)
{
MaxSearchDepth = NewDepthLimit;
}
void UEdGraph_ReferenceViewer::SetSearchBreadthLimit(int32 NewBreadthLimit)
{
MaxSearchBreadth = NewBreadthLimit;
}
EAssetRegistryDependencyType::Type UEdGraph_ReferenceViewer::GetReferenceSearchFlags(bool bReferencers) const
{
int32 ReferenceFlags = 0;
if (bIsShowSoftReferences)
{
ReferenceFlags |= EAssetRegistryDependencyType::Soft;
}
if (bIsShowHardReferences)
{
ReferenceFlags |= EAssetRegistryDependencyType::Hard;
}
if (bIsShowSearchableNames)
{
ReferenceFlags |= EAssetRegistryDependencyType::SearchableName;
}
return (EAssetRegistryDependencyType::Type)ReferenceFlags;
}
UEdGraphNode_Reference* UEdGraph_ReferenceViewer::ConstructNodes(const TArray<FAssetIdentifier>& GraphRootIdentifiers, const FIntPoint& GraphRootOrigin )
{
UEdGraphNode_Reference* RootNode = NULL;
if (GraphRootIdentifiers.Num() > 0 )
{
TMap<FAssetIdentifier, int32> ReferencerNodeSizes;
TSet<FAssetIdentifier> VisitedReferencerSizeNames;
int32 ReferencerDepth = 1;
RecursivelyGatherSizes(/*bReferencers=*/true, GraphRootIdentifiers, ReferencerDepth, VisitedReferencerSizeNames, ReferencerNodeSizes);
TMap<FAssetIdentifier, int32> DependencyNodeSizes;
TSet<FAssetIdentifier> VisitedDependencySizeNames;
int32 DependencyDepth = 1;
RecursivelyGatherSizes(/*bReferencers=*/false, GraphRootIdentifiers, DependencyDepth, VisitedDependencySizeNames, DependencyNodeSizes);
TSet<FName> AllPackageNames;
auto AddPackage = [](const FAssetIdentifier& AssetId, TSet<FName>& PackageNames)
{
// Only look for asset data if this is a package
if (!AssetId.IsValue())
{
PackageNames.Add(AssetId.PackageName);
}
};
for (const FAssetIdentifier& AssetId : VisitedReferencerSizeNames)
{
AddPackage(AssetId, AllPackageNames);
}
for (const FAssetIdentifier& AssetId : VisitedDependencySizeNames)
{
AddPackage(AssetId, AllPackageNames);
}
TMap<FName, FAssetData> PackagesToAssetDataMap;
GatherAssetData(AllPackageNames, PackagesToAssetDataMap);
// Create the root node
RootNode = CreateReferenceNode();
RootNode->SetupReferenceNode(GraphRootOrigin, GraphRootIdentifiers, PackagesToAssetDataMap.FindRef(GraphRootIdentifiers[0].PackageName));
TSet<FAssetIdentifier> VisitedReferencerNames;
int32 VisitedReferencerDepth = 1;
RecursivelyConstructNodes(/*bReferencers=*/true, RootNode, GraphRootIdentifiers, GraphRootOrigin, ReferencerNodeSizes, PackagesToAssetDataMap, VisitedReferencerDepth, VisitedReferencerNames);
TSet<FAssetIdentifier> VisitedDependencyNames;
int32 VisitedDependencyDepth = 1;
RecursivelyConstructNodes(/*bReferencers=*/false, RootNode, GraphRootIdentifiers, GraphRootOrigin, DependencyNodeSizes, PackagesToAssetDataMap, VisitedDependencyDepth, VisitedDependencyNames);
}
return RootNode;
}
int32 UEdGraph_ReferenceViewer::RecursivelyGatherSizes(bool bReferencers, const TArray<FAssetIdentifier>& Identifiers, int32 CurrentDepth, TSet<FAssetIdentifier>& VisitedNames, TMap<FAssetIdentifier, int32>& OutNodeSizes) const
{
check(Identifiers.Num() > 0);
VisitedNames.Append(Identifiers);
FAssetRegistryModule& AssetRegistryModule = FModuleManager::LoadModuleChecked<FAssetRegistryModule>("AssetRegistry");
TArray<FAssetIdentifier> ReferenceNames;
if ( bReferencers )
{
for (const FAssetIdentifier& AssetId : Identifiers)
{
AssetRegistryModule.Get().GetReferencers(AssetId, ReferenceNames, GetReferenceSearchFlags(bReferencers));
}
}
else
{
for (const FAssetIdentifier& AssetId : Identifiers)
{
AssetRegistryModule.Get().GetDependencies(AssetId, ReferenceNames, GetReferenceSearchFlags(bReferencers));
}
}
if (!bIsShowNativePackages)
{
auto RemoveNativePackage = [](const FAssetIdentifier& InAsset) { return InAsset.PackageName.ToString().StartsWith(TEXT("/Script")) && !InAsset.IsValue(); };
ReferenceNames.RemoveAll(RemoveNativePackage);
}
int32 NodeSize = 0;
if ( ReferenceNames.Num() > 0 && !ExceedsMaxSearchDepth(CurrentDepth) )
{
int32 NumReferencesMade = 0;
int32 NumReferencesExceedingMax = 0;
// Since there are referencers, use the size of all your combined referencers.
// Do not count your own size since there could just be a horizontal line of nodes
for (const FAssetIdentifier& AssetId : ReferenceNames)
{
if ( !VisitedNames.Contains(AssetId) )
{
if ( !ExceedsMaxSearchBreadth(NumReferencesMade) )
{
TArray<FAssetIdentifier> NewPackageNames;
NewPackageNames.Add(AssetId);
NodeSize += RecursivelyGatherSizes(bReferencers, NewPackageNames, CurrentDepth + 1, VisitedNames, OutNodeSizes);
NumReferencesMade++;
}
else
{
NumReferencesExceedingMax++;
}
}
}
if ( NumReferencesExceedingMax > 0 )
{
// Add one size for the collapsed node
NodeSize++;
}
}
if ( NodeSize == 0 )
{
// If you have no valid children, the node size is just 1 (counting only self to make a straight line)
NodeSize = 1;
}
OutNodeSizes.Add(Identifiers[0], NodeSize);
return NodeSize;
}
void UEdGraph_ReferenceViewer::GatherAssetData(const TSet<FName>& AllPackageNames, TMap<FName, FAssetData>& OutPackageToAssetDataMap) const
{
// Take a guess to find the asset instead of searching for it. Most packages have a single asset in them with the same name as the package.
FAssetRegistryModule& AssetRegistryModule = FModuleManager::LoadModuleChecked<FAssetRegistryModule>("AssetRegistry");
FARFilter Filter;
for ( auto PackageIt = AllPackageNames.CreateConstIterator(); PackageIt; ++PackageIt )
{
const FString& PackageName = (*PackageIt).ToString();
const FString& PackagePath = PackageName + TEXT(".") + FPackageName::GetLongPackageAssetName(PackageName);
Filter.ObjectPaths.Add( FName(*PackagePath) );
}
TArray<FAssetData> AssetDataList;
AssetRegistryModule.Get().GetAssets(Filter, AssetDataList);
for ( auto AssetIt = AssetDataList.CreateConstIterator(); AssetIt; ++AssetIt )
{
OutPackageToAssetDataMap.Add((*AssetIt).PackageName, *AssetIt);
}
}
UEdGraphNode_Reference* UEdGraph_ReferenceViewer::RecursivelyConstructNodes(bool bReferencers, UEdGraphNode_Reference* RootNode, const TArray<FAssetIdentifier>& Identifiers, const FIntPoint& NodeLoc, const TMap<FAssetIdentifier, int32>& NodeSizes, const TMap<FName, FAssetData>& PackagesToAssetDataMap, int32 CurrentDepth, TSet<FAssetIdentifier>& VisitedNames)
{
check(Identifiers.Num() > 0);
VisitedNames.Append(Identifiers);
UEdGraphNode_Reference* NewNode = NULL;
if ( RootNode->GetIdentifier() == Identifiers[0] )
{
// Don't create the root node. It is already created!
NewNode = RootNode;
}
else
{
NewNode = CreateReferenceNode();
NewNode->SetupReferenceNode(NodeLoc, Identifiers, PackagesToAssetDataMap.FindRef(Identifiers[0].PackageName));
}
FAssetRegistryModule& AssetRegistryModule = FModuleManager::LoadModuleChecked<FAssetRegistryModule>("AssetRegistry");
TArray<FAssetIdentifier> ReferenceNames;
TArray<FAssetIdentifier> HardReferenceNames;
if ( bReferencers )
{
for (const FAssetIdentifier& AssetId : Identifiers)
{
AssetRegistryModule.Get().GetReferencers(AssetId, HardReferenceNames, EAssetRegistryDependencyType::Hard);
AssetRegistryModule.Get().GetReferencers(AssetId, ReferenceNames, GetReferenceSearchFlags(bReferencers));
}
}
else
{
for (const FAssetIdentifier& AssetId : Identifiers)
{
AssetRegistryModule.Get().GetDependencies(AssetId, HardReferenceNames, EAssetRegistryDependencyType::Hard);
AssetRegistryModule.Get().GetDependencies(AssetId, ReferenceNames, GetReferenceSearchFlags(bReferencers));
}
}
if (!bIsShowNativePackages)
{
auto RemoveNativePackage = [](const FAssetIdentifier& InAsset) { return InAsset.PackageName.ToString().StartsWith(TEXT("/Script")) && !InAsset.IsValue(); };
HardReferenceNames.RemoveAll(RemoveNativePackage);
ReferenceNames.RemoveAll(RemoveNativePackage);
}
if ( ReferenceNames.Num() > 0 && !ExceedsMaxSearchDepth(CurrentDepth) )
{
FIntPoint ReferenceNodeLoc = NodeLoc;
if ( bReferencers )
{
// Referencers go left
ReferenceNodeLoc.X -= 800;
}
else
{
// Dependencies go right
ReferenceNodeLoc.X += 800;
}
const int32 NodeSizeY = 200;
const int32 TotalReferenceSizeY = NodeSizes.FindChecked(Identifiers[0]) * NodeSizeY;
ReferenceNodeLoc.Y -= TotalReferenceSizeY * 0.5f;
ReferenceNodeLoc.Y += NodeSizeY * 0.5f;
int32 NumReferencesMade = 0;
int32 NumReferencesExceedingMax = 0;
for ( int32 RefIdx = 0; RefIdx < ReferenceNames.Num(); ++RefIdx )
{
FAssetIdentifier ReferenceName = ReferenceNames[RefIdx];
if ( !VisitedNames.Contains(ReferenceName) )
{
if ( !ExceedsMaxSearchBreadth(NumReferencesMade) )
{
int32 ThisNodeSizeY = ReferenceName.IsValue() ? 100 : NodeSizeY;
const int32 RefSizeY = NodeSizes.FindChecked(ReferenceName);
FIntPoint RefNodeLoc;
RefNodeLoc.X = ReferenceNodeLoc.X;
RefNodeLoc.Y = ReferenceNodeLoc.Y + RefSizeY * ThisNodeSizeY * 0.5 - ThisNodeSizeY * 0.5;
TArray<FAssetIdentifier> NewIdentifiers;
NewIdentifiers.Add(ReferenceName);
UEdGraphNode_Reference* ReferenceNode = RecursivelyConstructNodes(bReferencers, RootNode, NewIdentifiers, RefNodeLoc, NodeSizes, PackagesToAssetDataMap, CurrentDepth + 1, VisitedNames);
if (HardReferenceNames.Contains(ReferenceName))
{
if (bReferencers)
{
ReferenceNode->GetDependencyPin()->PinType.PinCategory = TEXT("hard");
}
else
{
ReferenceNode->GetReferencerPin()->PinType.PinCategory = TEXT("hard");
}
}
if ( ensure(ReferenceNode) )
{
if ( bReferencers )
{
NewNode->AddReferencer( ReferenceNode );
}
else
{
ReferenceNode->AddReferencer( NewNode );
}
ReferenceNodeLoc.Y += RefSizeY * ThisNodeSizeY;
}
NumReferencesMade++;
}
else
{
NumReferencesExceedingMax++;
}
}
}
if ( NumReferencesExceedingMax > 0 )
{
// There are more references than allowed to be displayed. Make a collapsed node.
UEdGraphNode_Reference* ReferenceNode = CreateReferenceNode();
FIntPoint RefNodeLoc;
RefNodeLoc.X = ReferenceNodeLoc.X;
RefNodeLoc.Y = ReferenceNodeLoc.Y;
if ( ensure(ReferenceNode) )
{
ReferenceNode->SetReferenceNodeCollapsed(RefNodeLoc, NumReferencesExceedingMax);
if ( bReferencers )
{
NewNode->AddReferencer( ReferenceNode );
}
else
{
ReferenceNode->AddReferencer( NewNode );
}
}
}
}
return NewNode;
}
const TSharedPtr<FAssetThumbnailPool>& UEdGraph_ReferenceViewer::GetAssetThumbnailPool() const
{
return AssetThumbnailPool;
}
bool UEdGraph_ReferenceViewer::ExceedsMaxSearchDepth(int32 Depth) const
{
return bLimitSearchDepth && Depth > MaxSearchDepth;
}
bool UEdGraph_ReferenceViewer::ExceedsMaxSearchBreadth(int32 Breadth) const
{
return bLimitSearchBreadth && Breadth > MaxSearchBreadth;
}
UEdGraphNode_Reference* UEdGraph_ReferenceViewer::CreateReferenceNode()
{
const bool bSelectNewNode = false;
return Cast<UEdGraphNode_Reference>(CreateNode(UEdGraphNode_Reference::StaticClass(), bSelectNewNode));
}
void UEdGraph_ReferenceViewer::RemoveAllNodes()
{
TArray<UEdGraphNode*> NodesToRemove = Nodes;
for (int32 NodeIndex = 0; NodeIndex < NodesToRemove.Num(); ++NodeIndex)
{
RemoveNode(NodesToRemove[NodeIndex]);
}
}