【UE客户端/技术策划】- 工具链篇: 资产编辑器(一) #5.2+ (施工中)

本文在博客园原创,转载请标注出处

前言

由于5.2+ UE更新了新的资产管理体系,市面上很多资产编辑器开发博客仍然停留在UE4版本,于是笔者在这里利用自身的项目正好对现在5.2+新版本的资产编辑器进行一个总结

Step1. 创建/注册资产 + 默认编辑器

自定义资产类 (Runtime模块)

如果资产编辑器中具备图表等,通常情况下会直接保存在资产中
资产类通常与编辑器分为两个模块(资产类位于Runtime模块,编辑器位于Editor)

UCLASS()
class EVENTENGINE_API UEventCore : public UObject
{
	GENERATED_BODY()

	
public:
	//事件ID,Runtime下唯一
	UPROPERTY(EditAnywhere,BlueprintReadOnly)
	int32 EventCoreID;
};


//流程化的事件核心资产,具备编辑器支持
UCLASS()
class EVENTENGINE_API UFlowEventAsset : public UEventCore
{
	GENERATED_BODY()

};

注册资产 (Editor模块)

由于5.2+ UE对资产管理器进行了更新,现版本不需要进行手动注册即可完成编辑器对资产注册和创建,无需手动New出,详情见笔者的上一篇博客
要将资产注册到引擎且能够产生基础的编辑器界面我们需要两个类进行配合。
只完成这两个类即可产生引擎默认原生编辑器(无需重写OpenAssets)

image

//由于其代码非常基础,不再赘述
/**
 * 5.2+ 新版资产属性,提供资产和实际类进行绑定。名称、资产颜色、资产类别、唤起资产编辑器的回调等
 */
UCLASS()
class FLOWEVENTEDITOR_API UAssetDefinition_FlowEventAsset : public UAssetDefinitionDefault
{
	GENERATED_BODY()

public:
	//获取资产自定义命名
	virtual FText GetAssetDisplayName() const override;
	virtual FLinearColor GetAssetColor() const override;
	//		核心		//
	//绑定的实际资产类
	virtual TSoftClassPtr<UObject> GetAssetClass() const override;
	//唤起资产编辑器
	virtual EAssetCommandResult OpenAssets(const FAssetOpenArgs& OpenArgs) const override;
};


UCLASS(HideCategories = Object)
class FLOWEVENTEDITOR_API UFlowEventAssetFactory : public UFactory
{
	GENERATED_BODY()

public:
	UFlowEventAssetFactory(const FObjectInitializer& ObjectInitializer);
	virtual bool ConfigureProperties() override;
	virtual UObject* FactoryCreateNew(UClass* Class, UObject* InParent, FName Name, EObjectFlags Flags, UObject* Context, FFeedbackContext* Warn) override;
};

Step2. 自定义编辑器

由于前方并没有指定编辑器,所以UE会诞生一个默认的只有细节面板的临时编辑器,接下来需要创建自定义编辑器,通常分为两步,涉及到两个类

构建自定义编辑器

FAssetEditorToolkit和它的子类FWorkflowCentricApplication,它们被用来构建工作流程和编辑器类型的应用程序。


class FLOWEVENTEDITOR_API FFlowEventAssetEditor : public FAssetEditorToolkit
{
public:
	/**	The tab ids for all the tabs used */
	static const FName DetailsTab;
	static const FName GraphTab;
	static const FName PaletteTab;

public:
	FFlowEventAssetEditor();
	virtual ~FFlowEventAssetEditor() override;
	//			Step1 继承编辑器类的核心方法		//
	// IToolkit
	virtual FName GetToolkitFName() const override;
	virtual FText GetBaseToolkitName() const override;
	virtual FString GetWorldCentricTabPrefix() const override;
	virtual FLinearColor GetWorldCentricTabColorScale() const override;

	virtual void RegisterTabSpawners(const TSharedRef<class FTabManager>& TabManager) override;
	virtual void UnregisterTabSpawners(const TSharedRef<class FTabManager>& TabManager) override;
	// --

