Failed to find objects / LoadAssetDataFromPath not working in packaged game

Hey! I recently tried to package my project for testing and encountered an issue.

I’m using UObjectLibrary to generate lists of all blueprints in certain folders:

ItemLibrary = UObjectLibrary::CreateLibrary(TSubclassOf<AWSPickup>(), true, GIsEditor); 
ItemLibrary->AddToRoot();
ItemLibrary->LoadAssetDataFromPath(TEXT("/Game/TwinStick/Gameplay/Pickups"));

This works fine in the editor, but not in the packaged game:

[2021.10.19-18.48.33:628][  0]LogUObjectGlobals: Warning: Failed to find object 'Object None./Game/TwinStick/Gameplay/Pickups/Consumables/Armor'
[2021.10.19-18.48.33:628][  0]LogStreamableManager: Failed attempt to load /Game/TwinStick/Gameplay/Pickups/Consumables/Armor
[2021.10.19-18.48.33:631][  0]LogUObjectGlobals: Warning: Failed to find object 'Object None./Game/TwinStick/Gameplay/Pickups/Consumables/Boost'
[2021.10.19-18.48.33:631][  0]LogStreamableManager: Failed attempt to load /Game/TwinStick/Gameplay/Pickups/Consumables/Boost
[2021.10.19-18.48.33:634][  0]LogUObjectGlobals: Warning: Failed to find object 'Object None./Game/TwinStick/Gameplay/Pickups/Consumables/Repair'
[2021.10.19-18.48.33:634][  0]LogStreamableManager: Failed attempt to load /Game/TwinStick/Gameplay/Pickups/Consumables/Repair
[2021.10.19-18.48.33:635][  0]LogUObjectGlobals: Warning: Failed to find object 'Object None./Game/TwinStick/Gameplay/Pickups/Consumables/Armor'

First thought would be to check if the blueprint folders are being cooked, which as far as I can tell they should be:

What else should I be looking out for?

Edit: Forgot to add the relevant code, the post should make more sense now!

Edit2: I think the issue might be due to LoadAssetDataFromPath not detecting the blueprints as TSubclassOf() after packaging. How can I make it detectable in both editor and the packaged game? I tried using StaticClass instead, but then it doesn’t find anything, I guess because the blueprints generate new classes instead of being instances of the parent class.

UObjectLibrary* ObjectLibrary = UObjectLibrary::CreateLibrary(UWidgetBlueprintGeneratedClass::StaticClass(), true, false);
ObjectLibrary->LoadAssetDataFromPath(Path);
TArray<FAssetData> AssetDatas;
ObjectLibrary->GetAssetDataList(AssetDatas);

for (const FAssetData& AssetData : AssetDatas)
{
	TSoftObjectPtr<UWidgetBlueprintGeneratedClass> SoftRef(AssetData.ToSoftObjectPath());
	TSubclassOf<T> HardRef = static_cast<TSubclassOf<T>>(SoftRef.LoadSynchronous());
            ....  now you can create a widget....
            .... didn't check if it is same for UBlueprints, but you could experiment with UBlueprint::StaticClass and UObject::StaticClass... 

The idea is Game is not treating blueprint files the same way as Editor does. So you need to manipulate not hard references but files of certain type. In my case it was WidgetBlueprints files which had type of UWidgetBlueprintGeneratedClass
but this solution is not perfect…
If anyone has a better solution please tell me…

But if you need it to work in both game and editor you need to implement 2 solutions

UObjectLibrary* ObjectLibrary = nullptr;
if (GetWorld()->IsPlayInEditor())
{
	ObjectLibrary = UObjectLibrary::CreateLibrary(UBlueprint::StaticClass(), true, false);
}
else
{
	ObjectLibrary = UObjectLibrary::CreateLibrary(UWidgetBlueprintGeneratedClass::StaticClass(), true, false);
}

ObjectLibrary->LoadAssetDataFromPath(Path);
TArray<FAssetData> AssetDatas;
ObjectLibrary->GetAssetDataList(AssetDatas);

ensureAlwaysMsgf(!(AssetDatas.Num() == 0), TEXT("No UI Assets were found. Check directory location or create temporary dummy widgets untl you have not created any for usage in your project"));

for (const FAssetData& AssetData : AssetDatas)
{
	TSubclassOf<T> HardRef = nullptr;
	if (GetWorld()->IsPlayInEditor())
	{
		TSoftObjectPtr<UBlueprint> SoftRef(AssetData.ToSoftObjectPath());
		UBlueprint* LoadedUnit = SoftRef.LoadSynchronous();
		HardRef = static_cast<TSubclassOf<T>>(LoadedUnit->GeneratedClass);
	}
	else
	{
		TSoftObjectPtr<UWidgetBlueprintGeneratedClass> SoftRef(AssetData.ToSoftObjectPath());
		HardRef = static_cast<TSubclassOf<T>>(SoftRef.LoadSynchronous());
	}

I found a single solution that worked for both in the end:


	if (!EnemyLibrary)
	{
		EnemyLibrary = UObjectLibrary::CreateLibrary(TSubclassOf<AWSNPC>(), true, GIsEditor);
		EnemyLibrary->AddToRoot();
	}
	EnemyLibrary->LoadAssetDataFromPath(TEXT("/Game/Gameplay/Enemies"));

	if (!EnemyLibrary->IsLibraryFullyLoaded())
		EnemyLibrary->LoadAssetsFromAssetData();

	EnemyLibrary->GetAssetDataList(SpawnableEnemies);

		UBlueprint* GeneratedBP = Cast<UBlueprint>(SpawnableEnemies[i].GetAsset());
		if (GeneratedBP)
			ClassToAdd = GeneratedBP->GeneratedClass;
		else
		{
			FString GeneratedClassName = SpawnableEnemies[i].AssetName.ToString() + "_C";
			ClassToAdd = FindObject<UClass>(SpawnableEnemies[i].GetPackage(), *GeneratedClassName);
		}