bevyengine / bevy

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

Required plugins / Plugin dependencies #16154

Open simbleau opened 3 weeks ago

simbleau commented 3 weeks ago

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

Adds ergonomics to plugin instantiation, rather than needing to do several checks:

pub struct PlayerHudPlugin;

impl Plugin for PlayerHudPlugin {
    fn build(&self, app: &mut App) {
        if !app.is_plugin_added::<PlayerPlugin>() {
            panic!("You must add the PlayerPlugin!");
        }
        ... Build plugin
    }
}

Would become:

#[requires(PlayerPlugin)]
pub struct PlayerHudPlugin;

impl Plugin for PlayerHudPlugin {
    fn build(&self, app: &mut App) {
        ... Build plugin
    }
}

What solution would you like?

Similar to required components, required plugins would enforce that a plugin requires other plugins to operate correctly.

For example,

mockersf commented 3 weeks ago

just wanted to note that

#[requires(PlayerPlugin)]
pub struct PlayerHudPlugin;

is not possible in Rust, we would need to make Plugin a derive macro for that

viridia commented 6 days ago

Some sort of plugin dependency system would make life easier for library authors. Currently if plugin A is added by both plugin B and plugin C (created by different authors, presumably), then using both B and C in the same app will panic because of duplication.

This doesn't need to be an annotation, however: the dependency can be specified at runtime in the Plugin implementation fairly easily. It could be something as simple as app.require_plugin::<Foo>().

However, one problem is that if the plugin struct has properties, there's no way to deal with conflicts. Thus, if plugin B requires A(true) and plugin C requires A(false), then you are out of luck.

Fortunately, plugins with properties are rare. We could simply punt and say that required plugins only work with "simple" plugins which are empty structs - if you need to require a plugin that has more complex properties, then it's up to the app developer to add it explicitly.