	// FAssetEditorToolkit
	virtual void InitToolMenuContext(FToolMenuContext& MenuContext) override;
	virtual void PostRegenerateMenusAndToolbars() override;
	virtual bool CanSaveAsset() const override;
	// --

	void InitFlowEventAssetEditor(const EToolkitMode::Type Mode, const TSharedPtr<class IToolkitHost>& InitToolkitHost, UObject* ObjectToEdit);
	
};

自定义编辑器与自定义资产挂钩

Tips:由于新版中资产能够自动注册,因此现在没有必要将创建编辑器方法放在模块中(过去通常这样做,且将模块作为静态类获取),可以直接在UAssetDefinitionDefault的子类中直接进行
UAssetDefinitionDefault::OpenAssets是自定义资产和自定义编辑器挂钩的核心,只要实现这个就能完成编辑器和资产的绑定,同时也可以将创建编辑器的方法提供在此类中

TSharedRef<FFlowEventAssetEditor> UAssetDefinition_FlowEventAsset::CreateFlowEventAssetEditor(const EToolkitMode::Type Mode, const TSharedPtr<IToolkitHost>& InitToolkitHost, UFlowEventAsset* FlowEventAsset)
{
	TSharedRef<FFlowEventAssetEditor> NewFlowEventAssetEditor(new FFlowEventAssetEditor());
	NewFlowEventAssetEditor->InitFlowEventAssetEditor(Mode, InitToolkitHost, FlowEventAsset);
	return NewFlowEventAssetEditor;
}

EAssetCommandResult UAssetDefinition_FlowEventAsset::OpenAssets(const FAssetOpenArgs& OpenArgs) const
{
	//return Super::OpenAssets(OpenArgs);
	const EToolkitMode::Type Mode = OpenArgs.ToolkitHost.IsValid() ? EToolkitMode::WorldCentric : EToolkitMode::Standalone;

	for (const FAssetData& AssetData : OpenArgs.Assets)
	{
		UObject* LoadedObject = AssetData.GetAsset();
		if (UFlowEventAsset* GraphSampleAsset = Cast<UFlowEventAsset>(LoadedObject))
		{
			CreateFlowEventAssetEditor(Mode, OpenArgs.ToolkitHost, GraphSampleAsset);
		}
	}

	return EAssetCommandResult::Handled;
}

当以上操作完成后,编辑器现在还不能打开,因为没有指定布局填充,现在需要提供一个基础的layout填充编辑器

void FFlowEventAssetEditor::InitFlowEventAssetEditor(const EToolkitMode::Type Mode,const TSharedPtr<class IToolkitHost>& InitToolkitHost, UObject* ObjectToEdit)
{
	const TSharedRef<FTabManager::FLayout> StandaloneDefaultLayout = FTabManager::NewLayout("FlowEventAssetEditor_Layout_v0.1")
		->AddArea
		(
			FTabManager::NewPrimaryArea()->SetOrientation(Orient_Horizontal)
				->Split
				(
					FTabManager::NewStack()
					->SetSizeCoefficient(0.225f)
					->AddTab(DetailsTab, ETabState::OpenedTab)
				)
				->Split
				(
					FTabManager::NewStack()
					->SetSizeCoefficient(0.6f)
					->SetHideTabWell(true)
					->AddTab(GraphTab, ETabState::OpenedTab)
				)

				->Split
				(
					FTabManager::NewStack()
					->SetSizeCoefficient(0.175f)
					->AddTab(PaletteTab, ETabState::OpenedTab)
				)
		);

	constexpr bool bCreateDefaultStandaloneMenu = true;
	constexpr bool bCreateDefaultToolbar = true;

	//将Layout传入进行初始化编辑器布局
	InitAssetEditor(Mode, InitToolkitHost, TEXT("FlowEventEditorApp"), StandaloneDefaultLayout, bCreateDefaultStandaloneMenu, bCreateDefaultToolbar, ObjectToEdit, false);

	RegenerateMenusAndToolbars();
}

填充过后即可打开编辑器

image

posted @ 2025-11-17 19:55  丨桐  阅读(7)  评论(0)    收藏  举报