Problem with LevelStreaming using C++

I have used LoadTitle function to load Levels in my GameMode::BeginPlay, After starting game,
I have not seen any Levels,

UWorld* const world = (UWorld*)GetWorld();
LoadTile(world, "World'/Game/Maps/level02.level02'");

Please help me, thanks.

void AMLGameMode::LoadTile(UWorld* World, FName LevelName) 
{
	//ULevelStreamingKismet* StreamingLevel = NewObject<ULevelStreamingKismet>(World, NAME_None, RF_Transient, nullptr);
	ULevelStreamingKismet* StreamingLevel = static_cast<ULevelStreamingKismet*>(StaticConstructObject(ULevelStreamingKismet::StaticClass(), GetWorld(), NAME_None, RF_NoFlags, NULL));
	StreamingLevel->bShouldBeLoaded = true;
	StreamingLevel->bShouldBeVisible = true;
	StreamingLevel->bShouldBlockOnLoad = false;
	StreamingLevel->bInitiallyLoaded = true;
	StreamingLevel->bInitiallyVisible = true;
	StreamingLevel->LevelTransform = FTransform(
		FQuat(0.f, 0.f, 0.f, 0.f),
		FVector(0.f, 0.f, 0.f),
		FVector(0.f, 0.f, 0.f));
	StreamingLevel->PackageNameToLoad = LevelName;

	World->StreamingLevels.Add(StreamingLevel);
}

First of all, are you just trying to load an already existing streaming level or are you trying to load one multiple times?

Loading a level at a given transform, this is used to load a level multiple times
at different locations.

bool UMyGameInstance::LoadLevelAtTransform(FName PackageNameToLoad, FTransform LevelTransform)
{
    // TODO: Add delegates
    ULevelStreamingKismet* StreamingLevel = static_cast<ULevelStreamingKismet*>(NewObject<ULevelStreamingKismet>(GetWorld(), NAME_None, RF_NoFlags, NULL));
  
    // Associate a package name.
    StreamingLevel->SetWorldAssetByPackageName(PackageNameToLoad);
    if (GetWorld()->IsPlayInEditor())
    {
        FWorldContext WorldContext = GEngine->GetWorldContextFromWorldChecked(GetWorld());
        StreamingLevel->RenameForPIE(WorldContext.PIEInstance);
    }
  
    StreamingLevel->LevelColor = FColor::MakeRandomColor();
    StreamingLevel->bShouldBeLoaded = true;
    StreamingLevel->bShouldBeVisible = true;
    StreamingLevel->bShouldBlockOnLoad = false;
    StreamingLevel->bInitiallyLoaded = true;
    StreamingLevel->bInitiallyVisible = true;
  
    StreamingLevel->LevelTransform = LevelTransform;
  
    StreamingLevel->PackageNameToLoad = PackageNameToLoad;
  
    FString PackageFileName;
    if (!FPackageName::DoesPackageExist(StreamingLevel->PackageNameToLoad.ToString(), NULL, &PackageFileName))
    {
        UE_LOG(LogGSStreamingLevel, Error, TEXT("trying to load invalid level %s"), *StreamingLevel->PackageNameToLoad.ToString());
        return false;
    }
  
    StreamingLevel->PackageNameToLoad = FName(*FPackageName::FilenameToLongPackageName(PackageFileName));
  
    // Add the new level to world.
    GetWorld()->StreamingLevels.Add(StreamingLevel);
  
    return true;
}

Loading an already existing streaming level, the tricky part is to get the level
instance, then you just have to kick loading in. This requires your levels to be in the level browser of your persistent level to work properly.

void UMyGameInstance::LoadLevel(const FName LevelName)
{
    ULevelStreaming* CurrentLevel = FindAndCacheLevelStreamingObject(GetWorld(), World);
    if (CurrentLevel)
    {
        // TODO: Add delegates
        CurrentLevel->bShouldBeLoaded = true;
        CurrentLevel->bShouldBeVisible = true;
        CurrentLevel->bShouldBlockOnLoad = false;
    }
}

