app: PluginGroups and DefaultPlugins (#744)

This commit is contained in:
Carter Anderson 2020-10-29 13:04:28 -07:00 committed by GitHub
parent a592ef0562
commit bf2a917b81
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 242 additions and 56 deletions

View file

@ -154,6 +154,10 @@ path = "examples/app/headless.rs"
name = "plugin" name = "plugin"
path = "examples/app/plugin.rs" path = "examples/app/plugin.rs"
[[example]]
name = "plugin_group"
path = "examples/app/plugin_group.rs"
[[example]] [[example]]
name = "return_after_run" name = "return_after_run"
path = "examples/app/return_after_run.rs" path = "examples/app/return_after_run.rs"

View file

@ -17,6 +17,7 @@ keywords = ["bevy"]
bevy_derive = { path = "../bevy_derive", version = "0.2.1" } bevy_derive = { path = "../bevy_derive", version = "0.2.1" }
bevy_ecs = { path = "../bevy_ecs", version = "0.2.1" } bevy_ecs = { path = "../bevy_ecs", version = "0.2.1" }
bevy_math = { path = "../bevy_math", version = "0.2.1" } bevy_math = { path = "../bevy_math", version = "0.2.1" }
bevy_utils = { path = "../bevy_utils", version = "0.2.1" }
# other # other
log = { version = "0.4", features = ["release_max_level_info"] } log = { version = "0.4", features = ["release_max_level_info"] }

View file

@ -2,7 +2,7 @@ use crate::{
app::{App, AppExit}, app::{App, AppExit},
event::Events, event::Events,
plugin::Plugin, plugin::Plugin,
stage, startup_stage, stage, startup_stage, PluginGroup, PluginGroupBuilder,
}; };
use bevy_ecs::{FromResources, IntoQuerySystem, Resources, System, World}; use bevy_ecs::{FromResources, IntoQuerySystem, Resources, System, World};
@ -271,4 +271,23 @@ impl AppBuilder {
plugin.build(self); plugin.build(self);
self self
} }
pub fn add_plugin_group<T: PluginGroup>(&mut self, mut group: T) -> &mut Self {
let mut plugin_group_builder = PluginGroupBuilder::default();
group.build(&mut plugin_group_builder);
plugin_group_builder.finish(self);
self
}
pub fn add_plugin_group_with<T, F>(&mut self, mut group: T, func: F) -> &mut Self
where
T: PluginGroup,
F: FnOnce(&mut PluginGroupBuilder) -> &mut PluginGroupBuilder,
{
let mut plugin_group_builder = PluginGroupBuilder::default();
group.build(&mut plugin_group_builder);
func(&mut plugin_group_builder);
plugin_group_builder.finish(self);
self
}
} }

View file

@ -7,6 +7,7 @@ mod app;
mod app_builder; mod app_builder;
mod event; mod event;
mod plugin; mod plugin;
mod plugin_group;
mod schedule_runner; mod schedule_runner;
pub use app::*; pub use app::*;
@ -14,6 +15,7 @@ pub use app_builder::*;
pub use bevy_derive::DynamicPlugin; pub use bevy_derive::DynamicPlugin;
pub use event::*; pub use event::*;
pub use plugin::*; pub use plugin::*;
pub use plugin_group::*;
pub use schedule_runner::*; pub use schedule_runner::*;
pub mod prelude { pub mod prelude {
@ -21,7 +23,6 @@ pub mod prelude {
app::App, app::App,
app_builder::AppBuilder, app_builder::AppBuilder,
event::{EventReader, Events}, event::{EventReader, Events},
plugin::Plugin, stage, DynamicPlugin, Plugin, PluginGroup,
stage, DynamicPlugin,
}; };
} }

View file

