StaticFindObjectFast when game is Launched

The problem is described here FAssetData.GetAsset - C++ - Epic Developer Community Forums
I explore engine sources and fing out that
StaticFindObjectFast works fine for Blueprints when game runs in editor or if i bush Play->Standalone. But it can not load object for me when i run really “standalone” application (Launch button in editor).

Library creation:

UObjectLibrary * lib = UObjectLibrary::CreateLibrary(base_class, true, GIsEditor);
lib->AddToRoot();
int32 loaded = lib->LoadBlueprintAssetDataFromPath(path);
GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Cyan, FString::FromInt(loaded) + TEXT(" objects loaded for lib - ") + name);

Asset retrieval:

lib->GetAssetDataList(Assets);
	for (int32 i = 0; i < Assets.Num(); ++i) {
		FAssetData& assetData = Assets[i];
		if (assetData.AssetName.ToString() == name) {
			GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Green, TEXT("AssetFound - ") + assetData.AssetName.ToString());
							
			if (!assetData.GetAsset())
				GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, TEXT("Get ship: Failed to load object by GetAsset - ") + assetData.AssetName.ToString());

			UBlueprint * bp = Cast<UBlueprint>(assetData.GetAsset());
			if (bp) {
				GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Green, TEXT("Get ship: bleprint cast done for asset - ") + assetData.AssetName.ToString());
				if (bp->GeneratedClass->IsChildOf(AShip::StaticClass())) {
					return *(bp->GeneratedClass);
				} else {
					GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, TEXT("Get ship: Class isn`t cild of AShip- ") + assetData.AssetName.ToString());
				}
			} else {
				GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, TEXT("Get ship: bleprint cast FAILED for asset - ") + assetData.AssetName.ToString());
			}
		}
	}

Hi ,

I am going to be doing some investigation into this issue you have described. I went ahead and copied over your code from the forums so that all of the information is in one place. I may need to get some additional information from you to fully investigate this. If that is the case, I will let you know what I need.

There the final varian of my blueprint function library:

#include "debugProj.h"
#include "ShipFunctionLibrary.h"
#include "Runtime/AssetRegistry/Public/AssetData.h"


UShipFunctionLibrary::UShipFunctionLibrary(const class FPostConstructInitializeProperties& PCIP)
	: Super(PCIP)
{

}

UObject * MyGetAsset(FAssetData & asset) {
	if (!asset.IsValid())
	{
		return NULL;
	}

	UObject * Asset = FindObject<UObject>(NULL, *asset.ObjectPath.ToString());
	if (Asset == NULL)
	{
		FString tmpstring = asset.ObjectPath.ToString();
		UObject * InOuter = NULL;
		ResolveName(InOuter, tmpstring, true, true);
		
		GEngine->AddOnScreenDebugMessage(-1, 15.f, FColor::Magenta, TEXT("Now string is ") + tmpstring);
		if (InOuter) {
			GEngine->AddOnScreenDebugMessage(-1, 15.f, FColor::Magenta, TEXT("InOuter->GetName is ") + InOuter->GetName());
			Asset = StaticFindObjectFast(UObject::StaticClass(), InOuter, *tmpstring);
		}
		if (Asset) {
			GEngine->AddOnScreenDebugMessage(-1, 15.f, FColor::Black, TEXT("WOW I Have Load Something with StaticFindObjectFast!") + Asset->GetName());
			return Asset;
		}
		
		Asset = (UObject *)StaticLoadObject(UBlueprint::StaticClass(), NULL, *asset.ObjectPath.ToString());
		if (!Asset)
			GEngine->AddOnScreenDebugMessage(-1, 15.f, FColor::Red, TEXT(" FAILED LOAD Object like BLUEPRINT By StaticLoadObject"));
		else {
			GEngine->AddOnScreenDebugMessage(-1, 15.f, FColor::Blue, TEXT(" LOADED like BLUEPRINT By StaticLoadObject"));
			return Asset;
		}

		Asset = (UObject *)StaticLoadObject(UObject::StaticClass(), NULL, *asset.ObjectPath.ToString());
		if (!Asset)
			GEngine->AddOnScreenDebugMessage(-1, 15.f, FColor::Red, TEXT(" FAILED LOAD Object like UOBJECT By StaticLoadObject"));
		else {
			GEngine->AddOnScreenDebugMessage(-1, 15.f, FColor::Blue, TEXT(" LOADED like UOBJECT By StaticLoadObject"));
			return Asset;
		}

		Asset = (UObject *)LoadObject<UBlueprint>(NULL, *asset.ObjectPath.ToString());
		if (!Asset)
			GEngine->AddOnScreenDebugMessage(-1, 15.f, FColor::Red, TEXT(" FAILED LOAD Object like BLUERPRINT "));
		else {
			GEngine->AddOnScreenDebugMessage(-1, 15.f, FColor::Blue, TEXT(" LOADED like BLUEPRINT By LoadObject"));
			return Asset;
		}

		Asset = LoadObject<UObject>(NULL, *asset.ObjectPath.ToString());
		if (!Asset)
			GEngine->AddOnScreenDebugMessage(-1, 15.f, FColor::Red, TEXT(" EVEN FAILED LOAD Object like UOBJECT "));
		else {
			GEngine->AddOnScreenDebugMessage(-1, 15.f, FColor::Blue, TEXT(" LOADED like UOBJECT By LoadObject"));
			return Asset;
		}		
	}

	return (UObject*)Asset;
}

