Dynamic level streaming with multiplayer support

I cannot, for yes, you will need a custom version of the engine.

I’m trying to make this work but I keep getting this on client:
Failed to find streaming level object associated with ‘Woods’ (Woods is the map I’m doing this in…)

1 Like

The plugin works for me fine, just LoadLevelInstance on server, and do a RunOnOwningClient event with the stream info to add that to the client in question.

BUT if a client logs in while the game has been going for a while we have to load the stream infos to that player too, right? That is easy alright but I have no way of telling when it finishes. There is no event sadly and using delays is just asking for it most of the time. So I cannot make a proper loading screen that actually disappears when the level is really loaded.
With load level instance you have the OnLoad event which you can bind but here, nope.
Can’t even check if a given streaminfo has been loaded already or not so I can’t even do a Gate+delay->retry hackery since I never know when it is actually loaded.

And even worse, if you start loading a level into the stream when the host issues the order to switch maps, thus your client gets the command to also remove the level from stream… if you are still adding it while the remove order arrives you have a good chance of being kicked just like when trying to load instance from a client.
This also means that if I want to set up a Queue where I do the loading one-by-one the code will just rush through the array and I run the chance that one will be still loading while another command comes to unload the same thing and the client gets kicked.

TLDR:
Add to/Remove from Streaming Levels have no event to notify us when it’s finished.
If Add to is still in progress when the same thing is in a Remove from order it can get you kicked.

Update:
Okay, so if I add just a 0.2 delay (yea, after talking about how I hate delays) after issueing an add/remove order, I’m not getting kicked or crashing or anything.
That works for that part especially if used with bolean to deny any sort of action while one delay is already in progress.
The loadingscreen issue on the other hand is a tad annoying but I guess I will have to live with it.

I hate to necro an old thread, but I can’t seem to get this to work at all with Rama’s Victory Plugin 4.23. I’m testing streaming in a level during runtime on Server, and then passing that data from the host to the client. The setup is quite simple overall and I thought this would be rather trivial, so I’m a bit baffled at this point.

I’ve set it up exactly as the screenshots here show, up to, including, and beyond avoiding all the potential issues everyone else has encountered in the thread. I’ve read every post in here multiple times over. I’ve tried regular PIE mode, dedicated server PIE mode, 2 clients in PIE, Single Process in PIE, I’ve tried standalone, I’ve tried it between two PCs in a packaged game, Clients will not load a Streaming level through the method shown here. I’m quite advanced in terms of my networking knowledge in UE4, so I am positive it’s being set up in the correct locations as far as Server vs. Client interaction goes. (In other words, these aren’t being done in the wrong location/not actually reaching the client.)

I have Game Instance (on server) adding to an empty array of these LevelStreamInstanceInfo structs in the Game Mode.

This array is passed through a Reliable Run on Owning Client event. Client never loads it. In fact, the only discrepancy I can find at all is “ShouldBeLoaded” is false in the struct (but true on server.) If I try to manually change that, it boots the client for trying to cheat (I assume.)

If I try to just load ONE, nothing happens either. I’ve also tried it with a single LevelStreamInstanceInfo struct, including a simple “get 0” from the array, including RepNotify on GameState as demonstrated in this thread, as well as even trying it on an independent actor that the client spawns!

I’ve also verified that the code is actually firing, and the level struct contains valid data, and I’ve even walked through the plugin’s .cpp file in the Victory Plugin (v4.23). If I try to have the client modify or load in any other fashion, the game boots them out (anti-cheat protection of course.) In fact, I know Add to Streaming Levels node is working because if I try to add an incorrect level, it also boots the client to the menu.

Is there some obscure setting somewhere that isn’t enabled (or could’ve been turned off?) Am I missing something really dumb and obvious here? [Apologies for the messy graph in the first picture, I’m just trying to get it all working before I tidy up more.]

Game Instance [on server]


Game Mode [again, on server] [this is run many seconds after the server has finished making the array, and the client has joined]

Player Controller [on Client]

Thanks, hope somebody has a helpful answer on this!

@Zaggoth I am also having an issue having the victory plugin load the streaming level on the client. It at least evades the anti-cheat logout behavior which used to happen when using the default level stream, but not effectively has the same purpose of never even trying to load a stream level on the client. I also am not using dedicated server so that is out of the question (as previous poster said that testing with dedicated server was the solution).

Heading to the Discord server, next, for more answers.

Thanks to the Unreal Slackers Discord Server, I as able to construe that the Rama Victory plugin in general is antiquated and was a hack-fix for earlier versions of the engine. “Load Level Instance (by name)” doesn’t seem compatible with networking.

A quick YT video search proved that the best/most updated node to use for loading stream level is “Load Stream Level”. Tested, and it works! So much easier than relying on the plugin method.


Note: I’m doing the stream level load from a server-replicated event on the game state.

This is cool, but unfortunately it doesn’t solve the issue when streaming in levels that need to be at specific orientations and loaded on demand (instead of being part of the sub-level list.)

