void SAssetDialog::CommitObjectPathForSave() { if ( ensure(DialogType == EAssetDialogType::Save) ) { if ( bLastInputValidityCheckSuccessful ) { const FString ObjectPath = GetObjectPathForSave(); bool bProceedWithSave = true; // If we were asked to warn on existing assets, do it now if ( ExistingAssetPolicy == ESaveAssetDialogExistingAssetPolicy::AllowButWarn ) { FAssetRegistryModule& AssetRegistryModule = FModuleManager::LoadModuleChecked<FAssetRegistryModule>("AssetRegistry"); FAssetData ExistingAsset = AssetRegistryModule.Get().GetAssetByObjectPath(FName(*ObjectPath)); if ( ExistingAsset.IsValid() && AssetClassNames.Contains(ExistingAsset.AssetClass) ) { EAppReturnType::Type ShouldReplace = FMessageDialog::Open( EAppMsgType::YesNo, FText::Format(LOCTEXT("ReplaceAssetMessage", "{ExistingAsset} already exists. Do you want to replace it?"), FText::FromString(CurrentlyEnteredAssetName)) ); bProceedWithSave = (ShouldReplace == EAppReturnType::Yes); } } if ( bProceedWithSave ) { OnObjectPathChosenForSave.ExecuteIfBound(ObjectPath); CloseDialog(); } } } }
void FActorFactoryAssetProxy::GenerateActorFactoryMenuItems( const FAssetData& AssetData, TArray<FMenuItem>* OutMenuItems, bool ExcludeStandAloneFactories ) { FText UnusedErrorMessage; const FAssetData NoAssetData; for ( int32 FactoryIdx = 0; FactoryIdx < GEditor->ActorFactories.Num(); FactoryIdx++ ) { UActorFactory* Factory = GEditor->ActorFactories[FactoryIdx]; const bool FactoryWorksWithoutAsset = Factory->CanCreateActorFrom( NoAssetData, UnusedErrorMessage ); const bool FactoryWorksWithAsset = AssetData.IsValid() && Factory->CanCreateActorFrom( AssetData, UnusedErrorMessage ); const bool FactoryWorks = FactoryWorksWithAsset || FactoryWorksWithoutAsset; if ( FactoryWorks ) { FMenuItem MenuItem = FMenuItem( Factory, NoAssetData ); if ( FactoryWorksWithAsset ) { MenuItem = FMenuItem( Factory, AssetData ); } if ( FactoryWorksWithAsset || ( !ExcludeStandAloneFactories && FactoryWorksWithoutAsset ) ) { OutMenuItems->Add( MenuItem ); } } } }
void SAssetDialog::OnAssetSelected(const FAssetData& AssetData) { CurrentlySelectedAssets = GetCurrentSelectionDelegate.Execute(); if ( AssetData.IsValid() ) { SetCurrentlySelectedPath(AssetData.PackagePath.ToString()); SetCurrentlyEnteredAssetName(AssetData.AssetName.ToString()); } }
bool UVoreealBasicVolumeActorFactory::CanCreateActorFrom(const FAssetData& AssetData, FText& OutErrorMsg) { if (AssetData.IsValid() && AssetData.GetClass()->IsChildOf(UBasicVolume::StaticClass())) { return true; } else { OutErrorMsg = NSLOCTEXT("Voreeal", "CanCreateActorFrom_NoVoxelVolume", "No voxel volume was specified."); return false; } }
bool UPaperFlipbookActorFactory::CanCreateActorFrom(const FAssetData& AssetData, FText& OutErrorMsg) { if (AssetData.IsValid() && AssetData.GetClass()->IsChildOf(UPaperFlipbook::StaticClass())) { return true; } else { OutErrorMsg = NSLOCTEXT("Paper2D", "CanCreateActorFrom_NoFlipbook", "No flipbook was specified."); return false; } }
static bool CanCreateAnimBlueprint(const FAssetData& Skeleton, UClass const * ParentClass) { if (Skeleton.IsValid() && ParentClass != NULL) { if (UAnimBlueprintGeneratedClass const * GeneratedParent = Cast<const UAnimBlueprintGeneratedClass>(ParentClass)) { if (Skeleton.GetExportTextName() != FAssetData(GeneratedParent->GetTargetSkeleton()).GetExportTextName()) { return false; } } } return true; }
void FPrimaryAssetIdCustomization::OnSetObject(const FAssetData& AssetData) { UAssetManager& Manager = UAssetManager::Get(); if (StructPropertyHandle.IsValid() && StructPropertyHandle->IsValidHandle()) { FPrimaryAssetId AssetId; if (AssetData.IsValid()) { AssetId = Manager.GetPrimaryAssetIdForData(AssetData); ensure(AssetId.IsValid()); } StructPropertyHandle->SetValueFromFormattedString(AssetId.ToString()); } }
bool UTerrainSplineActorFactory::CanCreateActorFrom(const FAssetData& AssetData, FText& OutErrorMsg) { if (GetDefault<UPaperRuntimeSettings>()->bEnableTerrainSplineEditing) { if (AssetData.IsValid() && AssetData.GetClass()->IsChildOf(UPaperTerrainMaterial::StaticClass())) { return true; } else { return Super::CanCreateActorFrom(AssetData, OutErrorMsg); } } else { return false; } }
bool SPropertyEditorAsset::CanSetBasedOnCustomClasses( const FAssetData& InAssetData ) const { bool bAllowedToSetBasedOnFilter = true; if( InAssetData.IsValid() && CustomClassFilters.Num() > 0 ) { bAllowedToSetBasedOnFilter = false; UClass* AssetClass = InAssetData.GetClass(); for( const UClass* AllowedClass : CustomClassFilters ) { if( AssetClass->IsChildOf( AllowedClass ) ) { bAllowedToSetBasedOnFilter = true; break; } } } return bAllowedToSetBasedOnFilter; }
END_SLATE_FUNCTION_BUILD_OPTIMIZATION void SReflectorTreeWidgetItem::HandleHyperlinkNavigate() { FAssetData AssetData = WidgetInfo->GetWidgetAssetData(); if ( AssetData.IsValid() ) { if ( OnAccessAsset.IsBound() ) { AssetData.GetPackage(); OnAccessAsset.Execute(AssetData.GetAsset()); return; } } if ( OnAccessSourceCode.IsBound() ) { OnAccessSourceCode.Execute(GetWidgetFile(), GetWidgetLineNumber(), 0); } }
bool SPropertyEditorAsset::CanSetBasedOnCustomClasses( const FAssetData& InAssetData ) const { bool bAllowedToSetBasedOnFilter = true; if( InAssetData.IsValid() && CustomClassFilters.Num() > 0 ) { bAllowedToSetBasedOnFilter = false; UClass* AssetClass = InAssetData.GetClass(); for( const UClass* AllowedClass : CustomClassFilters ) { const bool bAllowedClassIsInterface = AllowedClass->HasAnyClassFlags(CLASS_Interface); if( AssetClass->IsChildOf( AllowedClass ) || (bAllowedClassIsInterface && AssetClass->ImplementsInterface(AllowedClass)) ) { bAllowedToSetBasedOnFilter = true; break; } } } return bAllowedToSetBasedOnFilter; }
TArray<FAssetData> ExtractAssetDataFromDrag(const TSharedPtr<FDragDropOperation>& Operation) { TArray<FAssetData> DroppedAssetData; if (!Operation.IsValid()) { return DroppedAssetData; } if (Operation->IsOfType<FExternalDragOperation>()) { TSharedPtr<FExternalDragOperation> DragDropOp = StaticCastSharedPtr<FExternalDragOperation>(Operation); if ( DragDropOp->HasText() ) { TArray<FString> DroppedAssetStrings; const TCHAR AssetDelimiter[] = { AssetMarshalDefs::AssetDelimiter, TEXT('\0') }; DragDropOp->GetText().ParseIntoArray(DroppedAssetStrings, AssetDelimiter, true); FAssetRegistryModule& AssetRegistryModule = FModuleManager::LoadModuleChecked<FAssetRegistryModule>(TEXT("AssetRegistry")); IAssetRegistry& AssetRegistry = AssetRegistryModule.Get(); for (int Index = 0; Index < DroppedAssetStrings.Num(); Index++) { // Truncate each string so that it doesn't exceed the maximum allowed length of characters to be converted to an FName FString TruncatedString = DroppedAssetStrings[ Index ].Left( NAME_SIZE ); FAssetData AssetData = AssetRegistry.GetAssetByObjectPath( FName( *TruncatedString ) ); if ( AssetData.IsValid() ) { DroppedAssetData.Add( AssetData ); } } } } else if (Operation->IsOfType<FAssetDragDropOp>()) { TSharedPtr<FAssetDragDropOp> DragDropOp = StaticCastSharedPtr<FAssetDragDropOp>( Operation ); DroppedAssetData.Append( DragDropOp->AssetData ); } return DroppedAssetData; }
void UEdGraphNode_Reference::CacheAssetData(const FAssetData& AssetData) { if ( AssetData.IsValid() ) { bUsesThumbnail = true; CachedAssetData = AssetData; } else { CachedAssetData = FAssetData(); bUsesThumbnail = false; if ( PackageNames.Num() == 1 ) { const FString PackageNameStr = PackageNames[0].ToString(); if ( FPackageName::IsValidLongPackageName(PackageNameStr, true) ) { if ( PackageNameStr.StartsWith(TEXT("/Script")) ) { CachedAssetData.AssetClass = FName(TEXT("Code")); } else { const FString PotentiallyMapFilename = FPackageName::LongPackageNameToFilename(PackageNameStr, FPackageName::GetMapPackageExtension()); const bool bIsMapPackage = FPlatformFileManager::Get().GetPlatformFile().FileExists(*PotentiallyMapFilename); if ( bIsMapPackage ) { CachedAssetData.AssetClass = FName(TEXT("World")); } } } } else { CachedAssetData.AssetClass = FName(TEXT("Multiple Nodes")); } } }
TArray<FAssetData> ExtractAssetDataFromDrag(const TSharedPtr<FDragDropOperation>& Operation) { TArray<FAssetData> DroppedAssetData; if (!Operation.IsValid()) { return DroppedAssetData; } if (Operation->IsOfType<FExternalDragOperation>()) { TSharedPtr<FExternalDragOperation> DragDropOp = StaticCastSharedPtr<FExternalDragOperation>(Operation); if ( DragDropOp->HasText() ) { TArray<FString> DroppedAssetStrings; const TCHAR AssetDelimiter[] = { AssetMarshalDefs::AssetDelimiter, TEXT('\0') }; DragDropOp->GetText().ParseIntoArray(DroppedAssetStrings, AssetDelimiter, true); FAssetRegistryModule& AssetRegistryModule = FModuleManager::LoadModuleChecked<FAssetRegistryModule>(TEXT("AssetRegistry")); IAssetRegistry& AssetRegistry = AssetRegistryModule.Get(); for (int Index = 0; Index < DroppedAssetStrings.Num(); Index++) { FAssetData AssetData = AssetRegistry.GetAssetByObjectPath( *DroppedAssetStrings[ Index ] ); if ( AssetData.IsValid() ) { DroppedAssetData.Add( AssetData ); } } } } else if (Operation->IsOfType<FAssetDragDropOp>()) { TSharedPtr<FAssetDragDropOp> DragDropOp = StaticCastSharedPtr<FAssetDragDropOp>( Operation ); DroppedAssetData.Append( DragDropOp->AssetData ); } return DroppedAssetData; }
void FPropertyEditor::OnAssetSelected( const FAssetData& AssetData ) { // Set the object found from the asset picker GetPropertyHandle()->SetValueFromFormattedString( AssetData.IsValid() ? AssetData.GetAsset()->GetPathName() : TEXT("None") ); }
virtual bool FixupObject(const FName& InObjectPath, FName& OutNewObjectPath) override { OutNewObjectPath = NAME_None; if (InObjectPath.ToString().StartsWith(TEXT("/Script/"))) { // We can't use FindObject while we're saving if (!GIsSavingPackage) { const FString ClassPathStr = InObjectPath.ToString(); UClass* FoundClass = FindObject<UClass>(ANY_PACKAGE, *ClassPathStr); if (!FoundClass) { // Use the linker to search for class name redirects (from the loaded ActiveClassRedirects) const FString ClassName = FPackageName::ObjectPathToObjectName(ClassPathStr); const FName NewClassName = FLinkerLoad::FindNewNameForClass(*ClassName, false); if (!NewClassName.IsNone()) { // Our new class name might be lacking the path, so try and find it so we can use the full path in the collection FoundClass = FindObject<UClass>(ANY_PACKAGE, *NewClassName.ToString()); if (FoundClass) { OutNewObjectPath = *FoundClass->GetPathName(); } } } } } else { // Keep track of visted redirectors in case we loop. TSet<FName> VisitedRedirectors; // Use the asset registry to avoid loading the object FAssetData ObjectAssetData = AssetRegistryModule.Get().GetAssetByObjectPath(InObjectPath); while (ObjectAssetData.IsValid() && ObjectAssetData.IsRedirector()) { // Check to see if we've already seen this path before, it's possible we might have found a redirector loop. if ( VisitedRedirectors.Contains(ObjectAssetData.ObjectPath) ) { UE_LOG(LogContentBrowser, Error, TEXT("Redirector Loop Found!")); for ( FName Redirector : VisitedRedirectors ) { UE_LOG(LogContentBrowser, Error, TEXT("Redirector: %s"), *Redirector.ToString()); } ObjectAssetData = FAssetData(); break; } VisitedRedirectors.Add(ObjectAssetData.ObjectPath); // Get the destination object from the meta-data rather than load the redirector object, as // loading a redirector will also load the object it points to, which could cause a large hitch FString DestinationObjectPath; if (ObjectAssetData.GetTagValue("DestinationObject", DestinationObjectPath)) { ConstructorHelpers::StripObjectClass(DestinationObjectPath); ObjectAssetData = AssetRegistryModule.Get().GetAssetByObjectPath(*DestinationObjectPath); } else { ObjectAssetData = FAssetData(); } } OutNewObjectPath = ObjectAssetData.ObjectPath; } return OutNewObjectPath != NAME_None && InObjectPath != OutNewObjectPath; }
void SSizeMap::GatherDependenciesRecursively( FAssetRegistryModule& AssetRegistryModule, TSharedPtr<FAssetThumbnailPool>& InAssetThumbnailPool, TMap<FName, TSharedPtr<FTreeMapNodeData>>& VisitedAssetPackageNames, const TArray<FName>& AssetPackageNames, const TSharedPtr<FTreeMapNodeData>& Node, TSharedPtr<FTreeMapNodeData>& SharedRootNode, int32& NumAssetsWhichFailedToLoad ) { for( const FName AssetPackageName : AssetPackageNames ) { // Have we already added this asset to the tree? If so, we'll either move it to a "shared" group or (if it's referenced again by the same // root-level asset) ignore it if( VisitedAssetPackageNames.Contains( AssetPackageName ) ) { // OK, we've determined that this asset has already been referenced by something else in our tree. We'll move it to a "shared" group // so all of the assets that are referenced in multiple places can be seen together. TSharedPtr<FTreeMapNodeData> ExistingNode = VisitedAssetPackageNames[ AssetPackageName ]; // Is the existing node not already under the "shared" group? Note that it might still be (indirectly) under // the "shared" group, in which case we'll still want to move it up to the root since we've figured out that it is // actually shared between multiple assets which themselves may be shared if( ExistingNode->Parent != SharedRootNode.Get() ) { // Don't bother moving any of the assets at the root level into a "shared" bucket. We're only trying to best // represent the memory used when all of the root-level assets have become loaded. It's OK if root-level assets // are referenced by other assets in the set -- we don't need to indicate they are shared explicitly FTreeMapNodeData* ExistingNodeParent = ExistingNode->Parent; check( ExistingNodeParent != nullptr ); const bool bExistingNodeIsAtRootLevel = ExistingNodeParent->Parent == nullptr || RootAssetPackageNames.Contains( AssetPackageName ); if( !bExistingNodeIsAtRootLevel ) { // OK, the current asset (AssetPackageName) is definitely not a root level asset, but its already in the tree // somewhere as a non-shared, non-root level asset. We need to make sure that this Node's reference is not from the // same root-level asset as the ExistingNodeInTree. Otherwise, there's no need to move it to a 'shared' group. FTreeMapNodeData* MyParentNode = Node.Get(); check( MyParentNode != nullptr ); FTreeMapNodeData* MyRootLevelAssetNode = MyParentNode; while( MyRootLevelAssetNode->Parent != nullptr && MyRootLevelAssetNode->Parent->Parent != nullptr ) { MyRootLevelAssetNode = MyRootLevelAssetNode->Parent; } if( MyRootLevelAssetNode->Parent == nullptr ) { // No root asset (Node must be a root level asset itself!) MyRootLevelAssetNode = nullptr; } // Find the existing node's root level asset node FTreeMapNodeData* ExistingNodeRootLevelAssetNode = ExistingNodeParent; while( ExistingNodeRootLevelAssetNode->Parent->Parent != nullptr ) { ExistingNodeRootLevelAssetNode = ExistingNodeRootLevelAssetNode->Parent; } // If we're being referenced by another node within the same asset, no need to move it to a 'shared' group. if( MyRootLevelAssetNode != ExistingNodeRootLevelAssetNode ) { // This asset was already referenced by something else (or was in our top level list of assets to display sizes for) if( !SharedRootNode.IsValid() ) { // Find the root-most tree node FTreeMapNodeData* RootNode = MyParentNode; while( RootNode->Parent != nullptr ) { RootNode = RootNode->Parent; } SharedRootNode = MakeShareable( new FTreeMapNodeData() ); RootNode->Children.Add( SharedRootNode ); SharedRootNode->Parent = RootNode; // Keep back-pointer to parent node } // Reparent the node that we've now determined to be shared ExistingNode->Parent->Children.Remove( ExistingNode ); SharedRootNode->Children.Add( ExistingNode ); ExistingNode->Parent = SharedRootNode.Get(); } } } } else { // This asset is new to us so far! Let's add it to the tree. Later as we descend through references, we might find that the // asset is referenced by something else as well, in which case we'll pull it out and move it to a "shared" top-level box // Don't bother showing code references const FString AssetPackageNameString = AssetPackageName.ToString(); if( !AssetPackageNameString.StartsWith( TEXT( "/Script/" ) ) ) { FTreeMapNodeDataRef ChildTreeMapNode = MakeShareable( new FTreeMapNodeData() ); Node->Children.Add( ChildTreeMapNode ); ChildTreeMapNode->Parent = Node.Get(); // Keep back-pointer to parent node VisitedAssetPackageNames.Add( AssetPackageName, ChildTreeMapNode ); FNodeSizeMapData& NodeSizeMapData = NodeSizeMapDataMap.Add( ChildTreeMapNode ); // Set some defaults for this node. These will be used if we can't actually locate the asset. // @todo sizemap urgent: We need a better indication in the UI when there are one or more missing assets. Because missing assets have a size // of zero, they are nearly impossible to zoom into. At the least, we should have some Output Log spew when assets cannot be loaded NodeSizeMapData.AssetData.AssetName = AssetPackageName; NodeSizeMapData.AssetData.AssetClass = FName( *LOCTEXT( "MissingAsset", "MISSING!" ).ToString() ); NodeSizeMapData.AssetSize = 0; NodeSizeMapData.bHasKnownSize = false; // Find the asset using the asset registry // @todo sizemap: Asset registry-based reference gathering is faster but possibly not as exhaustive (no PostLoad created references, etc.) Maybe should be optional? // @todo sizemap: With AR-based reference gathering, sometimes the size map is missing root level dependencies until you reopen it a few times (Buggy BP) // @todo sizemap: With AR-based reference gathering, reference changes at editor-time do not appear in the Size Map until you restart // @todo sizemap: With AR-based reference gathering, opening the size map for all engine content caused the window to not respond until a restart // @todo sizemap: We don't really need the asset registry given we need to load the objects to figure out their size, unless we make that AR-searchable. // ---> This would allow us to not have to wait for AR initialization. But if we made size AR-searchable, we could run very quickly for large data sets! const bool bUseAssetRegistryForDependencies = false; const FString AssetPathString = AssetPackageNameString + TEXT(".") + FPackageName::GetLongPackageAssetName( AssetPackageNameString ); const FAssetData FoundAssetData = AssetRegistryModule.Get().GetAssetByObjectPath( FName( *AssetPathString ) ); if( FoundAssetData.IsValid() ) { NodeSizeMapData.AssetData = FoundAssetData; // Now actually load up the asset. We need it in memory in order to accurately determine its size. // @todo sizemap: We could async load these packages to make the editor experience a bit nicer (smoother progress) UObject* Asset = StaticLoadObject( UObject::StaticClass(), nullptr, *AssetPathString ); if( Asset != nullptr ) { TArray<FName> ReferencedAssetPackageNames; if( bUseAssetRegistryForDependencies ) { AssetRegistryModule.Get().GetDependencies( AssetPackageName, ReferencedAssetPackageNames ); } else { SizeMapInternals::FAssetReferenceFinder References( Asset ); for( UObject* Object : References.GetReferencedAssets() ) { ReferencedAssetPackageNames.Add( FName( *Object->GetOutermost()->GetPathName() ) ); } } // For textures, make sure we're getting the worst case size, not the size of the currently loaded set of mips // @todo sizemap: We should instead have a special EResourceSizeMode that asks for the worst case size. Some assets (like UTextureCube) currently always report resident mip size, even when asked for inclusive size if( Asset->IsA( UTexture2D::StaticClass() ) ) { NodeSizeMapData.AssetSize = Asset->GetResourceSize( EResourceSizeMode::Inclusive ); } else { NodeSizeMapData.AssetSize = Asset->GetResourceSize( EResourceSizeMode::Exclusive ); } NodeSizeMapData.bHasKnownSize = NodeSizeMapData.AssetSize != UObject::RESOURCE_SIZE_NONE && NodeSizeMapData.AssetSize != 0; if( !NodeSizeMapData.bHasKnownSize ) { // Asset has no meaningful size NodeSizeMapData.AssetSize = 0; // @todo sizemap urgent: Try to serialize to figure out how big it is (not into sub-assets though!) // FObjectMemoryAnalyzer ObjectMemoryAnalyzer( Asset ); } // Now visit all of the assets that we are referencing GatherDependenciesRecursively( AssetRegistryModule, InAssetThumbnailPool, VisitedAssetPackageNames, ReferencedAssetPackageNames, ChildTreeMapNode, SharedRootNode, NumAssetsWhichFailedToLoad ); } else { ++NumAssetsWhichFailedToLoad; } } else { ++NumAssetsWhichFailedToLoad; } } } } }