@ -0,0 +1,103 @@
use crate::{AppBuilder, Plugin};
use bevy_utils::HashMap;
use std::any::TypeId;
pub trait PluginGroup {
fn build(&mut self, group: &mut PluginGroupBuilder);
}
struct PluginEntry {
plugin: Box<dyn Plugin>,
enabled: bool,
}
#[derive(Default)]
pub struct PluginGroupBuilder {
plugins: HashMap<TypeId, PluginEntry>,
order: Vec<TypeId>,
}
impl PluginGroupBuilder {
pub fn add<T: Plugin>(&mut self, plugin: T) -> &mut Self {
self.order.push(TypeId::of::<T>());
self.plugins.insert(
TypeId::of::<T>(),
PluginEntry {
plugin: Box::new(plugin),
enabled: true,
},
);
self
}
pub fn add_before<Target: Plugin, T: Plugin>(&mut self, plugin: T) -> &mut Self {
let target_index = self
.order
.iter()
.enumerate()
.find(|(_i, ty)| **ty == TypeId::of::<Target>())
.map(|(i, _)| i)
.unwrap_or_else(|| {
panic!("Plugin does not exist: {}", std::any::type_name::<Target>())
});
self.order.insert(target_index, TypeId::of::<T>());
self.plugins.insert(
TypeId::of::<T>(),
PluginEntry {
plugin: Box::new(plugin),
enabled: true,
},
);
self
}
pub fn add_after<Target: Plugin, T: Plugin>(&mut self, plugin: T) -> &mut Self {
let target_index = self
.order
.iter()
.enumerate()
.find(|(_i, ty)| **ty == TypeId::of::<Target>())
.map(|(i, _)| i)
.unwrap_or_else(|| {
panic!("Plugin does not exist: {}", std::any::type_name::<Target>())
});
self.order.insert(target_index + 1, TypeId::of::<T>());
self.plugins.insert(
TypeId::of::<T>(),
PluginEntry {
plugin: Box::new(plugin),
enabled: true,
},
);
self
}
pub fn enable<T: Plugin>(&mut self) -> &mut Self {
let mut plugin_entry = self
.plugins
.get_mut(&TypeId::of::<T>())
.expect("Cannot enable a plugin that does not exist");
plugin_entry.enabled = true;
self
}
pub fn disable<T: Plugin>(&mut self) -> &mut Self {
let mut plugin_entry = self
.plugins
.get_mut(&TypeId::of::<T>())
.expect("Cannot disable a plugin that does not exist");
plugin_entry.enabled = false;
self
}
pub fn finish(self, app: &mut AppBuilder) {
for ty in self.order.iter() {
if let Some(entry) = self.plugins.get(ty) {
if entry.enabled {
log::debug!("added plugin: {}", entry.plugin.name());
entry.plugin.build(app);
}
}
}
}
}

View file

@ -0,0 +1,50 @@
use bevy::{app::PluginGroupBuilder, prelude::*};
/// PluginGroups are a way to group sets of plugins that should be registered together.
fn main() {
App::build()
// The app.add_default_plugins() you see in all of the examples is just an alias for this:
.add_plugin_group(DefaultPlugins)
// Adding a plugin group adds all plugins in the group by default
.add_plugin_group(HelloWorldPlugins)
// You can also modify a PluginGroup (such as disabling plugins) like this:
// .add_plugin_group_with(HelloWorldPlugins, |group| {
// group
// .disable::<PrintWorldPlugin>()
// .add_before::<PrintHelloPlugin, _>(bevy::diagnostic::PrintDiagnosticsPlugin::default())
// })
.run();
}
/// A group of plugins that produce the "hello world" behavior
pub struct HelloWorldPlugins;
impl PluginGroup for HelloWorldPlugins {
fn build(&mut self, group: &mut PluginGroupBuilder) {
group.add(PrintHelloPlugin).add(PrintWorldPlugin);
}
}
pub struct PrintHelloPlugin;
impl Plugin for PrintHelloPlugin {
fn build(&self, app: &mut AppBuilder) {
app.add_system(print_hello_system.system());
}
}
fn print_hello_system() {
println!("hello");
}
pub struct PrintWorldPlugin;
impl Plugin for PrintWorldPlugin {
fn build(&self, app: &mut AppBuilder) {
app.add_system(print_world_system.system());
}
}
fn print_world_system() {
println!("world");
}

View file

@ -1,50 +0,0 @@
use crate::app::AppBuilder;
pub trait AddDefaultPlugins {
fn add_default_plugins(&mut self) -> &mut Self;
}
impl AddDefaultPlugins for AppBuilder {
fn add_default_plugins(&mut self) -> &mut Self {
self.add_plugin(bevy_type_registry::TypeRegistryPlugin::default());
self.add_plugin(bevy_core::CorePlugin::default());
self.add_plugin(bevy_transform::TransformPlugin::default());
self.add_plugin(bevy_diagnostic::DiagnosticsPlugin::default());
self.add_plugin(bevy_input::InputPlugin::default());
self.add_plugin(bevy_window::WindowPlugin::default());
self.add_plugin(bevy_asset::AssetPlugin::default());
self.add_plugin(bevy_scene::ScenePlugin::default());
#[cfg(feature = "bevy_render")]
self.add_plugin(bevy_render::RenderPlugin::default());
#[cfg(feature = "bevy_sprite")]
self.add_plugin(bevy_sprite::SpritePlugin::default());
#[cfg(feature = "bevy_pbr")]
self.add_plugin(bevy_pbr::PbrPlugin::default());
#[cfg(feature = "bevy_ui")]
self.add_plugin(bevy_ui::UiPlugin::default());
#[cfg(feature = "bevy_text")]
self.add_plugin(bevy_text::TextPlugin::default());
#[cfg(feature = "bevy_audio")]
self.add_plugin(bevy_audio::AudioPlugin::default());
#[cfg(feature = "bevy_gilrs")]
self.add_plugin(bevy_gilrs::GilrsPlugin::default());
#[cfg(feature = "bevy_gltf")]
self.add_plugin(bevy_gltf::GltfPlugin::default());
#[cfg(feature = "bevy_winit")]
self.add_plugin(bevy_winit::WinitPlugin::default());
#[cfg(feature = "bevy_wgpu")]
self.add_plugin(bevy_wgpu::WgpuPlugin::default());
self
}
}

