Last active
September 23, 2024 00:05
-
-
Save kirby561/d10de39f457f15ab24cffbc1787c183f to your computer and use it in GitHub Desktop.
Custom Asset Editors in Unreal Engine 5 - This is the source code from the Custom Asset Editor Youtube video.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma once | |
#include "CoreMinimal.h" | |
#include "CustomAsset.generated.h" | |
UCLASS(BlueprintType) | |
class CUSTOMASSETEDITORRUNTIME_API UCustomAsset : public UObject { | |
GENERATED_BODY() | |
public: | |
UPROPERTY(EditAnywhere) | |
FString SomeData = TEXT("DefaultData"); | |
UPROPERTY(EditAnywhere) | |
int32 SomeNumber = 0; | |
UPROPERTY(EditAnywhere) | |
bool SomeBool = false; | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "CustomAssetAction.h" | |
#include "CustomAsset.h" | |
#include "CustomAssetEditorApp.h" | |
CustomAssetAction::CustomAssetAction(EAssetTypeCategories::Type category) { | |
_assetCategory = category; | |
} | |
FText CustomAssetAction::GetName() const { | |
return NSLOCTEXT("AssetTypeActions", "AssetTypeActions_MyCustomAsset", "My Custom Asset"); | |
} | |
FColor CustomAssetAction::GetTypeColor() const { | |
return FColor::Cyan; | |
} | |
UClass* CustomAssetAction::GetSupportedClass() const { | |
return UCustomAsset::StaticClass(); | |
} | |
void CustomAssetAction::OpenAssetEditor(const TArray<UObject*>& inObjects, TSharedPtr<class IToolkitHost> editWithinLevelEditor) { | |
EToolkitMode::Type mode = editWithinLevelEditor.IsValid() ? EToolkitMode::WorldCentric : EToolkitMode::Standalone; | |
for (UObject* object : inObjects) { | |
UCustomAsset* customAsset = Cast<UCustomAsset>(object); | |
if (customAsset != nullptr) { | |
TSharedRef<CustomAssetEditorApp> editor(new CustomAssetEditorApp()); | |
editor->InitEditor(mode, editWithinLevelEditor, customAsset); | |
} | |
} | |
} | |
uint32 CustomAssetAction::GetCategories() { | |
return _assetCategory; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma once | |
#include "CoreMinimal.h" | |
#include "AssetTypeActions_Base.h" | |
class CustomAssetAction : public FAssetTypeActions_Base { | |
public: | |
CustomAssetAction(EAssetTypeCategories::Type category); | |
public: // FAssetTypeActions_Base interface | |
virtual FText GetName() const override; | |
virtual FColor GetTypeColor() const override; | |
virtual UClass* GetSupportedClass() const override; | |
virtual void OpenAssetEditor(const TArray<UObject*>& inObjects, TSharedPtr<class IToolkitHost> editWithinLevelEditor = TSharedPtr<IToolkitHost>()) override; | |
virtual uint32 GetCategories() override; | |
private: | |
EAssetTypeCategories::Type _assetCategory; | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "CustomAssetAppMode.h" | |
#include "CustomAssetEditorApp.h" | |
#include "CustomAssetPrimaryTabFactory.h" | |
CustomAssetAppMode::CustomAssetAppMode(TSharedPtr<CustomAssetEditorApp> app) : FApplicationMode(TEXT("CustomAssetAppMode")) { | |
_app = app; | |
_tabs.RegisterFactory(MakeShareable(new CustomAssetPrimaryTabFactory(app))); | |
TabLayout = FTabManager::NewLayout("CustomAssetAppMode_Layout_v1") | |
->AddArea | |
( | |
FTabManager::NewPrimaryArea()->SetOrientation(Orient_Vertical) | |
->Split | |
( | |
FTabManager::NewStack() | |
->AddTab(FName(TEXT("CustomAssetPrimaryTab")), ETabState::OpenedTab) | |
) | |
); | |
} | |
void CustomAssetAppMode::RegisterTabFactories(TSharedPtr<class FTabManager> InTabManager) { | |
TSharedPtr<CustomAssetEditorApp> app = _app.Pin(); | |
app->PushTabFactories(_tabs); | |
FApplicationMode::RegisterTabFactories(InTabManager); | |
} | |
void CustomAssetAppMode::PreDeactivateMode() { | |
FApplicationMode::PreDeactivateMode(); | |
} | |
void CustomAssetAppMode::PostActivateMode() { | |
FApplicationMode::PostActivateMode(); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma once | |
#include "CoreMinimal.h" | |
#include "WorkflowOrientedApp/ApplicationMode.h" | |
#include "WorkflowOrientedApp/WorkflowTabManager.h" | |
/** Application mode for main behavior tree editing mode */ | |
class CustomAssetAppMode : public FApplicationMode | |
{ | |
public: | |
CustomAssetAppMode(TSharedPtr<class CustomAssetEditorApp> app); | |
virtual void RegisterTabFactories(TSharedPtr<class FTabManager> InTabManager) override; | |
virtual void PreDeactivateMode() override; | |
virtual void PostActivateMode() override; | |
protected: | |
TWeakPtr<class CustomAssetEditorApp> _app; | |
FWorkflowAllowedTabSet _tabs; | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Copyright Epic Games, Inc. All Rights Reserved. | |
using UnrealBuildTool; | |
public class CustomAssetEditor : ModuleRules | |
{ | |
public CustomAssetEditor(ReadOnlyTargetRules Target) : base(Target) | |
{ | |
PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs; | |
PublicIncludePaths.AddRange( | |
new string[] { | |
// ... add public include paths required here ... | |
} | |
); | |
PrivateIncludePaths.AddRange( | |
new string[] { | |
// ... add other private include paths required here ... | |
} | |
); | |
PublicDependencyModuleNames.AddRange( | |
new string[] | |
{ | |
"Core", | |
// ... add other public dependencies that you statically link with here ... | |
} | |
); | |
PrivateDependencyModuleNames.AddRange( | |
new string[] | |
{ | |
"CoreUObject", | |
"Engine", | |
"Slate", | |
"SlateCore", | |
"CustomAssetEditorRuntime", | |
"AssetTools", | |
"UnrealEd", | |
"PropertyEditor" | |
} | |
); | |
DynamicallyLoadedModuleNames.AddRange( | |
new string[] | |
{ | |
// ... add any modules that your module loads dynamically here ... | |
} | |
); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Copyright Epic Games, Inc. All Rights Reserved. | |
#include "CustomAssetEditor.h" | |
#include "CustomAssetAction.h" | |
#include "IAssetTools.h" | |
#include "AssetToolsModule.h" | |
#define LOCTEXT_NAMESPACE "FCustomAssetEditorModule" | |
void FCustomAssetEditorModule::StartupModule() | |
{ | |
// This code will execute after your module is loaded into memory; the exact timing is specified in the .uplugin file per-module | |
IAssetTools& assetToolsModule = IAssetTools::Get(); | |
EAssetTypeCategories::Type assetType = assetToolsModule.RegisterAdvancedAssetCategory(FName(TEXT("CustomAssets")), LOCTEXT("CustomAssets", "Custom Assets")); | |
TSharedPtr<CustomAssetAction> customAssetAction = MakeShareable(new CustomAssetAction(assetType)); | |
assetToolsModule.RegisterAssetTypeActions(customAssetAction.ToSharedRef()); | |
} | |
void FCustomAssetEditorModule::ShutdownModule() | |
{ | |
// This function may be called during shutdown to clean up your module. For modules that support dynamic reloading, | |
// we call this function before unloading the module. | |
} | |
#undef LOCTEXT_NAMESPACE | |
IMPLEMENT_MODULE(FCustomAssetEditorModule, CustomAssetEditor) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Copyright Epic Games, Inc. All Rights Reserved. | |
#pragma once | |
#include "CoreMinimal.h" | |
#include "Modules/ModuleManager.h" | |
class FCustomAssetEditorModule : public IModuleInterface | |
{ | |
public: | |
/** IModuleInterface implementation */ | |
virtual void StartupModule() override; | |
virtual void ShutdownModule() override; | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "CustomAssetEditorApp.h" | |
#include "CustomAssetAppMode.h" | |
#include "CustomAsset.h" | |
void CustomAssetEditorApp::RegisterTabSpawners(const TSharedRef<class FTabManager>& tabManager) { | |
FWorkflowCentricApplication::RegisterTabSpawners(tabManager); | |
} | |
void CustomAssetEditorApp::InitEditor(const EToolkitMode::Type mode, const TSharedPtr<class IToolkitHost>& initToolkitHost, UObject* inObject) { | |
TArray<UObject*> objectsToEdit; | |
objectsToEdit.Add(inObject); | |
_workingAsset = Cast<UCustomAsset>(inObject); | |
InitAssetEditor( | |
mode, | |
initToolkitHost, | |
TEXT("CustomAssetEditor"), | |
FTabManager::FLayout::NullLayout, | |
true, // createDefaultStandaloneMenu | |
true, // createDefaultToolbar | |
objectsToEdit); | |
// Add our modes (just one for this example) | |
AddApplicationMode(TEXT("CustomAssetAppMode"), MakeShareable(new CustomAssetAppMode(SharedThis(this)))); | |
// Set the mode | |
SetCurrentMode(TEXT("CustomAssetAppMode")); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma once | |
#include "CoreMinimal.h" | |
#include "WorkflowOrientedApp/WorkflowCentricApplication.h" | |
class CustomAssetEditorApp : public FWorkflowCentricApplication, public FEditorUndoClient, public FNotifyHook { | |
public: // FWorkflowCentricApplication interface | |
virtual void RegisterTabSpawners(const TSharedRef<class FTabManager>& TabManager) override; | |
void InitEditor(const EToolkitMode::Type mode, const TSharedPtr<class IToolkitHost>& initToolkitHost, UObject* inObject); | |
class UCustomAsset* GetWorkingAsset() { return _workingAsset; } | |
public: // FAssetEditorToolkit interface | |
virtual FName GetToolkitFName() const override { return FName(TEXT("CustomAssetEditorApp")); } | |
virtual FText GetBaseToolkitName() const override { return FText::FromString(TEXT("CustomAssetEditorApp")); } | |
virtual FString GetWorldCentricTabPrefix() const override { return TEXT("CustomAssetEditorApp"); } | |
virtual FLinearColor GetWorldCentricTabColorScale() const override { return FLinearColor(0.3f, 0.2f, 0.5f, 0.5f); } | |
virtual FString GetDocumentationLink() const override { return TEXT("https://github.com/kirby561"); } | |
virtual void OnToolkitHostingStarted(const TSharedRef<class IToolkit>& Toolkit) override { } | |
virtual void OnToolkitHostingFinished(const TSharedRef<class IToolkit>& Toolkit) override { } | |
private: | |
class UCustomAsset* _workingAsset = nullptr; | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Copyright Epic Games, Inc. All Rights Reserved. | |
using UnrealBuildTool; | |
public class CustomAssetEditorRuntime : ModuleRules | |
{ | |
public CustomAssetEditorRuntime(ReadOnlyTargetRules Target) : base(Target) | |
{ | |
PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs; | |
PublicIncludePaths.AddRange( | |
new string[] { | |
// ... add public include paths required here ... | |
} | |
); | |
PrivateIncludePaths.AddRange( | |
new string[] { | |
// ... add other private include paths required here ... | |
} | |
); | |
PublicDependencyModuleNames.AddRange( | |
new string[] | |
{ | |
"Core", | |
// ... add other public dependencies that you statically link with here ... | |
} | |
); | |
PrivateDependencyModuleNames.AddRange( | |
new string[] | |
{ | |
"CoreUObject", | |
"Engine", | |
"Slate", | |
"SlateCore", | |
// ... add private dependencies that you statically link with here ... | |
} | |
); | |
DynamicallyLoadedModuleNames.AddRange( | |
new string[] | |
{ | |
// ... add any modules that your module loads dynamically here ... | |
} | |
); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Copyright Epic Games, Inc. All Rights Reserved. | |
#include "CustomAssetEditorRuntime.h" | |
#define LOCTEXT_NAMESPACE "FCustomAssetEditorRuntimeModule" | |
void FCustomAssetEditorRuntimeModule::StartupModule() | |
{ | |
// This code will execute after your module is loaded into memory; the exact timing is specified in the .uplugin file per-module | |
} | |
void FCustomAssetEditorRuntimeModule::ShutdownModule() | |
{ | |
// This function may be called during shutdown to clean up your module. For modules that support dynamic reloading, | |
// we call this function before unloading the module. | |
} | |
#undef LOCTEXT_NAMESPACE | |
IMPLEMENT_MODULE(FCustomAssetEditorRuntimeModule, CustomAssetEditor) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Copyright Epic Games, Inc. All Rights Reserved. | |
#pragma once | |
#include "CoreMinimal.h" | |
#include "Modules/ModuleManager.h" | |
class FCustomAssetEditorRuntimeModule : public IModuleInterface | |
{ | |
public: | |
/** IModuleInterface implementation */ | |
virtual void StartupModule() override; | |
virtual void ShutdownModule() override; | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "CustomAssetFactory.h" | |
#include "CustomAsset.h" | |
UCustomAssetFactory::UCustomAssetFactory(const FObjectInitializer& objectInitializer) : Super(objectInitializer) { | |
SupportedClass = UCustomAsset::StaticClass(); | |
} | |
UObject* UCustomAssetFactory::FactoryCreateNew(UClass* uclass, UObject* inParent, FName name, EObjectFlags flags, UObject* context, FFeedbackContext* warn) { | |
UCustomAsset* asset = NewObject<UCustomAsset>(inParent, name, flags); | |
return asset; | |
} | |
bool UCustomAssetFactory::CanCreateNew() const { | |
return true; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma once | |
#include "CoreMinimal.h" | |
#include "CustomAssetFactory.generated.h" | |
UCLASS() | |
class UCustomAssetFactory : public UFactory { | |
GENERATED_BODY() | |
public: | |
UCustomAssetFactory(const FObjectInitializer& objectInitializer); | |
public: // UFactory interface | |
virtual UObject* FactoryCreateNew(UClass* uclass, UObject* inParent, FName name, EObjectFlags flags, UObject* context, FFeedbackContext* warn) override; | |
virtual bool CanCreateNew() const override; | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "CustomAssetPrimaryTabFactory.h" | |
#include "CustomAssetEditorApp.h" | |
#include "CustomAsset.h" | |
#include "IDetailsView.h" | |
#include "PropertyEditorModule.h" | |
CustomAssetPrimaryTabFactory::CustomAssetPrimaryTabFactory(TSharedPtr<CustomAssetEditorApp> app) : FWorkflowTabFactory(FName("CustomAssetPrimaryTab"), app) { | |
_app = app; | |
TabLabel = FText::FromString(TEXT("Primary")); | |
ViewMenuDescription = FText::FromString(TEXT("Displays a primary view for whatever you want to do.")); | |
ViewMenuTooltip = FText::FromString(TEXT("Show the primary view.")); | |
} | |
TSharedRef<SWidget> CustomAssetPrimaryTabFactory::CreateTabBody(const FWorkflowTabSpawnInfo& Info) const { | |
TSharedPtr<CustomAssetEditorApp> app = _app.Pin(); | |
FPropertyEditorModule& propertyEditorModule = FModuleManager::LoadModuleChecked<FPropertyEditorModule>(TEXT("PropertyEditor")); | |
FDetailsViewArgs detailsViewArgs; | |
{ | |
detailsViewArgs.bAllowSearch = false; | |
detailsViewArgs.bHideSelectionTip = true; | |
detailsViewArgs.bLockable = false; | |
detailsViewArgs.bSearchInitialKeyFocus = true; | |
detailsViewArgs.bUpdatesFromSelection = false; | |
detailsViewArgs.NotifyHook = nullptr; | |
detailsViewArgs.bShowOptions = true; | |
detailsViewArgs.bShowModifiedPropertiesOption = false; | |
detailsViewArgs.bShowScrollBar = false; | |
} | |
TSharedPtr<IDetailsView> detailsView = propertyEditorModule.CreateDetailView(detailsViewArgs); | |
detailsView->SetObject(app->GetWorkingAsset()); | |
return SNew(SVerticalBox) | |
+ SVerticalBox::Slot() | |
.FillHeight(1.0f) | |
.HAlign(HAlign_Fill) | |
[ | |
detailsView.ToSharedRef() | |
]; | |
} | |
FText CustomAssetPrimaryTabFactory::GetTabToolTipText(const FWorkflowTabSpawnInfo& Info) const { | |
return FText::FromString(TEXT("A primary view for doing primary things.")); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma once | |
#include "CoreMinimal.h" | |
#include "WorkflowOrientedApp/WorkflowTabFactory.h" | |
class CustomAssetPrimaryTabFactory : public FWorkflowTabFactory { | |
public: | |
CustomAssetPrimaryTabFactory(TSharedPtr<class CustomAssetEditorApp> app); | |
virtual TSharedRef<SWidget> CreateTabBody(const FWorkflowTabSpawnInfo& Info) const override; | |
virtual FText GetTabToolTipText(const FWorkflowTabSpawnInfo& Info) const override; | |
protected: | |
TWeakPtr<class CustomAssetEditorApp> _app; | |
}; |
Firstly, thank you for these tutorials. I thought you would like to know that the _workingAsset field, defined in CustomEditorApp.h, being marked as a UPROPERTY has no effect inside a non-UCLASS class.
Woops, thanks for the correction!
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Firstly, thank you for these tutorials. I thought you would like to know that the _workingAsset field, defined in CustomEditorApp.h, being marked as a UPROPERTY has no effect inside a non-UCLASS class.