How to Create Assets Visible to the Content Browser in C++

Hi All,

Sorry if this seems like a simple question, but how exactly would one create an object that is visible to the content browser (editor) through c++?

This mainly pertains to inbuilt objects such as materials, curves etc.

So I guess the question is, how do I create a UCurveFloat / UCurve object using C++ that will appear in the content browser? – (Seems I’ve tried everything! )

Thank you for any help in advance!

Assets are just UObjects, but you need to do a few things to register them as Assets. Someone has made an Text Asset Plugin which I used to see how I can make my own Assets. Everything you need to know is included there, how to register it and how to make your own editor for it.

If you want to learn more about it, you need to dig through the Unreal code and see how they have done it.

Thanks for replying!

I have had an extensive dig around in the source for how it is implemented, however I’m 100% sure on how to call a factory to create an object.

As far as I can tell, creating an object is a matter of a line such as the following:

NewObject(InParent, InClass, InName, Flags) – Which occurs within the factory.

Being that factories are the preferred method of creating objects, how does one call a factory to create an object? – I believe I am on the right track, but I am getting unresolved externals

testfactory.FactoryCreateNew(UCurveBase::StaticClass(), OutermostPkg, CurveName, Flags, NULL, GWarn);

What I’m really after is just an example of how I can call an Inbuilt factory for UCurve, Material, or similar to create an object.

Exactly as it is created when using the Right-Click menu in the Editor, except in this instance I’ll be using C++.

Shouldnt this just be as easy as …

UCurveFloat* NewCurve = NewObject<UCurveFloat>();

I don’t really understand why it doesn’t work…

Edit: Sorry if I sound frustrated, I’ve just been at this for a couple of days, digging around trying to find something that should by all accounts be easy. I’ve even tried backtracking from the GUI options when you right-click on the content browser to create an object.

First, have you looked in the “TextAssetEditor.Build.cs”? You need to add a few dependencies to your module to use the AssetTools

PrivateIncludePathModuleNames.AddRange(
			new string[] {
"AssetTools",
...

Then you also need to implement an asset action for your asset and register it in your module, the action tells the editor what name your asset has and to what category it belongs. You can leave out the “GetActions” function and return false at the “HasActions” function.

Take a look at the “TextAssetEditorModule.cpp” and at the “TextAssetActions” files. If you leave out the “OpenAssetEditor” function, unreal will just open a default property editor window for your asset.

When you have registeres your asset action, the asset shows up in the category you specified and the “FactoryCreateNew” function is called when you add the asset. You probably have to restart the editor, I think the hot reload don’t work fine with this.

Thanks for helping out!

So I understand how to go ahead and configure a NEW type of asset that can be added to the Content Browser, so when I right-click to add a new asset it will iterate through all the factories (as seen in NewAssetOrClassContextMenu.cpp) and the new asset will be one of the options.

However, if I want to add that Asset automatically using CODE as part of my plugin (or even a custom blueprint module etc), how do I do this?

How do I call the UFactory interface specifically to create the asset? – Is it something like the following?

	virtual UObject* FactoryCreateNew(UClass* InClass, UObject* InParent, FName InName, EObjectFlags Flags, UObject* Context, FFeedbackContext* Warn) override;

What data do I fill in for ‘InClass’, ‘InParent’ etc…?

Thanks again, I really appreciate the help

1 Like

Okay, I missunderstood your question first, thinking you just wanted to creat it by context menu, sorry for that :), but your question is quite complicated but got me interested as I want to also know how to do that now.

But I digged a little bit in the code and may found what you are looking for. In the “LevelEditorViewport.cpp” file in the “GetOrCreateMaterialFromTexture(…)”(Line 395) function is a good example how to do that. It seems the “InParent” must be a UPackage, and you need to create it with a proper file name but I think you can figure out how to make that name. The “CreatePackage(…)” function is global.

The rest of the parameters a very simple:

InClass is simple, just use “YourAsset”::StaticClass() to get the class.
InName is obvious and you can copy the flags from the example.
Context can just be a nullptr and for Warn they just use the globel GWarn variable.

Thanks again for looking into this, I really appreciate it!

I feel like we are very close to getting this functional, at least for curves.

I’ve tried the following in one of my files…

auto CurveFactory = NewObject<UCurveFactory>();
FString PackageName;
FString CurveName;
UPackage* Package = CreatePackage(NULL, *PackageName);
UObject* TestObj = CurveFactory->FactoryCreateNew(UCurveFactory::StaticClass(), Package, *CurveName, RF_Standalone | RF_Public, NULL, GWarn);

However I am getting unresolved symbols, I wonder if this is because the definitions for UCurveFactory or UCurveFloatFactory do not have ENGINE_API flagged on them?

EDIT:

Same result with the following as well…

auto CurveFactory = NewObject<UCurveFloatFactory >();

OK, so I managed to get it working! (with your help of course!)

So, basically there are three components:

  • The Factory (.cpp + .h)
  • The Asset Definition (we are using the inbuild Unreal one as I’m on interested in their assets for the moment)
  • Actually utilizing the factory to create the Asset

I’ll include my basic definition for curves:

MyFactory.cpp

MyCurveFactory::MyCurveFactory(const FObjectInitializer& ObjectInitializer)
    	: Super(ObjectInitializer)
    {
    	SupportedClass = UCurveFloat::StaticClass();
    }
    
    UObject* MyCurveFactory::FactoryCreateNew(UClass* InClass, UObject* InParent, FName InName, EObjectFlags Flags, UObject* Context, FFeedbackContext* Warn)
    {
    
    	UCurveBase* NewCurve = nullptr;
    	
    	NewCurve = NewObject<UCurveBase>(InParent, InClass, InName, Flags);
    
    	return NewCurve;
    }
    
    bool MyCurveFactory::ShouldShowInNewMenu() const
    {
    	return true;
    }

MyFactory.h

UCLASS()
class MyCurveFactory : public UFactory
{
	GENERATED_UCLASS_BODY()

public:

	virtual UObject* FactoryCreateNew(UClass* InClass, UObject* InParent, FName InName, EObjectFlags Flags, UObject* Context, FFeedbackContext* Warn) override;
	virtual bool ShouldShowInNewMenu() const override;

};

In-Text usage of the factories (ideally, create a function for this)

FString FinalPackageName = TEXT("/Game/testpackage");
FString CurveName = FString(TEXT("curve"));
UPackage* Package = CreatePackage(NULL, *FinalPackageName);

UPackage* OutermostPkg = Package->GetOutermost();

auto CurveFactory = NewObject<Um2uCurveFloatFactory>();

UObject* TestObj = CurveFactory->FactoryCreateNew(UCurveFloat::StaticClass(), OutermostPkg, *CurveName, RF_Standalone | RF_Public, NULL, GWarn);

FAssetRegistryModule::AssetCreated(TestObj);
TestObj->MarkPackageDirty();
Package->SetDirtyFlag(true);
TestObj->PostEditChange();
TestObj->AddToRoot();
1 Like