diff --git a/Unreal/UnrealPlugin/DazToUnreal/Content/BasePBRSkinMaterial.uasset b/Unreal/UnrealPlugin/DazToUnreal/Content/BasePBRSkinMaterial.uasset new file mode 100644 index 0000000..ec7e50f Binary files /dev/null and b/Unreal/UnrealPlugin/DazToUnreal/Content/BasePBRSkinMaterial.uasset differ diff --git a/Unreal/UnrealPlugin/DazToUnreal/Content/Genesis8BaseSkeleton.uasset b/Unreal/UnrealPlugin/DazToUnreal/Content/Genesis8BaseSkeleton.uasset index 3721302..afb39fe 100644 Binary files a/Unreal/UnrealPlugin/DazToUnreal/Content/Genesis8BaseSkeleton.uasset and b/Unreal/UnrealPlugin/DazToUnreal/Content/Genesis8BaseSkeleton.uasset differ diff --git a/Unreal/UnrealPlugin/DazToUnreal/Content/PBRSkinParameters.uasset b/Unreal/UnrealPlugin/DazToUnreal/Content/PBRSkinParameters.uasset new file mode 100644 index 0000000..2ba4519 Binary files /dev/null and b/Unreal/UnrealPlugin/DazToUnreal/Content/PBRSkinParameters.uasset differ diff --git a/Unreal/UnrealPlugin/DazToUnreal/Source/DazToUnreal/Private/DazToUnreal.cpp b/Unreal/UnrealPlugin/DazToUnreal/Source/DazToUnreal/Private/DazToUnreal.cpp index 9d3e142..f56e791 100644 --- a/Unreal/UnrealPlugin/DazToUnreal/Source/DazToUnreal/Private/DazToUnreal.cpp +++ b/Unreal/UnrealPlugin/DazToUnreal/Source/DazToUnreal/Private/DazToUnreal.cpp @@ -6,6 +6,7 @@ #include "DazToUnrealUtils.h" #include "DazToUnrealFbx.h" #include "DazToUnrealEnvironment.h" +#include "DazToUnrealPoses.h" #include "LevelEditor.h" #include "Widgets/Docking/SDockTab.h" @@ -325,6 +326,8 @@ UObject* FDazToUnrealModule::ImportFromDaz(TSharedPtr JsonObject) AssetType = DazAssetType::Animation; else if (JsonObject->GetStringField(TEXT("Asset Type")) == TEXT("Environment")) AssetType = DazAssetType::Environment; + else if (JsonObject->GetStringField(TEXT("Asset Type")) == TEXT("Pose")) + AssetType = DazAssetType::Pose; // Set up the folder paths FString ImportDirectory = FPaths::ProjectDir() / TEXT("Import"); @@ -357,14 +360,14 @@ UObject* FDazToUnrealModule::ImportFromDaz(TSharedPtr JsonObject) FString LocalCharacterMaterialFolder = CharacterMaterialFolder.Replace(TEXT("/Game/"), *ContentDirectory); // Make any needed folders. If any of these fail, don't continue - if (!MakeDirectoryAndCheck(ImportDirectory)) return false; - if (!MakeDirectoryAndCheck(ImportCharacterFolder)) return false; - if (!MakeDirectoryAndCheck(ImportCharacterTexturesFolder)) return false; - if (!MakeDirectoryAndCheck(LocalDAZImportFolder)) return false; - if (!MakeDirectoryAndCheck(LocalDAZAnimationImportFolder)) return false; - if (!MakeDirectoryAndCheck(LocalCharacterFolder)) return false; - if (!MakeDirectoryAndCheck(LocalCharacterTexturesFolder)) return false; - if (!MakeDirectoryAndCheck(LocalCharacterMaterialFolder)) return false; + if (!FDazToUnrealUtils::MakeDirectoryAndCheck(ImportDirectory)) return false; + if (!FDazToUnrealUtils::MakeDirectoryAndCheck(ImportCharacterFolder)) return false; + if (!FDazToUnrealUtils::MakeDirectoryAndCheck(ImportCharacterTexturesFolder)) return false; + if (!FDazToUnrealUtils::MakeDirectoryAndCheck(LocalDAZImportFolder)) return false; + if (!FDazToUnrealUtils::MakeDirectoryAndCheck(LocalDAZAnimationImportFolder)) return false; + if (!FDazToUnrealUtils::MakeDirectoryAndCheck(LocalCharacterFolder)) return false; + if (!FDazToUnrealUtils::MakeDirectoryAndCheck(LocalCharacterTexturesFolder)) return false; + if (!FDazToUnrealUtils::MakeDirectoryAndCheck(LocalCharacterMaterialFolder)) return false; if (AssetType == DazAssetType::Environment) { @@ -477,6 +480,20 @@ UObject* FDazToUnrealModule::ImportFromDaz(TSharedPtr JsonObject) { Property.Type = TEXT("Color"); } + + // Properties that end with Enabled are switches for functionality + if (Property.Name.EndsWith(TEXT(" Enable"))) + { + Property.Type = TEXT("Switch"); + if (Property.Value == TEXT("0")) + { + Property.Value = TEXT("false"); + } + else + { + Property.Value = TEXT("true"); + } + } MaterialProperties[MaterialName].Add(Property); if (!TextureName.IsEmpty()) @@ -1017,6 +1034,22 @@ UObject* FDazToUnrealModule::ImportFromDaz(TSharedPtr JsonObject) MorphMappings.Add(MorphName, MorphLabel); } + // Get a list of morph name mappings + TArray PoseNameList; + const TArray>* PoseList; + if (JsonObject->TryGetArrayField(TEXT("Poses"), PoseList)) + { + PoseNameList.Add(TEXT("ReferencePose")); + for (int32 i = 0; i < PoseList->Num(); i++) + { + TSharedPtr Pose = (*PoseList)[i]->AsObject(); + FString PoseName = Pose->GetStringField(TEXT("Name")); + FString PoseLabel = Pose->GetStringField(TEXT("Label")); + + PoseNameList.Add(PoseLabel); + } + } + // Combine clothing and body morphs for (int NodeIndex = 0; NodeIndex < Scene->GetNodeCount(); ++NodeIndex) { @@ -1153,23 +1186,23 @@ UObject* FDazToUnrealModule::ImportFromDaz(TSharedPtr JsonObject) // If this is a character, determine the type. DazCharacterType CharacterType = DazCharacterType::Unknown; FString CharacterTypeName = RootBoneName.Replace(TEXT("\0"), TEXT("")); - if (RootBoneName.Contains(TEXT("Genesis3Male"))) + if (RootBoneName == TEXT("Genesis3Male")) { CharacterType = DazCharacterType::Genesis3Male; } - else if (RootBoneName.Contains(TEXT("Genesis3Female"))) + else if (RootBoneName == TEXT("Genesis3Female")) { CharacterType = DazCharacterType::Genesis3Female; } - else if (RootBoneName.Contains(TEXT("Genesis8Male"))) + else if (RootBoneName == TEXT("Genesis8Male")) { CharacterType = DazCharacterType::Genesis8Male; } - else if (RootBoneName.Contains(TEXT("Genesis8Female"))) + else if (RootBoneName == TEXT("Genesis8Female")) { CharacterType = DazCharacterType::Genesis8Female; } - else if (RootBoneName.Contains(TEXT("Genesis"))) + else if (RootBoneName == TEXT("Genesis")) { CharacterType = DazCharacterType::Genesis1; } @@ -1266,14 +1299,19 @@ UObject* FDazToUnrealModule::ImportFromDaz(TSharedPtr JsonObject) } } - // Create Material Instances - /*if (AssetType == DazAssetType::SkeletalMesh || AssetType == DazAssetType::StaticMesh) + // Import FBX + UObject* NewObject = ImportFBXAsset(UpdatedFBXFile, CharacterFolder, AssetType, CharacterType, CharacterTypeName); + + // If this is a Pose transfer, an AnimSequence was created. Make a PoseAsset from it. + if (AssetType == DazAssetType::Pose) { - CreateMaterials(CharacterMaterialFolder, CharacterTexturesFolder, MaterialNames, MaterialProperties, CharacterType); - }*/ + if (UAnimSequence* AnimSequence = Cast(NewObject)) + { + FDazToUnrealPoses::CreatePoseAsset(AnimSequence, PoseNameList); + } + } - // Import FBX - return ImportFBXAsset(UpdatedFBXFile, CharacterFolder, AssetType, CharacterType, CharacterTypeName); + return NewObject; } @@ -1419,7 +1457,7 @@ UObject* FDazToUnrealModule::ImportFBXAsset(const FString& SourcePath, const FSt FbxFactory->ImportUI->bImportMaterials = true; FbxFactory->ImportUI->MeshTypeToImport = FBXIT_StaticMesh; } - if (AssetType == DazAssetType::Animation) + if (AssetType == DazAssetType::Animation || AssetType == DazAssetType::Pose) { FbxFactory->ImportUI->bImportAsSkeletal = true; FbxFactory->ImportUI->Skeleton = Skeleton; @@ -1436,7 +1474,7 @@ UObject* FDazToUnrealModule::ImportFBXAsset(const FString& SourcePath, const FSt ImportData->Filenames = FileNames; ImportData->DestinationPath = ImportLocation; ImportData->bReplaceExisting = true; - if (AssetType == DazAssetType::Animation) + if (AssetType == DazAssetType::Animation || AssetType == DazAssetType::Pose) { ImportData->DestinationPath = CachedSettings->AnimationImportDirectory.Path; } @@ -1501,7 +1539,7 @@ UObject* FDazToUnrealModule::ImportFBXAsset(const FString& SourcePath, const FSt //EditableSkeleton->Set CachedSettings->OtherSkeletons.Add(CharacterTypeName, Skeleton); - CachedSettings->SaveConfig(); + CachedSettings->SaveConfig(CPF_Config, *CachedSettings->GetDefaultConfigFilename()); } } } diff --git a/Unreal/UnrealPlugin/DazToUnreal/Source/DazToUnreal/Private/DazToUnrealMaterials.cpp b/Unreal/UnrealPlugin/DazToUnreal/Source/DazToUnreal/Private/DazToUnrealMaterials.cpp index d3b3d56..0204ffa 100644 --- a/Unreal/UnrealPlugin/DazToUnreal/Source/DazToUnreal/Private/DazToUnrealMaterials.cpp +++ b/Unreal/UnrealPlugin/DazToUnreal/Source/DazToUnreal/Private/DazToUnrealMaterials.cpp @@ -209,22 +209,9 @@ UMaterialInstanceConstant* FDazToUnrealMaterials::CreateMaterial(const FString C } } } - /* - // Set the default material type - if (CachedSettings->DefaultShaderMaterials.Contains(ShaderName)) - { - BaseMaterialAssetPath = CachedSettings->DefaultShaderMaterials[ShaderName]; - }*/ - /*if (AssetType == TEXT("Follower/Hair")) - { - BaseMaterialAssetPath = CachedSettings->BaseHairMaterial; - if (MaterialName.EndsWith(TEXT("_scalp"))) - { - BaseMaterialAssetPath = CachedSettings->BaseScalpMaterial; - } - }*/ - /*else*/ if (AssetType == TEXT("Follower/Attachment/Head/Face/Eyelashes")) + if (AssetType == TEXT("Follower/Attachment/Head/Face/Eyelashes") || + AssetType == TEXT("Follower/Attachment/Head/Face/Eyes")) { if (MaterialName.Contains(TEXT("_EyeMoisture")) || MaterialName.EndsWith(TEXT("_EyeReflection"))) { @@ -234,6 +221,13 @@ UMaterialInstanceConstant* FDazToUnrealMaterials::CreateMaterial(const FString C SetMaterialProperty(MaterialName, TEXT("Diffuse Color"), TEXT("Color"), TEXT("#bababa"), MaterialProperties); SetMaterialProperty(MaterialName, TEXT("Index of Refraction"), TEXT("Double"), TEXT("1.0"), MaterialProperties); } + else if (MaterialName.EndsWith(TEXT("_Tear"))) + { + //BaseMaterialAssetPath = CachedSettings->BaseCorneaMaterial; + SetMaterialProperty(MaterialName, TEXT("Metallic Weight"), TEXT("Double"), TEXT("1"), MaterialProperties); + SetMaterialProperty(MaterialName, TEXT("Opacity Strength"), TEXT("Double"), TEXT("0.05"), MaterialProperties); + SetMaterialProperty(MaterialName, TEXT("Index of Refraction"), TEXT("Double"), TEXT("1.0"), MaterialProperties); + } else { //BaseMaterialAssetPath = CachedSettings->BaseAlphaMaterial; diff --git a/Unreal/UnrealPlugin/DazToUnreal/Source/DazToUnreal/Private/DazToUnrealPoses.cpp b/Unreal/UnrealPlugin/DazToUnreal/Source/DazToUnreal/Private/DazToUnrealPoses.cpp new file mode 100644 index 0000000..1f78131 --- /dev/null +++ b/Unreal/UnrealPlugin/DazToUnreal/Source/DazToUnreal/Private/DazToUnrealPoses.cpp @@ -0,0 +1,78 @@ +#include "DazToUnrealPoses.h" +#include "DazToUnrealSettings.h" +#include "DazToUnrealTextures.h" +#include "DazToUnrealUtils.h" + +#include "Animation/Skeleton.h" +#include "Animation/AnimSequence.h" +#include "Animation/PoseAsset.h" + +#include "Factories/PoseAssetFactory.h" +#include "IContentBrowserSingleton.h" +#include "ContentBrowserModule.h" +#include "AssetRegistryModule.h" +#include "PackageTools.h" + +// Partially taken from UPoseAssetFactory::FactoryCreateNew +void FDazToUnrealPoses::CreatePoseAsset(UAnimSequence* SourceAnimation, TArray PoseNames) +{ + if (SourceAnimation) + { + const UDazToUnrealSettings* CachedSettings = GetDefault(); + + // Make sure the path exists + FString ContentDirectory = FPaths::ProjectContentDir(); + FString DAZPoseImportFolder = CachedSettings->PoseImportDirectory.Path.Replace(TEXT("/Game/"), *ContentDirectory); + if (!FDazToUnrealUtils::MakeDirectoryAndCheck(DAZPoseImportFolder)) + { + //log error + } + + USkeleton* TargetSkeleton = SourceAnimation->GetSkeleton(); + + TArray InputPoseNames; + if (PoseNames.Num() > 0) + { + for (int32 Index = 0; Index < PoseNames.Num(); ++Index) + { + FName PoseName = FName(*PoseNames[Index]); + FSmartName NewName; + if (TargetSkeleton->GetSmartNameByName(USkeleton::AnimCurveMappingName, PoseName, NewName) == false) + { + // if failed, add it + TargetSkeleton->AddSmartNameAndModify(USkeleton::AnimCurveMappingName, PoseName, NewName); + } + + // we want same names in multiple places + InputPoseNames.AddUnique(NewName); + } + } + + FString PackageName = UPackageTools::SanitizePackageName(*(CachedSettings->PoseImportDirectory.Path / FString(SourceAnimation->GetName()))); +#if ENGINE_MAJOR_VERSION == 4 && ENGINE_MINOR_VERSION < 26 + UPackage* Pkg = CreatePackage(nullptr, *PackageName); +#else + UPackage* Pkg = CreatePackage(*PackageName); +#endif + EObjectFlags Flags = RF_Public | RF_Standalone | RF_Transactional; + + UPoseAsset* PoseAsset = NewObject(Pkg, FName(*SourceAnimation->GetName()), Flags); + //PoseAsset->bAdditivePose = true; + //PoseAsset->BasePoseIndex = 0; + PoseAsset->CreatePoseFromAnimation(SourceAnimation, &InputPoseNames); + PoseAsset->SetSkeleton(TargetSkeleton); + PoseAsset->ConvertSpace(true, 0); + } + //return NewPose; + + //UPoseAssetFactory* Factory = NewObject(); + //Factory->TargetSkeleton = Skeleton; + //Factory->PreviewSkeletalMesh = SkeletalMesh; + + //FContentBrowserModule& ContentBrowserModule = FModuleManager::LoadModuleChecked("ContentBrowser"); + //ContentBrowserModule.Get().CreateNewAsset(Name, FPackageName::GetLongPackagePath(PackageName), T::StaticClass(), Factory); + + /*UPoseAsset* PoseAsset = NewObject(InParent, Class, Name, Flags); + PoseAsset->CreatePoseFromAnimation(SourceAnimation, &InputPoseNames); + PoseAsset->SetSkeleton(TargetSkeleton);*/ +} \ No newline at end of file diff --git a/Unreal/UnrealPlugin/DazToUnreal/Source/DazToUnreal/Private/DazToUnrealUtils.cpp b/Unreal/UnrealPlugin/DazToUnreal/Source/DazToUnreal/Private/DazToUnrealUtils.cpp index 7cfacbb..5539d85 100644 --- a/Unreal/UnrealPlugin/DazToUnreal/Source/DazToUnreal/Private/DazToUnrealUtils.cpp +++ b/Unreal/UnrealPlugin/DazToUnreal/Source/DazToUnreal/Private/DazToUnrealUtils.cpp @@ -1,4 +1,6 @@ #include "DazToUnrealUtils.h" +#include "GenericPlatform/GenericPlatformFile.h" +#include "Misc/Paths.h" FString FDazToUnrealUtils::SanitizeName(FString OriginalName) { @@ -13,4 +15,18 @@ FString FDazToUnrealUtils::SanitizeName(FString OriginalName) .Replace(TEXT(">"), TEXT("_")) .Replace(TEXT("?"), TEXT("_")) .Replace(TEXT("\\"), TEXT("_")); +} + +bool FDazToUnrealUtils::MakeDirectoryAndCheck(FString& Directory) +{ + IPlatformFile& PlatformFile = FPlatformFileManager::Get().GetPlatformFile(); + if (!FPaths::DirectoryExists(Directory)) + { + PlatformFile.CreateDirectory(*Directory); + if (!FPaths::DirectoryExists(Directory)) + { + return false; + } + } + return true; } \ No newline at end of file diff --git a/Unreal/UnrealPlugin/DazToUnreal/Source/DazToUnreal/Public/DazToUnreal.h b/Unreal/UnrealPlugin/DazToUnreal/Source/DazToUnreal/Public/DazToUnreal.h index 7f4c378..eeb64fb 100644 --- a/Unreal/UnrealPlugin/DazToUnreal/Source/DazToUnreal/Public/DazToUnreal.h +++ b/Unreal/UnrealPlugin/DazToUnreal/Source/DazToUnreal/Public/DazToUnreal.h @@ -20,7 +20,8 @@ enum DazAssetType SkeletalMesh, StaticMesh, Animation, - Environment + Environment, + Pose }; diff --git a/Unreal/UnrealPlugin/DazToUnreal/Source/DazToUnreal/Public/DazToUnrealPoses.h b/Unreal/UnrealPlugin/DazToUnreal/Source/DazToUnreal/Public/DazToUnrealPoses.h new file mode 100644 index 0000000..02625b8 --- /dev/null +++ b/Unreal/UnrealPlugin/DazToUnreal/Source/DazToUnreal/Public/DazToUnrealPoses.h @@ -0,0 +1,11 @@ +#pragma once + +#include "CoreMinimal.h" +#include "DazToUnrealEnums.h" + + +class FDazToUnrealPoses +{ +public: + static void CreatePoseAsset(UAnimSequence* SourceAnimation, TArray PoseNames); +}; \ No newline at end of file diff --git a/Unreal/UnrealPlugin/DazToUnreal/Source/DazToUnreal/Public/DazToUnrealSettings.h b/Unreal/UnrealPlugin/DazToUnreal/Source/DazToUnreal/Public/DazToUnrealSettings.h index 2edfe97..93e6b1b 100644 --- a/Unreal/UnrealPlugin/DazToUnreal/Source/DazToUnreal/Public/DazToUnrealSettings.h +++ b/Unreal/UnrealPlugin/DazToUnreal/Source/DazToUnreal/Public/DazToUnrealSettings.h @@ -19,12 +19,16 @@ class DAZTOUNREAL_API UDazToUnrealSettings : public UDeveloperSettings Port = 32345; ImportDirectory.Path = TEXT("/Game/DazToUnreal"); AnimationImportDirectory.Path = TEXT("/Game/DazToUnreal/Animation"); + PoseImportDirectory.Path = TEXT("/Game/DazToUnreal/Pose"); ShowFBXImportDialog = false; FrameZeroIsReferencePose = false; FixBoneRotationsOnImport = false; + Genesis1Skeleton = FSoftObjectPath(TEXT("/DazToUnreal/Genesis1BaseSkeleton.Genesis1BaseSkeleton")); Genesis3Skeleton = FSoftObjectPath(TEXT("/DazToUnreal/Genesis3BaseSkeleton.Genesis3BaseSkeleton")); Genesis8Skeleton = FSoftObjectPath(TEXT("/DazToUnreal/Genesis8BaseSkeleton.Genesis8BaseSkeleton")); + OtherSkeletons.Add(TEXT("Genesis8_1Male"), FSoftObjectPath(TEXT("/DazToUnreal/Genesis8BaseSkeleton.Genesis8BaseSkeleton"))); + OtherSkeletons.Add(TEXT("Genesis8_1Female"), FSoftObjectPath(TEXT("/DazToUnreal/Genesis8BaseSkeleton.Genesis8BaseSkeleton"))); Genesis1PostProcessAnimation = FSoftClassPath(TEXT("/DazToUnreal/Genesis1JCMPostProcess.Genesis1JCMPostProcess_C")); Genesis3PostProcessAnimation = FSoftClassPath(TEXT("/DazToUnreal/Genesis3JCMPostProcess.Genesis3JCMPostProcess_C")); @@ -34,11 +38,13 @@ class DAZTOUNREAL_API UDazToUnrealSettings : public UDeveloperSettings BaseShaderMaterials.Add(TEXT("omUberSurface"), FSoftObjectPath(TEXT("/DazToUnreal/omUberBaseMaterial.omUberBaseMaterial"))); BaseShaderMaterials.Add(TEXT("AoA_Subsurface"), FSoftObjectPath(TEXT("/DazToUnreal/AoASubsurfaceBaseMaterial.AoASubsurfaceBaseMaterial"))); BaseShaderMaterials.Add(TEXT("Iray Uber"), FSoftObjectPath(TEXT("/DazToUnreal/IrayUberBaseMaterial.IrayUberBaseMaterial"))); + BaseShaderMaterials.Add(TEXT("PBRSkin"), FSoftObjectPath(TEXT("/DazToUnreal/BasePBRSkinMaterial.BasePBRSkinMaterial"))); SkinShaderMaterials.Add(TEXT("Daz Studio Default"), FSoftObjectPath(TEXT("/DazToUnreal/DSDBaseMaterial.DSDBaseMaterial"))); SkinShaderMaterials.Add(TEXT("omUberSurface"), FSoftObjectPath(TEXT("/DazToUnreal/omUberSkinMaterial.omUberSkinMaterial"))); SkinShaderMaterials.Add(TEXT("AoA_Subsurface"), FSoftObjectPath(TEXT("/DazToUnreal/AoASubsurfaceSkinMaterial.AoASubsurfaceSkinMaterial"))); SkinShaderMaterials.Add(TEXT("Iray Uber"), FSoftObjectPath(TEXT("/DazToUnreal/IrayUberSkinMaterial.IrayUberSkinMaterial"))); + SkinShaderMaterials.Add(TEXT("PBRSkin"), FSoftObjectPath(TEXT("/DazToUnreal/BasePBRSkinMaterial.BasePBRSkinMaterial"))); BaseMaterial = FSoftObjectPath(TEXT("/DazToUnreal/BaseMaterial.BaseMaterial")); BaseAlphaMaterial = FSoftObjectPath(TEXT("/DazToUnreal/BaseAlphaMaterial.BaseAlphaMaterial")); @@ -95,6 +101,10 @@ class DAZTOUNREAL_API UDazToUnrealSettings : public UDeveloperSettings UPROPERTY(config, EditAnywhere, Category = PluginSettings, meta = (RelativeToGameContentDir, LongPackageName)) FDirectoryPath AnimationImportDirectory; + /** Directory PoseAssets will be imported to */ + UPROPERTY(config, EditAnywhere, Category = PluginSettings, meta = (RelativeToGameContentDir, LongPackageName)) + FDirectoryPath PoseImportDirectory; + /** Show the FBX Import dialog when importing the udpated FBX file */ UPROPERTY(config, EditAnywhere, Category = PluginSettings, meta = (RelativeToGameContentDir, LongPackageName)) bool ShowFBXImportDialog; diff --git a/Unreal/UnrealPlugin/DazToUnreal/Source/DazToUnreal/Public/DazToUnrealUtils.h b/Unreal/UnrealPlugin/DazToUnreal/Source/DazToUnreal/Public/DazToUnrealUtils.h index 27253a9..cfccc20 100644 --- a/Unreal/UnrealPlugin/DazToUnreal/Source/DazToUnreal/Public/DazToUnrealUtils.h +++ b/Unreal/UnrealPlugin/DazToUnreal/Source/DazToUnreal/Public/DazToUnrealUtils.h @@ -7,4 +7,5 @@ class FDazToUnrealUtils { public: static FString SanitizeName(FString OriginalName); + static bool MakeDirectoryAndCheck(FString& Directory); }; \ No newline at end of file