Streaming levels without calling BeginPlay

We’d like to have granular power over when packages are loaded versus when they are “begun”. Is there a way to do this? It looks like even when you send false to bMakeVisibleAfterLoad in UGameplayStatics::LoadStreamLevel, BeginPlay is called on the level.

Seeing as BeginPlay is the final step called on an actor as far as I understand the content pipeline, that seems very limiting. We just want all the assets ready, invisible and inactive, floating in RAM until we hit the switch. Is there a way to accomplish this?

Alternatively, is there an event we should move our BeginPlay logic to instead, that only fires when we set it to be visible? That’s not an ideal solution since that would be a pretty big migration, but it seems pertinent to ask.

In a nutshell, we want to separate the idea of “loading” from “activating”, if that makes sense.

It totally makes sense that you could have levels you load and keep inactive. …And the good news is that you definitely CAN do that.
But the bad news is that you’ll have to make some local changes to the engine code and then integrate your changes any time you take a new version of the UE4 engine. We have massive changes throughout the UE4 engine, so that’s just part of life for us.

Anyways, you could make some code changes where BeginPlay() is only called when you set the level to isVisible = true, OR you could also go with your event idea and broadcast the even when you set the level to active/visible.

The code for all this shouldn’t be too tough to do.

Without writing the code for you and posting it here, I’ll point you in the right direction. (Mainly because I have changed the hell out of World.cpp in our codebase so any code I copy from there isn’t going to match your for the most part and will only confuse you.) :stuck_out_tongue:

Start by checking out:

void UWorld::UpdateLevelStreamingInner(ULevelStreaming* StreamingLevel)

Then check out UWorld::AddToWorld() method. You definitely going to need to change AddToWorld’s behavior to not just set the level to visible and broadcast that the level is changed / visible. You’ll need you add your own code that set the added to world level to dormant instead until you say it’s time to set it visible and then call this following code at the end of AddToWorld():

		// Notify the texture streaming system now that everything is set up.
		IStreamingManager::Get().AddLevel( Level );

		Level->bIsVisible = true;
	
		// send a callback that a level was added to the world
		FWorldDelegates::LevelAddedToWorld.Broadcast(Level, this);

		BroadcastLevelsChanged();

		ULevelStreaming::BroadcastLevelVisibleStatus(this, Level->GetOutermost()->GetFName(), true);

Hope this gets you on the right path!

Cheers.

Hi,

BeginPlay on sub-level actors should be called only after sub-level became visible. UGameplayStatics::LoadStreamLevel with bMakeVisibleAfterLoad=fasle should just load level package into memory without making it visible. If you see that BeginPlay called on hidden level that a bug. Do you see this issue in PIE or in standalone game?