TAssetPtr / Asynchronous problem in the Editor

Greetings! I am attempting to create a asynchronous load system for hundreds of textures that are defined by TAssetPtrs in datatables. Something like:

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Textures")
	TAssetPtr<UTexture> buttonImage;

In order to load this texture, I have created a function in the game instance:

.h

UPROPERTY(EditAnywhere, BlueprintReadWrite)
FStreamableManager AssetLoader;

UFUNCTION(BlueprintCallable, Category="GUI / Core Interaction")
void LoadTexture2dForAsset(const TAssetPtr<UTexture> &image);

.c

void UGameInstance::LoadTexture2dForAsset(const TAssetPtr<UTexture>  &image)
 {
if (image.IsValid())
{
FStringAssetReference AssetToLoad;
AssetToLoad = image.ToStringReference();
AssetLoader.SimpleAsyncLoad(AssetToLoad);
}
else
{
UE_LOG(LogTemp, Error, TEXT("Error Loading Button Texture"));
}
}

So, the only weird thing is that the TAssetPtr is defined as a const – the code doesn’t seem to work when it is not.

Now, in blueprints I am using a function that formats buttons by changing the brush widget. It looks something like:

So basically before I set the image for the brush widget, I call LoadTexture2dForAsset(). In theory, this is supposed to look at the TAssetPtr, see if it is valid and then load the texture if it is not loaded.

It sorta works, but only if I load / edit the texture in the editor before.

Run game in editor. No button:

107714-help1.png

Now open up the texture in the editor:

Now run the game again:

107716-help3.png

So basically, this works, but only if I open the texture in the editor; it seems the texture is not being loaded properly by SimpleAsyncLoad().

It seems someone else had this problem. Their solution was to change the TAssetPtr to a texture pointer. This would, though, seem to negate the memory advantage of using Asynchronous loading.

Any help would be appreciated! Really just want to be able to load textures as needed for the GUI.

Asynchronous loading is non-blocking. It may be that it is loading properly, just not until after you’ve already tried to create the brush.
Either move your brush creation into a deferred action called by a delegate you pass to the Asynch load (you’ll have to use RequestAsyncLoad), or make your loading action here synchronous (and blocking):

AssetLoader.SynchronousLoad(AssetToLoad);

It might work better if you can not pass in the TAssetPtr as const, but set your string reference as const:

void UGameInstance::LoadTexture2dForAsset(TAssetPtr<UTexture>  &image)
  {
     if (image.IsValid())
     {
         const FStringAssetReference& AssetToLoad = image.ToStringReference();
         image = Cast<UTexture>(AssetLoader.SynchronousLoad(AssetToLoad));

     } else {
         UE_LOG(LogTemp, Error, TEXT("Error Loading Button Texture"));

     }
 }

Also, your error check is going to throw if you ever try to load the button texture after it’s already been loaded, even if there isn’t a problem. Is that error just there for now so you’re sure the loading procedure is being called?

You may want to structure it like this:

void UGameInstance::LoadTexture2dForAsset(TAssetPtr<UTexture>  &image)
{
    if (image.IsPending())
    {
        const FStringAssetReference& AssetToLoad = image.ToStringReference();
        image = Cast<UTexture>(AssetLoader.SynchronousLoad(AssetToLoad));

    }
    if (!image.Get()) {
        UE_LOG(LogTemp, Error, TEXT("Error Loading Button Texture"));
    
    }

}

Thank you so much for your answer! Just delving into texture loading and memory, so my grasp on the process is a bit shaky Will test and post tomorrow.