Zeenobit / moonshine_save

A save/load framework for Bevy game engine.
MIT License
81 stars 9 forks source link

Spawning "game visuals" on load? #1

Closed shnewto closed 1 year ago

shnewto commented 1 year ago

Hello! This is a really fantastic crate, and what feels like a really ergonomic solution for picking out the specific components in my scenes I want to save 🤩

In the docs I noticed this comment:

You should try to design your game logic to keep saved data separate from game visuals. This can be done by using systems which spawn visuals for saved game data

But for me, it'd be really useful actually if there was some capability to spawn game visuals on load in a startup system. In my app, it's not exactly difficult to reconstruct and spawn each visual object from the saved data (3d shapes with some state), it just seems like it would be convenient if I didn't have to 😆

Feel free to disregard and close this issue if it's just not a use case you're looking to address :)

Thanks!

Zeenobit commented 1 year ago

I keep going back and forth on this topic internally. What defines "visual aspects" of the game is a very subjective thing that varies between projects.

Using this crate, you can save all components (Bevy ones or otherwise) that implement Reflect. So if you have simple components that don't have any entity references, you can use this crate as-is.

Problems arise when you're dealing with components which reference entities. The main ones being Parent and Children. I have been toying with an implementation of saving/loading Parent and Children in this branch: https://github.com/Zeenobit/moonshine_save/tree/hierarchy

If Parent and Children are your only issue, then using that branch should solve your problem. Let me know if run into any issues with it.

If you're using other Bevy/external components that reference entities though, you'll manually have to fix the references. This is mainly why I keep going back and forth on this idea. Because unless Bevy gives us a standard trait for updating entity references, it'd be impossible for this crate to fix references of external types.

We have MapEntities trait in Bevy, but that doesn't quite work due to Entity generations being dropped during serialization.

shnewto commented 1 year ago

@Zeenobit thanks for the thoughtful reply 😄 I don't really know for sure if anything I'm bumping into is related to Parent and Children relationships, my experience with those concepts in the code relates mostly to spawning nested UX elements which isn't my use case. I did bump into issues with meshes and materials which is maybe related to your comments about updating entity references? i.e. the handles for meshes and materials save but that's not useful information on load... and the bevy Mesh object doesn't derive or implement Reflect so it's even further out of the scope for this crate I think.

My use case at the moment is generating a bunch of little emissive icospheres of various sizes. Saving their positions that are otherwise generated using some noise algorithms, is definitely a time saver. And adding the meshes and materials isn't really any overhead for me.

I'm happy to use your crate for the wins I'm already seeing, and for you to close this issue if you'd like. I do sort of think if there are cases where actually batch spawning is possible (instead of just inserting resources) there would be some convenience in it but I tend to agree that it's probably a moving target.

Thanks again!

Zeenobit commented 1 year ago

Just check the definition of the components you're using. If they derive Reflect and don't have any Entity members, or members that have Entity members, then you can stick that component on an entity with Save and save/load should work just fine with this crate.

Otherwise, you'll have to manually fix the references, or put that data into a separate entity and don't save it (i.e. spawn it after load).

Any Transform component, for example, would be saved fine. For meshes, I haven't personally tried it. I suspect it may have something to do with mesh resources being saved/loaded. I'd be happy to look into a (non)working example and see if I can/should integrate support for it in this crate like Parent/Children.

shnewto commented 1 year ago

Ah happy to provide a basic example of my current approach, i.e. saving a bundle, grabbing the transform from the loaded data then creating meshes and materials and spawning

https://github.com/shnewto/bevy-sandbox

Zeenobit commented 1 year ago

I checked your repository, and I don't see any issues here. As long as you have a "flat scene" (i.e. no child entities), and you load the same assets as the ones used when saving, saving a basic scene with all the visual elements should be fine with this crate.

If you do decide to have a hierarchy (i.e. set parents, add children), then I recommend grabbing the hierarchy branch I mentioned earlier.

shnewto commented 1 year ago

ah right, yeah that example is how I have it working now, and I'm totally happy with it like that.

my idea when opening this ticket though was that maybe this code

            load_from_file(SAVE_FILE_PATH).in_schedule(OnEnter(AppState::CreateMeshesAndMaterials)),
            create_meshes_and_materials.run_if(in_state(AppState::CreateMeshesAndMaterials)),
            spawn_geometry.in_schedule(OnEnter(AppState::SpawnGeometry)),
            setup_camera.in_schedule(OnExit(AppState::SpawnGeometry)),

from here: https://github.com/shnewto/bevy-sandbox/blob/705998b74b8c74bb5d87bacfaf306a38370b9e45/src/main.rs#L40-L43

could be pruned down to

            load_from_file(SAVE_FILE_PATH).in_schedule(OnEnter(AppState::CreateMeshesAndMaterials)),
            setup_camera.in_schedule(OnExit(AppState::SpawnGeometry)),

i.e. the load_from_file could handle the "create meshes and materials" and "spawn geometry" for me

shnewto commented 1 year ago

well, not quite do the work of "create meshes and materials" for me, more like "load the saved meshes and materials" so I wouldn't have to create them when the app starts. I do think though, that's probably well out of the scope of the utility this crate offers

Zeenobit commented 1 year ago

Yah that's not something I want to support in the save system out of the box, because it'd be hard to come up with a generic solution for it. For example, would the save system store the paths to the assets, or the physical binary data? I think those are problems that are more project-specific for a generic crate to handle them.

shnewto commented 1 year ago

I'm pretty much on the same page as you now. I am wondering a bit now though, whether there's a path in bevy for a crate to basically export only tagged components in a scene to a straight up gltf or glb file. If I create a 3d scene in blender for instance, I can export a gltf that contains all the mesh/matieral/transform data and load it in a bevy app, so maybe it could go the other way 🤔

anyway, thanks for the conversation and your willingness to entertain my questions! feel free to close the issue if you're feeling satisfied with things (I am)