58
src/default_plugins.rs Normal file
View file

@ -0,0 +1,58 @@
use bevy_app::{PluginGroup, PluginGroupBuilder};
use crate::app::AppBuilder;
pub struct DefaultPlugins;
impl PluginGroup for DefaultPlugins {
fn build(&mut self, group: &mut PluginGroupBuilder) {
group.add(bevy_type_registry::TypeRegistryPlugin::default());
group.add(bevy_core::CorePlugin::default());
group.add(bevy_transform::TransformPlugin::default());
group.add(bevy_diagnostic::DiagnosticsPlugin::default());
group.add(bevy_input::InputPlugin::default());
group.add(bevy_window::WindowPlugin::default());
group.add(bevy_asset::AssetPlugin::default());
group.add(bevy_scene::ScenePlugin::default());
#[cfg(feature = "bevy_render")]
group.add(bevy_render::RenderPlugin::default());
#[cfg(feature = "bevy_sprite")]
group.add(bevy_sprite::SpritePlugin::default());
#[cfg(feature = "bevy_pbr")]
group.add(bevy_pbr::PbrPlugin::default());
#[cfg(feature = "bevy_ui")]
group.add(bevy_ui::UiPlugin::default());
#[cfg(feature = "bevy_text")]
group.add(bevy_text::TextPlugin::default());
#[cfg(feature = "bevy_audio")]
group.add(bevy_audio::AudioPlugin::default());
#[cfg(feature = "bevy_gilrs")]
group.add(bevy_gilrs::GilrsPlugin::default());
#[cfg(feature = "bevy_gltf")]
group.add(bevy_gltf::GltfPlugin::default());
#[cfg(feature = "bevy_winit")]
group.add(bevy_winit::WinitPlugin::default());
#[cfg(feature = "bevy_wgpu")]
group.add(bevy_wgpu::WgpuPlugin::default());
}
}
pub trait AddDefaultPlugins {
fn add_default_plugins(&mut self) -> &mut Self;
}
impl AddDefaultPlugins for AppBuilder {
fn add_default_plugins(&mut self) -> &mut Self {
self.add_plugin_group(DefaultPlugins)
}
}

View file

@ -37,10 +37,9 @@
html_favicon_url = "https://bevyengine.org/assets/icon.png" html_favicon_url = "https://bevyengine.org/assets/icon.png"
)] )]
mod add_default_plugins; mod default_plugins;
pub mod prelude; pub mod prelude;
pub use add_default_plugins::*;
pub use bevy_app as app; pub use bevy_app as app;
pub use bevy_asset as asset; pub use bevy_asset as asset;
pub use bevy_core as core; pub use bevy_core as core;
@ -55,6 +54,7 @@ pub use bevy_transform as transform;
pub use bevy_type_registry as type_registry; pub use bevy_type_registry as type_registry;
pub use bevy_utils as utils; pub use bevy_utils as utils;
pub use bevy_window as window; pub use bevy_window as window;
pub use default_plugins::*;
#[cfg(feature = "bevy_audio")] #[cfg(feature = "bevy_audio")]
pub use bevy_audio as audio; pub use bevy_audio as audio;

View file

@ -1,7 +1,7 @@
pub use crate::{ pub use crate::{
app::prelude::*, asset::prelude::*, core::prelude::*, ecs::prelude::*, input::prelude::*, app::prelude::*, asset::prelude::*, core::prelude::*, ecs::prelude::*, input::prelude::*,
math::prelude::*, property::prelude::*, scene::prelude::*, transform::prelude::*, math::prelude::*, property::prelude::*, scene::prelude::*, transform::prelude::*,
type_registry::RegisterType, window::prelude::*, AddDefaultPlugins, type_registry::RegisterType, window::prelude::*, AddDefaultPlugins, DefaultPlugins,
}; };
#[cfg(feature = "bevy_audio")] #[cfg(feature = "bevy_audio")]