Example #1
0
UClass* FGraphNodeClassData::GetClass(bool bSilent)
{
	UClass* RetClass = Class.Get();
	if (RetClass == NULL && GeneratedClassPackage.Len())
	{
		GWarn->BeginSlowTask(LOCTEXT("LoadPackage", "Loading Package..."), true);

		UPackage* Package = LoadPackage(NULL, *GeneratedClassPackage, LOAD_NoRedirects);
		if (Package)
		{
			Package->FullyLoad();

			UObject* Object = FindObject<UObject>(Package, *AssetName);

			GWarn->EndSlowTask();

			UBlueprint* BlueprintOb = Cast<UBlueprint>(Object);
			RetClass = BlueprintOb ? *BlueprintOb->GeneratedClass :
				Object ? Object->GetClass() :
				NULL;

			Class = RetClass;
		}
		else
		{
			GWarn->EndSlowTask();

			if (!bSilent)
			{
				FMessageLog EditorErrors("EditorErrors");
				EditorErrors.Error(LOCTEXT("PackageLoadFail", "Package Load Failed"));
				EditorErrors.Info(FText::FromString(GeneratedClassPackage));
				EditorErrors.Notify(LOCTEXT("PackageLoadFail", "Package Load Failed"));
			}
		}
	}

	return RetClass;
}
	/**
	* Imports an object using a given factory
	*
	* @param ImportFactory - The factory to use to import the object
	* @param ObjectName - The name of the object to create
	* @param PackagePath - The full path of the package file to create
	* @param ImportPath - The path to the object to import
	*/
	UObject* ImportAssetUsingFactory(UFactory* ImportFactory, const FString& ObjectName, const FString& PackagePath, const FString& ImportPath)
	{
		UObject* ImportedAsset = NULL;

		UPackage* Pkg = CreatePackage(NULL, *PackagePath);
		if (Pkg)
		{
			// Make sure the destination package is loaded
			Pkg->FullyLoad();

			UClass* ImportAssetType = ImportFactory->ResolveSupportedClass();
			bool bDummy = false;

			//If we are a texture factory suppress some warning dialog that we don't want
			if (ImportFactory->IsA(UTextureFactory::StaticClass()))
			{
				UTextureFactory::SuppressImportOverwriteDialog();
			}

			ImportedAsset = UFactory::StaticImportObject(ImportAssetType, Pkg, FName(*ObjectName), RF_Public | RF_Standalone, bDummy, *ImportPath, NULL, ImportFactory, NULL, GWarn, 0);

			if (ImportedAsset)
			{
				UE_LOG(LogAutomationEditorCommon, Display, TEXT("Imported %s"), *ImportPath);
			}
			else
			{
				UE_LOG(LogAutomationEditorCommon, Error, TEXT("Failed to import asset using factory %s!"), *ImportFactory->GetName());
			}
		}
		else
		{
			UE_LOG(LogAutomationEditorCommon, Error, TEXT("Failed to create a package!"));
		}

		return ImportedAsset;
	}
