bevyengine / bevy

A refreshingly simple data-driven game engine built in Rust
https://bevyengine.org
Apache License 2.0
36.24k stars 3.57k forks source link

Replace startup systems with a built-in state enum that handles resource cleanup #5437

Open alice-i-cecile opened 2 years ago

alice-i-cecile commented 2 years ago

Problem

  1. Startup systems are largely special-cased, they rely on custom stage implementations and it's quite hard to teach the model.
  2. It is challenging to ensure appropriate cleanup of resources on AppExit: we must listen for the event and carefully time the resources.

Proposed solution

/// A built-in game state that controls app control flow
///
/// This is enabled by default, and user systems are added to the `Main` variant by default
enum AppState {
    Startup,
    Main,
    Exit,
}

This allows us to use standard on-enter, on-exit and state transition methods to control things like asset loading, cleanup, pausing the game, autosaving on exit and so on.

Extensions

We could add an explicit asset loading state as well. This may work well, but could be controversial.

Context

Discussed with @IceSentry on Discord after trying to help a user ensure data is cleaned up correctly.

This builds on but does not require the patterns espoused by the [Stageless RFC}(https://github.com/bevyengine/rfcs/pull/45).

Would address #1353. If we were to implement this, we would likely want to have a more robust event strategy by default, to ensure that gameplay events do not get lost during a pause.

mockersf commented 2 years ago

Anything that's part of an Exit state can't be reliable.

The game will panic, crash, the user will force quit it.

The most reliable thing we have from Rust is to implement Drop on everything that needs a custom cleanup.

alice-i-cecile commented 2 years ago

Mhmm 🤔 Could we use a drop impl to attempt auto-saving? I suppose if you could somehow have a custom drop impl on World that might work, but a) orphan rules and b) you won't have a good way to get disk access...

Nilirad commented 2 years ago

Bikeshedding: there is no concept of “Game” in Bevy, so it should be named something like AppState.

I think adding a Paused state by default is not something we would want: pausing is such a high level feature that games should manage by their own. Also it is not pertinent about the other more “lifecycle” variants.

alice-i-cecile commented 2 years ago

Bikeshedding: there is no concept of “Game” in Bevy, so it should be named something like AppState.

Agreed.

I think adding a Paused state by default is not something we would want: pausing is such a high level feature that games should manage by their own.

Part of my concern here is that I want app.add_system to do the right thing by default. However, I think you're probably right; we can cut this to reduce complexity and enable more flexibility.

Weibye commented 2 years ago

Could we also get a Build state? Ref https://github.com/bevyengine/bevy/discussions/5016

(Expecting to this to not be trivial)

Nilirad commented 2 years ago

@Weibye Plugins are built during App creation, so I don't think it's something that can be defined with states.