Dynamic level streaming with multiplayer support

In the past, I had issues in the past trying to dynamically streaming levels that work with multiplayer.

Recently I found a solution, thought I’d share.

I created a simple Blueprintable struct to hold the info from a Load Level Instance - which includes the unique name of the instance - that can be replicated to clients.
Once replicated to a client, I created a function that takes the info from the struct, create a level streaming object, add it the clients StreamingLevels and makes it visible etc.

End result - loading a level at runtime on the server and having it appear on a client.

I’ve already created a pull request for the Victory Plugin and annoyed Rama about it, so hopefully it’ll be in there soon.

We’re currently using it in Ground Branch to stream in a single level and it seems to work fine, both in packaged and non-packaged builds.

I hoping a few people will be interested enough to try it out and either break it or confirm it works.

If this does interest you, post a comment letting me know.
I can either post the C++ directly here (its pretty simple) and/or annoy Rama about it more :slight_smile:

2 Likes

Hello Kris,

I would be interested in the code as I have managed to load a level but the actors from the server map are not replicated, the client loads a new instance with new actors.

Thank you.

G’day,

I submitted it quite some time ago and it should already be part of Rama’s Blueprint function library.

Should :slight_smile:

Yep, I later found that out, thank you.

I have also made a pull request to be able to unload level instances replicated using this method on the client ( altought I had to add a little bit of extra code to handle that in Play In Editor as that appends some additional information to the level instance packageName based on the client id )

Hi Kris!

Thank you for sharing your solution.

This really helps me out with my project but I have actually got a crash problem :S
Everything seems to crash when I try to have more than 2 clients.

Have you or any other person any idea what may cause this problem and how to solve it?

Sorry, nothing comes to mind :frowning:

Thank for your answer man!

I am Sorry, it actually when I have 2 clients or more that it crashes.
Created a dummy project and implemented the same solution as you have in your example.

It works with either:
Server + Client
or
Dedicated server with one client

So it seems that it crashes when I try to run the game with more than one client. :S

@Kris , i am little bit lost, even when using your screenshot as guide. Could you please tell me how did you get from setting variable ‘LevelStreamInstanceInfo’ to event ‘Load on client’?
My guess is that after setting the instance info variable, something triggers ‘LoadOnClient’ event. That event first checks if the variable is not empty and adds level to streaming levels.
But what then? How do i get the level to load on client? Could you please elaborate on that? In any case, thanks for the nodes!

From what I recall, I had BeginPlay() calling either LoadOnServer() or LoadOnClient() depending on whether it was the server or client.
It would have been better to set the LevelStreamInstanceInfo to “rep notify” instead, which would guarantee the struct had been replicated before trying to access it.
That is what I do now, but with a C++ version of this same class.

Thank you! With your help I made it work. I still have few problems with it tho.
Same as @Celldelning was reporting, i cannot have more than 2 players. Be it server and client or 2 clients.
And then, i have no idea how to load more levels into the persistent level. If i add more ‘load level instance’ nodes, it loads only last one. If possible, please advice.

PIE multiplayer?

Or multilayer in general. I am trying to create system where one Persistent map is filled with smaller level instances by random generator. In singleplayer game it works fine. In multiplayer, it seems impossible. Screenshot i posted above works with only instance added to the persistent map and only two players.

Wondering if in my doing this in C++ fixed some unforeseen bug and/or something changed in the underlying engine since I created the Blueprint node.

As mentioned, it definitely works with multiple clients my end.

ugh

Welcome to game development! :slight_smile:

This is one more reason for me to go over the old code I submitted to Rama’s Victory Plugin.

I would really appreciate if you could please make it work. I am really helpless without this feature.

So the reason it’s only streaming in the last segment is because replication doesn’t start until after the server has finished loading (I think). So your replication is only getting called once, after the last tile has loaded. I worked around this by making a separate Level Instance Info Array, and storing each tiles individual info into it as the server streamed them in. Then by the ttime the replication call happens, that array is full of all the level streaming infos and you can just use a for loop to parse through and load each one.

Found the solution to the multiplayer crash in editor with 2 players or more!!!

@Kris code works well, and as a matter of fact has always been working if you tried it with a real built server, outside the editor.

We are all *just *testing it wrong.
[TABLE=“border: 0, cellpadding: 1, width: 75%”]

When you want to try your game with multiplayer in the editor,
basically all you do is set the correct options in the dropdown next to the huge ‘Play’ button:

  • Number of players

  • Dedicated server or not

    	And that's it, you hit play.
    	![UE4EditorWin64DebugGame_20190106_182143.jpg|340x445](upload://8j3URUhwwaFbI8Mlgd2bQrXAVLZ.jpeg)
    

But it turns out that the default behavior of the engine is to spawn multiple player windows in the same instance of UE4.
This means that your players are kinda faked and that they all share the same World, for example.

Doing this loads much faster indeed, but it can cause lots and lots of various issues (as this precise one), and this is absolutely not what you want when testing your game. You want to be as close as possible to what happens on a real server and real clients.

Here is what you have to do to fix that weird behavior:

1 - Click on Advanced Settings

2 - Locate Multiplayer Options and uncheck **Use single process

**

3 - New options will appear and some will disappear. Set the Editor Multiplayer Mode to Play As Client.

4 - You can also obviously set the other options to whatever suits your needs - and/or your machine performances.

Now when you hit play, you have a real server instance, and players each in their respective engine instance as well!

Here is a screenshot of a level that has been loaded with level streaming in dedicated mode with @Kris code and 2 players:

Hope it helps :wink:

That’ll explain why it worked for me then.
I tend to use batch file to start a dedicated server etc outside of the editor.
I leave in-editor testing for quick basic things.

I may have been a bit too optimistic…
It sure does not crash anymore with 2 players or more, but replication does not work for Actors in levels that have been streamed.

I mean, replication still works for PlayerControllers, I can see other players move, etc. Their variables are replicated, and RPCs from and to a PlayerController work as well.

But for Actors in levels that have been dynamically streamed, it just doesn’t. Everything is visually there and seems in order, but…no. :frowning:
It’s like the server does not know it has to replicate things to clients.

When I play those levels with the same multiplayer settings, everything is just fine, so the issue is definitely with dynamic level streaming… or maybe the way I am using it…
Precisely, I’m creating levels instances on the server using ULevelStreamingDynamic::LoadLevelInstance in my GameMode::BeginPlay, and I stream them on the client when the client connects, using your code.

@Kris, do/did you have this problem?
Or maybe all the replication your game needed was in the PlayerController? (seems unprobable but it may be possible depending on what kind of game you’re using dynamic level streaming for, I don’t know…)

I tried** A LOT** of things, so at this point I’m willing to try any new idea. :stuck_out_tongue:

Sounds awfully familiar (replication issues).

Looking at code, I see reference to a hack-fix:

Thanks for this, it will be helpful.

But dammit… Correct me if I’m wrong…that means I’ll have to use a custom engine to have this working properly? :frowning: