Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

bevy_app: Allow SubApps to be modified at runtime #6700

Open
soqb opened this issue Nov 20, 2022 · 5 comments
Open

bevy_app: Allow SubApps to be modified at runtime #6700

soqb opened this issue Nov 20, 2022 · 5 comments
Labels
A-App Bevy apps and plugins C-Usability A targeted quality-of-life change that makes Bevy easier to use

Comments

@soqb
Copy link
Contributor

soqb commented Nov 20, 2022

What problem does this solve or what need does it fill?

Currently, Bevy provides no way to add, remove or replace SubApps while the app is running.
One can currently (IIRC): end the running of the app, recreate the app with the changed SubApp and then run the app. This is unwieldy, slow, and prevents one from easily maintaining parent app state (e.g. windows).

I use SubApps for "sandboxed" loading of dynamic plugins, where their initialization and updates can be controlled separately from the parent app. Without a way to modifiy SubApps after the parent app starts running, hot-reloading is impossible.

What solution would you like?

  1. Add an exclusive SystemParam which provides access to the list of SubApps (but i'm not sure how this would be done considering the app is outside of the scope of the ecs and in the future one app may have many worlds), e.g.
fn add_sub_app_system(mut params: ParamSet<(&mut World, &mut SubApps)>) {
    let should_change = {
        let world = params.p0();
        world.resource::<MySubAppInfo>().should_change()
    };
    if should_change {
        let mut app = params.p1();
        sub_apps.add_sub_app("my_sub_app", MySubApp, MySubApp::runner);
    }
}
  1. Add composable runner functions, which would be a significant breaking change (although i believe most users use the Bevy-provided runners: run_once, the ScheduleRunnerPlugin runner or the winit runner) e.g.
let mut App::new();
app.add_plugins(MinimalPlugins);
let old_runner = app.take_runner(); // new method that replaces the runner with `run_once`

// new `Runner` struct that seperates behavior into three distinct phases.
app.set_runner(Runner {
    start: old_runner.start,
    update: Box::new(move |app: &mut App| { // now by mutable reference rather than by value.
        old_runner.update();
        if app.world.resource::<MySubAppInfo>().should_change() {
            app.add_sub_app("my_sub_app", MySubApp, MySubApp::runner);
        }
    }),
    end: old_runner.end,
});

// this could be sugared to something like
let old_runner = app.take_runner();
app.set_runner(old_runner.wrap_update(|app, old_update| {
    old_update();
    if app.world.resource::<MySubAppInfo>().should_change() {
        app.add_sub_app("my_sub_app", MySubApp, MySubApp::runner);
    }
}));
  1. a way to pause the app while a function runs. this could take many forms e.g.
fn app_exclusive_system(app: &mut App) {
    if app.world.resource::<MySubAppInfo>().should_change() {
        app.add_sub_app("my_sub_app", MySubApp, MySubApp::runner);
    }
}

let mut app = App::new();
app.add_app_exclusive_system(app_exclusive_system);

or

fn system(
    info: Res<MySubAppInfo>,
    mut app_commands: AppCommands // or maybe `&mut AppCommandQueue` since rarely used
) {
    if info.should_change() {
        app_commands.add_sub_app("my_sub_app", MySubApp, MySubApp::runner);
        // or
        app_commands.push(|app: &mut App| {
            app.add_sub_app("my_sub_app", MySubApp, MySubApp::runner);
        });
    }
}

What alternative(s) have you considered?

Not allowing SubApp modification.

Additional context

None.

@soqb soqb added C-Feature A new feature, making something new possible S-Needs-Triage This issue needs to be labelled labels Nov 20, 2022
@alice-i-cecile alice-i-cecile added C-Usability A targeted quality-of-life change that makes Bevy easier to use A-App Bevy apps and plugins and removed C-Feature A new feature, making something new possible S-Needs-Triage This issue needs to be labelled labels Nov 20, 2022
@hymm
Copy link
Contributor

hymm commented Nov 20, 2022

As a workaround can you use std::mem:swap in the sub app runner? It gives &mut access to the sub app.

@soqb
Copy link
Contributor Author

soqb commented Nov 20, 2022

thanks. that should work for what i'm doing (swapping SubApps) but we're still missing a way to add and remove them.

@james7132
Copy link
Member

This seems to have changed with #6503. App::insert_sub_app and App::remove_sub_app are now available. Do these APIs resolve this issue?

@soqb
Copy link
Contributor Author

soqb commented Jan 22, 2023

it's still impossible to remove a sub app after app.run() is called.

@SamJBarney
Copy link

I'm currently trying to figure out how to do this, so seeing that someone else has considered it is nice to see. I'm partial to the third option of AppCommands as it takes less boilerplate code to make changes, and you don't need to worry about the multiple world scenario. Maybe information about the subapps should be accessible via AppCommands as well?

Sorry, know this is an old thread.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-App Bevy apps and plugins C-Usability A targeted quality-of-life change that makes Bevy easier to use
Projects
None yet
Development

No branches or pull requests

5 participants