Skip to content

Commit

Permalink
app: PluginGroups and DefaultPlugins (#744)
Browse files Browse the repository at this point in the history
  • Loading branch information
cart committed Oct 29, 2020
1 parent a592ef0 commit bf2a917
Show file tree
Hide file tree
Showing 10 changed files with 242 additions and 56 deletions.
4 changes: 4 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,10 @@ path = "examples/app/headless.rs"
name = "plugin"
path = "examples/app/plugin.rs"

[[example]]
name = "plugin_group"
path = "examples/app/plugin_group.rs"

[[example]]
name = "return_after_run"
path = "examples/app/return_after_run.rs"
Expand Down
1 change: 1 addition & 0 deletions crates/bevy_app/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ keywords = ["bevy"]
bevy_derive = { path = "../bevy_derive", version = "0.2.1" }
bevy_ecs = { path = "../bevy_ecs", version = "0.2.1" }
bevy_math = { path = "../bevy_math", version = "0.2.1" }
bevy_utils = { path = "../bevy_utils", version = "0.2.1" }

# other
log = { version = "0.4", features = ["release_max_level_info"] }
Expand Down
21 changes: 20 additions & 1 deletion crates/bevy_app/src/app_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use crate::{
app::{App, AppExit},
event::Events,
plugin::Plugin,
stage, startup_stage,
stage, startup_stage, PluginGroup, PluginGroupBuilder,
};
use bevy_ecs::{FromResources, IntoQuerySystem, Resources, System, World};

Expand Down Expand Up @@ -271,4 +271,23 @@ impl AppBuilder {
plugin.build(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
}
}
5 changes: 3 additions & 2 deletions crates/bevy_app/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,22 @@ mod app;
mod app_builder;
mod event;
mod plugin;
mod plugin_group;
mod schedule_runner;

pub use app::*;
pub use app_builder::*;
pub use bevy_derive::DynamicPlugin;
pub use event::*;
pub use plugin::*;
pub use plugin_group::*;
pub use schedule_runner::*;

pub mod prelude {
pub use crate::{
app::App,
app_builder::AppBuilder,
event::{EventReader, Events},
plugin::Plugin,
stage, DynamicPlugin,
stage, DynamicPlugin, Plugin, PluginGroup,
};
}
103 changes: 103 additions & 0 deletions crates/bevy_app/src/plugin_group.rs
Original file line number Diff line number Diff line change
@@ -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);
}
}
}
}
}
50 changes: 50 additions & 0 deletions examples/app/plugin_group.rs
Original file line number Diff line number Diff line change
@@ -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");
}
50 changes: 0 additions & 50 deletions src/add_default_plugins.rs

This file was deleted.

58 changes: 58 additions & 0 deletions src/default_plugins.rs
Original file line number Diff line number Diff line change
@@ -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)
}
}
4 changes: 2 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,9 @@
html_favicon_url = "https://bevyengine.org/assets/icon.png"
)]

mod add_default_plugins;
mod default_plugins;
pub mod prelude;

pub use add_default_plugins::*;
pub use bevy_app as app;
pub use bevy_asset as asset;
pub use bevy_core as core;
Expand All @@ -55,6 +54,7 @@ pub use bevy_transform as transform;
pub use bevy_type_registry as type_registry;
pub use bevy_utils as utils;
pub use bevy_window as window;
pub use default_plugins::*;

#[cfg(feature = "bevy_audio")]
pub use bevy_audio as audio;
Expand Down
2 changes: 1 addition & 1 deletion src/prelude.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
pub use crate::{
app::prelude::*, asset::prelude::*, core::prelude::*, ecs::prelude::*, input::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")]
Expand Down

0 comments on commit bf2a917

Please sign in to comment.