I already know how to save and load variables explicitly handled by a subclass of SaveGameObject as demonstrated in the TappyChicken examples. So, no problems there.
This question is about saving variables stored in multiple spawnable/placable Blueprint actors.
A basic scenario
Let’s say we have a single-player adventure style game with lots of doors. Each door is an instance of some Blueprint that contains the mesh components and an event graph handling the behaviour. The player can open or close any door, and when quitting the game, the state of each door (open or closed) must be stored in the players savegame object so that the next time the player starts the game, all the doors will show up in the same state they were when he quit the previous game.
This is clearly not an unusual feature, but I can’t figure out how it’s supposed to be handled. Looking through the hidden part of the details panel for variables created in a Blueprint reveals a flag labeled “SaveGame” which, according to the tooltip, should toggle serialization for it in saved games:
It’s probably safe to assume that this flag has something to do with the answer to my question, but it’s unclear how to make use of it. When testing it out using the ordinary SaveGameObject routine, it doesn’t appear to make any difference to the data stored in the .sav-file, so clearly I’m missing some crucial piece of information.
Since this kind of serialization potentially applies to hundreds of actors in any given level, it doesn’t seem like a SaveGameObject is designed to handle it. If the player breaks a destructible, it should already be destroyed when the containing map is reloaded at a later time, and if he finds and steals a one-of-a-kind magic sausage with unicorn dust on it in level 5, then that magic sausage should most certainly not be available again the next time the same player enters level 5… Well, you get the idea by now.
Does anyone have any ideas about this? In case my original question was unclear in any way, this boils down to saving and subsequently reloading changes that a player would make to various props in a level while playing, and SaveGameObjects do not seem to be appropriate for that kind of data since there would not be a fixed list of things that need to be saved. It would vary from one map to another.
Nope, still waiting to see if anyone has any hard info. There are obviously a few ways to “roll your own” here, as it were, but I’m pretty sure it would be better to find out how it’s supposed to be done by default.
I really hope epic fleshes out the documentation about saving and loading games! There are obviously some powerful features in the editor and its a hugely important element to shipping a finished game, but the tappy chicken example doesn’t really flesh out what all is possible…
Just a thought here, haven’t yet begun saving things yet myself, but the way I would think to do it is to use variables as states since you know how to save them. Idk if there are switches or not but variables tend to work as more dynamic/betters switches imho. I would set, say, 0 to be the door in its closed state, and 1 to be opened. Perhaps 2 for locked and 4 to require a key. Save the state of the variable, and when the game loads them up it sets the doors how you want them.
I know this is an older post, but it still comes up in searches.
The SaveGame is used by FArchive::Serialize() internally when ArIsSaveGame is set. Any variables on the blueprint that have SaveGame checked will be serialized. I’ve done all this in C++ where I call Serialize() in a C++ class that blueprints inherit from my C++ class and then the archiver will check for the SaveGame being checked on properties in the blueprints and will also serialize those out to disk as well.
I’m not sure if you can directly use SaveGame in a blueprint only save scheme.
Thanks for this, exactly what I was searching for.
The serialization of actors using the SaveGame flag makes sense, but I am missing some parts of the process, particularly what to do after this serialization and how this affects Load Game.
I imagine that you call Serialize() on all applicable actors during a Save Game event. That will package the actors up into nicely serialized objects, but where do they go? In a big array on the SaveGame object which is then written to a slot?
Then on Load Game, I’m not sure how you would restore the serialized actor objects (from the SaveGame object) to their appropriate counterparts in the loaded level. I think I’m missing some high-level ideas.
The beautiful thing about FArchive is that it’s a binary serializer. It doesn’t know or care about the type of your underlying data. It’s simply a steam of bytes: TArray< uint8 > which is both serialized out and back in when ::Serialize() is called on an object.
So, when you serialize back in your save game, it will actually do a binary overlay of the loaded data back on to the object you are serializing.
I imagine that you call Serialize() on all applicable actors during a Save Game event. That will package the actors up into nicely serialized objects, but where do they go? In a big array on the SaveGame object which is then written to a slot? <<<
Yeah, you generally will serialize everything into some save class you create which has an array of data records in it, then you call SaveGameToSlot either in code or from a blueprint.
To load the game back up, you call LoadGameFromSlot() and then using that loaded binary data you call Serialize again on your objects that have been created to overlay the loaded data back on.
To get a better understanding of how this works, have a look at Rama’s serialization tutorial on the wiki.
I did mention that in the links in my original answer. Whether you go with C++ or Blueprints really just comes down to the complexity and needs of a particular game. The game I’m working on is much too complex for the Blueprint only solution, but for example, I did read another post where someone (maybe at Epic) did use Blueprint only load/save for an iOS title.
That struct is inside a SaveGame object, and as long as it’s marked as a UProperty it will be saved to disk along with the SaveGame. On load (make sure it’s a fresh level start or restart as a property will not be serialized if it’s equal to its default value), I go through all of the saved structs and de-serialize over the matching actor in the world. For static actors, I find the world’s matching actor using FindObject:
Dynamic actors like PlayerCharacter and GameState can’t use the FindObject method as their names change each time the level restarts - you will need to get these objects from something like UGameplayStatics.