Fix #19: Lua crashes when spawning entities in optimized builds #27
|
@ -4,6 +4,24 @@
|
||||||
// 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",
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,9 +1,18 @@
|
||||||
---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
|
---@return string|nil
|
||||||
function udname(val)
|
function udname(val)
|
||||||
return getmetatable(val).__name
|
local tbl = debug.getmetatable(val)
|
||||||
|
|
||||||
|
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")
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use lyra_engine::{
|
use lyra_engine::{
|
||||||
assets::{gltf::Gltf, ResourceManager},
|
assets::{gltf::Gltf, ResourceManager},
|
||||||
game::Game,
|
game::App,
|
||||||
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,75 +33,73 @@ async fn main() {
|
||||||
.bind(
|
.bind(
|
||||||
ACTLBL_MOVE_FORWARD_BACKWARD,
|
ACTLBL_MOVE_FORWARD_BACKWARD,
|
||||||
&[
|
&[
|
||||||
ActionSource::Keyboard(KeyCode::W).into_binding_modifier(1.0),
|
ActionSource::Keyboard(KeyCode::KeyW).into_binding_modifier(1.0),
|
||||||
ActionSource::Keyboard(KeyCode::S).into_binding_modifier(-1.0),
|
ActionSource::Keyboard(KeyCode::KeyS).into_binding_modifier(-1.0),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
.bind(
|
.bind(
|
||||||
ACTLBL_MOVE_LEFT_RIGHT,
|
ACTLBL_MOVE_LEFT_RIGHT,
|
||||||
&[
|
&[
|
||||||
ActionSource::Keyboard(KeyCode::A).into_binding_modifier(-1.0),
|
ActionSource::Keyboard(KeyCode::KeyA).into_binding_modifier(-1.0),
|
||||||
ActionSource::Keyboard(KeyCode::D).into_binding_modifier(1.0),
|
ActionSource::Keyboard(KeyCode::KeyD).into_binding_modifier(1.0),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
.bind(
|
.bind(
|
||||||
ACTLBL_MOVE_UP_DOWN,
|
ACTLBL_MOVE_UP_DOWN,
|
||||||
&[
|
&[
|
||||||
ActionSource::Keyboard(KeyCode::C).into_binding_modifier(1.0),
|
ActionSource::Keyboard(KeyCode::KeyC).into_binding_modifier(1.0),
|
||||||
ActionSource::Keyboard(KeyCode::Z).into_binding_modifier(-1.0),
|
ActionSource::Keyboard(KeyCode::KeyZ).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::Left).into_binding_modifier(-1.0),
|
ActionSource::Keyboard(KeyCode::ArrowLeft).into_binding_modifier(-1.0),
|
||||||
ActionSource::Keyboard(KeyCode::Right).into_binding_modifier(1.0),
|
ActionSource::Keyboard(KeyCode::ArrowRight).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::Up).into_binding_modifier(-1.0),
|
ActionSource::Keyboard(KeyCode::ArrowUp).into_binding_modifier(-1.0),
|
||||||
ActionSource::Keyboard(KeyCode::Down).into_binding_modifier(1.0),
|
ActionSource::Keyboard(KeyCode::ArrowDown).into_binding_modifier(1.0),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
.bind(
|
.bind(
|
||||||
ACTLBL_LOOK_ROLL,
|
ACTLBL_LOOK_ROLL,
|
||||||
&[
|
&[
|
||||||
ActionSource::Keyboard(KeyCode::E).into_binding_modifier(-1.0),
|
ActionSource::Keyboard(KeyCode::KeyE).into_binding_modifier(-1.0),
|
||||||
ActionSource::Keyboard(KeyCode::Q).into_binding_modifier(1.0),
|
ActionSource::Keyboard(KeyCode::KeyQ).into_binding_modifier(1.0),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
.bind(
|
.bind(
|
||||||
"Debug",
|
"Debug",
|
||||||
&[ActionSource::Keyboard(KeyCode::B).into_binding()],
|
&[ActionSource::Keyboard(KeyCode::KeyB).into_binding()],
|
||||||
)
|
)
|
||||||
.finish(),
|
.finish(),
|
||||||
)
|
)
|
||||||
.finish();
|
.finish();
|
||||||
|
|
||||||
let world = game.world_mut();
|
let world = &mut app.world;
|
||||||
world.add_resource(action_handler);
|
world.add_resource(action_handler);
|
||||||
game.with_plugin(InputActionPlugin);
|
app.with_plugin(InputActionPlugin);
|
||||||
};
|
};
|
||||||
|
|
||||||
Game::initialize()
|
let mut app = App::new();
|
||||||
.await
|
app.with_plugin(lyra_engine::DefaultPlugins);
|
||||||
.with_plugin(lyra_engine::DefaultPlugins)
|
app.with_plugin(setup_scene_plugin);
|
||||||
.with_plugin(setup_scene_plugin)
|
app.with_plugin(action_handler_plugin);
|
||||||
.with_plugin(action_handler_plugin)
|
app.with_plugin(setup_script_plugin);
|
||||||
.with_plugin(setup_script_plugin)
|
//app.with_plugin(camera_debug_plugin);
|
||||||
//.with_plugin(camera_debug_plugin)
|
app.with_plugin(FreeFlyCameraPlugin);
|
||||||
.with_plugin(FreeFlyCameraPlugin)
|
app.run();
|
||||||
.run()
|
|
||||||
.await;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn setup_scene_plugin(app: &mut App) {
|
fn setup_scene_plugin(app: &mut App) {
|
||||||
let world = game.world_mut();
|
let world = &mut app.world;
|
||||||
let resman = world.get_resource_mut::<ResourceManager>();
|
let resman = world.get_resource_mut::<ResourceManager>().unwrap();
|
||||||
let camera_gltf = resman
|
let camera_gltf = resman
|
||||||
.request::<Gltf>("../assets/AntiqueCamera.glb")
|
.request::<Gltf>("../assets/AntiqueCamera.glb")
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
@ -137,10 +135,10 @@ fn setup_scene_plugin(app: &mut App) {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn setup_script_plugin(app: &mut App) {
|
fn setup_script_plugin(app: &mut App) {
|
||||||
game.with_plugin(LuaScriptingPlugin);
|
app.with_plugin(LuaScriptingPlugin);
|
||||||
|
|
||||||
let world = game.world_mut();
|
let world = &mut app.world;
|
||||||
let res_man = world.get_resource_mut::<ResourceManager>();
|
let res_man = world.get_resource_mut::<ResourceManager>().unwrap();
|
||||||
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);
|
||||||
|
|
|
@ -509,7 +509,11 @@ 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 { NonNull::new_unchecked(d.data.as_ptr() as *mut T) })
|
.map(|d| unsafe {
|
||||||
|
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 {
|
||||||
|
|
|
@ -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::DEBUG)
|
.with_target("wgsl_preprocessor", Level::INFO)
|
||||||
.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))
|
||||||
|
|
|
@ -21,6 +21,12 @@ 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>>,
|
||||||
|
@ -37,9 +43,7 @@ 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, .. } => {
|
||||||
if let PhysicalKey::Code(code) = event.physical_key {
|
write_key_event(&mut key_code_res, event.physical_key, event.state);
|
||||||
key_code_res.add_input_from_winit(code, event.state);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
WindowEvent::CursorMoved { position, .. } => {
|
WindowEvent::CursorMoved { position, .. } => {
|
||||||
let exact = MouseExact {
|
let exact = MouseExact {
|
||||||
|
@ -100,6 +104,9 @@ 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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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: 'static>);
|
impl_reflect_trait_value!(::core::marker::PhantomData<T: Send + Sync + '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 {
|
||||||
|
|
|
@ -52,7 +52,7 @@ pub use registry::*;
|
||||||
|
|
||||||
pub mod impls;
|
pub mod impls;
|
||||||
|
|
||||||
pub trait Reflect: Any {
|
pub trait Reflect: Any + Send + Sync {
|
||||||
fn name(&self) -> String;
|
fn name(&self) -> String;
|
||||||
fn type_id(&self) -> TypeId;
|
fn type_id(&self) -> TypeId;
|
||||||
|
|
||||||
|
|
|
@ -7,8 +7,8 @@ edition = "2021"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["lua"]
|
default = ["lua"]
|
||||||
lua = ["dep:elua"]
|
lua = ["dep:mlua"]
|
||||||
teal = ["lua", "elua/teal"]
|
#teal = ["lua", "mlua/teal"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
lyra-scripting-derive = { path = "lyra-scripting-derive" }
|
lyra-scripting-derive = { path = "lyra-scripting-derive" }
|
||||||
|
@ -22,11 +22,13 @@ 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?
|
#
|
||||||
elua = { path = "./elua", optional = true }
|
#mlua = { version = "0.9.9", features = ["lua54", "send"], optional = true } # luajit maybe?
|
||||||
|
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" ] }
|
||||||
|
|
|
@ -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).as_lua(lua))
|
quote!(#wrap(data.#field).into_lua(lua))
|
||||||
},
|
},
|
||||||
None => match &g.body {
|
None => match &g.body {
|
||||||
Some(body) => {
|
Some(body) => {
|
||||||
quote!(#body)
|
quote!(#body)
|
||||||
},
|
},
|
||||||
None => {
|
None => {
|
||||||
quote!(data.#field.clone().as_lua(lua))
|
quote!(data.#field.clone().into_lua(lua))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
quote! {
|
quote! {
|
||||||
builder.field_getter(stringify!($field), |lua, this| {
|
fields.add_field_method_get(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(Value::Nil)
|
Ok(mlua::Value::Nil)
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -186,16 +186,12 @@ pub(crate) fn lua_wrap_handle_impl(input: proc_macro::TokenStream) -> proc_macro
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl elua::Userdata for #wrapper_name {
|
impl mlua::UserData for #wrapper_name {
|
||||||
fn name() -> String {
|
fn add_fields<F: mlua::UserDataFields<Self>>(fields: &mut F) {
|
||||||
#ud_name.to_string()
|
fields.add_field_method_get("path", |_, this| Ok(this.path()));
|
||||||
}
|
fields.add_field_method_get("version", |_, this| Ok(this.version()));
|
||||||
|
fields.add_field_method_get("uuid", |_, this| Ok(this.uuid().to_string()));
|
||||||
fn build<'a>(builder: &mut elua::UserdataBuilder<'a, Self>) {
|
fields.add_field_method_get("state", |_, this| {
|
||||||
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() {
|
||||||
|
@ -206,29 +202,31 @@ pub(crate) fn lua_wrap_handle_impl(input: proc_macro::TokenStream) -> proc_macro
|
||||||
});
|
});
|
||||||
|
|
||||||
#(#custom_getters)*
|
#(#custom_getters)*
|
||||||
|
}
|
||||||
|
|
||||||
builder.method("is_watched", |_, this, ()| {
|
fn add_methods<M: mlua::UserDataMethods<Self>>(methods: &mut M) {
|
||||||
|
methods.add_method("is_watched", |_, this, ()| {
|
||||||
Ok(this.is_watched())
|
Ok(this.is_watched())
|
||||||
});
|
});
|
||||||
|
|
||||||
builder.method("is_loaded", |_, this, ()| {
|
methods.add_method("is_loaded", |_, this, ()| {
|
||||||
Ok(this.is_loaded())
|
Ok(this.is_loaded())
|
||||||
});
|
});
|
||||||
|
|
||||||
builder.method("is_loaded", |_, this, ()| {
|
methods.add_method("is_loaded", |_, this, ()| {
|
||||||
Ok(this.is_loaded())
|
Ok(this.is_loaded())
|
||||||
});
|
});
|
||||||
|
|
||||||
builder.method("wait_until_loaded", |_, this, ()| {
|
methods.add_method("wait_until_loaded", |_, this, ()| {
|
||||||
this.wait_recurse_dependencies_load();
|
this.wait_recurse_dependencies_load();
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
});
|
});
|
||||||
|
|
||||||
builder.function(FN_NAME_INTERNAL_REFLECT_TYPE, |_, ()| {
|
methods.add_function(FN_NAME_INTERNAL_REFLECT_TYPE, |_, ()| {
|
||||||
Ok(ScriptBorrow::from_component::<ResHandle<#handle_name>>(None))
|
Ok(ScriptBorrow::from_component::<ResHandle<#handle_name>>(None))
|
||||||
});
|
});
|
||||||
builder.method(FN_NAME_INTERNAL_REFLECT, |_, this, ()| {
|
methods.add_method(FN_NAME_INTERNAL_REFLECT, |_, this, ()| {
|
||||||
Ok(ScriptBorrow::from_component(Some(this.0.clone())))
|
Ok(ScriptBorrow::from_component(Some(this.0.clone())))
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -236,12 +234,12 @@ pub(crate) fn lua_wrap_handle_impl(input: proc_macro::TokenStream) -> proc_macro
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> FromLua<'a> for #wrapper_name {
|
impl mlua::FromLua for #wrapper_name {
|
||||||
fn from_lua(_: &'a elua::State, val: elua::Value<'a>) -> elua::Result<Self> {
|
fn from_lua(val: mlua::Value, _: &mlua::Lua) -> mlua::Result<Self> {
|
||||||
let tyname = val.type_name();
|
let tyname = val.type_name();
|
||||||
let ud = val.as_userdata()
|
let ud = val.as_userdata()
|
||||||
.ok_or(elua::Error::type_mismatch(#ud_name, &tyname))?;
|
.ok_or(mlua::Error::external(crate::lua::Error::type_mismatch(#ud_name, &tyname)))?;
|
||||||
let ud = ud.as_ref::<#wrapper_name>()?;
|
let ud = ud.borrow::<#wrapper_name>()?;
|
||||||
|
|
||||||
Ok(ud.clone())
|
Ok(ud.clone())
|
||||||
}
|
}
|
||||||
|
|
|
@ -156,13 +156,13 @@ impl MetaMethod {
|
||||||
|
|
||||||
if Self::does_metamethod_have_arg(&self.name) {
|
if Self::does_metamethod_have_arg(&self.name) {
|
||||||
quote! {
|
quote! {
|
||||||
builder.meta_method(elua::MetaMethod::#mt_ident, |_, this, (v,): (#wrapper_ident,)| {
|
methods.add_meta_method(mlua::MetaMethod::#mt_ident, |_, this, (v,): (#wrapper_ident,)| {
|
||||||
#body
|
#body
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
quote! {
|
quote! {
|
||||||
builder.meta_method(elua::MetaMethod::#mt_ident, |_, this, ()| {
|
methods.add_meta_method(mlua::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! {
|
||||||
builder.meta_method(elua::MetaMethod::#mt_ident, |_, this, (v,): (#first,)| {
|
methods.add_meta_method(mlua::MetaMethod::#mt_ident, |_, this, (v,): (#first,)| {
|
||||||
#body
|
#body
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// an optional match arm that matches elua::Value:Number
|
// an optional match arm that matches mlua::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! {
|
||||||
elua::Value::Number(n) => {
|
mlua::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.as_ref::<#i>() {
|
if let Ok(other) = ud.borrow::<#i>() {
|
||||||
#body
|
#body
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -219,30 +219,30 @@ impl MetaMethod {
|
||||||
});
|
});
|
||||||
|
|
||||||
quote! {
|
quote! {
|
||||||
elua::Value::Userdata(ud) => {
|
mlua::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.get_metatable() {
|
if let Ok(mt) = ud.metatable() {
|
||||||
if let Ok(name) = mt.get::<_, String>("__name") {
|
if let Ok(name) = mt.get::<String>("__name") {
|
||||||
return Err(elua::Error::BadArgument {
|
return Err(mlua::Error::BadArgument {
|
||||||
func: Some(format!("{}.__{}", #wrapped_str, #mt_lua_name)),
|
to: Some(format!("{}.__{}", #wrapped_str, #mt_lua_name)),
|
||||||
arg_index: 2,
|
pos: 2,
|
||||||
arg_name: Some("rhs".to_string()),
|
name: Some("rhs".to_string()),
|
||||||
error: std::sync::Arc::new(elua::Error::Runtime(
|
cause: std::sync::Arc::new(mlua::Error::runtime(
|
||||||
format!("cannot multiply with unknown userdata named {}", name)
|
format!("cannot multiply with unknown userdata named {}", name)
|
||||||
))
|
))
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Err(elua::Error::BadArgument {
|
Err(mlua::Error::BadArgument {
|
||||||
func: Some(format!("{}.__{}", #wrapped_str, #mt_lua_name)),
|
to: Some(format!("{}.__{}", #wrapped_str, #mt_lua_name)),
|
||||||
arg_index: 2,
|
pos: 2,
|
||||||
arg_name: Some("rhs".to_string()),
|
name: Some("rhs".to_string()),
|
||||||
error: std::sync::Arc::new(
|
cause: std::sync::Arc::new(
|
||||||
elua::Error::runtime("cannot multiply with unknown userdata")
|
mlua::Error::runtime("cannot multiply with unknown userdata")
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -251,16 +251,16 @@ impl MetaMethod {
|
||||||
};
|
};
|
||||||
|
|
||||||
quote! {
|
quote! {
|
||||||
builder.meta_method(elua::MetaMethod::#mt_ident, |_, this, (v,): (elua::Value,)| {
|
methods.add_meta_method(mlua::MetaMethod::#mt_ident, |_, this, (v,): (mlua::Value,)| {
|
||||||
match v {
|
match v {
|
||||||
#number_arm
|
#number_arm
|
||||||
#userdata_arm
|
#userdata_arm
|
||||||
_ => Err(elua::Error::BadArgument {
|
_ => Err(mlua::Error::BadArgument {
|
||||||
func: Some(format!("{}.__{}", #wrapped_str, #mt_lua_name)),
|
to: Some(format!("{}.__{}", #wrapped_str, #mt_lua_name)),
|
||||||
arg_index: 2,
|
pos: 2,
|
||||||
arg_name: Some("rhs".to_string()),
|
name: Some("rhs".to_string()),
|
||||||
error: std::sync::Arc::new(
|
cause: std::sync::Arc::new(
|
||||||
elua::Error::Runtime(format!("cannot multiply with {}", v.type_name()))
|
mlua::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! {
|
||||||
builder.field_getter(#is, |_, this| {
|
fields.add_field_method_get(#is, |_, this| {
|
||||||
Ok(this.#i)
|
Ok(this.#i)
|
||||||
});
|
});
|
||||||
builder.field_setter(#is, |_, this, #i| {
|
fields.add_field_method_set(#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(...)
|
||||||
builder.function("new", |_, ( #(#arg_names_clone),* )| {
|
methods.add_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! {
|
||||||
builder.method(#FN_NAME_INTERNAL_REFLECT, |_, this, ()| {
|
methods.add_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())))
|
||||||
});
|
});
|
||||||
|
|
||||||
builder.function(#FN_NAME_INTERNAL_REFLECT_TYPE, |_, ()| {
|
methods.add_function(#FN_NAME_INTERNAL_REFLECT_TYPE, |_, ()| {
|
||||||
Ok(crate::ScriptBorrow::from_component::<#path>(None))
|
Ok(crate::ScriptBorrow::from_component::<#path>(None))
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -480,22 +480,21 @@ pub fn wrap_lua_struct_impl(input: proc_macro::TokenStream) -> proc_macro::Token
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'lua> elua::FromLua<'lua> for #wrapper_typename {
|
impl mlua::FromLua for #wrapper_typename {
|
||||||
fn from_lua(_lua: &'lua elua::State, value: elua::Value<'lua>) -> elua::Result<Self> {
|
fn from_lua(value: mlua::Value, _: &mlua::Lua) -> mlua::Result<Self> {
|
||||||
match value {
|
match value {
|
||||||
elua::Value::Userdata(ud) => Ok(ud.as_ref::<Self>()?.clone()),
|
mlua::Value::UserData(ud) => Ok(ud.borrow::<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 elua::Userdata for #wrapper_typename {
|
impl mlua::UserData for #wrapper_typename {
|
||||||
fn name() -> String {
|
fn add_fields<F: mlua::UserDataFields<Self>>(fields: &mut F) {
|
||||||
stringify!(#type_name).to_string()
|
#(#field_get_set_pairs)*
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build<'a>(builder: &mut elua::UserdataBuilder<'a, Self>) {
|
fn add_methods<M: mlua::UserDataMethods<Self>>(methods: &mut M) {
|
||||||
#(#field_get_set_pairs)*
|
|
||||||
#lua_reflects
|
#lua_reflects
|
||||||
|
|
||||||
#new_func_tokens
|
#new_func_tokens
|
||||||
|
@ -509,20 +508,5 @@ 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,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
}
|
}
|
|
@ -49,8 +49,8 @@ impl VecWrapper {
|
||||||
|
|
||||||
if axis_type_name.contains("b") {
|
if axis_type_name.contains("b") {
|
||||||
return quote! {
|
return quote! {
|
||||||
builder.field("FALSE", #wrapper_ident(#wrapped_path::FALSE));
|
fields.add_field_method_get("FALSE", #wrapper_ident(#wrapped_path::FALSE));
|
||||||
builder.field("TRUE", #wrapper_ident(#wrapped_path::TRUE));
|
fields.add_field_method_get("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! {
|
||||||
builder.field(#const_name, #wrapper_ident(#wrapped_path::#cnst));
|
fields.add_field_method_get(#const_name, #wrapper_ident(#wrapped_path::#cnst));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -112,27 +112,37 @@ impl VecWrapper {
|
||||||
|
|
||||||
optional_methods.push(
|
optional_methods.push(
|
||||||
quote! {
|
quote! {
|
||||||
builder.method("clamp_length",
|
methods.add_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)))
|
||||||
});
|
});
|
||||||
|
|
||||||
builder.method("abs_diff_eq",
|
methods.add_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))
|
||||||
});
|
});
|
||||||
|
|
||||||
builder.method("ceil",
|
methods.add_method("ceil",
|
||||||
|_, this, (): ()| {
|
|_, this, (): ()| {
|
||||||
Ok(#wrapper_ident(this.ceil()))
|
Ok(#wrapper_ident(this.ceil()))
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
if vec_size != 4 {
|
if vec_size == 2 {
|
||||||
|
// angle_between is deprecated for Vec2, must use angle_to instead.
|
||||||
optional_methods.push(
|
optional_methods.push(
|
||||||
quote! {
|
quote! {
|
||||||
builder.method("angle_between",
|
methods.add_method("angle_to",
|
||||||
|
|_, 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))
|
||||||
});
|
});
|
||||||
|
@ -144,7 +154,7 @@ impl VecWrapper {
|
||||||
if !axis_type_name.contains("u") {
|
if !axis_type_name.contains("u") {
|
||||||
optional_methods.push(
|
optional_methods.push(
|
||||||
quote! {
|
quote! {
|
||||||
builder.method("abs",
|
methods.add_method("abs",
|
||||||
|_, this, (): ()| {
|
|_, this, (): ()| {
|
||||||
Ok(#wrapper_ident(this.abs()))
|
Ok(#wrapper_ident(this.abs()))
|
||||||
});
|
});
|
||||||
|
@ -154,21 +164,18 @@ 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
|
||||||
/* builder.method("clamp_length",
|
/* methods.add_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())
|
||||||
});
|
});
|
||||||
|
|
|
@ -8,16 +8,23 @@ use crate::ScriptWorldPtr;
|
||||||
pub enum ScriptError {
|
pub enum ScriptError {
|
||||||
#[error("{0}")]
|
#[error("{0}")]
|
||||||
#[cfg(feature = "lua")]
|
#[cfg(feature = "lua")]
|
||||||
MluaError(elua::Error),
|
LuaError(crate::lua::Error),
|
||||||
|
|
||||||
#[error("{0}")]
|
#[error("{0}")]
|
||||||
Other(anyhow::Error),
|
Other(anyhow::Error),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "lua")]
|
#[cfg(feature = "lua")]
|
||||||
impl From<elua::Error> for ScriptError {
|
impl From<mlua::Error> for ScriptError {
|
||||||
fn from(value: elua::Error) -> Self {
|
fn from(value: mlua::Error) -> Self {
|
||||||
ScriptError::MluaError(value)
|
ScriptError::LuaError(crate::lua::Error::Mlua(value))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "lua")]
|
||||||
|
impl From<crate::lua::Error> for ScriptError {
|
||||||
|
fn from(value: crate::lua::Error) -> Self {
|
||||||
|
ScriptError::LuaError(value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,7 @@ pub use host::*;
|
||||||
pub mod script;
|
pub mod script;
|
||||||
pub use script::*;
|
pub use script::*;
|
||||||
|
|
||||||
use lyra_game::game::Game;
|
use lyra_game::game::App;
|
||||||
|
|
||||||
// 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 Game {
|
impl GameScriptExt for App {
|
||||||
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 = self.world_mut();
|
let world = &mut self.world;
|
||||||
provider.prepare_world(world);
|
provider.prepare_world(world);
|
||||||
let mut providers = world.get_resource_mut::<ScriptApiProviders<T>>();
|
let mut providers = world.get_resource_mut::<ScriptApiProviders<T>>().unwrap();
|
||||||
providers.add_provider(provider);
|
providers.add_provider(provider);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -6,44 +6,41 @@ 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<'a> {
|
pub struct ReflectedItem {
|
||||||
//pub proxy: &'a ReflectLuaProxy,
|
//pub proxy: &'a ReflectLuaProxy,
|
||||||
pub comp_ptr: NonNull<u8>,
|
pub comp_ptr: NonNull<u8>,
|
||||||
pub comp_val: elua::Value<'a>,
|
pub comp_val: mlua::Value,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "lua")]
|
#[cfg(feature = "lua")]
|
||||||
pub struct ReflectedRow<'a> {
|
pub struct ReflectedRow {
|
||||||
pub entity: Entity,
|
pub entity: Entity,
|
||||||
pub row: Vec<ReflectedItem<'a>>,
|
pub row: Vec<ReflectedItem>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ReflectedIterator {
|
pub struct ReflectedIterator<'a> {
|
||||||
pub world: ScriptWorldPtr,
|
pub world: &'a lyra_ecs::World,
|
||||||
pub dyn_view: DynamicViewStateIter,
|
pub dyn_view: DynamicViewStateIter,
|
||||||
pub reflected_components: Option<NonNull<TypeRegistry>>
|
pub reflected_components: Option<NonNull<TypeRegistry>>
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ReflectedIterator {
|
impl<'a> ReflectedIterator<'a> {
|
||||||
#[cfg(feature = "lua")]
|
#[cfg(feature = "lua")]
|
||||||
pub fn next_lua<'a>(&mut self, lua: &'a elua::State) -> Option<ReflectedRow<'a>> {
|
pub fn next_lua(&mut self, lua: &mlua::Lua) -> Option<ReflectedRow> {
|
||||||
use elua::AsLua;
|
use mlua::IntoLua;
|
||||||
|
|
||||||
|
//let world = self.world.read();
|
||||||
|
let n = self.dyn_view.next(&self.world);
|
||||||
|
|
||||||
let world = self.world.as_ref();
|
if let Some((en, row)) = n {
|
||||||
let n = self.dyn_view.next(world);
|
|
||||||
|
|
||||||
if let Some(row) = n {
|
|
||||||
if self.reflected_components.is_none() {
|
if self.reflected_components.is_none() {
|
||||||
let world = self.world.as_ref();
|
self.reflected_components = self.world.get_resource::<TypeRegistry>()
|
||||||
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.row.iter() {
|
for d in 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() };
|
||||||
|
@ -54,7 +51,7 @@ impl ReflectedIterator {
|
||||||
// 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()
|
||||||
.as_lua(lua).unwrap();
|
.into_lua(lua).unwrap();
|
||||||
|
|
||||||
dynamic_row.push(ReflectedItem {
|
dynamic_row.push(ReflectedItem {
|
||||||
comp_ptr: d.ptr,
|
comp_ptr: d.ptr,
|
||||||
|
@ -63,7 +60,7 @@ impl ReflectedIterator {
|
||||||
}
|
}
|
||||||
|
|
||||||
let row = ReflectedRow {
|
let row = ReflectedRow {
|
||||||
entity: row.entity,
|
entity: en,
|
||||||
row: dynamic_row
|
row: dynamic_row
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@ pub mod dynamic_iter;
|
||||||
pub use dynamic_iter::*;
|
pub use dynamic_iter::*;
|
||||||
|
|
||||||
pub mod world;
|
pub mod world;
|
||||||
use elua::FromLua;
|
use mlua::ObjectLike;
|
||||||
pub use world::*;
|
pub use world::*;
|
||||||
|
|
||||||
pub mod script;
|
pub mod script;
|
||||||
|
@ -22,13 +22,48 @@ pub use system::*;
|
||||||
|
|
||||||
use std::{any::TypeId, sync::Mutex};
|
use std::{any::TypeId, sync::Mutex};
|
||||||
|
|
||||||
use lyra_ecs::{
|
use lyra_ecs::World;
|
||||||
Component, ComponentInfo, World
|
|
||||||
};
|
|
||||||
use lyra_reflect::{Reflect, TypeRegistry};
|
use lyra_reflect::{Reflect, TypeRegistry};
|
||||||
use crate::ScriptBorrow;
|
use crate::ScriptBorrow;
|
||||||
|
|
||||||
pub type LuaContext = Mutex<elua::State>;
|
pub type LuaContext = Mutex<mlua::Lua>;
|
||||||
|
|
||||||
|
#[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.
|
||||||
///
|
///
|
||||||
|
@ -47,7 +82,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 [`elua::Value::Nil`] if for some reason the type could not be converted
|
/// You can return [`mlua::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
|
||||||
|
@ -78,32 +113,26 @@ 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 + elua::FromLua<'a> + elua::Userdata;
|
T: Reflect + LuaProxy + Clone + mlua::FromLua + mlua::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 + elua::FromLua<'a> + elua::Userdata;
|
W: Reflect + LuaProxy + LuaWrapper + Clone + mlua::FromLua + mlua::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 + for<'a> elua::FromLua<'a> + for<'a> elua::AsLua<'a> + LuaWrapper + 'static;
|
T: Clone + mlua::FromLua + mlua::IntoLua + 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 + elua::FromLua<'a> + elua::Userdata
|
T: Reflect + LuaProxy + Clone + mlua::FromLua + mlua::UserData
|
||||||
{
|
{
|
||||||
let mut registry = self.get_resource_mut::<TypeRegistry>();
|
let mut registry = self.get_resource_mut::<TypeRegistry>().unwrap();
|
||||||
|
|
||||||
let type_id = TypeId::of::<T>();
|
let type_id = TypeId::of::<T>();
|
||||||
|
|
||||||
|
@ -113,72 +142,40 @@ 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 + elua::FromLua<'a> + elua::Userdata
|
W: Reflect + LuaProxy + LuaWrapper + Clone + mlua::FromLua + mlua::UserData
|
||||||
{
|
{
|
||||||
let mut registry = self.get_resource_mut::<TypeRegistry>();
|
let mut registry = self.get_resource_mut::<TypeRegistry>().unwrap();
|
||||||
|
|
||||||
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>());
|
||||||
}
|
}
|
||||||
|
|
||||||
fn register_lua_convert<T>(&mut self)
|
fn register_lua_convert<T>(&mut self)
|
||||||
where
|
where
|
||||||
T: Clone + for<'a> elua::FromLua<'a> + for<'a> elua::AsLua<'a> + LuaWrapper + 'static,
|
T: Clone + mlua::FromLua + mlua::IntoLua + LuaWrapper + 'static,
|
||||||
{
|
{
|
||||||
let mut registry = self.get_resource_mut::<TypeRegistry>();
|
let mut registry = self.get_resource_mut::<TypeRegistry>().unwrap();
|
||||||
|
|
||||||
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<'lua> elua::FromLua<'lua> for ScriptBorrow {
|
impl mlua::FromLua for ScriptBorrow {
|
||||||
fn from_lua(_: &'lua elua::State, value: elua::Value<'lua>) -> elua::Result<Self> {
|
fn from_lua(value: mlua::Value, _: &mlua::Lua) -> mlua::Result<Self> {
|
||||||
match value {
|
match value {
|
||||||
elua::Value::Userdata(ud) => Ok(ud.as_ref::<Self>()?.clone()),
|
mlua::Value::UserData(ud) => Ok(ud.borrow::<Self>()?.clone()),
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'lua> elua::FromLuaVec<'lua> for ScriptBorrow {
|
impl mlua::UserData 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: &elua::AnyUserdata) -> ScriptBorrow {
|
pub fn reflect_user_data(ud: &mlua::AnyUserData) -> ScriptBorrow {
|
||||||
ud.execute_method::<_, ScriptBorrow>(FN_NAME_INTERNAL_REFLECT, ())
|
ud.call_method::<ScriptBorrow>(FN_NAME_INTERNAL_REFLECT, ())
|
||||||
.expect("Type does not implement internal reflect method properly")
|
.expect("Type does not implement internal reflect method properly")
|
||||||
}
|
}
|
|
@ -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>();
|
let mut registry = world.get_resource_mut::<TypeRegistry>().unwrap();
|
||||||
|
|
||||||
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: &elua::State) -> elua::Result<elua::Table> {
|
fn create_reflect_table<T: Reflect + ResourceObject + Default + 'static>(lua: &mlua::Lua) -> mlua::Result<mlua::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))
|
||||||
|
|
|
@ -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>()?)?;
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
use std::sync::{Mutex, Arc};
|
use std::{ops::Deref, sync::{Arc, Mutex}};
|
||||||
|
|
||||||
use tracing::{debug_span, debug};
|
use mlua::{AnyUserData, ObjectLike};
|
||||||
|
use tracing::{debug, debug_span};
|
||||||
|
|
||||||
use crate::{ScriptApiProvider, ScriptData};
|
use crate::{ScriptApiProvider, ScriptData};
|
||||||
|
|
||||||
/// This Api provider provides some nice utility functions.
|
/// This Api provider provides some nice utility functions.
|
||||||
///
|
///
|
||||||
/// Functions:
|
/// Functions:
|
||||||
/// ```lua
|
/// ```lua
|
||||||
/// ---@param str (string) A format string.
|
/// ---@param str (string) A format string.
|
||||||
|
@ -17,99 +18,122 @@ use crate::{ScriptApiProvider, ScriptData};
|
||||||
pub struct UtilityApiProvider;
|
pub struct UtilityApiProvider;
|
||||||
|
|
||||||
impl ScriptApiProvider for UtilityApiProvider {
|
impl ScriptApiProvider for UtilityApiProvider {
|
||||||
type ScriptContext = Mutex<elua::State>;
|
type ScriptContext = Mutex<mlua::Lua>;
|
||||||
|
|
||||||
fn expose_api(&mut self, data: &ScriptData, ctx: &mut Self::ScriptContext) -> Result<(), crate::ScriptError> {
|
fn expose_api(
|
||||||
|
&mut self,
|
||||||
|
data: &ScriptData,
|
||||||
|
ctx: &mut Self::ScriptContext,
|
||||||
|
) -> Result<(), crate::ScriptError> {
|
||||||
let ctx = ctx.lock().unwrap();
|
let ctx = ctx.lock().unwrap();
|
||||||
|
|
||||||
//fn printf(lua: &elua::State, (mut text, formats): (String, elua::Variadic<elua::Value>)) -> elua::Result<()> {
|
//fn printf(lua: &mlua::State, (mut text, formats): (String, mlua::Variadic<mlua::Value>)) -> mlua::Result<()> {
|
||||||
let printf = |lua: &elua::State, (mut text, formats): (String, elua::Variadic<elua::Value>)| {
|
let printf =
|
||||||
let mut formatted = String::new();
|
|lua: &mlua::Lua, (mut text, formats): (String, mlua::Variadic<mlua::Value>)| {
|
||||||
let mut arg_num = 0;
|
let mut formatted = String::new();
|
||||||
|
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 {
|
||||||
elua::Value::Nil => "nil".to_string(),
|
mlua::Value::Nil => "nil".to_string(),
|
||||||
elua::Value::Boolean(b) => b.to_string(),
|
mlua::Value::Boolean(b) => b.to_string(),
|
||||||
elua::Value::Number(n) => n.to_string(),
|
mlua::Value::Integer(n) => n.to_string(),
|
||||||
elua::Value::String(s) => s.clone(),
|
mlua::Value::Number(n) => n.to_string(),
|
||||||
elua::Value::Table(_) => {
|
mlua::Value::String(s) => s.to_string_lossy().to_string(),
|
||||||
return Err(elua::Error::runtime("unable to get string representation of Table"));
|
mlua::Value::Table(_) => {
|
||||||
|
return Err(mlua::Error::runtime(
|
||||||
|
"unable to get string representation of Table",
|
||||||
|
));
|
||||||
|
},
|
||||||
|
mlua::Value::Function(_) => {
|
||||||
|
return Err(mlua::Error::runtime(
|
||||||
|
"unable to get string representation of Function",
|
||||||
|
));
|
||||||
|
},
|
||||||
|
mlua::Value::Thread(_) => {
|
||||||
|
return Err(mlua::Error::runtime(
|
||||||
|
"unable to get string representation of Thread",
|
||||||
|
));
|
||||||
|
},
|
||||||
|
mlua::Value::UserData(ud) => {
|
||||||
|
if let Ok(tos) =
|
||||||
|
ud.get::<mlua::Function>(mlua::MetaMethod::ToString.name())
|
||||||
|
{
|
||||||
|
tos.call::<String>(())?
|
||||||
|
} else {
|
||||||
|
return Err(mlua::Error::runtime(
|
||||||
|
"UserData does not implement MetaMethod '__tostring'",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mlua::Value::LightUserData(_) => {
|
||||||
|
return Err(mlua::Error::runtime(
|
||||||
|
"unable to get string representation of LightUserData",
|
||||||
|
));
|
||||||
|
},
|
||||||
|
mlua::Value::Error(error) => {
|
||||||
|
return Err(error.deref().clone());
|
||||||
|
},
|
||||||
},
|
},
|
||||||
elua::Value::Function(_) => {
|
None => {
|
||||||
return Err(elua::Error::runtime("unable to get string representation of Function"));
|
let got_args = arg_num; // - 1;
|
||||||
},
|
|
||||||
elua::Value::Thread(_) => {
|
// continue searching for {} to get the number of format spots for the error message.
|
||||||
return Err(elua::Error::runtime("unable to get string representation of Thread"));
|
while let Some(start) = text.find("{}") {
|
||||||
},
|
text = text[start + 2..].to_string();
|
||||||
elua::Value::Userdata(ud) => {
|
arg_num += 1;
|
||||||
if let Ok(tos) = ud.get::<_, elua::Function>(elua::MetaMethod::ToString) {
|
|
||||||
tos.exec::<_, String>(())?
|
|
||||||
} else {
|
|
||||||
return Err(elua::Error::runtime("UserData does not implement MetaMethod '__tostring'"));
|
|
||||||
}
|
}
|
||||||
},
|
|
||||||
elua::Value::None => "None".to_string(),
|
|
||||||
elua::Value::Multi(_) => {
|
|
||||||
return Err(elua::Error::runtime("unable to get string representation of ValueVec"));
|
|
||||||
},
|
|
||||||
},
|
|
||||||
None => {
|
|
||||||
let got_args = arg_num;// - 1;
|
|
||||||
|
|
||||||
// continue searching for {} to get the number of format spots for the error message.
|
return Err(mlua::Error::BadArgument {
|
||||||
while let Some(start) = text.find("{}") {
|
to: Some("printf".into()),
|
||||||
text = text[start + 2..].to_string();
|
pos: 2,
|
||||||
arg_num += 1;
|
name: Some("fmt...".into()),
|
||||||
|
cause: Arc::new(mlua::Error::runtime(format!(
|
||||||
|
"not enough args \
|
||||||
|
given for the amount of format areas in the string. Expected {}, \
|
||||||
|
got {}.",
|
||||||
|
arg_num, got_args
|
||||||
|
))),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return Err(elua::Error::BadArgument {
|
formatted = format!("{}{}{}", formatted, &text[0..start], val_str);
|
||||||
func: Some("printf".to_string()),
|
|
||||||
arg_index: 2,
|
|
||||||
arg_name: Some("fmt...".to_string()),
|
|
||||||
error: Arc::new(elua::Error::Runtime(format!(
|
|
||||||
"not enough args \
|
|
||||||
given for the amount of format areas in the string. Expected {}, \
|
|
||||||
got {}.", arg_num, got_args
|
|
||||||
)))
|
|
||||||
})
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
formatted = format!("{}{}{}", formatted, &text[0..start], val_str);
|
text = text[start + 2..].to_string();
|
||||||
|
|
||||||
text = text[start + 2..].to_string();
|
arg_num += 1;
|
||||||
|
}
|
||||||
|
|
||||||
arg_num += 1;
|
if arg_num < formats.len() {
|
||||||
}
|
return Err(mlua::Error::BadArgument {
|
||||||
|
to: Some("printf".into()),
|
||||||
|
pos: 2,
|
||||||
|
name: Some("fmt...".into()),
|
||||||
|
cause: Arc::new(mlua::Error::runtime(format!(
|
||||||
|
"got more args \
|
||||||
|
than format areas in the string. Expected {}, got {}.",
|
||||||
|
formats.len(),
|
||||||
|
arg_num
|
||||||
|
))),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if arg_num < formats.len() {
|
formatted = format!("{}{}", formatted, text);
|
||||||
return Err(elua::Error::BadArgument {
|
|
||||||
func: Some("printf".to_string()),
|
|
||||||
arg_index: 2,
|
|
||||||
arg_name: Some("fmt...".to_string()),
|
|
||||||
error: Arc::new(elua::Error::Runtime(format!(
|
|
||||||
"got more args \
|
|
||||||
than format areas in the string. Expected {}, got {}.", formats.len(), arg_num
|
|
||||||
)))
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
formatted = format!("{}{}", formatted, text);
|
|
||||||
|
|
||||||
lua.globals()?
|
lua.globals()
|
||||||
.get::<_, elua::Function>("print")?
|
.get::<mlua::Function>("print")?
|
||||||
.exec::<_, ()>(formatted)?;
|
.call::<()>(formatted)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
};
|
};
|
||||||
|
|
||||||
let script_name_reg = ctx.registry_insert(data.name.clone())?;
|
let script_name_reg = ctx.create_registry_value(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_get::<String>(script_name_reg)?;
|
let name = lua.registry_value::<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);
|
||||||
|
@ -117,18 +141,42 @@ impl ScriptApiProvider for UtilityApiProvider {
|
||||||
Ok(())
|
Ok(())
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
let globals = ctx.globals()?;
|
// a custom implementation of `getmetatable` is required since mlua protects __metatable,
|
||||||
|
// 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(&mut self, _data: &ScriptData, _ctx: &mut Self::ScriptContext) -> Result<(), crate::ScriptError> {
|
fn setup_script(
|
||||||
|
&mut self,
|
||||||
|
_data: &ScriptData,
|
||||||
|
_ctx: &mut Self::ScriptContext,
|
||||||
|
) -> Result<(), crate::ScriptError> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_script_environment(&mut self, _world: crate::ScriptWorldPtr, _data: &ScriptData, _ctx: &mut Self::ScriptContext) -> Result<(), crate::ScriptError> {
|
fn update_script_environment(
|
||||||
|
&mut self,
|
||||||
|
_world: crate::ScriptWorldPtr,
|
||||||
|
_data: &ScriptData,
|
||||||
|
_ctx: &mut Self::ScriptContext,
|
||||||
|
) -> Result<(), crate::ScriptError> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
use std::{any::TypeId, collections::HashMap, ptr::NonNull};
|
use std::{any::TypeId, collections::HashMap, ptr::NonNull};
|
||||||
|
|
||||||
use elua::{FromLua, TableProxy, AsLua};
|
use mlua::{ObjectLike, IntoLua};
|
||||||
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::FN_NAME_INTERNAL_REFLECT;
|
use super::{Error, 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,40 +15,39 @@ 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<'lua>(
|
fn as_lua_value(
|
||||||
lua: &'lua elua::State,
|
lua: &mlua::Lua,
|
||||||
this: &dyn Reflect,
|
this: &dyn Reflect,
|
||||||
) -> elua::Result<elua::Value<'lua>>;
|
) -> mlua::Result<mlua::Value>;
|
||||||
|
|
||||||
fn apply(
|
fn apply(
|
||||||
lua: &elua::State,
|
lua: &mlua::Lua,
|
||||||
this: &mut dyn Reflect,
|
this: &mut dyn Reflect,
|
||||||
value: &elua::Value,
|
value: &mlua::Value,
|
||||||
) -> elua::Result<()>;
|
) -> mlua::Result<()>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, T> LuaProxy for T
|
impl<'a, T> LuaProxy for T
|
||||||
where
|
where
|
||||||
T: Reflect + Clone + elua::FromLua<'a> + elua::Userdata
|
T: Reflect + Clone + mlua::FromLua + mlua::UserData
|
||||||
{
|
{
|
||||||
fn as_lua_value<'lua>(
|
fn as_lua_value(
|
||||||
lua: &'lua elua::State,
|
lua: &mlua::Lua,
|
||||||
this: &dyn Reflect,
|
this: &dyn Reflect,
|
||||||
) -> elua::Result<elua::Value<'lua>> {
|
) -> mlua::Result<mlua::Value> {
|
||||||
let this = this.as_any().downcast_ref::<T>().unwrap();
|
let this = this.as_any().downcast_ref::<T>().unwrap();
|
||||||
lua.create_userdata(this.clone())
|
this.clone().into_lua(lua)
|
||||||
.and_then(|ud| ud.as_lua(lua))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn apply(
|
fn apply(
|
||||||
_: &elua::State,
|
_: &mlua::Lua,
|
||||||
this: &mut dyn Reflect,
|
this: &mut dyn Reflect,
|
||||||
apply: &elua::Value,
|
apply: &mlua::Value,
|
||||||
) -> elua::Result<()> {
|
) -> mlua::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")
|
||||||
.as_ref::<T>()?;
|
.borrow::<T>()?;
|
||||||
|
|
||||||
*this = apply.clone();
|
*this = apply.clone();
|
||||||
|
|
||||||
|
@ -67,12 +66,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 elua::State, this_ptr: NonNull<()>) -> elua::Result<elua::Value<'a>>,
|
for<'a> fn(lua: &'a mlua::Lua, this_ptr: NonNull<()>) -> mlua::Result<mlua::Value>,
|
||||||
pub fn_apply: for<'a> fn(
|
pub fn_apply: for<'a> fn(
|
||||||
lua: &'a elua::State,
|
lua: &'a mlua::Lua,
|
||||||
this_ptr: NonNull<()>,
|
this_ptr: NonNull<()>,
|
||||||
value: &'a elua::Value<'a>,
|
value: &'a mlua::Value,
|
||||||
) -> elua::Result<()>,
|
) -> mlua::Result<()>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ReflectLuaProxy {
|
impl ReflectLuaProxy {
|
||||||
|
@ -82,7 +81,7 @@ impl ReflectLuaProxy {
|
||||||
T: Reflect + LuaProxy
|
T: Reflect + LuaProxy
|
||||||
{
|
{
|
||||||
Self {
|
Self {
|
||||||
fn_as_lua: |lua, this| -> elua::Result<elua::Value> {
|
fn_as_lua: |lua, this| -> mlua::Result<mlua::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)
|
||||||
},
|
},
|
||||||
|
@ -93,42 +92,19 @@ impl ReflectLuaProxy {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_table_proxy<T>() -> Self
|
|
||||||
where
|
|
||||||
T: TableProxy
|
|
||||||
{
|
|
||||||
Self {
|
|
||||||
fn_as_lua: |lua, this| -> elua::Result<elua::Value> {
|
|
||||||
let this = unsafe { this.cast::<T>().as_ref() };
|
|
||||||
this.as_table(lua)
|
|
||||||
.and_then(|t| t.as_lua(lua))
|
|
||||||
},
|
|
||||||
fn_apply: |lua, ptr, value| {
|
|
||||||
let this = unsafe { ptr.cast::<T>().as_mut() };
|
|
||||||
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
|
/// Create from a type that implements FromLua and AsLua
|
||||||
pub fn from_as_and_from_lua<T>() -> Self
|
pub fn from_as_and_from_lua<T>() -> Self
|
||||||
where
|
where
|
||||||
T: for<'a> elua::FromLua<'a> + for<'a> elua::AsLua<'a> + Clone
|
T: mlua::FromLua + mlua::IntoLua + Clone
|
||||||
{
|
{
|
||||||
Self {
|
Self {
|
||||||
fn_as_lua: |lua, this| -> elua::Result<elua::Value> {
|
fn_as_lua: |lua, this| -> mlua::Result<mlua::Value> {
|
||||||
let this = unsafe { this.cast::<T>().as_ref() };
|
let this = unsafe { this.cast::<T>().as_ref() };
|
||||||
this.clone().as_lua(lua)
|
this.clone().into_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(lua, value.clone())?;
|
let new_val = T::from_lua(value.clone(), lua)?;
|
||||||
|
|
||||||
*this = new_val;
|
*this = new_val;
|
||||||
|
|
||||||
|
@ -138,42 +114,27 @@ impl ReflectLuaProxy {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'lua> elua::FromLua<'lua> for ScriptDynamicBundle {
|
impl mlua::FromLua for ScriptDynamicBundle {
|
||||||
fn from_lua(_: &'lua elua::State, val: elua::Value<'lua>) -> elua::Result<Self> {
|
fn from_lua(val: mlua::Value, _: &mlua::Lua) -> mlua::Result<Self> {
|
||||||
match val {
|
match val {
|
||||||
elua::Value::Userdata(ud) => Ok(ud.as_ref::<Self>()?.clone()),
|
mlua::Value::UserData(ud) => Ok(ud.borrow::<Self>()?.clone()),
|
||||||
elua::Value::Nil => Err(elua::Error::Nil),
|
mlua::Value::Nil => Err(Error::Nil.into()),
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'lua> elua::FromLuaVec<'lua> for ScriptDynamicBundle {
|
impl mlua::UserData for ScriptDynamicBundle {
|
||||||
fn from_lua_value_vec(state: &'lua elua::State, mut values: elua::ValueVec<'lua>) -> elua::Result<Self> {
|
fn add_methods<M: mlua::UserDataMethods<Self>>(methods: &mut M) {
|
||||||
if let Some(v) = values.pop_front() {
|
methods.add_function("new", |_, ()| Ok(ScriptDynamicBundle(DynamicBundle::new())));
|
||||||
Ok(ScriptDynamicBundle::from_lua(state, v)?)
|
methods.add_method_mut("push", |_, this, comp: mlua::AnyUserData| {
|
||||||
} else {
|
let script_brw = comp.call_method::<ScriptBorrow>(FN_NAME_INTERNAL_REFLECT, ())?;
|
||||||
Err(elua::Error::Nil)
|
let reflect = script_brw.reflect_branch.as_component_unchecked();
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl elua::Userdata for ScriptDynamicBundle {
|
let refl_data = script_brw.data.unwrap();
|
||||||
fn name() -> String {
|
reflect.bundle_insert(&mut this.0, refl_data);
|
||||||
"Bundle".to_string()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn build<'a>(builder: &mut elua::UserdataBuilder<'a, Self>) {
|
Ok(())
|
||||||
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 refl_data = script_brw.data.unwrap();
|
|
||||||
reflect.bundle_insert(&mut this.0, refl_data);
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,31 +1,32 @@
|
||||||
use std::sync::Mutex;
|
use std::sync::Mutex;
|
||||||
|
|
||||||
use elua::{AsLua, StdLibraries};
|
use mlua::{IntoLua, StdLib};
|
||||||
|
|
||||||
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: &elua::State, fn_name: &str) -> Result<(), ScriptError> {
|
fn try_call_lua_function(lua: &mlua::Lua, fn_name: &str) -> Result<(), ScriptError> {
|
||||||
let globals = lua.globals()?;
|
let globals = lua.globals();
|
||||||
|
|
||||||
if globals.has_key(fn_name)? {
|
if globals.contains_key(fn_name)? {
|
||||||
let lua_fn = globals.get::<_, elua::Function>(fn_name)?;
|
let lua_fn = globals.get::<mlua::Function>(fn_name)?;
|
||||||
lua_fn.exec(())
|
lua_fn.call::<()>(())
|
||||||
.map_err(ScriptError::MluaError)?;
|
.map_err(ScriptError::from)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ScriptHost for LuaHost {
|
impl ScriptHost for LuaHost {
|
||||||
type ScriptContext = Mutex<elua::State>;
|
type ScriptContext = Mutex<mlua::Lua>;
|
||||||
|
|
||||||
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({
|
||||||
let s = elua::State::new();
|
// unsafe is required to allow the debug module
|
||||||
s.expose_libraries(StdLibraries::all());
|
let s = unsafe { mlua::Lua::unsafe_new() };
|
||||||
|
s.load_std_libs(StdLib::ALL)?;
|
||||||
s
|
s
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -35,9 +36,9 @@ impl ScriptHost for LuaHost {
|
||||||
}
|
}
|
||||||
|
|
||||||
let lua = ctx.lock().unwrap();
|
let lua = ctx.lock().unwrap();
|
||||||
lua.load(&script_data.name, script)?
|
lua.load(script)
|
||||||
.execute(())
|
.exec()
|
||||||
.map_err(|e| ScriptError::MluaError(e))?;
|
.map_err(|e| ScriptError::LuaError(super::Error::Mlua(e)))?;
|
||||||
drop(lua);
|
drop(lua);
|
||||||
|
|
||||||
Ok(ctx)
|
Ok(ctx)
|
||||||
|
@ -65,9 +66,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.as_lua(&ctx)?)?;
|
globals.set("world", world.into_lua(&ctx)?)?;
|
||||||
globals.set("entity", ScriptEntity(script_data.entity).as_lua(&ctx)?)?;
|
globals.set("entity", ScriptEntity(script_data.entity).into_lua(&ctx)?)?;
|
||||||
|
|
||||||
try_call_lua_function(&ctx, function_name)?;
|
try_call_lua_function(&ctx, function_name)?;
|
||||||
|
|
||||||
|
|
|
@ -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, ScriptWorldPtr};
|
use crate::{GameScriptExt, ScriptApiProviders, ScriptContexts, ScriptData, ScriptError, ScriptHost, ScriptList, ScriptWorldPtrGuard};
|
||||||
|
|
||||||
use super::{providers::{LyraEcsApiProvider, LyraMathApiProvider, UtilityApiProvider}, LuaContext, LuaHost, LuaLoader, LuaScript};
|
use super::{providers::{LyraEcsApiProvider, LyraMathApiProvider, UtilityApiProvider}, LuaContext, LuaHost, LuaLoader, LuaScript};
|
||||||
|
|
||||||
|
@ -40,7 +40,8 @@ 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_ptr = ScriptWorldPtr::from_ref(&world);
|
let world_guard = unsafe { ScriptWorldPtrGuard::new(world) };
|
||||||
|
let world_ptr = (*world_guard).clone();
|
||||||
match host.call_script(
|
match host.call_script(
|
||||||
world_ptr,
|
world_ptr,
|
||||||
&script_data,
|
&script_data,
|
||||||
|
@ -50,7 +51,7 @@ pub fn lua_scripts_create_contexts(
|
||||||
) {
|
) {
|
||||||
Ok(()) => {}
|
Ok(()) => {}
|
||||||
Err(e) => match e {
|
Err(e) => match e {
|
||||||
ScriptError::MluaError(m) => {
|
ScriptError::LuaError(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()),
|
||||||
|
@ -114,10 +115,11 @@ 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_ptr = ScriptWorldPtr::from_ref(&world);
|
let world_guard = unsafe { ScriptWorldPtrGuard::new(world) };
|
||||||
let mut host = world.get_resource_mut::<LuaHost>();
|
let world_ptr = (*world_guard).clone();
|
||||||
let mut contexts = world.get_resource_mut::<ScriptContexts<LuaContext>>();
|
let mut host = world.get_resource_mut::<LuaHost>().unwrap();
|
||||||
let mut providers = world.get_resource_mut::<ScriptApiProviders<LuaHost>>();
|
let mut contexts = world.get_resource_mut::<ScriptContexts<LuaContext>>().unwrap();
|
||||||
|
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() {
|
||||||
|
@ -143,7 +145,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::MluaError(m) => {
|
ScriptError::LuaError(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()),
|
||||||
|
@ -190,8 +192,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, game: &mut lyra_game::game::Game) {
|
fn setup(&mut self, app: &mut lyra_game::game::App) {
|
||||||
let world = game.world_mut();
|
let world = &mut app.world;
|
||||||
|
|
||||||
world.add_resource_default::<TypeRegistry>();
|
world.add_resource_default::<TypeRegistry>();
|
||||||
|
|
||||||
|
@ -200,16 +202,16 @@ impl Plugin for LuaScriptingPlugin {
|
||||||
world.add_resource_default::<ScriptContexts<LuaContext>>();
|
world.add_resource_default::<ScriptContexts<LuaContext>>();
|
||||||
|
|
||||||
let loader = world
|
let loader = world
|
||||||
.try_get_resource_mut::<ResourceManager>()
|
.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);
|
||||||
|
|
||||||
game.add_script_api_provider::<LuaHost, _>(UtilityApiProvider);
|
app.add_script_api_provider::<LuaHost, _>(UtilityApiProvider);
|
||||||
game.add_script_api_provider::<LuaHost, _>(LyraEcsApiProvider);
|
app.add_script_api_provider::<LuaHost, _>(LyraEcsApiProvider);
|
||||||
game.add_script_api_provider::<LuaHost, _>(LyraMathApiProvider);
|
app.add_script_api_provider::<LuaHost, _>(LyraMathApiProvider);
|
||||||
|
|
||||||
game.add_system_to_stage(
|
app.add_system_to_stage(
|
||||||
GameStages::First,
|
GameStages::First,
|
||||||
"lua_create_contexts",
|
"lua_create_contexts",
|
||||||
lua_scripts_create_contexts,
|
lua_scripts_create_contexts,
|
||||||
|
|
|
@ -1,32 +1,31 @@
|
||||||
use std::{ptr::NonNull, sync::Arc};
|
use std::{ops::DerefMut, ptr::NonNull, sync::Arc};
|
||||||
|
|
||||||
use crate::{ScriptBorrow, ScriptEntity, ScriptWorldPtr};
|
use crate::{ScriptBorrow, ScriptEntity, ScriptWorldPtr};
|
||||||
use elua::AsLua;
|
use lyra_ecs::{
|
||||||
use lyra_ecs::{query::dynamic::{DynamicViewState, DynamicViewStateIter, QueryDynamicType}, CommandQueue, Commands, DynamicBundle, World};
|
query::dynamic::{DynamicViewState, DynamicViewStateIter, QueryDynamicType},
|
||||||
|
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, LuaTableProxyLookup, ReflectLuaProxy, ReflectedIterator, FN_NAME_INTERNAL_AS_COMPONENT, FN_NAME_INTERNAL_REFLECT, FN_NAME_INTERNAL_REFLECT_TYPE
|
reflect_user_data, wrappers::LuaResHandleToComponent, Error, LuaTableProxyLookup, ReflectLuaProxy, ReflectedIterator, FN_NAME_INTERNAL_AS_COMPONENT, FN_NAME_INTERNAL_REFLECT, FN_NAME_INTERNAL_REFLECT_TYPE
|
||||||
};
|
};
|
||||||
|
|
||||||
impl<'lua> elua::FromLua<'lua> for ScriptEntity {
|
impl mlua::FromLua for ScriptEntity {
|
||||||
fn from_lua(_: &'lua elua::State, value: elua::Value<'lua>) -> elua::Result<Self> {
|
fn from_lua(value: mlua::Value, _: &mlua::Lua) -> mlua::Result<Self> {
|
||||||
match value {
|
match value {
|
||||||
elua::Value::Userdata(ud) => Ok(ud.as_ref::<Self>()?.clone()),
|
mlua::Value::UserData(ud) => Ok(ud.borrow::<Self>()?.clone()),
|
||||||
elua::Value::Nil => Err(elua::Error::type_mismatch("ScriptEntity", "Nil")),
|
mlua::Value::Nil => Err(mlua::Error::external(Error::type_mismatch("ScriptEntity", "Nil"))),
|
||||||
_ => panic!(),
|
_ => panic!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl elua::Userdata for ScriptEntity {
|
impl mlua::UserData for ScriptEntity {
|
||||||
fn name() -> String {
|
fn add_methods<M: mlua::UserDataMethods<Self>>(methods: &mut M) {
|
||||||
"Entity".to_string()
|
methods.add_meta_method(mlua::MetaMethod::ToString, |_, this, ()| {
|
||||||
}
|
|
||||||
|
|
||||||
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))
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -38,279 +37,278 @@ pub enum WorldError {
|
||||||
LuaInvalidUsage(String),
|
LuaInvalidUsage(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> elua::FromLua<'a> for ScriptWorldPtr {
|
impl mlua::FromLua for ScriptWorldPtr {
|
||||||
fn from_lua(_: &'a elua::State, val: elua::Value<'a>) -> elua::Result<Self> {
|
fn from_lua(val: mlua::Value, _: &mlua::Lua) -> mlua::Result<Self> {
|
||||||
match val {
|
match val {
|
||||||
elua::Value::Userdata(ud) => Ok(ud.as_ref::<Self>()?.clone()),
|
mlua::Value::UserData(ud) => Ok(ud.borrow::<Self>()?.clone()),
|
||||||
elua::Value::Nil => Err(elua::Error::type_mismatch("ScriptWorldPtr", "Nil")),
|
mlua::Value::Nil => Err(mlua::Error::external(Error::type_mismatch("ScriptWorldPtr", "Nil"))),
|
||||||
_ => panic!(),
|
_ => panic!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl elua::Userdata for ScriptWorldPtr {
|
impl mlua::UserData for ScriptWorldPtr {
|
||||||
fn name() -> String {
|
fn add_methods<M: mlua::UserDataMethods<Self>>(methods: &mut M) {
|
||||||
"World".to_string()
|
methods.add_method_mut("spawn", |_, this, vals: mlua::MultiValue| {
|
||||||
}
|
let mut world = this.write();
|
||||||
|
|
||||||
fn build<'a>(builder: &mut elua::UserdataBuilder<'a, Self>) {
|
let mut bundle = DynamicBundle::new();
|
||||||
builder
|
|
||||||
.method_mut("spawn", |_, this, vals: elua::ValueVec| {
|
|
||||||
let world = this.as_mut();
|
|
||||||
|
|
||||||
let mut bundle = DynamicBundle::new();
|
//while let Some(val) = vals.pop_front() {
|
||||||
|
for (i, val) in vals.into_iter().enumerate() {
|
||||||
|
let ud = val.as_userdata().ok_or(mlua::Error::BadArgument {
|
||||||
|
to: Some("World:spawn".into()),
|
||||||
|
pos: 2 + i, // i starts at 0
|
||||||
|
name: Some("components...".into()),
|
||||||
|
cause: Arc::new(mlua::Error::runtime("provided component is not userdata")),
|
||||||
|
})?;
|
||||||
|
|
||||||
//while let Some(val) = vals.pop_front() {
|
let comp_borrow = {
|
||||||
for (i, val) in vals.into_iter().enumerate() {
|
if let Ok(as_comp) = ud.get::<mlua::Function>(FN_NAME_INTERNAL_AS_COMPONENT)
|
||||||
let ud = val.as_userdata().ok_or(
|
{
|
||||||
elua::Error::bad_arg(
|
let ud = match as_comp.call(ud.clone())? {
|
||||||
Some("World:spawn"),
|
mlua::Value::UserData(ud) => ud,
|
||||||
2 + i as i32, // i starts at 0
|
mlua::Value::Nil => ud.clone(),
|
||||||
Some("components..."),
|
_ => todo!(),
|
||||||
Arc::new(elua::Error::runtime("provided component is not userdata")),
|
};
|
||||||
))?;
|
|
||||||
|
|
||||||
let comp_borrow = {
|
|
||||||
if let Ok(as_comp) = ud.get::<_, elua::Function>(FN_NAME_INTERNAL_AS_COMPONENT) {
|
|
||||||
let ud = match as_comp.exec(ud.clone())? {
|
|
||||||
elua::Value::Userdata(ud) => ud,
|
|
||||||
elua::Value::Nil => ud.clone(),
|
|
||||||
_ => todo!(),
|
|
||||||
};
|
|
||||||
|
|
||||||
ud.execute_method::<_, ScriptBorrow>(FN_NAME_INTERNAL_REFLECT, ())?
|
ud.call_method::<ScriptBorrow>(FN_NAME_INTERNAL_REFLECT, ())?
|
||||||
} else {
|
} else {
|
||||||
ud.execute_method::<_, ScriptBorrow>(FN_NAME_INTERNAL_REFLECT, ())?
|
ud.call_method::<ScriptBorrow>(FN_NAME_INTERNAL_REFLECT, ())?
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let reflect = comp_borrow.reflect_branch.as_component_unchecked();
|
let reflect = comp_borrow.reflect_branch.as_component_unchecked();
|
||||||
let refl_data = comp_borrow.data.unwrap();
|
let refl_data = comp_borrow.data.unwrap();
|
||||||
reflect.bundle_insert(&mut bundle, refl_data);
|
reflect.bundle_insert(&mut bundle, refl_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
// defer the entity spawn
|
||||||
|
// SAFETY: Commands borrows Entities from World, the resource borrows from the world resources,
|
||||||
|
// They are borrowing different parts of World.
|
||||||
|
let world_ptr: *mut World = world.deref_mut();
|
||||||
|
let mut commands_queue = world.get_resource_mut::<CommandQueue>().unwrap();
|
||||||
|
let mut commands = Commands::new(&mut commands_queue, unsafe { &mut *world_ptr });
|
||||||
|
let entity = commands.spawn(bundle);
|
||||||
|
|
||||||
|
Ok(ScriptEntity(entity))
|
||||||
|
});
|
||||||
|
methods.add_method_mut(
|
||||||
|
"view",
|
||||||
|
|lua, this, (system, queries): (mlua::Function, mlua::MultiValue)| {
|
||||||
|
if queries.is_empty() {
|
||||||
|
return Err(mlua::Error::BadArgument {
|
||||||
|
to: Some("World:view".into()),
|
||||||
|
pos: 2,
|
||||||
|
name: Some("query...".into()),
|
||||||
|
cause: Arc::new(mlua::Error::external(WorldError::LuaInvalidUsage(
|
||||||
|
"no component types provided".into(),
|
||||||
|
))),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// defer the entity spawn
|
let world = this.read();
|
||||||
// safety: Commands borrows Entities from World, the resource borrows from the world resouces,
|
let mut view = DynamicViewState::new();
|
||||||
// they are borrowing different parts of World.
|
|
||||||
let world_ptr: *mut World = world;
|
|
||||||
let mut commands_queue = world.get_resource_mut::<CommandQueue>();
|
|
||||||
let mut commands = Commands::new(&mut commands_queue, unsafe { &mut *world_ptr });
|
|
||||||
let entity = commands.spawn(bundle);
|
|
||||||
|
|
||||||
Ok(ScriptEntity(entity))
|
for (idx, comp) in queries.into_iter().enumerate() {
|
||||||
})
|
match comp {
|
||||||
.method_mut(
|
mlua::Value::Table(t) => {
|
||||||
"view",
|
let name: String = t.get(mlua::MetaMethod::Type.name())?;
|
||||||
|lua, this, (system, queries): (elua::Function, elua::ValueVec)| {
|
|
||||||
if queries.is_empty() {
|
|
||||||
return Err(elua::Error::BadArgument {
|
|
||||||
func: Some("World:view".to_string()),
|
|
||||||
arg_index: 2,
|
|
||||||
arg_name: Some("query...".to_string()),
|
|
||||||
error: Arc::new(elua::Error::other(WorldError::LuaInvalidUsage(
|
|
||||||
"no component types provided".to_string(),
|
|
||||||
))),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
let world = unsafe { this.inner.as_ref() };
|
let lookup = world.get_resource::<LuaTableProxyLookup>().ok_or(
|
||||||
//let mut view = world.dynamic_view();
|
mlua::Error::runtime(
|
||||||
let mut view = DynamicViewState::new();
|
"Unable to lookup table proxy, none were ever registered!",
|
||||||
|
),
|
||||||
for (idx, comp) in queries.into_iter().enumerate() {
|
)?;
|
||||||
match comp {
|
let info = lookup.comp_info_from_name.get(&name).ok_or_else(|| {
|
||||||
elua::Value::Table(t) => {
|
mlua::Error::BadArgument {
|
||||||
let name: String = t.get(elua::MetaMethod::Name)?;
|
to: Some("World:view".into()),
|
||||||
|
pos: 2 + idx,
|
||||||
let lookup = world
|
name: Some("query...".into()),
|
||||||
.try_get_resource::<LuaTableProxyLookup>()
|
cause: Arc::new(mlua::Error::external(
|
||||||
.ok_or(elua::Error::runtime(
|
WorldError::LuaInvalidUsage(format!(
|
||||||
"Unable to lookup table proxy, none were ever registered!",
|
|
||||||
))?;
|
|
||||||
let info = lookup.comp_info_from_name.get(&name).ok_or_else(
|
|
||||||
|| elua::Error::BadArgument {
|
|
||||||
func: Some("World:view".to_string()),
|
|
||||||
arg_index: 2 + idx as i32,
|
|
||||||
arg_name: Some("query...".to_string()),
|
|
||||||
error: Arc::new(elua::Error::Runtime(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);
|
||||||
}
|
|
||||||
elua::Value::Userdata(ud) => {
|
|
||||||
let reflect = ud
|
|
||||||
.execute_function::<_, ScriptBorrow>(
|
|
||||||
FN_NAME_INTERNAL_REFLECT_TYPE,
|
|
||||||
(),
|
|
||||||
)
|
|
||||||
.expect("Type does not implement 'reflect_type' properly");
|
|
||||||
let refl_comp = reflect.reflect_branch.as_component_unchecked();
|
|
||||||
|
|
||||||
let dyn_type = QueryDynamicType::from_info(refl_comp.info);
|
|
||||||
view.push(dyn_type);
|
|
||||||
}
|
|
||||||
_ => todo!(),
|
|
||||||
}
|
}
|
||||||
}
|
mlua::Value::UserData(ud) => {
|
||||||
|
let reflect = ud
|
||||||
|
.call_function::<ScriptBorrow>(
|
||||||
|
FN_NAME_INTERNAL_REFLECT_TYPE,
|
||||||
|
(),
|
||||||
|
)
|
||||||
|
.expect("Type does not implement 'reflect_type' properly");
|
||||||
|
let refl_comp = reflect.reflect_branch.as_component_unchecked();
|
||||||
|
|
||||||
let iter = view.into_iter();
|
let dyn_type = QueryDynamicType::from_info(refl_comp.info);
|
||||||
let mut reflected_iter = ReflectedIterator {
|
view.push(dyn_type);
|
||||||
world: this.clone(),
|
|
||||||
dyn_view: DynamicViewStateIter::from(iter),
|
|
||||||
reflected_components: None,
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut current = world.current_tick();
|
|
||||||
let mut has_ticked = false;
|
|
||||||
|
|
||||||
while let Some(row) = reflected_iter.next_lua(lua) {
|
|
||||||
let r = row
|
|
||||||
.row
|
|
||||||
.into_iter()
|
|
||||||
.map(|r| (r.comp_val, r.comp_ptr.cast::<()>()))
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
let (values, ptrs) =
|
|
||||||
itertools::multiunzip::<(Vec<elua::Value>, Vec<NonNull<()>>), _>(r);
|
|
||||||
let mult_val = elua::ValueVec::from(values);
|
|
||||||
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 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) {
|
|
||||||
let lua_typeid = match &comp {
|
|
||||||
elua::Value::Userdata(ud) => {
|
|
||||||
let lua_comp = reflect_user_data(ud);
|
|
||||||
let refl_comp =
|
|
||||||
lua_comp.reflect_branch.as_component_unchecked();
|
|
||||||
refl_comp.info.type_id().as_rust()
|
|
||||||
},
|
|
||||||
elua::Value::Table(tbl) => {
|
|
||||||
let name: String = tbl.get(elua::MetaMethod::Name)?;
|
|
||||||
|
|
||||||
let lookup = world.get_resource::<LuaTableProxyLookup>();
|
|
||||||
*lookup.typeid_from_name.get(&name).unwrap()
|
|
||||||
},
|
|
||||||
_ => {
|
|
||||||
panic!("A userdata or table value was not returned!");
|
|
||||||
// TODO: Handle properly
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// update the component tick
|
|
||||||
let world = unsafe { this.inner.as_mut() };
|
|
||||||
let arch = world.entity_archetype_mut(row.entity).unwrap();
|
|
||||||
let idx = arch.entity_indexes().get(&row.entity).unwrap().clone();
|
|
||||||
let c = arch.get_column_mut(lua_typeid).unwrap();
|
|
||||||
c.entity_ticks[idx.0 as usize] = current;
|
|
||||||
|
|
||||||
// apply the new component data
|
|
||||||
let reg = this.as_ref().get_resource::<TypeRegistry>();
|
|
||||||
let reg_type = reg.get_type(lua_typeid).unwrap();
|
|
||||||
|
|
||||||
let proxy = reg_type
|
|
||||||
.get_data::<ReflectLuaProxy>()
|
|
||||||
// this should actually be safe since the ReflectedIterator
|
|
||||||
// attempts to get the type data before it is tried here
|
|
||||||
.expect("Type does not have ReflectLuaProxy as a TypeData");
|
|
||||||
(proxy.fn_apply)(lua, ptr, &comp)?;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
let msg = format!(
|
|
||||||
"Too many arguments were returned from the World view!
|
|
||||||
At most, the expected number of results is {}.",
|
|
||||||
ptrs.len()
|
|
||||||
);
|
|
||||||
return Err(elua::Error::Runtime(msg));
|
|
||||||
}
|
}
|
||||||
|
_ => todo!(),
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
|
||||||
},
|
|
||||||
)
|
|
||||||
.method_mut("resource", |lua, this, (ty,): (elua::Value,)| {
|
|
||||||
let reflect = match ty {
|
|
||||||
elua::Value::Userdata(ud) => ud
|
|
||||||
.execute_function::<_, ScriptBorrow>(FN_NAME_INTERNAL_REFLECT_TYPE, ())
|
|
||||||
.expect("Type does not implement 'reflect_type' properly"),
|
|
||||||
elua::Value::Table(t) => {
|
|
||||||
let f: elua::Function = t.get(FN_NAME_INTERNAL_REFLECT_TYPE)?;
|
|
||||||
f.exec::<_, ScriptBorrow>(())
|
|
||||||
.expect("Type does not implement 'reflect_type' properly")
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
panic!("how");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
/* let reflect = ty
|
|
||||||
.execute_function::<_, ScriptBorrow>(FN_NAME_INTERNAL_REFLECT_TYPE, ())
|
|
||||||
.expect("Type does not implement 'reflect_type' properly"); */
|
|
||||||
|
|
||||||
let res = reflect.reflect_branch.as_resource_unchecked();
|
|
||||||
if let Some(res_ptr) = res.reflect_ptr(this.as_mut()) {
|
|
||||||
let reg_type = this
|
|
||||||
.as_ref()
|
|
||||||
.get_type::<RegisteredType>(reflect.reflect_branch.reflect_type_id())
|
|
||||||
.expect("Resource is not type registered!");
|
|
||||||
let proxy = reg_type
|
|
||||||
.get_data::<ReflectLuaProxy>()
|
|
||||||
.expect("Type does not have ReflectLuaProxy as a TypeData");
|
|
||||||
|
|
||||||
(proxy.fn_as_lua)(lua, res_ptr.cast()).and_then(|ud| ud.as_lua(lua))
|
|
||||||
} else {
|
|
||||||
// if the resource is not found in the world, return nil
|
|
||||||
Ok(elua::Value::Nil)
|
|
||||||
}
|
}
|
||||||
})
|
|
||||||
.method_mut("add_resource", |_, this, res: elua::Value| {
|
let iter = view.into_iter();
|
||||||
let reflect = match res {
|
let mut reflected_iter = ReflectedIterator {
|
||||||
elua::Value::Userdata(ud) => ud
|
// SAFETY: bypassing the borrow checker here to get a pointer of the world
|
||||||
.execute_method::<_, ScriptBorrow>(FN_NAME_INTERNAL_REFLECT, ())
|
// is required since we mutably borrow below. Its safe to do so since
|
||||||
.expect("Type does not implement 'reflect_type' properly"),
|
// only the entity ticks are updated. They are accessing different things
|
||||||
elua::Value::Table(t) => {
|
// from the world.
|
||||||
let f: elua::Function = t.get(FN_NAME_INTERNAL_REFLECT)?;
|
world: unsafe { NonNull::from(&*world).as_ref() },
|
||||||
f.exec::<_, ScriptBorrow>(())
|
dyn_view: DynamicViewStateIter::from(iter),
|
||||||
.expect("Type does not implement 'reflect_type' properly")
|
reflected_components: None,
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
panic!("how");
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let data = reflect.data
|
let current = world.current_tick();
|
||||||
.expect("Its expected that 'FN_NAME_INTERNAL_REFLECT' returns data in World:add_resource");
|
|
||||||
|
|
||||||
let res = reflect.reflect_branch.as_resource()
|
// drop read lock and acquire the write lock.
|
||||||
.ok_or(elua::Error::runtime("Provided type is not a resource!"))?;
|
// dropping must be done to avoid mutex deadlock
|
||||||
|
drop(world);
|
||||||
|
let mut world = this.write();
|
||||||
|
|
||||||
let world = this.as_mut();
|
while let Some(row) = reflected_iter.next_lua(lua) {
|
||||||
res.insert(world, data);
|
let r = row.row.into_iter()
|
||||||
|
.into_iter()
|
||||||
|
.map(|r| (r.comp_val, r.comp_ptr.cast::<()>()))
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
let (values, ptrs) =
|
||||||
|
itertools::multiunzip::<(Vec<mlua::Value>, Vec<NonNull<()>>), _>(r);
|
||||||
|
let mult_val = mlua::MultiValue::from_iter(values.into_iter());
|
||||||
|
let res: mlua::MultiValue = system.call(mult_val)?;
|
||||||
|
|
||||||
|
// if values were returned, find the type in the type registry, and apply the new values
|
||||||
|
if res.len() <= ptrs.len() {
|
||||||
|
|
||||||
|
for (comp, ptr) in res.into_iter().zip(ptrs) {
|
||||||
|
let lua_typeid = match &comp {
|
||||||
|
mlua::Value::UserData(ud) => {
|
||||||
|
let lua_comp = reflect_user_data(ud);
|
||||||
|
let refl_comp =
|
||||||
|
lua_comp.reflect_branch.as_component_unchecked();
|
||||||
|
refl_comp.info.type_id().as_rust()
|
||||||
|
}
|
||||||
|
mlua::Value::Table(tbl) => {
|
||||||
|
let name: String = tbl.get(mlua::MetaMethod::Type.name())?;
|
||||||
|
|
||||||
|
let lookup = world.get_resource::<LuaTableProxyLookup>().unwrap();
|
||||||
|
*lookup.typeid_from_name.get(&name).unwrap()
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
panic!("A userdata or table value was not returned!");
|
||||||
|
// TODO: Handle properly
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// update the component tick
|
||||||
|
let arch = world.entity_archetype_mut(row.entity).unwrap();
|
||||||
|
let idx = arch.entity_indexes().get(&row.entity).unwrap().clone();
|
||||||
|
let c = arch.get_column_mut(lua_typeid).unwrap();
|
||||||
|
c.entity_ticks[idx.0 as usize] = current;
|
||||||
|
|
||||||
|
// apply the new component data
|
||||||
|
let reg = world.get_resource::<TypeRegistry>().unwrap();
|
||||||
|
let reg_type = reg.get_type(lua_typeid).unwrap();
|
||||||
|
|
||||||
|
let proxy = reg_type
|
||||||
|
.get_data::<ReflectLuaProxy>()
|
||||||
|
// this should actually be safe since the ReflectedIterator
|
||||||
|
// attempts to get the type data before it is tried here
|
||||||
|
.expect("Type does not have ReflectLuaProxy as a TypeData");
|
||||||
|
(proxy.fn_apply)(lua, ptr, &comp)?;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let msg = format!(
|
||||||
|
"Too many arguments were returned from the World view!
|
||||||
|
At most, the expected number of results is {}.",
|
||||||
|
ptrs.len()
|
||||||
|
);
|
||||||
|
return Err(mlua::Error::runtime(msg));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
})
|
},
|
||||||
.method_mut("request_res", |lua, this, path: String| {
|
);
|
||||||
let world: &mut World = this.as_mut();
|
methods.add_method_mut("resource", |lua, this, (ty,): (mlua::Value,)| {
|
||||||
let man = world.get_resource_mut::<ResourceManager>();
|
let reflect = match ty {
|
||||||
let handle = man.request_raw(&path).unwrap();
|
mlua::Value::UserData(ud) => ud
|
||||||
|
.call_function::<ScriptBorrow>(FN_NAME_INTERNAL_REFLECT_TYPE, ())
|
||||||
|
.expect("Type does not implement 'reflect_type' properly"),
|
||||||
|
mlua::Value::Table(t) => {
|
||||||
|
let f: mlua::Function = t.get(FN_NAME_INTERNAL_REFLECT_TYPE)?;
|
||||||
|
f.call::<ScriptBorrow>(())
|
||||||
|
.expect("Type does not implement 'reflect_type' properly")
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
panic!("how");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// get the actual resource handle wrapper
|
let mut world = this.write();
|
||||||
let registry = world.get_resource::<TypeRegistry>();
|
let res = reflect.reflect_branch.as_resource_unchecked();
|
||||||
let ty = registry.get_type(handle.resource_type_id())
|
if let Some(res_ptr) = res.reflect_ptr(&mut world) {
|
||||||
.expect("Could not find asset type in registry");
|
let reg_type = world
|
||||||
let data = ty.get_data::<LuaResHandleToComponent>()
|
.get_type::<RegisteredType>(reflect.reflect_branch.reflect_type_id())
|
||||||
.expect("Asset type does not have 'LuaResHandleToComponent' as TypeData");
|
.expect("Resource is not type registered!");
|
||||||
|
let proxy = reg_type
|
||||||
|
.get_data::<ReflectLuaProxy>()
|
||||||
|
.expect("Type does not have ReflectLuaProxy as a TypeData");
|
||||||
|
|
||||||
Ok((data.fn_to_lua)(lua, handle).unwrap())
|
(proxy.fn_as_lua)(lua, res_ptr.cast()).and_then(|ud| ud.into_lua(lua))
|
||||||
});
|
} else {
|
||||||
|
// if the resource is not found in the world, return nil
|
||||||
|
Ok(mlua::Value::Nil)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
methods.add_method_mut("add_resource", |_, this, res: mlua::Value| {
|
||||||
|
let reflect = match res {
|
||||||
|
mlua::Value::UserData(ud) => ud
|
||||||
|
.call_method::<ScriptBorrow>(FN_NAME_INTERNAL_REFLECT, ())
|
||||||
|
.expect("Type does not implement 'reflect_type' properly"),
|
||||||
|
mlua::Value::Table(t) => {
|
||||||
|
let f: mlua::Function = t.get(FN_NAME_INTERNAL_REFLECT)?;
|
||||||
|
f.call::<ScriptBorrow>(())
|
||||||
|
.expect("Type does not implement 'reflect_type' properly")
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
panic!("how");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let data = reflect.data.expect(
|
||||||
|
"Its expected that 'FN_NAME_INTERNAL_REFLECT' returns data in World:add_resource",
|
||||||
|
);
|
||||||
|
|
||||||
|
let res = reflect
|
||||||
|
.reflect_branch
|
||||||
|
.as_resource()
|
||||||
|
.ok_or(mlua::Error::runtime("Provided type is not a resource!"))?;
|
||||||
|
|
||||||
|
let mut world = this.write();
|
||||||
|
res.insert(&mut world, data);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
});
|
||||||
|
methods.add_method_mut("request_res", |lua, this, path: String| {
|
||||||
|
let world = this.write();
|
||||||
|
let man = world.get_resource_mut::<ResourceManager>().unwrap();
|
||||||
|
let handle = man.request_raw(&path).unwrap();
|
||||||
|
|
||||||
|
// get the actual resource handle wrapper
|
||||||
|
let registry = world.get_resource::<TypeRegistry>().unwrap();
|
||||||
|
let ty = registry
|
||||||
|
.get_type(handle.resource_type_id())
|
||||||
|
.expect("Could not find asset type in registry");
|
||||||
|
let data = ty
|
||||||
|
.get_data::<LuaResHandleToComponent>()
|
||||||
|
.expect("Asset type does not have 'LuaResHandleToComponent' as TypeData");
|
||||||
|
|
||||||
|
Ok((data.fn_to_lua)(lua, handle).unwrap())
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,21 +1,23 @@
|
||||||
use std::{any::TypeId, ops::Deref};
|
use std::{any::TypeId, ops::Deref};
|
||||||
use elua::{AnyUserdata, AsLua, FromLua, State, Value};
|
//use mlua::{AnyUserData, IntoLua, FromLua, Lua, 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::{LuaWrapper, FN_NAME_INTERNAL_AS_COMPONENT, FN_NAME_INTERNAL_REFLECT, FN_NAME_INTERNAL_REFLECT_TYPE}, lyra_engine, ScriptBorrow};
|
use crate::{lua::{Error, 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(&State, UntypedResHandle) -> Option<AnyUserdata>,
|
pub fn_to_lua: fn(&mlua::Lua, UntypedResHandle) -> Option<mlua::AnyUserData>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LuaResHandleToComponent {
|
impl LuaResHandleToComponent {
|
||||||
pub fn new(f: fn(&State, UntypedResHandle) -> Option<AnyUserdata>) -> Self {
|
pub fn new(f: fn(&mlua::Lua, UntypedResHandle) -> Option<mlua::AnyUserData>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
fn_to_lua: f
|
fn_to_lua: f
|
||||||
}
|
}
|
||||||
|
@ -53,16 +55,12 @@ impl From<UntypedResHandle> for LuaResHandle {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl elua::Userdata for LuaResHandle {
|
impl mlua::UserData for LuaResHandle {
|
||||||
fn name() -> String {
|
fn add_fields<F: mlua::UserDataFields<Self>>(fields: &mut F) {
|
||||||
"Handle".to_string()
|
fields.add_field_method_get("path", |_, this| Ok(this.path()));
|
||||||
}
|
fields.add_field_method_get("version", |_, this| Ok(this.version()));
|
||||||
|
fields.add_field_method_get("uuid", |_, this| Ok(this.uuid().to_string()));
|
||||||
fn build<'a>(builder: &mut elua::UserdataBuilder<'a, Self>) {
|
fields.add_field_method_get("state", |_, this| {
|
||||||
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() {
|
||||||
|
@ -71,41 +69,43 @@ impl elua::Userdata for LuaResHandle {
|
||||||
|
|
||||||
Ok(name)
|
Ok(name)
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
builder.method("is_watched", |_, this, ()| {
|
fn add_methods<M: mlua::UserDataMethods<Self>>(methods: &mut M) {
|
||||||
|
methods.add_method("is_watched", |_, this, ()| {
|
||||||
Ok(this.is_watched())
|
Ok(this.is_watched())
|
||||||
});
|
});
|
||||||
|
|
||||||
builder.method("is_loaded", |_, this, ()| {
|
methods.add_method("is_loaded", |_, this, ()| {
|
||||||
Ok(this.is_loaded())
|
Ok(this.is_loaded())
|
||||||
});
|
});
|
||||||
|
|
||||||
builder.method("wait_until_loaded", |_, this, ()| {
|
methods.add_method("wait_until_loaded", |_, this, ()| {
|
||||||
this.wait_recurse_dependencies_load();
|
this.wait_recurse_dependencies_load();
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
});
|
});
|
||||||
|
|
||||||
builder.method(FN_NAME_INTERNAL_AS_COMPONENT, |lua, this, ()| {
|
methods.add_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).as_lua(lua)
|
LuaSceneHandle(handle).into_lua(lua)
|
||||||
} else if let Some(handle) = handle.as_typed::<Gltf>() {
|
} else if let Some(handle) = handle.as_typed::<Gltf>() {
|
||||||
LuaGltfHandle(handle).as_lua(lua)
|
LuaGltfHandle(handle).into_lua(lua)
|
||||||
} else {
|
} else {
|
||||||
Ok(elua::Value::Nil)
|
Ok(mlua::Value::Nil)
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> FromLua<'a> for LuaResHandle {
|
impl mlua::FromLua for LuaResHandle {
|
||||||
fn from_lua(_: &'a elua::State, val: elua::Value<'a>) -> elua::Result<Self> {
|
fn from_lua(val: mlua::Value, _: &mlua::Lua) -> mlua::Result<Self> {
|
||||||
let tyname = val.type_name();
|
let tyname = val.type_name();
|
||||||
let ud = val.as_userdata()
|
let ud = val.as_userdata()
|
||||||
.ok_or(elua::Error::type_mismatch("Handle", &tyname))?;
|
.ok_or(mlua::Error::external(Error::type_mismatch("Handle", &tyname)))?;
|
||||||
let handle = ud.as_ref::<LuaResHandle>()?;
|
let handle = ud.borrow::<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()))
|
||||||
.as_lua(lua)
|
.into_lua(lua)
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
builder.method("indices", |lua, this, ()| {
|
methods.add_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_seti(i, *ind)?;
|
table.raw_set(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_seti(i, *ind)?;
|
table.raw_set(i, *ind)?;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
None => {},
|
None => {},
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Value::Table(table))
|
Ok(mlua::Value::Table(table))
|
||||||
} else {
|
} else {
|
||||||
Ok(Value::Nil)
|
Ok(mlua::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()))
|
||||||
.as_lua(lua)
|
.into_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()))
|
||||||
.as_lua(lua)
|
.into_lua(lua)
|
||||||
}),
|
}),
|
||||||
(pbr_glossiness, {
|
(pbr_glossiness, {
|
||||||
data.pbr_glossiness.clone()
|
data.pbr_glossiness.clone()
|
||||||
.map(|v| LuaPbrGlossiness(v.clone()))
|
.map(|v| LuaPbrGlossiness(v.clone()))
|
||||||
.as_lua(lua)
|
.into_lua(lua)
|
||||||
}),
|
}),
|
||||||
alpha_cutoff,
|
alpha_cutoff,
|
||||||
(alpha_mode, {
|
(alpha_mode, {
|
||||||
|
@ -186,55 +186,57 @@ 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",
|
||||||
}.as_lua(lua)
|
}.into_lua(lua)
|
||||||
}),
|
}),
|
||||||
(specular, {
|
(specular, {
|
||||||
data.specular.clone()
|
data.specular.clone()
|
||||||
.map(|v| LuaSpecular(v.clone()))
|
.map(|v| LuaSpecular(v.clone()))
|
||||||
.as_lua(lua)
|
.into_lua(lua)
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
lua_wrap_handle!(Gltf, {
|
lua_wrap_handle!(Gltf, {
|
||||||
builder.method("scenes", |lua, this, ()| {
|
methods.add_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_seti(i, LuaSceneHandle(scene.clone()))?;
|
table.raw_set(i, LuaSceneHandle(scene.clone()))?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Value::Table(table))
|
Ok(mlua::Value::Table(table))
|
||||||
} else {
|
} else {
|
||||||
Ok(Value::Nil)
|
Ok(mlua::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_seti(i, LuaMaterialHandle(mat.clone()))?;
|
table.raw_set(i, LuaMaterialHandle(mat.clone()))?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Value::Table(table))
|
Ok(mlua::Value::Table(table))
|
||||||
} else {
|
} else {
|
||||||
Ok(Value::Nil)
|
Ok(mlua::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_seti(i, LuaMeshHandle(mesh.clone()))?;
|
table.raw_set(i, LuaMeshHandle(mesh.clone()))?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Value::Table(table))
|
Ok(mlua::Value::Table(table))
|
||||||
} else {
|
} else {
|
||||||
Ok(Value::Nil)
|
Ok(mlua::Value::Nil)
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
|
@ -21,15 +21,15 @@ impl std::ops::DerefMut for LuaDeltaTime {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'lua> elua::FromLua<'lua> for LuaDeltaTime {
|
impl mlua::FromLua for LuaDeltaTime {
|
||||||
fn from_lua(_: &'lua elua::State, _: elua::Value<'lua>) -> elua::Result<Self> {
|
fn from_lua(_: mlua::Value, _: &mlua::Lua) -> mlua::Result<Self> {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'lua> elua::AsLua<'lua> for LuaDeltaTime {
|
impl mlua::IntoLua for LuaDeltaTime {
|
||||||
fn as_lua(self, _: &'lua elua::State) -> elua::Result<elua::Value<'lua>> {
|
fn into_lua(self, _: &mlua::Lua) -> mlua::Result<mlua::Value> {
|
||||||
Ok(elua::Value::Number(*self.0 as f64))
|
Ok(mlua::Value::Number(*self.0 as f64))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
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 crate::lyra_engine;
|
use mlua::IntoLua;
|
||||||
|
use crate::{lua::Error, lyra_engine};
|
||||||
|
|
||||||
use lyra_reflect::Reflect;
|
use lyra_reflect::Reflect;
|
||||||
|
|
||||||
|
@ -10,27 +11,23 @@ pub struct LuaActionHandler {
|
||||||
handler: ActionHandler
|
handler: ActionHandler
|
||||||
}
|
}
|
||||||
|
|
||||||
impl elua::Userdata for LuaActionHandler {
|
impl mlua::UserData for LuaActionHandler {
|
||||||
fn name() -> String {
|
fn add_methods<M: mlua::UserDataMethods<Self>>(methods: &mut M) {
|
||||||
"ActionHandler".to_string()
|
methods.add_function("new", |_, table: mlua::Table| {
|
||||||
}
|
|
||||||
|
|
||||||
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::<_, elua::Table>("layouts")
|
let layouts = table.get::<mlua::Table>("layouts")
|
||||||
.map_err(|_| elua::Error::runtime("missing 'layouts' in ActionHandler table"))?;
|
.map_err(|_| mlua::Error::runtime("missing 'layouts' in ActionHandler table"))?;
|
||||||
for layout_id in layouts.sequence_iter::<u32>() {
|
for layout_id in layouts.sequence_values::<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::<_, elua::Table>("actions")
|
let actions = table.get::<mlua::Table>("actions")
|
||||||
.map_err(|_| elua::Error::runtime("missing 'actions' in ActionHandler table"))?;
|
.map_err(|_| mlua::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();
|
||||||
|
@ -45,26 +42,26 @@ impl elua::Userdata for LuaActionHandler {
|
||||||
}
|
}
|
||||||
|
|
||||||
// find the mappings and start processing them
|
// find the mappings and start processing them
|
||||||
let mappings= table.get::<_, elua::Table>("mappings")
|
let mappings= table.get::<mlua::Table>("mappings")
|
||||||
.map_err(|_| elua::Error::runtime("missing 'mappings' in ActionHandler table"))?;
|
.map_err(|_| mlua::Error::runtime("missing 'mappings' in ActionHandler table"))?;
|
||||||
for (map_id, tbl) in mappings.sequence_iter::<elua::Table>().enumerate() {
|
for (map_id, tbl) in mappings.sequence_values::<mlua::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::<_, elua::Table>("binds")
|
let binds_tbl = tbl.get::<mlua::Table>("binds")
|
||||||
.map_err(|_| elua::Error::runtime("missing 'binds' in ActionHandler 'mappings' table"))?;
|
.map_err(|_| mlua::Error::runtime("missing 'binds' in ActionHandler 'mappings' table"))?;
|
||||||
for pair in binds_tbl.pairs::<String, elua::Table>() {
|
for pair in binds_tbl.pairs::<String, mlua::Table>() {
|
||||||
let (action_lbl, input_binds) = pair?;
|
let (action_lbl, input_binds) = pair?;
|
||||||
|
|
||||||
for input in input_binds.sequence_iter::<String>() {
|
for input in input_binds.sequence_values::<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(elua::Error::Runtime(format!("Unknown action specified in mapping binds: {}", action_lbl)))?;
|
.ok_or(mlua::Error::runtime(format!("Unknown action specified in mapping binds: {}", action_lbl)))?;
|
||||||
|
|
||||||
let mut binds = Vec::new();
|
let mut binds = Vec::new();
|
||||||
|
|
||||||
|
@ -77,18 +74,18 @@ impl elua::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(elua::Error::Runtime(format!("invalid bind '{input_name}', unable to find device or axis for device")))?;
|
.ok_or(mlua::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(elua::Error::Runtime(format!("invalid bind string for Axis Action: '{input}' (expected '=' with float)")))?;
|
.ok_or(mlua::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| elua::Error::Runtime(format!("invalid bind string for Axis Action: '{input}' ({e})")))?;
|
.map_err(|e| mlua::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(elua::Error::Runtime(format!("invalid key in bind: '{button}'")))?;
|
.ok_or(mlua::Error::runtime(format!("invalid key in bind: '{button}'")))?;
|
||||||
binds.push(src.into_binding_modifier(val));
|
binds.push(src.into_binding_modifier(val));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -105,23 +102,29 @@ impl elua::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 {
|
||||||
|
@ -133,28 +136,29 @@ impl elua::Userdata for LuaActionHandler {
|
||||||
ActionState::Other(v) => ("Other", Some(v)),
|
ActionState::Other(v) => ("Other", Some(v)),
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut multi = elua::ValueVec::new();
|
let mut multi = Vec::new();
|
||||||
multi.push_val(lua, name)?;
|
multi.push(name.into_lua(lua)?);
|
||||||
multi.push_val(lua, val)?;
|
multi.push(val.into_lua(lua)?);
|
||||||
|
|
||||||
Ok(elua::Value::Multi(multi))
|
Ok(mlua::MultiValue::from_iter(multi.into_iter()))
|
||||||
})
|
|
||||||
.method(FN_NAME_INTERNAL_REFLECT, |_, this, ()| {
|
|
||||||
Ok(ScriptBorrow::from_resource::<ActionHandler>(Some(this.handler.clone())))
|
|
||||||
})
|
|
||||||
.function(FN_NAME_INTERNAL_REFLECT_TYPE, |_, ()| {
|
|
||||||
Ok(ScriptBorrow::from_resource::<ActionHandler>(None))
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
methods.add_method(FN_NAME_INTERNAL_REFLECT, |_, this, ()| {
|
||||||
|
Ok(ScriptBorrow::from_resource::<ActionHandler>(Some(this.handler.clone())))
|
||||||
|
});
|
||||||
|
|
||||||
|
methods.add_function(FN_NAME_INTERNAL_REFLECT_TYPE, |_, ()| {
|
||||||
|
Ok(ScriptBorrow::from_resource::<ActionHandler>(None))
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> elua::FromLua<'a> for LuaActionHandler {
|
impl mlua::FromLua for LuaActionHandler {
|
||||||
fn from_lua(_: &'a elua::State, val: elua::Value<'a>) -> elua::Result<Self> {
|
fn from_lua(val: mlua::Value, _: &mlua::Lua) -> mlua::Result<Self> {
|
||||||
let tyname = val.type_name();
|
let tyname = val.type_name();
|
||||||
let ud = val.as_userdata()
|
let ud = val.as_userdata()
|
||||||
.ok_or(elua::Error::type_mismatch("ActionHandler", &tyname))?;
|
.ok_or(mlua::Error::external(Error::type_mismatch("ActionHandler", &tyname)))?;
|
||||||
let handle = ud.as_ref::<LuaActionHandler>()?;
|
let handle = ud.borrow::<LuaActionHandler>()?;
|
||||||
|
|
||||||
Ok(handle.clone())
|
Ok(handle.clone())
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
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;
|
||||||
|
|
||||||
|
@ -20,13 +21,15 @@ wrap_lua_struct!(
|
||||||
{
|
{
|
||||||
lua_vec_wrap_extension!(math::Vec2, LuaVec2);
|
lua_vec_wrap_extension!(math::Vec2, LuaVec2);
|
||||||
|
|
||||||
builder.method_mut("move_by", |lua, this, vals: elua::ValueVec| {
|
methods.add_method_mut("move_by", |lua, this, vals: mlua::MultiValue| {
|
||||||
let vals_clone = vals.clone();
|
let vals_clone = vals.clone();
|
||||||
if let Some((x, y)) = vals.try_into_vals::<(f32, f32)>(lua)? {
|
if let Ok((x, y)) = <(f32, f32) as FromLuaMulti>::from_lua_multi(vals, lua) {
|
||||||
this.x += x;
|
this.x += x;
|
||||||
this.y += y;
|
this.y += y;
|
||||||
} else if let Some(v) = vals_clone.try_into_vals::<Self>(lua)? {
|
} else if let Ok(v) = Self::from_lua_multi(vals_clone, lua) {
|
||||||
this.0 += v.0;
|
this.0 += v.0;
|
||||||
|
} else {
|
||||||
|
todo!("handle invalid argument error");
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -50,14 +53,16 @@ wrap_lua_struct!(
|
||||||
{
|
{
|
||||||
lua_vec_wrap_extension!(math::Vec3, LuaVec3);
|
lua_vec_wrap_extension!(math::Vec3, LuaVec3);
|
||||||
|
|
||||||
builder.method_mut("move_by", |lua, this, vals: elua::ValueVec| {
|
methods.add_method_mut("move_by", |lua, this, vals: mlua::MultiValue| {
|
||||||
let vals_clone = vals.clone();
|
let vals_clone = vals.clone();
|
||||||
if let Some((x, y, z)) = vals.try_into_vals::<(f32, f32, f32)>(lua)? {
|
if let Ok((x, y, z)) = <(f32, f32, f32) as FromLuaMulti>::from_lua_multi(vals, lua) {
|
||||||
this.x += x;
|
this.x += x;
|
||||||
this.y += y;
|
this.y += y;
|
||||||
this.z += z;
|
this.z += z;
|
||||||
} else if let Some(v) = vals_clone.try_into_vals::<Self>(lua)? {
|
} else if let Ok(v) = Self::from_lua_multi(vals_clone, lua) {
|
||||||
this.0 += v.0;
|
this.0 += v.0;
|
||||||
|
} else {
|
||||||
|
todo!("handle invalid argument error");
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -98,70 +103,70 @@ wrap_lua_struct!(
|
||||||
),
|
),
|
||||||
{
|
{
|
||||||
// manually implemented since Quat doesn't have a `new` function
|
// manually implemented since Quat doesn't have a `new` function
|
||||||
builder.function("new", |_, (x, y, z, w)| {
|
methods.add_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)))
|
||||||
});
|
});
|
||||||
|
|
||||||
builder.function("from_rotation_x", |_, (rad,)| {
|
methods.add_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))
|
||||||
});
|
});
|
||||||
|
|
||||||
builder.function("from_rotation_y", |_, (rad,)| {
|
methods.add_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))
|
||||||
});
|
});
|
||||||
|
|
||||||
builder.function("from_rotation_z", |_, (rad,)| {
|
methods.add_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))
|
||||||
});
|
});
|
||||||
|
|
||||||
builder.method("dot", |_, this, (rhs,): (Self,)| {
|
methods.add_method("dot", |_, this, (rhs,): (Self,)| {
|
||||||
Ok(this.dot(rhs.0))
|
Ok(this.dot(rhs.0))
|
||||||
});
|
});
|
||||||
|
|
||||||
builder.method("length", |_, this, ()| {
|
methods.add_method("length", |_, this, ()| {
|
||||||
Ok(this.length())
|
Ok(this.length())
|
||||||
});
|
});
|
||||||
|
|
||||||
builder.method("length_squared", |_, this, ()| {
|
methods.add_method("length_squared", |_, this, ()| {
|
||||||
Ok(this.length_squared())
|
Ok(this.length_squared())
|
||||||
});
|
});
|
||||||
|
|
||||||
builder.method_mut("normalize", |_, this, ()| {
|
methods.add_method_mut("normalize", |_, this, ()| {
|
||||||
this.0 = this.normalize();
|
this.0 = this.normalize();
|
||||||
Ok(())
|
Ok(())
|
||||||
});
|
});
|
||||||
|
|
||||||
builder.method_mut("mult_quat", |_, this, (rhs,): (Self,)| {
|
methods.add_method_mut("mult_quat", |_, this, (rhs,): (Self,)| {
|
||||||
this.0 *= rhs.0;
|
this.0 *= rhs.0;
|
||||||
Ok(())
|
Ok(())
|
||||||
});
|
});
|
||||||
|
|
||||||
builder.method("mult_vec3", |_, this, (rhs,): (LuaVec3,)| {
|
methods.add_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`.
|
||||||
builder.meta_method(elua::MetaMethod::Mul, |lua, this, (val,): (elua::Value,)| {
|
methods.add_meta_method(mlua::MetaMethod::Mul, |lua, this, (val,): (mlua::Value,)| {
|
||||||
use elua::AsLua;
|
use mlua::IntoLua;
|
||||||
|
|
||||||
match val {
|
match val {
|
||||||
elua::Value::Userdata(ud) => {
|
mlua::Value::UserData(ud) => {
|
||||||
if ud.is::<LuaVec3>()? {
|
if ud.is::<LuaVec3>() {
|
||||||
let v3 = ud.as_ref::<LuaVec3>()?;
|
let v3 = ud.borrow::<LuaVec3>()?;
|
||||||
LuaVec3(this.0 * v3.0)
|
LuaVec3(this.0 * v3.0)
|
||||||
.as_lua(lua)
|
.into_lua(lua)
|
||||||
} else {
|
} else {
|
||||||
let quat = ud.as_ref::<LuaQuat>()?;
|
let quat = ud.borrow::<LuaQuat>()?;
|
||||||
LuaQuat(this.0 * quat.0)
|
LuaQuat(this.0 * quat.0)
|
||||||
.as_lua(lua)
|
.into_lua(lua)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
elua::Value::Number(n) => {
|
mlua::Value::Number(n) => {
|
||||||
LuaQuat(this.0 * (n as f32))
|
LuaQuat(this.0 * (n as f32))
|
||||||
.as_lua(lua)
|
.into_lua(lua)
|
||||||
},
|
},
|
||||||
_ => {
|
_ => {
|
||||||
todo!()
|
todo!()
|
||||||
|
@ -169,7 +174,7 @@ wrap_lua_struct!(
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
builder.method("lerp", |_, this, (rhs, alpha): (Self, f32)| {
|
methods.add_method("lerp", |_, this, (rhs, alpha): (Self, f32)| {
|
||||||
Ok(Self(this.lerp(*rhs, alpha)))
|
Ok(Self(this.lerp(*rhs, alpha)))
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -180,94 +185,94 @@ wrap_lua_struct!(
|
||||||
derives(PartialEq, Copy),
|
derives(PartialEq, Copy),
|
||||||
metamethods(ToString, Eq),
|
metamethods(ToString, Eq),
|
||||||
{
|
{
|
||||||
builder.function("default", |_, ()| {
|
methods.add_function("default", |_, ()| {
|
||||||
Ok(Self(math::Transform::default()))
|
Ok(Self(math::Transform::default()))
|
||||||
});
|
});
|
||||||
|
|
||||||
builder.function("new", |_, (pos, rot, scale): (LuaVec3, LuaQuat, LuaVec3)| {
|
methods.add_function("new", |_, (pos, rot, scale): (LuaVec3, LuaQuat, LuaVec3)| {
|
||||||
Ok(Self(math::Transform::new(*pos, *rot, *scale)))
|
Ok(Self(math::Transform::new(*pos, *rot, *scale)))
|
||||||
});
|
});
|
||||||
|
|
||||||
builder.function("from_translation", |_, (pos,): (LuaVec3,)| {
|
methods.add_function("from_translation", |_, (pos,): (LuaVec3,)| {
|
||||||
Ok(Self(math::Transform::from_translation(*pos)))
|
Ok(Self(math::Transform::from_translation(*pos)))
|
||||||
});
|
});
|
||||||
|
|
||||||
builder.function("from_xyz", |_, (x, y, z)| {
|
methods.add_function("from_xyz", |_, (x, y, z)| {
|
||||||
Ok(Self(math::Transform::from_xyz(x, y, z)))
|
Ok(Self(math::Transform::from_xyz(x, y, z)))
|
||||||
});
|
});
|
||||||
|
|
||||||
builder.method("clone", |_, this, ()| {
|
methods.add_method("clone", |_, this, ()| {
|
||||||
Ok(this.clone())
|
Ok(this.clone())
|
||||||
});
|
});
|
||||||
|
|
||||||
builder.method("forward", |_, this, ()| {
|
methods.add_method("forward", |_, this, ()| {
|
||||||
Ok(LuaVec3(this.forward()))
|
Ok(LuaVec3(this.forward()))
|
||||||
});
|
});
|
||||||
|
|
||||||
builder.method("left", |_, this, ()| {
|
methods.add_method("left", |_, this, ()| {
|
||||||
Ok(LuaVec3(this.left()))
|
Ok(LuaVec3(this.left()))
|
||||||
});
|
});
|
||||||
|
|
||||||
builder.method("up", |_, this, ()| {
|
methods.add_method("up", |_, this, ()| {
|
||||||
Ok(LuaVec3(this.up()))
|
Ok(LuaVec3(this.up()))
|
||||||
});
|
});
|
||||||
|
|
||||||
builder.method_mut("rotate", |_, this, (quat,): (LuaQuat,)| {
|
methods.add_method_mut("rotate", |_, this, (quat,): (LuaQuat,)| {
|
||||||
this.rotate(*quat);
|
this.rotate(*quat);
|
||||||
Ok(())
|
Ok(())
|
||||||
});
|
});
|
||||||
|
|
||||||
builder.method_mut("rotate_x", |_, this, (deg,): (f32,)| {
|
methods.add_method_mut("rotate_x", |_, this, (deg,): (f32,)| {
|
||||||
this.rotate_x(math::Angle::Degrees(deg));
|
this.rotate_x(math::Angle::Degrees(deg));
|
||||||
Ok(())
|
Ok(())
|
||||||
});
|
});
|
||||||
|
|
||||||
builder.method_mut("rotate_y", |_, this, (deg,): (f32,)| {
|
methods.add_method_mut("rotate_y", |_, this, (deg,): (f32,)| {
|
||||||
this.rotate_y(math::Angle::Degrees(deg));
|
this.rotate_y(math::Angle::Degrees(deg));
|
||||||
Ok(())
|
Ok(())
|
||||||
});
|
});
|
||||||
|
|
||||||
builder.method_mut("rotate_z", |_, this, (deg,): (f32,)| {
|
methods.add_method_mut("rotate_z", |_, this, (deg,): (f32,)| {
|
||||||
this.rotate_z(math::Angle::Degrees(deg));
|
this.rotate_z(math::Angle::Degrees(deg));
|
||||||
Ok(())
|
Ok(())
|
||||||
});
|
});
|
||||||
|
|
||||||
builder.method_mut("rotate_x_rad", |_, this, (rad,): (f32,)| {
|
methods.add_method_mut("rotate_x_rad", |_, this, (rad,): (f32,)| {
|
||||||
this.rotate_x(math::Angle::Radians(rad));
|
this.rotate_x(math::Angle::Radians(rad));
|
||||||
Ok(())
|
Ok(())
|
||||||
});
|
});
|
||||||
|
|
||||||
builder.method_mut("rotate_y_rad", |_, this, (rad,): (f32,)| {
|
methods.add_method_mut("rotate_y_rad", |_, this, (rad,): (f32,)| {
|
||||||
this.rotate_y(math::Angle::Radians(rad));
|
this.rotate_y(math::Angle::Radians(rad));
|
||||||
Ok(())
|
Ok(())
|
||||||
});
|
});
|
||||||
|
|
||||||
builder.method_mut("rotate_z_rad", |_, this, (rad,): (f32,)| {
|
methods.add_method_mut("rotate_z_rad", |_, this, (rad,): (f32,)| {
|
||||||
this.rotate_z(math::Angle::Radians(rad));
|
this.rotate_z(math::Angle::Radians(rad));
|
||||||
Ok(())
|
Ok(())
|
||||||
});
|
});
|
||||||
|
|
||||||
builder.method_mut("translate", |_, this, (x, y, z): (f32, f32, f32)| {
|
methods.add_method_mut("translate", |_, this, (x, y, z): (f32, f32, f32)| {
|
||||||
this.translate(x, y, z);
|
this.translate(x, y, z);
|
||||||
Ok(())
|
Ok(())
|
||||||
});
|
});
|
||||||
|
|
||||||
builder.method("lerp", |_, this, (rhs, alpha): (Self, f32)| {
|
methods.add_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
|
||||||
builder.meta_method(elua::MetaMethod::Mul, |_, this, (quat,): (LuaQuat,)| {
|
methods.add_meta_method(mlua::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
|
||||||
builder.meta_method(elua::MetaMethod::Add, |_, this, (pos,): (LuaVec3,)| {
|
methods.add_meta_method(mlua::MetaMethod::Add, |_, this, (pos,): (LuaVec3,)| {
|
||||||
let mut t = *this;
|
let mut t = *this;
|
||||||
t.translation += *pos;
|
t.translation += *pos;
|
||||||
Ok(t)
|
Ok(t)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
);
|
);
|
|
@ -1,6 +1,7 @@
|
||||||
use std::ptr::NonNull;
|
use std::{ops::Deref, ptr::NonNull, sync::Arc};
|
||||||
|
|
||||||
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);
|
||||||
|
@ -14,33 +15,41 @@ impl std::ops::Deref for ScriptEntity {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct ScriptWorldPtr {
|
pub struct ScriptWorldPtr(Arc<RwLock<NonNull<World>>>);
|
||||||
pub inner: NonNull<World>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ScriptWorldPtr {
|
impl ScriptWorldPtr {
|
||||||
/// Creates a world pointer from a world borrow.
|
pub fn read(&self) -> MappedRwLockReadGuard<World> {
|
||||||
pub fn from_ref(world: &World) -> Self {
|
RwLockReadGuard::map(self.0.read(), |p| unsafe { p.as_ref() })
|
||||||
Self {
|
|
||||||
inner: NonNull::from(world),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a borrow to the world from the ptr.
|
pub fn write(&self) -> MappedRwLockWriteGuard<World> {
|
||||||
pub fn as_ref(&self) -> &World {
|
RwLockWriteGuard::map(self.0.write(), |p| unsafe { p.as_mut() })
|
||||||
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() }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::ops::Deref for ScriptWorldPtr {
|
// SAFETY: The inner NonNull pointer is wrapped in an Arc<RwLock<>>
|
||||||
type Target = NonNull<World>;
|
unsafe impl Send for ScriptWorldPtr {}
|
||||||
|
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.inner
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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)))))
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -9,4 +9,7 @@ impl std::ops::Deref for ScriptDynamicBundle {
|
||||||
fn deref(&self) -> &Self::Target {
|
fn deref(&self) -> &Self::Target {
|
||||||
&self.0
|
&self.0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SAFETY: todo!()
|
||||||
|
unsafe impl Send for ScriptDynamicBundle {}
|
Loading…
Reference in New Issue