How to pass parameters to a Dynamic Delegates (like OnLevelLoaded)?

Hello !

How could i do to pass arguments with Dynamic Delegates ?

I can’t find anything about how to do it, and if it is possible or not.

I’m using level streaming, and, when a level is loaded, i want to use it with some parameters passed with it.

I tried with a TScriptDelegate<FWeakObjectPtr>, but i can only bind UFunction without any parameters or variables payload.

What i want to achieve would be something like that (passing Var1 & Var2) :

SpawnedLevel->OnLevelLoaded.AddDynamic(this, &ARoomBuilder::OnLevelLoadFunction, Var1, Var2);

I could achieve to something with queuing levels into an array but i dont think that’s good practice, it would be better to have a real reference to it.

Thanks for your help !

1 Like

The issue there is that OnLevelLoaded is defined by the engine, and is defined to take no parameters. Thus, it shall take no parameters.

It’s absolutely possible to have a dynamic delegate that does take parameters, but the parameters to a delegate are passed by the thing calling the delegate, not as part of registration.

For instance, if you bind to an input event, the parameters to the delegate when it’s called will be what the input event that triggered it is, not something you passed at time of registration.

If you’re hoping for advice on how you could do this, it’ll help to know what Var1 and Var2 actually represent in your code, and where they’re coming from.

(Given the ARoomBuilder class there, I’m assuming you’re doing basically a procedurally-generated level of some sort, where you’re loading in individual pre-made “tiles” to connect, a’la Warframe’s instanced missions or Dragon Age: Inquisition’s multiplayer mode or such.)

Thanks for your reply !

You’re correct, RoomBuilder class load levels instances (wich are just rooms for now) with some random seeds !

What i want to achieve is to get a reference to the loaded level when it finished loading (for example, the Var1 could be :

ULevelStreamingDynamic* LoadedLevel

And then, i could get the loaded level, find an actor within the loaded level instance (For this case, i want to find an actor called “RoomManager”, that will be responsible of holding the room cell location, start enemy waves, etc)

I don’t know if it will work but it’s the only way i found

For Var2 it could be a FVector2D that hold the CellLocation, to set to actors within the loaded level.
This FVector2D is in an Array that hold every cell location

It could be something like :

ULevelStreamingDynamic* SpawnedLevel;
FVector2D Location = FVector2D(2.f,6.f);

SpawnedLevel->OnLevelLoaded.AddDynamic(this, &ARoomBuilder::OnServerLoaded, SpawnedLevel, Location );

that could be sent to a function :

void OnServerLoaded(ULevelStreamingDynamic* InLevel, FVector2D InLocation);

I know it won’t be as easy as this, but it’s to give you a “context”.

Thanks a lot for you help !

Nevermind…
I think i can’t achieve what i want to do with this approach

I want to get a reference to an Actor within the streamed level instance when it’s loaded, but i can’t get it, every GetLevel/GetLevelLoaded/GetCurrentLevel functions return “PersistentLevel” and not “NewLevel_1” (the room one)

Any clue ?

Thanks !

So, first off, I would probably create a wrapper around ULevelStreaming. You could then bind that to the level’s OnLevelLoaded, and since you should have access to the ULevel instance for that specific streamed level via ULevelStreaming::GetLoadedLevel(), you can deal with the level (rather than the world) that way.

Moreover, since this custom class can store your Var1 and Var2, you can easily add a broadcast event of your own which has multiple parameters, such as the loaded level (or whatever actor you needed to find within that level, presumably), and those two variables.

Then your overall ARoomBuilder can bind to that, instead of the level’s own OnLevelLoaded… and when it gets called you’re now passing all the information that ARoomBuilder presumably needs.

(The disclaimer, of course, is that I’m making this suggestion off the top of my head, not actually trying the code in anything to make sure it works; I’ve not bothered with level streaming that much, so there may be a gotcha I’m not seeing.)

Thanks for your reply !

I’ll try this way, thank you for your help !

Hello again,

I tried to use ULevelStreaming but i can’t spawn an Instance, and i dont know why, i can’t find anything on it.

// LevelStreamingClass = TSubclassOf<ULevelStreaming>
ULevelStreaming *StreamedLevel = NewObject<ULevelStreaming>(GetWorld(), LevelStreamingClass);
		
FTransform LevelTransform;
LevelTransform.SetLocation(Location);
StreamedLevel->LevelTransform = LevelTransform;

	
StreamedLevel->SetShouldBeLoaded(true);
StreamedLevel->SetShouldBeVisible(true);
StreamedLevel->bShouldBlockOnLoad = true;

// LevelInstanceToSpawn = TSoftObjectPtr<UWorld> set in BP
StreamedLevel->SetWorldAsset(LevelInstanceToSpawn);

FString StreamedLevelName;
StreamedLevel->CreateInstance(StreamedLevelName);
	
StreamedLevel->OnLevelLoaded.AddDynamic(this, &ARoomBuilder::PrintTest);

UE_LOG(LogTemp, Warning, TEXT("Executed !"))

I dont know why the level is not spawning, there is no crash and the code execute itself and print “Executed !”

But there is no instance created, no warning message, and OnServerLoaded never get called.

Do you have any clue ?

Thanks a lot

I succed to spawn a level instance with blueprint but i can’t achieve it in CPP, i dont know why…