Compare commits

..

No commits in common. "958c86cf7326ddd2e635205a56f6e8f3921707eb" and "798719a7a2aa21f23948d50101b12b1d7fa86460" have entirely different histories.

30 changed files with 1697 additions and 979 deletions

18
.vscode/launch.json vendored
View File

@ -4,24 +4,6 @@
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0", "version": "0.2.0",
"configurations": [ "configurations": [
{
"type": "lldb",
"request": "launch",
"name": "Debug lyra lua-scripting",
"cargo": {
"args": [
"build",
"--manifest-path", "${workspaceFolder}/examples/lua-scripting/Cargo.toml"
//"--bin=testbed",
],
"filter": {
"name": "lua-scripting",
"kind": "bin"
}
},
"args": [],
"cwd": "${workspaceFolder}/examples/lua-scripting"
},
{ {
"type": "lldb", "type": "lldb",
"request": "launch", "request": "launch",

859
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -1,19 +1,10 @@
---Return the userdata's name from its metatable. ---Return the userdata's name from its metatable
---
---Returns nil if the userdata doesn't have a metatable.
---@param val userdata ---@param val userdata
---@return string|nil ---@return string
function udname(val) function udname(val)
local tbl = debug.getmetatable(val) return getmetatable(val).__name
if tbl == nil then
return nil
end
return tbl.__name
end end
function on_init() function on_init()
local cube = world:request_res("../assets/cube-texture-embedded.gltf") local cube = world:request_res("../assets/cube-texture-embedded.gltf")
print("Loaded textured cube (" .. udname(cube) .. ")") print("Loaded textured cube (" .. udname(cube) .. ")")

View File

@ -1,6 +1,6 @@
use lyra_engine::{ use lyra_engine::{
assets::{gltf::Gltf, ResourceManager}, assets::{gltf::Gltf, ResourceManager},
game::App, game::Game,
input::{ input::{
Action, ActionHandler, ActionKind, ActionMapping, ActionMappingId, ActionSource, Action, ActionHandler, ActionKind, ActionMapping, ActionMappingId, ActionSource,
InputActionPlugin, KeyCode, LayoutId, MouseAxis, MouseInput, InputActionPlugin, KeyCode, LayoutId, MouseAxis, MouseInput,
@ -33,73 +33,75 @@ async fn main() {
.bind( .bind(
ACTLBL_MOVE_FORWARD_BACKWARD, ACTLBL_MOVE_FORWARD_BACKWARD,
&[ &[
ActionSource::Keyboard(KeyCode::KeyW).into_binding_modifier(1.0), ActionSource::Keyboard(KeyCode::W).into_binding_modifier(1.0),
ActionSource::Keyboard(KeyCode::KeyS).into_binding_modifier(-1.0), ActionSource::Keyboard(KeyCode::S).into_binding_modifier(-1.0),
], ],
) )
.bind( .bind(
ACTLBL_MOVE_LEFT_RIGHT, ACTLBL_MOVE_LEFT_RIGHT,
&[ &[
ActionSource::Keyboard(KeyCode::KeyA).into_binding_modifier(-1.0), ActionSource::Keyboard(KeyCode::A).into_binding_modifier(-1.0),
ActionSource::Keyboard(KeyCode::KeyD).into_binding_modifier(1.0), ActionSource::Keyboard(KeyCode::D).into_binding_modifier(1.0),
], ],
) )
.bind( .bind(
ACTLBL_MOVE_UP_DOWN, ACTLBL_MOVE_UP_DOWN,
&[ &[
ActionSource::Keyboard(KeyCode::KeyC).into_binding_modifier(1.0), ActionSource::Keyboard(KeyCode::C).into_binding_modifier(1.0),
ActionSource::Keyboard(KeyCode::KeyZ).into_binding_modifier(-1.0), ActionSource::Keyboard(KeyCode::Z).into_binding_modifier(-1.0),
], ],
) )
.bind( .bind(
ACTLBL_LOOK_LEFT_RIGHT, ACTLBL_LOOK_LEFT_RIGHT,
&[ &[
ActionSource::Mouse(MouseInput::Axis(MouseAxis::X)).into_binding(), ActionSource::Mouse(MouseInput::Axis(MouseAxis::X)).into_binding(),
ActionSource::Keyboard(KeyCode::ArrowLeft).into_binding_modifier(-1.0), ActionSource::Keyboard(KeyCode::Left).into_binding_modifier(-1.0),
ActionSource::Keyboard(KeyCode::ArrowRight).into_binding_modifier(1.0), ActionSource::Keyboard(KeyCode::Right).into_binding_modifier(1.0),
], ],
) )
.bind( .bind(
ACTLBL_LOOK_UP_DOWN, ACTLBL_LOOK_UP_DOWN,
&[ &[
ActionSource::Mouse(MouseInput::Axis(MouseAxis::Y)).into_binding(), ActionSource::Mouse(MouseInput::Axis(MouseAxis::Y)).into_binding(),
ActionSource::Keyboard(KeyCode::ArrowUp).into_binding_modifier(-1.0), ActionSource::Keyboard(KeyCode::Up).into_binding_modifier(-1.0),
ActionSource::Keyboard(KeyCode::ArrowDown).into_binding_modifier(1.0), ActionSource::Keyboard(KeyCode::Down).into_binding_modifier(1.0),
], ],
) )
.bind( .bind(
ACTLBL_LOOK_ROLL, ACTLBL_LOOK_ROLL,
&[ &[
ActionSource::Keyboard(KeyCode::KeyE).into_binding_modifier(-1.0), ActionSource::Keyboard(KeyCode::E).into_binding_modifier(-1.0),
ActionSource::Keyboard(KeyCode::KeyQ).into_binding_modifier(1.0), ActionSource::Keyboard(KeyCode::Q).into_binding_modifier(1.0),
], ],
) )
.bind( .bind(
"Debug", "Debug",
&[ActionSource::Keyboard(KeyCode::KeyB).into_binding()], &[ActionSource::Keyboard(KeyCode::B).into_binding()],
) )
.finish(), .finish(),
) )
.finish(); .finish();
let world = &mut app.world; let world = game.world_mut();
world.add_resource(action_handler); world.add_resource(action_handler);
app.with_plugin(InputActionPlugin); game.with_plugin(InputActionPlugin);
}; };
let mut app = App::new(); Game::initialize()
app.with_plugin(lyra_engine::DefaultPlugins); .await
app.with_plugin(setup_scene_plugin); .with_plugin(lyra_engine::DefaultPlugins)
app.with_plugin(action_handler_plugin); .with_plugin(setup_scene_plugin)
app.with_plugin(setup_script_plugin); .with_plugin(action_handler_plugin)
//app.with_plugin(camera_debug_plugin); .with_plugin(setup_script_plugin)
app.with_plugin(FreeFlyCameraPlugin); //.with_plugin(camera_debug_plugin)
app.run(); .with_plugin(FreeFlyCameraPlugin)
.run()
.await;
} }
fn setup_scene_plugin(app: &mut App) { fn setup_scene_plugin(app: &mut App) {
let world = &mut app.world; let world = game.world_mut();
let resman = world.get_resource_mut::<ResourceManager>().unwrap(); let resman = world.get_resource_mut::<ResourceManager>();
let camera_gltf = resman let camera_gltf = resman
.request::<Gltf>("../assets/AntiqueCamera.glb") .request::<Gltf>("../assets/AntiqueCamera.glb")
.unwrap(); .unwrap();
@ -135,10 +137,10 @@ fn setup_scene_plugin(app: &mut App) {
} }
fn setup_script_plugin(app: &mut App) { fn setup_script_plugin(app: &mut App) {
app.with_plugin(LuaScriptingPlugin); game.with_plugin(LuaScriptingPlugin);
let world = &mut app.world; let world = game.world_mut();
let res_man = world.get_resource_mut::<ResourceManager>().unwrap(); let res_man = world.get_resource_mut::<ResourceManager>();
let script = res_man.request::<LuaScript>("scripts/test.lua").unwrap(); let script = res_man.request::<LuaScript>("scripts/test.lua").unwrap();
res_man.watch("scripts/test.lua", false).unwrap(); res_man.watch("scripts/test.lua", false).unwrap();
drop(res_man); drop(res_man);

View File

@ -509,11 +509,7 @@ impl World {
/// Attempts to find a resource in the world and returns a NonNull pointer to it /// Attempts to find a resource in the world and returns a NonNull pointer to it
pub unsafe fn get_resource_ptr<T: ResourceObject>(&self) -> Option<NonNull<T>> { pub unsafe fn get_resource_ptr<T: ResourceObject>(&self) -> Option<NonNull<T>> {
self.resources.get(&TypeId::of::<T>()) self.resources.get(&TypeId::of::<T>())
.map(|d| unsafe { .map(|d| unsafe { NonNull::new_unchecked(d.data.as_ptr() as *mut T) })
let data = d.data.borrow();
let ptr = NonNull::from(&data.res);
NonNull::new_unchecked(ptr.as_ptr() as *mut T)
})
} }
pub fn archetype_count(&self) -> usize { pub fn archetype_count(&self) -> usize {

View File

@ -72,7 +72,7 @@ impl App {
t.with(filter::Targets::new() t.with(filter::Targets::new()
// done by prefix, so it includes all lyra subpackages // done by prefix, so it includes all lyra subpackages
.with_target("lyra", Level::DEBUG) .with_target("lyra", Level::DEBUG)
.with_target("wgsl_preprocessor", Level::INFO) .with_target("wgsl_preprocessor", Level::DEBUG)
.with_target("wgpu", Level::WARN) .with_target("wgpu", Level::WARN)
.with_target("winit", Level::DEBUG) .with_target("winit", Level::DEBUG)
.with_default(Level::INFO)) .with_default(Level::INFO))

View File

@ -21,12 +21,6 @@ fn write_scroll_delta(mouse_scroll_ev: &mut EventWriter<MouseScroll>, delta: &Mo
mouse_scroll_ev.write(event); mouse_scroll_ev.write(event);
} }
fn write_key_event(key_buttons: &mut ResMut<InputButtons<winit::keyboard::KeyCode>>, physical_key: winit::keyboard::PhysicalKey, state: winit::event::ElementState) {
if let PhysicalKey::Code(code) = physical_key {
key_buttons.add_input_from_winit(code, state);
}
}
pub fn input_system( pub fn input_system(
mut key_code_res: ResMut<InputButtons<winit::keyboard::KeyCode>>, mut key_code_res: ResMut<InputButtons<winit::keyboard::KeyCode>>,
mut mouse_btn_res: ResMut<InputButtons<MouseButton>>, mut mouse_btn_res: ResMut<InputButtons<MouseButton>>,
@ -43,7 +37,9 @@ pub fn input_system(
while let Some(event) = window_ev.read() { while let Some(event) = window_ev.read() {
match event.deref() { match event.deref() {
WindowEvent::KeyboardInput { event, .. } => { WindowEvent::KeyboardInput { event, .. } => {
write_key_event(&mut key_code_res, event.physical_key, event.state); if let PhysicalKey::Code(code) = event.physical_key {
key_code_res.add_input_from_winit(code, event.state);
}
}, },
WindowEvent::CursorMoved { position, .. } => { WindowEvent::CursorMoved { position, .. } => {
let exact = MouseExact { let exact = MouseExact {
@ -104,9 +100,6 @@ pub fn input_system(
winit::event::DeviceEvent::MouseWheel { delta } => { winit::event::DeviceEvent::MouseWheel { delta } => {
write_scroll_delta(&mut mouse_scroll_ev, delta); write_scroll_delta(&mut mouse_scroll_ev, delta);
}, },
winit::event::DeviceEvent::Key(key) => {
write_key_event(&mut key_code_res, key.physical_key, key.state);
},
_ => { _ => {
todo!("unhandled device event: {:?}", device.event); todo!("unhandled device event: {:?}", device.event);
} }

View File

@ -37,13 +37,13 @@ impl_reflect_trait_value!(String);
impl_reflect_trait_value!(::core::option::Option<T: Clone + Reflect>); impl_reflect_trait_value!(::core::option::Option<T: Clone + Reflect>);
impl_reflect_trait_value!(::core::result::Result<T: Clone + Reflect, E: Clone + Reflect>); impl_reflect_trait_value!(::core::result::Result<T: Clone + Reflect, E: Clone + Reflect>);
impl_reflect_trait_value!(::core::marker::PhantomData<T: Send + Sync + 'static>); impl_reflect_trait_value!(::core::marker::PhantomData<T: 'static>);
impl_reflect_trait_value!(::std::sync::Arc<T: Reflect>); impl_reflect_trait_value!(::std::sync::Arc<T: Reflect>);
//impl_reflect_trait_value!(::std::sync::Arc<std::sync::Mutex<T: Reflect>>); //impl_reflect_trait_value!(::std::sync::Arc<std::sync::Mutex<T: Reflect>>);
//impl_reflect_trait_value!(::std::sync::RwLock<T: Reflect>); //impl_reflect_trait_value!(::std::sync::RwLock<T: Reflect>);
//impl_reflect_trait_value!(::core::ptr::NonNull<T: Reflect>); impl_reflect_trait_value!(::core::ptr::NonNull<T: Reflect>);
impl<T: Clone + Reflect, const N: usize> Reflect for [T; N] { impl<T: Clone + Reflect, const N: usize> Reflect for [T; N] {
fn name(&self) -> String { fn name(&self) -> String {

View File

@ -52,7 +52,7 @@ pub use registry::*;
pub mod impls; pub mod impls;
pub trait Reflect: Any + Send + Sync { pub trait Reflect: Any {
fn name(&self) -> String; fn name(&self) -> String;
fn type_id(&self) -> TypeId; fn type_id(&self) -> TypeId;

View File

@ -7,8 +7,8 @@ edition = "2021"
[features] [features]
default = ["lua"] default = ["lua"]
lua = ["dep:mlua"] lua = ["dep:elua"]
#teal = ["lua", "mlua/teal"] teal = ["lua", "elua/teal"]
[dependencies] [dependencies]
lyra-scripting-derive = { path = "lyra-scripting-derive" } lyra-scripting-derive = { path = "lyra-scripting-derive" }
@ -22,13 +22,11 @@ tracing = "0.1.37"
atomic_refcell = "0.1.13" atomic_refcell = "0.1.13"
# enabled with lua feature # enabled with lua feature
# #mlua = { version = "0.9.2", features = ["lua54"], optional = true } # luajit maybe?
#mlua = { version = "0.9.9", features = ["lua54", "send"], optional = true } # luajit maybe? elua = { path = "./elua", optional = true }
mlua = { git = "https://github.com/mlua-rs/mlua", rev = "4dddf3c18d4590f7c92214fa592c3faca3d2c812", features = ["lua54", "send"], optional = true } # luajit maybe?
#elua = { path = "./elua", optional = true }
itertools = "0.12.0" itertools = "0.12.0"
paste = "1.0.14" paste = "1.0.14"
parking_lot = "0.12.3"
[dev-dependencies] [dev-dependencies]
tracing-subscriber = { version = "0.3.16", features = [ "tracing-log" ] } tracing-subscriber = { version = "0.3.16", features = [ "tracing-log" ] }

View File

@ -145,24 +145,24 @@ pub(crate) fn lua_wrap_handle_impl(input: proc_macro::TokenStream) -> proc_macro
let field_creator = match &g.wrapper_type { let field_creator = match &g.wrapper_type {
Some(wrap) => { Some(wrap) => {
quote!(#wrap(data.#field).into_lua(lua)) quote!(#wrap(data.#field).as_lua(lua))
}, },
None => match &g.body { None => match &g.body {
Some(body) => { Some(body) => {
quote!(#body) quote!(#body)
}, },
None => { None => {
quote!(data.#field.clone().into_lua(lua)) quote!(data.#field.clone().as_lua(lua))
} }
} }
}; };
quote! { quote! {
fields.add_field_method_get(stringify!($field), |lua, this| { builder.field_getter(stringify!($field), |lua, this| {
if let Some(data) = this.0.data_ref() { if let Some(data) = this.0.data_ref() {
#field_creator #field_creator
} else { } else {
Ok(mlua::Value::Nil) Ok(Value::Nil)
} }
}); });
} }
@ -186,12 +186,16 @@ pub(crate) fn lua_wrap_handle_impl(input: proc_macro::TokenStream) -> proc_macro
} }
} }
impl mlua::UserData for #wrapper_name { impl elua::Userdata for #wrapper_name {
fn add_fields<F: mlua::UserDataFields<Self>>(fields: &mut F) { fn name() -> String {
fields.add_field_method_get("path", |_, this| Ok(this.path())); #ud_name.to_string()
fields.add_field_method_get("version", |_, this| Ok(this.version())); }
fields.add_field_method_get("uuid", |_, this| Ok(this.uuid().to_string()));
fields.add_field_method_get("state", |_, this| { fn build<'a>(builder: &mut elua::UserdataBuilder<'a, Self>) {
builder.field_getter("path", |_, this| Ok(this.path()));
builder.field_getter("version", |_, this| Ok(this.version()));
builder.field_getter("uuid", |_, this| Ok(this.uuid().to_string()));
builder.field_getter("state", |_, this| {
let name = if this.is_loaded() { let name = if this.is_loaded() {
"ready" "ready"
} else if this.get_error().is_some() { } else if this.get_error().is_some() {
@ -202,31 +206,29 @@ pub(crate) fn lua_wrap_handle_impl(input: proc_macro::TokenStream) -> proc_macro
}); });
#(#custom_getters)* #(#custom_getters)*
}
fn add_methods<M: mlua::UserDataMethods<Self>>(methods: &mut M) { builder.method("is_watched", |_, this, ()| {
methods.add_method("is_watched", |_, this, ()| {
Ok(this.is_watched()) Ok(this.is_watched())
}); });
methods.add_method("is_loaded", |_, this, ()| { builder.method("is_loaded", |_, this, ()| {
Ok(this.is_loaded()) Ok(this.is_loaded())
}); });
methods.add_method("is_loaded", |_, this, ()| { builder.method("is_loaded", |_, this, ()| {
Ok(this.is_loaded()) Ok(this.is_loaded())
}); });
methods.add_method("wait_until_loaded", |_, this, ()| { builder.method("wait_until_loaded", |_, this, ()| {
this.wait_recurse_dependencies_load(); this.wait_recurse_dependencies_load();
Ok(()) Ok(())
}); });
methods.add_function(FN_NAME_INTERNAL_REFLECT_TYPE, |_, ()| { builder.function(FN_NAME_INTERNAL_REFLECT_TYPE, |_, ()| {
Ok(ScriptBorrow::from_component::<ResHandle<#handle_name>>(None)) Ok(ScriptBorrow::from_component::<ResHandle<#handle_name>>(None))
}); });
methods.add_method(FN_NAME_INTERNAL_REFLECT, |_, this, ()| { builder.method(FN_NAME_INTERNAL_REFLECT, |_, this, ()| {
Ok(ScriptBorrow::from_component(Some(this.0.clone()))) Ok(ScriptBorrow::from_component(Some(this.0.clone())))
}); });
@ -234,12 +236,12 @@ pub(crate) fn lua_wrap_handle_impl(input: proc_macro::TokenStream) -> proc_macro
} }
} }
impl mlua::FromLua for #wrapper_name { impl<'a> FromLua<'a> for #wrapper_name {
fn from_lua(val: mlua::Value, _: &mlua::Lua) -> mlua::Result<Self> { fn from_lua(_: &'a elua::State, val: elua::Value<'a>) -> elua::Result<Self> {
let tyname = val.type_name(); let tyname = val.type_name();
let ud = val.as_userdata() let ud = val.as_userdata()
.ok_or(mlua::Error::external(crate::lua::Error::type_mismatch(#ud_name, &tyname)))?; .ok_or(elua::Error::type_mismatch(#ud_name, &tyname))?;
let ud = ud.borrow::<#wrapper_name>()?; let ud = ud.as_ref::<#wrapper_name>()?;
Ok(ud.clone()) Ok(ud.clone())
} }

View File

@ -156,13 +156,13 @@ impl MetaMethod {
if Self::does_metamethod_have_arg(&self.name) { if Self::does_metamethod_have_arg(&self.name) {
quote! { quote! {
methods.add_meta_method(mlua::MetaMethod::#mt_ident, |_, this, (v,): (#wrapper_ident,)| { builder.meta_method(elua::MetaMethod::#mt_ident, |_, this, (v,): (#wrapper_ident,)| {
#body #body
}); });
} }
} else { } else {
quote! { quote! {
methods.add_meta_method(mlua::MetaMethod::#mt_ident, |_, this, ()| { builder.meta_method(elua::MetaMethod::#mt_ident, |_, this, ()| {
#body #body
}); });
} }
@ -173,12 +173,12 @@ impl MetaMethod {
let body = Self::get_body_for_arg(&self.name, first, quote!(v)); let body = Self::get_body_for_arg(&self.name, first, quote!(v));
quote! { quote! {
methods.add_meta_method(mlua::MetaMethod::#mt_ident, |_, this, (v,): (#first,)| { builder.meta_method(elua::MetaMethod::#mt_ident, |_, this, (v,): (#first,)| {
#body #body
}); });
} }
} else { } else {
// an optional match arm that matches mlua::Value:Number // an optional match arm that matches elua::Value:Number
let number_arm = { let number_arm = {
let num_ident = self.arg.iter().find(|i| { let num_ident = self.arg.iter().find(|i| {
let is = i.to_string(); let is = i.to_string();
@ -195,7 +195,7 @@ impl MetaMethod {
let body = Self::get_body_for_arg(&self.name, num_ident, quote!(n as #num_ident)); let body = Self::get_body_for_arg(&self.name, num_ident, quote!(n as #num_ident));
quote! { quote! {
mlua::Value::Number(n) => { elua::Value::Number(n) => {
#body #body
}, },
} }
@ -211,7 +211,7 @@ impl MetaMethod {
let body = Self::get_method_body(&self.name, quote!(other.0)); let body = Self::get_method_body(&self.name, quote!(other.0));
quote! { quote! {
if let Ok(other) = ud.borrow::<#i>() { if let Ok(other) = ud.as_ref::<#i>() {
#body #body
} }
} }
@ -219,30 +219,30 @@ impl MetaMethod {
}); });
quote! { quote! {
mlua::Value::UserData(ud) => { elua::Value::Userdata(ud) => {
#(#if_statements else)* #(#if_statements else)*
// this is the body of the else statement // this is the body of the else statement
{ {
// try to get the name of the userdata for the error message // try to get the name of the userdata for the error message
if let Ok(mt) = ud.metatable() { if let Ok(mt) = ud.get_metatable() {
if let Ok(name) = mt.get::<String>("__name") { if let Ok(name) = mt.get::<_, String>("__name") {
return Err(mlua::Error::BadArgument { return Err(elua::Error::BadArgument {
to: Some(format!("{}.__{}", #wrapped_str, #mt_lua_name)), func: Some(format!("{}.__{}", #wrapped_str, #mt_lua_name)),
pos: 2, arg_index: 2,
name: Some("rhs".to_string()), arg_name: Some("rhs".to_string()),
cause: std::sync::Arc::new(mlua::Error::runtime( error: std::sync::Arc::new(elua::Error::Runtime(
format!("cannot multiply with unknown userdata named {}", name) format!("cannot multiply with unknown userdata named {}", name)
)) ))
}); });
} }
} }
Err(mlua::Error::BadArgument { Err(elua::Error::BadArgument {
to: Some(format!("{}.__{}", #wrapped_str, #mt_lua_name)), func: Some(format!("{}.__{}", #wrapped_str, #mt_lua_name)),
pos: 2, arg_index: 2,
name: Some("rhs".to_string()), arg_name: Some("rhs".to_string()),
cause: std::sync::Arc::new( error: std::sync::Arc::new(
mlua::Error::runtime("cannot multiply with unknown userdata") elua::Error::runtime("cannot multiply with unknown userdata")
) )
}) })
} }
@ -251,16 +251,16 @@ impl MetaMethod {
}; };
quote! { quote! {
methods.add_meta_method(mlua::MetaMethod::#mt_ident, |_, this, (v,): (mlua::Value,)| { builder.meta_method(elua::MetaMethod::#mt_ident, |_, this, (v,): (elua::Value,)| {
match v { match v {
#number_arm #number_arm
#userdata_arm #userdata_arm
_ => Err(mlua::Error::BadArgument { _ => Err(elua::Error::BadArgument {
to: Some(format!("{}.__{}", #wrapped_str, #mt_lua_name)), func: Some(format!("{}.__{}", #wrapped_str, #mt_lua_name)),
pos: 2, arg_index: 2,
name: Some("rhs".to_string()), arg_name: Some("rhs".to_string()),
cause: std::sync::Arc::new( error: std::sync::Arc::new(
mlua::Error::runtime(format!("cannot multiply with {}", v.type_name())) elua::Error::Runtime(format!("cannot multiply with {}", v.type_name()))
) )
}) })
} }
@ -410,10 +410,10 @@ pub fn wrap_lua_struct_impl(input: proc_macro::TokenStream) -> proc_macro::Token
let field_get_set_pairs = input.auto_fields.iter().map(|i| { let field_get_set_pairs = input.auto_fields.iter().map(|i| {
let is = i.to_string(); let is = i.to_string();
quote! { quote! {
fields.add_field_method_get(#is, |_, this| { builder.field_getter(#is, |_, this| {
Ok(this.#i) Ok(this.#i)
}); });
fields.add_field_method_set(#is, |_, this, #i| { builder.field_setter(#is, |_, this, #i| {
this.#i = #i; this.#i = #i;
Ok(()) Ok(())
}); });
@ -431,7 +431,7 @@ pub fn wrap_lua_struct_impl(input: proc_macro::TokenStream) -> proc_macro::Token
quote! { quote! {
// arguments for function are not specified since they can be implied from the call // arguments for function are not specified since they can be implied from the call
// to new(...) // to new(...)
methods.add_function("new", |_, ( #(#arg_names_clone),* )| { builder.function("new", |_, ( #(#arg_names_clone),* )| {
Ok(#wrapper_typename(#path::new( #(#arg_names),* ))) Ok(#wrapper_typename(#path::new( #(#arg_names),* )))
}); });
} }
@ -452,11 +452,11 @@ pub fn wrap_lua_struct_impl(input: proc_macro::TokenStream) -> proc_macro::Token
quote!() quote!()
} else { } else {
quote! { quote! {
methods.add_method(#FN_NAME_INTERNAL_REFLECT, |_, this, ()| { builder.method(#FN_NAME_INTERNAL_REFLECT, |_, this, ()| {
Ok(crate::ScriptBorrow::from_component::<#path>(Some(this.0.clone()))) Ok(crate::ScriptBorrow::from_component::<#path>(Some(this.0.clone())))
}); });
methods.add_function(#FN_NAME_INTERNAL_REFLECT_TYPE, |_, ()| { builder.function(#FN_NAME_INTERNAL_REFLECT_TYPE, |_, ()| {
Ok(crate::ScriptBorrow::from_component::<#path>(None)) Ok(crate::ScriptBorrow::from_component::<#path>(None))
}); });
} }
@ -480,21 +480,22 @@ pub fn wrap_lua_struct_impl(input: proc_macro::TokenStream) -> proc_macro::Token
} }
} }
impl mlua::FromLua for #wrapper_typename { impl<'lua> elua::FromLua<'lua> for #wrapper_typename {
fn from_lua(value: mlua::Value, _: &mlua::Lua) -> mlua::Result<Self> { fn from_lua(_lua: &'lua elua::State, value: elua::Value<'lua>) -> elua::Result<Self> {
match value { match value {
mlua::Value::UserData(ud) => Ok(ud.borrow::<Self>()?.clone()), elua::Value::Userdata(ud) => Ok(ud.as_ref::<Self>()?.clone()),
_ => panic!("Attempt to get {} from a {} value", stringify!(#wrapper_typename), value.type_name()), _ => panic!("Attempt to get {} from a {} value", stringify!(#wrapper_typename), value.type_name()),
} }
} }
} }
impl mlua::UserData for #wrapper_typename { impl elua::Userdata for #wrapper_typename {
fn add_fields<F: mlua::UserDataFields<Self>>(fields: &mut F) { fn name() -> String {
#(#field_get_set_pairs)* stringify!(#type_name).to_string()
} }
fn add_methods<M: mlua::UserDataMethods<Self>>(methods: &mut M) { fn build<'a>(builder: &mut elua::UserdataBuilder<'a, Self>) {
#(#field_get_set_pairs)*
#lua_reflects #lua_reflects
#new_func_tokens #new_func_tokens
@ -508,5 +509,20 @@ pub fn wrap_lua_struct_impl(input: proc_macro::TokenStream) -> proc_macro::Token
std::any::TypeId::of::<#path>() std::any::TypeId::of::<#path>()
} }
} }
impl<'a> elua::FromLuaVec<'a> for #wrapper_typename {
fn from_lua_value_vec(state: &'a elua::State, mut values: elua::ValueVec<'a>) -> elua::Result<Self> {
use elua::FromLua;
if let Some(val) = values.pop_front() {
#wrapper_typename::from_lua(state, val)
} else {
Err(elua::Error::IncorrectArgCount {
arg_expected: 1,
arg_count: values.len() as i32,
})
}
}
}
}) })
} }

View File

@ -49,8 +49,8 @@ impl VecWrapper {
if axis_type_name.contains("b") { if axis_type_name.contains("b") {
return quote! { return quote! {
fields.add_field_method_get("FALSE", #wrapper_ident(#wrapped_path::FALSE)); builder.field("FALSE", #wrapper_ident(#wrapped_path::FALSE));
fields.add_field_method_get("TRUE", #wrapper_ident(#wrapped_path::TRUE)); builder.field("TRUE", #wrapper_ident(#wrapped_path::TRUE));
}; };
} }
@ -87,7 +87,7 @@ impl VecWrapper {
let const_name = cnst.to_string(); let const_name = cnst.to_string();
quote! { quote! {
fields.add_field_method_get(#const_name, #wrapper_ident(#wrapped_path::#cnst)); builder.field(#const_name, #wrapper_ident(#wrapped_path::#cnst));
} }
}); });
@ -112,37 +112,27 @@ impl VecWrapper {
optional_methods.push( optional_methods.push(
quote! { quote! {
methods.add_method("clamp_length", builder.method("clamp_length",
|_, this, (min, max): (#type_id, #type_id)| { |_, this, (min, max): (#type_id, #type_id)| {
Ok(#wrapper_ident(this.clamp_length(min, max))) Ok(#wrapper_ident(this.clamp_length(min, max)))
}); });
methods.add_method("abs_diff_eq", builder.method("abs_diff_eq",
|_, this, (rhs, max_abs_diff): (#wrapper_ident, #type_id)| { |_, this, (rhs, max_abs_diff): (#wrapper_ident, #type_id)| {
Ok(this.abs_diff_eq(rhs.0, max_abs_diff)) Ok(this.abs_diff_eq(rhs.0, max_abs_diff))
}); });
methods.add_method("ceil", builder.method("ceil",
|_, this, (): ()| { |_, this, (): ()| {
Ok(#wrapper_ident(this.ceil())) Ok(#wrapper_ident(this.ceil()))
}); });
} }
); );
if vec_size == 2 { if vec_size != 4 {
// angle_between is deprecated for Vec2, must use angle_to instead.
optional_methods.push( optional_methods.push(
quote! { quote! {
methods.add_method("angle_to", builder.method("angle_between",
|_, this, (rhs,): (#wrapper_ident,)| {
Ok(this.angle_to(rhs.0))
});
}
)
} else if vec_size != 4 {
optional_methods.push(
quote! {
methods.add_method("angle_between",
|_, this, (rhs,): (#wrapper_ident,)| { |_, this, (rhs,): (#wrapper_ident,)| {
Ok(this.angle_between(rhs.0)) Ok(this.angle_between(rhs.0))
}); });
@ -154,7 +144,7 @@ impl VecWrapper {
if !axis_type_name.contains("u") { if !axis_type_name.contains("u") {
optional_methods.push( optional_methods.push(
quote! { quote! {
methods.add_method("abs", builder.method("abs",
|_, this, (): ()| { |_, this, (): ()| {
Ok(#wrapper_ident(this.abs())) Ok(#wrapper_ident(this.abs()))
}); });
@ -164,18 +154,21 @@ impl VecWrapper {
let optional_methods_iter = optional_methods.iter(); let optional_methods_iter = optional_methods.iter();
quote! { quote! {
methods.add_method("clamp",
builder.method("clamp",
|_, this, (min, max): (#wrapper_ident, #wrapper_ident)| { |_, this, (min, max): (#wrapper_ident, #wrapper_ident)| {
Ok(#wrapper_ident(this.clamp(min.0, max.0))) Ok(#wrapper_ident(this.clamp(min.0, max.0)))
}); });
// TODO: Not all Vecs have this // TODO: Not all Vecs have this
/* methods.add_method("clamp_length", /* builder.method("clamp_length",
|_, this, (min, max): (f32, f32)| { |_, this, (min, max): (f32, f32)| {
Ok(#wrapper_ident(this.clamp_length(min, max))) Ok(#wrapper_ident(this.clamp_length(min, max)))
}); */ }); */
methods.add_method("to_array",
builder.method("to_array",
|_, this, (): ()| { |_, this, (): ()| {
Ok(this.to_array()) Ok(this.to_array())
}); });

View File

@ -8,23 +8,16 @@ use crate::ScriptWorldPtr;
pub enum ScriptError { pub enum ScriptError {
#[error("{0}")] #[error("{0}")]
#[cfg(feature = "lua")] #[cfg(feature = "lua")]
LuaError(crate::lua::Error), MluaError(elua::Error),
#[error("{0}")] #[error("{0}")]
Other(anyhow::Error), Other(anyhow::Error),
} }
#[cfg(feature = "lua")] #[cfg(feature = "lua")]
impl From<mlua::Error> for ScriptError { impl From<elua::Error> for ScriptError {
fn from(value: mlua::Error) -> Self { fn from(value: elua::Error) -> Self {
ScriptError::LuaError(crate::lua::Error::Mlua(value)) ScriptError::MluaError(value)
}
}
#[cfg(feature = "lua")]
impl From<crate::lua::Error> for ScriptError {
fn from(value: crate::lua::Error) -> Self {
ScriptError::LuaError(value)
} }
} }

View File

@ -16,7 +16,7 @@ pub use host::*;
pub mod script; pub mod script;
pub use script::*; pub use script::*;
use lyra_game::game::App; use lyra_game::game::Game;
// required for some proc macros :( // required for some proc macros :(
#[allow(unused_imports)] #[allow(unused_imports)]
@ -136,15 +136,15 @@ pub trait GameScriptExt {
P: ScriptApiProvider<ScriptContext = T::ScriptContext> + 'static; P: ScriptApiProvider<ScriptContext = T::ScriptContext> + 'static;
} }
impl GameScriptExt for App { impl GameScriptExt for Game {
fn add_script_api_provider<T, P>(&mut self, mut provider: P) fn add_script_api_provider<T, P>(&mut self, mut provider: P)
where where
T: ScriptHost, T: ScriptHost,
P: ScriptApiProvider<ScriptContext = T::ScriptContext> + 'static P: ScriptApiProvider<ScriptContext = T::ScriptContext> + 'static
{ {
let world = &mut self.world; let world = self.world_mut();
provider.prepare_world(world); provider.prepare_world(world);
let mut providers = world.get_resource_mut::<ScriptApiProviders<T>>().unwrap(); let mut providers = world.get_resource_mut::<ScriptApiProviders<T>>();
providers.add_provider(provider); providers.add_provider(provider);
} }
} }

View File

@ -6,41 +6,44 @@ use lyra_reflect::TypeRegistry;
#[cfg(feature = "lua")] #[cfg(feature = "lua")]
use super::ReflectLuaProxy; use super::ReflectLuaProxy;
use crate::ScriptWorldPtr;
#[cfg(feature = "lua")] #[cfg(feature = "lua")]
pub struct ReflectedItem { pub struct ReflectedItem<'a> {
//pub proxy: &'a ReflectLuaProxy, //pub proxy: &'a ReflectLuaProxy,
pub comp_ptr: NonNull<u8>, pub comp_ptr: NonNull<u8>,
pub comp_val: mlua::Value, pub comp_val: elua::Value<'a>,
} }
#[cfg(feature = "lua")] #[cfg(feature = "lua")]
pub struct ReflectedRow { pub struct ReflectedRow<'a> {
pub entity: Entity, pub entity: Entity,
pub row: Vec<ReflectedItem>, pub row: Vec<ReflectedItem<'a>>,
} }
pub struct ReflectedIterator<'a> { pub struct ReflectedIterator {
pub world: &'a lyra_ecs::World, pub world: ScriptWorldPtr,
pub dyn_view: DynamicViewStateIter, pub dyn_view: DynamicViewStateIter,
pub reflected_components: Option<NonNull<TypeRegistry>> pub reflected_components: Option<NonNull<TypeRegistry>>
} }
impl<'a> ReflectedIterator<'a> { impl ReflectedIterator {
#[cfg(feature = "lua")] #[cfg(feature = "lua")]
pub fn next_lua(&mut self, lua: &mlua::Lua) -> Option<ReflectedRow> { pub fn next_lua<'a>(&mut self, lua: &'a elua::State) -> Option<ReflectedRow<'a>> {
use mlua::IntoLua; use elua::AsLua;
//let world = self.world.read(); let world = self.world.as_ref();
let n = self.dyn_view.next(&self.world); let n = self.dyn_view.next(world);
if let Some((en, row)) = n { if let Some(row) = n {
if self.reflected_components.is_none() { if self.reflected_components.is_none() {
self.reflected_components = self.world.get_resource::<TypeRegistry>() let world = self.world.as_ref();
self.reflected_components = world.try_get_resource::<TypeRegistry>()
.map(|r| NonNull::from(r.deref())); .map(|r| NonNull::from(r.deref()));
} }
let mut dynamic_row = vec![]; let mut dynamic_row = vec![];
for d in row.iter() { for d in row.row.iter() {
let id = d.info.type_id().as_rust(); let id = d.info.type_id().as_rust();
let reflected_components = let reflected_components =
unsafe { self.reflected_components.as_ref().unwrap().as_ref() }; unsafe { self.reflected_components.as_ref().unwrap().as_ref() };
@ -51,7 +54,7 @@ impl<'a> ReflectedIterator<'a> {
// TODO: properly handle this error // TODO: properly handle this error
.expect("Type does not have ReflectLuaProxy as a TypeData"); .expect("Type does not have ReflectLuaProxy as a TypeData");
let value = (proxy.fn_as_lua)(lua, d.ptr.cast()).unwrap() let value = (proxy.fn_as_lua)(lua, d.ptr.cast()).unwrap()
.into_lua(lua).unwrap(); .as_lua(lua).unwrap();
dynamic_row.push(ReflectedItem { dynamic_row.push(ReflectedItem {
comp_ptr: d.ptr, comp_ptr: d.ptr,
@ -60,7 +63,7 @@ impl<'a> ReflectedIterator<'a> {
} }
let row = ReflectedRow { let row = ReflectedRow {
entity: en, entity: row.entity,
row: dynamic_row row: dynamic_row
}; };

View File

@ -2,7 +2,7 @@ pub mod dynamic_iter;
pub use dynamic_iter::*; pub use dynamic_iter::*;
pub mod world; pub mod world;
use mlua::ObjectLike; use elua::FromLua;
pub use world::*; pub use world::*;
pub mod script; pub mod script;
@ -22,48 +22,13 @@ pub use system::*;
use std::{any::TypeId, sync::Mutex}; use std::{any::TypeId, sync::Mutex};
use lyra_ecs::World; use lyra_ecs::{
Component, ComponentInfo, World
};
use lyra_reflect::{Reflect, TypeRegistry}; use lyra_reflect::{Reflect, TypeRegistry};
use crate::ScriptBorrow; use crate::ScriptBorrow;
pub type LuaContext = Mutex<mlua::Lua>; pub type LuaContext = Mutex<elua::State>;
#[derive(Debug, thiserror::Error)]
pub enum Error {
#[error("mismatched type, expected `{expected}`, got: `{got}`")]
TypeMismatch {
expected: String,
got: String,
},
#[error("received nil value from Lua")]
Nil,
#[error("{0}")]
Mlua(#[from] mlua::Error)
}
/* impl Into<mlua::Error> for Error {
fn into(self) -> mlua::Error {
match self {
Error::Mlua(error) => error,
_ => mlua::Error::external(self)
}
}
}
*/
impl From<Error> for mlua::Error {
fn from(value: Error) -> Self {
match value {
Error::Mlua(error) => error,
_ => mlua::Error::external(value)
}
}
}
impl Error {
pub fn type_mismatch(expected: &str, got: &str) -> Self {
Self::TypeMismatch { expected: expected.into(), got: got.into() }
}
}
/// Name of a Lua function that is used to Reflect the Userdata, but without a value. /// Name of a Lua function that is used to Reflect the Userdata, but without a value.
/// ///
@ -82,7 +47,7 @@ pub const FN_NAME_INTERNAL_REFLECT: &str = "__lyra_internal_reflect";
/// ///
/// This is used for types that can be converted into components. When implementing this function, /// 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 must return a [`ScriptBorrow`] that contains the component for this userdata.
/// You can return [`mlua::Value::Nil`] if for some reason the type could not be converted /// You can return [`elua::Value::Nil`] if for some reason the type could not be converted
/// into a component. /// into a component.
/// ///
/// A good example of this is `LuaResHandle`. The resource handle is requested from the /// A good example of this is `LuaResHandle`. The resource handle is requested from the
@ -113,26 +78,32 @@ pub trait RegisterLuaType {
/// Register a type to Lua that **is not wrapped**. /// Register a type to Lua that **is not wrapped**.
fn register_lua_type<'a, T>(&mut self) fn register_lua_type<'a, T>(&mut self)
where where
T: Reflect + LuaProxy + Clone + mlua::FromLua + mlua::UserData; T: Reflect + LuaProxy + Clone + elua::FromLua<'a> + elua::Userdata;
/// Registers a type to Lua that is wrapped another type. /// Registers a type to Lua that is wrapped another type.
/// This would be used for something like `UserdataRef<T>`. /// This would be used for something like `UserdataRef<T>`.
fn register_lua_wrapper<'a, W>(&mut self) fn register_lua_wrapper<'a, W>(&mut self)
where where
W: Reflect + LuaProxy + LuaWrapper + Clone + mlua::FromLua + mlua::UserData; W: Reflect + LuaProxy + LuaWrapper + Clone + elua::FromLua<'a> + elua::Userdata;
/// Registers a type to Lua that can be converted into and from Lua types. /// Registers a type to Lua that can be converted into and from Lua types.
fn register_lua_convert<T>(&mut self) fn register_lua_convert<T>(&mut self)
where where
T: Clone + mlua::FromLua + mlua::IntoLua + LuaWrapper + 'static; T: Clone + for<'a> elua::FromLua<'a> + for<'a> elua::AsLua<'a> + LuaWrapper + 'static;
/// Registers a type to Lua that implements [`elua::TableProxy`]
fn register_lua_table_proxy<'a, T, W>(&mut self)
where
T: elua::TableProxy + 'static,
W: Component;
} }
impl RegisterLuaType for World { impl RegisterLuaType for World {
fn register_lua_type<'a, T>(&mut self) fn register_lua_type<'a, T>(&mut self)
where where
T: Reflect + LuaProxy + Clone + mlua::FromLua + mlua::UserData T: Reflect + LuaProxy + Clone + elua::FromLua<'a> + elua::Userdata
{ {
let mut registry = self.get_resource_mut::<TypeRegistry>().unwrap(); let mut registry = self.get_resource_mut::<TypeRegistry>();
let type_id = TypeId::of::<T>(); let type_id = TypeId::of::<T>();
@ -142,9 +113,9 @@ impl RegisterLuaType for World {
fn register_lua_wrapper<'a, W>(&mut self) fn register_lua_wrapper<'a, W>(&mut self)
where where
W: Reflect + LuaProxy + LuaWrapper + Clone + mlua::FromLua + mlua::UserData W: Reflect + LuaProxy + LuaWrapper + Clone + elua::FromLua<'a> + elua::Userdata
{ {
let mut registry = self.get_resource_mut::<TypeRegistry>().unwrap(); let mut registry = self.get_resource_mut::<TypeRegistry>();
let reg_type = registry.get_type_or_default(W::wrapped_type_id()); let reg_type = registry.get_type_or_default(W::wrapped_type_id());
reg_type.add_data(ReflectLuaProxy::from_lua_proxy::<W>()); reg_type.add_data(ReflectLuaProxy::from_lua_proxy::<W>());
@ -152,30 +123,62 @@ impl RegisterLuaType for World {
fn register_lua_convert<T>(&mut self) fn register_lua_convert<T>(&mut self)
where where
T: Clone + mlua::FromLua + mlua::IntoLua + LuaWrapper + 'static, T: Clone + for<'a> elua::FromLua<'a> + for<'a> elua::AsLua<'a> + LuaWrapper + 'static,
{ {
let mut registry = self.get_resource_mut::<TypeRegistry>().unwrap(); let mut registry = self.get_resource_mut::<TypeRegistry>();
let reg_type = registry.get_type_or_default(T::wrapped_type_id()); let reg_type = registry.get_type_or_default(T::wrapped_type_id());
reg_type.add_data(ReflectLuaProxy::from_as_and_from_lua::<T>()); reg_type.add_data(ReflectLuaProxy::from_as_and_from_lua::<T>());
} }
fn register_lua_table_proxy<'a, T, C>(&mut self)
where
T: elua::TableProxy + 'static,
C: Component
{
let mut registry = self.get_resource_mut::<TypeRegistry>();
let reg_type = registry.get_type_or_default(TypeId::of::<C>());
reg_type.add_data(ReflectLuaProxy::from_table_proxy::<T>());
drop(registry);
let mut lookup = self.get_resource_or_else::<LuaTableProxyLookup, _>(LuaTableProxyLookup::default);
lookup.typeid_from_name.insert(T::table_name(), TypeId::of::<C>());
let info = ComponentInfo::new::<C>();
lookup.comp_info_from_name.insert(T::table_name(), info);
}
} }
impl mlua::FromLua for ScriptBorrow { impl<'lua> elua::FromLua<'lua> for ScriptBorrow {
fn from_lua(value: mlua::Value, _: &mlua::Lua) -> mlua::Result<Self> { fn from_lua(_: &'lua elua::State, value: elua::Value<'lua>) -> elua::Result<Self> {
match value { match value {
mlua::Value::UserData(ud) => Ok(ud.borrow::<Self>()?.clone()), elua::Value::Userdata(ud) => Ok(ud.as_ref::<Self>()?.clone()),
_ => unreachable!(), _ => unreachable!(),
} }
} }
} }
impl mlua::UserData for ScriptBorrow { impl<'lua> elua::FromLuaVec<'lua> for ScriptBorrow {
fn from_lua_value_vec(state: &'lua elua::State, mut values: elua::ValueVec<'lua>) -> elua::Result<Self> {
if let Some(v) = values.pop_front() {
ScriptBorrow::from_lua(state, v)
} else {
Err(elua::Error::Nil)
}
}
}
impl elua::Userdata for ScriptBorrow {
fn name() -> String {
"ScriptBorrow".to_string()
}
fn build<'a>(_: &mut elua::UserdataBuilder<'a, Self>) { }
} }
/// Helper function used for reflecting userdata as a ScriptBorrow /// Helper function used for reflecting userdata as a ScriptBorrow
pub fn reflect_user_data(ud: &mlua::AnyUserData) -> ScriptBorrow { pub fn reflect_user_data(ud: &elua::AnyUserdata) -> ScriptBorrow {
ud.call_method::<ScriptBorrow>(FN_NAME_INTERNAL_REFLECT, ()) ud.execute_method::<_, ScriptBorrow>(FN_NAME_INTERNAL_REFLECT, ())
.expect("Type does not implement internal reflect method properly") .expect("Type does not implement internal reflect method properly")
} }

View File

@ -17,7 +17,7 @@ impl ScriptApiProvider for LyraEcsApiProvider {
world.register_lua_wrapper::<LuaSceneHandle>(); world.register_lua_wrapper::<LuaSceneHandle>();
world.register_lua_wrapper::<LuaActionHandler>(); world.register_lua_wrapper::<LuaActionHandler>();
let mut registry = world.get_resource_mut::<TypeRegistry>().unwrap(); let mut registry = world.get_resource_mut::<TypeRegistry>();
let reg_type = registry.get_type_or_default(TypeId::of::<Gltf>()); let reg_type = registry.get_type_or_default(TypeId::of::<Gltf>());
reg_type.add_data(ReflectLuaProxy::from_lua_proxy::<LuaGltfHandle>()); reg_type.add_data(ReflectLuaProxy::from_lua_proxy::<LuaGltfHandle>());
@ -39,7 +39,7 @@ impl ScriptApiProvider for LyraEcsApiProvider {
fn expose_api(&mut self, _: &ScriptData, ctx: &mut Self::ScriptContext) -> Result<(), crate::ScriptError> { fn expose_api(&mut self, _: &ScriptData, ctx: &mut Self::ScriptContext) -> Result<(), crate::ScriptError> {
let ctx = ctx.lock().unwrap(); let ctx = ctx.lock().unwrap();
let globals = ctx.globals(); let globals = ctx.globals()?;
globals.set("World", ctx.create_proxy::<ScriptWorldPtr>()?)?; globals.set("World", ctx.create_proxy::<ScriptWorldPtr>()?)?;
globals.set("DynamicBundle", ctx.create_proxy::<ScriptDynamicBundle>()?)?; globals.set("DynamicBundle", ctx.create_proxy::<ScriptDynamicBundle>()?)?;
globals.set("SceneComponent", ctx.create_proxy::<LuaSceneHandle>()?)?; globals.set("SceneComponent", ctx.create_proxy::<LuaSceneHandle>()?)?;
@ -60,7 +60,7 @@ impl ScriptApiProvider for LyraEcsApiProvider {
} }
} }
fn create_reflect_table<T: Reflect + ResourceObject + Default + 'static>(lua: &mlua::Lua) -> mlua::Result<mlua::Table> { fn create_reflect_table<T: Reflect + ResourceObject + Default + 'static>(lua: &elua::State) -> elua::Result<elua::Table> {
let table = lua.create_table()?; let table = lua.create_table()?;
table.set(FN_NAME_INTERNAL_REFLECT_TYPE, lua.create_function(|_, ()| { table.set(FN_NAME_INTERNAL_REFLECT_TYPE, lua.create_function(|_, ()| {
Ok(ScriptBorrow::from_resource::<T>(None)) Ok(ScriptBorrow::from_resource::<T>(None))

View File

@ -23,7 +23,7 @@ impl ScriptApiProvider for LyraMathApiProvider {
/* let bytes = include_bytes!("../../../scripts/lua/math/transform.lua"); /* let bytes = include_bytes!("../../../scripts/lua/math/transform.lua");
ctx.load("lyra/math/transform.lua", bytes.as_slice())?.execute(())?; */ ctx.load("lyra/math/transform.lua", bytes.as_slice())?.execute(())?; */
let globals = ctx.globals(); let globals = ctx.globals()?;
globals.set("Vec3", ctx.create_proxy::<LuaVec3>()?)?; globals.set("Vec3", ctx.create_proxy::<LuaVec3>()?)?;
globals.set("Quat", ctx.create_proxy::<LuaQuat>()?)?; globals.set("Quat", ctx.create_proxy::<LuaQuat>()?)?;
globals.set("Transform", ctx.create_proxy::<LuaTransform>()?)?; globals.set("Transform", ctx.create_proxy::<LuaTransform>()?)?;

View File

@ -1,7 +1,6 @@
use std::{ops::Deref, sync::{Arc, Mutex}}; use std::sync::{Mutex, Arc};
use mlua::{AnyUserData, ObjectLike}; use tracing::{debug_span, debug};
use tracing::{debug, debug_span};
use crate::{ScriptApiProvider, ScriptData}; use crate::{ScriptApiProvider, ScriptData};
@ -18,66 +17,46 @@ use crate::{ScriptApiProvider, ScriptData};
pub struct UtilityApiProvider; pub struct UtilityApiProvider;
impl ScriptApiProvider for UtilityApiProvider { impl ScriptApiProvider for UtilityApiProvider {
type ScriptContext = Mutex<mlua::Lua>; type ScriptContext = Mutex<elua::State>;
fn expose_api( fn expose_api(&mut self, data: &ScriptData, ctx: &mut Self::ScriptContext) -> Result<(), crate::ScriptError> {
&mut self,
data: &ScriptData,
ctx: &mut Self::ScriptContext,
) -> Result<(), crate::ScriptError> {
let ctx = ctx.lock().unwrap(); let ctx = ctx.lock().unwrap();
//fn printf(lua: &mlua::State, (mut text, formats): (String, mlua::Variadic<mlua::Value>)) -> mlua::Result<()> { //fn printf(lua: &elua::State, (mut text, formats): (String, elua::Variadic<elua::Value>)) -> elua::Result<()> {
let printf = let printf = |lua: &elua::State, (mut text, formats): (String, elua::Variadic<elua::Value>)| {
|lua: &mlua::Lua, (mut text, formats): (String, mlua::Variadic<mlua::Value>)| {
let mut formatted = String::new(); let mut formatted = String::new();
let mut arg_num = 0; let mut arg_num = 0;
while let Some(start) = text.find("{}") { while let Some(start) = text.find("{}") {
let val_str = match formats.get(arg_num) { let val_str = match formats.get(arg_num) {
Some(v) => match v { Some(v) => match v {
mlua::Value::Nil => "nil".to_string(), elua::Value::Nil => "nil".to_string(),
mlua::Value::Boolean(b) => b.to_string(), elua::Value::Boolean(b) => b.to_string(),
mlua::Value::Integer(n) => n.to_string(), elua::Value::Number(n) => n.to_string(),
mlua::Value::Number(n) => n.to_string(), elua::Value::String(s) => s.clone(),
mlua::Value::String(s) => s.to_string_lossy().to_string(), elua::Value::Table(_) => {
mlua::Value::Table(_) => { return Err(elua::Error::runtime("unable to get string representation of Table"));
return Err(mlua::Error::runtime(
"unable to get string representation of Table",
));
}, },
mlua::Value::Function(_) => { elua::Value::Function(_) => {
return Err(mlua::Error::runtime( return Err(elua::Error::runtime("unable to get string representation of Function"));
"unable to get string representation of Function",
));
}, },
mlua::Value::Thread(_) => { elua::Value::Thread(_) => {
return Err(mlua::Error::runtime( return Err(elua::Error::runtime("unable to get string representation of Thread"));
"unable to get string representation of Thread",
));
}, },
mlua::Value::UserData(ud) => { elua::Value::Userdata(ud) => {
if let Ok(tos) = if let Ok(tos) = ud.get::<_, elua::Function>(elua::MetaMethod::ToString) {
ud.get::<mlua::Function>(mlua::MetaMethod::ToString.name()) tos.exec::<_, String>(())?
{
tos.call::<String>(())?
} else { } else {
return Err(mlua::Error::runtime( return Err(elua::Error::runtime("UserData does not implement MetaMethod '__tostring'"));
"UserData does not implement MetaMethod '__tostring'",
));
} }
}, },
mlua::Value::LightUserData(_) => { elua::Value::None => "None".to_string(),
return Err(mlua::Error::runtime( elua::Value::Multi(_) => {
"unable to get string representation of LightUserData", return Err(elua::Error::runtime("unable to get string representation of ValueVec"));
));
},
mlua::Value::Error(error) => {
return Err(error.deref().clone());
}, },
}, },
None => { None => {
let got_args = arg_num; // - 1; let got_args = arg_num;// - 1;
// continue searching for {} to get the number of format spots for the error message. // continue searching for {} to get the number of format spots for the error message.
while let Some(start) = text.find("{}") { while let Some(start) = text.find("{}") {
@ -85,18 +64,17 @@ impl ScriptApiProvider for UtilityApiProvider {
arg_num += 1; arg_num += 1;
} }
return Err(mlua::Error::BadArgument { return Err(elua::Error::BadArgument {
to: Some("printf".into()), func: Some("printf".to_string()),
pos: 2, arg_index: 2,
name: Some("fmt...".into()), arg_name: Some("fmt...".to_string()),
cause: Arc::new(mlua::Error::runtime(format!( error: Arc::new(elua::Error::Runtime(format!(
"not enough args \ "not enough args \
given for the amount of format areas in the string. Expected {}, \ given for the amount of format areas in the string. Expected {}, \
got {}.", got {}.", arg_num, got_args
arg_num, got_args )))
))), })
}); },
}
}; };
formatted = format!("{}{}{}", formatted, &text[0..start], val_str); formatted = format!("{}{}{}", formatted, &text[0..start], val_str);
@ -107,33 +85,31 @@ impl ScriptApiProvider for UtilityApiProvider {
} }
if arg_num < formats.len() { if arg_num < formats.len() {
return Err(mlua::Error::BadArgument { return Err(elua::Error::BadArgument {
to: Some("printf".into()), func: Some("printf".to_string()),
pos: 2, arg_index: 2,
name: Some("fmt...".into()), arg_name: Some("fmt...".to_string()),
cause: Arc::new(mlua::Error::runtime(format!( error: Arc::new(elua::Error::Runtime(format!(
"got more args \ "got more args \
than format areas in the string. Expected {}, got {}.", than format areas in the string. Expected {}, got {}.", formats.len(), arg_num
formats.len(), )))
arg_num })
))),
});
} }
formatted = format!("{}{}", formatted, text); formatted = format!("{}{}", formatted, text);
lua.globals() lua.globals()?
.get::<mlua::Function>("print")? .get::<_, elua::Function>("print")?
.call::<()>(formatted)?; .exec::<_, ()>(formatted)?;
Ok(()) Ok(())
}; };
let script_name_reg = ctx.create_registry_value(data.name.clone())?; let script_name_reg = ctx.registry_insert(data.name.clone())?;
let printf_func = ctx.create_function(printf)?; let printf_func = ctx.create_function(printf)?;
let print_func = ctx.create_function(move |lua, text: String| { let print_func = ctx.create_function(move |lua, text: String| {
let name = lua.registry_value::<String>(&script_name_reg)?; let name = lua.registry_get::<String>(script_name_reg)?;
let _span = debug_span!("lua", script = &name).entered(); let _span = debug_span!("lua", script = &name).entered();
debug!(target: "lyra_scripting::lua", "{}", text); debug!(target: "lyra_scripting::lua", "{}", text);
@ -141,42 +117,18 @@ impl ScriptApiProvider for UtilityApiProvider {
Ok(()) Ok(())
})?; })?;
// a custom implementation of `getmetatable` is required since mlua protects __metatable, let globals = ctx.globals()?;
// making it impossible to get the metatable of userdata.
let getmetatable_func = ctx.create_function(|lua, ud: AnyUserData| {
// the userdata is left on the stack from `lua_getmetatable`, so that needs to be
// included in the returns
let (_ud, table): (mlua::AnyUserData, mlua::Table) = unsafe {
lua.exec_raw(ud, |state| {
mlua::ffi::lua_getmetatable(state, -1);
})
}?;
Ok(table)
})?;
let globals = ctx.globals();
globals.set("printf", printf_func)?; globals.set("printf", printf_func)?;
globals.set("print", print_func)?; globals.set("print", print_func)?;
globals.set("getmetatable2", getmetatable_func)?;
Ok(()) Ok(())
} }
fn setup_script( fn setup_script(&mut self, _data: &ScriptData, _ctx: &mut Self::ScriptContext) -> Result<(), crate::ScriptError> {
&mut self,
_data: &ScriptData,
_ctx: &mut Self::ScriptContext,
) -> Result<(), crate::ScriptError> {
Ok(()) Ok(())
} }
fn update_script_environment( fn update_script_environment(&mut self, _world: crate::ScriptWorldPtr, _data: &ScriptData, _ctx: &mut Self::ScriptContext) -> Result<(), crate::ScriptError> {
&mut self,
_world: crate::ScriptWorldPtr,
_data: &ScriptData,
_ctx: &mut Self::ScriptContext,
) -> Result<(), crate::ScriptError> {
Ok(()) Ok(())
} }
} }

View File

@ -1,12 +1,12 @@
use std::{any::TypeId, collections::HashMap, ptr::NonNull}; use std::{any::TypeId, collections::HashMap, ptr::NonNull};
use mlua::{ObjectLike, IntoLua}; use elua::{FromLua, TableProxy, AsLua};
use lyra_ecs::{ComponentInfo, DynamicBundle}; use lyra_ecs::{ComponentInfo, DynamicBundle};
use lyra_reflect::Reflect; use lyra_reflect::Reflect;
use crate::{ScriptBorrow, ScriptDynamicBundle}; use crate::{ScriptBorrow, ScriptDynamicBundle};
use super::{Error, FN_NAME_INTERNAL_REFLECT}; use super::FN_NAME_INTERNAL_REFLECT;
pub trait LuaWrapper { pub trait LuaWrapper {
/// The type id of the wrapped type. /// The type id of the wrapped type.
@ -15,39 +15,40 @@ pub trait LuaWrapper {
/// A trait that used to convert something into lua, or to set something to a value from lua. /// A trait that used to convert something into lua, or to set something to a value from lua.
pub trait LuaProxy { pub trait LuaProxy {
fn as_lua_value( fn as_lua_value<'lua>(
lua: &mlua::Lua, lua: &'lua elua::State,
this: &dyn Reflect, this: &dyn Reflect,
) -> mlua::Result<mlua::Value>; ) -> elua::Result<elua::Value<'lua>>;
fn apply( fn apply(
lua: &mlua::Lua, lua: &elua::State,
this: &mut dyn Reflect, this: &mut dyn Reflect,
value: &mlua::Value, value: &elua::Value,
) -> mlua::Result<()>; ) -> elua::Result<()>;
} }
impl<'a, T> LuaProxy for T impl<'a, T> LuaProxy for T
where where
T: Reflect + Clone + mlua::FromLua + mlua::UserData T: Reflect + Clone + elua::FromLua<'a> + elua::Userdata
{ {
fn as_lua_value( fn as_lua_value<'lua>(
lua: &mlua::Lua, lua: &'lua elua::State,
this: &dyn Reflect, this: &dyn Reflect,
) -> mlua::Result<mlua::Value> { ) -> elua::Result<elua::Value<'lua>> {
let this = this.as_any().downcast_ref::<T>().unwrap(); let this = this.as_any().downcast_ref::<T>().unwrap();
this.clone().into_lua(lua) lua.create_userdata(this.clone())
.and_then(|ud| ud.as_lua(lua))
} }
fn apply( fn apply(
_: &mlua::Lua, _: &elua::State,
this: &mut dyn Reflect, this: &mut dyn Reflect,
apply: &mlua::Value, apply: &elua::Value,
) -> mlua::Result<()> { ) -> elua::Result<()> {
let this = this.as_any_mut().downcast_mut::<T>().unwrap(); let this = this.as_any_mut().downcast_mut::<T>().unwrap();
let apply = apply.as_userdata() let apply = apply.as_userdata()
.expect("Somehow a non-userdata Lua Value was provided to a LuaProxy") .expect("Somehow a non-userdata Lua Value was provided to a LuaProxy")
.borrow::<T>()?; .as_ref::<T>()?;
*this = apply.clone(); *this = apply.clone();
@ -66,12 +67,12 @@ pub struct LuaTableProxyLookup {
#[derive(Clone)] #[derive(Clone)]
pub struct ReflectLuaProxy { pub struct ReflectLuaProxy {
pub fn_as_lua: pub fn_as_lua:
for<'a> fn(lua: &'a mlua::Lua, this_ptr: NonNull<()>) -> mlua::Result<mlua::Value>, for<'a> fn(lua: &'a elua::State, this_ptr: NonNull<()>) -> elua::Result<elua::Value<'a>>,
pub fn_apply: for<'a> fn( pub fn_apply: for<'a> fn(
lua: &'a mlua::Lua, lua: &'a elua::State,
this_ptr: NonNull<()>, this_ptr: NonNull<()>,
value: &'a mlua::Value, value: &'a elua::Value<'a>,
) -> mlua::Result<()>, ) -> elua::Result<()>,
} }
impl ReflectLuaProxy { impl ReflectLuaProxy {
@ -81,7 +82,7 @@ impl ReflectLuaProxy {
T: Reflect + LuaProxy T: Reflect + LuaProxy
{ {
Self { Self {
fn_as_lua: |lua, this| -> mlua::Result<mlua::Value> { fn_as_lua: |lua, this| -> elua::Result<elua::Value> {
let this = unsafe { this.cast::<T>().as_ref() }; let this = unsafe { this.cast::<T>().as_ref() };
<T as LuaProxy>::as_lua_value(lua, this) <T as LuaProxy>::as_lua_value(lua, this)
}, },
@ -92,19 +93,42 @@ impl ReflectLuaProxy {
} }
} }
/// Create from a type that implements FromLua and AsLua pub fn from_table_proxy<T>() -> Self
pub fn from_as_and_from_lua<T>() -> Self
where where
T: mlua::FromLua + mlua::IntoLua + Clone T: TableProxy
{ {
Self { Self {
fn_as_lua: |lua, this| -> mlua::Result<mlua::Value> { fn_as_lua: |lua, this| -> elua::Result<elua::Value> {
let this = unsafe { this.cast::<T>().as_ref() }; let this = unsafe { this.cast::<T>().as_ref() };
this.clone().into_lua(lua) this.as_table(lua)
.and_then(|t| t.as_lua(lua))
}, },
fn_apply: |lua, ptr, value| { fn_apply: |lua, ptr, value| {
let this = unsafe { ptr.cast::<T>().as_mut() }; let this = unsafe { ptr.cast::<T>().as_mut() };
let new_val = T::from_lua(value.clone(), lua)?; let table = value.as_table()
.expect("Somehow a non-Table Lua Value was provided to a TableProxy");
let new_val = T::from_table(lua, table.clone())?;
*this = new_val;
Ok(())
},
}
}
/// Create from a type that implements FromLua and AsLua
pub fn from_as_and_from_lua<T>() -> Self
where
T: for<'a> elua::FromLua<'a> + for<'a> elua::AsLua<'a> + Clone
{
Self {
fn_as_lua: |lua, this| -> elua::Result<elua::Value> {
let this = unsafe { this.cast::<T>().as_ref() };
this.clone().as_lua(lua)
},
fn_apply: |lua, ptr, value| {
let this = unsafe { ptr.cast::<T>().as_mut() };
let new_val = T::from_lua(lua, value.clone())?;
*this = new_val; *this = new_val;
@ -114,21 +138,36 @@ impl ReflectLuaProxy {
} }
} }
impl mlua::FromLua for ScriptDynamicBundle { impl<'lua> elua::FromLua<'lua> for ScriptDynamicBundle {
fn from_lua(val: mlua::Value, _: &mlua::Lua) -> mlua::Result<Self> { fn from_lua(_: &'lua elua::State, val: elua::Value<'lua>) -> elua::Result<Self> {
match val { match val {
mlua::Value::UserData(ud) => Ok(ud.borrow::<Self>()?.clone()), elua::Value::Userdata(ud) => Ok(ud.as_ref::<Self>()?.clone()),
mlua::Value::Nil => Err(Error::Nil.into()), elua::Value::Nil => Err(elua::Error::Nil),
_ => unreachable!(), _ => unreachable!(),
} }
} }
} }
impl mlua::UserData for ScriptDynamicBundle { impl<'lua> elua::FromLuaVec<'lua> for ScriptDynamicBundle {
fn add_methods<M: mlua::UserDataMethods<Self>>(methods: &mut M) { fn from_lua_value_vec(state: &'lua elua::State, mut values: elua::ValueVec<'lua>) -> elua::Result<Self> {
methods.add_function("new", |_, ()| Ok(ScriptDynamicBundle(DynamicBundle::new()))); if let Some(v) = values.pop_front() {
methods.add_method_mut("push", |_, this, comp: mlua::AnyUserData| { Ok(ScriptDynamicBundle::from_lua(state, v)?)
let script_brw = comp.call_method::<ScriptBorrow>(FN_NAME_INTERNAL_REFLECT, ())?; } else {
Err(elua::Error::Nil)
}
}
}
impl elua::Userdata for ScriptDynamicBundle {
fn name() -> String {
"Bundle".to_string()
}
fn build<'a>(builder: &mut elua::UserdataBuilder<'a, Self>) {
builder
.function("new", |_, ()| Ok(ScriptDynamicBundle(DynamicBundle::new())))
.method_mut("push", |_, this, comp: elua::AnyUserdata| {
let script_brw = comp.execute_method::<_, ScriptBorrow>(FN_NAME_INTERNAL_REFLECT, ())?;
let reflect = script_brw.reflect_branch.as_component_unchecked(); let reflect = script_brw.reflect_branch.as_component_unchecked();
let refl_data = script_brw.data.unwrap(); let refl_data = script_brw.data.unwrap();

View File

@ -1,32 +1,31 @@
use std::sync::Mutex; use std::sync::Mutex;
use mlua::{IntoLua, StdLib}; use elua::{AsLua, StdLibraries};
use crate::{ScriptHost, ScriptError, ScriptWorldPtr, ScriptEntity}; use crate::{ScriptHost, ScriptError, ScriptWorldPtr, ScriptEntity};
#[derive(Default)] #[derive(Default)]
pub struct LuaHost; pub struct LuaHost;
fn try_call_lua_function(lua: &mlua::Lua, fn_name: &str) -> Result<(), ScriptError> { fn try_call_lua_function(lua: &elua::State, fn_name: &str) -> Result<(), ScriptError> {
let globals = lua.globals(); let globals = lua.globals()?;
if globals.contains_key(fn_name)? { if globals.has_key(fn_name)? {
let lua_fn = globals.get::<mlua::Function>(fn_name)?; let lua_fn = globals.get::<_, elua::Function>(fn_name)?;
lua_fn.call::<()>(()) lua_fn.exec(())
.map_err(ScriptError::from)?; .map_err(ScriptError::MluaError)?;
} }
Ok(()) Ok(())
} }
impl ScriptHost for LuaHost { impl ScriptHost for LuaHost {
type ScriptContext = Mutex<mlua::Lua>; type ScriptContext = Mutex<elua::State>;
fn load_script(&mut self, script: &[u8], script_data: &crate::ScriptData, providers: &mut crate::ScriptApiProviders<Self>) -> Result<Self::ScriptContext, crate::ScriptError> { fn load_script(&mut self, script: &[u8], script_data: &crate::ScriptData, providers: &mut crate::ScriptApiProviders<Self>) -> Result<Self::ScriptContext, crate::ScriptError> {
let mut ctx = Mutex::new({ let mut ctx = Mutex::new({
// unsafe is required to allow the debug module let s = elua::State::new();
let s = unsafe { mlua::Lua::unsafe_new() }; s.expose_libraries(StdLibraries::all());
s.load_std_libs(StdLib::ALL)?;
s s
}); });
@ -36,9 +35,9 @@ impl ScriptHost for LuaHost {
} }
let lua = ctx.lock().unwrap(); let lua = ctx.lock().unwrap();
lua.load(script) lua.load(&script_data.name, script)?
.exec() .execute(())
.map_err(|e| ScriptError::LuaError(super::Error::Mlua(e)))?; .map_err(|e| ScriptError::MluaError(e))?;
drop(lua); drop(lua);
Ok(ctx) Ok(ctx)
@ -66,9 +65,9 @@ impl ScriptHost for LuaHost {
let ctx = ctx.lock().expect("Failure to get Lua ScriptContext"); let ctx = ctx.lock().expect("Failure to get Lua ScriptContext");
let globals = ctx.globals(); let globals = ctx.globals()?;
globals.set("world", world.into_lua(&ctx)?)?; globals.set("world", world.as_lua(&ctx)?)?;
globals.set("entity", ScriptEntity(script_data.entity).into_lua(&ctx)?)?; globals.set("entity", ScriptEntity(script_data.entity).as_lua(&ctx)?)?;
try_call_lua_function(&ctx, function_name)?; try_call_lua_function(&ctx, function_name)?;

View File

@ -5,7 +5,7 @@ use lyra_reflect::TypeRegistry;
use lyra_resource::ResourceManager; use lyra_resource::ResourceManager;
use tracing::{debug, debug_span, error, trace}; use tracing::{debug, debug_span, error, trace};
use crate::{GameScriptExt, ScriptApiProviders, ScriptContexts, ScriptData, ScriptError, ScriptHost, ScriptList, ScriptWorldPtrGuard}; use crate::{GameScriptExt, ScriptApiProviders, ScriptContexts, ScriptData, ScriptError, ScriptHost, ScriptList, ScriptWorldPtr};
use super::{providers::{LyraEcsApiProvider, LyraMathApiProvider, UtilityApiProvider}, LuaContext, LuaHost, LuaLoader, LuaScript}; use super::{providers::{LyraEcsApiProvider, LyraMathApiProvider, UtilityApiProvider}, LuaContext, LuaHost, LuaLoader, LuaScript};
@ -40,8 +40,7 @@ pub fn lua_scripts_create_contexts(
trace!("Finished setting up script"); trace!("Finished setting up script");
// call on_init, handle the error // call on_init, handle the error
let world_guard = unsafe { ScriptWorldPtrGuard::new(world) }; let world_ptr = ScriptWorldPtr::from_ref(&world);
let world_ptr = (*world_guard).clone();
match host.call_script( match host.call_script(
world_ptr, world_ptr,
&script_data, &script_data,
@ -51,7 +50,7 @@ pub fn lua_scripts_create_contexts(
) { ) {
Ok(()) => {} Ok(()) => {}
Err(e) => match e { Err(e) => match e {
ScriptError::LuaError(m) => { ScriptError::MluaError(m) => {
error!("Script '{}' ran into an error: {}", script.name(), m); error!("Script '{}' ran into an error: {}", script.name(), m);
} }
ScriptError::Other(_) => return Err(e.into()), ScriptError::Other(_) => return Err(e.into()),
@ -115,11 +114,10 @@ pub fn lua_scripts_reload_system(
} }
fn lua_call_script_function(world: &mut World, stage_name: &str) -> anyhow::Result<()> { fn lua_call_script_function(world: &mut World, stage_name: &str) -> anyhow::Result<()> {
let world_guard = unsafe { ScriptWorldPtrGuard::new(world) }; let world_ptr = ScriptWorldPtr::from_ref(&world);
let world_ptr = (*world_guard).clone(); let mut host = world.get_resource_mut::<LuaHost>();
let mut host = world.get_resource_mut::<LuaHost>().unwrap(); let mut contexts = world.get_resource_mut::<ScriptContexts<LuaContext>>();
let mut contexts = world.get_resource_mut::<ScriptContexts<LuaContext>>().unwrap(); let mut providers = world.get_resource_mut::<ScriptApiProviders<LuaHost>>();
let mut providers = world.get_resource_mut::<ScriptApiProviders<LuaHost>>().unwrap();
for (en, scripts) in world.view_iter::<(Entities, &ScriptList<LuaScript>)>() { for (en, scripts) in world.view_iter::<(Entities, &ScriptList<LuaScript>)>() {
for script in scripts.iter() { for script in scripts.iter() {
@ -145,7 +143,7 @@ fn lua_call_script_function(world: &mut World, stage_name: &str) -> anyhow::Resu
) { ) {
Ok(()) => {} Ok(()) => {}
Err(e) => match e { Err(e) => match e {
ScriptError::LuaError(m) => { ScriptError::MluaError(m) => {
error!("Script '{}' ran into an error: {}", script.name(), m); error!("Script '{}' ran into an error: {}", script.name(), m);
} }
ScriptError::Other(_) => return Err(e.into()), ScriptError::Other(_) => return Err(e.into()),
@ -192,8 +190,8 @@ pub fn lua_script_last_stage_system(world: &mut World) -> anyhow::Result<()> {
pub struct LuaScriptingPlugin; pub struct LuaScriptingPlugin;
impl Plugin for LuaScriptingPlugin { impl Plugin for LuaScriptingPlugin {
fn setup(&mut self, app: &mut lyra_game::game::App) { fn setup(&mut self, game: &mut lyra_game::game::Game) {
let world = &mut app.world; let world = game.world_mut();
world.add_resource_default::<TypeRegistry>(); world.add_resource_default::<TypeRegistry>();
@ -202,16 +200,16 @@ impl Plugin for LuaScriptingPlugin {
world.add_resource_default::<ScriptContexts<LuaContext>>(); world.add_resource_default::<ScriptContexts<LuaContext>>();
let loader = world let loader = world
.get_resource_mut::<ResourceManager>() .try_get_resource_mut::<ResourceManager>()
.expect("Add 'ResourceManager' to the world before trying to add this plugin"); .expect("Add 'ResourceManager' to the world before trying to add this plugin");
loader.register_loader::<LuaLoader>(); loader.register_loader::<LuaLoader>();
drop(loader); drop(loader);
app.add_script_api_provider::<LuaHost, _>(UtilityApiProvider); game.add_script_api_provider::<LuaHost, _>(UtilityApiProvider);
app.add_script_api_provider::<LuaHost, _>(LyraEcsApiProvider); game.add_script_api_provider::<LuaHost, _>(LyraEcsApiProvider);
app.add_script_api_provider::<LuaHost, _>(LyraMathApiProvider); game.add_script_api_provider::<LuaHost, _>(LyraMathApiProvider);
app.add_system_to_stage( game.add_system_to_stage(
GameStages::First, GameStages::First,
"lua_create_contexts", "lua_create_contexts",
lua_scripts_create_contexts, lua_scripts_create_contexts,

View File

@ -1,31 +1,32 @@
use std::{ops::DerefMut, ptr::NonNull, sync::Arc}; use std::{ptr::NonNull, sync::Arc};
use crate::{ScriptBorrow, ScriptEntity, ScriptWorldPtr}; use crate::{ScriptBorrow, ScriptEntity, ScriptWorldPtr};
use lyra_ecs::{ use elua::AsLua;
query::dynamic::{DynamicViewState, DynamicViewStateIter, QueryDynamicType}, use lyra_ecs::{query::dynamic::{DynamicViewState, DynamicViewStateIter, QueryDynamicType}, CommandQueue, Commands, DynamicBundle, World};
CommandQueue, Commands, DynamicBundle, World,
};
use lyra_reflect::{ReflectWorldExt, RegisteredType, TypeRegistry}; use lyra_reflect::{ReflectWorldExt, RegisteredType, TypeRegistry};
use lyra_resource::ResourceManager; use lyra_resource::ResourceManager;
use mlua::{IntoLua, ObjectLike};
use super::{ use super::{
reflect_user_data, wrappers::LuaResHandleToComponent, Error, LuaTableProxyLookup, ReflectLuaProxy, ReflectedIterator, FN_NAME_INTERNAL_AS_COMPONENT, FN_NAME_INTERNAL_REFLECT, FN_NAME_INTERNAL_REFLECT_TYPE reflect_user_data, wrappers::LuaResHandleToComponent, LuaTableProxyLookup, ReflectLuaProxy, ReflectedIterator, FN_NAME_INTERNAL_AS_COMPONENT, FN_NAME_INTERNAL_REFLECT, FN_NAME_INTERNAL_REFLECT_TYPE
}; };
impl mlua::FromLua for ScriptEntity { impl<'lua> elua::FromLua<'lua> for ScriptEntity {
fn from_lua(value: mlua::Value, _: &mlua::Lua) -> mlua::Result<Self> { fn from_lua(_: &'lua elua::State, value: elua::Value<'lua>) -> elua::Result<Self> {
match value { match value {
mlua::Value::UserData(ud) => Ok(ud.borrow::<Self>()?.clone()), elua::Value::Userdata(ud) => Ok(ud.as_ref::<Self>()?.clone()),
mlua::Value::Nil => Err(mlua::Error::external(Error::type_mismatch("ScriptEntity", "Nil"))), elua::Value::Nil => Err(elua::Error::type_mismatch("ScriptEntity", "Nil")),
_ => panic!(), _ => panic!(),
} }
} }
} }
impl mlua::UserData for ScriptEntity { impl elua::Userdata for ScriptEntity {
fn add_methods<M: mlua::UserDataMethods<Self>>(methods: &mut M) { fn name() -> String {
methods.add_meta_method(mlua::MetaMethod::ToString, |_, this, ()| { "Entity".to_string()
}
fn build<'a>(builder: &mut elua::userdata::UserdataBuilder<'a, Self>) {
builder.meta_method(elua::MetaMethod::ToString, |_, this, ()| {
Ok(format!("{:?}", this.0)) Ok(format!("{:?}", this.0))
}); });
} }
@ -37,44 +38,49 @@ pub enum WorldError {
LuaInvalidUsage(String), LuaInvalidUsage(String),
} }
impl mlua::FromLua for ScriptWorldPtr { impl<'a> elua::FromLua<'a> for ScriptWorldPtr {
fn from_lua(val: mlua::Value, _: &mlua::Lua) -> mlua::Result<Self> { fn from_lua(_: &'a elua::State, val: elua::Value<'a>) -> elua::Result<Self> {
match val { match val {
mlua::Value::UserData(ud) => Ok(ud.borrow::<Self>()?.clone()), elua::Value::Userdata(ud) => Ok(ud.as_ref::<Self>()?.clone()),
mlua::Value::Nil => Err(mlua::Error::external(Error::type_mismatch("ScriptWorldPtr", "Nil"))), elua::Value::Nil => Err(elua::Error::type_mismatch("ScriptWorldPtr", "Nil")),
_ => panic!(), _ => panic!(),
} }
} }
} }
impl mlua::UserData for ScriptWorldPtr { impl elua::Userdata for ScriptWorldPtr {
fn add_methods<M: mlua::UserDataMethods<Self>>(methods: &mut M) { fn name() -> String {
methods.add_method_mut("spawn", |_, this, vals: mlua::MultiValue| { "World".to_string()
let mut world = this.write(); }
fn build<'a>(builder: &mut elua::UserdataBuilder<'a, Self>) {
builder
.method_mut("spawn", |_, this, vals: elua::ValueVec| {
let world = this.as_mut();
let mut bundle = DynamicBundle::new(); let mut bundle = DynamicBundle::new();
//while let Some(val) = vals.pop_front() { //while let Some(val) = vals.pop_front() {
for (i, val) in vals.into_iter().enumerate() { for (i, val) in vals.into_iter().enumerate() {
let ud = val.as_userdata().ok_or(mlua::Error::BadArgument { let ud = val.as_userdata().ok_or(
to: Some("World:spawn".into()), elua::Error::bad_arg(
pos: 2 + i, // i starts at 0 Some("World:spawn"),
name: Some("components...".into()), 2 + i as i32, // i starts at 0
cause: Arc::new(mlua::Error::runtime("provided component is not userdata")), Some("components..."),
})?; Arc::new(elua::Error::runtime("provided component is not userdata")),
))?;
let comp_borrow = { let comp_borrow = {
if let Ok(as_comp) = ud.get::<mlua::Function>(FN_NAME_INTERNAL_AS_COMPONENT) if let Ok(as_comp) = ud.get::<_, elua::Function>(FN_NAME_INTERNAL_AS_COMPONENT) {
{ let ud = match as_comp.exec(ud.clone())? {
let ud = match as_comp.call(ud.clone())? { elua::Value::Userdata(ud) => ud,
mlua::Value::UserData(ud) => ud, elua::Value::Nil => ud.clone(),
mlua::Value::Nil => ud.clone(),
_ => todo!(), _ => todo!(),
}; };
ud.call_method::<ScriptBorrow>(FN_NAME_INTERNAL_REFLECT, ())? ud.execute_method::<_, ScriptBorrow>(FN_NAME_INTERNAL_REFLECT, ())?
} else { } else {
ud.call_method::<ScriptBorrow>(FN_NAME_INTERNAL_REFLECT, ())? ud.execute_method::<_, ScriptBorrow>(FN_NAME_INTERNAL_REFLECT, ())?
} }
}; };
@ -84,62 +90,61 @@ impl mlua::UserData for ScriptWorldPtr {
} }
// defer the entity spawn // defer the entity spawn
// SAFETY: Commands borrows Entities from World, the resource borrows from the world resources, // safety: Commands borrows Entities from World, the resource borrows from the world resouces,
// They are borrowing different parts of World. // they are borrowing different parts of World.
let world_ptr: *mut World = world.deref_mut(); let world_ptr: *mut World = world;
let mut commands_queue = world.get_resource_mut::<CommandQueue>().unwrap(); let mut commands_queue = world.get_resource_mut::<CommandQueue>();
let mut commands = Commands::new(&mut commands_queue, unsafe { &mut *world_ptr }); let mut commands = Commands::new(&mut commands_queue, unsafe { &mut *world_ptr });
let entity = commands.spawn(bundle); let entity = commands.spawn(bundle);
Ok(ScriptEntity(entity)) Ok(ScriptEntity(entity))
}); })
methods.add_method_mut( .method_mut(
"view", "view",
|lua, this, (system, queries): (mlua::Function, mlua::MultiValue)| { |lua, this, (system, queries): (elua::Function, elua::ValueVec)| {
if queries.is_empty() { if queries.is_empty() {
return Err(mlua::Error::BadArgument { return Err(elua::Error::BadArgument {
to: Some("World:view".into()), func: Some("World:view".to_string()),
pos: 2, arg_index: 2,
name: Some("query...".into()), arg_name: Some("query...".to_string()),
cause: Arc::new(mlua::Error::external(WorldError::LuaInvalidUsage( error: Arc::new(elua::Error::other(WorldError::LuaInvalidUsage(
"no component types provided".into(), "no component types provided".to_string(),
))), ))),
}); });
} }
let world = this.read(); let world = unsafe { this.inner.as_ref() };
//let mut view = world.dynamic_view();
let mut view = DynamicViewState::new(); let mut view = DynamicViewState::new();
for (idx, comp) in queries.into_iter().enumerate() { for (idx, comp) in queries.into_iter().enumerate() {
match comp { match comp {
mlua::Value::Table(t) => { elua::Value::Table(t) => {
let name: String = t.get(mlua::MetaMethod::Type.name())?; let name: String = t.get(elua::MetaMethod::Name)?;
let lookup = world.get_resource::<LuaTableProxyLookup>().ok_or( let lookup = world
mlua::Error::runtime( .try_get_resource::<LuaTableProxyLookup>()
.ok_or(elua::Error::runtime(
"Unable to lookup table proxy, none were ever registered!", "Unable to lookup table proxy, none were ever registered!",
), ))?;
)?; let info = lookup.comp_info_from_name.get(&name).ok_or_else(
let info = lookup.comp_info_from_name.get(&name).ok_or_else(|| { || elua::Error::BadArgument {
mlua::Error::BadArgument { func: Some("World:view".to_string()),
to: Some("World:view".into()), arg_index: 2 + idx as i32,
pos: 2 + idx, arg_name: Some("query...".to_string()),
name: Some("query...".into()), error: Arc::new(elua::Error::Runtime(format!(
cause: Arc::new(mlua::Error::external(
WorldError::LuaInvalidUsage(format!(
"the 'Table' with name {} is unknown to the engine!", "the 'Table' with name {} is unknown to the engine!",
name name
)), ))),
)), },
} )?;
})?;
let dyn_type = QueryDynamicType::from_info(info.clone()); let dyn_type = QueryDynamicType::from_info(info.clone());
view.push(dyn_type); view.push(dyn_type);
} }
mlua::Value::UserData(ud) => { elua::Value::Userdata(ud) => {
let reflect = ud let reflect = ud
.call_function::<ScriptBorrow>( .execute_function::<_, ScriptBorrow>(
FN_NAME_INTERNAL_REFLECT_TYPE, FN_NAME_INTERNAL_REFLECT_TYPE,
(), (),
) )
@ -155,49 +160,47 @@ impl mlua::UserData for ScriptWorldPtr {
let iter = view.into_iter(); let iter = view.into_iter();
let mut reflected_iter = ReflectedIterator { let mut reflected_iter = ReflectedIterator {
// SAFETY: bypassing the borrow checker here to get a pointer of the world world: this.clone(),
// is required since we mutably borrow below. Its safe to do so since
// only the entity ticks are updated. They are accessing different things
// from the world.
world: unsafe { NonNull::from(&*world).as_ref() },
dyn_view: DynamicViewStateIter::from(iter), dyn_view: DynamicViewStateIter::from(iter),
reflected_components: None, reflected_components: None,
}; };
let current = world.current_tick(); let mut current = world.current_tick();
let mut has_ticked = false;
// drop read lock and acquire the write lock.
// dropping must be done to avoid mutex deadlock
drop(world);
let mut world = this.write();
while let Some(row) = reflected_iter.next_lua(lua) { while let Some(row) = reflected_iter.next_lua(lua) {
let r = row.row.into_iter() let r = row
.row
.into_iter() .into_iter()
.map(|r| (r.comp_val, r.comp_ptr.cast::<()>())) .map(|r| (r.comp_val, r.comp_ptr.cast::<()>()))
.collect::<Vec<_>>(); .collect::<Vec<_>>();
let (values, ptrs) = let (values, ptrs) =
itertools::multiunzip::<(Vec<mlua::Value>, Vec<NonNull<()>>), _>(r); itertools::multiunzip::<(Vec<elua::Value>, Vec<NonNull<()>>), _>(r);
let mult_val = mlua::MultiValue::from_iter(values.into_iter()); let mult_val = elua::ValueVec::from(values);
let res: mlua::MultiValue = system.call(mult_val)?; let res: elua::ValueVec = system.exec(mult_val)?;
// if values were returned, find the type in the type registry, and apply the new values // if values were returned, find the type in the type registry, and apply the new values
if res.len() <= ptrs.len() { if res.len() <= ptrs.len() {
// we only want to tick one time per system
if !has_ticked {
current = world.tick();
has_ticked = true;
}
for (comp, ptr) in res.into_iter().zip(ptrs) { for (comp, ptr) in res.into_iter().zip(ptrs) {
let lua_typeid = match &comp { let lua_typeid = match &comp {
mlua::Value::UserData(ud) => { elua::Value::Userdata(ud) => {
let lua_comp = reflect_user_data(ud); let lua_comp = reflect_user_data(ud);
let refl_comp = let refl_comp =
lua_comp.reflect_branch.as_component_unchecked(); lua_comp.reflect_branch.as_component_unchecked();
refl_comp.info.type_id().as_rust() refl_comp.info.type_id().as_rust()
} },
mlua::Value::Table(tbl) => { elua::Value::Table(tbl) => {
let name: String = tbl.get(mlua::MetaMethod::Type.name())?; let name: String = tbl.get(elua::MetaMethod::Name)?;
let lookup = world.get_resource::<LuaTableProxyLookup>().unwrap(); let lookup = world.get_resource::<LuaTableProxyLookup>();
*lookup.typeid_from_name.get(&name).unwrap() *lookup.typeid_from_name.get(&name).unwrap()
} },
_ => { _ => {
panic!("A userdata or table value was not returned!"); panic!("A userdata or table value was not returned!");
// TODO: Handle properly // TODO: Handle properly
@ -205,13 +208,14 @@ impl mlua::UserData for ScriptWorldPtr {
}; };
// update the component tick // update the component tick
let world = unsafe { this.inner.as_mut() };
let arch = world.entity_archetype_mut(row.entity).unwrap(); let arch = world.entity_archetype_mut(row.entity).unwrap();
let idx = arch.entity_indexes().get(&row.entity).unwrap().clone(); let idx = arch.entity_indexes().get(&row.entity).unwrap().clone();
let c = arch.get_column_mut(lua_typeid).unwrap(); let c = arch.get_column_mut(lua_typeid).unwrap();
c.entity_ticks[idx.0 as usize] = current; c.entity_ticks[idx.0 as usize] = current;
// apply the new component data // apply the new component data
let reg = world.get_resource::<TypeRegistry>().unwrap(); let reg = this.as_ref().get_resource::<TypeRegistry>();
let reg_type = reg.get_type(lua_typeid).unwrap(); let reg_type = reg.get_type(lua_typeid).unwrap();
let proxy = reg_type let proxy = reg_type
@ -227,52 +231,55 @@ impl mlua::UserData for ScriptWorldPtr {
At most, the expected number of results is {}.", At most, the expected number of results is {}.",
ptrs.len() ptrs.len()
); );
return Err(mlua::Error::runtime(msg)); return Err(elua::Error::Runtime(msg));
} }
} }
Ok(()) Ok(())
}, },
); )
methods.add_method_mut("resource", |lua, this, (ty,): (mlua::Value,)| { .method_mut("resource", |lua, this, (ty,): (elua::Value,)| {
let reflect = match ty { let reflect = match ty {
mlua::Value::UserData(ud) => ud elua::Value::Userdata(ud) => ud
.call_function::<ScriptBorrow>(FN_NAME_INTERNAL_REFLECT_TYPE, ()) .execute_function::<_, ScriptBorrow>(FN_NAME_INTERNAL_REFLECT_TYPE, ())
.expect("Type does not implement 'reflect_type' properly"), .expect("Type does not implement 'reflect_type' properly"),
mlua::Value::Table(t) => { elua::Value::Table(t) => {
let f: mlua::Function = t.get(FN_NAME_INTERNAL_REFLECT_TYPE)?; let f: elua::Function = t.get(FN_NAME_INTERNAL_REFLECT_TYPE)?;
f.call::<ScriptBorrow>(()) f.exec::<_, ScriptBorrow>(())
.expect("Type does not implement 'reflect_type' properly") .expect("Type does not implement 'reflect_type' properly")
} }
_ => { _ => {
panic!("how"); panic!("how");
} }
}; };
/* let reflect = ty
.execute_function::<_, ScriptBorrow>(FN_NAME_INTERNAL_REFLECT_TYPE, ())
.expect("Type does not implement 'reflect_type' properly"); */
let mut world = this.write();
let res = reflect.reflect_branch.as_resource_unchecked(); let res = reflect.reflect_branch.as_resource_unchecked();
if let Some(res_ptr) = res.reflect_ptr(&mut world) { if let Some(res_ptr) = res.reflect_ptr(this.as_mut()) {
let reg_type = world let reg_type = this
.as_ref()
.get_type::<RegisteredType>(reflect.reflect_branch.reflect_type_id()) .get_type::<RegisteredType>(reflect.reflect_branch.reflect_type_id())
.expect("Resource is not type registered!"); .expect("Resource is not type registered!");
let proxy = reg_type let proxy = reg_type
.get_data::<ReflectLuaProxy>() .get_data::<ReflectLuaProxy>()
.expect("Type does not have ReflectLuaProxy as a TypeData"); .expect("Type does not have ReflectLuaProxy as a TypeData");
(proxy.fn_as_lua)(lua, res_ptr.cast()).and_then(|ud| ud.into_lua(lua)) (proxy.fn_as_lua)(lua, res_ptr.cast()).and_then(|ud| ud.as_lua(lua))
} else { } else {
// if the resource is not found in the world, return nil // if the resource is not found in the world, return nil
Ok(mlua::Value::Nil) Ok(elua::Value::Nil)
} }
}); })
methods.add_method_mut("add_resource", |_, this, res: mlua::Value| { .method_mut("add_resource", |_, this, res: elua::Value| {
let reflect = match res { let reflect = match res {
mlua::Value::UserData(ud) => ud elua::Value::Userdata(ud) => ud
.call_method::<ScriptBorrow>(FN_NAME_INTERNAL_REFLECT, ()) .execute_method::<_, ScriptBorrow>(FN_NAME_INTERNAL_REFLECT, ())
.expect("Type does not implement 'reflect_type' properly"), .expect("Type does not implement 'reflect_type' properly"),
mlua::Value::Table(t) => { elua::Value::Table(t) => {
let f: mlua::Function = t.get(FN_NAME_INTERNAL_REFLECT)?; let f: elua::Function = t.get(FN_NAME_INTERNAL_REFLECT)?;
f.call::<ScriptBorrow>(()) f.exec::<_, ScriptBorrow>(())
.expect("Type does not implement 'reflect_type' properly") .expect("Type does not implement 'reflect_type' properly")
} }
_ => { _ => {
@ -280,32 +287,27 @@ impl mlua::UserData for ScriptWorldPtr {
} }
}; };
let data = reflect.data.expect( let data = reflect.data
"Its expected that 'FN_NAME_INTERNAL_REFLECT' returns data in World:add_resource", .expect("Its expected that 'FN_NAME_INTERNAL_REFLECT' returns data in World:add_resource");
);
let res = reflect let res = reflect.reflect_branch.as_resource()
.reflect_branch .ok_or(elua::Error::runtime("Provided type is not a resource!"))?;
.as_resource()
.ok_or(mlua::Error::runtime("Provided type is not a resource!"))?;
let mut world = this.write(); let world = this.as_mut();
res.insert(&mut world, data); res.insert(world, data);
Ok(()) Ok(())
}); })
methods.add_method_mut("request_res", |lua, this, path: String| { .method_mut("request_res", |lua, this, path: String| {
let world = this.write(); let world: &mut World = this.as_mut();
let man = world.get_resource_mut::<ResourceManager>().unwrap(); let man = world.get_resource_mut::<ResourceManager>();
let handle = man.request_raw(&path).unwrap(); let handle = man.request_raw(&path).unwrap();
// get the actual resource handle wrapper // get the actual resource handle wrapper
let registry = world.get_resource::<TypeRegistry>().unwrap(); let registry = world.get_resource::<TypeRegistry>();
let ty = registry let ty = registry.get_type(handle.resource_type_id())
.get_type(handle.resource_type_id())
.expect("Could not find asset type in registry"); .expect("Could not find asset type in registry");
let data = ty let data = ty.get_data::<LuaResHandleToComponent>()
.get_data::<LuaResHandleToComponent>()
.expect("Asset type does not have 'LuaResHandleToComponent' as TypeData"); .expect("Asset type does not have 'LuaResHandleToComponent' as TypeData");
Ok((data.fn_to_lua)(lua, handle).unwrap()) Ok((data.fn_to_lua)(lua, handle).unwrap())

View File

@ -1,23 +1,21 @@
use std::{any::TypeId, ops::Deref}; use std::{any::TypeId, ops::Deref};
//use mlua::{AnyUserData, IntoLua, FromLua, Lua, Value}; use elua::{AnyUserdata, AsLua, FromLua, State, Value};
use lyra_resource::{gltf::{Gltf, Material, Mesh}, Texture, ResHandle, UntypedResHandle}; use lyra_resource::{gltf::{Gltf, Material, Mesh}, Texture, ResHandle, UntypedResHandle};
use lyra_game::scene::SceneGraph; use lyra_game::scene::SceneGraph;
use lyra_reflect::{Reflect, TypeData}; use lyra_reflect::{Reflect, TypeData};
use lyra_scripting_derive::{lua_wrap_handle, wrap_lua_struct}; use lyra_scripting_derive::{lua_wrap_handle, wrap_lua_struct};
use crate::{lua::{Error, LuaWrapper, FN_NAME_INTERNAL_AS_COMPONENT, FN_NAME_INTERNAL_REFLECT, FN_NAME_INTERNAL_REFLECT_TYPE}, lyra_engine, ScriptBorrow}; use crate::{lua::{LuaWrapper, FN_NAME_INTERNAL_AS_COMPONENT, FN_NAME_INTERNAL_REFLECT, FN_NAME_INTERNAL_REFLECT_TYPE}, lyra_engine, ScriptBorrow};
use crate as lyra_scripting; use crate as lyra_scripting;
use mlua::IntoLua;
pub struct LuaResHandleToComponent { pub struct LuaResHandleToComponent {
/// Create the userdata component that /// Create the userdata component that
pub fn_to_lua: fn(&mlua::Lua, UntypedResHandle) -> Option<mlua::AnyUserData>, pub fn_to_lua: fn(&State, UntypedResHandle) -> Option<AnyUserdata>,
} }
impl LuaResHandleToComponent { impl LuaResHandleToComponent {
pub fn new(f: fn(&mlua::Lua, UntypedResHandle) -> Option<mlua::AnyUserData>) -> Self { pub fn new(f: fn(&State, UntypedResHandle) -> Option<AnyUserdata>) -> Self {
Self { Self {
fn_to_lua: f fn_to_lua: f
} }
@ -55,12 +53,16 @@ impl From<UntypedResHandle> for LuaResHandle {
} }
} }
impl mlua::UserData for LuaResHandle { impl elua::Userdata for LuaResHandle {
fn add_fields<F: mlua::UserDataFields<Self>>(fields: &mut F) { fn name() -> String {
fields.add_field_method_get("path", |_, this| Ok(this.path())); "Handle".to_string()
fields.add_field_method_get("version", |_, this| Ok(this.version())); }
fields.add_field_method_get("uuid", |_, this| Ok(this.uuid().to_string()));
fields.add_field_method_get("state", |_, this| { fn build<'a>(builder: &mut elua::UserdataBuilder<'a, Self>) {
builder.field_getter("path", |_, this| Ok(this.path()));
builder.field_getter("version", |_, this| Ok(this.version()));
builder.field_getter("uuid", |_, this| Ok(this.uuid().to_string()));
builder.field_getter("state", |_, this| {
let name = if this.is_loaded() { let name = if this.is_loaded() {
"ready" "ready"
} else if this.get_error().is_some() { } else if this.get_error().is_some() {
@ -69,43 +71,41 @@ impl mlua::UserData for LuaResHandle {
Ok(name) Ok(name)
}); });
}
fn add_methods<M: mlua::UserDataMethods<Self>>(methods: &mut M) { builder.method("is_watched", |_, this, ()| {
methods.add_method("is_watched", |_, this, ()| {
Ok(this.is_watched()) Ok(this.is_watched())
}); });
methods.add_method("is_loaded", |_, this, ()| { builder.method("is_loaded", |_, this, ()| {
Ok(this.is_loaded()) Ok(this.is_loaded())
}); });
methods.add_method("wait_until_loaded", |_, this, ()| { builder.method("wait_until_loaded", |_, this, ()| {
this.wait_recurse_dependencies_load(); this.wait_recurse_dependencies_load();
Ok(()) Ok(())
}); });
methods.add_method(FN_NAME_INTERNAL_AS_COMPONENT, |lua, this, ()| { builder.method(FN_NAME_INTERNAL_AS_COMPONENT, |lua, this, ()| {
let handle = &this.0; let handle = &this.0;
if let Some(handle) = handle.as_typed::<SceneGraph>() { if let Some(handle) = handle.as_typed::<SceneGraph>() {
LuaSceneHandle(handle).into_lua(lua) LuaSceneHandle(handle).as_lua(lua)
} else if let Some(handle) = handle.as_typed::<Gltf>() { } else if let Some(handle) = handle.as_typed::<Gltf>() {
LuaGltfHandle(handle).into_lua(lua) LuaGltfHandle(handle).as_lua(lua)
} else { } else {
Ok(mlua::Value::Nil) Ok(elua::Value::Nil)
} }
}); });
} }
} }
impl mlua::FromLua for LuaResHandle { impl<'a> FromLua<'a> for LuaResHandle {
fn from_lua(val: mlua::Value, _: &mlua::Lua) -> mlua::Result<Self> { fn from_lua(_: &'a elua::State, val: elua::Value<'a>) -> elua::Result<Self> {
let tyname = val.type_name(); let tyname = val.type_name();
let ud = val.as_userdata() let ud = val.as_userdata()
.ok_or(mlua::Error::external(Error::type_mismatch("Handle", &tyname)))?; .ok_or(elua::Error::type_mismatch("Handle", &tyname))?;
let handle = ud.borrow::<LuaResHandle>()?; let handle = ud.as_ref::<LuaResHandle>()?;
Ok(handle.clone()) Ok(handle.clone())
} }
@ -121,11 +121,11 @@ lua_wrap_handle!(Mesh,
(material, { (material, {
data.material.clone() data.material.clone()
.map(|v| LuaMaterialHandle(v.clone())) .map(|v| LuaMaterialHandle(v.clone()))
.into_lua(lua) .as_lua(lua)
}) })
}, },
{ {
methods.add_method("indices", |lua, this, ()| { builder.method("indices", |lua, this, ()| {
if let Some(data) = this.0.data_ref() { if let Some(data) = this.0.data_ref() {
let table = lua.create_table()?; let table = lua.create_table()?;
@ -133,21 +133,21 @@ lua_wrap_handle!(Mesh,
Some(lyra_resource::gltf::MeshIndices::U16(v)) => { Some(lyra_resource::gltf::MeshIndices::U16(v)) => {
for (i, ind) in v.iter().enumerate() { for (i, ind) in v.iter().enumerate() {
let i = i as i64 + 1; // lua indexes start at 1 let i = i as i64 + 1; // lua indexes start at 1
table.raw_set(i, *ind)?; table.raw_seti(i, *ind)?;
} }
}, },
Some(lyra_resource::gltf::MeshIndices::U32(v)) => { Some(lyra_resource::gltf::MeshIndices::U32(v)) => {
for (i, ind) in v.iter().enumerate() { for (i, ind) in v.iter().enumerate() {
let i = i as i64 + 1; // lua indexes start at 1 let i = i as i64 + 1; // lua indexes start at 1
table.raw_set(i, *ind)?; table.raw_seti(i, *ind)?;
} }
}, },
None => {}, None => {},
} }
Ok(mlua::Value::Table(table)) Ok(Value::Table(table))
} else { } else {
Ok(mlua::Value::Nil) Ok(Value::Nil)
} }
}); });
@ -167,17 +167,17 @@ lua_wrap_handle!(Material,
(base_color_texture, { (base_color_texture, {
data.base_color_texture.clone() data.base_color_texture.clone()
.map(|v| LuaTextureHandle(v.clone())) .map(|v| LuaTextureHandle(v.clone()))
.into_lua(lua) .as_lua(lua)
}), }),
(metallic_roughness_texture, { (metallic_roughness_texture, {
data.metallic_roughness_texture.clone() data.metallic_roughness_texture.clone()
.map(|v| LuaTextureHandle(v.clone())) .map(|v| LuaTextureHandle(v.clone()))
.into_lua(lua) .as_lua(lua)
}), }),
(pbr_glossiness, { (pbr_glossiness, {
data.pbr_glossiness.clone() data.pbr_glossiness.clone()
.map(|v| LuaPbrGlossiness(v.clone())) .map(|v| LuaPbrGlossiness(v.clone()))
.into_lua(lua) .as_lua(lua)
}), }),
alpha_cutoff, alpha_cutoff,
(alpha_mode, { (alpha_mode, {
@ -186,57 +186,55 @@ lua_wrap_handle!(Material,
lyra_resource::gltf::AlphaMode::Opaque => "opaque", lyra_resource::gltf::AlphaMode::Opaque => "opaque",
lyra_resource::gltf::AlphaMode::Mask => "mask", lyra_resource::gltf::AlphaMode::Mask => "mask",
lyra_resource::gltf::AlphaMode::Blend => "blend", lyra_resource::gltf::AlphaMode::Blend => "blend",
}.into_lua(lua) }.as_lua(lua)
}), }),
(specular, { (specular, {
data.specular.clone() data.specular.clone()
.map(|v| LuaSpecular(v.clone())) .map(|v| LuaSpecular(v.clone()))
.into_lua(lua) .as_lua(lua)
}), }),
} }
); );
lua_wrap_handle!(Gltf, { lua_wrap_handle!(Gltf, {
methods.add_method("scenes", |lua, this, ()| { builder.method("scenes", |lua, this, ()| {
if let Some(data) = this.0.data_ref() { if let Some(data) = this.0.data_ref() {
let table = lua.create_table()?; let table = lua.create_table()?;
for (i, scene) in data.scenes.iter().enumerate() { for (i, scene) in data.scenes.iter().enumerate() {
let i = i as i64 + 1; // lua indexes start at 1 let i = i as i64 + 1; // lua indexes start at 1
table.raw_set(i, LuaSceneHandle(scene.clone()))?; table.raw_seti(i, LuaSceneHandle(scene.clone()))?;
} }
Ok(mlua::Value::Table(table)) Ok(Value::Table(table))
} else { } else {
Ok(mlua::Value::Nil) Ok(Value::Nil)
} }
}); }).method("materials", |lua, this, ()| {
methods.add_method("materials", |lua, this, ()| {
if let Some(data) = this.0.data_ref() { if let Some(data) = this.0.data_ref() {
let table = lua.create_table()?; let table = lua.create_table()?;
for (i, mat) in data.materials.iter().enumerate() { for (i, mat) in data.materials.iter().enumerate() {
let i = i as i64 + 1; // lua indexes start at 1 let i = i as i64 + 1; // lua indexes start at 1
table.raw_set(i, LuaMaterialHandle(mat.clone()))?; table.raw_seti(i, LuaMaterialHandle(mat.clone()))?;
} }
Ok(mlua::Value::Table(table)) Ok(Value::Table(table))
} else { } else {
Ok(mlua::Value::Nil) Ok(Value::Nil)
} }
}); }).method("meshes", |lua, this, ()| {
methods.add_method("meshes", |lua, this, ()| {
if let Some(data) = this.0.data_ref() { if let Some(data) = this.0.data_ref() {
let table = lua.create_table()?; let table = lua.create_table()?;
for (i, mesh) in data.meshes.iter().enumerate() { for (i, mesh) in data.meshes.iter().enumerate() {
let i = i as i64 + 1; // lua indexes start at 1 let i = i as i64 + 1; // lua indexes start at 1
table.raw_set(i, LuaMeshHandle(mesh.clone()))?; table.raw_seti(i, LuaMeshHandle(mesh.clone()))?;
} }
Ok(mlua::Value::Table(table)) Ok(Value::Table(table))
} else { } else {
Ok(mlua::Value::Nil) Ok(Value::Nil)
} }
}); });
}); });

View File

@ -21,15 +21,15 @@ impl std::ops::DerefMut for LuaDeltaTime {
} }
} }
impl mlua::FromLua for LuaDeltaTime { impl<'lua> elua::FromLua<'lua> for LuaDeltaTime {
fn from_lua(_: mlua::Value, _: &mlua::Lua) -> mlua::Result<Self> { fn from_lua(_: &'lua elua::State, _: elua::Value<'lua>) -> elua::Result<Self> {
todo!() todo!()
} }
} }
impl mlua::IntoLua for LuaDeltaTime { impl<'lua> elua::AsLua<'lua> for LuaDeltaTime {
fn into_lua(self, _: &mlua::Lua) -> mlua::Result<mlua::Value> { fn as_lua(self, _: &'lua elua::State) -> elua::Result<elua::Value<'lua>> {
Ok(mlua::Value::Number(*self.0 as f64)) Ok(elua::Value::Number(*self.0 as f64))
} }
} }

View File

@ -1,6 +1,5 @@
use lyra_game::input::{keycode_from_str, Action, ActionHandler, ActionKind, ActionMapping, ActionMappingId, ActionSource, ActionState, LayoutId, MouseAxis, MouseInput}; use lyra_game::input::{keycode_from_str, Action, ActionHandler, ActionKind, ActionMapping, ActionMappingId, ActionSource, ActionState, LayoutId, MouseAxis, MouseInput};
use mlua::IntoLua; use crate::lyra_engine;
use crate::{lua::Error, lyra_engine};
use lyra_reflect::Reflect; use lyra_reflect::Reflect;
@ -11,23 +10,27 @@ pub struct LuaActionHandler {
handler: ActionHandler handler: ActionHandler
} }
impl mlua::UserData for LuaActionHandler { impl elua::Userdata for LuaActionHandler {
fn add_methods<M: mlua::UserDataMethods<Self>>(methods: &mut M) { fn name() -> String {
methods.add_function("new", |_, table: mlua::Table| { "ActionHandler".to_string()
}
fn build<'a>(builder: &mut elua::UserdataBuilder<'a, Self>) {
builder.function("new", |_, table: elua::Table| {
let mut handler = ActionHandler::new(); let mut handler = ActionHandler::new();
// create the layouts and add them to the handler // create the layouts and add them to the handler
let layouts = table.get::<mlua::Table>("layouts") let layouts = table.get::<_, elua::Table>("layouts")
.map_err(|_| mlua::Error::runtime("missing 'layouts' in ActionHandler table"))?; .map_err(|_| elua::Error::runtime("missing 'layouts' in ActionHandler table"))?;
for layout_id in layouts.sequence_values::<u32>() { for layout_id in layouts.sequence_iter::<u32>() {
let layout_id = layout_id?; let layout_id = layout_id?;
handler.add_layout(LayoutId(layout_id)); handler.add_layout(LayoutId(layout_id));
} }
// add the actions to the handler // add the actions to the handler
let actions = table.get::<mlua::Table>("actions") let actions = table.get::<_, elua::Table>("actions")
.map_err(|_| mlua::Error::runtime("missing 'actions' in ActionHandler table"))?; .map_err(|_| elua::Error::runtime("missing 'actions' in ActionHandler table"))?;
for pair in actions.pairs::<String, String>() { for pair in actions.pairs::<String, String>() {
let (action_lbl, action_type) = pair?; let (action_lbl, action_type) = pair?;
let action_type = action_type.to_lowercase(); let action_type = action_type.to_lowercase();
@ -42,26 +45,26 @@ impl mlua::UserData for LuaActionHandler {
} }
// find the mappings and start processing them // find the mappings and start processing them
let mappings= table.get::<mlua::Table>("mappings") let mappings= table.get::<_, elua::Table>("mappings")
.map_err(|_| mlua::Error::runtime("missing 'mappings' in ActionHandler table"))?; .map_err(|_| elua::Error::runtime("missing 'mappings' in ActionHandler table"))?;
for (map_id, tbl) in mappings.sequence_values::<mlua::Table>().enumerate() { for (map_id, tbl) in mappings.sequence_iter::<elua::Table>().enumerate() {
let tbl = tbl?; let tbl = tbl?;
let layout_id = tbl.get::<u32>("layout")?; let layout_id = tbl.get::<_, u32>("layout")?;
let mut mapping = ActionMapping::new(LayoutId(layout_id), ActionMappingId(map_id as u32)); let mut mapping = ActionMapping::new(LayoutId(layout_id), ActionMappingId(map_id as u32));
// find the binds and start processing them // find the binds and start processing them
// the keys are used as the action names, and then the value is an array (lua table) // the keys are used as the action names, and then the value is an array (lua table)
let binds_tbl = tbl.get::<mlua::Table>("binds") let binds_tbl = tbl.get::<_, elua::Table>("binds")
.map_err(|_| mlua::Error::runtime("missing 'binds' in ActionHandler 'mappings' table"))?; .map_err(|_| elua::Error::runtime("missing 'binds' in ActionHandler 'mappings' table"))?;
for pair in binds_tbl.pairs::<String, mlua::Table>() { for pair in binds_tbl.pairs::<String, elua::Table>() {
let (action_lbl, input_binds) = pair?; let (action_lbl, input_binds) = pair?;
for input in input_binds.sequence_values::<String>() { for input in input_binds.sequence_iter::<String>() {
let input = input?.to_lowercase(); let input = input?.to_lowercase();
let action = handler.action(&action_lbl) let action = handler.action(&action_lbl)
.ok_or(mlua::Error::runtime(format!("Unknown action specified in mapping binds: {}", action_lbl)))?; .ok_or(elua::Error::Runtime(format!("Unknown action specified in mapping binds: {}", action_lbl)))?;
let mut binds = Vec::new(); let mut binds = Vec::new();
@ -74,18 +77,18 @@ impl mlua::UserData for LuaActionHandler {
let axis_name = input_split[2]; let axis_name = input_split[2];
let src = process_axis_string(input_name, axis_name) let src = process_axis_string(input_name, axis_name)
.ok_or(mlua::Error::runtime(format!("invalid bind '{input_name}', unable to find device or axis for device")))?; .ok_or(elua::Error::Runtime(format!("invalid bind '{input_name}', unable to find device or axis for device")))?;
binds.push(src.into_binding()); binds.push(src.into_binding());
} else { } else {
// splits 'down=1' into 'down' and '1' // splits 'down=1' into 'down' and '1'
let (button, val_str) = button.split_once("=") let (button, val_str) = button.split_once("=")
.ok_or(mlua::Error::runtime(format!("invalid bind string for Axis Action: '{input}' (expected '=' with float)")))?; .ok_or(elua::Error::Runtime(format!("invalid bind string for Axis Action: '{input}' (expected '=' with float)")))?;
let val = val_str.parse::<f32>() let val = val_str.parse::<f32>()
.map_err(|e| mlua::Error::runtime(format!("invalid bind string for Axis Action: '{input}' ({e})")))?; .map_err(|e| elua::Error::Runtime(format!("invalid bind string for Axis Action: '{input}' ({e})")))?;
let src = process_keyboard_string(button) let src = process_keyboard_string(button)
.ok_or(mlua::Error::runtime(format!("invalid key in bind: '{button}'")))?; .ok_or(elua::Error::Runtime(format!("invalid key in bind: '{button}'")))?;
binds.push(src.into_binding_modifier(val)); binds.push(src.into_binding_modifier(val));
} }
} else { } else {
@ -102,29 +105,23 @@ impl mlua::UserData for LuaActionHandler {
Ok(LuaActionHandler { Ok(LuaActionHandler {
handler, handler,
}) })
}); })
.method("get_axis", |_, this, action: String| {
methods.add_method("get_axis", |_, this, action: String| {
Ok(this.handler.get_axis_modifier(action)) Ok(this.handler.get_axis_modifier(action))
}); })
.method("is_pressed", |_, this, action: String| {
methods.add_method("is_pressed", |_, this, action: String| {
Ok(this.handler.is_action_pressed(action)) Ok(this.handler.is_action_pressed(action))
}); })
.method("was_just_pressed", |_, this, action: String| {
methods.add_method("was_just_pressed", |_, this, action: String| {
Ok(this.handler.was_action_just_pressed(action)) Ok(this.handler.was_action_just_pressed(action))
}); })
.method("was_just_released", |_, this, action: String| {
methods.add_method("was_just_released", |_, this, action: String| {
Ok(this.handler.was_action_just_released(action)) Ok(this.handler.was_action_just_released(action))
}); })
.method("get_just_pressed", |_, this, action: String| {
methods.add_method("get_just_pressed", |_, this, action: String| {
Ok(this.handler.get_just_pressed_modifier(action)) Ok(this.handler.get_just_pressed_modifier(action))
}); })
.method("get_action_state", |lua, this, action: String| {
methods.add_method("get_action_state", |lua, this, action: String| {
let state = this.handler.get_action_state(action); let state = this.handler.get_action_state(action);
let (name, val) = match state { let (name, val) = match state {
@ -136,29 +133,28 @@ impl mlua::UserData for LuaActionHandler {
ActionState::Other(v) => ("Other", Some(v)), ActionState::Other(v) => ("Other", Some(v)),
}; };
let mut multi = Vec::new(); let mut multi = elua::ValueVec::new();
multi.push(name.into_lua(lua)?); multi.push_val(lua, name)?;
multi.push(val.into_lua(lua)?); multi.push_val(lua, val)?;
Ok(mlua::MultiValue::from_iter(multi.into_iter())) Ok(elua::Value::Multi(multi))
}); })
.method(FN_NAME_INTERNAL_REFLECT, |_, this, ()| {
methods.add_method(FN_NAME_INTERNAL_REFLECT, |_, this, ()| {
Ok(ScriptBorrow::from_resource::<ActionHandler>(Some(this.handler.clone()))) Ok(ScriptBorrow::from_resource::<ActionHandler>(Some(this.handler.clone())))
}); })
.function(FN_NAME_INTERNAL_REFLECT_TYPE, |_, ()| {
methods.add_function(FN_NAME_INTERNAL_REFLECT_TYPE, |_, ()| {
Ok(ScriptBorrow::from_resource::<ActionHandler>(None)) Ok(ScriptBorrow::from_resource::<ActionHandler>(None))
}); });
} }
} }
impl mlua::FromLua for LuaActionHandler { impl<'a> elua::FromLua<'a> for LuaActionHandler {
fn from_lua(val: mlua::Value, _: &mlua::Lua) -> mlua::Result<Self> { fn from_lua(_: &'a elua::State, val: elua::Value<'a>) -> elua::Result<Self> {
let tyname = val.type_name(); let tyname = val.type_name();
let ud = val.as_userdata() let ud = val.as_userdata()
.ok_or(mlua::Error::external(Error::type_mismatch("ActionHandler", &tyname)))?; .ok_or(elua::Error::type_mismatch("ActionHandler", &tyname))?;
let handle = ud.borrow::<LuaActionHandler>()?; let handle = ud.as_ref::<LuaActionHandler>()?;
Ok(handle.clone()) Ok(handle.clone())
} }

View File

@ -1,7 +1,6 @@
use lyra_scripting_derive::{lua_vec_wrap_extension, wrap_lua_struct};
use crate::lyra_engine; use crate::lyra_engine;
use lyra_game::math; use lyra_game::math;
use lyra_scripting_derive::{lua_vec_wrap_extension, wrap_lua_struct};
use mlua::FromLuaMulti;
use crate as lyra_scripting; use crate as lyra_scripting;
@ -21,15 +20,13 @@ wrap_lua_struct!(
{ {
lua_vec_wrap_extension!(math::Vec2, LuaVec2); lua_vec_wrap_extension!(math::Vec2, LuaVec2);
methods.add_method_mut("move_by", |lua, this, vals: mlua::MultiValue| { builder.method_mut("move_by", |lua, this, vals: elua::ValueVec| {
let vals_clone = vals.clone(); let vals_clone = vals.clone();
if let Ok((x, y)) = <(f32, f32) as FromLuaMulti>::from_lua_multi(vals, lua) { if let Some((x, y)) = vals.try_into_vals::<(f32, f32)>(lua)? {
this.x += x; this.x += x;
this.y += y; this.y += y;
} else if let Ok(v) = Self::from_lua_multi(vals_clone, lua) { } else if let Some(v) = vals_clone.try_into_vals::<Self>(lua)? {
this.0 += v.0; this.0 += v.0;
} else {
todo!("handle invalid argument error");
} }
Ok(()) Ok(())
@ -53,16 +50,14 @@ wrap_lua_struct!(
{ {
lua_vec_wrap_extension!(math::Vec3, LuaVec3); lua_vec_wrap_extension!(math::Vec3, LuaVec3);
methods.add_method_mut("move_by", |lua, this, vals: mlua::MultiValue| { builder.method_mut("move_by", |lua, this, vals: elua::ValueVec| {
let vals_clone = vals.clone(); let vals_clone = vals.clone();
if let Ok((x, y, z)) = <(f32, f32, f32) as FromLuaMulti>::from_lua_multi(vals, lua) { if let Some((x, y, z)) = vals.try_into_vals::<(f32, f32, f32)>(lua)? {
this.x += x; this.x += x;
this.y += y; this.y += y;
this.z += z; this.z += z;
} else if let Ok(v) = Self::from_lua_multi(vals_clone, lua) { } else if let Some(v) = vals_clone.try_into_vals::<Self>(lua)? {
this.0 += v.0; this.0 += v.0;
} else {
todo!("handle invalid argument error");
} }
Ok(()) Ok(())
@ -103,70 +98,70 @@ wrap_lua_struct!(
), ),
{ {
// manually implemented since Quat doesn't have a `new` function // manually implemented since Quat doesn't have a `new` function
methods.add_function("new", |_, (x, y, z, w)| { builder.function("new", |_, (x, y, z, w)| {
Ok(Self(math::Quat::from_xyzw(x, y, z, w))) Ok(Self(math::Quat::from_xyzw(x, y, z, w)))
}); });
methods.add_function("from_rotation_x", |_, (rad,)| { builder.function("from_rotation_x", |_, (rad,)| {
let q = math::Quat::from_rotation_x(rad); let q = math::Quat::from_rotation_x(rad);
Ok(Self(q)) Ok(Self(q))
}); });
methods.add_function("from_rotation_y", |_, (rad,)| { builder.function("from_rotation_y", |_, (rad,)| {
let q = math::Quat::from_rotation_y(rad); let q = math::Quat::from_rotation_y(rad);
Ok(Self(q)) Ok(Self(q))
}); });
methods.add_function("from_rotation_z", |_, (rad,)| { builder.function("from_rotation_z", |_, (rad,)| {
let q = math::Quat::from_rotation_z(rad); let q = math::Quat::from_rotation_z(rad);
Ok(Self(q)) Ok(Self(q))
}); });
methods.add_method("dot", |_, this, (rhs,): (Self,)| { builder.method("dot", |_, this, (rhs,): (Self,)| {
Ok(this.dot(rhs.0)) Ok(this.dot(rhs.0))
}); });
methods.add_method("length", |_, this, ()| { builder.method("length", |_, this, ()| {
Ok(this.length()) Ok(this.length())
}); });
methods.add_method("length_squared", |_, this, ()| { builder.method("length_squared", |_, this, ()| {
Ok(this.length_squared()) Ok(this.length_squared())
}); });
methods.add_method_mut("normalize", |_, this, ()| { builder.method_mut("normalize", |_, this, ()| {
this.0 = this.normalize(); this.0 = this.normalize();
Ok(()) Ok(())
}); });
methods.add_method_mut("mult_quat", |_, this, (rhs,): (Self,)| { builder.method_mut("mult_quat", |_, this, (rhs,): (Self,)| {
this.0 *= rhs.0; this.0 *= rhs.0;
Ok(()) Ok(())
}); });
methods.add_method("mult_vec3", |_, this, (rhs,): (LuaVec3,)| { builder.method("mult_vec3", |_, this, (rhs,): (LuaVec3,)| {
Ok(LuaVec3(this.0 * rhs.0)) Ok(LuaVec3(this.0 * rhs.0))
}); });
// manually implemented here since multiplying may not return `Self`. // manually implemented here since multiplying may not return `Self`.
methods.add_meta_method(mlua::MetaMethod::Mul, |lua, this, (val,): (mlua::Value,)| { builder.meta_method(elua::MetaMethod::Mul, |lua, this, (val,): (elua::Value,)| {
use mlua::IntoLua; use elua::AsLua;
match val { match val {
mlua::Value::UserData(ud) => { elua::Value::Userdata(ud) => {
if ud.is::<LuaVec3>() { if ud.is::<LuaVec3>()? {
let v3 = ud.borrow::<LuaVec3>()?; let v3 = ud.as_ref::<LuaVec3>()?;
LuaVec3(this.0 * v3.0) LuaVec3(this.0 * v3.0)
.into_lua(lua) .as_lua(lua)
} else { } else {
let quat = ud.borrow::<LuaQuat>()?; let quat = ud.as_ref::<LuaQuat>()?;
LuaQuat(this.0 * quat.0) LuaQuat(this.0 * quat.0)
.into_lua(lua) .as_lua(lua)
} }
}, },
mlua::Value::Number(n) => { elua::Value::Number(n) => {
LuaQuat(this.0 * (n as f32)) LuaQuat(this.0 * (n as f32))
.into_lua(lua) .as_lua(lua)
}, },
_ => { _ => {
todo!() todo!()
@ -174,7 +169,7 @@ wrap_lua_struct!(
} }
}); });
methods.add_method("lerp", |_, this, (rhs, alpha): (Self, f32)| { builder.method("lerp", |_, this, (rhs, alpha): (Self, f32)| {
Ok(Self(this.lerp(*rhs, alpha))) Ok(Self(this.lerp(*rhs, alpha)))
}); });
} }
@ -185,91 +180,91 @@ wrap_lua_struct!(
derives(PartialEq, Copy), derives(PartialEq, Copy),
metamethods(ToString, Eq), metamethods(ToString, Eq),
{ {
methods.add_function("default", |_, ()| { builder.function("default", |_, ()| {
Ok(Self(math::Transform::default())) Ok(Self(math::Transform::default()))
}); });
methods.add_function("new", |_, (pos, rot, scale): (LuaVec3, LuaQuat, LuaVec3)| { builder.function("new", |_, (pos, rot, scale): (LuaVec3, LuaQuat, LuaVec3)| {
Ok(Self(math::Transform::new(*pos, *rot, *scale))) Ok(Self(math::Transform::new(*pos, *rot, *scale)))
}); });
methods.add_function("from_translation", |_, (pos,): (LuaVec3,)| { builder.function("from_translation", |_, (pos,): (LuaVec3,)| {
Ok(Self(math::Transform::from_translation(*pos))) Ok(Self(math::Transform::from_translation(*pos)))
}); });
methods.add_function("from_xyz", |_, (x, y, z)| { builder.function("from_xyz", |_, (x, y, z)| {
Ok(Self(math::Transform::from_xyz(x, y, z))) Ok(Self(math::Transform::from_xyz(x, y, z)))
}); });
methods.add_method("clone", |_, this, ()| { builder.method("clone", |_, this, ()| {
Ok(this.clone()) Ok(this.clone())
}); });
methods.add_method("forward", |_, this, ()| { builder.method("forward", |_, this, ()| {
Ok(LuaVec3(this.forward())) Ok(LuaVec3(this.forward()))
}); });
methods.add_method("left", |_, this, ()| { builder.method("left", |_, this, ()| {
Ok(LuaVec3(this.left())) Ok(LuaVec3(this.left()))
}); });
methods.add_method("up", |_, this, ()| { builder.method("up", |_, this, ()| {
Ok(LuaVec3(this.up())) Ok(LuaVec3(this.up()))
}); });
methods.add_method_mut("rotate", |_, this, (quat,): (LuaQuat,)| { builder.method_mut("rotate", |_, this, (quat,): (LuaQuat,)| {
this.rotate(*quat); this.rotate(*quat);
Ok(()) Ok(())
}); });
methods.add_method_mut("rotate_x", |_, this, (deg,): (f32,)| { builder.method_mut("rotate_x", |_, this, (deg,): (f32,)| {
this.rotate_x(math::Angle::Degrees(deg)); this.rotate_x(math::Angle::Degrees(deg));
Ok(()) Ok(())
}); });
methods.add_method_mut("rotate_y", |_, this, (deg,): (f32,)| { builder.method_mut("rotate_y", |_, this, (deg,): (f32,)| {
this.rotate_y(math::Angle::Degrees(deg)); this.rotate_y(math::Angle::Degrees(deg));
Ok(()) Ok(())
}); });
methods.add_method_mut("rotate_z", |_, this, (deg,): (f32,)| { builder.method_mut("rotate_z", |_, this, (deg,): (f32,)| {
this.rotate_z(math::Angle::Degrees(deg)); this.rotate_z(math::Angle::Degrees(deg));
Ok(()) Ok(())
}); });
methods.add_method_mut("rotate_x_rad", |_, this, (rad,): (f32,)| { builder.method_mut("rotate_x_rad", |_, this, (rad,): (f32,)| {
this.rotate_x(math::Angle::Radians(rad)); this.rotate_x(math::Angle::Radians(rad));
Ok(()) Ok(())
}); });
methods.add_method_mut("rotate_y_rad", |_, this, (rad,): (f32,)| { builder.method_mut("rotate_y_rad", |_, this, (rad,): (f32,)| {
this.rotate_y(math::Angle::Radians(rad)); this.rotate_y(math::Angle::Radians(rad));
Ok(()) Ok(())
}); });
methods.add_method_mut("rotate_z_rad", |_, this, (rad,): (f32,)| { builder.method_mut("rotate_z_rad", |_, this, (rad,): (f32,)| {
this.rotate_z(math::Angle::Radians(rad)); this.rotate_z(math::Angle::Radians(rad));
Ok(()) Ok(())
}); });
methods.add_method_mut("translate", |_, this, (x, y, z): (f32, f32, f32)| { builder.method_mut("translate", |_, this, (x, y, z): (f32, f32, f32)| {
this.translate(x, y, z); this.translate(x, y, z);
Ok(()) Ok(())
}); });
methods.add_method("lerp", |_, this, (rhs, alpha): (Self, f32)| { builder.method("lerp", |_, this, (rhs, alpha): (Self, f32)| {
Ok(Self(this.lerp(*rhs, alpha))) Ok(Self(this.lerp(*rhs, alpha)))
}); });
// rotate a transform // rotate a transform
methods.add_meta_method(mlua::MetaMethod::Mul, |_, this, (quat,): (LuaQuat,)| { builder.meta_method(elua::MetaMethod::Mul, |_, this, (quat,): (LuaQuat,)| {
let mut t = *this; let mut t = *this;
t.rotation *= *quat; t.rotation *= *quat;
Ok(t) Ok(t)
}); });
// move a transform // move a transform
methods.add_meta_method(mlua::MetaMethod::Add, |_, this, (pos,): (LuaVec3,)| { builder.meta_method(elua::MetaMethod::Add, |_, this, (pos,): (LuaVec3,)| {
let mut t = *this; let mut t = *this;
t.translation += *pos; t.translation += *pos;
Ok(t) Ok(t)

View File

@ -1,7 +1,6 @@
use std::{ops::Deref, ptr::NonNull, sync::Arc}; use std::ptr::NonNull;
use lyra_ecs::{World, Entity}; use lyra_ecs::{World, Entity};
use parking_lot::{MappedRwLockReadGuard, MappedRwLockWriteGuard, RwLock, RwLockReadGuard, RwLockWriteGuard};
#[derive(Clone)] #[derive(Clone)]
pub struct ScriptEntity(pub Entity); pub struct ScriptEntity(pub Entity);
@ -15,41 +14,33 @@ impl std::ops::Deref for ScriptEntity {
} }
#[derive(Clone)] #[derive(Clone)]
pub struct ScriptWorldPtr(Arc<RwLock<NonNull<World>>>); pub struct ScriptWorldPtr {
pub inner: NonNull<World>,
}
impl ScriptWorldPtr { impl ScriptWorldPtr {
pub fn read(&self) -> MappedRwLockReadGuard<World> { /// Creates a world pointer from a world borrow.
RwLockReadGuard::map(self.0.read(), |p| unsafe { p.as_ref() }) pub fn from_ref(world: &World) -> Self {
Self {
inner: NonNull::from(world),
}
} }
pub fn write(&self) -> MappedRwLockWriteGuard<World> { /// Returns a borrow to the world from the ptr.
RwLockWriteGuard::map(self.0.write(), |p| unsafe { p.as_mut() }) pub fn as_ref(&self) -> &World {
unsafe { self.inner.as_ref() }
}
/// Returns a mutable borrow to the world from the ptr.
pub fn as_mut(&mut self) -> &mut World {
unsafe { self.inner.as_mut() }
} }
} }
// SAFETY: The inner NonNull pointer is wrapped in an Arc<RwLock<>> impl std::ops::Deref for ScriptWorldPtr {
unsafe impl Send for ScriptWorldPtr {} type Target = NonNull<World>;
unsafe impl Sync for ScriptWorldPtr {}
#[derive(Clone)]
pub struct ScriptWorldPtrGuard(ScriptWorldPtr);
impl Deref for ScriptWorldPtrGuard {
type Target = ScriptWorldPtr;
fn deref(&self) -> &Self::Target { fn deref(&self) -> &Self::Target {
&self.0 &self.inner
}
}
impl ScriptWorldPtrGuard {
/// Creates a new world pointer.
///
/// # Safety
/// The original `&mut World` must not be used while this guard is created.
/// The [World] may only be accessed through this guard or one of its cloned [ScriptWorldPtr]s.
#[allow(clippy::arc_with_non_send_sync)]
pub unsafe fn new(world: &mut World) -> Self {
ScriptWorldPtrGuard(ScriptWorldPtr(Arc::new(RwLock::new(NonNull::from(world)))))
} }
} }

View File

@ -10,6 +10,3 @@ impl std::ops::Deref for ScriptDynamicBundle {
&self.0 &self.0
} }
} }
// SAFETY: todo!()
unsafe impl Send for ScriptDynamicBundle {}