diff --git a/crates/bevy_app/src/app.rs b/crates/bevy_app/src/app.rs index da41efbc15..b502e32f64 100644 --- a/crates/bevy_app/src/app.rs +++ b/crates/bevy_app/src/app.rs @@ -92,8 +92,12 @@ impl Debug for App { impl Default for App { fn default() -> Self { let mut app = App::empty(); + app.sub_apps.main.update_schedule = Some(Main.intern()); + #[cfg(feature = "bevy_reflect")] + bevy_reflect::wasm_init::wasm_init(); + #[cfg(feature = "bevy_reflect")] app.init_resource::(); diff --git a/crates/bevy_reflect/Cargo.toml b/crates/bevy_reflect/Cargo.toml index 5cfbf83300..401ef4071a 100644 --- a/crates/bevy_reflect/Cargo.toml +++ b/crates/bevy_reflect/Cargo.toml @@ -39,6 +39,8 @@ glam = { version = "0.28", features = ["serde"], optional = true } petgraph = { version = "0.6", features = ["serde-1"], optional = true } smol_str = { version = "0.2.0", optional = true } uuid = { version = "1.0", optional = true, features = ["v4", "serde"] } +inventory = "0.3" +wasm-init = "0.2" [dev-dependencies] ron = "0.8.0" diff --git a/crates/bevy_reflect/derive/src/impls/structs.rs b/crates/bevy_reflect/derive/src/impls/structs.rs index 15b11d4dd9..8095cda8c3 100644 --- a/crates/bevy_reflect/derive/src/impls/structs.rs +++ b/crates/bevy_reflect/derive/src/impls/structs.rs @@ -60,6 +60,22 @@ pub(crate) fn impl_struct(reflect_struct: &ReflectStruct) -> proc_macro2::TokenS .generics() .split_for_impl(); + let auto_reflect = if ty_generics.clone().into_token_stream().is_empty() { + quote! { + #[cfg(target_arch = "wasm32")] + #bevy_reflect_path::wasm_init::wasm_init!{ + #bevy_reflect_path::AUTOMATIC_REFLECT_TYPES + .write() + .unwrap() + .push(|reg: &mut #bevy_reflect_path::TypeRegistry| reg.register::<#struct_path>()); + } + #[cfg(not(target_arch = "wasm32"))] + #bevy_reflect_path::inventory::submit!(#bevy_reflect_path::AUTOMATIC_REFLECT_TYPES(|reg: &mut #bevy_reflect_path::TypeRegistry| reg.register::<#struct_path>())); + } + } else { + quote! {} + }; + let where_reflect_clause = where_clause_options.extend_where_clause(where_clause); quote! { @@ -73,6 +89,8 @@ pub(crate) fn impl_struct(reflect_struct: &ReflectStruct) -> proc_macro2::TokenS #function_impls + #auto_reflect + impl #impl_generics #bevy_reflect_path::Struct for #struct_path #ty_generics #where_reflect_clause { fn field(&self, name: &str) -> #FQOption<&dyn #bevy_reflect_path::PartialReflect> { match name { diff --git a/crates/bevy_reflect/src/lib.rs b/crates/bevy_reflect/src/lib.rs index 29829130fe..240bc3bd61 100644 --- a/crates/bevy_reflect/src/lib.rs +++ b/crates/bevy_reflect/src/lib.rs @@ -597,6 +597,9 @@ pub use type_registry::*; pub use bevy_reflect_derive::*; pub use erased_serde; +pub extern crate inventory; +pub extern crate wasm_init; + extern crate alloc; /// Exports used by the reflection macros. diff --git a/crates/bevy_reflect/src/type_registry.rs b/crates/bevy_reflect/src/type_registry.rs index 1263b0bbed..0f9f087257 100644 --- a/crates/bevy_reflect/src/type_registry.rs +++ b/crates/bevy_reflect/src/type_registry.rs @@ -9,6 +9,13 @@ use std::{ sync::{Arc, PoisonError, RwLock, RwLockReadGuard, RwLockWriteGuard}, }; +#[cfg(target_arch = "wasm32")] +pub static AUTOMATIC_REFLECT_TYPES: RwLock> = RwLock::new(Vec::new()); +#[cfg(not(target_arch = "wasm32"))] +pub struct AUTOMATIC_REFLECT_TYPES(pub fn(&mut TypeRegistry)); +#[cfg(not(target_arch = "wasm32"))] +inventory::collect!(AUTOMATIC_REFLECT_TYPES); + /// A registry of [reflected] types. /// /// This struct is used as the central store for type information. @@ -108,6 +115,14 @@ impl TypeRegistry { registry.register::(); registry.register::(); registry.register::(); + #[cfg(target_arch = "wasm32")] + for f in AUTOMATIC_REFLECT_TYPES.read().unwrap().iter() { + f(&mut registry) + } + #[cfg(not(target_arch = "wasm32"))] + for f in inventory::iter:: { + f.0(&mut registry) + } registry } diff --git a/examples/reflection/reflection.rs b/examples/reflection/reflection.rs index 283c1c6d18..4cb6003116 100644 --- a/examples/reflection/reflection.rs +++ b/examples/reflection/reflection.rs @@ -4,6 +4,8 @@ //! by their string name. Reflection is a core part of Bevy and enables a number of interesting //! features (like scenes). +use std::any::Any; + use bevy::{ prelude::*, reflect::{ @@ -17,7 +19,7 @@ fn main() { App::new() .add_plugins(DefaultPlugins) // Bar will be automatically registered as it's a dependency of Foo - .register_type::() + // .register_type::() .add_systems(Startup, setup) .run(); } @@ -101,6 +103,8 @@ fn setup(type_registry: Res) { let mut deserializer = ron::de::Deserializer::from_str(&ron_string).unwrap(); let reflect_value = reflect_deserializer.deserialize(&mut deserializer).unwrap(); + assert!(type_registry.contains(value.type_id())); + // Deserializing returns a `Box` value. // Generally, deserializing a value will return the "dynamic" variant of a type. // For example, deserializing a struct will return the DynamicStruct type. @@ -118,4 +122,6 @@ fn setup(type_registry: Res) { // By "patching" `Foo` with the deserialized DynamicStruct, we can "Deserialize" Foo. // This means we can serialize and deserialize with a single `Reflect` derive! value.apply(&*reflect_value); + + info!("{}", type_registry.iter().collect::>().len()); }