From 388f686917812b215a9fe8896d3e8e70a599ce00 Mon Sep 17 00:00:00 2001 From: SeanOMik Date: Sat, 24 Feb 2024 15:27:01 -0500 Subject: [PATCH] scripting: create `FN_NAME_INTERNAL_AS_COMPONENT` for implicitly converting some types as components --- examples/testbed/scripts/test.lua | 3 +- lyra-scripting/src/lua/mod.rs | 44 ++++++++++++++++++- lyra-scripting/src/lua/world.rs | 22 +++++++--- lyra-scripting/src/lua/wrappers/delta_time.rs | 4 +- lyra-scripting/src/lua/wrappers/model_comp.rs | 7 +-- lyra-scripting/src/lua/wrappers/res_handle.rs | 21 ++++++++- 6 files changed, 84 insertions(+), 17 deletions(-) diff --git a/examples/testbed/scripts/test.lua b/examples/testbed/scripts/test.lua index 1e67ad3..29f39ff 100644 --- a/examples/testbed/scripts/test.lua +++ b/examples/testbed/scripts/test.lua @@ -3,9 +3,8 @@ function on_init() print("Loaded textured cube") local pos = Transform.from_translation(Vec3.new(0, 0, -8.0)) - local cube_comp = ModelComponent.new(cube) - local e = world:spawn(pos, cube_comp) + local e = world:spawn(pos, cube) print("spawned entity " .. tostring(e)) end diff --git a/lyra-scripting/src/lua/mod.rs b/lyra-scripting/src/lua/mod.rs index ed8e36e..c068582 100644 --- a/lyra-scripting/src/lua/mod.rs +++ b/lyra-scripting/src/lua/mod.rs @@ -26,13 +26,52 @@ use lyra_ecs::{ Component, ComponentInfo, World }; use lyra_reflect::{Reflect, TypeRegistry}; +use crate::ScriptBorrow; pub type LuaContext = Mutex; +/// Name of a Lua function that is used to Reflect the Userdata, but without a value. +/// +/// This is used for reflecting the userdata as an ECS Component or Resource. This **function** +/// returns a [`ScriptBorrow`] with data as `None`. pub const FN_NAME_INTERNAL_REFLECT_TYPE: &str = "__lyra_internal_reflect_type"; + +/// Name of a Lua function that is used to Reflect the Userdata. +/// +/// This is used for reflecting the userdata as an ECS Component or Resource. This **method** +/// returns a [`ScriptBorrow`] with data as `Some`. **Anything that calls this expects the +/// method to return data**. pub const FN_NAME_INTERNAL_REFLECT: &str = "__lyra_internal_reflect"; -use crate::ScriptBorrow; +/// Name of a Lua function implemented for Userdata types that can be made into components. +/// +/// This is used for types that can be converted into components. When implementing this function, +/// you must return a [`ScriptBorrow`] that contains the component for this userdata. +/// You can return [`elua::Value::Nil`] if for some reason the type could not be converted +/// into a component. +/// +/// A good example of this is `LuaResHandle`. The resource handle is requested from the +/// world, and could be a 3d model. The 3d model could then be manually wrapped as +/// [`LuaModelComponent`] with its `new` function. But for quality of life, this internal +/// function was created so that the userdata can be converted into its component +/// type without having to wrap it. +/// +/// Without implementing this function: +/// ```lua +/// local cube = world:request_res("assets/cube-texture-embedded.gltf") +/// local cube_comp = ModelComponent.new(cube) -- annoying to write +/// +/// local pos = Transform.from_translation(Vec3.new(0, 0, -8.0)) +/// local e = world:spawn(pos, cube_comp) +/// ``` +/// +/// With this function: +/// /// ```lua +/// local cube = world:request_res("assets/cube-texture-embedded.gltf") +/// local pos = Transform.from_translation(Vec3.new(0, 0, -8.0)) +/// local e = world:spawn(pos, cube) +/// ``` +pub const FN_NAME_INTERNAL_AS_COMPONENT: &str = "__lyra_internal_refl_as_component"; /// A trait used for registering a Lua type with the world. pub trait RegisterLuaType { @@ -140,7 +179,8 @@ impl elua::Userdata for ScriptBorrow { } } +/// Helper function used for reflecting userdata as a ScriptBorrow pub fn reflect_user_data(ud: &elua::AnyUserdata) -> ScriptBorrow { ud.execute_method::<_, ScriptBorrow>(FN_NAME_INTERNAL_REFLECT, ()) - .expect("Type does not implement '__internal_reflect' properly") + .expect("Type does not implement internal reflect method properly") } \ No newline at end of file diff --git a/lyra-scripting/src/lua/world.rs b/lyra-scripting/src/lua/world.rs index 615812d..3cb081f 100644 --- a/lyra-scripting/src/lua/world.rs +++ b/lyra-scripting/src/lua/world.rs @@ -7,8 +7,7 @@ use lyra_reflect::{ReflectWorldExt, RegisteredType, TypeRegistry}; use lyra_resource::ResourceManager; use super::{ - reflect_user_data, wrappers::LuaResHandle, DynamicViewIter, LuaTableProxyLookup, - ReflectLuaProxy, ReflectedIterator, FN_NAME_INTERNAL_REFLECT, FN_NAME_INTERNAL_REFLECT_TYPE, + reflect_user_data, wrappers::LuaResHandle, DynamicViewIter, LuaTableProxyLookup, ReflectLuaProxy, ReflectedIterator, FN_NAME_INTERNAL_AS_COMPONENT, FN_NAME_INTERNAL_REFLECT, FN_NAME_INTERNAL_REFLECT_TYPE }; impl<'lua> elua::FromLua<'lua> for ScriptEntity { @@ -79,11 +78,22 @@ impl elua::Userdata for ScriptWorldPtr { Arc::new(elua::Error::runtime("provided component is not userdata")), ))?; - let script_brw = ud.execute_method::<_, ScriptBorrow>(FN_NAME_INTERNAL_REFLECT, ())?; - let reflect = script_brw.reflect_branch.as_component_unchecked(); + let comp_borrow = { + if let Ok(as_comp) = ud.get::<_, elua::Function>(FN_NAME_INTERNAL_AS_COMPONENT) { + let ud = match as_comp.exec(ud.clone())? { + elua::Value::Userdata(ud) => ud, + elua::Value::Nil => ud.clone(), + _ => todo!(), + }; - let refl_data = script_brw.data.unwrap(); - //let refl_data = refl_data.as_ref(); + ud.execute_method::<_, ScriptBorrow>(FN_NAME_INTERNAL_REFLECT, ())? + } else { + ud.execute_method::<_, ScriptBorrow>(FN_NAME_INTERNAL_REFLECT, ())? + } + }; + + let reflect = comp_borrow.reflect_branch.as_component_unchecked(); + let refl_data = comp_borrow.data.unwrap(); reflect.bundle_insert(&mut bundle, refl_data); } diff --git a/lyra-scripting/src/lua/wrappers/delta_time.rs b/lyra-scripting/src/lua/wrappers/delta_time.rs index da6e850..027985c 100644 --- a/lyra-scripting/src/lua/wrappers/delta_time.rs +++ b/lyra-scripting/src/lua/wrappers/delta_time.rs @@ -22,13 +22,13 @@ impl std::ops::DerefMut for LuaDeltaTime { } impl<'lua> elua::FromLua<'lua> for LuaDeltaTime { - fn from_lua(lua: &'lua elua::State, value: elua::Value<'lua>) -> elua::Result { + fn from_lua(_: &'lua elua::State, _: elua::Value<'lua>) -> elua::Result { todo!() } } impl<'lua> elua::AsLua<'lua> for LuaDeltaTime { - fn as_lua(self, lua: &'lua elua::State) -> elua::Result> { + fn as_lua(self, _: &'lua elua::State) -> elua::Result> { Ok(elua::Value::Number(*self.0 as f64)) } } diff --git a/lyra-scripting/src/lua/wrappers/model_comp.rs b/lyra-scripting/src/lua/wrappers/model_comp.rs index d9445d9..442b049 100644 --- a/lyra-scripting/src/lua/wrappers/model_comp.rs +++ b/lyra-scripting/src/lua/wrappers/model_comp.rs @@ -1,7 +1,7 @@ use std::any::TypeId; use std::{cell::Ref, sync::Arc}; -use elua::{AsLua, FromLua}; +use elua::FromLua; use lyra_game::scene::ModelComponent; use lyra_reflect::Reflect; use lyra_resource::{Model, ResHandle}; @@ -13,7 +13,7 @@ use crate::{lua::{FN_NAME_INTERNAL_REFLECT, FN_NAME_INTERNAL_REFLECT_TYPE}, Scri use super::LuaResHandle; #[derive(Clone, Reflect)] -pub struct LuaModelComponent(ModelComponent); +pub struct LuaModelComponent(pub ModelComponent); impl elua::Userdata for LuaModelComponent { fn name() -> String { @@ -44,7 +44,8 @@ impl elua::Userdata for LuaModelComponent { }) .function(FN_NAME_INTERNAL_REFLECT_TYPE, |_, ()| { Ok(ScriptBorrow::from_component::(None)) - }).method(FN_NAME_INTERNAL_REFLECT, |_, this, ()| { + }) + .method(FN_NAME_INTERNAL_REFLECT, |_, this, ()| { Ok(ScriptBorrow::from_component(Some(this.0.clone()))) }); diff --git a/lyra-scripting/src/lua/wrappers/res_handle.rs b/lyra-scripting/src/lua/wrappers/res_handle.rs index c3f6d0e..884cddf 100644 --- a/lyra-scripting/src/lua/wrappers/res_handle.rs +++ b/lyra-scripting/src/lua/wrappers/res_handle.rs @@ -1,7 +1,12 @@ use std::{ops::Deref, sync::Arc}; -use elua::FromLua; -use lyra_resource::ResourceStorage; +use elua::{AsLua, FromLua}; +use lyra_game::scene::ModelComponent; +use lyra_resource::{Model, ResHandle, ResourceStorage}; + +use crate::lua::FN_NAME_INTERNAL_AS_COMPONENT; + +use super::LuaModelComponent; #[derive(Clone)] pub struct LuaResHandle(pub Arc); @@ -46,6 +51,18 @@ impl elua::Userdata for LuaResHandle { Ok(this.is_loaded()) }); + builder.method(FN_NAME_INTERNAL_AS_COMPONENT, |lua, this, ()| { + let any = this.0.as_any(); + match any.downcast_ref::>() { + Some(model) => { + LuaModelComponent(ModelComponent(model.clone())).as_lua(lua) + }, + None => { + Ok(elua::Value::Nil) + } + } + }); + Ok(()) } }