Levels loaded from .umap file name during Runtime flicker constantly and Lightning never finishes rebuilding

#Update

I got rid of the Stationary Lights in the streamed in levels

now lighting rebuild issue is fixed!

But the levels added from filename still flicker constantly!

Rama

Dear Friends at Epic,

#Context

I am doing all of this during Runtime, not in the editor.

#Goal

I am trying to create a set of .umaps that are tiles, that will all be loaded into a persistent world to generate a semi-random world made of the tiles placed in different ways.

I have gotten this far

  1. obtain list of .umap files from content dir
  2. load each .umap via the code below
  3. the added level’s levelscript actor runs just fine! Level BP is running!

#Issue

The problem is that the loaded levels blink constantly.

And a message appears that lighting needs to be rebuilt.

The Lighting rebuild counter keeps stuttering as it is trying to go down to 0, and going back to its highest number.

So if the highest is 20, it keeps trying to go down to 19 or 18 and then going back to 20

Indicating that the some process is being continually restarted and never finished.

This would also explain the incessant blinking.

#Question

What additional steps do I need to take besides the code below in order to finalize the loading of a map from file name without using level streaming volumes?

#Picture

#Code

void UDynamicLevels::LoadTileToStreamingArray(const FName& TileUMAP)
{
	//World
	if( ! ISVALID(PersistentWorld))
	{
		UE_LOG(Victory,Fatal,TEXT("UDynamicLevels::LoadTileToStreamingArray >> Invalid PersistentWorld!!!"));
		return;
	}
	
	//new StreamingClass Instance
	UClass* StreamingClass 				= ULevelStreamingKismet::StaticClass();
	ULevelStreaming* StreamingTile 	= Cast<ULevelStreaming>(StaticConstructObject(StreamingClass, PersistentWorld, NAME_None, RF_Transient, NULL));
	
	
	//Very Important, used by LevelStreaming* to load the map
	StreamingTile->PackageName			= TileUMAP;
	StreamingTile->PackageNameToLoad	= TileUMAP;
	
	//Add!
	StreamedTiles.Add(StreamingTile);

   //Make New Level Visible
   StreamingTile->bShouldBeLoaded = true;
   StreamingTile->bShouldBeVisible = true;

  //Add to UWorld
  PersistentWorld->StreamingLevels.Add(StreamingTile);

}

#Thank You For Your Help!

Rama

#Level Bounds Actor

I had to spawn a level bounds actor for each level loaded from .umap

now there is no more flickering!

Yay!

if(!EachLevel->LevelBoundsActor.IsValid())
{
	UE_LOG(Victory,Error,TEXT("THERE IS NO LEVEL BOUNDS ACTOR!!!!!!!!!!!!!!!!!!!!")); 
	
	FActorSpawnParameters SpawnParameters;
	
	//spawn in the tile level instead of persistent
	//so the tile picks it up as its level bounds actor
	SpawnParameters.OverrideLevel = EachLevel;
	PersistentWorld->SpawnActor<ALevelBounds>(SpawnParameters);
}

I’m having the same issue here, but I can’t fix it like you did. I’m adding the level bounds actor, but there is no change.:

void ULevelDelegate::TileLoaded() {
	if (Streaming) {
		ULevel* Tile = Streaming->GetLoadedLevel();
		if (Tile) {
			if (!Tile->LevelBoundsActor.IsValid()) {
				FActorSpawnParameters FASP;
				FASP.OverrideLevel = Tile;
				Streaming->GetWorld()->SpawnActor<ALevelBounds>(FASP);
				GEngine->AddOnScreenDebugMessage(-1, 60.f, FColor::Yellow, TEXT("LevelLoaded"));
			} else {
				GEngine->AddOnScreenDebugMessage(-1, 60.f, FColor::Red, TEXT("Already has bounds"));
			}
		} else {
			GEngine->AddOnScreenDebugMessage(-1, 60.f, FColor::Red, TEXT("Level Not Loaded"));
		}
	} else {
		GEngine->AddOnScreenDebugMessage(-1, 60.f, FColor::Red, TEXT("NO STREAM FOUND"));
	}
	Streaming = NULL;
}

And the LoadTile function looks like this:

void MapLib::LoadTile(UWorld* World, FString LevelName) {
	UClass* StrClass = ULevelStreaming::StaticClass();
	ULevelStreaming* StrLevel = Cast<ULevelStreaming>(StaticConstructObject(StrClass, World));

	StrLevel->PackageName = FName(*LevelName);
	StrLevel->PackageNameToLoad = FName(*LevelName);
	StrLevel->bShouldBeLoaded = true;
	StrLevel->bShouldBeVisible = true;

	ULevelDelegate* delegate = NewObject<ULevelDelegate>();
	delegate->Streaming = StrLevel;

	StrLevel->OnLevelLoaded.AddDynamic(delegate, &ULevelDelegate::TileLoaded);

	World->StreamingLevels.Add(StrLevel);
}

Can you be so kind as to explain to me where exactly I’m supposed to attach the new bounds if not onLoad?

what you have looks good,

could you try spawning a new level bounds actor on key press, after the level is loaded, just as a test, using the same code in this thread?

Rama

No luck, I did what you said and it’s still flickering.

I’ve discovered a few things:

  1. This is happening because it keeps reloading the umap (the LevelBP and OnLoad get fired once and again)
  2. The bounds are kept by the editor between calls to onLoad but if compiled without it, the are not
  3. If I remove the ULevelStreaming from the UWorld right after setting the bounds in the OnLoad function, the level doesn’t show and the LevelBP is not called
  4. If I remove the ULevelSteaming from the UWorld on the OnLoad function only if the level already has bounds (second call) The first tile doesn’t show, but the second works fine in the editor.
  5. If I compile this last scenario without the editor, everything still flickers (the bounds are not kept from one call to onload to another, so the ULevelStreaming does not get removed)

This is kind of strange, I’ll keep looking tomorrow and if I can’t find an explanation I might start a proper question about it

I would look a step larger than the flickering, which seems symptomatic of a larger issue

and instead find the larger issue, which is related to your ULevelStreaming it sounds like

I’d suggest taking a different approach, for perspective, to how you create the tile in the world,

and see if you can get a different result, while still spawning the level bounds actor as usual!

#My Code For You

Here’s the core of my .umap loading sequence

//Create ULevelStreaming For Each .UMAP
	TArray<ULevelStreaming*> NewTiles;
	//for(int32 v = 0; v < Maps.Num(); v++)
	for (const FString& EachMap : Maps) //faster to type
	{
		//new StreamingClass Instance
		UClass* StreamingClass 				= ULevelStreamingKismet::StaticClass();
		ULevelStreaming* StreamingTile 	= Cast<ULevelStreaming>(StaticConstructObject(StreamingClass, PersistentWorld, NAME_None, RF_Transient, NULL));
		
		
		//Very Important, used by LevelStreaming* to load the map
		const FName TileUMAP(*EachMap);
		StreamingTile->PackageName			= TileUMAP;
		StreamingTile->PackageNameToLoad	= TileUMAP;
	}

Then after the above happens

I wait at least SEVERAL TICKS

then I create the levelbounds actor

#Important

I found that I had to wait a moment at least to give it time to cycle over to world.h and then actually get loaded

Rama