2 Likes

Regardless, loading a level instance into the game at runtime will cause issues with any actors inside that level.
If you are unable to patch in the fix, you will need to wait for UE4.26.

Ah, yeah I’m aware of that issue but I’ve already compensated for it in my design. I’m already spawning the actors on the server-side at generation time, the level doesn’t actually bring any actors with it that a client would have to worry about. The whole level is basically generated at runtime, along with the actors that populate it, so this wouldn’t be an issue.

Any news on this? I really need this and also… saving the levelstreaminfo struct should be a method to save and load procedural maps from a gamesave, right?

To those looking for a solution, dungeon architect seems to do this just fine on it’s own. There may be an answer buried in the code. If you go to the discord server the author may be willing to say what he is doing. Unfortunately I cannot share a discord link as it comes with purchase of the plugin :confused:

I wrote a quick blog post on how to do this. If anyone needs more info let me know, I’ll update the post.

UE4 Streaming Navigation Data from Instanced Level – Life Art Studios

What I have found, If you are using the LoadLevelInstanceBySoftObjectPtr (c++), make sure the NAME attribute is exactly the same for clients and the Server.

Example:
LevelName = FName(TEXT(“MyLevelStreamed”));
ULevelStreamingDynamic::LoadLevelInstanceBySoftObjectPtr(this, LevelToStream, RootComponent->GetComponentLocation(), RootComponent->GetComponentRotation(), bLevelInstanceSuccess, LevelName.ToString());

After found this, I finally understood the logic behind. If you have an item inside your streamed level, but the level name is different on each client and the server, then in the end is not the same item for everyone. But if the level name is exactly the same on each one, then the item is also the same for everyone :slight_smile:

This seems to be the proper way to stream levels for Multiplayer.

If you have Multiples levels to Load, make sure to generate the level names exactly the same on every client and server.

Please remember that you can’t repeat the same level name over and over for the same client or server. Level name should be unique (but the same between your network players and server).

Hope I have explain myself well.

8 Likes

What I found is that dynamic level streaming with multiplayer, listener server where one of the 4 players is the host and world composition doesn’t work on 4.26.2. The host/server only loads levels based on its perception of the world. This causes clients that are not located near these server loaded levels to not have their needed levels loaded on the server. This, in turn, causes big problems (clients falling thru the terrain, world assets with no collisions, etc.).

My solution was to make my own level streamer (which is currently too slow at game startup…) and change all world composition levels to “OnDemand”.

Now the issue I need to solve is with PIE in that for some reason the clients do not recognize the, I claim, correct level name. For example, I have a level called “Cave1”. Literally, “Cave1.umap”. The host/server loaded this level fine; however, I get a warning like…

LogLevel: Warning: Failed to find streaming level object associated with ‘Cave1’

…and as a result “Cave1” does not load for the clients in PIE.

If I run in a standalone game or a complied game, levels the client cares about work fine.

So what do I have to do to get levels to load in PIE such that I can test my game using this debug method???

I just figured it out!

Turns out atleast one level, I tested 4, has to have the fully qualified path to the level for PIE and “Load Stream Level (By Name)” to find the levels from the client perspective.

So, in addition to having to make your own level streamer, I claim you need to use fully qualified paths to your levels such that PIE will work correctly for your clients.

2 Likes

%^$#&^%$

OK. So… …I have recently implemented Git locally on my development computer and for PIE to work correctly with clients and world composition something gets screwed up on the persistent level which has all of the streaming levels. I caught a version that works with PIE and then I got a version that no longer would stream levels to clients. I tried to do a “Source Control → Diff Against Repo” and it returned nothing. I then reverted the old persistent level and PIE worked correctly again. What???

The truth is still out there…

…path name, or not, on the level streamer seems not to be the answer…

Slightly necroing this thread for any future googlers such as myself or anyone else who is wondering this- I did some quick tests and it does appear that was correct. If you have already-placed actors in your levels and you stream them in on both client and server with the same name override, the replication appears to work. I suggest testing it yourself as well, of course, but his solution seemed to be overlooked so I wanted to give it a +1.

6 Likes

Multiplayer level streaming is working for me except in PIE of which “most” of the time levels do not stream correctly. Every once in a while it does work; however, in most cases, for me, it does not.

UE 4.26

I am doing “Play As Listener Server”, “Run Under One Process” and “New Editor Window (PIE)”.

Doesn’t seem to matter if I use just the level name, say, “Encounter13” or the fully qualified level name “/Game/Maps/Level1/Encounter13”.

I am using “Load Stream Level (by Name)” with “Make Visible After Lead” set to True to load my levels.

Any tricks you may have to make PIE level loading work all the time in PIE???

Hm, that’s odd. I haven’t had issues testing it with PIE as a Listen server. I am using the LoadLevelInstanceBySoftObjectPtr method though, other than that I don’t know what we’re doing differently.

Interesting. I am just doing the following:

Can you post an example as to how you are loading your streaming levels?