/** * Duplicates the asset */ void DuplicateAsset() { if (AssetPackage && CreatedAsset) { const FString NewObjectName = FString::Printf(TEXT("%s_Copy"), *AssetName); const FString NewPackageName = FString::Printf(TEXT("%s/%s"), *GetGamePath(), *NewObjectName); // Make sure the referenced object is deselected before duplicating it. GEditor->GetSelectedObjects()->Deselect(CreatedAsset); // Duplicate the asset DuplicatedPackage = CreatePackage(NULL, *NewPackageName); DuplicatedAsset = StaticDuplicateObject(CreatedAsset, DuplicatedPackage, *NewObjectName); if (DuplicatedAsset) { DuplicatedAsset->MarkPackageDirty(); // Notify the asset registry FAssetRegistryModule::AssetCreated(DuplicatedAsset); TestStats->NumDuplicated++; UE_LOG(LogEditorAssetAutomationTests, Display, TEXT("Duplicated asset %s to %s (%s)"), *AssetName, *NewObjectName, *Class->GetName()); } else { UE_LOG(LogEditorAssetAutomationTests, Error, TEXT("Failed to duplicate asset %s (%s)"), *AssetName, *Class->GetName()); } } }
void FAssetTypeActions_TextureRenderTarget::ExecuteCreateStatic(TArray<TWeakObjectPtr<UTextureRenderTarget>> Objects) { for (auto ObjIt = Objects.CreateConstIterator(); ObjIt; ++ObjIt) { auto Object = (*ObjIt).Get(); if ( Object ) { FString Name; FString PackageName; CreateUniqueAssetName(Object->GetOutermost()->GetName(), TEXT("_Tex"), PackageName, Name); UObject* NewObj = NULL; UTextureRenderTarget2D* TexRT = Cast<UTextureRenderTarget2D>(Object); UTextureRenderTargetCube* TexRTCube = Cast<UTextureRenderTargetCube>(Object); if( TexRTCube ) { // create a static cube texture as well as its 6 faces NewObj = TexRTCube->ConstructTextureCube( CreatePackage(NULL,*PackageName), Name, Object->GetMaskedFlags() ); } else if( TexRT ) { // create a static 2d texture NewObj = TexRT->ConstructTexture2D( CreatePackage(NULL,*PackageName), Name, Object->GetMaskedFlags(), CTF_Default, NULL ); } if( NewObj ) { // package needs saving NewObj->MarkPackageDirty(); // Notify the asset registry FAssetRegistryModule::AssetCreated(NewObj); } } } }
/** * Nulls out references to a given object * * @param InObject - Object to null references to */ void NullReferencesToObject(UObject* InObject) { TArray<UObject*> ReplaceableObjects; TMap<UObject*, UObject*> ReplacementMap; ReplacementMap.Add(InObject, NULL); ReplacementMap.GenerateKeyArray(ReplaceableObjects); // Find all the properties (and their corresponding objects) that refer to any of the objects to be replaced TMap< UObject*, TArray<UProperty*> > ReferencingPropertiesMap; for (FObjectIterator ObjIter; ObjIter; ++ObjIter) { UObject* CurObject = *ObjIter; // Find the referencers of the objects to be replaced FFindReferencersArchive FindRefsArchive(CurObject, ReplaceableObjects); // Inform the object referencing any of the objects to be replaced about the properties that are being forcefully // changed, and store both the object doing the referencing as well as the properties that were changed in a map (so that // we can correctly call PostEditChange later) TMap<UObject*, int32> CurNumReferencesMap; TMultiMap<UObject*, UProperty*> CurReferencingPropertiesMMap; if (FindRefsArchive.GetReferenceCounts(CurNumReferencesMap, CurReferencingPropertiesMMap) > 0) { TArray<UProperty*> CurReferencedProperties; CurReferencingPropertiesMMap.GenerateValueArray(CurReferencedProperties); ReferencingPropertiesMap.Add(CurObject, CurReferencedProperties); for (TArray<UProperty*>::TConstIterator RefPropIter(CurReferencedProperties); RefPropIter; ++RefPropIter) { CurObject->PreEditChange(*RefPropIter); } } } // Iterate over the map of referencing objects/changed properties, forcefully replacing the references and then // alerting the referencing objects the change has completed via PostEditChange int32 NumObjsReplaced = 0; for (TMap< UObject*, TArray<UProperty*> >::TConstIterator MapIter(ReferencingPropertiesMap); MapIter; ++MapIter) { ++NumObjsReplaced; UObject* CurReplaceObj = MapIter.Key(); const TArray<UProperty*>& RefPropArray = MapIter.Value(); FArchiveReplaceObjectRef<UObject> ReplaceAr(CurReplaceObj, ReplacementMap, false, true, false); for (TArray<UProperty*>::TConstIterator RefPropIter(RefPropArray); RefPropIter; ++RefPropIter) { FPropertyChangedEvent PropertyEvent(*RefPropIter); CurReplaceObj->PostEditChangeProperty(PropertyEvent); } if (!CurReplaceObj->HasAnyFlags(RF_Transient) && CurReplaceObj->GetOutermost() != GetTransientPackage()) { if (!CurReplaceObj->RootPackageHasAnyFlags(PKG_CompiledIn)) { CurReplaceObj->MarkPackageDirty(); } } } }
void FNiagaraEditor::PasteNodesHere(const FVector2D& Location) { TSharedPtr<SGraphEditor> CurrentGraphEditor = NodeGraphEditorPtr.Pin(); if (!CurrentGraphEditor.IsValid()) { return; } // Undo/Redo support const FScopedTransaction Transaction(FGenericCommands::Get().Paste->GetDescription()); UEdGraph* EdGraph = Cast<UEdGraph>(CurrentGraphEditor->GetCurrentGraph()); EdGraph->Modify(); const FGraphPanelSelectionSet SelectedNodes = CurrentGraphEditor->GetSelectedNodes(); // Clear the selection set (newly pasted stuff will be selected) CurrentGraphEditor->ClearSelectionSet(); // Grab the text to paste from the clipboard. FString TextToImport; FPlatformMisc::ClipboardPaste(TextToImport); // Import the nodes TSet<UEdGraphNode*> PastedNodes; FEdGraphUtilities::ImportNodesFromText(EdGraph, TextToImport, /*out*/ PastedNodes); //Average position of nodes so we can move them while still maintaining relative distances to each other FVector2D AvgNodePosition(0.0f, 0.0f); for (TSet<UEdGraphNode*>::TIterator It(PastedNodes); It; ++It) { UEdGraphNode* Node = (*It); if (Node) { AvgNodePosition.X += Node->NodePosX; AvgNodePosition.Y += Node->NodePosY; } } if (PastedNodes.Num() > 0) { float InvNumNodes = 1.0f / float(PastedNodes.Num()); AvgNodePosition.X *= InvNumNodes; AvgNodePosition.Y *= InvNumNodes; } for (TSet<UEdGraphNode*>::TIterator It(PastedNodes); It; ++It) { UEdGraphNode* PasteNode = (*It); if (PasteNode) { // Select the newly pasted stuff CurrentGraphEditor->SetNodeSelection(PasteNode, true); PasteNode->NodePosX = (PasteNode->NodePosX - AvgNodePosition.X) + Location.X; PasteNode->NodePosY = (PasteNode->NodePosY - AvgNodePosition.Y) + Location.Y; PasteNode->SnapToGrid(16); // Give new node a different Guid from the old one PasteNode->CreateNewGuid(); } } // Update UI CurrentGraphEditor->NotifyGraphChanged(); UObject* GraphOwner = EdGraph->GetOuter(); if (GraphOwner) { GraphOwner->PostEditChange(); GraphOwner->MarkPackageDirty(); } }
UObject* UFbxFactory::FactoryCreateBinary ( UClass* Class, UObject* InParent, FName Name, EObjectFlags Flags, UObject* Context, const TCHAR* Type, const uint8*& Buffer, const uint8* BufferEnd, FFeedbackContext* Warn, bool& bOutOperationCanceled ) { if( bOperationCanceled ) { bOutOperationCanceled = true; FEditorDelegates::OnAssetPostImport.Broadcast(this, NULL); return NULL; } FEditorDelegates::OnAssetPreImport.Broadcast(this, Class, InParent, Name, Type); UObject* NewObject = NULL; if ( bDetectImportTypeOnImport ) { if ( !DetectImportType(UFactory::CurrentFilename) ) { // Failed to read the file info, fail the import FEditorDelegates::OnAssetPostImport.Broadcast(this, NULL); return NULL; } } // logger for all error/warnings // this one prints all messages that are stored in FFbxImporter UnFbx::FFbxImporter* FbxImporter = UnFbx::FFbxImporter::GetInstance(); UnFbx::FFbxLoggerSetter Logger(FbxImporter); EFBXImportType ForcedImportType = FBXIT_StaticMesh; bool bIsObjFormat = false; if( FString(Type).Equals(TEXT("obj"), ESearchCase::IgnoreCase ) ) { bIsObjFormat = true; } bool bShowImportDialog = bShowOption && !GIsAutomationTesting; bool bImportAll = false; UnFbx::FBXImportOptions* ImportOptions = GetImportOptions(FbxImporter, ImportUI, bShowImportDialog, InParent->GetPathName(), bOperationCanceled, bImportAll, bIsObjFormat, bIsObjFormat, ForcedImportType ); bOutOperationCanceled = bOperationCanceled; if( bImportAll ) { // If the user chose to import all, we don't show the dialog again and use the same settings for each object until importing another set of files bShowOption = false; } // For multiple files, use the same settings bDetectImportTypeOnImport = false; if (ImportOptions) { Warn->BeginSlowTask( NSLOCTEXT("FbxFactory", "BeginImportingFbxMeshTask", "Importing FBX mesh"), true ); if ( !FbxImporter->ImportFromFile( *UFactory::CurrentFilename, Type ) ) { // Log the error message and fail the import. Warn->Log(ELogVerbosity::Error, FbxImporter->GetErrorMessage() ); } else { // Log the import message and import the mesh. const TCHAR* errorMessage = FbxImporter->GetErrorMessage(); if (errorMessage[0] != '\0') { Warn->Log( errorMessage ); } FbxNode* RootNodeToImport = NULL; RootNodeToImport = FbxImporter->Scene->GetRootNode(); // For animation and static mesh we assume there is at lease one interesting node by default int32 InterestingNodeCount = 1; TArray< TArray<FbxNode*>* > SkelMeshArray; bool bImportStaticMeshLODs = ImportUI->StaticMeshImportData->bImportMeshLODs; bool bCombineMeshes = ImportUI->bCombineMeshes; if ( ImportUI->MeshTypeToImport == FBXIT_SkeletalMesh ) { FbxImporter->FillFbxSkelMeshArrayInScene(RootNodeToImport, SkelMeshArray, false); InterestingNodeCount = SkelMeshArray.Num(); } else if( ImportUI->MeshTypeToImport == FBXIT_StaticMesh ) { FbxImporter->ApplyTransformSettingsToFbxNode(RootNodeToImport, ImportUI->StaticMeshImportData); if( bCombineMeshes && !bImportStaticMeshLODs ) { // If Combine meshes and dont import mesh LODs, the interesting node count should be 1 so all the meshes are grouped together into one static mesh InterestingNodeCount = 1; } else { // count meshes in lod groups if we dont care about importing LODs bool bCountLODGroupMeshes = !bImportStaticMeshLODs; int32 NumLODGroups = 0; InterestingNodeCount = FbxImporter->GetFbxMeshCount(RootNodeToImport,bCountLODGroupMeshes,NumLODGroups); // if there were LODs in the file, do not combine meshes even if requested if( bImportStaticMeshLODs && bCombineMeshes ) { bCombineMeshes = NumLODGroups == 0; } } } if (InterestingNodeCount > 1) { // the option only works when there are only one asset ImportOptions->bUsedAsFullName = false; } const FString Filename( UFactory::CurrentFilename ); if (RootNodeToImport && InterestingNodeCount > 0) { int32 NodeIndex = 0; int32 ImportedMeshCount = 0; UStaticMesh* NewStaticMesh = NULL; if ( ImportUI->MeshTypeToImport == FBXIT_StaticMesh ) // static mesh { if (bCombineMeshes) { TArray<FbxNode*> FbxMeshArray; FbxImporter->FillFbxMeshArray(RootNodeToImport, FbxMeshArray, FbxImporter); if (FbxMeshArray.Num() > 0) { NewStaticMesh = FbxImporter->ImportStaticMeshAsSingle(InParent, FbxMeshArray, Name, Flags, ImportUI->StaticMeshImportData, NULL, 0); } ImportedMeshCount = NewStaticMesh ? 1 : 0; } else { TArray<UObject*> AllNewAssets; UObject* Object = RecursiveImportNode(FbxImporter,RootNodeToImport,InParent,Name,Flags,NodeIndex,InterestingNodeCount, AllNewAssets); NewStaticMesh = Cast<UStaticMesh>( Object ); // Make sure to notify the asset registry of all assets created other than the one returned, which will notify the asset registry automatically. for ( auto AssetIt = AllNewAssets.CreateConstIterator(); AssetIt; ++AssetIt ) { UObject* Asset = *AssetIt; if ( Asset != NewStaticMesh ) { FAssetRegistryModule::AssetCreated(Asset); Asset->MarkPackageDirty(); } } ImportedMeshCount = AllNewAssets.Num(); } // Importing static mesh sockets only works if one mesh is being imported if( ImportedMeshCount == 1 && NewStaticMesh ) { FbxImporter->ImportStaticMeshSockets( NewStaticMesh ); } NewObject = NewStaticMesh; } else if ( ImportUI->MeshTypeToImport == FBXIT_SkeletalMesh )// skeletal mesh { int32 TotalNumNodes = 0; for (int32 i = 0; i < SkelMeshArray.Num(); i++) { TArray<FbxNode*> NodeArray = *SkelMeshArray[i]; TotalNumNodes += NodeArray.Num(); // check if there is LODGroup for this skeletal mesh int32 MaxLODLevel = 1; for (int32 j = 0; j < NodeArray.Num(); j++) { FbxNode* Node = NodeArray[j]; if (Node->GetNodeAttribute() && Node->GetNodeAttribute()->GetAttributeType() == FbxNodeAttribute::eLODGroup) { // get max LODgroup level if (MaxLODLevel < Node->GetChildCount()) { MaxLODLevel = Node->GetChildCount(); } } } int32 LODIndex; bool bImportSkeletalMeshLODs = ImportUI->SkeletalMeshImportData->bImportMeshLODs; for (LODIndex = 0; LODIndex < MaxLODLevel; LODIndex++) { if ( !bImportSkeletalMeshLODs && LODIndex > 0) // not import LOD if UI option is OFF { break; } TArray<FbxNode*> SkelMeshNodeArray; for (int32 j = 0; j < NodeArray.Num(); j++) { FbxNode* Node = NodeArray[j]; if (Node->GetNodeAttribute() && Node->GetNodeAttribute()->GetAttributeType() == FbxNodeAttribute::eLODGroup) { if (Node->GetChildCount() > LODIndex) { SkelMeshNodeArray.Add(Node->GetChild(LODIndex)); } else // in less some LODGroups have less level, use the last level { SkelMeshNodeArray.Add(Node->GetChild(Node->GetChildCount() - 1)); } } else { SkelMeshNodeArray.Add(Node); } } if (LODIndex == 0 && SkelMeshNodeArray.Num() != 0) { FName OutputName = FbxImporter->MakeNameForMesh(Name.ToString(), SkelMeshNodeArray[0]); USkeletalMesh* NewMesh = FbxImporter->ImportSkeletalMesh( InParent, SkelMeshNodeArray, OutputName, Flags, ImportUI->SkeletalMeshImportData, &bOperationCanceled ); NewObject = NewMesh; if(bOperationCanceled) { // User cancelled, clean up and return FbxImporter->ReleaseScene(); Warn->EndSlowTask(); bOperationCanceled = true; return nullptr; } if ( NewMesh && ImportUI->bImportAnimations ) { // We need to remove all scaling from the root node before we set up animation data. // Othewise some of the global transform calculations will be incorrect. FbxImporter->RemoveTransformSettingsFromFbxNode(RootNodeToImport, ImportUI->SkeletalMeshImportData); FbxImporter->SetupAnimationDataFromMesh(NewMesh, InParent, SkelMeshNodeArray, ImportUI->AnimSequenceImportData, OutputName.ToString()); // Reapply the transforms for the rest of the import FbxImporter->ApplyTransformSettingsToFbxNode(RootNodeToImport, ImportUI->SkeletalMeshImportData); } } else if (NewObject) // the base skeletal mesh is imported successfully { USkeletalMesh* BaseSkeletalMesh = Cast<USkeletalMesh>(NewObject); FName LODObjectName = NAME_None; USkeletalMesh *LODObject = FbxImporter->ImportSkeletalMesh( GetTransientPackage(), SkelMeshNodeArray, LODObjectName, RF_NoFlags, ImportUI->SkeletalMeshImportData, &bOperationCanceled ); bool bImportSucceeded = !bOperationCanceled && FbxImporter->ImportSkeletalMeshLOD(LODObject, BaseSkeletalMesh, LODIndex, false); if (bImportSucceeded) { BaseSkeletalMesh->LODInfo[LODIndex].ScreenSize = 1.0f / (MaxLODLevel * LODIndex); } else { FbxImporter->AddTokenizedErrorMessage(FTokenizedMessage::Create(EMessageSeverity::Error, LOCTEXT("FailedToImport_SkeletalMeshLOD", "Failed to import Skeletal mesh LOD.")), FFbxErrors::SkeletalMesh_LOD_FailedToImport); } } // import morph target if ( NewObject && ImportUI->SkeletalMeshImportData->bImportMorphTargets) { // Disable material importing when importing morph targets uint32 bImportMaterials = ImportOptions->bImportMaterials; ImportOptions->bImportMaterials = 0; FbxImporter->ImportFbxMorphTarget(SkelMeshNodeArray, Cast<USkeletalMesh>(NewObject), InParent, LODIndex); ImportOptions->bImportMaterials = !!bImportMaterials; } } if (NewObject) { NodeIndex++; FFormatNamedArguments Args; Args.Add( TEXT("NodeIndex"), NodeIndex ); Args.Add( TEXT("ArrayLength"), SkelMeshArray.Num() ); GWarn->StatusUpdate( NodeIndex, SkelMeshArray.Num(), FText::Format( NSLOCTEXT("UnrealEd", "Importingf", "Importing ({NodeIndex} of {ArrayLength})"), Args ) ); } } for (int32 i = 0; i < SkelMeshArray.Num(); i++) { delete SkelMeshArray[i]; } // if total nodes we found is 0, we didn't find anything. if (TotalNumNodes == 0) { FbxImporter->AddTokenizedErrorMessage(FTokenizedMessage::Create(EMessageSeverity::Error, LOCTEXT("FailedToImport_NoMeshFoundOnRoot", "Could not find any valid mesh on the root hierarchy. If you have mesh in the sub hierarchy, please enable option of [Import Meshes In Bone Hierarchy] when import.")), FFbxErrors::SkeletalMesh_NoMeshFoundOnRoot); } } else if ( ImportUI->MeshTypeToImport == FBXIT_Animation )// animation { if (ImportOptions->SkeletonForAnimation) { // will return the last animation sequence that were added NewObject = UEditorEngine::ImportFbxAnimation( ImportOptions->SkeletonForAnimation, InParent, ImportUI->AnimSequenceImportData, *Filename, *Name.ToString(), true ); } } } else { if (RootNodeToImport == NULL) { FbxImporter->AddTokenizedErrorMessage(FTokenizedMessage::Create(EMessageSeverity::Error, LOCTEXT("FailedToImport_InvalidRoot", "Could not find root node.")), FFbxErrors::SkeletalMesh_InvalidRoot); } else if (ImportUI->MeshTypeToImport == FBXIT_SkeletalMesh) { FbxImporter->AddTokenizedErrorMessage(FTokenizedMessage::Create(EMessageSeverity::Error, LOCTEXT("FailedToImport_InvalidBone", "Failed to find any bone hierarchy. Try disabling the \"Import As Skeletal\" option to import as a rigid mesh. ")), FFbxErrors::SkeletalMesh_InvalidBone); } else { FbxImporter->AddTokenizedErrorMessage(FTokenizedMessage::Create(EMessageSeverity::Error, LOCTEXT("FailedToImport_InvalidNode", "Could not find any node.")), FFbxErrors::SkeletalMesh_InvalidNode); } } } if (NewObject == NULL) { FbxImporter->AddTokenizedErrorMessage(FTokenizedMessage::Create(EMessageSeverity::Error, LOCTEXT("FailedToImport_NoObject", "Import failed.")), FFbxErrors::Generic_ImportingNewObjectFailed); } FbxImporter->ReleaseScene(); Warn->EndSlowTask(); } FEditorDelegates::OnAssetPostImport.Broadcast(this, NewObject); return NewObject; }
void FContentDirectoryMonitor::ProcessModifications(const DirectoryWatcher::FTimeLimit& TimeLimit, TArray<UPackage*>& OutPackagesToSave, FReimportFeedbackContext& Context) { auto* ReimportManager = FReimportManager::Instance(); for (int32 Index = 0; Index < ModifiedFiles.Num(); ++Index) { Context.MainTask->EnterProgressFrame(); auto& Change = ModifiedFiles[Index]; const FString FullFilename = Cache.GetDirectory() + Change.Filename.Get(); // Move the asset before reimporting it. We always reimport moved assets to ensure that their import path is up to date if (Change.Action == DirectoryWatcher::EFileAction::Moved) { const FString OldFilename = Cache.GetDirectory() + Change.MovedFromFilename.Get(); const auto Assets = Utils::FindAssetsPertainingToFile(*Registry, OldFilename); if (Assets.Num() == 1) { UObject* Asset = Assets[0].GetAsset(); if (Asset && Utils::ExtractSourceFilePaths(Asset).Num() == 1) { UPackage* ExistingPackage = Asset->GetOutermost(); const bool bAssetWasDirty = IsAssetDirty(Asset); const FString NewAssetName = ObjectTools::SanitizeObjectName(FPaths::GetBaseFilename(Change.Filename.Get())); const FString PackagePath = PackageTools::SanitizePackageName(MountedContentPath / FPaths::GetPath(Change.Filename.Get())); const FString FullDestPath = PackagePath / NewAssetName; if (ExistingPackage && ExistingPackage->FileName.ToString() == FullDestPath) { // No need to process this asset - it's already been moved to the right location Cache.CompleteTransaction(MoveTemp(Change)); continue; } const FText SrcPathText = FText::FromString(Assets[0].PackageName.ToString()), DstPathText = FText::FromString(FullDestPath); if (FPackageName::DoesPackageExist(*FullDestPath)) { Context.AddMessage(EMessageSeverity::Warning, FText::Format(LOCTEXT("MoveWarning_ExistingAsset", "Can't move {0} to {1} - one already exists."), SrcPathText, DstPathText)); } else { TArray<FAssetRenameData> RenameData; RenameData.Emplace(Asset, PackagePath, NewAssetName); Context.AddMessage(EMessageSeverity::Info, FText::Format(LOCTEXT("Success_MovedAsset", "Moving asset {0} to {1}."), SrcPathText, DstPathText)); FModuleManager::LoadModuleChecked<FAssetToolsModule>("AssetTools").Get().RenameAssets(RenameData); TArray<FString> Filenames; Filenames.Add(FullFilename); // Update the reimport file names FReimportManager::Instance()->UpdateReimportPaths(Asset, Filenames); Asset->MarkPackageDirty(); if (!bAssetWasDirty) { OutPackagesToSave.Add(Asset->GetOutermost()); } } } } } else { // Modifications or additions are treated the same by this point for (const auto& AssetData : Utils::FindAssetsPertainingToFile(*Registry, FullFilename)) { if (UObject* Asset = AssetData.GetAsset()) { ReimportAsset(Asset, FullFilename, OutPackagesToSave, Context); } } } // Let the cache know that we've dealt with this change Cache.CompleteTransaction(MoveTemp(Change)); if (TimeLimit.Exceeded()) { ModifiedFiles.RemoveAt(0, Index + 1); return; } } ModifiedFiles.Empty(); }
UObject* UFactory::StaticImportObject ( UClass* Class, UObject* InOuter, FName Name, EObjectFlags Flags, bool& bOutOperationCanceled, const TCHAR* Filename, UObject* Context, UFactory* InFactory, const TCHAR* Parms, FFeedbackContext* Warn, int32 MaxImportFileSize ) { check(Class); CurrentFilename = Filename; // Make list of all applicable factories. TArray<UFactory*> Factories; if( InFactory ) { // Use just the specified factory. if (ensureMsgf( !InFactory->SupportedClass || Class->IsChildOf(InFactory->SupportedClass), TEXT("Factory is (%s), SupportedClass is (%s) and Class name is (%s)"), *InFactory->GetName(), (InFactory->SupportedClass)? *InFactory->SupportedClass->GetName() : TEXT("None"), *Class->GetName() )) { Factories.Add( InFactory ); } } else { auto TransientPackage = GetTransientPackage(); // Try all automatic factories, sorted by priority. for( TObjectIterator<UClass> It; It; ++It ) { if( It->IsChildOf( UFactory::StaticClass() ) ) { UFactory* Default = It->GetDefaultObject<UFactory>(); if (Class->IsChildOf(Default->SupportedClass) && Default->ImportPriority >= 0) { Factories.Add(NewObject<UFactory>(TransientPackage, *It)); } } } Factories.Sort([](const UFactory& A, const UFactory& B) -> bool { // First sort so that higher priorities are earlier in the list if( A.ImportPriority > B.ImportPriority ) { return true; } else if( A.ImportPriority < B.ImportPriority ) { return false; } // Then sort so that factories that only create new assets are tried after those that actually import the file data (when they have an equivalent priority) const bool bFactoryAImportsFiles = !A.CanCreateNew(); const bool bFactoryBImportsFiles = !B.CanCreateNew(); if( bFactoryAImportsFiles && !bFactoryBImportsFiles ) { return true; } return false; }); } bool bLoadedFile = false; // Try each factory in turn. for( int32 i=0; i<Factories.Num(); i++ ) { UFactory* Factory = Factories[i]; UObject* Result = NULL; if( Factory->CanCreateNew() ) { UE_LOG(LogFactory, Log, TEXT("FactoryCreateNew: %s with %s (%i %i %s)"), *Class->GetName(), *Factories[i]->GetClass()->GetName(), Factory->bCreateNew, Factory->bText, Filename ); Factory->ParseParms( Parms ); Result = Factory->FactoryCreateNew( Class, InOuter, Name, Flags, NULL, Warn ); } else if( FCString::Stricmp(Filename,TEXT(""))!=0 ) { if( Factory->bText ) { //UE_LOG(LogFactory, Log, TEXT("FactoryCreateText: %s with %s (%i %i %s)"), *Class->GetName(), *Factories(i)->GetClass()->GetName(), Factory->bCreateNew, Factory->bText, Filename ); FString Data; if( FFileHelper::LoadFileToString( Data, Filename ) ) { bLoadedFile = true; const TCHAR* Ptr = *Data; Factory->ParseParms( Parms ); Result = Factory->FactoryCreateText( Class, InOuter, Name, Flags, NULL, *FPaths::GetExtension(Filename), Ptr, Ptr+Data.Len(), Warn ); } } else { UE_LOG(LogFactory, Log, TEXT("FactoryCreateBinary: %s with %s (%i %i %s)"), *Class->GetName(), *Factories[i]->GetClass()->GetName(), Factory->bCreateNew, Factory->bText, Filename ); // Sanity check the file size of the impending import and prompt the user if they wish to continue if the file size is very large const int32 FileSize = IFileManager::Get().FileSize( Filename ); bool bValidFileSize = true; if ( FileSize == INDEX_NONE ) { UE_LOG(LogFactory, Error,TEXT("File '%s' does not exist"), Filename ); bValidFileSize = false; } TArray<uint8> Data; if( bValidFileSize && FFileHelper::LoadFileToArray( Data, Filename ) ) { bLoadedFile = true; Data.Add( 0 ); const uint8* Ptr = &Data[ 0 ]; Factory->ParseParms( Parms ); Result = Factory->FactoryCreateBinary( Class, InOuter, Name, Flags, NULL, *FPaths::GetExtension(Filename), Ptr, Ptr+Data.Num()-1, Warn, bOutOperationCanceled ); } } } if( Result ) { // prevent UTextureCube created from UTextureFactory check(Result->IsA(Class)); Result->MarkPackageDirty(); ULevel::LevelDirtiedEvent.Broadcast(); Result->PostEditChange(); CurrentFilename = TEXT(""); return Result; } } if ( !bLoadedFile && !bOutOperationCanceled ) { Warn->Logf( *FText::Format( NSLOCTEXT( "UnrealEd", "NoFindImport", "Can't find file '{0}' for import" ), FText::FromString( FString(Filename) ) ).ToString() ); } CurrentFilename = TEXT(""); return NULL; }