While our game may be running without any issues in the editor or even in…
Creating Custom Editor Assets
In this post we’re going to create custom editor assets. In order to extend the UE4 Editor and add your own assets you need two classes:
- One class that contains the various properties of your asset
- One class (named XFactory where the X stands for the asset’s class name) that constructs the above class as an Editor asset (meaning a .uasset file).
For most assets, their factory classes are inside the EditorFactories files of the Editor. For example, when you’re creating a new Texture inside the Editor you will be presented with the various properties that are written in the Texture.h file. However, the class (named UTexture2DFactoryNew) that constructs this asset in the Editor is contained inside the EditorFactories.
So, let’s create our custom editor assets.
Creating the Asset class
In order to create a custom class, add a new C++ class (I’ve named my class as OrfeasCustomAsset) that inheirts the Object class and type the following code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
#include "CoreMinimal.h" #include "UObject/NoExportTypes.h" #include "OrfeasCustomAsset.generated.h" /** * */ UCLASS() class CUSTOMASSET_API UOrfeasCustomAsset : public UObject { GENERATED_BODY() protected: //Just some properties to display on the Editor UPROPERTY(EditAnywhere) FString Description; UPROPERTY(EditAnywhere) int32 BonusCoins; }; |
Then, add a new C++ class that inherits the factory class:
and add the following code to its header file:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
UCLASS() class CUSTOMASSET_API UOrfeasFactory : public UFactory { GENERATED_BODY() public: UOrfeasFactory(); /* New assets that don't override this function are automatically placed into the "Miscellaneous" category in the editor */ virtual uint32 GetMenuCategories() const override; /* Creates the asset inside the UE4 Editor */ virtual UObject* FactoryCreateNew(UClass* InClass, UObject* InParent, FName InName, EObjectFlags Flags, UObject* Context, FFeedbackContext* Warn) override; }; |
Let’s type the logic for these function inside our source file:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
#include "OrfeasFactory.h" //The asset header file that we wish to create #include "OrfeasCustomAsset.h" //The asset type categories will let us access the various asset categories inside the Editor #include "AssetTypeCategories.h" UOrfeasFactory::UOrfeasFactory() { bCreateNew = true; bEditAfterNew = true; //Configure the class that this factory creates SupportedClass = UOrfeasCustomAsset::StaticClass(); } uint32 UOrfeasFactory::GetMenuCategories() const { //Let's place this asset in the Blueprints category in the Editor return EAssetTypeCategories::Blueprint; } UObject* UOrfeasFactory::FactoryCreateNew(UClass* InClass, UObject* InParent, FName InName, EObjectFlags Flags, UObject* Context, FFeedbackContext* Warn) { //Create the editor asset UOrfeasCustomAsset* OrfeasEditorAsset = NewObject<UOrfeasCustomAsset>(InParent, InClass, InName, Flags); return OrfeasEditorAsset; } |
In order to access the AssetTypeCategories.h file you need to add the “AssetTools” in your project’s public dependencies:
PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore", "AssetTools" });At this point, save and compile your code. Then, restart the Editor and check out the Blueprints category:
Adding a custom thumbnail to your asset
The default thumbnail for your new asset is simply the name of the Asset’s class. In case you want to have a customized thumbnail you need to create a new Slate style and bind it with this asset’s class.
Ideally, you will place your new assets in a new module or plugin. For the sake of this example, I’m going to use a plugin’s startup module in order to create a new slate style for my custom assets. At this point, I’ve added a blank plugin named “OrfeasPlugin” into my project and I’m going to use its default icon as a new thumbnail. Go inside your plugin’s header file and add the following code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
#include "CoreMinimal.h" #include "ModuleManager.h" #include "SlateStyle.h" class FOrfeasPluginModule : public IModuleInterface { public: TSharedPtr<FSlateStyleSet> StyleSet; /** IModuleInterface implementation */ virtual void StartupModule() override; virtual void ShutdownModule() override; }; |
Then, inside your plugin’s source file, add the following code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
#include "IPluginManager.h" #include "SlateStyleRegistry.h" #define LOCTEXT_NAMESPACE "FOrfeasPluginModule" void FOrfeasPluginModule::StartupModule() { // This code will execute after your module is loaded into memory; the exact timing is specified in the .uplugin file per-module StyleSet = MakeShareable(new FSlateStyleSet("OrfeasStyle")); //Content path of this plugin FString ContentDir = IPluginManager::Get().FindPlugin("OrfeasPlugin")->GetBaseDir(); //The image we wish to load is located inside the Resources folder inside the Base Directory //so let's set the content dir to the base dir and manually switch to the Resources folder: StyleSet->SetContentRoot(ContentDir); //Create a brush from the icon FSlateImageBrush* ThumbnailBrush = new FSlateImageBrush(StyleSet->RootToContentDir(TEXT("Resources/Icon128"), TEXT(".png")), FVector2D(128.f, 128.f)); if (ThumbnailBrush) { //In order to bind the thumbnail to our class we need to type ClassThumbnail.X where X is the name of the C++ class of the asset StyleSet->Set("ClassThumbnail.OrfeasCustomAsset", ThumbnailBrush); //Reguster the created style FSlateStyleRegistry::RegisterSlateStyle(*StyleSet); } } void FOrfeasPluginModule::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. //Unregister the style FSlateStyleRegistry::UnRegisterSlateStyle(StyleSet->GetStyleSetName()); } #undef LOCTEXT_NAMESPACE IMPLEMENT_MODULE(FOrfeasPluginModule, OrfeasPlugin) |
In order to access the IPluginManager.h header file you need to add the “Projects” dependency on your plugin’s dependencies:
1 2 3 4 5 6 7 8 9 10 11 |
PrivateDependencyModuleNames.AddRange( new string[] { "CoreUObject", "Engine", "Slate", "SlateCore", "Projects" // ... add private dependencies that you statically link with here ... } ); |
As a last step, make sure to mark your plugin’s type as Runtime instead of Developer so you can ship your project successfully.
Save and compile your code. Then, restart the Editor.
Here is the end result:
This is really helpful, I just wish there was information on creating editor menus as I can’t seem to get past this part to actually making a functional asset instead of something that just stores data.
Thanks!
Assertion failed: Child->IsChildOf(Parent) [File:D:\Build\++UE4\Sync\Engine\Source\Runtime\CoreUObject\Private\UObject\UObjectGlobals.cpp] [Line: 3037] NewObject called with invalid class, DGRGAnimationSetAssetFactory must be a child of DGRGAnimationSetAsset
Thank you for the quick summary, I was missing this line:
FSlateStyleRegistry::RegisterSlateStyle(*StyleSet);
…and you set me straight!
Hi,
Is there a reason why same code works for project based on pre-builded engine install, and
don’t work at all on my own builded engine from source code? Both cases: 4.24
Hello,
I’m afraid I haven’t tested this out. Usually when something doesn’t work in a different build it’s enclosed in various build configurations that do not apply in 2 different cases, however I may be wrong on this one.
-Orfeas
Having attempted to do this all via a Plugins’ source folder than a Projects I cannot see the additional context menu item for my custom item.
I didn’t understand your setup, can you elaborate on this?
-Orfeas
Not sure if it’s a 4.26 thing, but I had to add “UnrealEd” to my private dependency modules to get this to compile…
Also, like George above I suspect, my custom category isn’t showing up in the blueprint menu section…
you need this in your StartupModule
IAssetTools& AssetTools = FModuleManager::LoadModuleChecked(“AssetTools”).Get();
DialogueAssetCategory = AssetTools.RegisterAdvancedAssetCategory(FName(TEXT(“Water”)), LOCTEXT(“DialogueAssetCategory”, “Water”));
The ‘Water’ plugin has all the new stuff
Hello, I’m working on 4.26.2 and cant manage to see my custom class in miscellaneous or any other categories, I followed every step and I don’t know where is my mistake.
Did you find a solution? I am having the same problem. 4.27
This was great! I was able to set up an asset for a custom importer I’m working on in no time! I just wish there was better documentation about this stuff.
To expand on what you explained though, how would one go about creating functionality so that you can drag and drop these custom assets into the viewport, and it will create an actor for you? Kinda like what happens with Static Mesh -> Static Mesh Actor?
It would be great if you could point me in the right direction!
In UE4.27.1 the Custom Asset won’t show up in the context menu.
Do you know what or how it needs to be changed to make it work?
I have the same problem. Everything I’ve seen says the same thing: create the subclass of UFactory, and the new asset type should appear in the context menu, but it doesn’t happen. Did you ever find an answer?
Did you find a solution? I am having the same problem. 4.27
The explanations are very good, and the sample code is well-commented. Thank you!