Custom Actor Asset

Hi guys,

I’m sorry if this seems obvious or is an unnecessary thing to do, but what I want to do is create a custom “Quest” asset that shows up in the content browser to help more easily find it. The asset itself inherits from the Actor class because I would like for it to have all the bells and whistles of the actors (Idk if I’m allowed to say this here, but if anyone has ever used REDkit to mod the witcher 2, that was where I really got my love of game design and I liked the quest editor in that so I was trying to create something similar here, hence why it is its own actor, in addition to just needing a begin play and access to delays and the like in bp extended classes).

So to make it show in the content browser independently, I created a “Factory” class for it that looks like this:

QuestActor_Factory.h:
#pragma once

#include "CoreMinimal.h"
#include "Factories/Factory.h"
#include "UnrealEd.h"
#include "QuestActor_Factory.generated.h"

/**
 * 
 */
UCLASS()
class QUESTSYSTEM_API UQuestActor_Factory : public UFactory
{
	GENERATED_BODY()


	UQuestActor_Factory();

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

	virtual bool ShouldShowInNewMenu() const override;

	virtual uint32 GetMenuCategories() const override;
};

QuestActor_Factory.cpp:
#include “QuestActor_Factory.h”

#include "QuestActor.h"

//The asset type categories will let us access the various asset categories inside the Editor
#include "AssetTypeCategories.h"


UQuestActor_Factory::UQuestActor_Factory()
{
	SupportedClass = AQuestActor::StaticClass();
	bCreateNew = true;
	bEditAfterNew = true;
}

UObject* UQuestActor_Factory::FactoryCreateNew(UClass* Class, UObject* InParent, FName Name, EObjectFlags Flags, UObject* Context, FFeedbackContext* Warn)
{
	AQuestActor* NewObjectAsset = NewObject<AQuestActor>(InParent, Class, Name, Flags);
	return NewObjectAsset;
}

uint32 UQuestActor_Factory::GetMenuCategories() const
{
	return EAssetTypeCategories::Blueprint;
}

bool UQuestActor_Factory::ShouldShowInNewMenu() const
{
	return true;
}

I followed the very few tutorials there are out there on this, and it worked: the asset shows up as its own thing in the content browser, and you can create and name it and save it, but when you try to open it it crashes the engine with this:
Assertion failed: ActorInfo.SharedWorld [File:D:\Build++UE4\Sync\Engine\Source\Editor\UnrealEd\Private\AssetSelection.cpp] [Line: 136]

And I can’t find anywhere that explains to me what this is. Can anyone help me?

(As an aside, if i attach the VS debugger to the engine it throws an “unhandled exception” without any specification to where that is, but if I click continue it actually opens the asset as normal)

I’m not sure if you even can create actors as assets. The assertion failed macro implies (without having looked into it) to me that an actor requires a world to live in, which doesn’t exist at this point of time. You might be able to override the ‘GetWorld’ function and supply the editor world instead, but that might complicate things further.

Yeah, I don’t have a ton of desire to mess with any of the built in engine functions, especially something so commonly used. In all honesty, creating the quest actor was more a method of making it convenient for other, non-coding designers to easily get to the quest editors, but that’s all it really is: a luxury.

If no other answers come up solving it, I’ll mark it as resolved and move on, I just figured there might be someone out there that knew something about how to do this that I couldn’t find anywhere.

However, one of the tutorials I found and followed explicitly states that assets don’t have to inherit directly from object, and can instead inherit from any class derived from object, even explicitly mentioning actors. (Adding New Asset Types to UE4 | gmpreussner), so I’m unsure if this is simply incorrect or not.

I can’t answer that either, but if I were you, I’d simply create a QuestData class inheriting from UDataAsset, create a QuestComponent (that inherits from ActorComponent), and the QuestComponent has a blueprint-editable field of the QuestData which it then uses to initialize itself: something like that.
Additionally, what you could do according to the ‘Working with Assets’ unreal page:

The Content Browser supports drag and
drop behavior for creating Actors
based on assets into your levels, as
well as for moving assets around in
between folders.

So you should be able to potentially create drag & drop behavior that creates a ‘QuestActor’ upon the drop instead of dropping the actor itself onto the scene.
This is somewhat advanced though and you’ll need to research the code base as to how it’s done.

I know this topic is old, but usually in new projects i found people asking how this can be done.
The only way i found to active this type of behaviour was making a custom C++ Actor , a Custom UActorComponent and inside of the component class constructor, load the Asset at the Component constructor and load the component inside Actor´s constructor.
Then when you drag/drop the actor in the level, you can choose the asset type you want for that actor.

To give an practical example imagine this:
I have a On-Crane Camera , and we want insert an aniomation being controlled by a FVector UCurve(an UCurve is an asset and can be edited by the UCurve Editor).

So , in the Actor Constructor you can include:

// Sets default values
AIVR_OnCraneCamera::AIVR_OnCraneCamera(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer)
{
	// Set this Actor to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
	PrimaryActorTick.bCanEverTick = true;

	IVR_CraneCam = nullptr;

	// Add static mesh component to actor
	IVR_CraneAnimation = CreateDefaultSubobject<UIVR_AnimationComponent>(TEXT("Crane Animation"));

	IVR_StartTime         = 0;
	IVR_FullAnimationTime = 20.0f;
	IVR_NumberOfLaps      = 0;
	IVR_MaxLoopLaps       = 3;
	IVR_LockAnimation     = false;
	IVR_AutoStart         = false;
	IVR_AutoRecord        = false;

}

Then in the component you can include:
// Sets default values for this component’s properties

UIVR_AnimationComponent::UIVR_AnimationComponent()
{
	// Set this component to be initialized when the game starts, and to be ticked every frame.  You can turn these features
	// off to improve performance if you don't need them.
	PrimaryComponentTick.bCanEverTick = false;
    IVR_IsFinished = false;

    static ConstructorHelpers::FObjectFinder< UCurveVector> Curve(TEXT("CurveVector'/IVRCameraMan/Assets/CraneAnimationCurve.CraneAnimationCurve'"));
    check(Curve.Succeeded());

    IVR_TimelineKeyframes = Curve.Object;

    // Add The Timeline Component
    IVR_AnimationTimeline = CreateDefaultSubobject<UTimelineComponent>(TEXT("Timeline Animation"));
    IVR_AnimationTimeline->SetComponentTickEnabled(false);
    
    IVR_AnimationTimeline->SetLooping(false);
    IVR_AnimationTimeline->SetTimelineLengthMode(ETimelineLengthMode::TL_LastKeyFrame);
    IVR_AnimationTimeline->SetPlaybackPosition(0.0f, false);

    //Add the float curve to the timeline and connect it to your timelines's interpolation function
    onTimelineCallback.BindUFunction(this, FName{ TEXT("TimelineCallback") });
    onTimelineFinishedCallback.BindUFunction(this, FName{ TEXT("TimelineFinishedCallback") });

    IVR_AnimationTimeline->AddInterpVector(IVR_TimelineKeyframes, onTimelineCallback);
    IVR_AnimationTimeline->SetTimelineFinishedFunc(onTimelineFinishedCallback);
	// ...
}

If you look at the component constructor its possible load the asset directly and change the component behavior. Since the actor constructor are called everyime you change it in the editor, you automatically update the actor if you change the asset, etc…

I hope this helps.
Regards.