diff --git a/Cargo.toml b/Cargo.toml index d0c03c1..9ab19bd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -53,6 +53,10 @@ path = "examples/rhai/function_params.rs" name = "hello_world_rhai" path = "examples/rhai/hello_world.rs" +[[example]] +name = "multiple_plugins_rhai" +path = "examples/rhai/multiple_plugins.rs" + [[example]] name = "non_closure_system_rhai" path = "examples/rhai/non_closure_system.rs" @@ -93,6 +97,10 @@ path = "examples/lua/function_params.rs" name = "hello_world_lua" path = "examples/lua/hello_world.rs" +[[example]] +name = "multiple_plugins_lua" +path = "examples/lua/multiple_plugins.rs" + [[example]] name = "non_closure_system_lua" path = "examples/lua/non_closure_system.rs" diff --git a/assets/examples/lua/multiple_plugins_plugin_a.lua b/assets/examples/lua/multiple_plugins_plugin_a.lua new file mode 100644 index 0000000..7befdb5 --- /dev/null +++ b/assets/examples/lua/multiple_plugins_plugin_a.lua @@ -0,0 +1 @@ +hello_from_plugin_a() \ No newline at end of file diff --git a/assets/examples/lua/multiple_plugins_plugin_b.lua b/assets/examples/lua/multiple_plugins_plugin_b.lua new file mode 100644 index 0000000..85a63e9 --- /dev/null +++ b/assets/examples/lua/multiple_plugins_plugin_b.lua @@ -0,0 +1 @@ +hello_from_plugin_b_with_parameters("hello", 42) \ No newline at end of file diff --git a/assets/examples/rhai/multiple_plugins_plugin_a.rhai b/assets/examples/rhai/multiple_plugins_plugin_a.rhai new file mode 100644 index 0000000..9d7bfe8 --- /dev/null +++ b/assets/examples/rhai/multiple_plugins_plugin_a.rhai @@ -0,0 +1 @@ +hello_from_plugin_a(); \ No newline at end of file diff --git a/assets/examples/rhai/multiple_plugins_plugin_b.rhai b/assets/examples/rhai/multiple_plugins_plugin_b.rhai new file mode 100644 index 0000000..dcb9e33 --- /dev/null +++ b/assets/examples/rhai/multiple_plugins_plugin_b.rhai @@ -0,0 +1 @@ +hello_from_plugin_b_with_parameters("hello", 42); \ No newline at end of file diff --git a/book/src/introduction.md b/book/src/introduction.md index 05babec..eade7af 100644 --- a/book/src/introduction.md +++ b/book/src/introduction.md @@ -88,6 +88,36 @@ which you can then call in your script like this: fun_with_string_param("Hello world!") ``` +It is also possible to split the definition of your callback functions up over multiple plugins. This enables you to split up your code by subject and keep the main initialization light and clean. +This can be accomplished by using `add_scripting_api`. Be careful though, `add_scripting` has to be called before adding plugins. +```rust +use bevy::prelude::*; +use bevy_scriptum::prelude::*; +use bevy_scriptum::runtimes::lua::prelude::*; + +struct MyPlugin; +impl Plugin for MyPlugin { + fn build(&self, app: &mut App) { + app.add_scripting_api::(|runtime| { + runtime.add_function(String::from("hello_from_my_plugin"), || { + info!("Hello from MyPlugin"); + }); + }); + } +} + +// Main +fn main() { + App::new() + .add_plugins(DefaultPlugins) + .add_scripting::(|_| { + // nice and clean + }) + .add_plugins(MyPlugin) + .run(); +} +``` + ### Usage Add the following to your `Cargo.toml`: diff --git a/examples/lua/multiple_plugins.rs b/examples/lua/multiple_plugins.rs new file mode 100644 index 0000000..979bbb8 --- /dev/null +++ b/examples/lua/multiple_plugins.rs @@ -0,0 +1,67 @@ +use bevy::prelude::*; +use bevy_scriptum::prelude::*; +use bevy_scriptum::runtimes::lua::prelude::*; + +// Plugin A +struct PluginA; +impl Plugin for PluginA { + fn build(&self, app: &mut App) { + app.add_scripting_api::(|runtime| { + runtime.add_function(String::from("hello_from_plugin_a"), || { + info!("Hello from Plugin A"); + }); + }) + .add_systems(Startup, plugin_a_startup); + } +} + +fn plugin_a_startup(mut commands: Commands, assets_server: Res) { + commands.spawn(Script::::new( + assets_server.load("examples/lua/multiple_plugins_plugin_a.lua"), + )); +} + +// Plugin B +struct PluginB; +impl Plugin for PluginB { + fn build(&self, app: &mut App) { + app.add_scripting_api::(|runtime| { + runtime.add_function( + String::from("hello_from_plugin_b_with_parameters"), + hello_from_b, + ); + }) + .add_systems(Startup, plugin_b_startup); + } +} + +fn plugin_b_startup(mut commands: Commands, assets_server: Res) { + commands.spawn(Script::::new( + assets_server.load("examples/lua/multiple_plugins_plugin_b.lua"), + )); +} + +fn hello_from_b(In((text, x)): In<(String, i32)>) { + info!("{} from Plugin B: {}", text, x); +} + +// Main +fn main() { + App::new() + .add_plugins(DefaultPlugins) + .add_scripting::(|runtime| { + runtime.add_function(String::from("hello_bevy"), || { + info!("hello bevy, called from script"); + }); + }) + .add_systems(Startup, main_startup) + .add_plugins(PluginA) + .add_plugins(PluginB) + .run(); +} + +fn main_startup(mut commands: Commands, assets_server: Res) { + commands.spawn(Script::::new( + assets_server.load("examples/lua/hello_world.lua"), + )); +} diff --git a/examples/rhai/multiple_plugins.rs b/examples/rhai/multiple_plugins.rs new file mode 100644 index 0000000..612334d --- /dev/null +++ b/examples/rhai/multiple_plugins.rs @@ -0,0 +1,68 @@ +use bevy::prelude::*; +use bevy_scriptum::prelude::*; +use bevy_scriptum::runtimes::rhai::prelude::*; +use rhai::ImmutableString; + +// Plugin A +struct PluginA; +impl Plugin for PluginA { + fn build(&self, app: &mut App) { + app.add_scripting_api::(|runtime| { + runtime.add_function(String::from("hello_from_plugin_a"), || { + info!("Hello from Plugin A"); + }); + }) + .add_systems(Startup, plugin_a_startup); + } +} + +fn plugin_a_startup(mut commands: Commands, assets_server: Res) { + commands.spawn(Script::::new( + assets_server.load("examples/rhai/multiple_plugins_plugin_a.rhai"), + )); +} + +// Plugin B +struct PluginB; +impl Plugin for PluginB { + fn build(&self, app: &mut App) { + app.add_scripting_api::(|runtime| { + runtime.add_function( + String::from("hello_from_plugin_b_with_parameters"), + hello_from_b, + ); + }) + .add_systems(Startup, plugin_b_startup); + } +} + +fn plugin_b_startup(mut commands: Commands, assets_server: Res) { + commands.spawn(Script::::new( + assets_server.load("examples/rhai/multiple_plugins_plugin_b.rhai"), + )); +} + +fn hello_from_b(In((text, x)): In<(ImmutableString, i64)>) { + info!("{} from Plugin B: {}", text, x); +} + +// Main +fn main() { + App::new() + .add_plugins(DefaultPlugins) + .add_scripting::(|runtime| { + runtime.add_function(String::from("hello_bevy"), || { + info!("hello bevy, called from script"); + }); + }) + .add_systems(Startup, main_startup) + .add_plugins(PluginA) + .add_plugins(PluginB) + .run(); +} + +fn main_startup(mut commands: Commands, assets_server: Res) { + commands.spawn(Script::::new( + assets_server.load("examples/rhai/hello_world.rhai"), + )); +} diff --git a/src/lib.rs b/src/lib.rs index efa1af5..259b7ba 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -82,7 +82,34 @@ //! ```lua //! fun_with_string_param("Hello world!") //! ``` +//! It is also possible to split the definition of your callback functions up over multiple plugins. This enables you to split up your code by subject and keep the main initialization light and clean. +//! This can be accomplished by using `add_scripting_api`. Be careful though, `add_scripting` has to be called before adding plugins. +//! ```rust +//! use bevy::prelude::*; +//! use bevy_scriptum::prelude::*; +//! use bevy_scriptum::runtimes::lua::prelude::*; //! +//! struct MyPlugin; +//! impl Plugin for MyPlugin { +//! fn build(&self, app: &mut App) { +//! app.add_scripting_api::(|runtime| { +//! runtime.add_function(String::from("hello_from_my_plugin"), || { +//! info!("Hello from MyPlugin"); +//! }); +//! }); +//! } +//! } +//! +//! App::new() +//! .add_plugins(DefaultPlugins) +//! .add_scripting::(|_| { +//! // nice and clean +//! }) +//! .add_plugins(MyPlugin) +//! .run(); +//! ``` +//! +//! //! ## Usage //! //! Add the following to your `Cargo.toml`: @@ -331,6 +358,12 @@ pub trait BuildScriptingRuntime { /// Returns a "runtime" type than can be used to setup scripting runtime( /// add scripting functions etc.). fn add_scripting(&mut self, f: impl Fn(ScriptingRuntimeBuilder)) -> &mut Self; + + /// Returns a "runtime" type that can be used to add additional scripting functions from plugins etc. + fn add_scripting_api( + &mut self, + f: impl Fn(ScriptingRuntimeBuilder), + ) -> &mut Self; } pub struct ScriptingRuntimeBuilder<'a, R: Runtime> { @@ -402,6 +435,21 @@ impl BuildScriptingRuntime for App { self } + + /// Adds a way to add additional accesspoints to the scripting runtime. For example from plugins to add + /// for example additional lua functions to the runtime. + /// + /// Be careful with calling this though, make sure that the `add_scripting` call is already called before calling this function. + fn add_scripting_api( + &mut self, + f: impl Fn(ScriptingRuntimeBuilder), + ) -> &mut Self { + let runtime = ScriptingRuntimeBuilder::::new(self.world_mut()); + + f(runtime); + + self + } } /// A resource that stores all the callbacks that were registered using [AddScriptFunctionAppExt::add_function].