Loading a level at runtime doesn't work. What am I doing wrong?

The registry finds “ThirdPersonMap” in “World” and returns a valid pointer (NewLevel).

But the app crashes nonetheless with:
“Error: Failed to load package /Game/ThirdPerson/Maps/ThirdPersonMap. Exiting.”

FAssetRegistryModule& AssetRegistryModule = FModuleManager::LoadModuleChecked<FAssetRegistryModule>("AssetRegistry");

TArray<FAssetData> AssetData;
IAssetRegistry& AssetRegistry = AssetRegistryModule.Get();
AssetRegistry.GetAssetsByClass(FName("World"), AssetData);

for (auto& Item : AssetData)
{
   if (*Item.AssetName.ToString() == FName("ThirdPersonMap"))
	{
		UObject* NewLevel = Item.GetAsset();
		if (NewLevel != NULL)
		{
			UGameplayStatics::OpenLevel(NewLevel, FName("ThirdPersonMap"));
		}
       }

If you put a “StaticLoadObject” before “OpenLevel” nothing happens (no crash, no loading).

NewLevel = StaticLoadObject(UWorld::StaticClass(), NULL, TEXT("ThirdPersonMap"));
UGameplayStatics::OpenLevel(NewLevel, FName("ThirdPersonMap"));

OpenLevel (By Name) in Blueprint works.
So all the required assets are available for loading. I am lost.

You don’t need the asset registry and loading part . Also you are passing wrong param at first param of OpenLevel Func. WorldContextObject is an object that engine can access the current World from it . Try UGameplayStatics::OpenLevel(GetWorld(), FName("ThirdPersonMap"))
If you are calling this from a UObject.

2 Likes

Thank you @irajsb. You were absolutely right about GetWord().

Loading maps in editor now works.
But at cooked runtime loading another level still doesn’t work.

Test setup:

  • Game have two maps: ThirdPersonMap and TestMap
  • Game starts with ThirdPersonMap
  • A button press event calls the below function: LoadLevel(TestMap)

Results:

  • In editor: works
  • During runtime: don’t work

In both cases, however, the registry finds the TestMap asset!
And both methods ( GetAsset(), LoadObject() ) works in Editor and both don’t work at runtime.
.

(BTW, i am doing the registry part because i am working on a modding framework.
But in this test case I’m only loading assets that are already included in the main game.
Should be easy, right? Obviously not. :weary:)

TSoftObjectPtr<UWorld> UBFL_Ini::LoadLevel(FString LevelName)
{
	FAssetRegistryModule& AssetRegistryModule = FModuleManager::LoadModuleChecked<FAssetRegistryModule>("AssetRegistry");

	TArray<FAssetData> AssetData;
	IAssetRegistry& AssetRegistry = AssetRegistryModule.Get();

	AssetRegistry.GetAssetsByClass(FName("World"), AssetData);

	for (auto& Item : AssetData)
	{
		if (*Item.AssetName.ToString() == FName(*LevelName))
		{
			UObject* NewLevel = Item.GetAsset();
			if (NewLevel != NULL)
			{
				return NewLevel;
			}
			
			NewLevel = LoadObject<UWorld>(nullptr, *Item.GetObjectPathString());
			if (NewLevel != NULL)
			{
				return NewLevel;
			}
		}
	}
	return NULL;
}

Next Blueprint calls “OpenLevel (by Object Reference)” with the return value of the above function.

If anyone has time and energy to debug. :nerd_face:

Works fine here I only slightly changed the code because you’re not supposed to explicitly load Level assets so maybe that was the issue, not sure, I didn’t test original code

AssetRegistry.GetAssetsByClass(FTopLevelAssetPath("/Script/Engine.World"), AssetData);
for (auto& Item : AssetData)
{
	if (*Item.AssetName.ToString() == FName(*PakContentPath))
	{
		return TSoftObjectPtr<UWorld>(Item.GetObjectPathString());
	}
}
1 Like

@Chatouille :white_check_mark:
I can now confirm that a virtual path to the level is enough to load a map into unreal.

FString LevelPath = FString("/Game/Mod2/L_Mod2TestLevel");

return TSoftObjectPtr<UWorld>(LevelPath);

Next blueprint nodes after “return TSoftObjectPtr” aka UObject*:

  • MakeSoftWorldReference
  • Split struct pins
  • OpenLevel (By Object Reference)

But my progress is still like a snail. :snail:

Ich can now load a level at runtime (as evidence, the directional light color and clouds were changed)

but nothing else in the map is created. (player character spawns at 0,0,0 and falls) .

Do I have to hand spawn all assets in a level mounted at runtime? (Answer: No)
Or am I still doing something wrong?

I found the explanation for my empty levels problem.

The Pak file i mounted did not contain the standard editor shape actors, i used for quick testing.
However, if a mod level consists only of self-created blueprint actors, loading works fine.

Summary:

  • mount mod pak
  • set virtual path [Game] to mod pak
  • load mod level
  • set virtual path [Game] to main game pak

Due to this order, all main game assets are invisible to a user-created mod level.
But the main game could offer a plugin (GameShared) to make assets available to modders.

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.