Create an early scripting engine #2
|
@ -12,18 +12,51 @@ function on_pre_update()
|
||||||
print("Lua's pre-update function was called")
|
print("Lua's pre-update function was called")
|
||||||
end ]]
|
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()
|
function on_update()
|
||||||
--print("Lua's update function was called")
|
--print("Lua's update function was called")
|
||||||
|
|
||||||
local dt = world:resource(DeltaTime)
|
--local v = Vec3:new(50, 10, 20)
|
||||||
--print("DeltaTime was " .. tostring(dt) .. "s")
|
--print("Vec3 = " .. tostring(v))
|
||||||
|
|
||||||
world:view(function (t)
|
world:view(
|
||||||
--print("Found entity at a really cool place: " .. tostring(t))
|
---@param t Transform
|
||||||
t.translation = t.translation + (Vec3.new(0, 0.5, 0) * dt:get())
|
function (t)
|
||||||
|
print("Found entity at a really cool place: " .. tostring(t))
|
||||||
|
t.translation:move_by(0, 0.001, 0)
|
||||||
|
|
||||||
return t
|
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
|
end
|
||||||
|
|
||||||
--[[ function on_post_update()
|
--[[ function on_post_update()
|
||||||
|
|
|
@ -84,16 +84,16 @@ async fn main() {
|
||||||
|
|
||||||
let mut resman = world.get_resource_mut::<ResourceManager>();
|
let mut resman = world.get_resource_mut::<ResourceManager>();
|
||||||
//let diffuse_texture = resman.request::<Texture>("assets/happy-tree.png").unwrap();
|
//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/cube-texture-bin.glb").unwrap();
|
||||||
let cube_model = resman.request::<Model>("assets/texture-sep/texture-sep.gltf").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();
|
let crate_model = resman.request::<Model>("assets/crate/crate.gltf").unwrap();
|
||||||
drop(resman);
|
drop(resman);
|
||||||
|
|
||||||
world.spawn((
|
/* world.spawn((
|
||||||
ModelComponent(antique_camera_model),
|
ModelComponent(antique_camera_model),
|
||||||
Transform::from_xyz(0.0, -5.0, -10.0),
|
Transform::from_xyz(0.0, -5.0, -10.0),
|
||||||
));
|
)); */
|
||||||
|
|
||||||
{
|
{
|
||||||
let cube_tran = Transform::from_xyz(-3.5, 0.0, -8.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(fmt::layer().with_writer(stdout_layer))
|
||||||
.with(filter::Targets::new()
|
.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::TRACE)
|
||||||
.with_target("wgpu", Level::WARN)
|
.with_target("wgpu", Level::WARN)
|
||||||
.with_default(Level::INFO))
|
.with_default(Level::INFO))
|
||||||
.init();
|
.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 = { x = 0.0, y = 0.0, z = 0.0, w = 0.0 }
|
||||||
Quat.__index = Quat
|
Quat.__index = Quat
|
||||||
Quat.__name = "Quat"
|
Quat.__name = "Quat"
|
||||||
|
@ -22,7 +27,7 @@ end
|
||||||
|
|
||||||
Quat.IDENTITY = Quat:new(0, 0, 0, 1)
|
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)
|
return Quat:new(self.x, self.y, self.z, self.w)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
--require("math.quat")
|
---@class Transform
|
||||||
--require("math.vec3")
|
---@field translation Vec3
|
||||||
|
---@field rotation Quat
|
||||||
|
---@field Scale Vec3
|
||||||
Transform = { translation = Vec3.ZERO, rotation = Quat.IDENTITY, scale = Vec3.ONE }
|
Transform = { translation = Vec3.ZERO, rotation = Quat.IDENTITY, scale = Vec3.ONE }
|
||||||
Transform.__index = Transform
|
Transform.__index = Transform
|
||||||
Transform.__name = "Transform"
|
Transform.__name = "Transform"
|
||||||
|
@ -16,14 +17,14 @@ function Transform:new(translation, rotation, scale)
|
||||||
return t
|
return t
|
||||||
end
|
end
|
||||||
|
|
||||||
function Transform:copy()
|
function Transform:clone()
|
||||||
return Transform:new(self.translation:copy(), self.rotation:copy(), self.scale:copy())
|
return Transform:new(self.translation:clone(), self.rotation:clone(), self.scale:clone())
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Creates a new Transform with the translation at the vec3
|
--- Creates a new Transform with the translation at the vec3
|
||||||
--- @param pos Vec3
|
--- @param pos Vec3
|
||||||
function Transform:from_vec3(pos)
|
function Transform:from_vec3(pos)
|
||||||
local t = Transform:copy() -- copy of default transform
|
local t = Transform:clone() -- copy of default transform
|
||||||
t.translation = pos
|
t.translation = pos
|
||||||
return t
|
return t
|
||||||
end
|
end
|
||||||
|
@ -81,7 +82,7 @@ end
|
||||||
--- @param alpha number
|
--- @param alpha number
|
||||||
--- @return Transform
|
--- @return Transform
|
||||||
function Transform:lerp(rhs, alpha)
|
function Transform:lerp(rhs, alpha)
|
||||||
local res = self:copy()
|
local res = self:clone()
|
||||||
res.translation = self.translation:lerp(rhs.translation, alpha)
|
res.translation = self.translation:lerp(rhs.translation, alpha)
|
||||||
res.rotation = self.rotation:lerp(rhs.rotation, alpha)
|
res.rotation = self.rotation:lerp(rhs.rotation, alpha)
|
||||||
res.scale = self.scale:lerp(rhs.scale, 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 = { x = 0.0, y = 0.0, z = 0.0 }
|
||||||
Vec3.__index = Vec3
|
Vec3.__index = Vec3
|
||||||
Vec3.__name = "Vec3"
|
Vec3.__name = "Vec3"
|
||||||
|
@ -18,7 +22,9 @@ function Vec3:new(x, y, z)
|
||||||
return v
|
return v
|
||||||
end
|
end
|
||||||
|
|
||||||
function Vec3:copy()
|
---Creates a copy of self
|
||||||
|
---@return Vec3
|
||||||
|
function Vec3:clone()
|
||||||
return Vec3:new(self.x, self.y, self.z)
|
return Vec3:new(self.x, self.y, self.z)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -49,9 +55,10 @@ Vec3.ZERO = Vec3:new(0, 0, 0)
|
||||||
Vec3.ONE = Vec3:new(1, 1, 1)
|
Vec3.ONE = Vec3:new(1, 1, 1)
|
||||||
|
|
||||||
--- Computes the absolute value of `self`.
|
--- Computes the absolute value of `self`.
|
||||||
---@return Vec3
|
|
||||||
function Vec3:abs()
|
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
|
end
|
||||||
|
|
||||||
--- Computes the length of `self`.
|
--- Computes the length of `self`.
|
||||||
|
@ -60,6 +67,16 @@ function Vec3:length()
|
||||||
return math.sqrt(self:dot(self))
|
return math.sqrt(self:dot(self))
|
||||||
end
|
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`.
|
--- Computes the dot product of `self` and `rhs`.
|
||||||
---@param rhs Vec3
|
---@param rhs Vec3
|
||||||
---@return number
|
---@return number
|
||||||
|
@ -80,11 +97,12 @@ function Vec3:min(rhs)
|
||||||
return Vec3:new(x, y, z)
|
return Vec3:new(x, y, z)
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Returns `self` normalized to a length 1.
|
--- Modifies `self` to be normalized to a length 1.
|
||||||
---@return unknown
|
|
||||||
function Vec3:normalize()
|
function Vec3:normalize()
|
||||||
local len_recip = 1.0 / self:length()
|
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
|
end
|
||||||
|
|
||||||
--- Calculates the linear iterpolation between `self` and `rhs` based on the `alpha`.
|
--- 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]
|
-- ensure alpha is [0, 1]
|
||||||
local alpha = math.max(0, math.min(1, alpha))
|
local alpha = math.max(0, math.min(1, alpha))
|
||||||
|
|
||||||
local res = self:copy()
|
local res = self:clone()
|
||||||
res = res + ((rhs - res) * alpha)
|
res = res + ((rhs - res) * alpha)
|
||||||
return res
|
return res
|
||||||
end
|
end
|
||||||
|
|
||||||
function Vec3:__add(rhs)
|
function Vec3:__add(rhs)
|
||||||
|
if type(rhs) == "Vec3" then
|
||||||
return Vec3:new(self.x + rhs.x, self.y + rhs.y, self.z + rhs.z)
|
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
|
end
|
||||||
|
|
||||||
function Vec3:__sub(rhs)
|
function Vec3:__sub(rhs)
|
||||||
|
if type(rhs) == "Vec3" then
|
||||||
return Vec3:new(self.x - rhs.x, self.y - rhs.y, self.z - rhs.z)
|
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
|
end
|
||||||
|
|
||||||
function Vec3:__mul(rhs)
|
function Vec3:__mul(rhs)
|
||||||
if type(rhs) == "number" then
|
if type(rhs) == "Vec3" then
|
||||||
return Vec3:new(self.x * rhs, self.y * rhs, self.z * rhs)
|
|
||||||
else
|
|
||||||
return Vec3:new(self.x * rhs.x, self.y * rhs.y, self.z * rhs.z)
|
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
|
||||||
end
|
end
|
||||||
|
|
||||||
function Vec3:__div(rhs)
|
function Vec3:__div(rhs)
|
||||||
if type(rhs) == "number" then
|
if type(rhs) == "Vec3" then
|
||||||
return Vec3:new(self.x / rhs, self.y / rhs, self.z / rhs)
|
|
||||||
else
|
|
||||||
return Vec3:new(self.x / rhs.x, self.y / rhs.y, self.z / rhs.z)
|
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
|
||||||
end
|
end
|
||||||
|
|
||||||
function Vec3:__idiv(rhs)
|
function Vec3:__idiv(rhs)
|
||||||
if type(rhs) == "number" then
|
if type(rhs) == "Vec3" then
|
||||||
return Vec3:new(self.x // rhs, self.y // rhs, self.z // rhs)
|
|
||||||
else
|
|
||||||
return Vec3:new(self.x // rhs.x, self.y // rhs.y, self.z // rhs.z)
|
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
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -8,15 +8,15 @@ use crate::ScriptWorldPtr;
|
||||||
pub enum ScriptError {
|
pub enum ScriptError {
|
||||||
#[error("{0}")]
|
#[error("{0}")]
|
||||||
#[cfg(feature = "lua")]
|
#[cfg(feature = "lua")]
|
||||||
MluaError(mlua::Error),
|
MluaError(elua::Error),
|
||||||
|
|
||||||
#[error("{0}")]
|
#[error("{0}")]
|
||||||
Other(anyhow::Error),
|
Other(anyhow::Error),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "lua")]
|
#[cfg(feature = "lua")]
|
||||||
impl From<mlua::Error> for ScriptError {
|
impl From<elua::Error> for ScriptError {
|
||||||
fn from(value: mlua::Error) -> Self {
|
fn from(value: elua::Error) -> Self {
|
||||||
ScriptError::MluaError(value)
|
ScriptError::MluaError(value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -134,9 +134,9 @@ impl Iterator for DynamicViewIter {
|
||||||
|
|
||||||
#[cfg(feature = "lua")]
|
#[cfg(feature = "lua")]
|
||||||
pub struct ReflectedItem<'a> {
|
pub struct ReflectedItem<'a> {
|
||||||
pub proxy: &'a ReflectLuaProxy,
|
//pub proxy: &'a ReflectLuaProxy,
|
||||||
pub comp_ptr: NonNull<u8>,
|
pub comp_ptr: NonNull<u8>,
|
||||||
pub comp_ud: mlua::AnyUserData<'a>,
|
pub comp_val: elua::Value<'a>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "lua")]
|
#[cfg(feature = "lua")]
|
||||||
|
@ -153,7 +153,11 @@ pub struct ReflectedIterator {
|
||||||
|
|
||||||
impl ReflectedIterator {
|
impl ReflectedIterator {
|
||||||
#[cfg(feature = "lua")]
|
#[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();
|
let n = self.dyn_view.next();
|
||||||
|
|
||||||
|
@ -172,17 +176,20 @@ impl ReflectedIterator {
|
||||||
|
|
||||||
let reg_type = reflected_components.get_type(id)
|
let reg_type = reflected_components.get_type(id)
|
||||||
.expect("Requested type was not found in TypeRegistry");
|
.expect("Requested type was not found in TypeRegistry");
|
||||||
let proxy = reg_type.get_data::<ReflectLuaProxy>()
|
let value = if let Some(proxy) = reg_type.get_data::<ReflectLuaProxy>() {
|
||||||
.expect("Type does not have ReflectLuaProxy as a TypeData");
|
(proxy.fn_as_uservalue)(lua, d.ptr).unwrap()
|
||||||
|
.as_lua(lua).unwrap()
|
||||||
let userdata = (proxy.fn_as_uservalue)(lua, d.ptr).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 {
|
dynamic_row.push(ReflectedItem {
|
||||||
proxy,
|
|
||||||
comp_ptr: d.ptr,
|
comp_ptr: d.ptr,
|
||||||
comp_ud: userdata
|
comp_val: value
|
||||||
});
|
});
|
||||||
//dynamic_row.push(( (proxy, d.ptr), userdata));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let row = ReflectedRow {
|
let row = ReflectedRow {
|
||||||
|
|
|
@ -2,6 +2,7 @@ pub mod dynamic_iter;
|
||||||
pub use dynamic_iter::*;
|
pub use dynamic_iter::*;
|
||||||
|
|
||||||
pub mod world;
|
pub mod world;
|
||||||
|
use elua::FromLua;
|
||||||
pub use world::*;
|
pub use world::*;
|
||||||
|
|
||||||
pub mod script;
|
pub mod script;
|
||||||
|
@ -19,19 +20,14 @@ pub use proxy::*;
|
||||||
pub mod system;
|
pub mod system;
|
||||||
pub use system::*;
|
pub use system::*;
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod test;
|
|
||||||
|
|
||||||
use std::{any::TypeId, sync::Mutex};
|
use std::{any::TypeId, sync::Mutex};
|
||||||
|
|
||||||
use lyra_ecs::{
|
use lyra_ecs::{
|
||||||
DynamicBundle, World,
|
Component, ComponentInfo, DynamicBundle, World
|
||||||
};
|
};
|
||||||
use lyra_reflect::{FromType, Reflect, TypeRegistry};
|
use lyra_reflect::{FromType, Reflect, TypeRegistry};
|
||||||
|
|
||||||
use mlua::{AnyUserDataExt, Lua};
|
pub type LuaContext = Mutex<elua::State>;
|
||||||
|
|
||||||
pub type LuaContext = Mutex<mlua::Lua>;
|
|
||||||
|
|
||||||
pub const FN_NAME_INTERNAL_REFLECT_TYPE: &str = "__lyra_internal_reflect_type";
|
pub const FN_NAME_INTERNAL_REFLECT_TYPE: &str = "__lyra_internal_reflect_type";
|
||||||
pub const FN_NAME_INTERNAL_REFLECT: &str = "__lyra_internal_reflect";
|
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.
|
/// A trait used for registering a Lua type with the world.
|
||||||
pub trait RegisterLuaType {
|
pub trait RegisterLuaType {
|
||||||
/// Register a type to lua that **is not wrapped**.
|
/// Register a type to Lua that **is not wrapped**.
|
||||||
fn register_lua_type<'a, T>(&mut self)
|
fn register_lua_type<'a, T>(&mut self)
|
||||||
where
|
where
|
||||||
T: Reflect + LuaProxy + Clone + mlua::FromLua<'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)
|
fn register_lua_wrapper<'a, W>(&mut self)
|
||||||
where
|
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 {
|
impl RegisterLuaType for World {
|
||||||
fn register_lua_type<'a, T>(&mut self)
|
fn register_lua_type<'a, T>(&mut self)
|
||||||
where
|
where
|
||||||
T: Reflect + LuaProxy + Clone + mlua::FromLua<'a> + mlua::UserData
|
T: Reflect + LuaProxy + Clone + elua::FromLua<'a> + elua::Userdata
|
||||||
{
|
{
|
||||||
let mut registry = self.get_resource_mut::<TypeRegistry>();
|
let mut registry = self.get_resource_mut::<TypeRegistry>();
|
||||||
|
|
||||||
|
@ -67,44 +70,64 @@ impl RegisterLuaType for World {
|
||||||
|
|
||||||
fn register_lua_wrapper<'a, W>(&mut self)
|
fn register_lua_wrapper<'a, W>(&mut self)
|
||||||
where
|
where
|
||||||
W: Reflect + LuaProxy + LuaWrapper + Clone + mlua::FromLua<'a> + mlua::UserData
|
W: Reflect + LuaProxy + LuaWrapper + Clone + elua::FromLua<'a> + elua::Userdata
|
||||||
{
|
{
|
||||||
let mut registry = self.get_resource_mut::<TypeRegistry>();
|
let mut registry = self.get_resource_mut::<TypeRegistry>();
|
||||||
|
|
||||||
let reg_type = registry.get_type_or_default(W::wrapped_type_id());
|
let reg_type = registry.get_type_or_default(W::wrapped_type_id());
|
||||||
reg_type.add_data(<ReflectLuaProxy as FromType<W>>::from_type());
|
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 {
|
impl<'lua> elua::FromLua<'lua> for ScriptBorrow {
|
||||||
fn from_lua(value: mlua::Value<'lua>, _lua: &'lua Lua) -> mlua::Result<Self> {
|
fn from_lua(_: &'lua elua::State, value: elua::Value<'lua>) -> elua::Result<Self> {
|
||||||
match value {
|
match value {
|
||||||
mlua::Value::UserData(ud) => Ok(ud.borrow::<Self>()?.clone()),
|
elua::Value::Userdata(ud) => Ok(ud.as_ref::<Self>()?.clone()),
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl mlua::UserData for ScriptBorrow {}
|
impl<'lua> elua::FromLuaVec<'lua> for ScriptBorrow {
|
||||||
|
fn from_lua_value_vec(state: &'lua elua::State, mut values: elua::ValueVec<'lua>) -> elua::Result<Self> {
|
||||||
pub fn reflect_user_data(ud: &mlua::AnyUserData) -> ScriptBorrow {
|
if let Some(v) = values.pop_front() {
|
||||||
ud.call_method::<_, ScriptBorrow>(FN_NAME_INTERNAL_REFLECT, ())
|
ScriptBorrow::from_lua(state, v)
|
||||||
.expect("Type does not implement '__internal_reflect' properly")
|
} else {
|
||||||
}
|
Err(elua::Error::Nil)
|
||||||
|
}
|
||||||
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 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> {
|
fn expose_api(&mut self, data: &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>()?)?;
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
|
use elua::{TableProxy, Userdata};
|
||||||
use lyra_ecs::World;
|
use lyra_ecs::World;
|
||||||
use lyra_game::math;
|
use lyra_game::math::{self, Quat, Transform, Vec3};
|
||||||
use crate::ScriptData;
|
use crate::ScriptData;
|
||||||
use crate::lua::RegisterLuaType;
|
use crate::lua::RegisterLuaType;
|
||||||
use crate::lua::wrappers::{LuaVec3, LuaTransform};
|
|
||||||
|
|
||||||
use crate::{ScriptApiProvider, lua::LuaContext};
|
use crate::{ScriptApiProvider, lua::LuaContext};
|
||||||
|
|
||||||
|
@ -13,26 +13,31 @@ impl ScriptApiProvider for LyraMathApiProvider {
|
||||||
type ScriptContext = LuaContext;
|
type ScriptContext = LuaContext;
|
||||||
|
|
||||||
fn prepare_world(&mut self, world: &mut World) {
|
fn prepare_world(&mut self, world: &mut World) {
|
||||||
world.register_lua_wrapper::<LuaVec3>();
|
// TODO
|
||||||
world.register_lua_wrapper::<LuaTransform>();
|
/* 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 ctx = ctx.lock().unwrap();
|
||||||
|
|
||||||
/* let bytes = include_bytes!("../../../scripts/lua/math/vec3.lua");
|
let bytes = include_bytes!("../../../scripts/lua/math/vec3.lua");
|
||||||
ctx.load(bytes.to_vec()).exec()?;
|
ctx.load("lyra/math/vec2.lua", bytes.as_slice())?.execute(())?;
|
||||||
|
|
||||||
let bytes = include_bytes!("../../../scripts/lua/math/quat.lua");
|
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");
|
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();
|
// TODO
|
||||||
globals.set("Vec3", ctx.create_proxy::<LuaVec3>()?)?;
|
//let globals = ctx.globals()?;
|
||||||
globals.set("Transform", ctx.create_proxy::<LuaTransform>()?)?;
|
//globals.set("Vec3", elua::Proxy::<LuaVec3>::from(LuaVec3(Vec3::ZERO)))?;
|
||||||
//globals.set("Vec3", LuaVec3(math::Vec3::ZERO).into_lua(&ctx)?)?;
|
//globals.set("Vec3", ctx.create_proxy::<LuaVec3>()?)?;
|
||||||
|
//globals.set("Transform", ctx.create_proxy::<LuaTransform>()?)?;
|
||||||
|
|
||||||
Ok(())
|
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)]
|
/* #[derive(Clone, Copy, PartialEq, Debug, lyra_reflect::Reflect)]
|
||||||
pub struct LuaVec3(#[reflect(skip)] math::Vec3);
|
pub struct LuaVec3(#[reflect(skip)] math::Vec3);
|
||||||
|
|
||||||
|
|
|
@ -17,47 +17,46 @@ use crate::{ScriptApiProvider, ScriptData};
|
||||||
pub struct UtilityApiProvider;
|
pub struct UtilityApiProvider;
|
||||||
|
|
||||||
impl ScriptApiProvider for UtilityApiProvider {
|
impl ScriptApiProvider for UtilityApiProvider {
|
||||||
type ScriptContext = Mutex<mlua::Lua>;
|
type ScriptContext = Mutex<elua::State>;
|
||||||
|
|
||||||
fn expose_api(&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: &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 formatted = String::new();
|
||||||
let mut arg_num = 0;
|
let mut arg_num = 0;
|
||||||
|
|
||||||
while let Some(start) = text.find("{}") {
|
while let Some(start) = text.find("{}") {
|
||||||
let val_str = match formats.get(arg_num) {
|
let val_str = match formats.get(arg_num) {
|
||||||
Some(v) => match v {
|
Some(v) => match v {
|
||||||
mlua::Value::Nil => "nil".to_string(),
|
elua::Value::Nil => "nil".to_string(),
|
||||||
mlua::Value::Boolean(b) => b.to_string(),
|
elua::Value::Boolean(b) => b.to_string(),
|
||||||
mlua::Value::LightUserData(_) => {
|
elua::Value::Number(n) => n.to_string(),
|
||||||
return Err(mlua::Error::RuntimeError(format!("unable to get string representation of LightUserData")));
|
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(),
|
elua::Value::Function(_) => {
|
||||||
mlua::Value::Number(n) => n.to_string(),
|
return Err(elua::Error::runtime("unable to get string representation of Function"));
|
||||||
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(_) => {
|
elua::Value::Thread(_) => {
|
||||||
return Err(mlua::Error::RuntimeError(format!("unable to get string representation of Function")));
|
return Err(elua::Error::runtime("unable to get string representation of Thread"));
|
||||||
},
|
},
|
||||||
mlua::Value::Thread(_) => {
|
elua::Value::Userdata(ud) => {
|
||||||
return Err(mlua::Error::RuntimeError(format!("unable to get string representation of Thread")));
|
if let Ok(tos) = ud.get::<_, elua::Function>(elua::MetaMethod::ToString) {
|
||||||
},
|
tos.exec::<_, String>(())?
|
||||||
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(),))?
|
|
||||||
} else {
|
} 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 => {
|
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.
|
// continue searching for {} to get the number of format spots for the error message.
|
||||||
while let Some(start) = text.find("{}") {
|
while let Some(start) = text.find("{}") {
|
||||||
|
@ -65,13 +64,15 @@ impl ScriptApiProvider for UtilityApiProvider {
|
||||||
arg_num += 1;
|
arg_num += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Err(mlua::Error::BadArgument {
|
return Err(elua::Error::BadArgument {
|
||||||
to: Some("printf".to_string()),
|
func: Some("printf".to_string()),
|
||||||
pos: 2,
|
arg_index: 2,
|
||||||
name: Some("...".to_string()),
|
arg_name: Some("fmt...".to_string()),
|
||||||
cause: Arc::new(mlua::Error::RuntimeError(format!("not enough args \
|
error: Arc::new(elua::Error::Runtime(format!(
|
||||||
|
"not enough args \
|
||||||
given for the amount of format areas in the string. Expected {}, \
|
given for the amount of format areas in the string. Expected {}, \
|
||||||
got {}.", arg_num, got_args)))
|
got {}.", arg_num, got_args
|
||||||
|
)))
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -84,29 +85,31 @@ impl ScriptApiProvider for UtilityApiProvider {
|
||||||
}
|
}
|
||||||
|
|
||||||
if arg_num < formats.len() {
|
if arg_num < formats.len() {
|
||||||
return Err(mlua::Error::BadArgument {
|
return Err(elua::Error::BadArgument {
|
||||||
to: Some("printf".to_string()),
|
func: Some("printf".to_string()),
|
||||||
pos: 2,
|
arg_index: 2,
|
||||||
name: Some("...".to_string()),
|
arg_name: Some("fmt...".to_string()),
|
||||||
cause: Arc::new(mlua::Error::RuntimeError(format!("got more args \
|
error: Arc::new(elua::Error::Runtime(format!(
|
||||||
than format areas in the string. Expected {}, got {}.", formats.len(), arg_num)))
|
"got more args \
|
||||||
|
than format areas in the string. Expected {}, got {}.", formats.len(), arg_num
|
||||||
|
)))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
formatted = format!("{}{}", formatted, text);
|
formatted = format!("{}{}", formatted, text);
|
||||||
|
|
||||||
lua.globals()
|
lua.globals()?
|
||||||
.get::<_, mlua::Function>("print")?
|
.get::<_, elua::Function>("print")?
|
||||||
.call::<_, ()>(formatted)?;
|
.exec::<_, ()>(formatted)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
};
|
||||||
|
|
||||||
let script_name_reg = ctx.create_registry_value(data.name.clone())?;
|
let script_name_reg = ctx.registry_insert(data.name.clone())?;
|
||||||
|
|
||||||
let printf_func = ctx.create_function(printf)?;
|
let printf_func = ctx.create_function(printf)?;
|
||||||
let print_func = ctx.create_function(move |lua, text: String| {
|
let print_func = ctx.create_function(move |lua, text: String| {
|
||||||
let name = lua.registry_value::<String>(&script_name_reg)?;
|
let name = lua.registry_get::<String>(script_name_reg)?;
|
||||||
let _span = debug_span!("lua", script = &name).entered();
|
let _span = debug_span!("lua", script = &name).entered();
|
||||||
|
|
||||||
debug!(target: "lyra_scripting::lua", "{}", text);
|
debug!(target: "lyra_scripting::lua", "{}", text);
|
||||||
|
@ -114,7 +117,7 @@ impl ScriptApiProvider for UtilityApiProvider {
|
||||||
Ok(())
|
Ok(())
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
let globals = ctx.globals();
|
let globals = ctx.globals()?;
|
||||||
globals.set("printf", printf_func)?;
|
globals.set("printf", printf_func)?;
|
||||||
globals.set("print", print_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 lyra_reflect::{Reflect, FromType};
|
||||||
|
|
||||||
use crate::ScriptDynamicBundle;
|
use crate::{ScriptBorrow, ScriptDynamicBundle};
|
||||||
|
|
||||||
|
use super::FN_NAME_INTERNAL_REFLECT;
|
||||||
|
|
||||||
pub trait LuaWrapper {
|
pub trait LuaWrapper {
|
||||||
/// The type id of the wrapped type.
|
/// The type id of the wrapped type.
|
||||||
fn wrapped_type_id() -> TypeId;
|
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 {
|
pub trait LuaProxy {
|
||||||
fn as_lua_value<'lua>(
|
fn as_lua_value<'lua>(
|
||||||
lua: &'lua mlua::Lua,
|
lua: &'lua elua::State,
|
||||||
this: &dyn Reflect,
|
this: &dyn Reflect,
|
||||||
) -> mlua::Result<mlua::AnyUserData<'lua>>;
|
) -> elua::Result<elua::AnyUserdata<'lua>>;
|
||||||
|
|
||||||
fn apply(
|
fn apply(
|
||||||
lua: &mlua::Lua,
|
lua: &elua::State,
|
||||||
this: &mut dyn Reflect,
|
this: &mut dyn Reflect,
|
||||||
apply: &mlua::AnyUserData,
|
apply: &elua::AnyUserdata,
|
||||||
) -> mlua::Result<()>;
|
) -> elua::Result<()>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, T> LuaProxy for T
|
impl<'a, T> LuaProxy for T
|
||||||
where
|
where
|
||||||
T: Reflect + Clone + mlua::FromLua<'a> + mlua::UserData
|
T: Reflect + Clone + elua::FromLua<'a> + elua::Userdata
|
||||||
{
|
{
|
||||||
fn as_lua_value<'lua>(
|
fn as_lua_value<'lua>(
|
||||||
lua: &'lua mlua::Lua,
|
lua: &'lua elua::State,
|
||||||
this: &dyn Reflect,
|
this: &dyn Reflect,
|
||||||
) -> mlua::Result<mlua::AnyUserData<'lua>> {
|
) -> elua::Result<elua::AnyUserdata<'lua>> {
|
||||||
let this = this.as_any().downcast_ref::<T>().unwrap();
|
let this = this.as_any().downcast_ref::<T>().unwrap();
|
||||||
lua.create_userdata(this.clone())
|
lua.create_userdata(this.clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn apply(
|
fn apply(
|
||||||
_lua: &mlua::Lua,
|
_: &elua::State,
|
||||||
this: &mut dyn Reflect,
|
this: &mut dyn Reflect,
|
||||||
apply: &mlua::AnyUserData,
|
apply: &elua::AnyUserdata,
|
||||||
) -> mlua::Result<()> {
|
) -> elua::Result<()> {
|
||||||
let this = this.as_any_mut().downcast_mut::<T>().unwrap();
|
let this = this.as_any_mut().downcast_mut::<T>().unwrap();
|
||||||
let apply = apply.borrow::<T>()?;
|
let apply = apply.as_ref::<T>()?;
|
||||||
|
|
||||||
*this = apply.clone();
|
*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)]
|
#[derive(Clone)]
|
||||||
pub struct ReflectLuaProxy {
|
pub struct ReflectLuaProxy {
|
||||||
pub fn_as_uservalue:
|
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(
|
pub fn_apply: for<'a> fn(
|
||||||
lua: &'a mlua::Lua,
|
lua: &'a elua::State,
|
||||||
this_ptr: NonNull<u8>,
|
this_ptr: NonNull<u8>,
|
||||||
apply: &'a mlua::AnyUserData<'a>,
|
apply: &'a elua::AnyUserdata<'a>,
|
||||||
) -> mlua::Result<()>,
|
) -> elua::Result<()>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, T> FromType<T> for ReflectLuaProxy
|
impl<'a, T> FromType<T> for ReflectLuaProxy
|
||||||
where
|
where
|
||||||
T: Reflect + LuaProxy + Clone + mlua::FromLua<'a> + mlua::UserData
|
T: Reflect + LuaProxy + Clone + elua::FromLua<'a> + elua::Userdata
|
||||||
{
|
{
|
||||||
fn from_type() -> Self {
|
fn from_type() -> Self {
|
||||||
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() };
|
let this = unsafe { this.cast::<T>().as_ref() };
|
||||||
<T as LuaProxy>::as_lua_value(lua, this)
|
<T as LuaProxy>::as_lua_value(lua, this)
|
||||||
},
|
},
|
||||||
|
@ -77,16 +124,45 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'lua> mlua::FromLua<'lua> for ScriptDynamicBundle {
|
impl<'lua> elua::FromLua<'lua> for ScriptDynamicBundle {
|
||||||
fn from_lua(value: mlua::Value<'lua>, _lua: &'lua mlua::Lua) -> mlua::Result<Self> {
|
fn from_lua(_: &'lua elua::State, val: elua::Value<'lua>) -> elua::Result<Self> {
|
||||||
match value {
|
match val {
|
||||||
mlua::Value::UserData(ud) => Ok(ud.borrow::<Self>()?.clone()),
|
elua::Value::Userdata(ud) => Ok(ud.as_ref::<Self>()?.clone()),
|
||||||
mlua::Value::Nil => Err(mlua::Error::FromLuaConversionError {
|
elua::Value::Nil => Err(elua::Error::Nil),
|
||||||
from: "Nil",
|
_ => unreachable!(),
|
||||||
to: "DynamicBundle",
|
|
||||||
message: Some("Value was nil".to_string()),
|
|
||||||
}),
|
|
||||||
_ => panic!(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 std::sync::Mutex;
|
||||||
|
|
||||||
use mlua::IntoLua;
|
use elua::{AsLua, StdLibraries, StdLibrary};
|
||||||
use tracing::{debug, trace};
|
use tracing::{debug, trace};
|
||||||
|
|
||||||
use crate::{ScriptHost, ScriptError, ScriptWorldPtr, ScriptEntity};
|
use crate::{ScriptHost, ScriptError, ScriptWorldPtr, ScriptEntity};
|
||||||
|
@ -8,40 +8,37 @@ use crate::{ScriptHost, ScriptError, ScriptWorldPtr, ScriptEntity};
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct LuaHost;
|
pub struct LuaHost;
|
||||||
|
|
||||||
fn try_call_lua_function(lua: &mlua::Lua, fn_name: &str) -> Result<(), ScriptError> {
|
fn try_call_lua_function(lua: &elua::State, fn_name: &str) -> Result<(), ScriptError> {
|
||||||
let globals = lua.globals();
|
let globals = lua.globals()?;
|
||||||
|
|
||||||
match globals.get::<_, mlua::Function>(fn_name) {
|
if globals.has_key(fn_name)? {
|
||||||
Ok(init_fn) => {
|
let lua_fn = globals.get::<_, elua::Function>(fn_name)?;
|
||||||
init_fn.call(())
|
lua_fn.exec(())
|
||||||
.map_err(ScriptError::MluaError)?;
|
.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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ScriptHost for LuaHost {
|
impl ScriptHost for LuaHost {
|
||||||
type ScriptContext = Mutex<mlua::Lua>;
|
type ScriptContext = Mutex<elua::State>;
|
||||||
|
|
||||||
fn load_script(&mut self, script: &[u8], script_data: &crate::ScriptData, providers: &mut crate::ScriptApiProviders<Self>) -> Result<Self::ScriptContext, crate::ScriptError> {
|
fn load_script(&mut self, script: &[u8], script_data: &crate::ScriptData, providers: &mut crate::ScriptApiProviders<Self>) -> Result<Self::ScriptContext, crate::ScriptError> {
|
||||||
let mut ctx = Mutex::new(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() {
|
for provider in providers.apis.iter_mut() {
|
||||||
provider.expose_api(script_data, &mut ctx)?;
|
provider.expose_api(script_data, &mut ctx)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let lua = ctx.lock().unwrap();
|
let lua = ctx.lock().unwrap();
|
||||||
lua.load(script)
|
lua.load(&script_data.name, script)?
|
||||||
.set_name(&script_data.name)
|
.execute(())
|
||||||
.exec()
|
|
||||||
.map_err(|e| ScriptError::MluaError(e))?;
|
.map_err(|e| ScriptError::MluaError(e))?;
|
||||||
drop(lua);
|
drop(lua);
|
||||||
|
|
||||||
|
@ -71,9 +68,9 @@ impl ScriptHost for LuaHost {
|
||||||
|
|
||||||
let ctx = ctx.lock().expect("Failure to get Lua ScriptContext");
|
let ctx = ctx.lock().expect("Failure to get Lua ScriptContext");
|
||||||
|
|
||||||
let globals = ctx.globals();
|
let globals = ctx.globals()?;
|
||||||
globals.set("world", world.into_lua(&ctx)?)?;
|
globals.set("world", world.as_lua(&ctx)?)?;
|
||||||
globals.set("entity", ScriptEntity(script_data.entity).into_lua(&ctx)?)?;
|
globals.set("entity", ScriptEntity(script_data.entity).as_lua(&ctx)?)?;
|
||||||
|
|
||||||
try_call_lua_function(&ctx, function_name)?;
|
try_call_lua_function(&ctx, function_name)?;
|
||||||
|
|
||||||
|
|
|
@ -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_ecs::query::dynamic::QueryDynamicType;
|
||||||
use lyra_reflect::{TypeRegistry, ReflectWorldExt, RegisteredType};
|
use lyra_reflect::{TypeRegistry, ReflectWorldExt, RegisteredType};
|
||||||
use mlua::{AnyUserDataExt, IntoLua, IntoLuaMulti};
|
|
||||||
|
|
||||||
use crate::{ScriptWorldPtr, ScriptEntity, ScriptDynamicBundle, ScriptBorrow};
|
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 {
|
impl<'lua> elua::FromLua<'lua> for ScriptEntity {
|
||||||
fn from_lua(value: mlua::Value<'lua>, _lua: &'lua mlua::Lua) -> mlua::Result<Self> {
|
fn from_lua(_: &'lua elua::State, value: elua::Value<'lua>) -> elua::Result<Self> {
|
||||||
match value {
|
match value {
|
||||||
mlua::Value::UserData(ud) => Ok(ud.borrow::<Self>()?.clone()),
|
elua::Value::Userdata(ud) => Ok(ud.as_ref::<Self>()?.clone()),
|
||||||
mlua::Value::Nil => Err(mlua::Error::FromLuaConversionError { from: "Nil", to: "ScriptEntity", message: Some("Value was nil".to_string()) }),
|
elua::Value::Nil => Err(elua::Error::type_mismatch("ScriptEntity", "Nil")),
|
||||||
_ => panic!(),
|
_ => panic!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl mlua::UserData for ScriptEntity {
|
impl elua::Userdata for ScriptEntity {
|
||||||
fn add_methods<'lua, M: mlua::prelude::LuaUserDataMethods<'lua, Self>>(methods: &mut M) {
|
fn name() -> String {
|
||||||
methods.add_meta_method(mlua::MetaMethod::ToString, |_, this, ()| {
|
"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(format!("{:?}", this.0))
|
||||||
})
|
});
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,64 +37,74 @@ pub enum WorldError {
|
||||||
LuaInvalidUsage(String),
|
LuaInvalidUsage(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl mlua::UserData for ScriptWorldPtr {
|
impl<'a> elua::FromLua<'a> for ScriptWorldPtr {
|
||||||
fn add_methods<'lua, M: mlua::prelude::LuaUserDataMethods<'lua, Self>>(methods: &mut M) {
|
fn from_lua(lua: &'a elua::State, val: elua::Value<'a>) -> elua::Result<Self> {
|
||||||
methods.add_method_mut("spawn", |_, this, (bundle,): (ScriptDynamicBundle,)| {
|
match val {
|
||||||
let world = unsafe { this.inner.as_mut() };
|
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)))
|
Ok(ScriptEntity(world.spawn(bundle.0)))
|
||||||
});
|
})
|
||||||
|
.method_mut("view", |lua, this, (system, queries): (elua::Function, elua::ValueVec)| {
|
||||||
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>)| {
|
|
||||||
if queries.is_empty() {
|
if queries.is_empty() {
|
||||||
return Err(mlua::Error::BadArgument { to: Some("world:view".to_string()), pos: 2, name: Some("...".to_string()), cause:
|
return Err(
|
||||||
Arc::new(mlua::Error::external(WorldError::LuaInvalidUsage("no component types provided".to_string())))
|
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 world = unsafe { this.inner.as_ref() };
|
||||||
let mut view = world.dynamic_view();
|
let mut view = world.dynamic_view();
|
||||||
|
|
||||||
for comp in queries.into_iter() {
|
for (idx, comp) in queries.into_iter().enumerate() {
|
||||||
let reflect = comp.call_function::<_, ScriptBorrow>(FN_NAME_INTERNAL_REFLECT_TYPE, ())
|
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");
|
.expect("Type does not implement 'reflect_type' properly");
|
||||||
let refl_comp = reflect.reflect_branch.as_component_unchecked();
|
let refl_comp = reflect.reflect_branch.as_component_unchecked();
|
||||||
|
|
||||||
let dyn_type = QueryDynamicType::from_info(refl_comp.info);
|
let dyn_type = QueryDynamicType::from_info(refl_comp.info);
|
||||||
view.push(dyn_type);
|
view.push(dyn_type);
|
||||||
|
},
|
||||||
|
_ => todo!()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let iter = view.into_iter();
|
let iter = view.into_iter();
|
||||||
|
@ -103,19 +118,15 @@ impl mlua::UserData for ScriptWorldPtr {
|
||||||
let mut has_ticked = false;
|
let mut has_ticked = false;
|
||||||
|
|
||||||
while let Some(row) = reflected_iter.next_lua(lua) {
|
while let Some(row) = reflected_iter.next_lua(lua) {
|
||||||
|
|
||||||
let r = row.row.into_iter()
|
let r = row.row.into_iter()
|
||||||
.map(|r| (r.proxy, r.comp_ud, r.comp_ptr))
|
.map(|r| (r.comp_val, r.comp_ptr))
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
let (reflects, values, ptrs):
|
let (values, ptrs) = itertools::multiunzip::<(Vec<elua::Value>, Vec<NonNull<u8>>), _>(r);
|
||||||
(Vec<&ReflectLuaProxy>, Vec<mlua::AnyUserData>, Vec<NonNull<u8>>)
|
let mult_val = elua::ValueVec::from(values);
|
||||||
= itertools::multiunzip(r);
|
let res: elua::ValueVec = system.exec(mult_val)?;
|
||||||
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)?;
|
|
||||||
|
|
||||||
// if values were returned, find the type in the type registry, and apply the new values
|
// if values were returned, find the type in the type registry, and apply the new values
|
||||||
if res.len() <= reflects.len() {
|
if res.len() <= ptrs.len() {
|
||||||
// we only want to tick one time per system
|
// we only want to tick one time per system
|
||||||
if !has_ticked {
|
if !has_ticked {
|
||||||
current = world.tick();
|
current = world.tick();
|
||||||
|
@ -125,9 +136,9 @@ impl mlua::UserData for ScriptWorldPtr {
|
||||||
for (i, comp) in res.into_iter().enumerate() {
|
for (i, comp) in res.into_iter().enumerate() {
|
||||||
let ptr = ptrs[i];
|
let ptr = ptrs[i];
|
||||||
|
|
||||||
match comp.as_userdata() {
|
match comp {
|
||||||
Some(ud) => {
|
elua::Value::Userdata(ud) => {
|
||||||
let lua_comp = reflect_user_data(ud);
|
let lua_comp = reflect_user_data(&ud);
|
||||||
let refl_comp = lua_comp.reflect_branch.as_component_unchecked();
|
let refl_comp = lua_comp.reflect_branch.as_component_unchecked();
|
||||||
let lua_typeid = refl_comp.info.type_id.as_rust();
|
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 = this.as_ref().get_resource::<TypeRegistry>();
|
||||||
let reg_type = reg.get_type(lua_typeid).unwrap();
|
let reg_type = reg.get_type(lua_typeid).unwrap();
|
||||||
|
|
||||||
let proxy = reg_type.get_data::<ReflectLuaProxy>().unwrap();
|
let proxy = reg_type.get_data::<ReflectLuaProxy>()
|
||||||
(proxy.fn_apply)(lua, ptr, ud)?;
|
.expect("Type does not have ReflectLuaProxy as a TypeData");
|
||||||
}
|
(proxy.fn_apply)(lua, ptr, &ud)?;
|
||||||
None => {
|
},
|
||||||
panic!("A userdata value was not returned!");
|
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 {
|
} else {
|
||||||
let msg = format!("Too many arguments were returned from the World view!
|
let msg = format!("Too many arguments were returned from the World view!
|
||||||
At most, the expected number of results is {}.", reflects.len());
|
At most, the expected number of results is {}.", ptrs.len());
|
||||||
return Err(mlua::Error::external(WorldError::LuaInvalidUsage(msg)));
|
return Err(elua::Error::Runtime(msg));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
});
|
})
|
||||||
|
.method_mut("resource", |lua, this, (ty,): (elua::AnyUserdata,)| {
|
||||||
methods.add_method_mut("resource", |lua, this, (ty,): (mlua::AnyUserData,)| {
|
|
||||||
let reflect = ty
|
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");
|
.expect("Type does not implement 'reflect_type' properly");
|
||||||
|
|
||||||
let res = reflect.reflect_branch.as_resource_unchecked();
|
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");
|
.expect("Type does not have ReflectLuaProxy as a TypeData");
|
||||||
|
|
||||||
(proxy.fn_as_uservalue)(lua, res_ptr)
|
(proxy.fn_as_uservalue)(lua, res_ptr)
|
||||||
.and_then(|ud| ud.into_lua(lua))
|
.and_then(|ud| ud.as_lua(lua))
|
||||||
} else {
|
} else {
|
||||||
// if the resource is not found in the world, return nil
|
// if the resource is not found in the world, return nil
|
||||||
Ok(mlua::Value::Nil)
|
Ok(elua::Value::Nil)
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
use std::{ops::Deref, any::TypeId};
|
use std::any::TypeId;
|
||||||
|
|
||||||
use lyra_game::DeltaTime;
|
use lyra_game::DeltaTime;
|
||||||
use crate::{lyra_engine, lua::{FN_NAME_INTERNAL_REFLECT_TYPE, LuaWrapper}, ScriptBorrow};
|
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 {
|
impl<'lua> elua::FromLua<'lua> for LuaDeltaTime {
|
||||||
fn from_lua(value: mlua::prelude::LuaValue<'lua>, lua: &'lua mlua::prelude::Lua) -> mlua::prelude::LuaResult<Self> {
|
fn from_lua(lua: &'lua elua::State, value: elua::Value<'lua>) -> elua::Result<Self> {
|
||||||
match value {
|
match value {
|
||||||
mlua::Value::UserData(ud) => Ok(ud.borrow::<Self>()?.clone()),
|
elua::Value::Userdata(ud) => Ok(ud.as_ref::<Self>()?.clone()),
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl mlua::UserData for LuaDeltaTime {
|
impl elua::Userdata for LuaDeltaTime {
|
||||||
fn add_methods<'lua, M: mlua::prelude::LuaUserDataMethods<'lua, Self>>(methods: &mut M) {
|
fn name() -> String {
|
||||||
methods.add_method("get", |_, this, ()| {
|
"DeltaTime".to_string()
|
||||||
Ok(*this.0.deref())
|
}
|
||||||
});
|
|
||||||
|
|
||||||
methods.add_meta_method(mlua::MetaMethod::ToString, |_, this, ()| {
|
fn build<'a>(state: &elua::State, builder: &mut elua::UserdataBuilder<'a, Self>) -> elua::Result<()> {
|
||||||
Ok(format!("{}", this.0.deref()))
|
builder
|
||||||
});
|
.method("get", |_, this, ()| {
|
||||||
|
Ok(*this.0)
|
||||||
methods.add_function(FN_NAME_INTERNAL_REFLECT_TYPE, |_, ()| {
|
})
|
||||||
|
.meta_method(elua::MetaMethod::ToString, |_, this, ()| {
|
||||||
|
Ok(format!("{}", *this.0))
|
||||||
|
})
|
||||||
|
.function(FN_NAME_INTERNAL_REFLECT_TYPE, |_, ()| {
|
||||||
Ok(ScriptBorrow::from_resource::<DeltaTime>(None))
|
Ok(ScriptBorrow::from_resource::<DeltaTime>(None))
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@ use lyra_scripting_derive::wrap_math_vec_copy;
|
||||||
use crate as lyra_scripting;
|
use crate as lyra_scripting;
|
||||||
|
|
||||||
// f32 types
|
// f32 types
|
||||||
wrap_math_vec_copy!(
|
/* wrap_math_vec_copy!(
|
||||||
math::Vec2,
|
math::Vec2,
|
||||||
derives(PartialEq),
|
derives(PartialEq),
|
||||||
fields(x, y),
|
fields(x, y),
|
||||||
|
@ -32,7 +32,11 @@ wrap_math_vec_copy!(
|
||||||
Mod(LuaVec3, f32),
|
Mod(LuaVec3, f32),
|
||||||
Eq, Unm, ToString
|
Eq, Unm, ToString
|
||||||
)
|
)
|
||||||
);
|
); */
|
||||||
|
|
||||||
|
|
||||||
|
// =================================================
|
||||||
|
|
||||||
|
|
||||||
/* wrap_math_vec_copy!(
|
/* wrap_math_vec_copy!(
|
||||||
math::Vec3A,
|
math::Vec3A,
|
||||||
|
@ -379,7 +383,20 @@ wrap_math_vec_copy!(
|
||||||
)
|
)
|
||||||
); */
|
); */
|
||||||
|
|
||||||
wrap_math_vec_copy!(
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* wrap_math_vec_copy!(
|
||||||
math::Quat,
|
math::Quat,
|
||||||
derives(PartialEq),
|
derives(PartialEq),
|
||||||
no_new,
|
no_new,
|
||||||
|
@ -559,3 +576,4 @@ wrap_math_vec_copy!(
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
*/
|
Loading…
Reference in New Issue