Skip to content

feat!: Add BMSPlugin group, feature flag for bindings per bevy crate & global registration options #408

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
Apr 4, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 19 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand All @@ -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"]
Expand Down
11 changes: 1 addition & 10 deletions crates/bevy_api_gen/templates/mod.tera
Original file line number Diff line number Diff line change
Expand Up @@ -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 %}
97 changes: 89 additions & 8 deletions crates/bevy_mod_scripting_core/src/bindings/globals/core.rs
Original file line number Diff line number Diff line change
@@ -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;

Expand All @@ -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<fn(&TypeRegistration) -> 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::<AppScriptGlobalsRegistry>();
}
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::<AppScriptGlobalsRegistry>()
.clone();
Expand All @@ -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;
}
Expand Down Expand Up @@ -89,7 +125,8 @@ impl CoreGlobals {
let type_registry = guard.type_registry();
let type_registry = type_registry.read();
let mut type_cache = HashMap::<String, _>::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)?;
Expand All @@ -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::<TestType>();
let plugin = CoreScriptGlobalsPlugin::default();
plugin.build(&mut app);
plugin.finish(&mut app);
let globals = app
.world()
.get_resource::<AppScriptGlobalsRegistry>()
.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::<AppScriptGlobalsRegistry>()
.unwrap()
.read();

// check that the type is not registered
assert!(globals.len() == 1);
assert!(globals.get("types").is_some());
}
}
3 changes: 3 additions & 0 deletions crates/bevy_mod_scripting_core/src/bindings/script_system.rs
Original file line number Diff line number Diff line change
Expand Up @@ -675,6 +675,8 @@ mod test {
};
use test_utils::make_test_plugin;

use crate::BMSScriptingInfrastructurePlugin;

use super::*;

make_test_plugin!(crate);
Expand All @@ -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::<MainScheduleOrder>();
Expand Down
2 changes: 2 additions & 0 deletions crates/bevy_mod_scripting_core/src/handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,7 @@ mod test {
event::{CallbackLabel, IntoCallbackLabel, ScriptCallbackEvent, ScriptErrorEvent},
runtime::RuntimeContainer,
script::{Script, ScriptComponent, ScriptId, Scripts, StaticScripts},
BMSScriptingInfrastructurePlugin,
};

use super::*;
Expand Down Expand Up @@ -597,6 +598,7 @@ mod test {
AssetPlugin::default(),
DiagnosticsPlugin,
TestPlugin::default(),
BMSScriptingInfrastructurePlugin,
));

assert!(app
Expand Down
Loading
Loading