[TUTORIAL] C++ - Runtime Async Load Modular Character (Intermediate)

Would be much appreciated, what version are you on? On 4.22 I can get everything working except that the UObject pointer from ResolveObject seems to be just garbage, using it in SetSkeletalMesh does nothing, and calling anything on it crashes the engine.

Yes please!

I want to shorten the path for some people, it is not necessary to to so much.
Simply use the GameInstance as it is already a singleton. Just put the following into your ‘MyGameInstance.h’

#include "Engine/StreamableManager.h"

public:
FStreamableManager StreamableManager;

In the header file of your ‘MyClass.h’

//Callback function. Is called when the asset(s) is/are loaded
UFUNCTION()
	void DoAsyncObjectsChange();

//Asset we want to load
TSoftObjectPtr MyMesh;
//Delegate. With this we bind our action but we can also unbind etc.
FStreamableDelegate StreamableDelegate;

In your ‘MyClass.cpp’ inside your own function that will load the asset at some point:

//Convert your Ptr to a Path. 
FSoftObjectPath Path = MyMesh.ToSoftObjectPath();
FStreamableManager& StreamableManager = GameInstance->StreamableManager;
//We bind our delegate.
StreamableDelegate = FStreamableDelegate::CreateUObject(this, &AMyClass::DoAsyncObjectsChange);
StreamableManager.RequestAsyncLoad(Path , StreamableDelegate);

In case you want to load multiple assets you can simply add all your SoftObject Paths to a TArray<FSoftObjectPath> Paths and pass this instead of the FSoftObjectPath Path. The coolest thing is that you can pass mulitple custom arguments with the delegate. For example in your ‘MyClass.h’:

void DoAsyncObjectsChange( float Rating, int32 Price)

and then in your ‘MyClass.cpp’:

float NewRating = 0.8f;
int32 NewPrice = 32000;
StreamableDelegate = FStreamableDelegate::CreateUObject(this, &AMyClass::DoAsyncObjectsChange, NewRating , NewPrice );

You can use MyMesh.IsNull() to check wether your pointer is working BEFORE you call MyMesh.ToSoftObjectPath().
Also when you want to resolve your loaded asset don’t use check() but rather if(). If the spawned instance of your class ‘Myclass’ is deleted from the world during the loading process the ‘DoAsyncObjectsChange()’ function is called and your check() will assert and UE4 closes. Simply doing a:

if (UStaticMesh* Mesh = Cast<UStaticMesh>(Path.ResolveObject()))
{
//Do whatever you want here
}

does the trick.