scripting: switch to elua, create LuaTableProxy for proxying rust types into and from lua tables
This commit is contained in:
parent
f2f8248de7
commit
4247c4f5c1
|
@ -12,18 +12,51 @@ function on_pre_update()
|
|||
print("Lua's pre-update function was called")
|
||||
end ]]
|
||||
|
||||
---
|
||||
---Recursively dumps a table as a string.
|
||||
---
|
||||
---@param obj table
|
||||
---@return string
|
||||
---@nodiscard
|
||||
function dump_table(obj)
|
||||
if type(obj) == 'table' then
|
||||
local s = '{ '
|
||||
for k,v in pairs(obj) do
|
||||
if type(k) ~= 'number' then k = '"'..k..'"' end
|
||||
s = s .. '['..k..'] = ' .. dump_table(v) .. ','
|
||||
end
|
||||
return s .. '} '
|
||||
else
|
||||
return tostring(obj)
|
||||
end
|
||||
end
|
||||
|
||||
function on_update()
|
||||
--print("Lua's update function was called")
|
||||
|
||||
local dt = world:resource(DeltaTime)
|
||||
--print("DeltaTime was " .. tostring(dt) .. "s")
|
||||
--local v = Vec3:new(50, 10, 20)
|
||||
--print("Vec3 = " .. tostring(v))
|
||||
|
||||
world:view(function (t)
|
||||
--print("Found entity at a really cool place: " .. tostring(t))
|
||||
t.translation = t.translation + (Vec3.new(0, 0.5, 0) * dt:get())
|
||||
world:view(
|
||||
---@param t Transform
|
||||
function (t)
|
||||
print("Found entity at a really cool place: " .. tostring(t))
|
||||
t.translation:move_by(0, 0.001, 0)
|
||||
|
||||
return t
|
||||
end, Transform)
|
||||
end,
|
||||
Transform
|
||||
)
|
||||
|
||||
-- local dt = world:resource(DeltaTime)
|
||||
-- --print("DeltaTime was " .. tostring(dt) .. "s")
|
||||
--
|
||||
-- world:view(function (t)
|
||||
-- --print("Found entity at a really cool place: " .. tostring(t))
|
||||
-- t.translation = t.translation + (Vec3.new(0, 0.5, 0) * dt:get())
|
||||
--
|
||||
-- return t
|
||||
-- end, Transform)
|
||||
end
|
||||
|
||||
--[[ function on_post_update()
|
||||
|
|
|
@ -84,16 +84,16 @@ async fn main() {
|
|||
|
||||
let mut resman = world.get_resource_mut::<ResourceManager>();
|
||||
//let diffuse_texture = resman.request::<Texture>("assets/happy-tree.png").unwrap();
|
||||
let antique_camera_model = resman.request::<Model>("assets/AntiqueCamera.glb").unwrap();
|
||||
//let antique_camera_model = resman.request::<Model>("assets/AntiqueCamera.glb").unwrap();
|
||||
//let cube_model = resman.request::<Model>("assets/cube-texture-bin.glb").unwrap();
|
||||
let cube_model = resman.request::<Model>("assets/texture-sep/texture-sep.gltf").unwrap();
|
||||
let crate_model = resman.request::<Model>("assets/crate/crate.gltf").unwrap();
|
||||
drop(resman);
|
||||
|
||||
world.spawn((
|
||||
/* world.spawn((
|
||||
ModelComponent(antique_camera_model),
|
||||
Transform::from_xyz(0.0, -5.0, -10.0),
|
||||
));
|
||||
)); */
|
||||
|
||||
{
|
||||
let cube_tran = Transform::from_xyz(-3.5, 0.0, -8.0);
|
||||
|
|
|
@ -342,7 +342,7 @@ impl Game {
|
|||
.with(fmt::layer().with_writer(stdout_layer))
|
||||
.with(filter::Targets::new()
|
||||
// done by prefix, so it includes all lyra subpackages
|
||||
.with_target("lyra", Level::DEBUG)
|
||||
.with_target("lyra", Level::TRACE)
|
||||
.with_target("wgpu", Level::WARN)
|
||||
.with_default(Level::INFO))
|
||||
.init();
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 5694d395abbbce340eda195c99104db3e9c9435a
|
||||
Subproject commit 35bd889b4829446f972292440174e7c0e4fa40a2
|
|
@ -1,3 +1,8 @@
|
|||
---@class Quat
|
||||
---@field x number
|
||||
---@field y number
|
||||
---@field z number
|
||||
---@field w number
|
||||
Quat = { x = 0.0, y = 0.0, z = 0.0, w = 0.0 }
|
||||
Quat.__index = Quat
|
||||
Quat.__name = "Quat"
|
||||
|
@ -22,7 +27,7 @@ end
|
|||
|
||||
Quat.IDENTITY = Quat:new(0, 0, 0, 1)
|
||||
|
||||
function Quat:copy()
|
||||
function Quat:clone()
|
||||
return Quat:new(self.x, self.y, self.z, self.w)
|
||||
end
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
--require("math.quat")
|
||||
--require("math.vec3")
|
||||
|
||||
---@class Transform
|
||||
---@field translation Vec3
|
||||
---@field rotation Quat
|
||||
---@field Scale Vec3
|
||||
Transform = { translation = Vec3.ZERO, rotation = Quat.IDENTITY, scale = Vec3.ONE }
|
||||
Transform.__index = Transform
|
||||
Transform.__name = "Transform"
|
||||
|
@ -16,14 +17,14 @@ function Transform:new(translation, rotation, scale)
|
|||
return t
|
||||
end
|
||||
|
||||
function Transform:copy()
|
||||
return Transform:new(self.translation:copy(), self.rotation:copy(), self.scale:copy())
|
||||
function Transform:clone()
|
||||
return Transform:new(self.translation:clone(), self.rotation:clone(), self.scale:clone())
|
||||
end
|
||||
|
||||
--- Creates a new Transform with the translation at the vec3
|
||||
--- @param pos Vec3
|
||||
function Transform:from_vec3(pos)
|
||||
local t = Transform:copy() -- copy of default transform
|
||||
local t = Transform:clone() -- copy of default transform
|
||||
t.translation = pos
|
||||
return t
|
||||
end
|
||||
|
@ -81,7 +82,7 @@ end
|
|||
--- @param alpha number
|
||||
--- @return Transform
|
||||
function Transform:lerp(rhs, alpha)
|
||||
local res = self:copy()
|
||||
local res = self:clone()
|
||||
res.translation = self.translation:lerp(rhs.translation, alpha)
|
||||
res.rotation = self.rotation:lerp(rhs.rotation, alpha)
|
||||
res.scale = self.scale:lerp(rhs.scale, alpha)
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
---@class Vec3
|
||||
---@field x number
|
||||
---@field y number
|
||||
---@field z number
|
||||
Vec3 = { x = 0.0, y = 0.0, z = 0.0 }
|
||||
Vec3.__index = Vec3
|
||||
Vec3.__name = "Vec3"
|
||||
|
@ -18,7 +22,9 @@ function Vec3:new(x, y, z)
|
|||
return v
|
||||
end
|
||||
|
||||
function Vec3:copy()
|
||||
---Creates a copy of self
|
||||
---@return Vec3
|
||||
function Vec3:clone()
|
||||
return Vec3:new(self.x, self.y, self.z)
|
||||
end
|
||||
|
||||
|
@ -49,9 +55,10 @@ Vec3.ZERO = Vec3:new(0, 0, 0)
|
|||
Vec3.ONE = Vec3:new(1, 1, 1)
|
||||
|
||||
--- Computes the absolute value of `self`.
|
||||
---@return Vec3
|
||||
function Vec3:abs()
|
||||
return Vec3:new(math.abs(self.x), math.abs(self.y), math.abs(self.z))
|
||||
self.x = math.abs(self.x)
|
||||
self.y = math.abs(self.y)
|
||||
self.z = math.abs(self.z)
|
||||
end
|
||||
|
||||
--- Computes the length of `self`.
|
||||
|
@ -60,6 +67,16 @@ function Vec3:length()
|
|||
return math.sqrt(self:dot(self))
|
||||
end
|
||||
|
||||
---Moves `self` by the provided coordinates
|
||||
---@param x number
|
||||
---@param y number
|
||||
---@param z number
|
||||
function Vec3:move_by(x, y, z)
|
||||
self.x = self.x + x
|
||||
self.y = self.y + y
|
||||
self.z = self.z + z
|
||||
end
|
||||
|
||||
--- Computes the dot product of `self` and `rhs`.
|
||||
---@param rhs Vec3
|
||||
---@return number
|
||||
|
@ -80,11 +97,12 @@ function Vec3:min(rhs)
|
|||
return Vec3:new(x, y, z)
|
||||
end
|
||||
|
||||
--- Returns `self` normalized to a length 1.
|
||||
---@return unknown
|
||||
--- Modifies `self` to be normalized to a length 1.
|
||||
function Vec3:normalize()
|
||||
local len_recip = 1.0 / self:length()
|
||||
return self * len_recip
|
||||
self.x = self.x * len_recip
|
||||
self.y = self.y * len_recip
|
||||
self.z = self.z * len_recip
|
||||
end
|
||||
|
||||
--- Calculates the linear iterpolation between `self` and `rhs` based on the `alpha`.
|
||||
|
@ -97,40 +115,48 @@ function Vec3:lerp(rhs, alpha)
|
|||
-- ensure alpha is [0, 1]
|
||||
local alpha = math.max(0, math.min(1, alpha))
|
||||
|
||||
local res = self:copy()
|
||||
local res = self:clone()
|
||||
res = res + ((rhs - res) * alpha)
|
||||
return res
|
||||
end
|
||||
|
||||
function Vec3:__add(rhs)
|
||||
if type(rhs) == "Vec3" then
|
||||
return Vec3:new(self.x + rhs.x, self.y + rhs.y, self.z + rhs.z)
|
||||
else
|
||||
return Vec3:new(self.x + rhs, self.y + rhs, self.z + rhs)
|
||||
end
|
||||
end
|
||||
|
||||
function Vec3:__sub(rhs)
|
||||
if type(rhs) == "Vec3" then
|
||||
return Vec3:new(self.x - rhs.x, self.y - rhs.y, self.z - rhs.z)
|
||||
else
|
||||
return Vec3:new(self.x - rhs, self.y - rhs, self.z - rhs)
|
||||
end
|
||||
end
|
||||
|
||||
function Vec3:__mul(rhs)
|
||||
if type(rhs) == "number" then
|
||||
return Vec3:new(self.x * rhs, self.y * rhs, self.z * rhs)
|
||||
else
|
||||
if type(rhs) == "Vec3" then
|
||||
return Vec3:new(self.x * rhs.x, self.y * rhs.y, self.z * rhs.z)
|
||||
else
|
||||
return Vec3:new(self.x * rhs, self.y * rhs, self.z * rhs)
|
||||
end
|
||||
end
|
||||
|
||||
function Vec3:__div(rhs)
|
||||
if type(rhs) == "number" then
|
||||
return Vec3:new(self.x / rhs, self.y / rhs, self.z / rhs)
|
||||
else
|
||||
if type(rhs) == "Vec3" then
|
||||
return Vec3:new(self.x / rhs.x, self.y / rhs.y, self.z / rhs.z)
|
||||
else
|
||||
return Vec3:new(self.x / rhs, self.y / rhs, self.z / rhs)
|
||||
end
|
||||
end
|
||||
|
||||
function Vec3:__idiv(rhs)
|
||||
if type(rhs) == "number" then
|
||||
return Vec3:new(self.x // rhs, self.y // rhs, self.z // rhs)
|
||||
else
|
||||
if type(rhs) == "Vec3" then
|
||||
return Vec3:new(self.x // rhs.x, self.y // rhs.y, self.z // rhs.z)
|
||||
else
|
||||
return Vec3:new(self.x // rhs, self.y // rhs, self.z // rhs)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -8,15 +8,15 @@ use crate::ScriptWorldPtr;
|
|||
pub enum ScriptError {
|
||||
#[error("{0}")]
|
||||
#[cfg(feature = "lua")]
|
||||
MluaError(mlua::Error),
|
||||
MluaError(elua::Error),
|
||||
|
||||
#[error("{0}")]
|
||||
Other(anyhow::Error),
|
||||
}
|
||||
|
||||
#[cfg(feature = "lua")]
|
||||
impl From<mlua::Error> for ScriptError {
|
||||
fn from(value: mlua::Error) -> Self {
|
||||
impl From<elua::Error> for ScriptError {
|
||||
fn from(value: elua::Error) -> Self {
|
||||
ScriptError::MluaError(value)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -134,9 +134,9 @@ impl Iterator for DynamicViewIter {
|
|||
|
||||
#[cfg(feature = "lua")]
|
||||
pub struct ReflectedItem<'a> {
|
||||
pub proxy: &'a ReflectLuaProxy,
|
||||
//pub proxy: &'a ReflectLuaProxy,
|
||||
pub comp_ptr: NonNull<u8>,
|
||||
pub comp_ud: mlua::AnyUserData<'a>,
|
||||
pub comp_val: elua::Value<'a>,
|
||||
}
|
||||
|
||||
#[cfg(feature = "lua")]
|
||||
|
@ -153,7 +153,11 @@ pub struct ReflectedIterator {
|
|||
|
||||
impl ReflectedIterator {
|
||||
#[cfg(feature = "lua")]
|
||||
pub fn next_lua<'a>(&mut self, lua: &'a mlua::Lua) -> Option<ReflectedRow<'a>> {
|
||||
pub fn next_lua<'a>(&mut self, lua: &'a elua::State) -> Option<ReflectedRow<'a>> {
|
||||
use elua::AsLua;
|
||||
|
||||
use super::ReflectedLuaTableProxy;
|
||||
|
||||
|
||||
let n = self.dyn_view.next();
|
||||
|
||||
|
@ -172,17 +176,20 @@ impl ReflectedIterator {
|
|||
|
||||
let reg_type = reflected_components.get_type(id)
|
||||
.expect("Requested type was not found in TypeRegistry");
|
||||
let proxy = reg_type.get_data::<ReflectLuaProxy>()
|
||||
.expect("Type does not have ReflectLuaProxy as a TypeData");
|
||||
|
||||
let userdata = (proxy.fn_as_uservalue)(lua, d.ptr).unwrap();
|
||||
let value = if let Some(proxy) = reg_type.get_data::<ReflectLuaProxy>() {
|
||||
(proxy.fn_as_uservalue)(lua, d.ptr).unwrap()
|
||||
.as_lua(lua).unwrap()
|
||||
} else if let Some(proxy) = reg_type.get_data::<ReflectedLuaTableProxy>() {
|
||||
(proxy.fn_as_table)(lua, d.ptr.cast()).unwrap()
|
||||
.as_lua(lua).unwrap()
|
||||
} else {
|
||||
panic!("Type does not have ReflectLuaProxy or ReflectedLuaTableProxy as a TypeData");
|
||||
};
|
||||
|
||||
dynamic_row.push(ReflectedItem {
|
||||
proxy,
|
||||
comp_ptr: d.ptr,
|
||||
comp_ud: userdata
|
||||
comp_val: value
|
||||
});
|
||||
//dynamic_row.push(( (proxy, d.ptr), userdata));
|
||||
}
|
||||
|
||||
let row = ReflectedRow {
|
||||
|
|
|
@ -2,6 +2,7 @@ pub mod dynamic_iter;
|
|||
pub use dynamic_iter::*;
|
||||
|
||||
pub mod world;
|
||||
use elua::FromLua;
|
||||
pub use world::*;
|
||||
|
||||
pub mod script;
|
||||
|
@ -19,19 +20,14 @@ pub use proxy::*;
|
|||
pub mod system;
|
||||
pub use system::*;
|
||||
|
||||
#[cfg(test)]
|
||||
mod test;
|
||||
|
||||
use std::{any::TypeId, sync::Mutex};
|
||||
|
||||
use lyra_ecs::{
|
||||
DynamicBundle, World,
|
||||
Component, ComponentInfo, DynamicBundle, World
|
||||
};
|
||||
use lyra_reflect::{FromType, Reflect, TypeRegistry};
|
||||
|
||||
use mlua::{AnyUserDataExt, Lua};
|
||||
|
||||
pub type LuaContext = Mutex<mlua::Lua>;
|
||||
pub type LuaContext = Mutex<elua::State>;
|
||||
|
||||
pub const FN_NAME_INTERNAL_REFLECT_TYPE: &str = "__lyra_internal_reflect_type";
|
||||
pub const FN_NAME_INTERNAL_REFLECT: &str = "__lyra_internal_reflect";
|
||||
|
@ -40,21 +36,28 @@ use crate::{ScriptBorrow, ScriptDynamicBundle};
|
|||
|
||||
/// A trait used for registering a Lua type with the world.
|
||||
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)
|
||||
where
|
||||
T: Reflect + LuaProxy + Clone + mlua::FromLua<'a> + mlua::UserData;
|
||||
T: Reflect + LuaProxy + Clone + elua::FromLua<'a> + elua::Userdata;
|
||||
|
||||
/// Registers a wrapped lua type.
|
||||
/// Registers a type to Lua that is wrapped another type.
|
||||
/// This would be used for something like `UserdataRef<T>`.
|
||||
fn register_lua_wrapper<'a, W>(&mut self)
|
||||
where
|
||||
W: Reflect + LuaProxy + LuaWrapper + Clone + mlua::FromLua<'a> + mlua::UserData;
|
||||
W: Reflect + LuaProxy + LuaWrapper + Clone + elua::FromLua<'a> + elua::Userdata;
|
||||
|
||||
/// 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 {
|
||||
fn register_lua_type<'a, T>(&mut self)
|
||||
where
|
||||
T: Reflect + LuaProxy + Clone + mlua::FromLua<'a> + mlua::UserData
|
||||
T: Reflect + LuaProxy + Clone + elua::FromLua<'a> + elua::Userdata
|
||||
{
|
||||
let mut registry = self.get_resource_mut::<TypeRegistry>();
|
||||
|
||||
|
@ -67,44 +70,64 @@ impl RegisterLuaType for World {
|
|||
|
||||
fn register_lua_wrapper<'a, W>(&mut self)
|
||||
where
|
||||
W: Reflect + LuaProxy + LuaWrapper + Clone + mlua::FromLua<'a> + mlua::UserData
|
||||
W: Reflect + LuaProxy + LuaWrapper + Clone + elua::FromLua<'a> + elua::Userdata
|
||||
{
|
||||
let mut registry = self.get_resource_mut::<TypeRegistry>();
|
||||
|
||||
let reg_type = registry.get_type_or_default(W::wrapped_type_id());
|
||||
reg_type.add_data(<ReflectLuaProxy as FromType<W>>::from_type());
|
||||
}
|
||||
|
||||
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 type_id = TypeId::of::<T>();
|
||||
let reg_type = registry.get_type_or_default(TypeId::of::<C>());
|
||||
reg_type.add_data(<ReflectedLuaTableProxy as FromType<T>>::from_type());
|
||||
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 mut info = ComponentInfo::new::<C>();
|
||||
lookup.comp_info_from_name.insert(T::table_name(), info);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'lua> mlua::FromLua<'lua> for ScriptBorrow {
|
||||
fn from_lua(value: mlua::Value<'lua>, _lua: &'lua Lua) -> mlua::Result<Self> {
|
||||
impl<'lua> elua::FromLua<'lua> for ScriptBorrow {
|
||||
fn from_lua(_: &'lua elua::State, value: elua::Value<'lua>) -> elua::Result<Self> {
|
||||
match value {
|
||||
mlua::Value::UserData(ud) => Ok(ud.borrow::<Self>()?.clone()),
|
||||
elua::Value::Userdata(ud) => Ok(ud.as_ref::<Self>()?.clone()),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl mlua::UserData for ScriptBorrow {}
|
||||
|
||||
pub fn reflect_user_data(ud: &mlua::AnyUserData) -> ScriptBorrow {
|
||||
ud.call_method::<_, ScriptBorrow>(FN_NAME_INTERNAL_REFLECT, ())
|
||||
.expect("Type does not implement '__internal_reflect' properly")
|
||||
}
|
||||
|
||||
impl mlua::UserData for ScriptDynamicBundle {
|
||||
fn add_methods<'lua, M: mlua::prelude::LuaUserDataMethods<'lua, Self>>(methods: &mut M) {
|
||||
methods.add_function("new", |_, ()| Ok(ScriptDynamicBundle(DynamicBundle::new())));
|
||||
|
||||
methods.add_method_mut("push", |_, this, (comp,): (mlua::AnyUserData,)| {
|
||||
let script_brw = comp.call_method::<_, ScriptBorrow>(FN_NAME_INTERNAL_REFLECT, ())?;
|
||||
let reflect = script_brw.reflect_branch.as_component_unchecked();
|
||||
|
||||
let refl_data = script_brw.data.unwrap();
|
||||
let refl_data = refl_data.as_ref();
|
||||
reflect.bundle_insert(&mut this.0, refl_data);
|
||||
|
||||
Ok(())
|
||||
});
|
||||
impl<'lua> elua::FromLuaVec<'lua> for ScriptBorrow {
|
||||
fn from_lua_value_vec(state: &'lua elua::State, mut values: elua::ValueVec<'lua>) -> elua::Result<Self> {
|
||||
if let Some(v) = values.pop_front() {
|
||||
ScriptBorrow::from_lua(state, v)
|
||||
} else {
|
||||
Err(elua::Error::Nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl elua::Userdata for ScriptBorrow {
|
||||
fn name() -> String {
|
||||
"ScriptBorrow".to_string()
|
||||
}
|
||||
|
||||
fn build<'a>(state: &elua::State, builder: &mut elua::UserdataBuilder<'a, Self>) -> elua::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn reflect_user_data(ud: &elua::AnyUserdata) -> ScriptBorrow {
|
||||
ud.execute_method::<_, ScriptBorrow>(FN_NAME_INTERNAL_REFLECT, ())
|
||||
.expect("Type does not implement '__internal_reflect' properly")
|
||||
}
|
|
@ -13,7 +13,7 @@ impl ScriptApiProvider for LyraEcsApiProvider {
|
|||
fn expose_api(&mut self, data: &ScriptData, ctx: &mut Self::ScriptContext) -> Result<(), crate::ScriptError> {
|
||||
let ctx = ctx.lock().unwrap();
|
||||
|
||||
let globals = ctx.globals();
|
||||
let globals = ctx.globals()?;
|
||||
globals.set("World", ctx.create_proxy::<ScriptWorldPtr>()?)?;
|
||||
globals.set("DynamicBundle", ctx.create_proxy::<ScriptDynamicBundle>()?)?;
|
||||
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
use elua::{TableProxy, Userdata};
|
||||
use lyra_ecs::World;
|
||||
use lyra_game::math;
|
||||
use lyra_game::math::{self, Quat, Transform, Vec3};
|
||||
use crate::ScriptData;
|
||||
use crate::lua::RegisterLuaType;
|
||||
use crate::lua::wrappers::{LuaVec3, LuaTransform};
|
||||
|
||||
use crate::{ScriptApiProvider, lua::LuaContext};
|
||||
|
||||
|
@ -13,26 +13,31 @@ impl ScriptApiProvider for LyraMathApiProvider {
|
|||
type ScriptContext = LuaContext;
|
||||
|
||||
fn prepare_world(&mut self, world: &mut World) {
|
||||
world.register_lua_wrapper::<LuaVec3>();
|
||||
world.register_lua_wrapper::<LuaTransform>();
|
||||
// TODO
|
||||
/* world.register_lua_wrapper::<LuaVec3>();
|
||||
world.register_lua_wrapper::<LuaTransform>(); */
|
||||
world.register_lua_table_proxy::<LuaVec3, Vec3>();
|
||||
world.register_lua_table_proxy::<LuaQuat, Quat>();
|
||||
world.register_lua_table_proxy::<LuaTransform, Transform>();
|
||||
}
|
||||
|
||||
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 bytes = include_bytes!("../../../scripts/lua/math/vec3.lua");
|
||||
ctx.load(bytes.to_vec()).exec()?;
|
||||
let bytes = include_bytes!("../../../scripts/lua/math/vec3.lua");
|
||||
ctx.load("lyra/math/vec2.lua", bytes.as_slice())?.execute(())?;
|
||||
|
||||
let bytes = include_bytes!("../../../scripts/lua/math/quat.lua");
|
||||
ctx.load(bytes.to_vec()).exec()?;
|
||||
ctx.load("lyra/math/quat.lua", bytes.as_slice())?.execute(())?;
|
||||
|
||||
let bytes = include_bytes!("../../../scripts/lua/math/transform.lua");
|
||||
ctx.load(bytes.to_vec()).exec()?; */
|
||||
ctx.load("lyra/math/transform.lua", bytes.as_slice())?.execute(())?;
|
||||
|
||||
let globals = ctx.globals();
|
||||
globals.set("Vec3", ctx.create_proxy::<LuaVec3>()?)?;
|
||||
globals.set("Transform", ctx.create_proxy::<LuaTransform>()?)?;
|
||||
//globals.set("Vec3", LuaVec3(math::Vec3::ZERO).into_lua(&ctx)?)?;
|
||||
// TODO
|
||||
//let globals = ctx.globals()?;
|
||||
//globals.set("Vec3", elua::Proxy::<LuaVec3>::from(LuaVec3(Vec3::ZERO)))?;
|
||||
//globals.set("Vec3", ctx.create_proxy::<LuaVec3>()?)?;
|
||||
//globals.set("Transform", ctx.create_proxy::<LuaTransform>()?)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -46,6 +51,94 @@ impl ScriptApiProvider for LyraMathApiProvider {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
struct LuaVec3(Vec3);
|
||||
|
||||
impl TableProxy for LuaVec3 {
|
||||
fn from_table<'a>(_: &'a elua::State, table: elua::Table<'a>) -> elua::Result<Self> {
|
||||
let x: f32 = table.get("x")?;
|
||||
let y: f32 = table.get("y")?;
|
||||
let z: f32 = table.get("z")?;
|
||||
|
||||
Ok(LuaVec3(Vec3 {
|
||||
x,
|
||||
y,
|
||||
z,
|
||||
}))
|
||||
}
|
||||
|
||||
fn as_table<'a>(&self, state: &'a elua::State) -> elua::Result<elua::Table<'a>> {
|
||||
let globals = state.globals()?;
|
||||
let vec3: elua::Table = globals.get("Vec3")?;
|
||||
let new_fn: elua::Function = vec3.get("new")?;
|
||||
new_fn.exec((vec3, self.0.x, self.0.y, self.0.z))
|
||||
}
|
||||
|
||||
fn table_name() -> String {
|
||||
"Vec3".to_string()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
struct LuaQuat(Quat);
|
||||
|
||||
impl TableProxy for LuaQuat {
|
||||
fn from_table<'a>(_: &'a elua::State, table: elua::Table<'a>) -> elua::Result<Self> {
|
||||
let x: f32 = table.get("x")?;
|
||||
let y: f32 = table.get("y")?;
|
||||
let z: f32 = table.get("z")?;
|
||||
let w: f32 = table.get("w")?;
|
||||
|
||||
Ok(LuaQuat(Quat::from_xyzw(x, y, z, w)))
|
||||
}
|
||||
|
||||
fn as_table<'a>(&self, state: &'a elua::State) -> elua::Result<elua::Table<'a>> {
|
||||
let globals = state.globals()?;
|
||||
let quat: elua::Table = globals.get("Quat")?;
|
||||
let new_fn: elua::Function = quat.get("new")?;
|
||||
new_fn.exec((quat, self.0.x, self.0.y, self.0.z, self.0.w))
|
||||
}
|
||||
|
||||
fn table_name() -> String {
|
||||
"Quat".to_string()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
struct LuaTransform(Transform);
|
||||
|
||||
impl TableProxy for LuaTransform {
|
||||
fn from_table<'a>(lua: &'a elua::State, table: elua::Table<'a>) -> elua::Result<Self> {
|
||||
let translation: elua::Table = table.get("translation")?;
|
||||
let rotation: elua::Table = table.get("rotation")?;
|
||||
let scale: elua::Table = table.get("scale")?;
|
||||
|
||||
let translation = LuaVec3::from_table(lua, translation)?;
|
||||
let rotation = LuaQuat::from_table(lua, rotation)?;
|
||||
let scale = LuaVec3::from_table(lua, scale)?;
|
||||
|
||||
Ok(LuaTransform(Transform::new(translation.0, rotation.0, scale.0)))
|
||||
}
|
||||
|
||||
fn as_table<'a>(&self, state: &'a elua::State) -> elua::Result<elua::Table<'a>> {
|
||||
let globals = state.globals()?;
|
||||
let transform: elua::Table = globals.get("Transform")?;
|
||||
let new_fn: elua::Function = transform.get("new")?;
|
||||
|
||||
let translation = LuaVec3(self.0.translation).as_table(state)?;
|
||||
let rotation = LuaQuat(self.0.rotation).as_table(state)?;
|
||||
let scale = LuaVec3(self.0.scale).as_table(state)?;
|
||||
|
||||
new_fn.exec((transform, translation, rotation, scale))
|
||||
}
|
||||
|
||||
fn table_name() -> String {
|
||||
"Transform".to_string()
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/* #[derive(Clone, Copy, PartialEq, Debug, lyra_reflect::Reflect)]
|
||||
pub struct LuaVec3(#[reflect(skip)] math::Vec3);
|
||||
|
||||
|
|
|
@ -17,47 +17,46 @@ use crate::{ScriptApiProvider, ScriptData};
|
|||
pub struct UtilityApiProvider;
|
||||
|
||||
impl ScriptApiProvider for UtilityApiProvider {
|
||||
type ScriptContext = Mutex<mlua::Lua>;
|
||||
type ScriptContext = Mutex<elua::State>;
|
||||
|
||||
fn expose_api(&mut self, data: &ScriptData, ctx: &mut Self::ScriptContext) -> Result<(), crate::ScriptError> {
|
||||
let ctx = ctx.lock().unwrap();
|
||||
|
||||
fn printf(lua: &mlua::Lua, (mut text, formats): (String, mlua::Variadic<mlua::Value>)) -> mlua::Result<()> {
|
||||
//fn printf(lua: &elua::State, (mut text, formats): (String, elua::Variadic<elua::Value>)) -> elua::Result<()> {
|
||||
let printf = |lua: &elua::State, (mut text, formats): (String, elua::Variadic<elua::Value>)| {
|
||||
let mut formatted = String::new();
|
||||
let mut arg_num = 0;
|
||||
|
||||
while let Some(start) = text.find("{}") {
|
||||
let val_str = match formats.get(arg_num) {
|
||||
Some(v) => match v {
|
||||
mlua::Value::Nil => "nil".to_string(),
|
||||
mlua::Value::Boolean(b) => b.to_string(),
|
||||
mlua::Value::LightUserData(_) => {
|
||||
return Err(mlua::Error::RuntimeError(format!("unable to get string representation of LightUserData")));
|
||||
elua::Value::Nil => "nil".to_string(),
|
||||
elua::Value::Boolean(b) => b.to_string(),
|
||||
elua::Value::Number(n) => n.to_string(),
|
||||
elua::Value::String(s) => s.clone(),
|
||||
elua::Value::Table(_) => {
|
||||
return Err(elua::Error::runtime("unable to get string representation of Table"));
|
||||
},
|
||||
mlua::Value::Integer(i) => i.to_string(),
|
||||
mlua::Value::Number(n) => n.to_string(),
|
||||
mlua::Value::String(s) => s.to_str().unwrap().to_string(),
|
||||
mlua::Value::Table(_) => {
|
||||
return Err(mlua::Error::RuntimeError(format!("unable to get string representation of Table")));
|
||||
elua::Value::Function(_) => {
|
||||
return Err(elua::Error::runtime("unable to get string representation of Function"));
|
||||
},
|
||||
mlua::Value::Function(_) => {
|
||||
return Err(mlua::Error::RuntimeError(format!("unable to get string representation of Function")));
|
||||
elua::Value::Thread(_) => {
|
||||
return Err(elua::Error::runtime("unable to get string representation of Thread"));
|
||||
},
|
||||
mlua::Value::Thread(_) => {
|
||||
return Err(mlua::Error::RuntimeError(format!("unable to get string representation of Thread")));
|
||||
},
|
||||
mlua::Value::UserData(ud) => {
|
||||
let metatable = ud.get_metatable()?;
|
||||
if let Ok(tos) = metatable.get::<mlua::Function>(mlua::MetaMethod::ToString) {
|
||||
tos.call::<_, String>((ud.clone(),))?
|
||||
elua::Value::Userdata(ud) => {
|
||||
if let Ok(tos) = ud.get::<_, elua::Function>(elua::MetaMethod::ToString) {
|
||||
tos.exec::<_, String>(())?
|
||||
} else {
|
||||
return Err(mlua::Error::RuntimeError(format!("UserData does not implement MetaMethod '__tostring'")));
|
||||
return Err(elua::Error::runtime("UserData does not implement MetaMethod '__tostring'"));
|
||||
}
|
||||
},
|
||||
mlua::Value::Error(e) => e.to_string(),
|
||||
elua::Value::None => "None".to_string(),
|
||||
elua::Value::Multi(v) => {
|
||||
return Err(elua::Error::runtime("unable to get string representation of ValueVec"));
|
||||
},
|
||||
},
|
||||
None => {
|
||||
let got_args = arg_num;
|
||||
let got_args = arg_num;// - 1;
|
||||
|
||||
// continue searching for {} to get the number of format spots for the error message.
|
||||
while let Some(start) = text.find("{}") {
|
||||
|
@ -65,13 +64,15 @@ impl ScriptApiProvider for UtilityApiProvider {
|
|||
arg_num += 1;
|
||||
}
|
||||
|
||||
return Err(mlua::Error::BadArgument {
|
||||
to: Some("printf".to_string()),
|
||||
pos: 2,
|
||||
name: Some("...".to_string()),
|
||||
cause: Arc::new(mlua::Error::RuntimeError(format!("not enough args \
|
||||
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!(
|
||||
"not enough args \
|
||||
given for the amount of format areas in the string. Expected {}, \
|
||||
got {}.", arg_num, got_args)))
|
||||
got {}.", arg_num, got_args
|
||||
)))
|
||||
})
|
||||
},
|
||||
};
|
||||
|
@ -84,29 +85,31 @@ impl ScriptApiProvider for UtilityApiProvider {
|
|||
}
|
||||
|
||||
if arg_num < formats.len() {
|
||||
return Err(mlua::Error::BadArgument {
|
||||
to: Some("printf".to_string()),
|
||||
pos: 2,
|
||||
name: Some("...".to_string()),
|
||||
cause: Arc::new(mlua::Error::RuntimeError(format!("got more args \
|
||||
than format areas in the string. Expected {}, got {}.", formats.len(), arg_num)))
|
||||
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()
|
||||
.get::<_, mlua::Function>("print")?
|
||||
.call::<_, ()>(formatted)?;
|
||||
lua.globals()?
|
||||
.get::<_, elua::Function>("print")?
|
||||
.exec::<_, ()>(formatted)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
};
|
||||
|
||||
let script_name_reg = ctx.create_registry_value(data.name.clone())?;
|
||||
let script_name_reg = ctx.registry_insert(data.name.clone())?;
|
||||
|
||||
let printf_func = ctx.create_function(printf)?;
|
||||
let print_func = ctx.create_function(move |lua, text: String| {
|
||||
let name = lua.registry_value::<String>(&script_name_reg)?;
|
||||
let name = lua.registry_get::<String>(script_name_reg)?;
|
||||
let _span = debug_span!("lua", script = &name).entered();
|
||||
|
||||
debug!(target: "lyra_scripting::lua", "{}", text);
|
||||
|
@ -114,7 +117,7 @@ impl ScriptApiProvider for UtilityApiProvider {
|
|||
Ok(())
|
||||
})?;
|
||||
|
||||
let globals = ctx.globals();
|
||||
let globals = ctx.globals()?;
|
||||
globals.set("printf", printf_func)?;
|
||||
globals.set("print", print_func)?;
|
||||
|
||||
|
|
|
@ -1,46 +1,51 @@
|
|||
use std::{any::TypeId, ptr::NonNull};
|
||||
use std::{any::TypeId, collections::HashMap, ptr::NonNull};
|
||||
|
||||
use elua::{FromLua, TableProxy};
|
||||
use lyra_ecs::{ComponentInfo, DynamicBundle};
|
||||
use lyra_reflect::{Reflect, FromType};
|
||||
|
||||
use crate::ScriptDynamicBundle;
|
||||
use crate::{ScriptBorrow, ScriptDynamicBundle};
|
||||
|
||||
use super::FN_NAME_INTERNAL_REFLECT;
|
||||
|
||||
pub trait LuaWrapper {
|
||||
/// The type id of the wrapped type.
|
||||
fn wrapped_type_id() -> TypeId;
|
||||
}
|
||||
|
||||
/// A trait that used to convert something into lua, or to set something to a value from lua.
|
||||
pub trait LuaProxy {
|
||||
fn as_lua_value<'lua>(
|
||||
lua: &'lua mlua::Lua,
|
||||
lua: &'lua elua::State,
|
||||
this: &dyn Reflect,
|
||||
) -> mlua::Result<mlua::AnyUserData<'lua>>;
|
||||
) -> elua::Result<elua::AnyUserdata<'lua>>;
|
||||
|
||||
fn apply(
|
||||
lua: &mlua::Lua,
|
||||
lua: &elua::State,
|
||||
this: &mut dyn Reflect,
|
||||
apply: &mlua::AnyUserData,
|
||||
) -> mlua::Result<()>;
|
||||
apply: &elua::AnyUserdata,
|
||||
) -> elua::Result<()>;
|
||||
}
|
||||
|
||||
impl<'a, T> LuaProxy for T
|
||||
where
|
||||
T: Reflect + Clone + mlua::FromLua<'a> + mlua::UserData
|
||||
T: Reflect + Clone + elua::FromLua<'a> + elua::Userdata
|
||||
{
|
||||
fn as_lua_value<'lua>(
|
||||
lua: &'lua mlua::Lua,
|
||||
lua: &'lua elua::State,
|
||||
this: &dyn Reflect,
|
||||
) -> mlua::Result<mlua::AnyUserData<'lua>> {
|
||||
) -> elua::Result<elua::AnyUserdata<'lua>> {
|
||||
let this = this.as_any().downcast_ref::<T>().unwrap();
|
||||
lua.create_userdata(this.clone())
|
||||
}
|
||||
|
||||
fn apply(
|
||||
_lua: &mlua::Lua,
|
||||
_: &elua::State,
|
||||
this: &mut dyn Reflect,
|
||||
apply: &mlua::AnyUserData,
|
||||
) -> mlua::Result<()> {
|
||||
apply: &elua::AnyUserdata,
|
||||
) -> elua::Result<()> {
|
||||
let this = this.as_any_mut().downcast_mut::<T>().unwrap();
|
||||
let apply = apply.borrow::<T>()?;
|
||||
let apply = apply.as_ref::<T>()?;
|
||||
|
||||
*this = apply.clone();
|
||||
|
||||
|
@ -48,24 +53,66 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
/// A struct that is used for retrieving rust type ids of types that implement `TableProxy`.
|
||||
#[derive(Default)]
|
||||
pub struct LuaTableProxyLookup {
|
||||
pub(crate) typeid_from_name: HashMap<String, TypeId>,
|
||||
pub(crate) comp_info_from_name: HashMap<String, ComponentInfo>,
|
||||
}
|
||||
|
||||
/// A struct used for converting types that implement `TableProxy` to and from Lua.
|
||||
#[derive(Clone)]
|
||||
pub struct ReflectedLuaTableProxy {
|
||||
pub table_name: String,
|
||||
pub fn_as_table:
|
||||
for<'a> fn(lua: &'a elua::State, this_ptr: NonNull<()>) -> elua::Result<elua::Table<'a>>,
|
||||
pub fn_apply: for<'a> fn(
|
||||
lua: &'a elua::State,
|
||||
this_ptr: NonNull<()>,
|
||||
table: &'a elua::Table<'a>,
|
||||
) -> elua::Result<()>,
|
||||
}
|
||||
|
||||
impl<'a, T> FromType<T> for ReflectedLuaTableProxy
|
||||
where
|
||||
T: TableProxy
|
||||
{
|
||||
fn from_type() -> Self {
|
||||
Self {
|
||||
table_name: T::table_name(),
|
||||
fn_as_table: |lua, this| -> elua::Result<elua::Table> {
|
||||
let this = unsafe { this.cast::<T>().as_ref() };
|
||||
this.as_table(lua)
|
||||
},
|
||||
fn_apply: |lua, ptr, table| {
|
||||
let this = unsafe { ptr.cast::<T>().as_mut() };
|
||||
let tbl = T::from_table(lua, table.clone())?;
|
||||
*this = tbl;
|
||||
Ok(())
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A struct used for converting types that implement `LuaProxy` to and from Lua.
|
||||
#[derive(Clone)]
|
||||
pub struct ReflectLuaProxy {
|
||||
pub fn_as_uservalue:
|
||||
for<'a> fn(lua: &'a mlua::Lua, this_ptr: NonNull<u8>) -> mlua::Result<mlua::AnyUserData<'a>>,
|
||||
for<'a> fn(lua: &'a elua::State, this_ptr: NonNull<u8>) -> elua::Result<elua::AnyUserdata<'a>>,
|
||||
pub fn_apply: for<'a> fn(
|
||||
lua: &'a mlua::Lua,
|
||||
lua: &'a elua::State,
|
||||
this_ptr: NonNull<u8>,
|
||||
apply: &'a mlua::AnyUserData<'a>,
|
||||
) -> mlua::Result<()>,
|
||||
apply: &'a elua::AnyUserdata<'a>,
|
||||
) -> elua::Result<()>,
|
||||
}
|
||||
|
||||
impl<'a, T> FromType<T> for ReflectLuaProxy
|
||||
where
|
||||
T: Reflect + LuaProxy + Clone + mlua::FromLua<'a> + mlua::UserData
|
||||
T: Reflect + LuaProxy + Clone + elua::FromLua<'a> + elua::Userdata
|
||||
{
|
||||
fn from_type() -> Self {
|
||||
Self {
|
||||
fn_as_uservalue: |lua, this| -> mlua::Result<mlua::AnyUserData> {
|
||||
fn_as_uservalue: |lua, this| -> elua::Result<elua::AnyUserdata> {
|
||||
let this = unsafe { this.cast::<T>().as_ref() };
|
||||
<T as LuaProxy>::as_lua_value(lua, this)
|
||||
},
|
||||
|
@ -77,16 +124,45 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<'lua> mlua::FromLua<'lua> for ScriptDynamicBundle {
|
||||
fn from_lua(value: mlua::Value<'lua>, _lua: &'lua mlua::Lua) -> mlua::Result<Self> {
|
||||
match value {
|
||||
mlua::Value::UserData(ud) => Ok(ud.borrow::<Self>()?.clone()),
|
||||
mlua::Value::Nil => Err(mlua::Error::FromLuaConversionError {
|
||||
from: "Nil",
|
||||
to: "DynamicBundle",
|
||||
message: Some("Value was nil".to_string()),
|
||||
}),
|
||||
_ => panic!(),
|
||||
impl<'lua> elua::FromLua<'lua> for ScriptDynamicBundle {
|
||||
fn from_lua(_: &'lua elua::State, val: elua::Value<'lua>) -> elua::Result<Self> {
|
||||
match val {
|
||||
elua::Value::Userdata(ud) => Ok(ud.as_ref::<Self>()?.clone()),
|
||||
elua::Value::Nil => Err(elua::Error::Nil),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'lua> elua::FromLuaVec<'lua> for ScriptDynamicBundle {
|
||||
fn from_lua_value_vec(state: &'lua elua::State, mut values: elua::ValueVec<'lua>) -> elua::Result<Self> {
|
||||
if let Some(v) = values.pop_front() {
|
||||
Ok(ScriptDynamicBundle::from_lua(state, v)?)
|
||||
} else {
|
||||
Err(elua::Error::Nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl elua::Userdata for ScriptDynamicBundle {
|
||||
fn name() -> String {
|
||||
"Bundle".to_string()
|
||||
}
|
||||
|
||||
fn build<'a>(_: &elua::State, builder: &mut elua::UserdataBuilder<'a, Self>) -> elua::Result<()> {
|
||||
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();
|
||||
let refl_data = refl_data.as_ref();
|
||||
reflect.bundle_insert(&mut this.0, refl_data);
|
||||
|
||||
Ok(())
|
||||
});
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
use std::sync::Mutex;
|
||||
|
||||
use mlua::IntoLua;
|
||||
use elua::{AsLua, StdLibraries, StdLibrary};
|
||||
use tracing::{debug, trace};
|
||||
|
||||
use crate::{ScriptHost, ScriptError, ScriptWorldPtr, ScriptEntity};
|
||||
|
@ -8,40 +8,37 @@ use crate::{ScriptHost, ScriptError, ScriptWorldPtr, ScriptEntity};
|
|||
#[derive(Default)]
|
||||
pub struct LuaHost;
|
||||
|
||||
fn try_call_lua_function(lua: &mlua::Lua, fn_name: &str) -> Result<(), ScriptError> {
|
||||
let globals = lua.globals();
|
||||
fn try_call_lua_function(lua: &elua::State, fn_name: &str) -> Result<(), ScriptError> {
|
||||
let globals = lua.globals()?;
|
||||
|
||||
match globals.get::<_, mlua::Function>(fn_name) {
|
||||
Ok(init_fn) => {
|
||||
init_fn.call(())
|
||||
if globals.has_key(fn_name)? {
|
||||
let lua_fn = globals.get::<_, elua::Function>(fn_name)?;
|
||||
lua_fn.exec(())
|
||||
.map_err(ScriptError::MluaError)?;
|
||||
},
|
||||
Err(mlua::Error::FromLuaConversionError { from: "nil", to: "function", message: None }) => {
|
||||
trace!("Function '{}' was not found, ignoring...", fn_name)
|
||||
// ignore
|
||||
},
|
||||
Err(e) => {
|
||||
return Err(ScriptError::MluaError(e));
|
||||
},
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
impl ScriptHost for LuaHost {
|
||||
type ScriptContext = Mutex<mlua::Lua>;
|
||||
type ScriptContext = Mutex<elua::State>;
|
||||
|
||||
fn load_script(&mut self, script: &[u8], script_data: &crate::ScriptData, providers: &mut crate::ScriptApiProviders<Self>) -> Result<Self::ScriptContext, crate::ScriptError> {
|
||||
let mut ctx = Mutex::new(mlua::Lua::new());
|
||||
let mut ctx = Mutex::new({
|
||||
let s = elua::State::new();
|
||||
s.expose_libraries(&[StdLibrary::Debug, StdLibrary::Package]);
|
||||
s
|
||||
});
|
||||
|
||||
//Mutex::new(elua::State::new_with_libraries(StdLibraries::all()));
|
||||
|
||||
for provider in providers.apis.iter_mut() {
|
||||
provider.expose_api(script_data, &mut ctx)?;
|
||||
}
|
||||
|
||||
let lua = ctx.lock().unwrap();
|
||||
lua.load(script)
|
||||
.set_name(&script_data.name)
|
||||
.exec()
|
||||
lua.load(&script_data.name, script)?
|
||||
.execute(())
|
||||
.map_err(|e| ScriptError::MluaError(e))?;
|
||||
drop(lua);
|
||||
|
||||
|
@ -71,9 +68,9 @@ impl ScriptHost for LuaHost {
|
|||
|
||||
let ctx = ctx.lock().expect("Failure to get Lua ScriptContext");
|
||||
|
||||
let globals = ctx.globals();
|
||||
globals.set("world", world.into_lua(&ctx)?)?;
|
||||
globals.set("entity", ScriptEntity(script_data.entity).into_lua(&ctx)?)?;
|
||||
let globals = ctx.globals()?;
|
||||
globals.set("world", world.as_lua(&ctx)?)?;
|
||||
globals.set("entity", ScriptEntity(script_data.entity).as_lua(&ctx)?)?;
|
||||
|
||||
try_call_lua_function(&ctx, function_name)?;
|
||||
|
||||
|
|
|
@ -1,177 +0,0 @@
|
|||
use std::{sync::{Mutex, Arc}, ptr::NonNull};
|
||||
|
||||
use lyra_ecs::{World, system::{GraphExecutor, IntoSystem}};
|
||||
use lyra_resource::ResourceManager;
|
||||
use mlua::{IntoLua, AnyUserDataExt};
|
||||
use tracing_subscriber::{layer::SubscriberExt, fmt, util::SubscriberInitExt};
|
||||
|
||||
use crate::{ScriptData, ScriptApiProvider, ScriptApiProviders, ScriptError, ScriptList, Script, ScriptContexts};
|
||||
|
||||
use super::{LuaHost, LuaLoader, LuaScript, lua_script_update_stage_system, lua_scripts_create_contexts, LuaContext};
|
||||
|
||||
fn enable_tracing() {
|
||||
tracing_subscriber::registry()
|
||||
.with(fmt::layer().with_writer(std::io::stdout))
|
||||
.init();
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct PrintfProvider;
|
||||
|
||||
impl ScriptApiProvider for PrintfProvider {
|
||||
type ScriptContext = Mutex<mlua::Lua>;
|
||||
|
||||
fn expose_api(&mut self, script_data: &ScriptData, ctx: &mut Self::ScriptContext) -> Result<(), crate::ScriptError> {
|
||||
let ctx = ctx.lock().unwrap();
|
||||
|
||||
fn printf(lua: &mlua::Lua, (mut text, formats): (String, mlua::Variadic<mlua::Value>)) -> mlua::Result<()> {
|
||||
let mut formatted = String::new();
|
||||
let mut arg_num = 0;
|
||||
|
||||
while let Some(start) = text.find("{}") {
|
||||
let val_str = match formats.get(arg_num) {
|
||||
Some(v) => match v {
|
||||
mlua::Value::Nil => "nil".to_string(),
|
||||
mlua::Value::Boolean(b) => b.to_string(),
|
||||
mlua::Value::LightUserData(_) => {
|
||||
return Err(mlua::Error::RuntimeError(format!("unable to get string representation of LightUserData")));
|
||||
},
|
||||
mlua::Value::Integer(i) => i.to_string(),
|
||||
mlua::Value::Number(n) => n.to_string(),
|
||||
mlua::Value::String(s) => s.to_str().unwrap().to_string(),
|
||||
mlua::Value::Table(_) => {
|
||||
return Err(mlua::Error::RuntimeError(format!("unable to get string representation of Table")));
|
||||
},
|
||||
mlua::Value::Function(_) => {
|
||||
return Err(mlua::Error::RuntimeError(format!("unable to get string representation of Function")));
|
||||
},
|
||||
mlua::Value::Thread(_) => {
|
||||
return Err(mlua::Error::RuntimeError(format!("unable to get string representation of Thread")));
|
||||
},
|
||||
mlua::Value::UserData(ud) => {
|
||||
if let Ok(tos) = ud.get::<_, mlua::Function>(mlua::MetaMethod::ToString.to_string()) {
|
||||
tos.call::<_, String>(())?
|
||||
} else {
|
||||
return Err(mlua::Error::RuntimeError(format!("UserData does not implement MetaMethod '__tostring'")));
|
||||
}
|
||||
},
|
||||
mlua::Value::Error(e) => e.to_string(),
|
||||
},
|
||||
None => {
|
||||
let got_args = arg_num;// - 1;
|
||||
|
||||
// continue searching for {} to get the number of format spots for the error message.
|
||||
while let Some(start) = text.find("{}") {
|
||||
text = text[start + 2..].to_string();
|
||||
arg_num += 1;
|
||||
}
|
||||
|
||||
return Err(mlua::Error::BadArgument {
|
||||
to: Some("printf".to_string()),
|
||||
pos: 2,
|
||||
name: Some("...".to_string()),
|
||||
cause: Arc::new(mlua::Error::RuntimeError(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();
|
||||
|
||||
arg_num += 1;
|
||||
}
|
||||
|
||||
if arg_num < formats.len() {
|
||||
return Err(mlua::Error::BadArgument {
|
||||
to: Some("printf".to_string()),
|
||||
pos: 2,
|
||||
name: Some("...".to_string()),
|
||||
cause: Arc::new(mlua::Error::RuntimeError(format!("got more args \
|
||||
than format areas in the string. Expected {}, got {}.", formats.len(), arg_num)))
|
||||
})
|
||||
}
|
||||
|
||||
formatted = format!("{}{}", formatted, text);
|
||||
|
||||
lua.globals()
|
||||
.get::<_, mlua::Function>("print")
|
||||
.unwrap()
|
||||
.call::<_, ()>(formatted)
|
||||
.unwrap();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
let printf_func = ctx.create_function(printf).unwrap();
|
||||
|
||||
let globals = ctx.globals();
|
||||
globals.set("printf", printf_func).unwrap();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn setup_script(&mut self, _data: &ScriptData, _ctx: &mut Self::ScriptContext) -> Result<(), crate::ScriptError> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn update_script_environment(&mut self, world: crate::ScriptWorldPtr, _data: &ScriptData, ctx: &mut Self::ScriptContext) -> Result<(), crate::ScriptError> {
|
||||
let ctx = ctx.lock().unwrap();
|
||||
let globals = ctx.globals();
|
||||
|
||||
let world_lua = world.into_lua(&ctx)
|
||||
.map_err(ScriptError::MluaError)?;
|
||||
globals.set("world", world_lua)
|
||||
.map_err(ScriptError::MluaError)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Tests a simple lua script that just prints some test
|
||||
#[test]
|
||||
pub fn lua_print() {
|
||||
enable_tracing();
|
||||
|
||||
let mut world = World::new();
|
||||
|
||||
let test_provider = PrintfProvider::default();
|
||||
let mut providers = ScriptApiProviders::<LuaHost>::default();
|
||||
providers.add_provider(test_provider);
|
||||
|
||||
let host = LuaHost::default();
|
||||
|
||||
world.add_resource(host);
|
||||
world.add_resource(providers);
|
||||
world.add_resource(ScriptContexts::<LuaContext>::default());
|
||||
|
||||
let mut res_loader = ResourceManager::new();
|
||||
res_loader.register_loader::<LuaLoader>();
|
||||
|
||||
let script =
|
||||
r#"
|
||||
print("Hello World")
|
||||
|
||||
function update()
|
||||
print("updated")
|
||||
printf("I love to eat formatted {}!", "food")
|
||||
--printf("World is {}", world)
|
||||
end
|
||||
"#;
|
||||
let script = script.as_bytes();
|
||||
|
||||
let script = res_loader.load_bytes::<LuaScript>("test_script.lua",
|
||||
"text/lua", script.to_vec(), 0, script.len()).unwrap();
|
||||
let script = Script::new("text_script.lua", script);
|
||||
|
||||
let scripts = ScriptList::new(vec![script]);
|
||||
|
||||
world.spawn((scripts,));
|
||||
|
||||
let mut exec = GraphExecutor::new();
|
||||
exec.insert_system("lua_create_contexts", lua_scripts_create_contexts.into_system(), &[]);
|
||||
exec.insert_system("lua_update_scripts", lua_script_update_stage_system.into_system(), &["lua_create_contexts"]);
|
||||
exec.execute(NonNull::from(&world), true).unwrap();
|
||||
}
|
|
@ -1,28 +1,33 @@
|
|||
use std::{sync::{Arc, RwLock}, ptr::NonNull, any::Any, ops::Deref};
|
||||
use std::{any::Any, ptr::NonNull, sync::Arc};
|
||||
|
||||
use elua::AsLua;
|
||||
use lyra_ecs::query::dynamic::QueryDynamicType;
|
||||
use lyra_reflect::{TypeRegistry, ReflectWorldExt, RegisteredType};
|
||||
use mlua::{AnyUserDataExt, IntoLua, IntoLuaMulti};
|
||||
|
||||
use crate::{ScriptWorldPtr, ScriptEntity, ScriptDynamicBundle, ScriptBorrow};
|
||||
|
||||
use super::{ReflectedIterator, DynamicViewIter, FN_NAME_INTERNAL_REFLECT_TYPE, reflect_user_data, ReflectLuaProxy, FN_NAME_INTERNAL_REFLECT};
|
||||
use super::{reflect_user_data, DynamicViewIter, LuaTableProxyLookup, ReflectLuaProxy, ReflectedIterator, ReflectedLuaTableProxy, FN_NAME_INTERNAL_REFLECT, FN_NAME_INTERNAL_REFLECT_TYPE};
|
||||
|
||||
impl<'lua> mlua::FromLua<'lua> for ScriptEntity {
|
||||
fn from_lua(value: mlua::Value<'lua>, _lua: &'lua mlua::Lua) -> mlua::Result<Self> {
|
||||
impl<'lua> elua::FromLua<'lua> for ScriptEntity {
|
||||
fn from_lua(_: &'lua elua::State, value: elua::Value<'lua>) -> elua::Result<Self> {
|
||||
match value {
|
||||
mlua::Value::UserData(ud) => Ok(ud.borrow::<Self>()?.clone()),
|
||||
mlua::Value::Nil => Err(mlua::Error::FromLuaConversionError { from: "Nil", to: "ScriptEntity", message: Some("Value was nil".to_string()) }),
|
||||
elua::Value::Userdata(ud) => Ok(ud.as_ref::<Self>()?.clone()),
|
||||
elua::Value::Nil => Err(elua::Error::type_mismatch("ScriptEntity", "Nil")),
|
||||
_ => panic!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl mlua::UserData for ScriptEntity {
|
||||
fn add_methods<'lua, M: mlua::prelude::LuaUserDataMethods<'lua, Self>>(methods: &mut M) {
|
||||
methods.add_meta_method(mlua::MetaMethod::ToString, |_, this, ()| {
|
||||
impl elua::Userdata for ScriptEntity {
|
||||
fn name() -> String {
|
||||
"Entity".to_string()
|
||||
}
|
||||
|
||||
fn build<'a>(state: &elua::State, builder: &mut elua::userdata::UserdataBuilder<'a, Self>) -> elua::Result<()> {
|
||||
builder.meta_method(elua::MetaMethod::ToString, |_, this, ()| {
|
||||
Ok(format!("{:?}", this.0))
|
||||
})
|
||||
});
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -32,64 +37,74 @@ pub enum WorldError {
|
|||
LuaInvalidUsage(String),
|
||||
}
|
||||
|
||||
impl mlua::UserData for ScriptWorldPtr {
|
||||
fn add_methods<'lua, M: mlua::prelude::LuaUserDataMethods<'lua, Self>>(methods: &mut M) {
|
||||
methods.add_method_mut("spawn", |_, this, (bundle,): (ScriptDynamicBundle,)| {
|
||||
let world = unsafe { this.inner.as_mut() };
|
||||
impl<'a> elua::FromLua<'a> for ScriptWorldPtr {
|
||||
fn from_lua(lua: &'a elua::State, val: elua::Value<'a>) -> elua::Result<Self> {
|
||||
match val {
|
||||
elua::Value::Userdata(ud) => Ok(ud.as_ref::<Self>()?.clone()),
|
||||
elua::Value::Nil => Err(elua::Error::type_mismatch("ScriptWorldPtr", "Nil")),
|
||||
_ => panic!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl elua::Userdata for ScriptWorldPtr {
|
||||
fn name() -> String {
|
||||
"World".to_string()
|
||||
}
|
||||
|
||||
fn build<'a>(state: &elua::State, builder: &mut elua::UserdataBuilder<'a, Self>) -> elua::Result<()> {
|
||||
builder
|
||||
.method("test", |_, this, ()| {
|
||||
println!("hgello world");
|
||||
Ok(())
|
||||
})
|
||||
.method_mut("spawn", |_, this, bundle: ScriptDynamicBundle| {
|
||||
let world = this.as_mut();
|
||||
|
||||
Ok(ScriptEntity(world.spawn(bundle.0)))
|
||||
});
|
||||
|
||||
methods.add_method("view_iter", |lua, this, queries: mlua::Variadic<mlua::AnyUserData>| {
|
||||
let world = unsafe { this.inner.as_ref() };
|
||||
let mut view = world.dynamic_view();
|
||||
|
||||
for comp in queries.into_iter() {
|
||||
let script_brw = comp.call_function::<_, ScriptBorrow>(FN_NAME_INTERNAL_REFLECT_TYPE, ())
|
||||
.expect("Type does not implement '__internal_reflect_type' properly");
|
||||
let refl_comp = script_brw.reflect_branch.as_component_unchecked();
|
||||
|
||||
let dyn_type = QueryDynamicType::from_info(refl_comp.info);
|
||||
view.push(dyn_type);
|
||||
}
|
||||
|
||||
let iter = view.into_iter();
|
||||
let mut reflected_iter = ReflectedIterator {
|
||||
world: this.clone(),
|
||||
dyn_view: DynamicViewIter::from(iter),
|
||||
reflected_components: None,
|
||||
};
|
||||
|
||||
let f = lua.create_function_mut(move |lua, ()| {
|
||||
if let Some(row) = reflected_iter.next_lua(lua) {
|
||||
let row = row.row.into_iter().map(|i| i.comp_ud.into_lua(lua))
|
||||
.collect::<mlua::Result<Vec<mlua::Value>>>()?;
|
||||
Ok(mlua::MultiValue::from_vec(row))
|
||||
} else {
|
||||
Ok(mlua::Value::Nil.into_lua_multi(lua)?)
|
||||
}
|
||||
})?;
|
||||
|
||||
Ok(f)
|
||||
});
|
||||
|
||||
methods.add_method_mut("view", |lua, this, (system, queries): (mlua::Function, mlua::Variadic<mlua::AnyUserData>)| {
|
||||
})
|
||||
.method_mut("view", |lua, this, (system, queries): (elua::Function, elua::ValueVec)| {
|
||||
if queries.is_empty() {
|
||||
return Err(mlua::Error::BadArgument { to: Some("world:view".to_string()), pos: 2, name: Some("...".to_string()), cause:
|
||||
Arc::new(mlua::Error::external(WorldError::LuaInvalidUsage("no component types provided".to_string())))
|
||||
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 mut view = world.dynamic_view();
|
||||
|
||||
for comp in queries.into_iter() {
|
||||
let reflect = comp.call_function::<_, ScriptBorrow>(FN_NAME_INTERNAL_REFLECT_TYPE, ())
|
||||
for (idx, comp) in queries.into_iter().enumerate() {
|
||||
match comp {
|
||||
elua::Value::Table(t) => {
|
||||
let name: String = t.get("__name")?;
|
||||
|
||||
let lookup = world.get_resource::<LuaTableProxyLookup>();
|
||||
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!", name))
|
||||
)
|
||||
}
|
||||
)?;
|
||||
|
||||
let dyn_type = QueryDynamicType::from_info(info.clone());
|
||||
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!()
|
||||
}
|
||||
}
|
||||
|
||||
let iter = view.into_iter();
|
||||
|
@ -103,19 +118,15 @@ impl mlua::UserData for ScriptWorldPtr {
|
|||
let mut has_ticked = false;
|
||||
|
||||
while let Some(row) = reflected_iter.next_lua(lua) {
|
||||
|
||||
let r = row.row.into_iter()
|
||||
.map(|r| (r.proxy, r.comp_ud, r.comp_ptr))
|
||||
.map(|r| (r.comp_val, r.comp_ptr))
|
||||
.collect::<Vec<_>>();
|
||||
let (reflects, values, ptrs):
|
||||
(Vec<&ReflectLuaProxy>, Vec<mlua::AnyUserData>, Vec<NonNull<u8>>)
|
||||
= itertools::multiunzip(r);
|
||||
let value_row: Vec<_> = values.into_iter().map(|ud| ud.into_lua(lua)).collect::<mlua::Result<Vec<mlua::Value>>>()?;
|
||||
let mult_val = mlua::MultiValue::from_vec(value_row);
|
||||
let res: mlua::MultiValue = system.call(mult_val)?;
|
||||
let (values, ptrs) = itertools::multiunzip::<(Vec<elua::Value>, Vec<NonNull<u8>>), _>(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() <= reflects.len() {
|
||||
if res.len() <= ptrs.len() {
|
||||
// we only want to tick one time per system
|
||||
if !has_ticked {
|
||||
current = world.tick();
|
||||
|
@ -125,9 +136,9 @@ impl mlua::UserData for ScriptWorldPtr {
|
|||
for (i, comp) in res.into_iter().enumerate() {
|
||||
let ptr = ptrs[i];
|
||||
|
||||
match comp.as_userdata() {
|
||||
Some(ud) => {
|
||||
let lua_comp = reflect_user_data(ud);
|
||||
match comp {
|
||||
elua::Value::Userdata(ud) => {
|
||||
let lua_comp = reflect_user_data(&ud);
|
||||
let refl_comp = lua_comp.reflect_branch.as_component_unchecked();
|
||||
let lua_typeid = refl_comp.info.type_id.as_rust();
|
||||
|
||||
|
@ -142,27 +153,48 @@ impl mlua::UserData for ScriptWorldPtr {
|
|||
let reg = this.as_ref().get_resource::<TypeRegistry>();
|
||||
let reg_type = reg.get_type(lua_typeid).unwrap();
|
||||
|
||||
let proxy = reg_type.get_data::<ReflectLuaProxy>().unwrap();
|
||||
(proxy.fn_apply)(lua, ptr, ud)?;
|
||||
}
|
||||
None => {
|
||||
panic!("A userdata value was not returned!");
|
||||
let proxy = reg_type.get_data::<ReflectLuaProxy>()
|
||||
.expect("Type does not have ReflectLuaProxy as a TypeData");
|
||||
(proxy.fn_apply)(lua, ptr, &ud)?;
|
||||
},
|
||||
elua::Value::Table(tbl) => {
|
||||
let name: String = tbl.get("__name")?;
|
||||
|
||||
let lookup = world.get_resource::<LuaTableProxyLookup>();
|
||||
let tyid = lookup.typeid_from_name.get(&name).unwrap();
|
||||
|
||||
// update the component tick
|
||||
let world = unsafe { this.inner.as_mut() };
|
||||
let arch = world.entity_archetype_mut(row.entity).unwrap();
|
||||
let idx = arch.entities().get(&row.entity).unwrap().clone();
|
||||
let c = arch.get_column_mut(tyid.clone().into()).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(*tyid).unwrap();
|
||||
|
||||
let proxy = reg_type.get_data::<ReflectedLuaTableProxy>()
|
||||
.expect("Type does not have ReflectLuaProxy as a TypeData");
|
||||
(proxy.fn_apply)(lua, ptr.cast(), &tbl)?;
|
||||
},
|
||||
_ => {
|
||||
panic!("A userdata or table value was not returned!");
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let msg = format!("Too many arguments were returned from the World view!
|
||||
At most, the expected number of results is {}.", reflects.len());
|
||||
return Err(mlua::Error::external(WorldError::LuaInvalidUsage(msg)));
|
||||
At most, the expected number of results is {}.", ptrs.len());
|
||||
return Err(elua::Error::Runtime(msg));
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
});
|
||||
|
||||
methods.add_method_mut("resource", |lua, this, (ty,): (mlua::AnyUserData,)| {
|
||||
})
|
||||
.method_mut("resource", |lua, this, (ty,): (elua::AnyUserdata,)| {
|
||||
let reflect = ty
|
||||
.call_function::<_, ScriptBorrow>(FN_NAME_INTERNAL_REFLECT_TYPE, ())
|
||||
.execute_function::<_, ScriptBorrow>(FN_NAME_INTERNAL_REFLECT_TYPE, ())
|
||||
.expect("Type does not implement 'reflect_type' properly");
|
||||
|
||||
let res = reflect.reflect_branch.as_resource_unchecked();
|
||||
|
@ -174,11 +206,13 @@ impl mlua::UserData for ScriptWorldPtr {
|
|||
.expect("Type does not have ReflectLuaProxy as a TypeData");
|
||||
|
||||
(proxy.fn_as_uservalue)(lua, res_ptr)
|
||||
.and_then(|ud| ud.into_lua(lua))
|
||||
.and_then(|ud| ud.as_lua(lua))
|
||||
} else {
|
||||
// if the resource is not found in the world, return nil
|
||||
Ok(mlua::Value::Nil)
|
||||
Ok(elua::Value::Nil)
|
||||
}
|
||||
});
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
use std::{ops::Deref, any::TypeId};
|
||||
use std::any::TypeId;
|
||||
|
||||
use lyra_game::DeltaTime;
|
||||
use crate::{lyra_engine, lua::{FN_NAME_INTERNAL_REFLECT_TYPE, LuaWrapper}, ScriptBorrow};
|
||||
|
@ -20,28 +20,33 @@ impl std::ops::DerefMut for LuaDeltaTime {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'lua> mlua::FromLua<'lua> for LuaDeltaTime {
|
||||
fn from_lua(value: mlua::prelude::LuaValue<'lua>, lua: &'lua mlua::prelude::Lua) -> mlua::prelude::LuaResult<Self> {
|
||||
impl<'lua> elua::FromLua<'lua> for LuaDeltaTime {
|
||||
fn from_lua(lua: &'lua elua::State, value: elua::Value<'lua>) -> elua::Result<Self> {
|
||||
match value {
|
||||
mlua::Value::UserData(ud) => Ok(ud.borrow::<Self>()?.clone()),
|
||||
elua::Value::Userdata(ud) => Ok(ud.as_ref::<Self>()?.clone()),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl mlua::UserData for LuaDeltaTime {
|
||||
fn add_methods<'lua, M: mlua::prelude::LuaUserDataMethods<'lua, Self>>(methods: &mut M) {
|
||||
methods.add_method("get", |_, this, ()| {
|
||||
Ok(*this.0.deref())
|
||||
});
|
||||
impl elua::Userdata for LuaDeltaTime {
|
||||
fn name() -> String {
|
||||
"DeltaTime".to_string()
|
||||
}
|
||||
|
||||
methods.add_meta_method(mlua::MetaMethod::ToString, |_, this, ()| {
|
||||
Ok(format!("{}", this.0.deref()))
|
||||
});
|
||||
|
||||
methods.add_function(FN_NAME_INTERNAL_REFLECT_TYPE, |_, ()| {
|
||||
fn build<'a>(state: &elua::State, builder: &mut elua::UserdataBuilder<'a, Self>) -> elua::Result<()> {
|
||||
builder
|
||||
.method("get", |_, this, ()| {
|
||||
Ok(*this.0)
|
||||
})
|
||||
.meta_method(elua::MetaMethod::ToString, |_, this, ()| {
|
||||
Ok(format!("{}", *this.0))
|
||||
})
|
||||
.function(FN_NAME_INTERNAL_REFLECT_TYPE, |_, ()| {
|
||||
Ok(ScriptBorrow::from_resource::<DeltaTime>(None))
|
||||
});
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ use lyra_scripting_derive::wrap_math_vec_copy;
|
|||
use crate as lyra_scripting;
|
||||
|
||||
// f32 types
|
||||
wrap_math_vec_copy!(
|
||||
/* wrap_math_vec_copy!(
|
||||
math::Vec2,
|
||||
derives(PartialEq),
|
||||
fields(x, y),
|
||||
|
@ -32,7 +32,11 @@ wrap_math_vec_copy!(
|
|||
Mod(LuaVec3, f32),
|
||||
Eq, Unm, ToString
|
||||
)
|
||||
);
|
||||
); */
|
||||
|
||||
|
||||
// =================================================
|
||||
|
||||
|
||||
/* wrap_math_vec_copy!(
|
||||
math::Vec3A,
|
||||
|
@ -379,7 +383,20 @@ wrap_math_vec_copy!(
|
|||
)
|
||||
); */
|
||||
|
||||
wrap_math_vec_copy!(
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// ============================================================
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/* wrap_math_vec_copy!(
|
||||
math::Quat,
|
||||
derives(PartialEq),
|
||||
no_new,
|
||||
|
@ -559,3 +576,4 @@ wrap_math_vec_copy!(
|
|||
});
|
||||
}
|
||||
);
|
||||
*/
|
Loading…
Reference in New Issue