Open idanarye opened 1 year ago
The general idea:
Saving be triggered by sending a YoleckInitiateSave
event, which will make Yoleck run a YoleckSchedule::Save
schedule where save systems will generate YoleckComponent
s based on the current state of the actual components. I'll need to decide exactly how to do that, but they probably won't be modifying the original YoleckComponent
s that the data was created from. After the schedule is done, a YoleckSaveReady
event will be sent with the save data as serde_json::Value
, and it'd be up to game code to persist it.
YoleckInitiateSave
will have a context field (need to decide if it'd be a Box<dyn Any>
or a serde_json::Value
) which YoleckSaveReady
will get (and edit systems can use as a resource). That field could be used by the game code to determine, for example, if the save is an autosave or user-invoked, and the name or number of the save in the later case.
As for loading - just add new YoleckLoadingCommand
variants (or add an Option
to the existing ones) with the serde_json::Value
from the save data.
Each entity type will have to declare its save strategy. I imagine three strategies (names TBD):
.yol
file every time the level is loaded, and they never change so there is no need to put them in the save file. Actually, even if they do change this is a type of entity that it's fine not to save. For example - the pots in Zelda games. You can destroy them, but when you reenter the level they get recreated.
This will be the default save strategy.YoleckComponent
s of the entity from the save data to override the ones from the .yol
file..yol
file, no entities of these types will be created at all when loading a saved level (only when loading that level for the very first time), and instead Yoleck will use the list of the se entities from the save data.
Note that unlike the second strategy, where only the YoleckComponent
s that can change during gameplay need to be saved, here all the YoleckComponent
s need to be saved because we can't match them to entities from a .yol
file.I'm tempted to just have a single boolean field on the entity type (unsaved/saved) and distinguish between the second and third strategy by the existence or lack of the identifier component. But I think I'll make them explicit (with a 3-options enum
) anyway, because the third strategy is kind of dangerous - using it would mean that new entities added to the level will be ignored when the level is loaded from a save. Also, this third strategy will probably be useful for Yoleck entities created on the fly (I should open a new ticket for that), and we may want to use UUIDs for these kind of entities (e.g. - a spawned monster and wanting to save some other entity that refers to that monster)
The common conception about saving and loading game state in Bevy (or ECS in general) is that you just have to do serialize all the components of all the entities into a file, and when loading just rebuild the scene from that component data. That, however, is very similar to the common conception about editors for Bevy - the very conception that Yoleck is trying to be an alternative to. So I figure Yoleck can offer a similar alternative to. Since Yoleck already has a concise representation of the level, one that does not have to store every single component because it can build them from
YoleckEntityType
s andYoleckComponent
s, it shouldn't be that much more work to save just the changed data.Advantages over entire-scene save:
Yoleck itself is not going to handle the storage medium for the saved files. Doing that will lock users to a specific persistence solution. Instead, when initiating a save Yoleck will send an event with a
serde_json::Value
that represents the state, and when loading the user will have to provide thatserde_json::Value
. Note thatserde_json::Value
is not an actual JSON - it's just an in-memory data type with JSON semantics. It can be stored as a more compact and less human-readable format.