seldom_fn_plugin

Crates.io MIT/Apache 2.0 Crates.io

seldom_fn_plugin allows using Rust functions in place of Bevy plugins without sacrificing the builder pattern. This improves the ergonomics of plugin-heavy apps and makes it possible to avoid certain .clone()s while maintaining modularity.

I would advise against exposing a fn_plugin in a public API. It is better to keep consistent with the rest of the Bevy ecosystem in this case.

The code for this crate is only 10 lines, excluding docs and whitespace, so you can avoid adding a dependency by just copying the code into your project. I decided to publish it despite its length for a few reasons. First, I want to see people use this pattern. Second, I work on many Bevy projects, and would like to reduce the duplication of this code. Finally, I intend to publish more crates, so it doesn't hurt to get familiar with the process.

Compatibility

| Bevy | seldom_fn_plugin | | ---- | ------------------ | | 0.8 | 0.1 |

Examples

Here is an example usage:

```Rust use bevy::prelude::*; use seldomfnplugin::FnPluginExt;

fn say_hi() { println!("hi"); }

fn myplugin(app: &mut App) { app.addsystem(say_hi); }

fn main() { App::new().fnplugin(myplugin).run(); } ```

Here are some examples from a game and some other crates I'm developing:

Before:

```Rust pub struct ControlsPlugin;

impl Plugin for ControlsPlugin { fn build(&self, app: &mut App) { app.init_resource::(); } } ```

After:

Rust pub fn controls_plugin(app: &mut App) { app.init_resource::<Controls>(); }

Before:

```Rust pub(crate) struct AssetPlugin;

impl Plugin for AssetPlugin { fn build(&self, app: &mut App) { app.addplugin(PxAssetPlugin::::default()) .addplugin(PxAssetPlugin::::default()) .addplugin(PxAssetPlugin::::default()) .addplugin(PxAssetPlugin::::default()); } }

struct PxAssetPlugin(PhantomData);

impl Plugin for PxAssetPlugin { fn build(&self, app: &mut App) { app.addasset::>() .initresource::>() .addsystemset(SystemSet::onupdate(PaletteState::Loaded).withsystem(D::load)); } }

impl Default for PxAssetPlugin { fn default() -> Self { Self(default()) } } ```

After (avoids an annoying PhantomData):

```Rust pub(crate) fn assetplugin(app: &mut App) { app.fnplugin(pxassetplugin::) .fnplugin(pxassetplugin::) .fnplugin(pxassetplugin::) .fnplugin(pxasset_plugin::); }

fn pxassetplugin(app: &mut App) { app.addasset::>() .initresource::>() .addsystemset(SystemSet::onupdate(PaletteState::Loaded).withsystem(D::load)); } ```

Before:

```Rust pub(crate) struct CollisionPlugin { listeners: HashMap>, resolvers: HashMap>, }

impl Plugin for CollisionPlugin { fn build(&self, app: &mut App) { app.addevent::().addsystem(detect_collisions( self.listeners.clone(), self.resolvers.clone(), )); } }

impl CollisionPlugin { pub(crate) fn new( listeners: HashMap>, resolvers: HashMap>, ) -> Self { Self { listeners, resolvers, } } } ```

After (avoids a couple .clone()s):

Rust pub(crate) fn collision_plugin<G: PxCollisionGroup>( listeners: HashMap<G, HashSet<G>>, resolvers: HashMap<G, HashSet<G>>, ) -> impl FnOnce(&mut App) { |app| { app.add_event::<PxCollision>() .add_system(detect_collisions(listeners, resolvers)); } }

License

seldom_fn_plugin is dual-licensed under MIT and Apache 2.0 at your option.