diff --git a/Cargo.toml b/Cargo.toml index eed07a081d..571598297a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,7 +21,17 @@ bench = false features = ["lua54", "rhai"] [features] -default = ["core_functions", "bevy_bindings"] +default = [ + "core_functions", + "bevy_core_bindings", + "bevy_ecs_bindings", + "bevy_hierarchy_bindings", + "bevy_input_bindings", + "bevy_math_bindings", + "bevy_reflect_bindings", + "bevy_time_bindings", + "bevy_transform_bindings", +] lua = [ "bevy_mod_scripting_lua", @@ -38,7 +48,14 @@ luau = ["bevy_mod_scripting_lua/luau", "lua"] # bindings core_functions = ["bevy_mod_scripting_functions/core_functions"] -bevy_bindings = ["bevy_mod_scripting_functions/bevy_bindings"] +bevy_core_bindings = ["bevy_mod_scripting_functions/bevy_core"] +bevy_ecs_bindings = ["bevy_mod_scripting_functions/bevy_ecs"] +bevy_hierarchy_bindings = ["bevy_mod_scripting_functions/bevy_hierarchy"] +bevy_input_bindings = ["bevy_mod_scripting_functions/bevy_input"] +bevy_math_bindings = ["bevy_mod_scripting_functions/bevy_math"] +bevy_reflect_bindings = ["bevy_mod_scripting_functions/bevy_reflect"] +bevy_time_bindings = ["bevy_mod_scripting_functions/bevy_time"] +bevy_transform_bindings = ["bevy_mod_scripting_functions/bevy_transform"] # optional unsafe_lua_modules = ["bevy_mod_scripting_lua?/unsafe_lua_modules"] diff --git a/crates/bevy_api_gen/templates/mod.tera b/crates/bevy_api_gen/templates/mod.tera index 3655a08e26..2a9676a85a 100644 --- a/crates/bevy_api_gen/templates/mod.tera +++ b/crates/bevy_api_gen/templates/mod.tera @@ -4,17 +4,8 @@ #![cfg_attr(rustfmt, rustfmt_skip)] {% filter prettyplease %} {%- for crate in crates %} + #[cfg(feature="{{crate.name}}")] pub mod {{ crate.name }}; {% endfor -%} -pub struct {{ api_name }}; - -impl ::bevy::app::Plugin for {{ api_name }} { - fn build(&self, app: &mut ::bevy::prelude::App) { - {% for crate in crates %} - {% set crate_name = crate.name %} - {{ crate_name }}::{{ "ScriptingPlugin" | prefix(val=crate_name) | convert_case(case="upper_camel")}}.build(app); - {% endfor %} - } -} {% endfilter %} \ No newline at end of file diff --git a/crates/bevy_mod_scripting_core/src/bindings/globals/core.rs b/crates/bevy_mod_scripting_core/src/bindings/globals/core.rs index 9960205917..44e85bd38d 100644 --- a/crates/bevy_mod_scripting_core/src/bindings/globals/core.rs +++ b/crates/bevy_mod_scripting_core/src/bindings/globals/core.rs @@ -1,10 +1,11 @@ //! Core globals exposed by the BMS framework -use std::{collections::HashMap, sync::Arc}; +use std::{cell::RefCell, collections::HashMap, sync::Arc}; use bevy::{ app::Plugin, ecs::{entity::Entity, reflect::AppTypeRegistry, world::World}, + reflect::TypeRegistration, }; use bevy_mod_scripting_derive::script_globals; @@ -20,20 +21,55 @@ use crate::{ use super::AppScriptGlobalsRegistry; -/// A plugin introducing core globals for the BMS framework -pub struct CoreScriptGlobalsPlugin; +/// A plugin introducing core globals for the BMS framework. +/// +/// By default all types added to the type registry are present as globals, you can customize this behavior +/// by providing a filter function +pub struct CoreScriptGlobalsPlugin { + /// the filter function used to determine which types are registered as globals + /// When `true` for the given type registration, the type will be registered as a global. + pub filter: fn(&TypeRegistration) -> bool, + + /// Whether to register static references to types + /// By default static type references such as `Vec3` or `Mat3` are accessible directly from the global namespace. + pub register_static_references: bool, +} + +impl Default for CoreScriptGlobalsPlugin { + fn default() -> Self { + Self { + filter: |_| true, + register_static_references: true, + } + } +} + +thread_local! { + static GLOBAL_OPTS: RefCell bool> = RefCell::new(|_| true); +} impl Plugin for CoreScriptGlobalsPlugin { - fn build(&self, _app: &mut bevy::app::App) {} + fn build(&self, app: &mut bevy::app::App) { + app.init_resource::(); + } fn finish(&self, app: &mut bevy::app::App) { profiling::function_scope!("app finish"); - register_static_core_globals(app.world_mut()); + + if self.register_static_references { + register_static_core_globals(app.world_mut(), self.filter); + } + + // TODO: add ability to make the generated function receive generic payload + GLOBAL_OPTS.replace(self.filter); register_core_globals(app.world_mut()); } } #[profiling::function] -fn register_static_core_globals(world: &mut bevy::ecs::world::World) { +fn register_static_core_globals( + world: &mut bevy::ecs::world::World, + filter: fn(&TypeRegistration) -> bool, +) { let global_registry = world .get_resource_or_init::() .clone(); @@ -42,7 +78,7 @@ fn register_static_core_globals(world: &mut bevy::ecs::world::World) { let type_registry = type_registry.read(); // find all reflectable types without generics - for registration in type_registry.iter() { + for registration in type_registry.iter().filter(|r| filter(r)) { if !registration.type_info().generics().is_empty() { continue; } @@ -89,7 +125,8 @@ impl CoreGlobals { let type_registry = guard.type_registry(); let type_registry = type_registry.read(); let mut type_cache = HashMap::::default(); - for registration in type_registry.iter() { + let filter = GLOBAL_OPTS.with(|opts| *opts.borrow()); + for registration in type_registry.iter().filter(|r| filter(r)) { let type_path = registration.type_info().type_path_table().short_path(); let registration = ScriptTypeRegistration::new(Arc::new(registration.clone())); let registration = guard.clone().get_type_registration(registration)?; @@ -101,3 +138,47 @@ impl CoreGlobals { Ok(type_cache) } } + +#[cfg(test)] +mod test { + use super::*; + use bevy::{app::App, reflect::Reflect}; + + #[test] + fn test_register_globals() { + let mut app = App::new(); + + // register a type + #[derive(Debug, Clone, Reflect)] + struct TestType; + app.register_type::(); + let plugin = CoreScriptGlobalsPlugin::default(); + plugin.build(&mut app); + plugin.finish(&mut app); + let globals = app + .world() + .get_resource::() + .unwrap() + .read(); + assert!(globals.get("TestType").is_some()); + + // now do the same but with a filter + let mut app = App::new(); + let plugin = CoreScriptGlobalsPlugin { + filter: |_| false, + register_static_references: true, + }; + plugin.build(&mut app); + plugin.finish(&mut app); + + let globals = app + .world() + .get_resource::() + .unwrap() + .read(); + + // check that the type is not registered + assert!(globals.len() == 1); + assert!(globals.get("types").is_some()); + } +} diff --git a/crates/bevy_mod_scripting_core/src/bindings/script_system.rs b/crates/bevy_mod_scripting_core/src/bindings/script_system.rs index 76d68370c8..ab840e9593 100644 --- a/crates/bevy_mod_scripting_core/src/bindings/script_system.rs +++ b/crates/bevy_mod_scripting_core/src/bindings/script_system.rs @@ -675,6 +675,8 @@ mod test { }; use test_utils::make_test_plugin; + use crate::BMSScriptingInfrastructurePlugin; + use super::*; make_test_plugin!(crate); @@ -692,6 +694,7 @@ mod test { AssetPlugin::default(), DiagnosticsPlugin, TestPlugin::default(), + BMSScriptingInfrastructurePlugin, )); app.init_schedule(TestSchedule); let mut main_schedule_order = app.world_mut().resource_mut::(); diff --git a/crates/bevy_mod_scripting_core/src/handler.rs b/crates/bevy_mod_scripting_core/src/handler.rs index 49c0ab5b85..34f259c4c7 100644 --- a/crates/bevy_mod_scripting_core/src/handler.rs +++ b/crates/bevy_mod_scripting_core/src/handler.rs @@ -301,6 +301,7 @@ mod test { event::{CallbackLabel, IntoCallbackLabel, ScriptCallbackEvent, ScriptErrorEvent}, runtime::RuntimeContainer, script::{Script, ScriptComponent, ScriptId, Scripts, StaticScripts}, + BMSScriptingInfrastructurePlugin, }; use super::*; @@ -597,6 +598,7 @@ mod test { AssetPlugin::default(), DiagnosticsPlugin, TestPlugin::default(), + BMSScriptingInfrastructurePlugin, )); assert!(app diff --git a/crates/bevy_mod_scripting_core/src/lib.rs b/crates/bevy_mod_scripting_core/src/lib.rs index 634c5218d9..15faf31ff4 100644 --- a/crates/bevy_mod_scripting_core/src/lib.rs +++ b/crates/bevy_mod_scripting_core/src/lib.rs @@ -9,13 +9,9 @@ use asset::{ }; use bevy::prelude::*; use bindings::{ - function::script_function::AppScriptFunctionRegistry, - garbage_collector, - globals::{core::CoreScriptGlobalsPlugin, AppScriptGlobalsRegistry}, - schedule::AppScheduleRegistry, - script_value::ScriptValue, - AppReflectAllocator, DynamicScriptComponentPlugin, ReflectAllocator, ReflectReference, - ScriptTypeRegistration, + function::script_function::AppScriptFunctionRegistry, garbage_collector, + schedule::AppScheduleRegistry, script_value::ScriptValue, AppReflectAllocator, + DynamicScriptComponentPlugin, ReflectAllocator, ReflectReference, ScriptTypeRegistration, }; use commands::{AddStaticScript, RemoveStaticScript}; use context::{ @@ -137,9 +133,6 @@ impl Plugin for ScriptingPlugin

{ register_script_plugin_systems::

(app); - // add extension for the language to the asset loader - once_per_app_init(app); - if !self.additional_supported_extensions.is_empty() { app.add_supported_script_extensions( self.additional_supported_extensions, @@ -149,10 +142,6 @@ impl Plugin for ScriptingPlugin

{ register_types(app); } - - fn finish(&self, app: &mut App) { - once_per_app_finalize(app); - } } impl ScriptingPlugin

{ @@ -246,38 +235,8 @@ impl>> ConfigureScriptPlugi } } -fn once_per_app_finalize(app: &mut App) { - #[derive(Resource)] - struct BMSFinalized; - - if app.world().contains_resource::() { - return; - } - app.insert_resource(BMSFinalized); - - // read extensions from asset settings - let asset_settings_extensions = app - .world_mut() - .get_resource_or_init::() - .supported_extensions; - - // convert extensions to static array - bevy::log::info!( - "Initializing BMS with Supported extensions: {:?}", - asset_settings_extensions - ); - - app.register_asset_loader(ScriptAssetLoader { - extensions: asset_settings_extensions, - preprocessor: None, - }); - - // pre-register component id's - pre_register_componnents(app); -} - /// Ensures all types with `ReflectComponent` type data are pre-registered with component ID's -fn pre_register_componnents(app: &mut App) { +fn pre_register_components(app: &mut App) { let type_registry = app .world_mut() .get_resource_or_init::() @@ -290,34 +249,54 @@ fn pre_register_componnents(app: &mut App) { } } -// One of registration of things that need to be done only once per app -fn once_per_app_init(app: &mut App) { - #[derive(Resource)] - struct BMSInitialized; - - if app.world().contains_resource::() { - return; +/// A plugin defining shared settings between various scripting plugins +/// It is necessary to register this plugin for any of them to work +#[derive(Default)] +pub struct BMSScriptingInfrastructurePlugin; + +impl Plugin for BMSScriptingInfrastructurePlugin { + fn build(&self, app: &mut App) { + app.add_event::() + .add_event::() + .add_event::() + .init_resource::() + .init_resource::() + .init_asset::() + .init_resource::() + .insert_resource(AppScheduleRegistry::new()); + + app.add_systems( + PostUpdate, + ((garbage_collector).in_set(ScriptingSystemSet::GarbageCollection),), + ); + + configure_asset_systems(app); + + DynamicScriptComponentPlugin.build(app); } - app.insert_resource(BMSInitialized); - - app.add_event::() - .add_event::() - .add_event::() - .init_resource::() - .init_resource::() - .init_asset::() - .init_resource::() - .init_resource::() - .insert_resource(AppScheduleRegistry::new()); - app.add_systems( - PostUpdate, - ((garbage_collector).in_set(ScriptingSystemSet::GarbageCollection),), - ); - - app.add_plugins((CoreScriptGlobalsPlugin, DynamicScriptComponentPlugin)); - - configure_asset_systems(app); + fn finish(&self, app: &mut App) { + // read extensions from asset settings + let asset_settings_extensions = app + .world_mut() + .get_resource_or_init::() + .supported_extensions; + + // convert extensions to static array + bevy::log::info!( + "Initializing BMS with Supported extensions: {:?}", + asset_settings_extensions + ); + + app.register_asset_loader(ScriptAssetLoader { + extensions: asset_settings_extensions, + preprocessor: None, + }); + + // pre-register component id's + pre_register_components(app); + DynamicScriptComponentPlugin.finish(app); + } } /// Systems registered per-language @@ -450,7 +429,7 @@ mod test { .resource_mut::() .supported_extensions = &["lua", "rhai"]; - once_per_app_finalize(&mut app); + BMSScriptingInfrastructurePlugin.finish(&mut app); let asset_loader = app .world() @@ -482,7 +461,7 @@ mod test { assert!(app.world_mut().component_id::().is_none()); - once_per_app_finalize(&mut app); + BMSScriptingInfrastructurePlugin.finish(&mut app); assert!(app.world_mut().component_id::().is_some()); } diff --git a/crates/bevy_mod_scripting_functions/Cargo.toml b/crates/bevy_mod_scripting_functions/Cargo.toml index f1a094af17..b8824624df 100644 --- a/crates/bevy_mod_scripting_functions/Cargo.toml +++ b/crates/bevy_mod_scripting_functions/Cargo.toml @@ -12,24 +12,22 @@ categories = ["game-development"] readme = "readme.md" [features] +bevy_core = [] +bevy_ecs = [] +bevy_hierarchy = [] +bevy_input = [] +bevy_math = [] +bevy_reflect = [] +bevy_time = [] +bevy_transform = [] + core_functions = [] -bevy_bindings = [] lua_bindings = ["bevy_mod_scripting_lua"] rhai_bindings = ["bevy_mod_scripting_rhai"] [dependencies] -bevy = { workspace = true, features = [ - "bevy_asset", - "bevy_animation", - "bevy_core_pipeline", - "bevy_ui", - "bevy_pbr", - "bevy_render", - "bevy_text", - "bevy_sprite", - "multi_threaded", -] } +bevy = { workspace = true } profiling = { workspace = true } uuid = "1.11" smol_str = "0.2.2" diff --git a/crates/bevy_mod_scripting_functions/src/bevy_bindings/mod.rs b/crates/bevy_mod_scripting_functions/src/bevy_bindings/mod.rs index 6cec690297..73d25afbce 100644 --- a/crates/bevy_mod_scripting_functions/src/bevy_bindings/mod.rs +++ b/crates/bevy_mod_scripting_functions/src/bevy_bindings/mod.rs @@ -2,24 +2,19 @@ #![allow(clippy::all)] #![allow(unused, deprecated, dead_code)] #![cfg_attr(rustfmt, rustfmt_skip)] +#[cfg(feature = "bevy_core")] pub mod bevy_core; +#[cfg(feature = "bevy_ecs")] pub mod bevy_ecs; +#[cfg(feature = "bevy_hierarchy")] pub mod bevy_hierarchy; +#[cfg(feature = "bevy_input")] pub mod bevy_input; +#[cfg(feature = "bevy_math")] pub mod bevy_math; +#[cfg(feature = "bevy_reflect")] pub mod bevy_reflect; +#[cfg(feature = "bevy_time")] pub mod bevy_time; +#[cfg(feature = "bevy_transform")] pub mod bevy_transform; -pub struct LuaBevyScriptingPlugin; -impl ::bevy::app::Plugin for LuaBevyScriptingPlugin { - fn build(&self, app: &mut ::bevy::prelude::App) { - bevy_core::BevyCoreScriptingPlugin.build(app); - bevy_ecs::BevyEcsScriptingPlugin.build(app); - bevy_hierarchy::BevyHierarchyScriptingPlugin.build(app); - bevy_input::BevyInputScriptingPlugin.build(app); - bevy_math::BevyMathScriptingPlugin.build(app); - bevy_reflect::BevyReflectScriptingPlugin.build(app); - bevy_time::BevyTimeScriptingPlugin.build(app); - bevy_transform::BevyTransformScriptingPlugin.build(app); - } -} diff --git a/crates/bevy_mod_scripting_functions/src/core.rs b/crates/bevy_mod_scripting_functions/src/core.rs index b6cb104d88..08963a02d3 100644 --- a/crates/bevy_mod_scripting_functions/src/core.rs +++ b/crates/bevy_mod_scripting_functions/src/core.rs @@ -30,9 +30,24 @@ use bindings::{ use error::InteropError; use reflection_extensions::{PartialReflectExt, TypeIdExtensions}; +#[allow(unused_variables, reason = "feature flags")] pub fn register_bevy_bindings(app: &mut App) { - #[cfg(feature = "bevy_bindings")] - app.add_plugins(crate::bevy_bindings::LuaBevyScriptingPlugin); + #[cfg(feature = "bevy_core")] + app.add_plugins(crate::bevy_bindings::bevy_core::BevyCoreScriptingPlugin); + #[cfg(feature = "bevy_ecs")] + app.add_plugins(crate::bevy_bindings::bevy_ecs::BevyEcsScriptingPlugin); + #[cfg(feature = "bevy_hierarchy")] + app.add_plugins(crate::bevy_bindings::bevy_hierarchy::BevyHierarchyScriptingPlugin); + #[cfg(feature = "bevy_input")] + app.add_plugins(crate::bevy_bindings::bevy_input::BevyInputScriptingPlugin); + #[cfg(feature = "bevy_math")] + app.add_plugins(crate::bevy_bindings::bevy_math::BevyMathScriptingPlugin); + #[cfg(feature = "bevy_reflect")] + app.add_plugins(crate::bevy_bindings::bevy_reflect::BevyReflectScriptingPlugin); + #[cfg(feature = "bevy_time")] + app.add_plugins(crate::bevy_bindings::bevy_time::BevyTimeScriptingPlugin); + #[cfg(feature = "bevy_transform")] + app.add_plugins(crate::bevy_bindings::bevy_transform::BevyTransformScriptingPlugin); } #[script_bindings( diff --git a/crates/bevy_mod_scripting_functions/src/lib.rs b/crates/bevy_mod_scripting_functions/src/lib.rs index 3a05127a05..5f998f4cb4 100644 --- a/crates/bevy_mod_scripting_functions/src/lib.rs +++ b/crates/bevy_mod_scripting_functions/src/lib.rs @@ -1,12 +1,12 @@ #![allow(missing_docs)] use ::bevy::prelude::*; -#[cfg(feature = "bevy_bindings")] pub mod bevy_bindings; pub mod core; pub use core::*; /// A plugin that registers the core scripting functions. +#[derive(Default)] pub struct ScriptFunctionsPlugin; impl Plugin for ScriptFunctionsPlugin { diff --git a/crates/testing_crates/script_integration_test_harness/Cargo.toml b/crates/testing_crates/script_integration_test_harness/Cargo.toml index 45c85b81bc..723e8a8cae 100644 --- a/crates/testing_crates/script_integration_test_harness/Cargo.toml +++ b/crates/testing_crates/script_integration_test_harness/Cargo.toml @@ -14,7 +14,6 @@ bevy = { workspace = true } test_utils = { workspace = true } bevy_mod_scripting_core = { workspace = true } bevy_mod_scripting_functions = { workspace = true, features = [ - "bevy_bindings", "core_functions", ] } regex = { version = "1.11" } diff --git a/crates/testing_crates/script_integration_test_harness/src/lib.rs b/crates/testing_crates/script_integration_test_harness/src/lib.rs index fc265369fe..7a2ebe890a 100644 --- a/crates/testing_crates/script_integration_test_harness/src/lib.rs +++ b/crates/testing_crates/script_integration_test_harness/src/lib.rs @@ -22,8 +22,8 @@ use bevy::{ use bevy_mod_scripting_core::{ asset::ScriptAsset, bindings::{ - pretty_print::DisplayWithWorld, script_value::ScriptValue, ReflectAccessId, - WorldAccessGuard, WorldGuard, + pretty_print::DisplayWithWorld, script_value::ScriptValue, CoreScriptGlobalsPlugin, + ReflectAccessId, WorldAccessGuard, WorldGuard, }, callback_labels, error::{InteropError, ScriptError}, @@ -31,7 +31,7 @@ use bevy_mod_scripting_core::{ extractors::{HandlerContext, WithWorldGuard}, handler::handle_script_errors, script::ScriptId, - IntoScriptPluginParams, ScriptingPlugin, + BMSScriptingInfrastructurePlugin, IntoScriptPluginParams, ScriptingPlugin, }; use bevy_mod_scripting_functions::ScriptFunctionsPlugin; use criterion::{measurement::Measurement, BatchSize}; @@ -203,7 +203,12 @@ pub fn execute_integration_test< let mut app = setup_integration_test(init); - app.add_plugins((ScriptFunctionsPlugin, plugin)); + app.add_plugins(( + ScriptFunctionsPlugin, + CoreScriptGlobalsPlugin::default(), + BMSScriptingInfrastructurePlugin, + plugin, + )); register_test_functions(&mut app); @@ -272,7 +277,7 @@ pub fn execute_integration_test< } let events_completed = app.world_mut().resource_ref::>(); - if events_completed.len() > 0 { + if !events_completed.is_empty() { return Ok(()); } } @@ -406,7 +411,12 @@ where let mut app = setup_integration_test(|_, _| {}); - app.add_plugins((ScriptFunctionsPlugin, plugin)); + app.add_plugins(( + ScriptFunctionsPlugin, + CoreScriptGlobalsPlugin::default(), + BMSScriptingInfrastructurePlugin, + plugin, + )); register_test_functions(&mut app); let script_id = script_id.to_owned(); diff --git a/crates/xtask/src/main.rs b/crates/xtask/src/main.rs index d5a75c4ca0..0b1136bce3 100644 --- a/crates/xtask/src/main.rs +++ b/crates/xtask/src/main.rs @@ -31,6 +31,17 @@ use strum::{IntoEnumIterator, VariantNames}; )] #[strum(serialize_all = "snake_case")] enum Feature { + // bindings + CoreFunctions, + BevyCoreBindings, + BevyEcsBindings, + BevyHierarchyBindings, + BevyInputBindings, + BevyMathBindings, + BevyReflectBindings, + BevyTimeBindings, + BevyTransformBindings, + // Lua Lua51, Lua52, @@ -39,8 +50,6 @@ enum Feature { Luajit, Luajit52, Luau, - BevyBindings, - CoreFunctions, UnsafeLuaModules, MluaSerialize, MluaMacros, @@ -61,6 +70,7 @@ enum FeatureGroup { // RuneExclusive, ForExternalCrate, BMSFeature, + BMSFeatureNotInPowerset, } impl FeatureGroup { @@ -101,9 +111,15 @@ impl IntoFeatureGroup for Feature { | Feature::MluaMacros | Feature::MluaSerialize | Feature::UnsafeLuaModules => FeatureGroup::ForExternalCrate, - Feature::BevyBindings | Feature::CoreFunctions | Feature::ProfileWithTracy => { - FeatureGroup::BMSFeature - } // don't use wildcard here, we want to be explicit + Feature::BevyCoreBindings + | Feature::BevyEcsBindings + | Feature::BevyHierarchyBindings + | Feature::BevyInputBindings + | Feature::BevyMathBindings + | Feature::BevyReflectBindings + | Feature::BevyTimeBindings + | Feature::BevyTransformBindings => FeatureGroup::BMSFeatureNotInPowerset, + Feature::CoreFunctions | Feature::ProfileWithTracy => FeatureGroup::BMSFeature, // don't use wildcard here, we want to be explicit } } } @@ -117,7 +133,14 @@ impl Default for Features { Features::new(vec![ Feature::Lua54, Feature::CoreFunctions, - Feature::BevyBindings, + Feature::BevyCoreBindings, + Feature::BevyEcsBindings, + Feature::BevyHierarchyBindings, + Feature::BevyInputBindings, + Feature::BevyMathBindings, + Feature::BevyReflectBindings, + Feature::BevyTimeBindings, + Feature::BevyTransformBindings, ]) } } @@ -142,6 +165,29 @@ impl Features { ) } + fn display_no_default(self) -> String { + let default_features = Self::default().0; + + let excluded_default_features = default_features + .difference(&self.0) + .map(|f| format!("-{f}")) + .collect::>(); + + let mut features = self + .0 + .into_iter() + .filter(|f| !default_features.contains(f)) + .map(|f| f.to_string()) + .collect::>(); + + features.sort(); + excluded_default_features + .into_iter() + .chain(features) + .collect::>() + .join(",") + } + fn without(self, feature: Feature) -> Self { Self(self.0.into_iter().filter(|f| *f != feature).collect()) } @@ -174,6 +220,7 @@ impl Features { impl std::fmt::Display for Features { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + // exclude default features for (i, feature) in self.0.iter().sorted().enumerate() { if i > 0 { write!(f, ",")?; @@ -405,7 +452,7 @@ impl App { if self.global_args.features == Features::all_features() { "all features".to_owned() } else { - self.global_args.features.to_string() + self.global_args.features.display_no_default() } ), os: os.to_string(), @@ -1273,17 +1320,12 @@ impl Xtasks { ) -> Result { log::info!("Profiling enabled: {profile}"); - let mut features = vec![ - Feature::Lua54, - Feature::Rhai, - Feature::CoreFunctions, - Feature::BevyBindings, - ]; + let mut features = Features::default(); if profile { std::env::set_var("ENABLE_PROFILING", "1"); // features.push(Feature::BevyTracy); - features.push(Feature::ProfileWithTracy); + features.0.insert(Feature::ProfileWithTracy); } else { std::env::set_var("RUST_LOG", "bevy_mod_scripting=error"); } @@ -1296,7 +1338,7 @@ impl Xtasks { let output = Self::run_workspace_command( // run with just lua54 - &app_settings.with_features(Features::new(features)), + &app_settings.with_features(features), "bench", "Failed to run benchmarks", args, @@ -1677,6 +1719,12 @@ impl Xtasks { feature_set.0.extend(f.iter().cloned()); } + // include all features which are excluded from powersetting + if let Some(f) = grouped.get(&FeatureGroup::BMSFeatureNotInPowerset) { + feature_set.0.extend(f.iter().cloned()); + } + + // replace args with powerset output.push(App { global_args: default_args.clone().with_features(feature_set.clone()), subcmd: Xtasks::Build, diff --git a/docs/src/Summary/controlling-script-bindings.md b/docs/src/Summary/controlling-script-bindings.md index d3642bd875..1c16396a6d 100644 --- a/docs/src/Summary/controlling-script-bindings.md +++ b/docs/src/Summary/controlling-script-bindings.md @@ -159,3 +159,12 @@ There are a few reserved functions that you can override by registering them on In this context `overridable` indicates whether language implementations will look for a specific function on your type before looking at the generic `ReflectReference` namespace. You can still remove the existing registration for these functions on the `ReflectReference` namespace if you want to replace them with your own implementation. Note the `ReflectReference` namespace is special, in that functions defined on it, act like a fallback and hence apply to ALL references. + + +## Globals + +By default, each type registered with the type registry, has the following set: +- a static reference in the global namespace, i.e.: `Vec3`, `Mat3` +- an entry in the `types` global type cache, i.e.: `types.Vec3`, `types.Mat3` + +You can filter the types included by customising the `CoreScriptGlobalsPlugin` \ No newline at end of file diff --git a/docs/src/Summary/installation.md b/docs/src/Summary/installation.md index 248b6eaae6..27f0a96912 100644 --- a/docs/src/Summary/installation.md +++ b/docs/src/Summary/installation.md @@ -13,17 +13,13 @@ Choose the language features you wish enabled and add them to the features block ## Bevy Plugin -The next step is to add the BMS plugin to your application, on top of any other extras you want included in your app: +The next step is to add the BMS plugin to your application. ```rust,ignore -app.add_plugins(( - LuaScriptingPlugin::default(), - ScriptFunctionsPlugin -)); +app.add_plugins(BMSPlugin); ``` -The above is how you'd setup BMS for Lua, if you want to use another language, simply use a corresponding plugin from the integration crate. - +You can modify each of the plugins contained within the plugin group using `set(MySubPlugin)`. ## Language Features @@ -50,7 +46,14 @@ By default all of the useful features are enabled, but you may disable them if y | Feature | Description | | ---- | ---- | | core_functions | If enabled, will enable all core functions, i.e. bevy integrations which let you interact with Bevy via reflection | -| bevy_bindings | If enabled, populates the function registry with additiona automatically generated bevy bindings. This includes functions on `glam` and `bevy::ecs` types. These are useful but will slow down compilation considerably. | +| bevy_core_bindings | Enables bindings for the `bevy_core` module | +| bevy_ecs_bindings | Enables bindings for the `bevy_ecs` module | +| bevy_hierarchy_bindings | Enables bindings for the `bevy_hierarchy` module | +| bevy_input_bindings | Enables bindings for the `bevy_input` module | +| bevy_math_bindings | Enables bindings for the `bevy_math` module | +| bevy_reflect_bindings | Enables bindings for the `bevy_reflect` module | +| bevy_time_bindings | Enables bindings for the `bevy_time` module | +| bevy_transform_bindings | Enables bindings for the `bevy_transform` module | | mlua_async | Enables `mlua/async`| | mlua_serialize | Enables `mlua/serialize` | | mlua_macros | Enables `mlua/macros` | diff --git a/examples/docgen.rs b/examples/docgen.rs index 8a227d8c56..0a85736ee2 100644 --- a/examples/docgen.rs +++ b/examples/docgen.rs @@ -16,7 +16,7 @@ fn main() -> std::io::Result<()> { app.add_plugins(( // normally the global plugin is included as part of each scripting plugin, here we just take // the definitions by themselves - CoreScriptGlobalsPlugin, + CoreScriptGlobalsPlugin::default(), ScriptFunctionsPlugin, )); diff --git a/examples/game_of_life.rs b/examples/game_of_life.rs index 247b98475a..325b4a4db9 100644 --- a/examples/game_of_life.rs +++ b/examples/game_of_life.rs @@ -15,13 +15,13 @@ use bevy::{ window::{PrimaryWindow, WindowResized}, }; use bevy_console::{make_layer, AddConsoleCommand, ConsoleCommand, ConsoleOpen, ConsolePlugin}; -use bevy_mod_scripting::ScriptFunctionsPlugin; +use bevy_mod_scripting::{BMSPlugin, ScriptFunctionsPlugin}; use bevy_mod_scripting_core::{ asset::ScriptAsset, bindings::{ function::namespace::{GlobalNamespace, NamespaceBuilder}, script_value::ScriptValue, - AllocatorDiagnosticPlugin, + AllocatorDiagnosticPlugin, CoreScriptGlobalsPlugin, }, callback_labels, commands::AddStaticScript, @@ -115,12 +115,7 @@ pub enum GameOfLifeCommand { // ------------- GAME OF LIFE fn game_of_life_app(app: &mut App) -> &mut App { app.insert_resource(Time::::from_seconds(UPDATE_FREQUENCY.into())) - .add_plugins(( - // for scripting - LuaScriptingPlugin::default(), - RhaiScriptingPlugin::default(), - ScriptFunctionsPlugin, - )) + .add_plugins(BMSPlugin) .register_type::() .register_type::() .init_resource::() diff --git a/src/lib.rs b/src/lib.rs index ba771f3123..a880540a76 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -19,5 +19,21 @@ pub mod rhai { // pub use bevy_mod_scripting_rune::*; // } +use bevy::app::plugin_group; +use bevy_mod_scripting_core::{ + bindings::CoreScriptGlobalsPlugin, BMSScriptingInfrastructurePlugin, +}; pub use bevy_mod_scripting_derive::*; pub use bevy_mod_scripting_functions::*; + +plugin_group! { + pub struct BMSPlugin { + :ScriptFunctionsPlugin, + :CoreScriptGlobalsPlugin, + :BMSScriptingInfrastructurePlugin, + #[custom(cfg(feature = "lua"))] + bevy_mod_scripting_lua:::LuaScriptingPlugin, + #[custom(cfg(feature = "rhai"))] + bevy_mod_scripting_rhai:::RhaiScriptingPlugin, + } +}