/* * Copyright (c) <2021> Side Effects Software Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. The name of Side Effects Software may not be used to endorse or * promote products derived from this software without specific prior * written permission. * * THIS SOFTWARE IS PROVIDED BY SIDE EFFECTS SOFTWARE "AS IS" AND ANY EXPRESS * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN * NO EVENT SHALL SIDE EFFECTS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "HoudiniAssetFactory.h" #include "HoudiniEngineEditorPrivatePCH.h" #include "HoudiniAsset.h" #include "EditorFramework/AssetImportData.h" #include "Misc/FileHelper.h" #include "Internationalization/Internationalization.h" #define LOCTEXT_NAMESPACE HOUDINI_LOCTEXT_NAMESPACE UHoudiniAssetFactory::UHoudiniAssetFactory(const FObjectInitializer & ObjectInitializer) : Super(ObjectInitializer) { // This factory is responsible for manufacturing HoudiniEngine assets. SupportedClass = UHoudiniAsset::StaticClass(); // This factory does not manufacture new objects from scratch. bCreateNew = false; // This factory will not open the editor for each new object. bEditAfterNew = false; // This factory will import objects from files. bEditorImport = true; // Factory does not import objects from text. bText = false; // Add supported formats. Formats.Add(TEXT("otl;Houdini Engine Asset")); Formats.Add(TEXT("otllc;Houdini Engine Limited Commercial Asset")); Formats.Add(TEXT("otlnc;Houdini Engine Non-Commercial Asset")); Formats.Add(TEXT("hda;Houdini Engine Asset")); Formats.Add(TEXT("hdalc;Houdini Engine Limited Commercial Asset")); Formats.Add(TEXT("hdanc;Houdini Engine Non-Commercial Asset")); Formats.Add(TEXT("hdalibrary;Houdini Engine Expanded Asset")); } bool UHoudiniAssetFactory::DoesSupportClass(UClass * Class) { return Class == SupportedClass; } FText UHoudiniAssetFactory::GetDisplayName() const { return LOCTEXT("HoudiniAssetFactoryDescription", "Houdini Engine Asset"); } UObject * UHoudiniAssetFactory::FactoryCreateBinary( UClass * InClass, UObject* InParent, FName InName, EObjectFlags Flags, UObject * Context, const TCHAR * Type, const uint8 *& Buffer, const uint8 * BufferEnd, FFeedbackContext * Warn ) { // Broadcast notification that a new asset is being imported. GEditor->GetEditorSubsystem()->BroadcastAssetPreImport(this, InClass, InParent, InName, Type); // Create a new asset. UHoudiniAsset * HoudiniAsset = NewObject< UHoudiniAsset >(InParent, InName, Flags); HoudiniAsset->CreateAsset(Buffer, BufferEnd, UFactory::GetCurrentFilename()); // Create reimport information. UAssetImportData * AssetImportData = HoudiniAsset->AssetImportData; if (!AssetImportData) { AssetImportData = NewObject< UAssetImportData >(HoudiniAsset, UAssetImportData::StaticClass()); HoudiniAsset->AssetImportData = AssetImportData; } AssetImportData->Update(UFactory::GetCurrentFilename()); // Broadcast notification that the new asset has been imported. GEditor->GetEditorSubsystem()->BroadcastAssetPostImport(this, HoudiniAsset); return HoudiniAsset; } UObject* UHoudiniAssetFactory::FactoryCreateFile(UClass* InClass, UObject* InParent, FName InName, EObjectFlags Flags, const FString& Filename, const TCHAR* Parms, FFeedbackContext* Warn, bool& bOutOperationCanceled) { // "houdini.hdalibrary" files (expanded hda / hda folder) need a special treatment, // but ".hda" files can be loaded normally FString FileExtension = FPaths::GetExtension(Filename); if (FileExtension.Compare(TEXT("hdalibrary"), ESearchCase::IgnoreCase) != 0) return Super::FactoryCreateFile(InClass, InParent, InName, Flags, Filename, Parms, Warn, bOutOperationCanceled); // Make sure the file name is sections.list FString NameOfFile = FPaths::GetBaseFilename(Filename); if (NameOfFile.Compare(TEXT("houdini"), ESearchCase::IgnoreCase) != 0) { HOUDINI_LOG_ERROR(TEXT("Failed to load file '%s'. File is not a valid extended HDA."), *Filename); return nullptr; } // Make sure that the proper .list file is loaded FString PathToFile = FPaths::GetPath(Filename); if (PathToFile.Find(TEXT(".hda")) != (PathToFile.Len() - 4)) { HOUDINI_LOG_ERROR(TEXT("Failed to load file '%s'. File is not a valid extended HDA."), *Filename); return nullptr; } FString NewFilename = PathToFile; FString NewFileNameNoHDA = FPaths::GetBaseFilename(PathToFile); FName NewIname = FName(*NewFileNameNoHDA); FString NewFileExtension = FPaths::GetExtension(NewFilename); // load as binary TArray Data; if (!FFileHelper::LoadFileToArray(Data, *Filename)) { HOUDINI_LOG_ERROR(TEXT("Failed to load file '%s' to array"), *Filename); return nullptr; } Data.Add(0); ParseParms(Parms); const uint8* Ptr = &Data[0]; return FactoryCreateBinary(InClass, InParent, NewIname, Flags, nullptr, *NewFileExtension, Ptr, Ptr + Data.Num() - 1, Warn); } bool UHoudiniAssetFactory::CanReimport(UObject * Obj, TArray< FString > & OutFilenames) { UHoudiniAsset * HoudiniAsset = Cast(Obj); if (HoudiniAsset) { UAssetImportData * AssetImportData = HoudiniAsset->AssetImportData; if (AssetImportData) OutFilenames.Add(AssetImportData->GetFirstFilename()); else OutFilenames.Add(TEXT("")); return true; } return false; } void UHoudiniAssetFactory::SetReimportPaths(UObject * Obj, const TArray< FString > & NewReimportPaths) { UHoudiniAsset * HoudiniAsset = Cast< UHoudiniAsset >(Obj); if (HoudiniAsset && (1 == NewReimportPaths.Num())) HoudiniAsset->AssetImportData->UpdateFilenameOnly(NewReimportPaths[0]); } EReimportResult::Type UHoudiniAssetFactory::Reimport(UObject * Obj) { UHoudiniAsset * HoudiniAsset = Cast< UHoudiniAsset >(Obj); if (HoudiniAsset && HoudiniAsset->AssetImportData) { // Make sure file is valid and exists. const FString & Filename = HoudiniAsset->AssetImportData->GetFirstFilename(); if (!Filename.Len() || IFileManager::Get().FileSize(*Filename) == INDEX_NONE) return EReimportResult::Failed; if (UFactory::StaticImportObject( HoudiniAsset->GetClass(), HoudiniAsset->GetOuter(), *HoudiniAsset->GetName(), RF_Public | RF_Standalone, *Filename, NULL, this)) { HOUDINI_LOG_MESSAGE(TEXT("Houdini Asset reimported successfully.")); if (HoudiniAsset->GetOuter()) HoudiniAsset->GetOuter()->MarkPackageDirty(); else HoudiniAsset->MarkPackageDirty(); return EReimportResult::Succeeded; } } HOUDINI_LOG_MESSAGE(TEXT("Houdini Asset reimport has failed.")); return EReimportResult::Failed; } #undef LOCTEXT_NAMESPACE