diff --git a/demos/scripting/assets/demo-data.yaml b/demos/scripting/assets/demo-data.yaml new file mode 100644 index 0000000000..834d2d776e --- /dev/null +++ b/demos/scripting/assets/demo-data.yaml @@ -0,0 +1 @@ +sprite: image.png diff --git a/demos/scripting/assets/game.yaml b/demos/scripting/assets/game.yaml index c3c0edafa4..49ba936a7e 100644 --- a/demos/scripting/assets/game.yaml +++ b/demos/scripting/assets/game.yaml @@ -1,5 +1,3 @@ plugins: - plugin1.plugin.lua -version: 1 -info: ./info.yaml -sprite: ./image.png +data: ./demo-data.yaml diff --git a/demos/scripting/assets/pack.yaml b/demos/scripting/assets/pack.yaml index 9445fe403c..b8f2267ae9 100644 --- a/demos/scripting/assets/pack.yaml +++ b/demos/scripting/assets/pack.yaml @@ -1,3 +1,4 @@ root: game.yaml schemas: - schemas/DemoSprite.yaml + - schemas/ScriptingDemoData.yaml diff --git a/demos/scripting/assets/plugin1.plugin.lua b/demos/scripting/assets/plugin1.plugin.lua index f7d7071782..91f34e8229 100644 --- a/demos/scripting/assets/plugin1.plugin.lua +++ b/demos/scripting/assets/plugin1.plugin.lua @@ -9,10 +9,13 @@ local function startup() local meta = assets.root local entities = resources:get(Entities) + local data_handle = meta.data + local data = assets:get(data_handle) + local ent = entities:create() components:insert(ent, Transform:create()) local sprite = Sprite:create() - sprite.image = meta.sprite + sprite.image = data.sprite components:insert(ent, sprite) components:insert(ent, DemoSprite:create()) end diff --git a/demos/scripting/assets/schemas/ScriptingDemoData.yaml b/demos/scripting/assets/schemas/ScriptingDemoData.yaml new file mode 100644 index 0000000000..da3fe283b9 --- /dev/null +++ b/demos/scripting/assets/schemas/ScriptingDemoData.yaml @@ -0,0 +1,9 @@ +# A marker type for our demo sprite. +name: ScriptingDemoData +full_name: demo_scripting::ScriptingDemoData +asset_extension: demo-data +kind: !Struct + fields: + - name: sprite + schema: UntypedHandle + diff --git a/demos/scripting/src/main.rs b/demos/scripting/src/main.rs index 9ab57a22c7..f2ceb2665c 100644 --- a/demos/scripting/src/main.rs +++ b/demos/scripting/src/main.rs @@ -6,46 +6,16 @@ use bones_framework::prelude::*; #[repr(C)] struct GameMeta { plugins: SVec>, - version: u32, - sprite: Handle, - info: Handle, -} - -#[derive(HasSchema, Default, Clone)] -#[repr(C)] -#[type_data(metadata_asset("info"))] -struct GameInfoMeta { - name: String, - gravity: f32, -} - -#[derive(HasSchema, Default, Clone)] -#[repr(C)] -struct DemoData { - name: String, - age: f32, - favorite_things: SVec, - attributes: SMap, - best_friend: Maybe, - state: DemoState, -} - -#[derive(HasSchema, Default, Clone)] -#[repr(C, u8)] -pub enum DemoState { - #[default] - Ready, - Thinking(f32), - Finished { - score: u32, - }, + data: Handle, } fn main() { let mut game = Game::new(); game.install_plugin(DefaultGamePlugin); + game.shared_resource_mut::() + .unwrap() + .register_default_assets(); GameMeta::register_schema(); - DemoData::register_schema(); game.sessions .create("launch") @@ -75,17 +45,6 @@ fn launch_game_session( meta.plugins.iter().copied().collect(), )) .add_startup_system(game_startup); - - game_session.world.insert_resource(DemoData { - name: "default name".into(), - age: 10.0, - favorite_things: ["candy".into(), "rain".into()].into_iter().collect(), - attributes: [("coolness".into(), 50.0), ("friendliness".into(), 10.57)] - .into_iter() - .collect(), - best_friend: Some("Jane".into()).into(), - state: DemoState::Thinking(20.), - }); } fn game_startup( diff --git a/framework_crates/bones_asset/src/asset.rs b/framework_crates/bones_asset/src/asset.rs index 7df677b786..ac2d6356e0 100644 --- a/framework_crates/bones_asset/src/asset.rs +++ b/framework_crates/bones_asset/src/asset.rs @@ -348,7 +348,7 @@ impl SchemaMetaAssetLoader { } } -/// The kind of asset a type represents. +/// A [type data][bones_schema::alloc::TypeDatas] that indicates how to load a type as an asset. #[derive(HasSchema)] #[schema(opaque, no_default, no_clone)] pub enum AssetKind { diff --git a/framework_crates/bones_asset/src/handle.rs b/framework_crates/bones_asset/src/handle.rs index e40a8caef9..e640bd6023 100644 --- a/framework_crates/bones_asset/src/handle.rs +++ b/framework_crates/bones_asset/src/handle.rs @@ -170,8 +170,8 @@ unsafe impl HasSchema for UntypedHandle { ); S.get_or_init(|| { SCHEMA_REGISTRY.register(SchemaData { - name: type_name::().into(), - full_name: format!("{}::{}", module_path!(), type_name::()).into(), + name: "UntypedHandle".into(), + full_name: format!("{}::{}", module_path!(), "UntypedHandle").into(), type_id: Some(TypeId::of::()), kind: SchemaKind::Struct(StructSchemaInfo { fields: vec![StructFieldInfo { diff --git a/framework_crates/bones_asset/src/server/schema_loader.rs b/framework_crates/bones_asset/src/server/schema_loader.rs index 9b101165be..6791752b83 100644 --- a/framework_crates/bones_asset/src/server/schema_loader.rs +++ b/framework_crates/bones_asset/src/server/schema_loader.rs @@ -1,6 +1,7 @@ use std::ffi::c_void; -use bones_utils::{default, ustr}; +use bones_schema::alloc::TypeDatas; +use bones_utils::ustr; use serde::Deserialize; use crate::prelude::*; @@ -14,6 +15,8 @@ struct SchemaMeta { name: String, full_name: String, kind: SchemaKindMeta, + #[serde(default)] + asset_extension: Option, } #[derive(Deserialize)] @@ -171,11 +174,18 @@ impl<'de> Deserialize<'de> for PackSchema { } }; + let type_data = TypeDatas::default(); + if let Some(ext) = meta.asset_extension { + type_data + .insert(AssetKind::Metadata { extension: ext }) + .unwrap(); + } + let schema_data = SchemaData { name, full_name, kind: schema_kind, - type_data: default(), + type_data, type_id: None, clone_fn: Some(unsafe { Unsafe::new(Box::leak(Box::new(clone_fn))) }), drop_fn: Some(unsafe { Unsafe::new(Box::leak(Box::new(drop_fn))) }), diff --git a/framework_crates/bones_schema/src/ptr.rs b/framework_crates/bones_schema/src/ptr.rs index 877e1536f3..f09f91d65c 100644 --- a/framework_crates/bones_schema/src/ptr.rs +++ b/framework_crates/bones_schema/src/ptr.rs @@ -1361,6 +1361,11 @@ pub struct SchemaBox { ptr: NonNull, schema: &'static Schema, } +impl Default for SchemaBox { + fn default() -> Self { + SchemaBox::new(()) + } +} unsafe impl Sync for SchemaBox {} unsafe impl Send for SchemaBox {} impl std::fmt::Debug for SchemaBox { diff --git a/framework_crates/bones_schema/src/std_impls.rs b/framework_crates/bones_schema/src/std_impls.rs index 875697abfd..baedbf8ba9 100644 --- a/framework_crates/bones_schema/src/std_impls.rs +++ b/framework_crates/bones_schema/src/std_impls.rs @@ -11,7 +11,7 @@ use crate::{alloc::TypeDatas, prelude::*, raw_fns::*}; use std::{alloc::Layout, any::TypeId, hash::Hasher, sync::OnceLock, time::Duration}; macro_rules! impl_primitive { - ($t:ty, $prim:ident) => { + ($t:ty, $prim:expr ) => { unsafe impl HasSchema for $t { fn schema() -> &'static Schema { static S: OnceLock<&'static Schema> = OnceLock::new(); @@ -19,7 +19,7 @@ macro_rules! impl_primitive { SCHEMA_REGISTRY.register(SchemaData { name: stringify!($t).into(), full_name: concat!("std::", stringify!($t)).into(), - kind: SchemaKind::Primitive(Primitive::$prim), + kind: SchemaKind::Primitive($prim), type_id: Some(TypeId::of::<$t>()), clone_fn: Some(<$t as RawClone>::raw_clone_cb()), drop_fn: Some(<$t as RawDrop>::raw_drop_cb()), @@ -34,18 +34,25 @@ macro_rules! impl_primitive { }; } -impl_primitive!(String, String); -impl_primitive!(bool, Bool); -impl_primitive!(u8, U8); -impl_primitive!(u16, U16); -impl_primitive!(u32, U32); -impl_primitive!(u64, U64); -impl_primitive!(u128, U128); -impl_primitive!(i8, I8); -impl_primitive!(i16, I16); -impl_primitive!(i32, I32); -impl_primitive!(i64, I64); -impl_primitive!(i128, I128); +impl_primitive!(String, Primitive::String); +impl_primitive!( + (), + Primitive::Opaque { + size: std::mem::size_of::<()>(), + align: std::mem::align_of::<()>() + } +); +impl_primitive!(bool, Primitive::Bool); +impl_primitive!(u8, Primitive::U8); +impl_primitive!(u16, Primitive::U16); +impl_primitive!(u32, Primitive::U32); +impl_primitive!(u64, Primitive::U64); +impl_primitive!(u128, Primitive::U128); +impl_primitive!(i8, Primitive::I8); +impl_primitive!(i16, Primitive::I16); +impl_primitive!(i32, Primitive::I32); +impl_primitive!(i64, Primitive::I64); +impl_primitive!(i128, Primitive::I128); macro_rules! schema_impl_float { ($t:ty, $prim:ident) => { diff --git a/framework_crates/bones_scripting/src/lib.rs b/framework_crates/bones_scripting/src/lib.rs index 22e313aa04..a63a53d96d 100644 --- a/framework_crates/bones_scripting/src/lib.rs +++ b/framework_crates/bones_scripting/src/lib.rs @@ -1,5 +1,6 @@ pub mod lua; +use bones_asset::UntypedHandle; use bones_lib::prelude::*; /// The prelude. @@ -22,6 +23,8 @@ impl Default for ScriptingGamePlugin { impl GamePlugin for ScriptingGamePlugin { fn install(self, game: &mut Game) { + UntypedHandle::register_schema(); + if self.enable_lua { game.install_plugin(lua::lua_game_plugin); } diff --git a/framework_crates/bones_scripting/src/lua/bindings/ecsref.rs b/framework_crates/bones_scripting/src/lua/bindings/ecsref.rs index 5f1dd4c26b..8310e070c1 100644 --- a/framework_crates/bones_scripting/src/lua/bindings/ecsref.rs +++ b/framework_crates/bones_scripting/src/lua/bindings/ecsref.rs @@ -363,7 +363,32 @@ pub fn metatable(ctx: Context) -> Table { let newvalue = newvalue.as_static_user_data::()?; let newvalue_b = newvalue.borrow(); let newvalue_ref = newvalue_b.schema_ref()?; - this_ref.write(newvalue_ref)?; + + // If the current and new ref are asset handles + if this_ref + .schema() + .type_data + .get::() + .is_some() + && newvalue_ref + .schema() + .type_data + .get::() + .is_some() + { + // SOUND: the `SchemaAssetHandle` type data asserts that these types + // are represented by `UntypedHandle`. Additionally, `SchemaAssetHandle` + // cannot be constructed outside the crate due to private fields, so it + // cannot be added to non-conforming types. + unsafe { + *this_ref.cast_mut_unchecked::() = + *newvalue_ref.cast_unchecked::() + } + } else { + // If we are not dealing with asset handles + // Attempt to write the new value + this_ref.write(newvalue_ref)?; + } } SchemaRefMutAccess::Primitive(p) => match (p, newvalue) { (PrimitiveRefMut::Bool(b), Value::Boolean(newb)) => *b = newb,