TSubclassOf<AShip> UShipFunctionLibrary::GetShip(const FString & name)
{
	UObjectLibrary * lib = UObjectLibrary::CreateLibrary(AShip::StaticClass(), true, GIsEditor);
	lib->AddToRoot();
	int32 loaded = lib->LoadBlueprintAssetDataFromPath("/Game/Ships");
	GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Cyan, FString::FromInt(loaded) + TEXT(" objects loaded for lib - ") + name);

	TArray<FAssetData> Assets;
	lib->GetAssetDataList(Assets);
	for (int32 i = 0; i < Assets.Num(); ++i) {
		FAssetData& assetData = Assets[i];
		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Green, TEXT("Get ship: check obj - ") + assetData.AssetName.ToString());
		if (assetData.AssetName.ToString() == name) {
			GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Green, TEXT("AssetFound - ") + assetData.AssetName.ToString());

			if (!MyGetAsset(assetData))
				GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, TEXT("Get ship: Failed to load object by GetAsset - ") + assetData.AssetName.ToString());

			GEngine->AddOnScreenDebugMessage(-1, 15.f, FColor::Green, TEXT("INFO Class Name - ") + assetData.GetClass()->GetName());
			GEngine->AddOnScreenDebugMessage(-1, 15.f, FColor::Green, TEXT("INFO FullName - ") + assetData.GetFullName());
			GEngine->AddOnScreenDebugMessage(-1, 15.f, FColor::Green, TEXT("INFO AssetClass - ") + assetData.AssetClass.ToString());
			GEngine->AddOnScreenDebugMessage(-1, 15.f, FColor::Green, TEXT("INFO ObjectPath - ") + assetData.ObjectPath.ToString());
			GEngine->AddOnScreenDebugMessage(-1, 15.f, FColor::Green, TEXT("INFO IsAssetLoaded - ") + (assetData.IsAssetLoaded() ? FString("YES") : FString("NO")));
			GEngine->AddOnScreenDebugMessage(-1, 15.f, FColor::Green, TEXT("INFO IsValid - ") + (assetData.IsValid() ? FString("YES") : FString("NO")));			
                    //UBlueprint * bp = Cast<UBlueprint>(assetData.GetAsset());
			UBlueprint * bp = Cast<UBlueprint>(MyGetAsset(assetData));
			if (bp) {
				GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Green, TEXT("Get ship: bleprint cast done for asset - ") + assetData.AssetName.ToString());
				if (bp->GeneratedClass->IsChildOf(AShip::StaticClass())) {
					return *(bp->GeneratedClass);
				}
				else {
					GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, TEXT("Get ship: Class isn`t cild of AShip- ") + assetData.AssetName.ToString());
				}
			}
			else {
				GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, TEXT("Get ship: bleprint cast FAILED for asset - ") + assetData.AssetName.ToString());
			}
		}
	}
	return NULL;
}

As you can see i was experimenting with loading object without GetAsset(). But unfortunately all variants that described in “MyGetAsset” fails to load object when game is Launched(NoEditor) and works fine when i run it in editor.

Hi ,
I provide more complex piece of code for you. But i had to post it like an answer, because there are character limit in comments.

Hi.
I have exactly same issue. Hope you will give answer soon. Thanks!

Hi , how are your investigations?

When you say “launched”, do you mean launched as standalone game in an editor build (UE4Editor.exe YourGame -game) or packaged (and cooked) game?

In cooked builds your assets won’t get cooked if you load them from code. They need to be referenced through some properties or in a level (you can always add them to the list of assets to always cook, but generally loading assets from code is a bad idea as it’s going to block the main thread).

First of all it is not resolving my problem. So please remove accepted status of that answer.

There is no referencing problem. I can see that my assets were cooked. I even tried to add them to level. But still in “cooked” game I can get info(FAssetData) about my assets using UObjectLibrary. But i CAN NOT load them using FAssetData.GetAsset. BUT it works perfectly in editor and in standalone editor mode.

In that level blueprint you can see that i referenced MyShip in ShipToSpawn Variable. And it spawns fine in editor and in cooked game. But then i try to get the same asset using my “GetShip”(see in second of code example) it works fine in editor mode, but can`t load asset in cooked game.

Ok, another thing that’s worth checking is if you have bDontLoadBlueprintOutsideEditor in your DefaultEditor.ini set to ‘false’. If it’s set to ‘true’, then UBlueprint objects will be stripped when cooking (UBlueprint objects are only useful in the editor builds, usually you only need to access “YourBlueprint_C” class object).

Try looking for something like this in your DefaultEditor.ini:

[EditoronlyBP]
bAllowClassAndBlueprintPinMatching=true
bReplaceBlueprintWithClass=true
bDontLoadBlueprintOutsideEditor=true
bBlueprintIsNotBlueprintType=true

BTW, as far as I know, the accepted status is automatically applied when someone from staff posts an answer, and removed when someone else comments.

Thank you. That is resolving my problem.

UObjectLibrary::LoadBlueprintAssetDataFromPath(path) - loads info about blueprint assets by path. In editor mode i can get them, and then get GeneratedClass of them. When game is cooked there is “no blueprints”( with bDontLoadBlueprintOutsideEditor= true) there is only GeneratedClass. So i can load GeneratedClass directly by adding “_C” to object path.

Good work, @!

Thank you very much!