Expose structs to Lua and write Lua type annotations #28
|
@ -93,13 +93,15 @@ function on_update()
|
|||
---@type number
|
||||
local dt = world:resource(DeltaTime)
|
||||
|
||||
--[[ world:view(
|
||||
world:view(
|
||||
---@param t Transform
|
||||
function (t)
|
||||
---@param wt WorldTransform
|
||||
function (t, wt)
|
||||
print("Entity is at: " .. tostring(wt))
|
||||
t:translate(0, 0.15 * dt, 0)
|
||||
return t
|
||||
end, Transform
|
||||
) ]]
|
||||
end, Transform, WorldTransform
|
||||
)
|
||||
|
||||
--[[ world:view(
|
||||
---@param c Camera
|
||||
|
|
|
@ -1,18 +1,10 @@
|
|||
use lyra_engine::{
|
||||
assets::{gltf::Gltf, ResourceManager},
|
||||
game::App,
|
||||
input::{
|
||||
assets::{gltf::Gltf, ResourceManager}, game::App, input::{
|
||||
Action, ActionHandler, ActionKind, ActionMapping, ActionMappingId, ActionSource,
|
||||
InputActionPlugin, KeyCode, LayoutId, MouseAxis, MouseInput,
|
||||
},
|
||||
script::{lua::{LuaScript, LuaScriptingPlugin}, Script, ScriptList},
|
||||
math::{self, Transform, Vec3},
|
||||
render::light::directional::DirectionalLight,
|
||||
scene::{
|
||||
CameraComponent, FreeFlyCamera, FreeFlyCameraPlugin, WorldTransform,
|
||||
ACTLBL_LOOK_LEFT_RIGHT, ACTLBL_LOOK_ROLL, ACTLBL_LOOK_UP_DOWN,
|
||||
ACTLBL_MOVE_FORWARD_BACKWARD, ACTLBL_MOVE_LEFT_RIGHT, ACTLBL_MOVE_UP_DOWN,
|
||||
},
|
||||
}, math::{self, Transform, Vec3}, render::light::directional::DirectionalLight, scene::{
|
||||
self, CameraComponent, FreeFlyCamera, FreeFlyCameraPlugin, WorldTransform, ACTLBL_LOOK_LEFT_RIGHT, ACTLBL_LOOK_ROLL, ACTLBL_LOOK_UP_DOWN, ACTLBL_MOVE_FORWARD_BACKWARD, ACTLBL_MOVE_LEFT_RIGHT, ACTLBL_MOVE_UP_DOWN
|
||||
}, script::{lua::{LuaScript, LuaScriptingPlugin}, Script, ScriptList}
|
||||
};
|
||||
|
||||
#[async_std::main]
|
||||
|
@ -91,6 +83,11 @@ async fn main() {
|
|||
app.with_plugin(setup_scene_plugin);
|
||||
app.with_plugin(action_handler_plugin);
|
||||
app.with_plugin(setup_script_plugin);
|
||||
app.with_system(
|
||||
"update_world_transforms",
|
||||
scene::system_update_world_transforms,
|
||||
&[],
|
||||
);
|
||||
//app.with_plugin(camera_debug_plugin);
|
||||
app.with_plugin(FreeFlyCameraPlugin);
|
||||
app.run();
|
||||
|
|
|
@ -2,6 +2,7 @@ use std::ops::Deref;
|
|||
|
||||
use lyra_ecs::{query::{filter::{Has, Not}, Entities, View}, relation::{ChildOf, RelationOriginComponent}, Component, Entity, World};
|
||||
use lyra_math::Transform;
|
||||
use lyra_reflect::Reflect;
|
||||
use crate::lyra_engine;
|
||||
|
||||
/// The world transform of an entity.
|
||||
|
@ -11,7 +12,7 @@ use crate::lyra_engine;
|
|||
/// you should use its [`Transform`]. You cannot mutate [`WorldTransform`] as its managed completey
|
||||
/// by the [`system_update_world_transforms`] system. For the WorldTransform to work properly, you
|
||||
/// must have both a [`Transform`] and [`WorldTransform`] on the entities in the scene.
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Default, Component)]
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Default, Component, Reflect)]
|
||||
pub struct WorldTransform(pub(crate) Transform);
|
||||
|
||||
impl Deref for WorldTransform {
|
||||
|
|
|
@ -47,7 +47,7 @@ fn field_table_getter(field: &Field) -> proc_macro2::TokenStream {
|
|||
}
|
||||
}
|
||||
|
||||
fn wrapper_creation(wrapper: &syn::Ident, type_path: &syn::Path, create: Option<&syn::Block>, fields: &Vec<Field>) -> proc_macro2::TokenStream {
|
||||
fn wrapper_creation(wrapper: &syn::Ident, type_path: &syn::Path, struct_type: StructType, create: Option<&syn::Block>, fields: &Vec<Field>) -> proc_macro2::TokenStream {
|
||||
|
||||
match create {
|
||||
Some(b) => quote!(#b),
|
||||
|
@ -59,19 +59,28 @@ fn wrapper_creation(wrapper: &syn::Ident, type_path: &syn::Path, create: Option<
|
|||
}); */
|
||||
let field_iter = fields.iter().map(|f| {
|
||||
let ident = &f.field;
|
||||
if f.field_ty.is_wrapped() {
|
||||
if f.field_ty.is_wrapped() && struct_type == StructType::Fields {
|
||||
quote!(#ident: (*#ident).clone())
|
||||
} else {
|
||||
quote!(#ident)
|
||||
}
|
||||
});
|
||||
|
||||
quote! {
|
||||
#wrapper(#type_path {
|
||||
#(
|
||||
#field_iter
|
||||
),*
|
||||
})
|
||||
match struct_type {
|
||||
StructType::Fields => {
|
||||
quote! {
|
||||
#wrapper(#type_path {
|
||||
#(
|
||||
#field_iter
|
||||
),*
|
||||
})
|
||||
}
|
||||
},
|
||||
StructType::Tuple => {
|
||||
quote! {
|
||||
#wrapper(#type_path( #(#field_iter),* ))
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -104,8 +113,17 @@ enum ReflectType {
|
|||
Resource,
|
||||
}
|
||||
|
||||
/// The type of the wrapping struct
|
||||
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
|
||||
enum StructType {
|
||||
#[default]
|
||||
Fields,
|
||||
Tuple,
|
||||
}
|
||||
|
||||
struct IntoLuaUsage {
|
||||
type_path: syn::Path,
|
||||
struct_type: StructType,
|
||||
override_name: Option<syn::Ident>,
|
||||
table_name: String,
|
||||
derives: Vec<syn::Ident>,
|
||||
|
@ -126,6 +144,7 @@ impl syn::parse::Parse for IntoLuaUsage {
|
|||
|
||||
let mut s = Self {
|
||||
type_path,
|
||||
struct_type: StructType::Fields,
|
||||
override_name: None,
|
||||
table_name: lua_name,
|
||||
derives: vec![],
|
||||
|
@ -149,6 +168,23 @@ impl syn::parse::Parse for IntoLuaUsage {
|
|||
let name: syn::Ident = input.parse()?;
|
||||
s.override_name = Some(name);
|
||||
},
|
||||
"struct_type" => {
|
||||
let _eq: Token![=] = input.parse()?;
|
||||
|
||||
let st_token = input.parse::<syn::LitStr>()?;
|
||||
let st_str = st_token.value().to_lowercase();
|
||||
let st_str = st_str.as_str();
|
||||
|
||||
let st = match st_str {
|
||||
"fields" => StructType::Fields,
|
||||
"tuple" => StructType::Tuple,
|
||||
_ => return Err(syn::Error::new_spanned(
|
||||
st_token,
|
||||
format!("unknown struct type: '{}', expected 'fields', or `tuple`", st_str),
|
||||
)),
|
||||
};
|
||||
s.struct_type = st;
|
||||
},
|
||||
"lua_name" => {
|
||||
let _eq: Token![=] = input.parse()?;
|
||||
s.table_name = input.parse::<syn::LitStr>()?.value();
|
||||
|
@ -242,7 +278,7 @@ pub fn to_lua_struct_impl(input: proc_macro::TokenStream) -> proc_macro::TokenSt
|
|||
let lua_name = &input.table_name;
|
||||
let field_getters_iter = input.fields.iter().map(|f| field_table_getter(f));
|
||||
let field_setters_iter = input.fields.iter().map(|f| field_table_setter(f));
|
||||
let struct_creator = wrapper_creation(&wrapper, type_path, input.create.as_ref(), &input.fields);
|
||||
let struct_creator = wrapper_creation(&wrapper, type_path, input.struct_type, input.create.as_ref(), &input.fields);
|
||||
let reflect_fn = get_reflect_lua_functions(reflect_type, &input.type_path, true);
|
||||
let reflect_type_fn = get_reflect_lua_functions(reflect_type, &input.type_path, false);
|
||||
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
---@meta
|
||||
|
||||
---@class Window: userdata
|
||||
Window = {
|
||||
---Gets or sets the window's focus.
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
---@meta
|
||||
|
||||
--- A Transform represents the relative position of the entity to its parent entity, while
|
||||
--- a world transform is the position relative to the World. When wanting to move an entity,
|
||||
--- you should use its [`Transform`]. You cannot mutate [`WorldTransform`] as its managed completey
|
||||
--- by the [`system_update_world_transforms`] system. For the WorldTransform to work properly, you
|
||||
--- must have both a [`Transform`] and [`WorldTransform`] on the entities in the scene.
|
||||
---@alias WorldTransform Transform The world transform of an entity.
|
||||
WorldTransform = {}
|
|
@ -19,6 +19,7 @@ impl ScriptApiProvider for LyraEcsApiProvider {
|
|||
|
||||
world.register_lua_convert_component::<LuaCamera>("Camera");
|
||||
world.register_lua_convert_component::<LuaFreeFlyCamera>("FreeFlyCamera");
|
||||
world.register_lua_convert_component::<LuaWorldTransform>("WorldTransform");
|
||||
|
||||
world.register_lua_wrapper::<LuaDeviceId>();
|
||||
world.register_lua_convert::<LuaDeviceEventRaw>();
|
||||
|
@ -44,6 +45,7 @@ impl ScriptApiProvider for LyraEcsApiProvider {
|
|||
|
||||
expose_comp_table_wrapper::<LuaCamera>(&ctx, &globals, "Camera")?;
|
||||
expose_comp_table_wrapper::<LuaFreeFlyCamera>(&ctx, &globals, "FreeFlyCamera")?;
|
||||
expose_comp_table_wrapper::<LuaWorldTransform>(&ctx, &globals, "WorldTransform")?;
|
||||
expose_table_wrapper::<LuaDeviceEvent>(&ctx, &globals, "DeviceEvent")?;
|
||||
|
||||
let dt_table = create_reflect_table::<lyra_game::DeltaTime>(&ctx)?;
|
||||
|
@ -86,11 +88,12 @@ where
|
|||
|
||||
table.set(mlua::MetaMethod::Type.name(), name)?;
|
||||
|
||||
|
||||
Ok(table)
|
||||
}
|
||||
|
||||
/// Expose a wrapper that converts to/from a lua type.
|
||||
/// Expose a wrapper of a component that converts to/from a lua type.
|
||||
///
|
||||
/// This type of wrapper could convert to/from a Lua table, or number, string, etc., any Lua type.
|
||||
///
|
||||
/// This creates the reflection functions on a table specified in globals.
|
||||
/// The table name is set to `name`, which is also how the script will use the table.
|
||||
|
|
|
@ -21,3 +21,6 @@ pub use free_fly_camera::*;
|
|||
|
||||
mod events;
|
||||
pub use events::*;
|
||||
|
||||
mod world_transform;
|
||||
pub use world_transform::*;
|
|
@ -0,0 +1,49 @@
|
|||
use crate::lua::{wrappers::LuaTransform, LuaWrapper};
|
||||
use crate::lyra_engine;
|
||||
use lyra_game::scene::WorldTransform;
|
||||
use lyra_reflect::Reflect;
|
||||
|
||||
#[derive(Clone, Default, Reflect)]
|
||||
pub struct LuaWorldTransform(pub(crate) WorldTransform);
|
||||
|
||||
impl std::ops::Deref for LuaWorldTransform {
|
||||
type Target = WorldTransform;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::DerefMut for LuaWorldTransform {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl mlua::FromLua for LuaWorldTransform {
|
||||
fn from_lua(v: mlua::Value, lua: &mlua::Lua) -> mlua::Result<Self> {
|
||||
let t = LuaTransform::from_lua(v, lua)?;
|
||||
Ok(Self(WorldTransform::from(*t)))
|
||||
}
|
||||
}
|
||||
|
||||
impl mlua::IntoLua for LuaWorldTransform {
|
||||
fn into_lua(self, lua: &mlua::Lua) -> mlua::Result<mlua::Value> {
|
||||
let t = LuaTransform(*self.0);
|
||||
t.into_lua(lua)
|
||||
}
|
||||
}
|
||||
|
||||
impl LuaWrapper for LuaWorldTransform {
|
||||
type Wrap = WorldTransform;
|
||||
|
||||
#[inline(always)]
|
||||
fn into_wrapped(self) -> Self::Wrap {
|
||||
self.0
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn from_wrapped(wrap: Self::Wrap) -> Option<Self> {
|
||||
Some(Self(wrap))
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue