Download

How to spawn actors during level load and save game loading.

I’m working on a system that will randomly generate levels. I’m basically trying to make a roguelike FPS out of well crafted rooms that spawn in random arrangements.

So far, I can create objects in the OnBeginPlay methods, but I was wondering if it may be more efficient to do some things at level load itself. I’d want to set up a correctly sized navigation mesh volume for example. At the moment, I have a blank level with a 20,000x20,000x20,000 navmesh volume, which works for now. I placed some breakpoints in constructors of objects that would spawn at level load time when loading a level I created in the editor, but it’s still not obvious to me how the whole level loading and actor spawning process works. The stack trace is full of unreal’s function invocation code when it’s spawning an actor on level start for the receiveBeginPlay event rather than what I was actually looking for, which is it finding some data in the level file and knowing that it must now spawn an actor of some type. I’d basically want to follow that same code path and spawn static actors in that same way instead of reading it from the file.

I was also thinking about how we’re supposed to go about saving and loading games. I saw these docs: Saving and Loading Your Game | Unreal Engine Documentation. But this talks about how to save simple things like variables. How do I save and load an entire level state, like if I was to do a quick save in the middle of a level.

Also, let’s say I have a networked game, what would be the best way to spawn a randomly generated level for all the people connected. I may send a random seed to each player at the start of the game, but if people join in the middle, I’d also need to send the states of actors themselves. If I make a level in the editor, I imagine each player first loads the level, and only the actors that aren’t static, like weapons, projectiles, characters, debris get updated. But if the level is created dynamically, I’d have to “load” the static parts first myself instead of from a file. I’d imagine loading a quick save is a bit like joining in the middle of a multiplayer match as well.

Doing something very similar and my plan is to keep it split between static level and any dynamic actors that spawn in it.

So for the static level the seed is used to recreate the same level on a joining client. Any important actors part of the spawned level would only live on the server. This means the spawned “rooms” does not contain any dynamic actors but actors but only server side markers of where those actors should be spawned. If this works out the way I plan all the dynamic actors (doors, enemies etc) should then be able to replicate from the server as normal. The risk I see whit this is the amount of data that needs to be replicated when you join but I don’t see any easy way around that. Spawning dynamic stuff client side and then after trying to sync it with the server seems like it would be quiet messy.

I haven’t worried about midlevel saving as I am not sure I will even support that but a similar approach of saving the seed for the static geometry and then storing all the important properties of the dynamic objects.

Of course if we want to allow an updated game to load a save from a previous version we might need to store the actual geometry as well in case the level generation code has changed.

I never even considered adding the level generation during level load as I didn’t see a need for it, would be interesting to know if you get anywhere with that though.

I use a fake loading screen on the level’s begin play, to make sure everything has generated and spawned on the server before the player spawns. While it’s ‘loading’ a random level when things are placed i save the vectors and rotations in the world space of the origin of the object in to a csv data file and plot down my stuff.

I dug some more into the level loading code. It’s not well documented, but it seems like ULevel is the class that stores info about how to actually spawn a level and its actors at runtime. It’s serialized from a file. That’s basically how it loads a level and its actors. They are all just serialized from a file in pretty much 1 line of code. ar >> Actors. And Actors is the array of actors to spawn.

These actors seem to exist as a template for what actors to actually spawn on begin play, because all that data exists way before the actors themselves are spawned. In fact ULevel seems like a resource file, just like a texture or sound. It’s loaded from a package.

In the code that loads a map, it starts looking at the map URL which is usually something like Game/Maps/SomeMap or something. You could tell it to load map Random or something and modify the engine so it instead creates a ULevel with randomly placed actors. That seems like it may be a little too much work.

I’m starting to think that randomly generating the level onBeginPlay is a better idea. There would be a loading screen until the level itself exists.

I’d still like to come up with a better way to do navigation than to create one giant 20kx20kx20k navmesh bounds volume. Like if I can spawn navmesh volumes for each area that is placed.

Still wondering how I’d go about saving though. Maybe save files are similar to map files in that they serialize all the actors to a file and then deserialize them all again when loading a saved game. I definitely want saving since I plan on having longish campaigns with permadeath and want people to be able to take a break.

Actually we just need a callback after the level has loaded: OnLevelLoaded(ULevel level).
Then we could perform our procedural tasks inside that function
Can please someone at Unreal put this one-liner into the source?
Would do it myself, but don’t know where. :slight_smile:

I’m just doing it in BeginPlay and it works.

I had to modify GameMode quite a bit to have extra states for waiting for levels to generate. It also handles players joining late in the game when a match is in progress already. Those players get sent the seed that generated the level and their player controller handles tracking the state of the level generator. I make their spawn point be at a position of WORLD_MAX or whatever that constant is called so they are well outside the net cull distance until their level is generated. It’s kind of a hack but it prevents them from receiving info about random actors and gameplay happening in the void while the level isn’t generated yet. Once the level is generated, the local player controller on the client side sends an RPC to the server to notify it that its level is ready. That player controller is then put into a game ready state and its spawn point is switched back to normal.

I also made a loading screen with UMG that shows progress of the level being generated.

This is just what I was able to come up with at the moment. I feel like there are much cleaner ways to do some of this stuff, but I had to settle for a few hacks since doing it cleanly would require a few huge overhauls of the engine in a few places.

I still have yet to figure out how to show Movies during loading screens and explicitly cut off the movie not when the ULevel loading phase is done but when the random level generation phase is done which takes place during runtime of the game after the ULevel is loaded.