BLOGブログ

2015.01.23UE4UE/ C++

[UE4] 独自のアセットを実装する方法(3) 再インポートの実装

※ 2019/10/31追記:この記事は古くなっており、最新のバージョンでは動作しない可能性があります。

前回の記事で、独自のアセットを外部ファイルからインポートする方法をご紹介しました。

しかし、実際のゲームプロジェクトで使用する場合、一度のインポートで完結することは殆ど無いと思います。

 

やはり、繰り返しの調整に対応するため、再インポート機能に対応したいところです。

今回は、その実装方法をご紹介したいと思います。

 

1.Asset及びFactoryをReimportに対応する

//~中略~

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 Values;
FString(Buffer).ParseIntoArray(&Values, TEXT(“,”), true);

UMyAsset* NewMyAsset =
CastChecked(StaticConstructObject(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 =
ConstructObject(UAssetImportData::StaticClass(), NewMyAsset);
}

NewMyAsset->AssetImportData->SourceFilePath =
FReimportManager::SanitizeImportFilename(CurrentFilename, NewMyAsset);
NewMyAsset->AssetImportData->SourceFileTimestamp =
IFileManager::Get().GetTimeStamp(*CurrentFilename).ToString();
NewMyAsset->AssetImportData->bDirty = false;
}

return NewMyAsset;
}

bool UMyAssetFactory::CanReimport(UObject* Obj, TArray& OutFilenames)
{
UMyAsset* MyAsset = Cast(Obj);
if(MyAsset && MyAsset->AssetImportData)
{
OutFilenames.Add(FReimportManager::ResolveImportFilename(
MyAsset->AssetImportData->SourceFilePath, MyAsset));
return true;
}
return false;
}
void UMyAssetFactory::SetReimportPaths(UObject* Obj, const TArray& NewReimportPaths)
{
UMyAsset* MyAsset = Cast(Obj);
if(MyAsset && ensure(NewReimportPaths.Num() == 1))
{
MyAsset->AssetImportData->SourceFilePath =
FReimportManager::ResolveImportFilename(NewReimportPaths[0], MyAsset);
}
}
EReimportResult::Type UMyAssetFactory::Reimport(UObject* Obj)
{
UMyAsset* MyAsset = Cast(Obj);
if(!MyAsset)
{
return EReimportResult::Failed;
}

const FString Filename = FReimportManager::ResolveImportFilename(
MyAsset->AssetImportData->SourceFilePath, MyAsset);
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;
}

 

まずは、MyAssetに再インポート用の情報を保存出来るように、UAssetImportDataを追加します。

このメンバはエディタでしか使用しませんので、#if WITH_EDITORONLY_DATAで囲っておきます。

 

次に、UMyAssetFactory::FactoryCreateText()でファイルをインポートした再に、ファイルパスとタイムスタンプを保存しておきます。

 

そして、このアセットが再インポート可能である、ということを示すため、UMyAssetFactoryの基底クラスにFReimportHandlerを追加し、CanReimport(),SetReimportPaths(),Reimport()の3つの関数を追加します。

ここから、先ほど追加したAssetImportDataを参照し、再インポート可能かどうかの判断が行われ、UFactory::StaticImportObject()の呼び出しを経由して再インポートが実行されます。

 

これで再インポートの準備は整いましたが、このままではアセットを右クリックしたメニューに、再インポートのための項目が登録されていません。

次はContentBrowserに、このアセットが再インポート可能だということを通知する必要があります。

 

2.AssetTypeActionsの追加

ContentBrowser上でアセットを右クリックした際に出てくるメニューを拡張するには、アセットに対応した AssetTypeActions クラスを実装する必要があります。

参照先モジュールに “AssetTools” を追加し、AssetTypeActionsクラスを実装します。

class FAssetTypeActions_MyAsset : public FAssetTypeActions_Base
{
public:
virtual FText GetName() const override
{ return NSLOCTEXT(“AssetTypeActions”, “AssetTypeActions_MyAsset”, “MyAsset”); }
virtual FColor GetTypeColor() const override { return FColor::White; }
virtual uint32 GetCategories() override { return EAssetTypeCategories::Misc; }
virtual UClass* GetSupportedClass() const override;
virtual bool IsImportedAsset() const override { return true; }
};

#define LOCTEXT_NAMESPACE “AssetTypeActions”

UClass* FAssetTypeActions_MyAsset::GetSupportedClass() const
{
return UMyAsset::StaticClass();
}

#undef LOCTEXT_NAMESPACE

FAssetTypeActions_Baseクラスを継承し、自分のアセットの情報を登録します。

特に重要なのは、GetSupportedClass()で、ココでアセットの型情報を指定します。

 

今回は独自のアクションを追加する訳ではないので、 IsImportedAsset() をオーバーライドすれば、”Reimport”メニューが実装されます。

 

3.AssetTypeActionsをAssetToolsモジュールに登録

AssetTypeActionsクラスは、クラスを定義しただけでは動作してくれません。

AssetToolsモジュールへの登録を行う必要があります。

 

この登録は、通常、AssetTypeActionsを実装したモジュールのロード時に行います。

モジュールの初期化コードが書かれている、プロジェクトと同じ名前が付いているcppを↓のように編集します。

 

class FBlog_MyAsset : public FDefaultGameModuleImpl
{
virtual void StartupModule() override;
virtual void ShutdownModule() override;
TSharedPtr MyAsset_AssetTypeActions;
};
IMPLEMENT_PRIMARY_GAME_MODULE( FBlog_MyAsset, Blog_MyAsset, “Blog_MyAsset” );

void FBlog_MyAsset::StartupModule()
{
MyAsset_AssetTypeActions = MakeShareable(new FAssetTypeActions_MyAsset);
FModuleManager::LoadModuleChecked(“AssetTools”).Get()
.RegisterAssetTypeActions(MyAsset_AssetTypeActions.ToSharedRef());
}
void FBlog_MyAsset::ShutdownModule()
{
if (MyAsset_AssetTypeActions.IsValid())
{
if (FModuleManager::Get().IsModuleLoaded(“AssetTools”))
{
FModuleManager::GetModuleChecked(“AssetTools”).Get()
.UnregisterAssetTypeActions(MyAsset_AssetTypeActions.ToSharedRef());
}
MyAsset_AssetTypeActions.Reset();
}
}

 

これで、モジュールのロード時に、AssetTypeActions_MyAssetが登録され、実際にContentBrowser上から再インポートが呼び出せるようになります。

 

実際に ImportSample.myasset の中身を書き換えて実行し、値が再読み込みされているのを確認してみて下さい。

 

コードばかりで長くなってしまいましたが、最後まで読んで頂き、ありがとうございました。

次回は、今回追加したAssetTypeActionsを利用して、アセットに対する独自のアクションを実装してみます。

 

[UE4] 独自のアセットを実装する方法(1) アセットクラスの実装
[UE4] 独自のアセットを実装する方法(2) インポートの実装
[UE4] 独自のアセットを実装する方法(3) 再インポートの実装
[UE4] 独自のアセットを実装する方法(4) アセットにアクションを追加する
[UE4] 独自のアセットを実装する方法(5) アセットエディタを実装する
[UE4] 独自のアセットを実装する方法(6) 独自のシリアライズを実装する