im currently banging my head, how to create an efficent SaveLoad-System.
I know how to save data in a file and read back from it. Using FArchive or via GamplayStatics with a SaveGame class so this is not the problem.
I can even load that data back and could restore every saved actor again.
For easiness i created an empty project with 2 maps:
everytime i save: i save the current levelname and the actors which are inside this level.
Lets say i saved in map1 → continue playing → enter map2 at some point…
Now i want to load the game to the previous state in map1…
So i call OpenLevel with the levelname from the save file.
Now everything is loaded with the default leveldata, so all the actors which are present by default will be loaded into the game, which is what i want to avoid because there may be actors which were already destroyed when i saved the game earlier.
Here are some specific questions:
What is a proper way to Open a saved level?
Restore all the actors which were valid back then without loading the defaults of the map?
One idea i had is serializing the current UWorld. Looking inside UWorld::Serialize(FArchive Ar) tells me, that its
saving a ULevel called PersistentLevel, which holds the information i want to save (f.e. an array of actors).
Serializing the UWorld does indeed fill the savegame file with the desired information but i somehow am unable to
load that data back to replace the current world (whatever it may be) with the one i saved to disk.
I don’t really know too much about the actual Savegame systems within UE4 at the moment, but I would probably approach this by having not actors in the level data, but spawn points. These spawn points would hold data such as “has spawned” (along with any other kind of setup data you need) which ofter loading the level would allow you to interrogate the component and manually spawn actors if needed.
Each time you spawn an actor, change the “has spawned” variable to state that it has already spawned, and ensure that is saved to the save data. Next time you load, you can ask the spawn point “should I spawn”, and the answer will be no, so don’t spawn an actor at that position.
Upon saving, you can also save the position / status of any existing actors in the level that you will want to re-spawn on a reload. Then, when reading the save data back in, you can spawn actors in and set them up as per their last known status.
You could of course just apply the paragraph above to all the default actors in your level as you currently have them setup, then immediately destroy them if they are no longer needed (i.e. already killed), but that seems in-efficient.
Ideally, you’d probably want to make an ISaveableItem interface or similar which you apply to anything you want to actually save in the game so you can easily read out / setup data
thanks for your hint, but it seems i wasnt precise enough.
It is no problem to check which actors were spawned at the moment you save the game. But it is very important to know how to avoid the spawning of the default actors when you open a level.
Consider the following:
a normal game has some kind of main menu which is probably a level itself, which opened when you hit the .exe of your game.
now you click on some load button to continue playing where you last saved a gamestate
so you would need to travel from mainmenu level to the actual gamelevel to the point you saved it.
but opening a level means its loading all the default actors and as you wrote
then immediately destroy them if they are no longer needed (i.e. already killed), but that seems in-efficient.
this is indeed insufficient. Even if it is, it might be the only option coming in my mind… Thats why i asked in here to maybe get a better idea to handle that.
I think you missed my point a little (I did write it in a hurry).
The point was that rather than placing an actor in the level which is alive, you place a component which can spawn an actor when the level is loaded if needed. These components have some variable(s) you save to your save data file which state if the actual actor should be spawned or not (depending on if it has already been done). This means that when you load the level, you are only loading in “spawn points” which may then choose to spawn an actor if it’s needed.
Combine that with some way of saving existing actor status and you should be able to restore a level to an exact state where it was saved.
but if i get you right it wont make things much easier and it even complicates things for any 3D-Artists/Level Designer whoever may be using actors and placing them into the world. Also it doesnt makes sense for me at all to place a component and check if its needs to spawn, since the component is somewhat spawned too, so i need to destroy this one instead of the actor.even though the SpawnPointActor may be a bit smaller in memory size. But if you just look at the workflow both do ways working the same way.
However, thank you for your ideas
edit: another things which just came up is: what if your level has some intro matinee like f.e. in Skyrim. When i would open a level with such an intro, it would play wouldnt it? I am sure there is a good solution avoiding all that unnecessary stuff but i havnt found it yet.
It would perhaps make things a little more tricky for a designer, but only a tiny amount as they’ll still be able to place and see the position of your ‘spawn’ object, but it might not be rendered as an actual character (they can always temporarily drag one in if they are looking to get scales of the world correct).
Also, when you load with spawn points as I mentioned, you don’t need to destroy them. They are just light-weight objects in the level (with no collision etc) which will always exist. Creating these when the level loads, even if they are not needed will be cheaper than creating a character, which may or may not then be destroyed.
Of course, there isn’t necessarily a problem with just creating then destroying a character if it’s not needed, but it isn’t all that efficient as a lot of code will be executed on the creation which gets more complex depending on the character (i.e. do you really want to spawn the character, make sure all the textures / animations etc are loaded into memory, kick off some behaviour trees, setup their default behaviours etc just to then have to remove it (which in itself will run more routines)).
As for the matinee stuff - again, you just need to save some variable in your save data for ‘playMatineeIntro’. When you load the level, some code will inspect your save data and decide if the matinee should be played or not. If it should be, trigger it to run.
hey there, im really thankful that you took your time telling me your intentions. And im sure this is a way you can work with.
However, anyone out there who tried to serialize the persistent level and load back all streamed levels using those levels to get the actors which needs a reload?