UE4で独自のアセットの作り方を制作し、
外部ファイルからインポートする方法についてのおぼえ書きです。
さっそくでなんですが・・
お世話になっているヒストリアさんのブログを参考にする方が早いです。
※こっから学びました、無事動作しました。
https://historia.co.jp/archives/1401/
https://historia.co.jp/archives/1423/
https://historia.co.jp/archives/1425/
historia.co.jp
いつもどおりプロジェクトを作ります。
ここではプロジェクト名をResTestとしています。
プロジェクトに
MyAsset.h MyAsset.cpp MyAssetFactory.h MyAssetFactory.cpp
をそれぞれを追加します。
※追加したら忘れずにGenerateVisualStudioProjectfilesを実行し
VisualStudioのプロジェクトファイルを更新しておく必要があります。
ResTest.Build.csの改造
事前にPublicDependencyModuleNamesにUnrealEdを追加しておく必要があります。
ResTest.Build.csを開き以下のように改造します
PublicDependencyModuleNames.AddRange(new string { "Core", "CoreUObject", "Engine", "InputCore" });
↓
PublicDependencyModuleNames.AddRange(new string { "Core", "CoreUObject", "Engine", "InputCore", "UnrealEd" });
using UnrealBuildTool; public class ResTest : ModuleRules { public ResTest(ReadOnlyTargetRules Target) : base(Target) { PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs; PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore", "UnrealEd" }); PrivateDependencyModuleNames.AddRange(new string[] { }); } }
つづいてMyAssetの中身を実装します。
MyAsset.h)
#pragma once #include "CoreMinimal.h" #include "MyAsset.generated.h" UCLASS() class RESTEST_API UMyAsset : public UObject { GENERATED_UCLASS_BODY() public: UPROPERTY(EditAnywhere) int32 ValueA; UPROPERTY(EditAnywhere) int32 ValueB; UPROPERTY(EditAnywhere) int32 ValueC; };
MyAsset.cpp)
#include "MyAsset.h" UMyAsset::UMyAsset(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) { }
つづいてMyAssetFactoryの中身を実装します。
MyAssetFactory.h)
#pragma once #include "CoreMinimal.h" #include "Factories/Factory.h" #include "MyAssetFactory.generated.h" UCLASS() class RESTEST_API UMyAssetFactory : public UFactory { GENERATED_UCLASS_BODY() virtual bool DoesSupportClass(UClass* Class) override; virtual UClass* ResolveSupportedClass() override; virtual UObject* FactoryCreateNew(UClass* InClass, UObject* InParent, FName InName, EObjectFlags Flags, UObject* Context, FFeedbackContext* Warn) override; virtual UObject* FactoryCreateText(UClass* InClass, UObject* InParent, FName InName, EObjectFlags Flags, UObject* Context, const TCHAR* Type, const TCHAR*& Buffer, const TCHAR* BuferEnd, FFeedbackContext* Warn) override; };
MyAssetFactory.cpp)
#include "MyAssetFactory.h" #include "Misc/FileHelper.h" #include "MyAsset.h" UMyAssetFactory::UMyAssetFactory(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) { SupportedClass = UMyAsset::StaticClass(); bCreateNew = false; bEditorImport = true; bText = true; Formats.Add(TEXT("myasset;My Asset")); } bool UMyAssetFactory::DoesSupportClass(UClass* Class) { return (Class == UMyAsset::StaticClass()); } UClass* UMyAssetFactory::ResolveSupportedClass() { return UMyAsset::StaticClass(); } UObject* UMyAssetFactory::FactoryCreateNew(UClass* InClass, UObject* InParent, FName InName, EObjectFlags Flags, UObject* Context, FFeedbackContext* Warn) { UMyAsset* NewMyAsset = CastChecked<UMyAsset>(StaticConstructObject_Internal(InClass, InParent, InName, Flags)); return NewMyAsset; } UObject* UMyAssetFactory::FactoryCreateText(UClass* InClass, UObject* InParent, FName InName, EObjectFlags Flags, UObject* Context, const TCHAR* Type, const TCHAR*& Buffer, const TCHAR* BuferEnd, FFeedbackContext* Warn) { TArray<FString> Values; FString(Buffer).ParseIntoArray(Values, TEXT(","), true); UMyAsset* NewMyAsset = CastChecked<UMyAsset>(StaticConstructObject_Internal(InClass, InParent, InName, Flags)); if (NewMyAsset && (3 <= Values.Num())) { NewMyAsset->ValueA = FCString::Atoi(*Values[0]); NewMyAsset->ValueB = FCString::Atoi(*Values[1]); NewMyAsset->ValueC = FCString::Atoi(*Values[2]); } return NewMyAsset; }
これで無事ビルドがとおるはずです。
外部データのインポート
ためしにインポート元のファイル(test.myasset⦆を作成しインポートしてみたいと思います。
test.myassetの中身は1,2,3としています。
test.myassetをドロップするとアセットが出来上がることが確認できます。
中身を開くとこのようにtest.myassetの中身が読み込まれていることを
確認できます。
しかしながらもう一度インポートすると失敗してしまいます。
こんどは再インポートに対応する方法を記述します。
MyAsset.hの修正
・AssetImportDataメンバ変数を指定作成します。
#pragma once #include "CoreMinimal.h" #include "MyAsset.generated.h" UCLASS() class RESTEST_API UMyAsset : public UObject { GENERATED_UCLASS_BODY() public: UPROPERTY(EditAnywhere) int32 ValueA; UPROPERTY(EditAnywhere) int32 ValueB; UPROPERTY(EditAnywhere) int32 ValueC; // ☆追加 #if WITH_EDITORONLY_DATA UPROPERTY(EditAnywhere, Instanced, Category = Reimport) class UAssetImportData* AssetImportData; #endif };
MyAssetFactory.hの修正
・EditorReimportHandler.hをインクルード
・FReimportHandlerを継承するように修正
・オーバーラード関数を定義します。
#pragma once #include "CoreMinimal.h" #include "Factories/Factory.h" #include "EditorReimportHandler.h" #include "MyAssetFactory.generated.h" UCLASS() class RESTEST_API UMyAssetFactory : public UFactory , public FReimportHandler { GENERATED_UCLASS_BODY() virtual bool DoesSupportClass(UClass* Class) override; virtual UClass* ResolveSupportedClass() override; virtual UObject* FactoryCreateNew(UClass* InClass, UObject* InParent, FName InName, EObjectFlags Flags, UObject* Context, FFeedbackContext* Warn) override; virtual UObject* FactoryCreateText(UClass* InClass, UObject* InParent, FName InName, EObjectFlags Flags, UObject* Context, const TCHAR* Type, const TCHAR*& Buffer, const TCHAR* BuferEnd, FFeedbackContext* Warn) override; // ☆追加 virtual bool CanReimport(UObject* Obj, TArray<FString>& OutFilenames) override; virtual void SetReimportPaths(UObject* Obj, const TArray<FString>& NewReimportPaths) override; virtual EReimportResult::Type Reimport(UObject* Obj) override; };
MyAssetFactory.cppの修正
・AssetImportData.hをインクルード
・MyAsset.AssetImportDataの設定部分を追加
・オーバーライド関数の実装を定義します。
#include "MyAssetFactory.h" #include "Misc/FileHelper.h" #include "EditorFrameWork/AssetImportData.h" #include "MyAsset.h" UMyAssetFactory::UMyAssetFactory(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) { SupportedClass = UMyAsset::StaticClass(); bCreateNew = false; bEditorImport = true; bText = true; Formats.Add(TEXT("myasset;My Asset")); } bool UMyAssetFactory::DoesSupportClass(UClass* Class) { return (Class == UMyAsset::StaticClass()); } UClass* UMyAssetFactory::ResolveSupportedClass() { return UMyAsset::StaticClass(); } UObject* UMyAssetFactory::FactoryCreateNew(UClass* InClass, UObject* InParent, FName InName, EObjectFlags Flags, UObject* Context, FFeedbackContext* Warn) { UMyAsset* NewMyAsset = CastChecked<UMyAsset>(StaticConstructObject_Internal(InClass, InParent, InName, Flags)); return NewMyAsset; } UObject* UMyAssetFactory::FactoryCreateText(UClass* InClass, UObject* InParent, FName InName, EObjectFlags Flags, UObject* Context, const TCHAR* Type, const TCHAR*& Buffer, const TCHAR* BuferEnd, FFeedbackContext* Warn) { TArray<FString> Values; FString(Buffer).ParseIntoArray(Values, TEXT(","), true); UMyAsset* NewMyAsset = CastChecked<UMyAsset>(StaticConstructObject_Internal(InClass, InParent, InName, Flags)); if (NewMyAsset && (3 <= Values.Num())) { NewMyAsset->ValueA = FCString::Atoi(*Values[0]); NewMyAsset->ValueB = FCString::Atoi(*Values[1]); NewMyAsset->ValueC = FCString::Atoi(*Values[2]); // ☆追加 if (!NewMyAsset->AssetImportData) { NewMyAsset->AssetImportData = NewObject<UAssetImportData>(NewMyAsset, UAssetImportData::StaticClass()); } NewMyAsset->AssetImportData->Update(CurrentFilename); } return NewMyAsset; } // ☆追加 bool UMyAssetFactory::CanReimport(UObject* Obj, TArray<FString>& OutFilenames) { UMyAsset* MyAsset = Cast<UMyAsset>(Obj); if (MyAsset && MyAsset->AssetImportData) { MyAsset->AssetImportData->ExtractFilenames(OutFilenames); return true; } return false; } // ☆追加 void UMyAssetFactory::SetReimportPaths(UObject* Obj, const TArray<FString>& NewReimportPaths) { UMyAsset* MyAsset = Cast<UMyAsset>(Obj); if (MyAsset && ensure(NewReimportPaths.Num() == 1)) { MyAsset->AssetImportData->UpdateFilenameOnly(NewReimportPaths[0]); } } // ☆追加 EReimportResult::Type UMyAssetFactory::Reimport(UObject* Obj) { UMyAsset* MyAsset = Cast<UMyAsset>(Obj); if (!MyAsset) { return EReimportResult::Failed; } const FString Filename = MyAsset->AssetImportData->GetFirstFilename(); if (!Filename.Len() || IFileManager::Get().FileSize(*Filename) == INDEX_NONE) { return EReimportResult::Failed; } EReimportResult::Type Result = EReimportResult::Failed; if (UFactory::StaticImportObject(MyAsset->GetClass(), MyAsset->GetOuter(), *MyAsset->GetName(), RF_Public|RF_Standalone, *Filename, NULL, this)) { if (MyAsset->GetOuter()) { MyAsset->GetOuter()->MarkPackageDirty(); }else { MyAsset->MarkPackageDirty(); } return EReimportResult::Succeeded; } return EReimportResult::Failed; }
これで無事ビルドがとおるはずです。
ためしにもう一度ファイルをドロップしてインポートしても
問題なく再インポートに成功します。