Can't Use Level Streaming in C++

Hi, I’ve some problems for level streaming in C++. I want to load a stream level, unload existing one after previous one has loaded. I’m working on this for 2-3 days and I didn’t figure out how to do it.
My first question is about delegates. OnLevelUnloaded delegate is not working when I trigger UnloadStreamLevel from GameplayStatics. It triggers OnLevelHidden (?)
Secondly, in first use, (Load->Unload) it’s working. When I want to unload currently loaded level and load hidden level, it’s not working. When I’ve looked the code, it’s searching for ExistingActions. If there’s one, loading or unloading doesn’t happen. But when I remove actions for the object, it doesn’t trigger like I didn’t remove them.

void AAndroidTpsGameMode::LoadLevel(const FName& InLoad, const FName& InUnload)
{
	UnloadName = InUnload;
	ULevelStreaming* Streaming = UGameplayStatics::GetStreamingLevel(this, InLoad);
	if(Streaming)
	{
		Streaming->OnLevelLoaded.Clear();
		Streaming->OnLevelLoaded.AddDynamic(this, &AAndroidTpsGameMode::OnLevelLoaded);

		FLatentActionInfo Latent;
		Latent.CallbackTarget = this;
		Latent.UUID = 1;
		UGameplayStatics::LoadStreamLevel(this, InLoad, true, false, Latent);
	}
}

void AAndroidTpsGameMode::OnLevelLoaded()
{
	print(-1, 5.f, "Level Loaded!");
	FLatentActionManager& LatentManager = GetWorld()->GetLatentActionManager();
	if (LatentManager.FindExistingAction<FStreamLevelAction>(this, 1) != nullptr)
	{
		printf(-1, 15.f, "LatentDescription: %s", *LatentManager.GetDescription(this, 1));
		LatentManager.RemoveActionsForObject(this);
		LatentManager.ProcessLatentActions(this, GetWorld()->GetDeltaSeconds());
	}

	ULevelStreaming* Streaming = UGameplayStatics::GetStreamingLevel(this, UnloadName);
	if (Streaming)
	{
		Streaming->OnLevelHidden.Clear();
		Streaming->OnLevelHidden.AddDynamic(this, &AAndroidTpsGameMode::OnLevelUnloaded);

		FLatentActionInfo Latent;
		Latent.CallbackTarget = this;
		Latent.UUID = 1;
		UGameplayStatics::UnloadStreamLevel(this, UnloadName, Latent, false);
	}
}

void AAndroidTpsGameMode::OnLevelUnloaded()
{
	print(-1, 5.f, "Level Hidden!");
	FLatentActionManager& LatentManager = GetWorld()->GetLatentActionManager();
	if (LatentManager.FindExistingAction<FStreamLevelAction>(this, 1) != nullptr)
	{
		printf(-1, 15.f, "LatentDescription: %s", *LatentManager.GetDescription(this, 1));
		LatentManager.RemoveActionsForObject(this);
		LatentManager.ProcessLatentActions(this, GetWorld()->GetDeltaSeconds());
	}
}

It works perfectly on Blueprints but I want to understand why C++ version is not working. :slight_smile: Thanks in advance…

I figured it out. There’re two boolean called ShouldBeVisible and ShouldBeLoaded in ULevelStreaming object. I check if level is Loaded before calling LoadStreamLevel. If level is loaded, I’m just setting ShouldBeVisible to true, it handles visibility. For removing, I’m making false both ShouldBeVisible and ShouldBeLoaded. After I call UnloadStreamLevel. If someone would have this issue, experiment these variables :slight_smile:

void AAndroidTpsGameMode::ClearLatentManager()
{
	FLatentActionManager& LatentManager = GetWorld()->GetLatentActionManager();
	if (LatentManager.FindExistingAction<FStreamLevelAction>(this, 1) != nullptr)
	{
		printf(-1, 1.f, "Removing existing action..");
		LatentManager.RemoveActionsForObject(this);
		LatentManager.ProcessLatentActions(this, GetWorld()->GetDeltaSeconds());
	}
}

void AAndroidTpsGameMode::LoadLevel(const FName& InLoad, const FName& InUnload)
{
	ClearLatentManager();
	UnloadName = InUnload;
	LoadStreaming = UGameplayStatics::GetStreamingLevel(this, InLoad);
	if(LoadStreaming)
	{
		if(LoadStreaming->IsLevelLoaded()) //If level is loaded, show it.
		{
			printf(-1, 1.f, "Level is loaded, showing it.");
			LoadStreaming->OnLevelShown.Clear();
			LoadStreaming->OnLevelShown.AddDynamic(this, &AAndroidTpsGameMode::OnLevelShown);
			LoadStreaming->SetShouldBeVisible(true);

			UnloadLevel();
		}
		else //If level is not loaded, load it.
		{
			LoadStreaming->OnLevelLoaded.Clear();
			LoadStreaming->OnLevelLoaded.AddDynamic(this, &AAndroidTpsGameMode::OnLevelLoaded);

			printf(-1, 1.f, "Level is loading...");
			FLatentActionInfo Latent;
			Latent.CallbackTarget = this;
			Latent.UUID = 1;
			UGameplayStatics::LoadStreamLevel(this, InLoad, true, false, Latent);
		}
	}
}

void AAndroidTpsGameMode::OnLevelLoaded()
{
	print(-1, 1.f, "Level Loaded!");
	ClearLatentManager();

	UnloadLevel();
}

void AAndroidTpsGameMode::UnloadLevel()
{
	UnloadStreaming = UGameplayStatics::GetStreamingLevel(this, UnloadName);
	if (UnloadStreaming)
	{
		UnloadStreaming->OnLevelHidden.Clear();
		UnloadStreaming->OnLevelHidden.AddDynamic(this, &AAndroidTpsGameMode::OnLevelHidden);

		UnloadStreaming->SetShouldBeLoaded(false);
		UnloadStreaming->SetShouldBeVisible(false);

		FLatentActionInfo Latent;
		Latent.CallbackTarget = this;
		Latent.UUID = 1;
		UGameplayStatics::UnloadStreamLevel(this, UnloadName, Latent, false);
	}
}

void AAndroidTpsGameMode::OnLevelShown()
{
	print(-1, 1.f, "Level Shown!");
	ClearLatentManager();
}

void AAndroidTpsGameMode::OnLevelHidden()
{
	print(-1, 1.f, "Level Hidden!");
	ClearLatentManager();
}
1 Like