bool UParticleSystemAuditCommandlet::ProcessParticleSystems()
{
	FAssetRegistryModule& AssetRegistryModule = FModuleManager::LoadModuleChecked<FAssetRegistryModule>(TEXT("AssetRegistry"));
	IAssetRegistry& AssetRegistry = AssetRegistryModule.Get();
	AssetRegistry.SearchAllAssets(true);

	TArray<FAssetData> AssetList;
	AssetRegistry.GetAssetsByClass(UParticleSystem::StaticClass()->GetFName(), AssetList);

	double StartProcessParticleSystemsTime = FPlatformTime::Seconds();

	// Find all level placed particle systems with:
	//	- Single LOD level
	//	- No fixed bounds
	//	- LODLevel Mismatch 
	//	- Kismet referenced & auto-activate set
	// Iterate over the list and check each system for *no* lod
	// 
	const FString DevelopersFolder = FPackageName::FilenameToLongPackageName(FPaths::GameDevelopersDir().LeftChop(1));
	FString LastPackageName = TEXT("");
	int32 PackageSwitches = 0;
	UPackage* CurrentPackage = NULL;
	for (const FAssetData& AssetIt : AssetList)
	{
		const FString PSysName = AssetIt.ObjectPath.ToString();
		const FString PackageName = AssetIt.PackageName.ToString();

		if ( PackageName.StartsWith(DevelopersFolder) )
		{
			// Skip developer folders
			continue;
		}

		if (PackageName != LastPackageName)
		{
			UPackage* Package = ::LoadPackage(NULL, *PackageName, LOAD_None);
			if (Package != NULL)
			{
				LastPackageName = PackageName;
				Package->FullyLoad();
				CurrentPackage = Package;
			}
			else
			{
				UE_LOG(LogParticleSystemAuditCommandlet, Warning, TEXT("Failed to load package %s processing %s"), *PackageName, *PSysName);
				CurrentPackage = NULL;
			}
		}

		const FString ShorterPSysName = AssetIt.AssetName.ToString();
		UParticleSystem* PSys = FindObject<UParticleSystem>(CurrentPackage, *ShorterPSysName);
		if (PSys != NULL)
		{
			bool bInvalidLOD = false;
			bool bSingleLOD = false;
			bool bFoundEmitter = false;
			bool bMissingMaterial = false;
			bool bHasHighSpawnRateOrBurst = false;
			bool bHasRibbonTrailOrBeam = false;
			for (int32 EmitterIdx = 0; EmitterIdx < PSys->Emitters.Num(); EmitterIdx++)
			{
				UParticleEmitter* Emitter = PSys->Emitters[EmitterIdx];
				if (Emitter != NULL)
				{
					if (Emitter->LODLevels.Num() == 0)
					{
						bInvalidLOD = true;
					}
					else if (Emitter->LODLevels.Num() == 1)
					{
						bSingleLOD = true;
					}
					bFoundEmitter = true;
					for (int32 LODIdx = 0; LODIdx < Emitter->LODLevels.Num(); LODIdx++)
					{
						UParticleLODLevel* LODLevel = Emitter->LODLevels[LODIdx];
						if (LODLevel != NULL)
						{
							if (LODLevel->RequiredModule != NULL)
							{
								if (LODLevel->RequiredModule->Material == NULL)
								{
									bMissingMaterial = true;
								}
							}

							if (Cast<UParticleModuleTypeDataRibbon>(LODLevel->TypeDataModule) ||
								Cast<UParticleModuleTypeDataBeam2>(LODLevel->TypeDataModule) ||
								Cast<UParticleModuleTypeDataAnimTrail>(LODLevel->TypeDataModule))
							{
								bHasRibbonTrailOrBeam = true;
							}

							for (int32 ModuleIdx = 0; ModuleIdx < LODLevel->Modules.Num(); ModuleIdx++)
							{
								UParticleModule* Module = LODLevel->Modules[ModuleIdx];

								if (UParticleModuleSpawn* SpawnModule = Cast<UParticleModuleSpawn>(Module))
								{
									if ( !bHasHighSpawnRateOrBurst )
									{
										if ( UDistributionFloatConstant* ConstantDistribution = Cast<UDistributionFloatConstant>(SpawnModule->Rate.Distribution) )
										{
											if ( ConstantDistribution->Constant > HighSpawnRateOrBurstThreshold )
											{
												bHasHighSpawnRateOrBurst = true;
											}
										}

										for ( const FParticleBurst& Burst : SpawnModule->BurstList )
										{
											if ( Burst.Count > HighSpawnRateOrBurstThreshold )
											{
												bHasHighSpawnRateOrBurst = true;
											}
										}
									}
								}
							}
						}
					}
				}
			}

			// Note all PSystems w/ a high constant spawn rate or burst count...
			if ( bHasHighSpawnRateOrBurst )
			{
				ParticleSystemsWithHighSpawnRateOrBurst.Add(PSys->GetPathName());
			}

			// Note all PSystems w/ a far LOD distance...
			for ( float LODDistance : PSys->LODDistances )
			{
				if (LODDistance > FarLODDistanceTheshold)
				{
					ParticleSystemsWithFarLODDistance.Add(PSys->GetPathName());
					break;
				}
			}

			// Note all PSystems w/ no emitters...
			if (PSys->Emitters.Num() == 0)
			{
				ParticleSystemsWithNoEmitters.Add(PSys->GetPathName());
			}

			// Note all missing material case PSystems...
			if (bMissingMaterial == true)
			{
				ParticleSystemsWithMissingMaterials.Add(PSys->GetPathName());
			}

			// Note all 0 LOD case PSystems...
			if (bInvalidLOD == true)
			{
				ParticleSystemsWithNoLODs.Add(PSys->GetPathName());
			}
			// Note all single LOD case PSystems...
			if (bSingleLOD == true)
			{
				ParticleSystemsWithSingleLOD.Add(PSys->GetPathName());
			}

			// Note all non-fixed bound PSystems, unless there is a ribbon, trail, or beam emitter...
			if (PSys->bUseFixedRelativeBoundingBox == false && !bHasRibbonTrailOrBeam)
			{
				ParticleSystemsWithoutFixedBounds.Add(PSys->GetPathName());
			}

			// Note all bOrientZAxisTowardCamera systems
			if (PSys->bOrientZAxisTowardCamera == true)
			{
				ParticleSystemsWithOrientZAxisTowardCamera.Add(PSys->GetPathName());
			}

			if ((PSys->LODMethod == PARTICLESYSTEMLODMETHOD_Automatic) &&
				(bInvalidLOD == false) && (bSingleLOD == false) &&
				(PSys->LODDistanceCheckTime == 0.0f))
			{
				ParticleSystemsWithBadLODCheckTimes.Add(PSys->GetPathName());
			}

			if (LastPackageName.Len() > 0)
			{
				if (LastPackageName != PSys->GetOutermost()->GetName())
				{
					LastPackageName = PSys->GetOutermost()->GetName();
					PackageSwitches++;
				}
			}
			else
			{
				LastPackageName = PSys->GetOutermost()->GetName();
			}

			if (PackageSwitches > 10)
			{
				::CollectGarbage(RF_Native);
				PackageSwitches = 0;
			}

		}
		else
		{
			UE_LOG(LogParticleSystemAuditCommandlet, Warning, TEXT("Failed to load particle system %s"), *PSysName);
		}
	}

	// Probably don't need to do this, but just in case we have any 'hanging' packages 
	// and more processing steps are added later, let's clean up everything...
	::CollectGarbage(RF_Native);

	double ProcessParticleSystemsTime = FPlatformTime::Seconds() - StartProcessParticleSystemsTime;
	UE_LOG(LogParticleSystemAuditCommandlet, Log, TEXT("Took %5.3f seconds to process referenced particle systems..."), ProcessParticleSystemsTime);

	return true;
}
FReply SPropertyEditorClass::OnDrop(const FGeometry& MyGeometry, const FDragDropEvent& DragDropEvent)
{
    TSharedPtr<FClassDragDropOp> ClassOperation = DragDropEvent.GetOperationAs<FClassDragDropOp>();
    if (ClassOperation.IsValid())
    {
        // We can only drop one item into the combo box, so drop the first one.
        FString AssetName = ClassOperation->ClassesToDrop[0]->GetName();

        // Set the property, it will be verified as valid.
        SendToObjects(AssetName);

        return FReply::Handled();
    }

    TSharedPtr<FUnloadedClassDragDropOp> UnloadedClassOp = DragDropEvent.GetOperationAs<FUnloadedClassDragDropOp>();
    if (UnloadedClassOp.IsValid())
    {
        // Check if the asset is loaded, used to see if the context menu should be available
        bool bAllAssetWereLoaded = true;

        TArray<FClassPackageData>& AssetArray = *(UnloadedClassOp->AssetsToDrop.Get());

        // We can only drop one item into the combo box, so drop the first one.
        FString& AssetName = AssetArray[0].AssetName;

        // Check to see if the asset can be found, otherwise load it.
        UObject* Object = FindObject<UObject>(NULL, *AssetName);
        if(Object == NULL)
        {
            // Check to see if the dropped asset was a blueprint
            const FString& PackageName = AssetArray[0].GeneratedPackageName;
            Object = FindObject<UObject>(NULL, *FString::Printf(TEXT("%s.%s"), *PackageName, *AssetName));

            if(Object == NULL)
            {
                // Load the package.
                GWarn->BeginSlowTask(LOCTEXT("OnDrop_LoadPackage", "Fully Loading Package For Drop"), true, false);
                UPackage* Package = LoadPackage(NULL, *PackageName, LOAD_NoRedirects );
                if(Package)
                {
                    Package->FullyLoad();
                }
                GWarn->EndSlowTask();

                Object = FindObject<UObject>(Package, *AssetName);
            }

            if(Object->IsA(UBlueprint::StaticClass()))
            {
                // Get the default object from the generated class.
                Object = Cast<UBlueprint>(Object)->GeneratedClass->GetDefaultObject();
            }
        }

        // Set the property, it will be verified as valid.
        SendToObjects(AssetName);

        return FReply::Handled();
    }

    return FReply::Unhandled();
}
Example #5
0
bool EngineUtils::FindOrLoadAssetsByPath(const FString& Path, TArray<UObject*>& OutAssets)
{
	if ( !FPackageName::IsValidLongPackageName(Path, true) )
	{
		return false;
	}

	// Convert the package path to a filename with no extension (directory)
	const FString FilePath = FPackageName::LongPackageNameToFilename(Path);

	// Gather the package files in that directory and subdirectories
	TArray<FString> Filenames;
	FPackageName::FindPackagesInDirectory(Filenames, FilePath);

	// Cull out map files
	for (int32 FilenameIdx = Filenames.Num() - 1; FilenameIdx >= 0; --FilenameIdx)
	{
		const FString Extension = FPaths::GetExtension(Filenames[FilenameIdx], true);
		if ( Extension == FPackageName::GetMapPackageExtension() )
		{
			Filenames.RemoveAt(FilenameIdx);
		}
	}

	// Load packages or find existing ones and fully load them
	TSet<UPackage*> Packages;
	for (int32 FileIdx = 0; FileIdx < Filenames.Num(); ++FileIdx)
	{
		const FString& Filename = Filenames[FileIdx];

		UPackage* Package = FindPackage(NULL, *FPackageName::FilenameToLongPackageName(Filename));

		if (Package)
		{
			Package->FullyLoad();
		}
		else
		{
			Package = LoadPackage(NULL, *Filename, LOAD_None);
		}

		if (Package)
		{
			Packages.Add(Package);
		}
	}

	// If any packages were successfully loaded, find all assets that were in the packages and add them to OutAssets
	if ( Packages.Num() > 0 )
	{
		for (FObjectIterator ObjIt; ObjIt; ++ObjIt)
		{
			if ( Packages.Contains(ObjIt->GetOutermost()) && ObjIt->IsAsset() )
			{
				OutAssets.Add(*ObjIt);
			}
		}
	}

	return true;
}
EReimportResult::Type UReimportFbxSceneFactory::ReimportStaticMesh(void* VoidFbxImporter, TSharedPtr<FFbxMeshInfo> MeshInfo)
{
	UnFbx::FFbxImporter* FbxImporter = (UnFbx::FFbxImporter*)VoidFbxImporter;
	//Find the UObject associate with this MeshInfo
	UPackage* PkgExist = LoadPackage(nullptr, *(MeshInfo->GetImportPath()), LOAD_Verify | LOAD_NoWarn);
	if (PkgExist != nullptr)
	{
		PkgExist->FullyLoad();
	}

	FString AssetName = MeshInfo->GetFullImportName();
	UStaticMesh* Mesh = FindObjectSafe<UStaticMesh>(ANY_PACKAGE, *AssetName);
	if (Mesh == nullptr)
	{
		//We reimport only static mesh here
		FbxImporter->AddTokenizedErrorMessage(FTokenizedMessage::Create(EMessageSeverity::Error, FText::Format(FText::FromString("Reimport Mesh {0} fail, the original staicmesh in the content browser cannot be load."), FText::FromString(MeshInfo->GetImportPath()))), FName(TEXT("Reimport Fbx Scene")));
		return EReimportResult::Failed;
	}
	
	//Copy default options to StaticMeshImportData
	SFbxSceneOptionWindow::CopyFbxOptionsToStaticMeshOptions(GlobalImportSettingsReference, SceneImportOptionsStaticMesh);
	SceneImportOptionsStaticMesh->FillStaticMeshInmportData(StaticMeshImportData, SceneImportOptions);

	UnFbx::FBXImportOptions* OverrideImportSettings = GetOptionsFromName(MeshInfo->OptionName);
	if (OverrideImportSettings != nullptr)
	{
		SFbxSceneOptionWindow::CopyFbxOptionsToFbxOptions(OverrideImportSettings, GlobalImportSettings);
		SFbxSceneOptionWindow::CopyFbxOptionsToStaticMeshOptions(OverrideImportSettings, SceneImportOptionsStaticMesh);
	}
	else
	{
		SFbxSceneOptionWindow::CopyFbxOptionsToFbxOptions(GlobalImportSettingsReference, GlobalImportSettings);
		SFbxSceneOptionWindow::CopyFbxOptionsToStaticMeshOptions(GlobalImportSettingsReference, SceneImportOptionsStaticMesh);
	}
	SceneImportOptionsStaticMesh->FillStaticMeshInmportData(StaticMeshImportData, SceneImportOptions);

	FbxImporter->ApplyTransformSettingsToFbxNode(FbxImporter->Scene->GetRootNode(), StaticMeshImportData);
	const TArray<UAssetUserData*>* UserData = Mesh->GetAssetUserDataArray();
	TArray<UAssetUserData*> UserDataCopy;
	if (UserData)
	{
		for (int32 Idx = 0; Idx < UserData->Num(); Idx++)
		{
			UserDataCopy.Add((UAssetUserData*)StaticDuplicateObject((*UserData)[Idx], GetTransientPackage()));
		}
	}

	// preserve settings in navcollision subobject
	UNavCollision* NavCollision = Mesh->NavCollision ?
		(UNavCollision*)StaticDuplicateObject(Mesh->NavCollision, GetTransientPackage()) :
		nullptr;

	// preserve extended bound settings
	const FVector PositiveBoundsExtension = Mesh->PositiveBoundsExtension;
	const FVector NegativeBoundsExtension = Mesh->NegativeBoundsExtension;
	Mesh = FbxImporter->ReimportSceneStaticMesh(MeshInfo->UniqueId, Mesh, StaticMeshImportData);
	if (Mesh != nullptr)
	{
		//Put back the new mesh data since the reimport is putting back the original import data
		SceneImportOptionsStaticMesh->FillStaticMeshInmportData(StaticMeshImportData, SceneImportOptions);
		Mesh->AssetImportData = StaticMeshImportData;

		// Copy user data to newly created mesh
		for (int32 Idx = 0; Idx < UserDataCopy.Num(); Idx++)
		{
			UserDataCopy[Idx]->Rename(nullptr, Mesh, REN_DontCreateRedirectors | REN_DoNotDirty);
			Mesh->AddAssetUserData(UserDataCopy[Idx]);
		}

		if (NavCollision)
		{
			Mesh->NavCollision = NavCollision;
			NavCollision->Rename(nullptr, Mesh, REN_DontCreateRedirectors | REN_DoNotDirty);
		}

		// Restore bounds extension settings
		Mesh->PositiveBoundsExtension = PositiveBoundsExtension;
		Mesh->NegativeBoundsExtension = NegativeBoundsExtension;

		Mesh->AssetImportData->Update(FbxImportFileName);

		// Try to find the outer package so we can dirty it up
		if (Mesh->GetOutermost())
		{
			Mesh->GetOutermost()->MarkPackageDirty();
		}
		else
		{
			Mesh->MarkPackageDirty();
		}
		AllNewAssets.Add(MeshInfo, Mesh);
		AssetToSyncContentBrowser.Add(Mesh);
	}
	else
	{
		return EReimportResult::Failed;
	}
	return EReimportResult::Succeeded;
}
UBlueprint *UReimportFbxSceneFactory::UpdateOriginalBluePrint(FString &BluePrintFullName, void* VoidNodeStatusMapPtr, TSharedPtr<FFbxSceneInfo> SceneInfoPtr, TSharedPtr<FFbxSceneInfo> SceneInfoOriginalPtr, TArray<FAssetData> &AssetDataToDelete)
{
	if (!SceneInfoPtr.IsValid() || VoidNodeStatusMapPtr == nullptr || !SceneInfoOriginalPtr.IsValid() || BluePrintFullName.IsEmpty())
	{
		return nullptr;
	}

	FbxSceneReimportStatusMapPtr NodeStatusMapPtr = (FbxSceneReimportStatusMapPtr)VoidNodeStatusMapPtr;
	//Find the BluePrint
	FAssetRegistryModule& AssetRegistryModule = FModuleManager::LoadModuleChecked<FAssetRegistryModule>("AssetRegistry");
	FAssetData BlueprintAssetData = AssetRegistryModule.Get().GetAssetByObjectPath(FName(*(BluePrintFullName)));
	UPackage* PkgExist = LoadPackage(nullptr, *BlueprintAssetData.PackageName.ToString(), LOAD_Verify | LOAD_NoWarn);
	if (PkgExist == nullptr)
	{
		return nullptr;
	}
	//Load the package before searching the asset
	PkgExist->FullyLoad();
	UBlueprint* BluePrint = FindObjectSafe<UBlueprint>(ANY_PACKAGE, *BluePrintFullName);
	if (BluePrint == nullptr)
	{
		return nullptr;
	}
	//Close all editor that edit this blueprint
	FAssetEditorManager::Get().CloseAllEditorsForAsset(BluePrint);
	//Set the import status for the next reimport
	for (TSharedPtr<FFbxNodeInfo> NodeInfo : SceneInfoPtr->HierarchyInfo)
	{
		if (!NodeStatusMapPtr->Contains(NodeInfo->NodeHierarchyPath))
			continue;
		EFbxSceneReimportStatusFlags NodeStatus = *(NodeStatusMapPtr->Find(NodeInfo->NodeHierarchyPath));
		NodeInfo->bImportNode = (NodeStatus & EFbxSceneReimportStatusFlags::ReimportAsset) != EFbxSceneReimportStatusFlags::None;
	}
	//Add back the component that was in delete state but no flag for reimport
	for (TSharedPtr<FFbxNodeInfo> OriginalNodeInfo : SceneInfoOriginalPtr->HierarchyInfo)
	{
		if (!NodeStatusMapPtr->Contains(OriginalNodeInfo->NodeHierarchyPath))
		{
			continue;
		}

		EFbxSceneReimportStatusFlags NodeStatus = *(NodeStatusMapPtr->Find(OriginalNodeInfo->NodeHierarchyPath));
		if (OriginalNodeInfo->bImportNode != true || (NodeStatus & EFbxSceneReimportStatusFlags::ReimportAsset) != EFbxSceneReimportStatusFlags::None)
		{
			continue;
		}

		//Clear the child
		OriginalNodeInfo->Childrens.Empty();

		//hook the node to the new hierarchy parent
		bool bFoundParent = false;
		if (OriginalNodeInfo->ParentNodeInfo.IsValid())
		{
			int32 InsertIndex = 0;
			for (TSharedPtr<FFbxNodeInfo> NodeInfo : SceneInfoPtr->HierarchyInfo)
			{
				InsertIndex++;
				if (NodeInfo->bImportNode && NodeInfo->NodeHierarchyPath.Compare(OriginalNodeInfo->ParentNodeInfo->NodeHierarchyPath) == 0)
				{
					OriginalNodeInfo->ParentNodeInfo = NodeInfo;
					NodeInfo->Childrens.Add(OriginalNodeInfo);
					SceneInfoPtr->HierarchyInfo.Insert(OriginalNodeInfo, InsertIndex);
					bFoundParent = true;
					break;
				}
			}
		}

		if (!bFoundParent)
		{
			//Insert after the root node
			OriginalNodeInfo->ParentNodeInfo = nullptr;
			SceneInfoPtr->HierarchyInfo.Insert(OriginalNodeInfo, 1);
		}
	}
	//Create a brand new actor with the correct component hierarchy then replace the existing blueprint
	//This function is using the bImportNode flag not the EFbxSceneReimportStatusFlags
	AActor *HierarchyActor = CreateActorComponentsHierarchy(SceneInfoPtr);
	if (HierarchyActor != nullptr)
	{
		//Modify the current blueprint to reflect the new actor
		//Clear all nodes by removing all root node
		TArray<USCS_Node*> BluePrintRootNodes = BluePrint->SimpleConstructionScript->GetRootNodes();
		for(USCS_Node* RootNode : BluePrintRootNodes)
		{
			RemoveChildNodeRecursively(BluePrint->SimpleConstructionScript, RootNode);
		}
		//Create the new nodes from the hierarchy actor
		FKismetEditorUtilities::AddComponentsToBlueprint(BluePrint, HierarchyActor->GetInstanceComponents());
		//Cleanup the temporary actor
		HierarchyActor->Destroy();

		BluePrint->Modify();
		BluePrint->PostEditChange();
		AssetToSyncContentBrowser.Add(BluePrint);
		return BluePrint;
	}
	return nullptr;
}
EReimportResult::Type UReimportFbxSceneFactory::Reimport(UObject* Obj)
{
	ReimportData = GetFbxSceneImportData(Obj);
	if (!ReimportData)
	{
		return EReimportResult::Failed;
	}

	//We will call other factory store the filename value since UFactory::CurrentFilename is static
	FbxImportFileName = ReimportData->SourceFbxFile;

	UnFbx::FFbxImporter* FbxImporter = UnFbx::FFbxImporter::GetInstance();
	UnFbx::FFbxLoggerSetter Logger(FbxImporter);
	GWarn->BeginSlowTask(NSLOCTEXT("FbxSceneReImportFactory", "BeginReImportingFbxSceneTask", "ReImporting FBX scene"), true);

	GlobalImportSettings = FbxImporter->GetImportOptions();

	//Fill the original options
	for (auto kvp : ReimportData->NameOptionsMap)
	{
		if (kvp.Key.Compare(DefaultOptionName) == 0)
		{
			SFbxSceneOptionWindow::CopyFbxOptionsToFbxOptions(kvp.Value, GlobalImportSettings);
			NameOptionsMap.Add(kvp.Key, GlobalImportSettings);
		}
		else
		{
			NameOptionsMap.Add(kvp.Key, kvp.Value);
		}
	}

	//Always convert the scene
	GlobalImportSettings->bConvertScene = true;
	GlobalImportSettings->bImportScene = ReimportData->bImportScene;

	//Read the fbx and store the hierarchy's information so we can reuse it after importing all the model in the fbx file
	if (!FbxImporter->ImportFromFile(*FbxImportFileName, FPaths::GetExtension(FbxImportFileName)))
	{
		// Log the error message and fail the import.
		GWarn->Log(ELogVerbosity::Error, FbxImporter->GetErrorMessage());
		FbxImporter->ReleaseScene();
		FbxImporter = nullptr;
		GWarn->EndSlowTask();
		return EReimportResult::Failed;
	}

	FString PackageName = "";
	Obj->GetOutermost()->GetName(PackageName);
	Path = FPaths::GetPath(PackageName);

	UnFbx::FbxSceneInfo SceneInfo;
	//Read the scene and found all instance with their scene information.
	FbxImporter->GetSceneInfo(FbxImportFileName, SceneInfo);

	//Convert old structure to the new scene export structure
	TSharedPtr<FFbxSceneInfo> SceneInfoPtr = ConvertSceneInfo(&SceneInfo);
	//Get import material info
	ExtractMaterialInfo(FbxImporter, SceneInfoPtr);

	if (!ReimportData->bCreateFolderHierarchy)
	{
		for (TSharedPtr<FFbxMeshInfo> MeshInfo : SceneInfoPtr->MeshInfo)
		{
			FString AssetName = Path + TEXT("/") + MeshInfo->Name;
			MeshInfo->SetOriginalImportPath(AssetName);
			FString OriginalFullImportName = PackageTools::SanitizePackageName(AssetName);
			OriginalFullImportName = OriginalFullImportName + TEXT(".") + PackageTools::SanitizePackageName(MeshInfo->Name);
			MeshInfo->SetOriginalFullImportName(OriginalFullImportName);
		}
	}
	else
	{
		TSet<uint64> AssetPathDone;
		FString AssetPath = Path;
		for (TSharedPtr<FFbxNodeInfo> NodeInfo : SceneInfoPtr->HierarchyInfo)
		{
			//Iterate the hierarchy and build the original path
			RecursivelyCreateOriginalPath(FbxImporter, NodeInfo, AssetPath, AssetPathDone);
		}
	}

	FillSceneHierarchyPath(SceneInfoPtr);

	FbxSceneReimportStatusMap MeshStatusMap;
	FbxSceneReimportStatusMap NodeStatusMap;
	bool bCanReimportHierarchy = ReimportData->HierarchyType == (int32)EFBXSceneOptionsCreateHierarchyType::FBXSOCHT_CreateBlueprint && !ReimportData->BluePrintFullName.IsEmpty();

	if (!GetFbxSceneReImportOptions(FbxImporter
		, SceneInfoPtr
		, ReimportData->SceneInfoSourceData
		, GlobalImportSettings
		, SceneImportOptions
		, SceneImportOptionsStaticMesh
		, NameOptionsMap
		, MeshStatusMap
		, NodeStatusMap
		, bCanReimportHierarchy
		, Path))
	{
		//User cancel the scene import
		FbxImporter->ReleaseScene();
		FbxImporter = nullptr;
		GlobalImportSettings = nullptr;
		GWarn->EndSlowTask();
		return EReimportResult::Cancelled;
	}
	
	GlobalImportSettingsReference = new UnFbx::FBXImportOptions();
	SFbxSceneOptionWindow::CopyFbxOptionsToFbxOptions(GlobalImportSettings, GlobalImportSettingsReference);

	//Overwrite the reimport asset data with the new data
	ReimportData->SceneInfoSourceData = SceneInfoPtr;
	ReimportData->SourceFbxFile = FPaths::ConvertRelativePathToFull(FbxImportFileName);
	ReimportData->bImportScene = GlobalImportSettingsReference->bImportScene;
	//Copy the options map
	ReimportData->NameOptionsMap.Reset();
	for (auto kvp : NameOptionsMap)
	{
		ReimportData->NameOptionsMap.Add(kvp.Key, kvp.Value);
	}

	FAssetRegistryModule& AssetRegistryModule = FModuleManager::LoadModuleChecked<FAssetRegistryModule>("AssetRegistry");
	TArray<FAssetData> AssetDataToDelete;
	for (TSharedPtr<FFbxMeshInfo> MeshInfo : SceneInfoPtr->MeshInfo)
	{
		//Delete all the delete asset
		if (!MeshStatusMap.Contains(MeshInfo->OriginalImportPath))
		{
			continue;
		}
		EFbxSceneReimportStatusFlags MeshStatus = *(MeshStatusMap.Find(MeshInfo->OriginalImportPath));
		if ((MeshStatus & EFbxSceneReimportStatusFlags::Removed) == EFbxSceneReimportStatusFlags::None || (MeshStatus & EFbxSceneReimportStatusFlags::ReimportAsset) == EFbxSceneReimportStatusFlags::None)
		{
			continue;
		}
		//Make sure we load all package that will be deleted
		UPackage* PkgExist = LoadPackage(nullptr, *(MeshInfo->GetImportPath()), LOAD_Verify | LOAD_NoWarn);
		if (PkgExist == nullptr)
		{
			continue;
		}
		PkgExist->FullyLoad();
		//Find the asset
		AssetDataToDelete.Add(AssetRegistryModule.Get().GetAssetByObjectPath(FName(*(MeshInfo->GetFullImportName()))));
	}

	AllNewAssets.Empty();
	AssetToSyncContentBrowser.Empty();
	EReimportResult::Type ReimportResult = EReimportResult::Succeeded;
	//Reimport and add asset
	for (TSharedPtr<FFbxMeshInfo> MeshInfo : SceneInfoPtr->MeshInfo)
	{
		if (!MeshStatusMap.Contains(MeshInfo->OriginalImportPath))
		{
			continue;
		}
		EFbxSceneReimportStatusFlags MeshStatus = *(MeshStatusMap.Find(MeshInfo->OriginalImportPath));
		
		//Set the import status for the next reimport
		MeshInfo->bImportAttribute = (MeshStatus & EFbxSceneReimportStatusFlags::ReimportAsset) != EFbxSceneReimportStatusFlags::None;
		
		if ((MeshStatus & EFbxSceneReimportStatusFlags::Removed) != EFbxSceneReimportStatusFlags::None ||
			(MeshStatus & EFbxSceneReimportStatusFlags::ReimportAsset) == EFbxSceneReimportStatusFlags::None)
		{
			continue;
		}

		if (((MeshStatus & EFbxSceneReimportStatusFlags::Same) != EFbxSceneReimportStatusFlags::None || (MeshStatus & EFbxSceneReimportStatusFlags::Added) != EFbxSceneReimportStatusFlags::None) &&
			(MeshStatus & EFbxSceneReimportStatusFlags::FoundContentBrowserAsset) != EFbxSceneReimportStatusFlags::None)
		{
			//Reimport over the old asset
			if (!MeshInfo->bIsSkelMesh)
			{
				ReimportResult = ReimportStaticMesh(FbxImporter, MeshInfo);
			}
			else
			{
				//TODO reimport skeletal mesh
			}
		}
		else if ((MeshStatus & EFbxSceneReimportStatusFlags::Added) != EFbxSceneReimportStatusFlags::None || (MeshStatus & EFbxSceneReimportStatusFlags::Same) != EFbxSceneReimportStatusFlags::None)
		{
			//Create a package for this node
			//Get Parent hierarchy name to create new package path
			ReimportResult = ImportStaticMesh(FbxImporter, MeshInfo, SceneInfoPtr);
		}
	}

	//Put back the default option in the static mesh import data, so next import will have those last import option
	SFbxSceneOptionWindow::CopyFbxOptionsToFbxOptions(GlobalImportSettingsReference, GlobalImportSettings);
	SFbxSceneOptionWindow::CopyFbxOptionsToStaticMeshOptions(GlobalImportSettingsReference, SceneImportOptionsStaticMesh);
	SceneImportOptionsStaticMesh->FillStaticMeshInmportData(StaticMeshImportData, SceneImportOptions);
	StaticMeshImportData->SaveConfig();

	//Update the blueprint
	UBlueprint *ReimportBlueprint = nullptr;
	if (bCanReimportHierarchy && GlobalImportSettingsReference->bImportScene)
	{
		ReimportBlueprint = UpdateOriginalBluePrint(ReimportData->BluePrintFullName, &NodeStatusMap, SceneInfoPtr, ReimportData->SceneInfoSourceData, AssetDataToDelete);
	}

	//Remove the deleted meshinfo node from the reimport data
	TArray<TSharedPtr<FFbxMeshInfo>> ToRemoveHierarchyNode;
	for (TSharedPtr<FFbxMeshInfo> MeshInfo : ReimportData->SceneInfoSourceData->MeshInfo)
	{
		EFbxSceneReimportStatusFlags MeshStatus = *(MeshStatusMap.Find(MeshInfo->OriginalImportPath));
		if ((MeshStatus & EFbxSceneReimportStatusFlags::Removed) != EFbxSceneReimportStatusFlags::None)
		{
			ToRemoveHierarchyNode.Add(MeshInfo);
		}
	}
	for (TSharedPtr<FFbxMeshInfo> MeshInfo : ToRemoveHierarchyNode)
	{
		ReimportData->SceneInfoSourceData->MeshInfo.Remove(MeshInfo);
	}
	ReimportData->Modify();
	ReimportData->PostEditChange();
	
	//Make sure the content browser is in sync before we delete
	FContentBrowserModule& ContentBrowserModule = FModuleManager::Get().LoadModuleChecked<FContentBrowserModule>("ContentBrowser");
	ContentBrowserModule.Get().SyncBrowserToAssets(AssetToSyncContentBrowser);

	if (AssetDataToDelete.Num() > 0)
	{
		bool AbortDelete = false;
		if (ReimportBlueprint != nullptr)
		{
			//Save the blueprint to avoid reference from the old blueprint
			FAssetData ReimportBlueprintAsset(ReimportBlueprint);
			TArray<UPackage*> Packages;
			Packages.Add(ReimportBlueprintAsset.GetPackage());
			FEditorFileUtils::PromptForCheckoutAndSave(Packages, false, false);

			//Make sure the Asset registry is up to date after the save
			TArray<FString> Paths;
			Paths.Add(ReimportBlueprintAsset.PackagePath.ToString());
			AssetRegistryModule.Get().ScanPathsSynchronous(Paths, true);
		}

		if (!AbortDelete)
		{
			//Delete the asset and use the normal dialog to make sure the user understand he will remove some content
			//The user can decide to cancel the delete or not. This will not interrupt the reimport process
			//The delete is done at the end because we want to remove the blueprint reference before deleting object
			ObjectTools::DeleteAssets(AssetDataToDelete, true);
		}
	}
	//Make sure the content browser is in sync
	ContentBrowserModule.Get().SyncBrowserToAssets(AssetToSyncContentBrowser);
	
	AllNewAssets.Empty();
	
	GlobalImportSettings = nullptr;
	GlobalImportSettingsReference = nullptr;

	FbxImporter->ReleaseScene();
	FbxImporter = nullptr;
	GWarn->EndSlowTask();
	return EReimportResult::Succeeded;
}
void FContentDirectoryMonitor::ProcessAdditions(const DirectoryWatcher::FTimeLimit& TimeLimit, TArray<UPackage*>& OutPackagesToSave, const TMap<FString, TArray<UFactory*>>& InFactoriesByExtension, FReimportFeedbackContext& Context)
{
	bool bCancelled = false;
	for (int32 Index = 0; Index < AddedFiles.Num(); ++Index)
	{
		auto& Addition = AddedFiles[Index];

		if (bCancelled)
		{
			// Just update the cache immediately if the user cancelled
			Cache.CompleteTransaction(MoveTemp(Addition));
			Context.MainTask->EnterProgressFrame();
			continue;
		}

		const FString FullFilename = Cache.GetDirectory() + Addition.Filename.Get();

		FString NewAssetName = ObjectTools::SanitizeObjectName(FPaths::GetBaseFilename(FullFilename));
		FString PackagePath = PackageTools::SanitizePackageName(MountedContentPath / FPaths::GetPath(Addition.Filename.Get()) / NewAssetName);

		// Don't create assets for new files if assets already exist for the filename
		auto ExistingReferences = Utils::FindAssetsPertainingToFile(*Registry, FullFilename);
		if (ExistingReferences.Num() != 0)
		{
			// Treat this as a modified file that will attempt to reimport it (if applicable). We don't update the progress for this item until it is processed by ProcessModifications
			ModifiedFiles.Add(MoveTemp(Addition));
			continue;
		}

		// Move the progress on now that we know we're going to process the file
		Context.MainTask->EnterProgressFrame();

		if (FPackageName::DoesPackageExist(*PackagePath))
		{
			// Package already exists, so try and import over the top of it, if it doesn't already have a source file path
			TArray<FAssetData> Assets;
			if (Registry->GetAssetsByPackageName(*PackagePath, Assets) && Assets.Num() == 1)
			{
				if (UObject* ExistingAsset = Assets[0].GetAsset())
				{
					// We're only eligible for reimport if the existing asset doesn't reference a source file already
					const bool bEligibleForReimport = !Utils::ExtractSourceFilePaths(ExistingAsset).ContainsByPredicate([&](const FString& In){
						return !In.IsEmpty() && In == FullFilename;
					});

					if (bEligibleForReimport)
					{
						ReimportAssetWithNewSource(ExistingAsset, FullFilename, OutPackagesToSave, Context);
					}
				}
			}
		}
		else
		{
			UPackage* NewPackage = CreatePackage(nullptr, *PackagePath);
			if ( !ensure(NewPackage) )
			{
				Context.AddMessage(EMessageSeverity::Error, FText::Format(LOCTEXT("Error_FailedToCreateAsset", "Failed to create new asset ({0}) for file ({1})."), FText::FromString(NewAssetName), FText::FromString(FullFilename)));
			}
			else
			{
				Context.AddMessage(EMessageSeverity::Info, FText::Format(LOCTEXT("Info_CreatingNewAsset", "Importing new asset {0}."), FText::FromString(PackagePath)));

				// Make sure the destination package is loaded
				NewPackage->FullyLoad();
				
				UObject* NewAsset = nullptr;

				// Find a relevant factory for this file
				// @todo import: gmp: show dialog in case of multiple matching factories
				const FString Ext = FPaths::GetExtension(Addition.Filename.Get(), false);
				auto* Factories = InFactoriesByExtension.Find(Ext);
				if (Factories && Factories->Num() != 0)
				{
					// Prefer a factory if it explicitly can import. UFactory::FactoryCanImport returns false by default, even if the factory supports the extension, so we can't use it directly.
					UFactory* const * PreferredFactory = Factories->FindByPredicate([&](UFactory* F){ return F->FactoryCanImport(FullFilename); });
					if (PreferredFactory)
					{
						NewAsset = AttemptImport((*PreferredFactory)->GetClass(), NewPackage, *NewAssetName, bCancelled, FullFilename);
					}
					// If there was no preferred factory, just try them all until one succeeds
					else for (UFactory* Factory : *Factories)
					{
						NewAsset = AttemptImport(Factory->GetClass(), NewPackage, *NewAssetName, bCancelled, FullFilename);

						if (bCancelled || NewAsset)
						{
							break;
						}
					}
				}

				// If we didn't create an asset, unload and delete the package we just created
				if (!NewAsset)
				{
					TArray<UPackage*> Packages;
					Packages.Add(NewPackage);

					TGuardValue<bool> SuppressSlowTaskMessages(Context.bSuppressSlowTaskMessages, true);

					FText ErrorMessage;
					if (!PackageTools::UnloadPackages(Packages, ErrorMessage))
					{
						Context.AddMessage(EMessageSeverity::Error, FText::Format(LOCTEXT("Error_UnloadingPackage", "There was an error unloading a package: {0}."), ErrorMessage));
					}

					// Just add the message to the message log rather than add it to the UI
					// Factories may opt not to import the file, so we let them report errors if they do
					Context.GetMessageLog().Message(EMessageSeverity::Info, FText::Format(LOCTEXT("Info_FailedToImportAsset", "Failed to import file {0}."), FText::FromString(FullFilename)));
				}
				else if (!bCancelled)
				{
					FAssetRegistryModule::AssetCreated(NewAsset);
					GEditor->BroadcastObjectReimported(NewAsset);

					OutPackagesToSave.Add(NewPackage);
				}

				// Refresh the supported class.  Some factories (e.g. FBX) only resolve their type after reading the file
				// ImportAssetType = Factory->ResolveSupportedClass();
				// @todo: analytics?
			}
		}

		// Let the cache know that we've dealt with this change (it will be imported immediately)
		Cache.CompleteTransaction(MoveTemp(Addition));

		if (!bCancelled && TimeLimit.Exceeded())
		{
			// Remove the ones we've processed
			AddedFiles.RemoveAt(0, Index + 1);
			return;
		}
	}

	AddedFiles.Empty();
}