ULevelStreaming* UMyGameInstance::FindAndCacheLevelStreamingObject(const FName LevelName, UWorld* InWorld)
{
    // Search for the level object by name.
    if (LevelName != NAME_None)
    {
        const FString SearchPackageName = MakeSafeLevelName(LevelName, InWorld);

        for (ULevelStreaming* LevelStreaming : InWorld->StreamingLevels)
        {
            // We check only suffix of package name, to handle situations when packages were saved for play into a temporary folder
            // Like Saved/Auto-saves/PackageName
            if (LevelStreaming &&
                    LevelStreaming->GetWorldAssetPackageName().EndsWith(SearchPackageName, ESearchCase::IgnoreCase))
            {
                return LevelStreaming;
            }
        }
    }

    return NULL;
}

FString UMyGameInstance::MakeSafeLevelName(const FName& InLevelName, UWorld* InWorld)
{
    // Special case for PIE, the PackageName gets mangled.
    if (!InWorld->StreamingLevelsPrefix.IsEmpty())
    {
        FString PackageName = InWorld->StreamingLevelsPrefix + FPackageName::GetShortName(InLevelName);
        if (!FPackageName::IsShortPackageName(InLevelName))
        {
            PackageName = FPackageName::GetLongPackagePath(InLevelName.ToString()) + TEXT("/") + PackageName;
        }

        return PackageName;
    }

    return InLevelName.ToString();
}

NOTE: All these examples are missing the level loaded/shown/unloaded/hidden delegates for clarity

1 Like

Thanks very much, My problem is solved.

If it’s solved and the answer was correct please remember to accept it to help others.

small update for ue5


ULevelStreamingDynamic* FIslandCreatorModule::LoadLevelAtTransform(
	int32 IslandID, UWorld* World, FTransform LevelTransform)
{
	// https://forums.unrealengine.com/t/problem-with-levelstreaming-using-c/339510/3
	UIslandCreatorSettings* const Settings = UIslandCreatorSettings::Get();
	const FString IslandName = Settings->GetIslandLevelName(IslandID);
	
	const FName PackageNameToLoad = FName(Settings->GeneratedIslandsPath / IslandName);
	// TODO: Add delegates
	ULevelStreamingDynamic* const StreamingLevel = NewObject<ULevelStreamingDynamic>(
		World, NAME_None, RF_NoFlags, NULL);

	FString PackageFileName;
	if (!FPackageName::DoesPackageExist(PackageNameToLoad.ToString(), &PackageFileName))
	{
		UE_LOG(LogTemp, Error, TEXT("Trying to load invalid level %s"), *PackageNameToLoad.ToString());
		return nullptr;
	}
	
	// Associate a package name.
	StreamingLevel->SetWorldAssetByPackageName(PackageNameToLoad);
	if (World->IsPlayInEditor())
	{
		FWorldContext WorldContext = GEngine->GetWorldContextFromWorldChecked(World);
		StreamingLevel->RenameForPIE(WorldContext.PIEInstance);
	}
  
	StreamingLevel->LevelColor = FColor::MakeRandomColor();
	StreamingLevel->SetShouldBeLoaded(true);
	StreamingLevel->SetShouldBeVisible(true);
	StreamingLevel->bShouldBlockOnLoad = true; // the value you choose here will not affect this working correctly.
	StreamingLevel->bInitiallyLoaded = true;
	StreamingLevel->bInitiallyVisible = true;

	StreamingLevel->LevelTransform = LevelTransform;
	StreamingLevel->PackageNameToLoad = FName(*FPackageName::FilenameToLongPackageName(PackageFileName));
  
	// Add the new level to world.
	World->AddStreamingLevel(StreamingLevel);

	// actually the level is being loaded at this point
	return StreamingLevel;
}

also i noticed the transform doesnt quite works if the level to load is already added in the levels tool window.