scripting: expose resources to the world

This commit is contained in:
SeanOMik 2024-01-20 00:54:36 -05:00
parent 94abf2ddf0
commit e88758f59d
Signed by: SeanOMik
GPG Key ID: FEC9E2FC15235964
16 changed files with 1030 additions and 736 deletions

View File

@ -15,9 +15,12 @@ end ]]
function on_update()
--print("Lua's update function was called")
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.0008, 0)
t.translation = t.translation + (Vec3.new(0, 0.5, 0) * dt:get())
return t
end, Transform)

View File

@ -6,7 +6,7 @@ impl<T: 'static> ResourceObject for T {}
/// A type erased storage for a Resource.
pub struct ResourceData {
data: Box<RefCell<dyn Any>>,
pub(crate) data: Box<RefCell<dyn Any>>,
type_id: TypeId,
}

View File

@ -1,6 +1,6 @@
use std::{collections::{HashMap, VecDeque}, any::TypeId, cell::{Ref, RefMut}, ptr::NonNull};
use crate::{archetype::{ArchetypeId, Archetype}, bundle::Bundle, query::{Query, ViewIter, View, AsQuery}, resource::ResourceData, query::{dynamic::DynamicView, ViewOne}, ComponentInfo, DynTypeId, TickTracker, Tick};
use crate::{archetype::{ArchetypeId, Archetype}, bundle::Bundle, query::{Query, ViewIter, View, AsQuery}, resource::ResourceData, query::{dynamic::DynamicView, ViewOne}, ComponentInfo, DynTypeId, TickTracker, Tick, ResourceObject};
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct EntityId(pub u64);
@ -306,6 +306,12 @@ impl World {
pub fn tick_tracker(&self) -> &TickTracker {
&self.tracker
}
/// Attempts to find a resource in the world and returns a NonNull pointer to it
pub unsafe fn try_get_resource_ptr<T: ResourceObject>(&self) -> Option<NonNull<T>> {
self.resources.get(&TypeId::of::<T>())
.map(|d| unsafe { NonNull::new_unchecked(d.data.as_ptr() as *mut T) })
}
}
#[cfg(test)]

View File

@ -1,10 +1,11 @@
use instant::Instant;
use lyra_ecs::{Component, world::World};
use lyra_reflect::Reflect;
use crate::{plugin::Plugin, game::GameStages};
#[derive(Clone, Component)]
pub struct DeltaTime(f32, Option<Instant>);
#[derive(Clone, Component, Default, Reflect)]
pub struct DeltaTime(f32, #[reflect(skip)] Option<Instant>);
impl std::ops::Deref for DeltaTime {
type Target = f32;

View File

@ -26,6 +26,7 @@ pub mod scene;
pub use lyra_resource as assets;
pub use lyra_ecs as ecs;
pub use lyra_math as math;
pub use lyra_reflect as reflect;
#[cfg(feature = "scripting")]
pub use lyra_scripting as script;

View File

@ -0,0 +1,70 @@
use std::{any::TypeId, cell::{Ref, RefMut}};
use lyra_ecs::{Component, ComponentInfo, World, Entity, DynamicBundle};
use crate::{Reflect, FromType};
#[derive(Clone)]
pub struct ReflectedComponent {
pub type_id: TypeId,
pub info: ComponentInfo,
//value: Value,
//from_world:
//from_world: for<'a> fn (world: &'a mut World) -> Box<dyn Reflect>,
/// Inserts component into entity in the world
fn_insert: for<'a> fn (world: &'a mut World, entity: Entity, component: &dyn Reflect),
/// Inserts component into a bundle
fn_bundle_insert: for<'a> fn (dynamic_bundle: &'a mut DynamicBundle, component: &dyn Reflect),
fn_reflect: for<'a> fn (world: &'a World, entity: Entity) -> Option<Ref<'a, dyn Reflect>>,
fn_reflect_mut: for<'a> fn (world: &'a mut World, entity: Entity) -> Option<RefMut<'a, dyn Reflect>>,
}
impl ReflectedComponent {
/// Insert the reflected component into an entity.
pub fn insert(&self, world: &mut World, entity: Entity, component: &dyn Reflect) {
(self.fn_insert)(world, entity, component);
}
/// Insert this component into a DynamicBundle
pub fn bundle_insert(&self, dynamic_bundle: &mut DynamicBundle, component: &dyn Reflect) {
(self.fn_bundle_insert)(dynamic_bundle, component)
}
/// Retrieves a reflected component from an entity.
pub fn reflect<'a>(&'a self, world: &'a World, entity: Entity) -> Option<Ref<'a, dyn Reflect>> {
(self.fn_reflect)(world, entity)
}
/// Retrieves a reflected component from an entity.
pub fn reflect_mut<'a>(&'a mut self, world: &'a mut World, entity: Entity) -> Option<RefMut<'a, dyn Reflect>> {
(self.fn_reflect_mut)(world, entity)
}
}
impl<C: Component + Reflect + Default> FromType<C> for ReflectedComponent {
fn from_type() -> Self {
ReflectedComponent {
type_id: TypeId::of::<C>(),
info: ComponentInfo::new::<C>(),
fn_insert: |world: &mut World, entity: Entity, component: &dyn Reflect| {
let mut c = C::default();
c.apply(component);
world.insert(entity, (c,));
},
fn_bundle_insert: |bundle: &mut DynamicBundle, component: &dyn Reflect| {
let mut c = C::default();
c.apply(component);
bundle.push(c);
},
fn_reflect: |world: &World, entity: Entity| {
world.view_one::<&C>(entity)
.get().map(|c| c as Ref<dyn Reflect>)
},
fn_reflect_mut: |world: &mut World, entity: Entity| {
world.view_one::<&mut C>(entity)
.get().map(|c| c as RefMut<dyn Reflect>)
},
}
}
}

View File

@ -36,6 +36,12 @@ pub use dynamic_tuple::*;
pub mod reflected_field;
pub use reflected_field::*;
pub mod component;
pub use component::*;
pub mod resource;
pub use resource::*;
pub mod util;
pub mod field;
pub use field::*;
@ -237,67 +243,48 @@ pub trait FromType<T> {
fn from_type() -> Self;
}
#[derive(Clone)]
pub struct ReflectedComponent {
pub type_id: TypeId,
pub info: ComponentInfo,
//value: Value,
//from_world:
//from_world: for<'a> fn (world: &'a mut World) -> Box<dyn Reflect>,
/// Inserts component into entity in the world
fn_insert: for<'a> fn (world: &'a mut World, entity: Entity, component: &dyn Reflect),
/// Inserts component into a bundle
fn_bundle_insert: for<'a> fn (dynamic_bundle: &'a mut DynamicBundle, component: &dyn Reflect),
fn_reflect: for<'a> fn (world: &'a World, entity: Entity) -> Option<Ref<'a, dyn Reflect>>,
fn_reflect_mut: for<'a> fn (world: &'a mut World, entity: Entity) -> Option<RefMut<'a, dyn Reflect>>,
pub trait ReflectWorldExt {
/// Retrieves the type registry from the world.
fn get_type_registry(&self) -> Ref<TypeRegistry>;
/// Retrieves the type registry mutably from the world.
fn get_type_registry_mut(&self) -> RefMut<TypeRegistry>;
/// Get a registered type from the type registry. Returns `None` if the type is not registered
fn get_type<T>(&self, type_id: TypeId) -> Option<Ref<RegisteredType>>;
/// Get a mutable registered type from the type registry in the world. returns `None` if the type is not registered.
fn get_type_mut<T>(&self, type_id: TypeId) -> Option<RefMut<RegisteredType>>;
/// Get a registered type, or register a new type and return it.
fn get_type_or_default<T>(&self, type_id: TypeId) -> RefMut<RegisteredType>;
}
impl ReflectedComponent {
/// Insert the reflected component into an entity.
pub fn insert(&self, world: &mut World, entity: Entity, component: &dyn Reflect) {
(self.fn_insert)(world, entity, component);
impl ReflectWorldExt for World {
fn get_type_registry(&self) -> Ref<TypeRegistry> {
self.get_resource::<TypeRegistry>()
}
/// Insert this component into a DynamicBundle
pub fn bundle_insert(&self, dynamic_bundle: &mut DynamicBundle, component: &dyn Reflect) {
(self.fn_bundle_insert)(dynamic_bundle, component)
fn get_type_registry_mut(&self) -> RefMut<TypeRegistry> {
self.get_resource_mut::<TypeRegistry>()
}
/// Retrieves a reflected component from an entity.
pub fn reflect<'a>(&'a self, world: &'a World, entity: Entity) -> Option<Ref<'a, dyn Reflect>> {
(self.fn_reflect)(world, entity)
}
/// Retrieves a reflected component from an entity.
pub fn reflect_mut<'a>(&'a mut self, world: &'a mut World, entity: Entity) -> Option<RefMut<'a, dyn Reflect>> {
(self.fn_reflect_mut)(world, entity)
}
}
impl<C: Component + Reflect + Default> FromType<C> for ReflectedComponent {
fn from_type() -> Self {
ReflectedComponent {
type_id: TypeId::of::<C>(),
info: ComponentInfo::new::<C>(),
fn_insert: |world: &mut World, entity: Entity, component: &dyn Reflect| {
let mut c = C::default();
c.apply(component);
world.insert(entity, (c,));
},
fn_bundle_insert: |bundle: &mut DynamicBundle, component: &dyn Reflect| {
let mut c = C::default();
c.apply(component);
bundle.push(c);
},
fn_reflect: |world: &World, entity: Entity| {
world.view_one::<&C>(entity)
.get().map(|c| c as Ref<dyn Reflect>)
},
fn_reflect_mut: |world: &mut World, entity: Entity| {
world.view_one::<&mut C>(entity)
.get().map(|c| c as RefMut<dyn Reflect>)
},
fn get_type<T>(&self, type_id: TypeId) -> Option<Ref<RegisteredType>> {
let r = self.get_resource::<TypeRegistry>();
if r.has_type(type_id) {
Some(Ref::map(r, |tr| tr.get_type(type_id).unwrap()))
} else {
None
}
}
fn get_type_mut<T>(&self, type_id: TypeId) -> Option<RefMut<RegisteredType>> {
let r = self.get_resource_mut::<TypeRegistry>();
if r.has_type(type_id) {
Some(RefMut::map(r, |tr| tr.get_type_mut(type_id).unwrap()))
} else {
None
}
}
fn get_type_or_default<T>(&self, type_id: TypeId) -> RefMut<RegisteredType> {
let r = self.get_resource_mut::<TypeRegistry>();
RefMut::map(r, |tr| tr.get_type_or_default(type_id))
}
}

View File

@ -0,0 +1,50 @@
use std::{any::TypeId, cell::{Ref, RefMut}, ptr::NonNull};
use lyra_ecs::{World, ResourceObject};
use crate::{Reflect, FromType};
#[derive(Clone)]
pub struct ReflectedResource {
pub type_id: TypeId,
fn_reflect: for<'a> fn (world: &'a World) -> Option<Ref<'a, dyn Reflect>>,
fn_reflect_mut: for<'a> fn (world: &'a mut World) -> Option<RefMut<'a, dyn Reflect>>,
fn_reflect_ptr: fn (world: &mut World) -> Option<NonNull<u8>>,
}
impl ReflectedResource {
/// Retrieves the reflected resource from the world.
pub fn reflect<'a>(&self, world: &'a World) -> Option<Ref<'a, dyn Reflect>> {
(self.fn_reflect)(world)
}
/// Retrieves a mutable reflected resource from the world.
pub fn reflect_mut<'a>(&self, world: &'a mut World) -> Option<RefMut<'a, dyn Reflect>> {
(self.fn_reflect_mut)(world)
}
pub fn reflect_ptr(&self, world: &mut World) -> Option<NonNull<u8>> {
(self.fn_reflect_ptr)(world)
}
}
impl<T: ResourceObject + Reflect> FromType<T> for ReflectedResource {
fn from_type() -> Self {
Self {
type_id: TypeId::of::<T>(),
fn_reflect: |world: &World| {
world.try_get_resource::<T>()
.map(|r| r as Ref<dyn Reflect>)
},
fn_reflect_mut: |world: &mut World| {
world.try_get_resource_mut::<T>()
.map(|r| r as RefMut<dyn Reflect>)
},
fn_reflect_ptr: |world: &mut World| unsafe {
world.try_get_resource_ptr::<T>()
.map(|ptr| ptr.cast::<u8>())
},
}
}
}

View File

@ -2,7 +2,9 @@
pub mod lua;
pub mod world;
use lyra_ecs::Component;
use std::any::TypeId;
use lyra_ecs::{Component, ResourceObject};
pub use world::*;
pub mod wrap;
@ -16,17 +18,19 @@ pub use script::*;
use lyra_game::game::Game;
// required for some proc macros :(
#[allow(unused_imports)]
pub(crate) mod lyra_engine {
pub use lyra_ecs as ecs;
pub use lyra_reflect as reflect;
}
use lyra_reflect::{ReflectedComponent, Reflect, FromType};
use lyra_reflect::{ReflectedComponent, Reflect, FromType, ReflectedResource};
#[derive(Clone)]
pub enum ReflectBranch {
Component(ReflectedComponent),
Resource(ReflectedResource),
}
impl ReflectBranch {
@ -37,13 +41,38 @@ impl ReflectBranch {
pub fn as_component_unchecked(&self) -> &ReflectedComponent {
match self {
ReflectBranch::Component(c) => c,
//_ => panic!("`self` is not an instance of `ReflectBranch::Component`")
_ => panic!("`self` is not an instance of `ReflectBranch::Component`")
}
}
/// Returns a boolean indicating if `self` is a reflection of a Component.
pub fn is_component(&self) -> bool {
matches!(self, ReflectBranch::Component(_))
}
/// Gets self as a [`ReflectedResource`].
///
/// # Panics
/// If `self` is not a variant of [`ReflectBranch::Resource`].
pub fn as_resource_unchecked(&self) -> &ReflectedResource {
match self {
ReflectBranch::Resource(v) => v,
_ => panic!("`self` is not an instance of `ReflectBranch::Component`")
}
}
/// Returns a boolean indicating if `self` is a reflection of a Resource.
pub fn is_resource(&self) -> bool {
matches!(self, ReflectBranch::Resource(_))
}
/// Returns the type id of the reflected thing
pub fn reflect_type_id(&self) -> TypeId {
match self {
ReflectBranch::Component(c) => c.type_id,
ReflectBranch::Resource(r) => r.type_id,
}
}
}
pub struct ScriptBorrow {
@ -63,6 +92,7 @@ impl Clone for ScriptBorrow {
}
impl ScriptBorrow {
/// Creates a ScriptBorrow from a Component
pub fn from_component<T>(data: Option<T>) -> Self
where
T: Reflect + Component + Default + 'static
@ -74,10 +104,24 @@ impl ScriptBorrow {
data,
}
}
/// Creates a ScriptBorrow from a Resource.
pub fn from_resource<T>(data: Option<T>) -> Self
where
T: Reflect + ResourceObject + Default + 'static
{
let data = data.map(|d| Box::new(d) as Box<(dyn Reflect + 'static)>);
Self {
reflect_branch: ReflectBranch::Resource(<ReflectedResource as FromType<T>>::from_type()),
data,
}
}
}
/// An extension trait that adds some helpful methods that makes it easier to do scripting things
pub trait GameScriptExt {
/// A helper method for adding a ScriptApiProvider into the world.
fn add_script_api_provider<T, P>(&mut self, provider: P)
where
T: ScriptHost,

View File

@ -5,7 +5,7 @@ pub use dynamic_iter::*;
pub mod world;
use lyra_game::{game::GameStages, plugin::Plugin};
use lyra_resource::ResourceManager;
use tracing::{debug, error, trace, debug_span};
use tracing::{debug, debug_span, error, trace};
pub use world::*;
pub mod script;
@ -17,6 +17,9 @@ pub use loader::*;
pub mod providers;
pub mod wrappers;
pub mod proxy;
pub use proxy::*;
#[cfg(test)]
mod test;
@ -43,24 +46,22 @@ use crate::{
use self::providers::{LyraEcsApiProvider, LyraMathApiProvider, UtilityApiProvider};
pub trait RegisterLuaType {
/// Register a lua type that **is not wrapped**.
fn register_lua_type<'a, T: Reflect + LuaProxy + Clone + mlua::FromLua<'a> + mlua::UserData>(
&mut self,
);
/// 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;
/// Registers a wrapped lua type.
/// You provide the wrapper as `W`, and the type that the wrapper wraps, as `T`.
fn register_lua_wrapper<
'a,
W: Reflect + LuaProxy + LuaWrapper + Clone + mlua::FromLua<'a> + mlua::UserData,
>(
&mut self,
);
fn register_lua_wrapper<'a, W>(&mut self)
where
W: Reflect + LuaProxy + LuaWrapper + Clone + mlua::FromLua<'a> + mlua::UserData;
}
impl RegisterLuaType for World {
fn register_lua_type<'a, T: Reflect + LuaProxy + Clone + mlua::FromLua<'a> + mlua::UserData>(
&mut self,
) {
fn register_lua_type<'a, T>(&mut self)
where
T: Reflect + LuaProxy + Clone + mlua::FromLua<'a> + mlua::UserData
{
let mut registry = self.get_resource_mut::<TypeRegistry>();
let type_id = TypeId::of::<T>();
@ -70,12 +71,10 @@ impl RegisterLuaType for World {
//reg_type.add_data(<ReflectedComponent as FromType<T>>::from_type());
}
fn register_lua_wrapper<
'a,
W: Reflect + LuaProxy + LuaWrapper + Clone + mlua::FromLua<'a> + mlua::UserData,
>(
&mut self,
) {
fn register_lua_wrapper<'a, W>(&mut self)
where
W: Reflect + LuaProxy + LuaWrapper + Clone + mlua::FromLua<'a> + mlua::UserData
{
let mut registry = self.get_resource_mut::<TypeRegistry>();
let reg_type = registry.get_type_or_default(W::wrapped_type_id());
@ -99,88 +98,6 @@ pub fn reflect_user_data(ud: &mlua::AnyUserData) -> ScriptBorrow {
.expect("Type does not implement '__internal_reflect' properly")
}
pub trait LuaWrapper {
/// The type id of the wrapped type.
fn wrapped_type_id() -> TypeId;
}
pub trait LuaProxy {
fn as_lua_value<'lua>(
lua: &'lua mlua::Lua,
this: &dyn Reflect,
) -> mlua::Result<mlua::AnyUserData<'lua>>;
fn apply(
lua: &mlua::Lua,
this: &mut dyn Reflect,
apply: &mlua::AnyUserData,
) -> mlua::Result<()>;
}
impl<'a, T: Reflect + Clone + mlua::FromLua<'a> + mlua::UserData> LuaProxy for T {
fn as_lua_value<'lua>(
lua: &'lua mlua::Lua,
this: &dyn Reflect,
) -> mlua::Result<mlua::AnyUserData<'lua>> {
let this = this.as_any().downcast_ref::<T>().unwrap();
lua.create_userdata(this.clone())
}
fn apply(
_lua: &mlua::Lua,
this: &mut dyn Reflect,
apply: &mlua::AnyUserData,
) -> mlua::Result<()> {
let this = this.as_any_mut().downcast_mut::<T>().unwrap();
let apply = apply.borrow::<T>()?;
*this = apply.clone();
Ok(())
}
}
#[derive(Clone)]
pub struct ReflectLuaProxy {
fn_as_uservalue:
for<'a> fn(lua: &'a Lua, this_ptr: NonNull<u8>) -> mlua::Result<mlua::AnyUserData<'a>>,
fn_apply: for<'a> fn(
lua: &'a Lua,
this_ptr: NonNull<u8>,
apply: &'a mlua::AnyUserData<'a>,
) -> mlua::Result<()>,
}
impl<'a, T: Reflect + LuaProxy + Clone + mlua::FromLua<'a> + mlua::UserData> FromType<T>
for ReflectLuaProxy
{
fn from_type() -> Self {
Self {
fn_as_uservalue: |lua, this| -> mlua::Result<mlua::AnyUserData> {
let this = unsafe { this.cast::<T>().as_ref() };
<T as LuaProxy>::as_lua_value(lua, this)
},
fn_apply: |lua, ptr, apply| {
let this = unsafe { ptr.cast::<T>().as_mut() };
<T as LuaProxy>::apply(lua, this, apply)
},
}
}
}
impl<'lua> mlua::FromLua<'lua> for ScriptDynamicBundle {
fn from_lua(value: mlua::Value<'lua>, _lua: &'lua 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 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())));

View File

@ -1,4 +1,4 @@
use crate::{lua::LuaContext, ScriptApiProvider, ScriptWorldPtr, ScriptDynamicBundle, ScriptData};
use crate::{lua::{LuaContext, wrappers::LuaDeltaTime, RegisterLuaType}, ScriptApiProvider, ScriptWorldPtr, ScriptDynamicBundle, ScriptData};
#[derive(Default)]
pub struct LyraEcsApiProvider;
@ -6,6 +6,10 @@ pub struct LyraEcsApiProvider;
impl ScriptApiProvider for LyraEcsApiProvider {
type ScriptContext = LuaContext;
fn prepare_world(&mut self, world: &mut lyra_ecs::World) {
world.register_lua_wrapper::<LuaDeltaTime>();
}
fn expose_api(&mut self, data: &ScriptData, ctx: &mut Self::ScriptContext) -> Result<(), crate::ScriptError> {
let ctx = ctx.lock().unwrap();
@ -13,6 +17,8 @@ impl ScriptApiProvider for LyraEcsApiProvider {
globals.set("World", ctx.create_proxy::<ScriptWorldPtr>()?)?;
globals.set("DynamicBundle", ctx.create_proxy::<ScriptDynamicBundle>()?)?;
globals.set("DeltaTime", ctx.create_proxy::<LuaDeltaTime>()?)?;
Ok(())
}

View File

@ -0,0 +1,92 @@
use std::{any::TypeId, ptr::NonNull};
use lyra_reflect::{Reflect, FromType};
use crate::ScriptDynamicBundle;
pub trait LuaWrapper {
/// The type id of the wrapped type.
fn wrapped_type_id() -> TypeId;
}
pub trait LuaProxy {
fn as_lua_value<'lua>(
lua: &'lua mlua::Lua,
this: &dyn Reflect,
) -> mlua::Result<mlua::AnyUserData<'lua>>;
fn apply(
lua: &mlua::Lua,
this: &mut dyn Reflect,
apply: &mlua::AnyUserData,
) -> mlua::Result<()>;
}
impl<'a, T> LuaProxy for T
where
T: Reflect + Clone + mlua::FromLua<'a> + mlua::UserData
{
fn as_lua_value<'lua>(
lua: &'lua mlua::Lua,
this: &dyn Reflect,
) -> mlua::Result<mlua::AnyUserData<'lua>> {
let this = this.as_any().downcast_ref::<T>().unwrap();
lua.create_userdata(this.clone())
}
fn apply(
_lua: &mlua::Lua,
this: &mut dyn Reflect,
apply: &mlua::AnyUserData,
) -> mlua::Result<()> {
let this = this.as_any_mut().downcast_mut::<T>().unwrap();
let apply = apply.borrow::<T>()?;
*this = apply.clone();
Ok(())
}
}
#[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>>,
pub fn_apply: for<'a> fn(
lua: &'a mlua::Lua,
this_ptr: NonNull<u8>,
apply: &'a mlua::AnyUserData<'a>,
) -> mlua::Result<()>,
}
impl<'a, T> FromType<T> for ReflectLuaProxy
where
T: Reflect + LuaProxy + Clone + mlua::FromLua<'a> + mlua::UserData
{
fn from_type() -> Self {
Self {
fn_as_uservalue: |lua, this| -> mlua::Result<mlua::AnyUserData> {
let this = unsafe { this.cast::<T>().as_ref() };
<T as LuaProxy>::as_lua_value(lua, this)
},
fn_apply: |lua, ptr, apply| {
let this = unsafe { ptr.cast::<T>().as_mut() };
<T as LuaProxy>::apply(lua, this, apply)
},
}
}
}
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!(),
}
}
}

View File

@ -1,7 +1,7 @@
use std::{sync::Arc, ptr::NonNull};
use std::{sync::Arc, ptr::NonNull, any::Any, ops::Deref};
use lyra_ecs::query::dynamic::QueryDynamicType;
use lyra_reflect::TypeRegistry;
use lyra_reflect::{TypeRegistry, ReflectWorldExt, RegisteredType};
use mlua::{AnyUserDataExt, IntoLua, IntoLuaMulti};
use crate::{ScriptWorldPtr, ScriptEntity, ScriptDynamicBundle, ScriptBorrow};
@ -159,5 +159,26 @@ impl mlua::UserData for ScriptWorldPtr {
Ok(())
});
methods.add_method_mut("resource", |lua, this, (ty,): (mlua::AnyUserData,)| {
let reflect = ty
.call_function::<_, ScriptBorrow>(FN_NAME_INTERNAL_REFLECT_TYPE, ())
.expect("Type does not implement 'reflect_type' properly");
let res = reflect.reflect_branch.as_resource_unchecked();
if let Some(res_ptr) = res.reflect_ptr(this.as_mut()) {
//.expect("Failed to find resource pointer in world!");
let reg_type = this.as_ref().get_type::<RegisteredType>(reflect.reflect_branch.reflect_type_id())
.unwrap();
let proxy = reg_type.get_data::<ReflectLuaProxy>()
.expect("Type does not have ReflectLuaProxy as a TypeData");
(proxy.fn_as_uservalue)(lua, res_ptr)
.and_then(|ud| ud.into_lua(lua))
} else {
// if the resource is not found in the world, return nil
Ok(mlua::Value::Nil)
}
});
}
}

View File

@ -0,0 +1,52 @@
use std::{ops::Deref, any::TypeId};
use lyra_game::DeltaTime;
use crate::{lyra_engine, lua::{FN_NAME_INTERNAL_REFLECT_TYPE, LuaWrapper}, ScriptBorrow};
#[derive(Clone, lyra_reflect::Reflect, Default)]
pub struct LuaDeltaTime(#[reflect(skip)] pub(crate) DeltaTime);
impl std::ops::Deref for LuaDeltaTime {
type Target = DeltaTime;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl std::ops::DerefMut for LuaDeltaTime {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl<'lua> mlua::FromLua<'lua> for LuaDeltaTime {
fn from_lua(value: mlua::prelude::LuaValue<'lua>, lua: &'lua mlua::prelude::Lua) -> mlua::prelude::LuaResult<Self> {
match value {
mlua::Value::UserData(ud) => Ok(ud.borrow::<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())
});
methods.add_meta_method(mlua::MetaMethod::ToString, |_, this, ()| {
Ok(format!("{}", this.0.deref()))
});
methods.add_function(FN_NAME_INTERNAL_REFLECT_TYPE, |_, ()| {
Ok(ScriptBorrow::from_resource::<DeltaTime>(None))
});
}
}
impl LuaWrapper for LuaDeltaTime {
fn wrapped_type_id() -> std::any::TypeId {
TypeId::of::<DeltaTime>()
}
}

View File

@ -0,0 +1,605 @@
use std::sync::Arc;
use crate::lyra_engine;
use lyra_game::math;
use lyra_scripting_derive::wrap_math_vec_copy;
use crate as lyra_scripting;
// f32 types
wrap_math_vec_copy!(
math::Vec2,
derives(PartialEq),
fields(x, y),
metamethods(
Add(LuaVec2, f32),
Sub(LuaVec2, f32),
Div(LuaVec2, f32),
Mul(LuaVec2, f32),
Mod(LuaVec2, f32),
Eq,
Unm
)
);
wrap_math_vec_copy!(
math::Vec3,
derives(PartialEq),
fields(x, y, z),
metamethods(
Add(LuaVec3),
Sub(LuaVec3, f32),
Div(LuaVec3, f32),
//Mul(LuaVec3, f32),
Mod(LuaVec3, f32),
Eq, Unm, ToString,
),
custom_methods {
methods.add_meta_method(mlua::MetaMethod::Mul, |_, this, (v,): (mlua::Value,)| {
match v {
mlua::Value::Number(n) => {
Ok(Self(this.0 * (n as f32)))
},
mlua::Value::UserData(ud) => {
if let Ok(other_this) = ud.borrow::<Self>() {
Ok(Self(this.0 * other_this.0))
} else {
if let Ok(mt) = ud.get_metatable() {
if let Ok(name) = mt.get::<String>("__name") {
return Err(mlua::Error::BadArgument {
to: Some("LuaVec3.__mul".to_string()),
pos: 2,
name: Some("rhs".to_string()),
cause: Arc::new(mlua::Error::RuntimeError(
format!("cannot multiply with unknown userdata named {}", name)
))
});
}
}
Err(mlua::Error::BadArgument {
to: Some("LuaVec3.__mul".to_string()),
pos: 2,
name: Some("rhs".to_string()),
cause: Arc::new(
mlua::Error::runtime("cannot multiply with unknown userdata")
)
})
}
},
_ => Err(mlua::Error::BadArgument {
to: Some("LuaVec3.__mul".to_string()),
pos: 2,
name: Some("rhs".to_string()),
cause: Arc::new(
mlua::Error::RuntimeError(format!("cannot multiply with {}", v.type_name()))
)
})
}
});
}
);
/* wrap_math_vec_copy!(
math::Vec3A,
derives(PartialEq),
fields(x, y, z),
metamethods(
Add(LuaVec3A, f32),
Sub(LuaVec3A, f32),
Div(LuaVec3A, f32),
Mul(LuaVec3A, f32),
Mod(LuaVec3A, f32),
Eq, Unm
)
);
wrap_math_vec_copy!(
math::Vec4,
derives(PartialEq),
fields(w, x, y, z),
metamethods(
Add(LuaVec4, f32),
Sub(LuaVec4, f32),
Div(LuaVec4, f32),
Mul(LuaVec4, f32),
Mod(LuaVec4, f32),
Eq, Unm
)
);
// f64 types
wrap_math_vec_copy!(
math::DVec2,
derives(PartialEq),
fields(x, y),
metamethods(
Add(LuaDVec2, f64),
Sub(LuaDVec2, f64),
Div(LuaDVec2, f64),
Mul(LuaDVec2, f64),
Mod(LuaDVec2, f64),
Eq, Unm
)
);
wrap_math_vec_copy!(
math::DVec3,
derives(PartialEq),
fields(x, y, z),
metamethods(
Add(LuaDVec3, f64),
Sub(LuaDVec3, f64),
Div(LuaDVec3, f64),
Mul(LuaDVec3, f64),
Mod(LuaDVec3, f64),
Eq, Unm
)
);
wrap_math_vec_copy!(
math::DVec4,
derives(PartialEq),
fields(w, x, y, z),
metamethods(
Add(LuaDVec4, f64),
Sub(LuaDVec4, f64),
Div(LuaDVec4, f64),
Mul(LuaDVec4, f64),
Mod(LuaDVec4, f64),
Eq, Unm
)
);
// i32 types
wrap_math_vec_copy!(
math::IVec2,
derives(PartialEq, Eq, Hash),
fields(x, y),
metamethods(
Add(LuaIVec2, i32),
Sub(LuaIVec2, i32),
Div(LuaIVec2, i32),
Mul(LuaIVec2, i32),
Mod(LuaIVec2, i32),
Shl(LuaIVec2, LuaUVec2, i32),
Shr(LuaIVec2, LuaUVec2, i32),
BAnd(LuaIVec2, i32),
BOr(LuaIVec2, i32),
BXor(LuaIVec2, i32),
Eq, Unm, BNot
)
);
wrap_math_vec_copy!(
math::IVec3,
derives(PartialEq, Eq, Hash),
fields(x, y, z),
metamethods(
Add(LuaIVec3, i32),
Sub(LuaIVec3, i32),
Div(LuaIVec3, i32),
Mul(LuaIVec3, i32),
Mod(LuaIVec3, i32),
Shl(LuaIVec3, LuaUVec3, i32),
Shr(LuaIVec3, LuaUVec3, i32),
BAnd(LuaIVec3, i32),
BOr(LuaIVec3, i32),
BXor(LuaIVec3, i32),
Eq, Unm, BNot
)
);
wrap_math_vec_copy!(
math::IVec4,
derives(PartialEq, Eq, Hash),
fields(w, x, y, z),
metamethods(
Add(LuaIVec4, i32),
Sub(LuaIVec4, i32),
Div(LuaIVec4, i32),
Mul(LuaIVec4, i32),
Mod(LuaIVec4, i32),
Shl(LuaIVec4, LuaUVec4, i32),
Shr(LuaIVec4, LuaUVec4, i32),
BAnd(LuaIVec4, i32),
BOr(LuaIVec4, i32),
BXor(LuaIVec4, i32),
Eq, Unm, BNot
)
);
// u32 types
wrap_math_vec_copy!(
math::UVec2,
derives(PartialEq, Eq, Hash),
fields(x, y),
metamethods(
Add(LuaUVec2, u32),
Sub(LuaUVec2, u32),
Div(LuaUVec2, u32),
Mul(LuaUVec2, u32),
Mod(LuaUVec2, u32),
Shl(LuaUVec2, LuaIVec2, i32),
Shr(LuaUVec2, LuaIVec2, i32),
BAnd(LuaUVec2, u32),
BOr(LuaUVec2, u32),
BXor(LuaUVec2, u32),
Eq, BNot
)
);
wrap_math_vec_copy!(
math::UVec3,
derives(PartialEq, Eq, Hash),
fields(x, y, z),
metamethods(
Add(LuaUVec3, u32),
Sub(LuaUVec3, u32),
Div(LuaUVec3, u32),
Mul(LuaUVec3, u32),
Mod(LuaUVec3, u32),
Shl(LuaUVec3, LuaIVec3, i32),
Shr(LuaUVec3, LuaIVec3, i32),
BAnd(LuaUVec3, u32),
BOr(LuaUVec3, u32),
BXor(LuaUVec3, u32),
Eq, BNot
)
);
wrap_math_vec_copy!(
math::UVec4,
derives(PartialEq, Eq, Hash),
fields(w, x, y, z),
metamethods(
Add(LuaUVec4, u32),
Sub(LuaUVec4, u32),
Div(LuaUVec4, u32),
Mul(LuaUVec4, u32),
Mod(LuaUVec4, u32),
Shl(LuaUVec4, LuaIVec4, i32),
Shr(LuaUVec4, LuaIVec4, i32),
BAnd(LuaUVec4, u32),
BOr(LuaUVec4, u32),
BXor(LuaUVec4, u32),
Eq, BNot
)
);
// i64 types
wrap_math_vec_copy!(
math::I64Vec2,
derives(PartialEq, Eq, Hash),
fields(x, y),
metamethods(
Add(LuaI64Vec2, i64),
Sub(LuaI64Vec2, i64),
Div(LuaI64Vec2, i64),
Mul(LuaI64Vec2, i64),
Mod(LuaI64Vec2, i64),
Shl(i64),
Shr(i64),
BAnd(LuaI64Vec2, i64),
BOr(LuaI64Vec2, i64),
BXor(LuaI64Vec2, i64),
Eq, BNot
)
);
wrap_math_vec_copy!(
math::I64Vec3,
derives(PartialEq, Eq, Hash),
fields(x, y, z),
metamethods(
Add(LuaI64Vec3, i64),
Sub(LuaI64Vec3, i64),
Div(LuaI64Vec3, i64),
Mul(LuaI64Vec3, i64),
Mod(LuaI64Vec3, i64),
Shl(i64),
Shr(i64),
BAnd(LuaI64Vec3, i64),
BOr(LuaI64Vec3, i64),
BXor(LuaI64Vec3, i64),
Eq, BNot
)
);
wrap_math_vec_copy!(
math::I64Vec4,
derives(PartialEq, Eq, Hash),
fields(w, x, y, z),
metamethods(
Add(LuaI64Vec4, i64),
Sub(LuaI64Vec4, i64),
Div(LuaI64Vec4, i64),
Mul(LuaI64Vec4, i64),
Mod(LuaI64Vec4, i64),
Shl(i64),
Shr(i64),
BAnd(LuaI64Vec4, i64),
BOr(LuaI64Vec4, i64),
BXor(LuaI64Vec4, i64),
Eq, BNot
)
);
// u64 types
wrap_math_vec_copy!(
math::U64Vec2,
derives(PartialEq, Eq, Hash),
fields(x, y),
metamethods(
Add(LuaU64Vec2, u64),
Sub(LuaU64Vec2, u64),
Div(LuaU64Vec2, u64),
Mul(LuaU64Vec2, u64),
Mod(LuaU64Vec2, u64),
Shl(i64),
Shr(i64),
BAnd(LuaU64Vec2, u64),
BOr(LuaU64Vec2, u64),
BXor(LuaU64Vec2, u64),
Eq, BNot
)
);
wrap_math_vec_copy!(
math::U64Vec3,
derives(PartialEq, Eq, Hash),
fields(x, y, z),
metamethods(
Add(LuaU64Vec3, u64),
Sub(LuaU64Vec3, u64),
Div(LuaU64Vec3, u64),
Mul(LuaU64Vec3, u64),
Mod(LuaU64Vec3, u64),
Shl(i64),
Shr(i64),
BAnd(LuaU64Vec3, u64),
BOr(LuaU64Vec3, u64),
BXor(LuaU64Vec3, u64),
Eq, BNot
)
);
wrap_math_vec_copy!(
math::U64Vec4,
derives(PartialEq, Eq, Hash),
fields(w, x, y, z),
metamethods(
Add(LuaU64Vec4, u64),
Sub(LuaU64Vec4, u64),
Div(LuaU64Vec4, u64),
Mul(LuaU64Vec4, u64),
Mod(LuaU64Vec4, u64),
Shl(i64),
Shr(i64),
BAnd(LuaU64Vec4, u64),
BOr(LuaU64Vec4, u64),
BXor(LuaU64Vec4, u64),
Eq, BNot
)
);
// bool types
wrap_math_vec_copy!(
math::BVec2,
derives(PartialEq, Eq, Hash),
fields(x, y),
metamethods(Eq, BAnd, BOr, BXor, BNot)
);
wrap_math_vec_copy!(
math::BVec3,
derives(PartialEq, Eq, Hash),
fields(x, y, z),
metamethods(Eq, BAnd, BOr, BXor, BNot)
);
wrap_math_vec_copy!(
math::BVec4,
derives(PartialEq, Eq, Hash),
fields(w, x, y, z),
metamethods(Eq, BAnd, BOr, BXor, BNot)
);
// mat2
wrap_math_vec_copy!(
math::Mat2,
derives(PartialEq),
no_new,
matrix {
col_type = LuaVec2
},
metamethods(
Eq,
Add,
Sub,
Mul(LuaMat2, f32),
Unm
)
); */
/* wrap_math_vec_copy!(
math::Mat4,
derives(PartialEq),
no_new,
matrix {
col_type = LuaVec4
},
metamethods(
Eq,
Add,
Sub,
Mul(LuaMat4, f32),
Unm
)
); */
wrap_math_vec_copy!(
math::Quat,
derives(PartialEq),
no_new,
metamethods(
Eq,
// __mul for LuaVec3 is manually implemented below since it doesn't return Self
Mul(LuaQuat, f32),
Add,
Sub,
Div(f32),
),
custom_methods {
methods.add_function("new", |_, (x, y, z, w)| {
Ok(Self(math::Quat::from_xyzw(x, y, z, w)))
});
methods.add_function("from_rotation_x", |_, (rad,)| {
let q = math::Quat::from_rotation_x(rad);
Ok(Self(q))
});
methods.add_function("from_rotation_y", |_, (rad,)| {
let q = math::Quat::from_rotation_y(rad);
Ok(Self(q))
});
methods.add_function("from_rotation_z", |_, (rad,)| {
let q = math::Quat::from_rotation_z(rad);
Ok(Self(q))
});
methods.add_method("dot", |_, this, (rhs,): (Self,)| {
Ok(this.dot(rhs.0))
});
methods.add_method("length", |_, this, ()| {
Ok(this.length())
});
methods.add_method("length_squared", |_, this, ()| {
Ok(this.length_squared())
});
methods.add_method("normalize", |_, this, ()| {
Ok(Self(this.normalize()))
});
methods.add_method("mult_quat", |_, this, (rhs,): (Self,)| {
Ok(Self(this.0 * rhs.0))
});
methods.add_method("mult_vec3", |_, this, (rhs,): (LuaVec3,)| {
Ok(LuaVec3(this.0 * rhs.0))
});
// manually implemented here since it doesn't return `Self`
methods.add_meta_method(mlua::MetaMethod::Mul, |_, this, (rhs,): (LuaVec3,)| {
Ok(LuaVec3(this.0 * rhs.0))
});
methods.add_method("lerp", |_, this, (rhs, alpha): (Self, f32)| {
Ok(Self(this.lerp(*rhs, alpha)))
});
}
);
wrap_math_vec_copy!(
math::Transform,
//derives(PartialEq),
no_new,
metamethods(ToString, Eq),
custom_fields {
fields.add_field_method_get("translation", |_, this| {
Ok(LuaVec3(this.translation))
});
fields.add_field_method_set("translation", |_, this, v: LuaVec3| {
this.translation = *v;
Ok(())
});
fields.add_field_method_get("rotation", |_, this| {
Ok(LuaQuat(this.rotation))
});
fields.add_field_method_set("rotation", |_, this, v: LuaQuat| {
this.rotation = *v;
Ok(())
});
fields.add_field_method_get("scale", |_, this| {
Ok(LuaVec3(this.scale))
});
fields.add_field_method_set("scale", |_, this, v: LuaVec3| {
this.scale = *v;
Ok(())
});
},
custom_methods {
methods.add_function("default", |_, ()| {
Ok(Self(math::Transform::default()))
});
methods.add_function("new", |_, (pos, rot, scale): (LuaVec3, LuaQuat, LuaVec3)| {
Ok(Self(math::Transform::new(*pos, *rot, *scale)))
});
methods.add_function("from_translation", |_, (pos,): (LuaVec3,)| {
Ok(Self(math::Transform::from_translation(*pos)))
});
methods.add_function("from_xyz", |_, (x, y, z)| {
Ok(Self(math::Transform::from_xyz(x, y, z)))
});
methods.add_method("forward", |_, this, ()| {
Ok(LuaVec3(this.forward()))
});
methods.add_method("left", |_, this, ()| {
Ok(LuaVec3(this.left()))
});
methods.add_method("up", |_, this, ()| {
Ok(LuaVec3(this.up()))
});
methods.add_method_mut("rotate", |_, this, (quat,): (LuaQuat,)| {
this.rotate(*quat);
Ok(())
});
methods.add_method_mut("rotate_x", |_, this, (deg,): (f32,)| {
this.rotate_x(math::Angle::Degrees(deg));
Ok(())
});
methods.add_method_mut("rotate_y", |_, this, (deg,): (f32,)| {
this.rotate_y(math::Angle::Degrees(deg));
Ok(())
});
methods.add_method_mut("rotate_z", |_, this, (deg,): (f32,)| {
this.rotate_z(math::Angle::Degrees(deg));
Ok(())
});
methods.add_method_mut("rotate_x_rad", |_, this, (rad,): (f32,)| {
this.rotate_x(math::Angle::Radians(rad));
Ok(())
});
methods.add_method_mut("rotate_y_rad", |_, this, (rad,): (f32,)| {
this.rotate_y(math::Angle::Radians(rad));
Ok(())
});
methods.add_method_mut("rotate_z_rad", |_, this, (rad,): (f32,)| {
this.rotate_z(math::Angle::Radians(rad));
Ok(())
});
methods.add_method("lerp", |_, this, (rhs, alpha): (Self, f32)| {
Ok(Self(this.lerp(*rhs, alpha)))
});
// rotate a transform
methods.add_meta_method(mlua::MetaMethod::Mul, |_, this, (quat,): (LuaQuat,)| {
let mut t = *this;
t.rotation *= *quat;
Ok(t)
});
// move a transform
methods.add_meta_method(mlua::MetaMethod::Add, |_, this, (pos,): (LuaVec3,)| {
let mut t = *this;
t.translation += *pos;
Ok(t)
});
}
);

View File

@ -1,566 +1,5 @@
use lyra_game::math;
use lyra_scripting_derive::wrap_math_vec_copy;
use crate::lyra_engine;
pub mod math;
pub use math::*;
use crate as lyra_scripting;
// f32 types
wrap_math_vec_copy!(
math::Vec2,
derives(PartialEq),
fields(x, y),
metamethods(
Add(LuaVec2, f32),
Sub(LuaVec2, f32),
Div(LuaVec2, f32),
Mul(LuaVec2, f32),
Mod(LuaVec2, f32),
Eq, Unm
)
);
wrap_math_vec_copy!(
math::Vec3,
derives(PartialEq),
fields(x, y, z),
metamethods(
Add(LuaVec3),
Sub(LuaVec3, f32),
Div(LuaVec3, f32),
Mul(LuaVec3, f32),
Mod(LuaVec3, f32),
Eq, Unm, ToString,
),
custom_methods {
/* methods.add_meta_method(mlua::MetaMethod::Add, |_, this, (trans,): (LuaTransform,)| {
println!("Adding");
let mut t = *trans;
t.translation += **this;
Ok(LuaTransform(t))
}); */
}
);
/* wrap_math_vec_copy!(
math::Vec3A,
derives(PartialEq),
fields(x, y, z),
metamethods(
Add(LuaVec3A, f32),
Sub(LuaVec3A, f32),
Div(LuaVec3A, f32),
Mul(LuaVec3A, f32),
Mod(LuaVec3A, f32),
Eq, Unm
)
);
wrap_math_vec_copy!(
math::Vec4,
derives(PartialEq),
fields(w, x, y, z),
metamethods(
Add(LuaVec4, f32),
Sub(LuaVec4, f32),
Div(LuaVec4, f32),
Mul(LuaVec4, f32),
Mod(LuaVec4, f32),
Eq, Unm
)
);
// f64 types
wrap_math_vec_copy!(
math::DVec2,
derives(PartialEq),
fields(x, y),
metamethods(
Add(LuaDVec2, f64),
Sub(LuaDVec2, f64),
Div(LuaDVec2, f64),
Mul(LuaDVec2, f64),
Mod(LuaDVec2, f64),
Eq, Unm
)
);
wrap_math_vec_copy!(
math::DVec3,
derives(PartialEq),
fields(x, y, z),
metamethods(
Add(LuaDVec3, f64),
Sub(LuaDVec3, f64),
Div(LuaDVec3, f64),
Mul(LuaDVec3, f64),
Mod(LuaDVec3, f64),
Eq, Unm
)
);
wrap_math_vec_copy!(
math::DVec4,
derives(PartialEq),
fields(w, x, y, z),
metamethods(
Add(LuaDVec4, f64),
Sub(LuaDVec4, f64),
Div(LuaDVec4, f64),
Mul(LuaDVec4, f64),
Mod(LuaDVec4, f64),
Eq, Unm
)
);
// i32 types
wrap_math_vec_copy!(
math::IVec2,
derives(PartialEq, Eq, Hash),
fields(x, y),
metamethods(
Add(LuaIVec2, i32),
Sub(LuaIVec2, i32),
Div(LuaIVec2, i32),
Mul(LuaIVec2, i32),
Mod(LuaIVec2, i32),
Shl(LuaIVec2, LuaUVec2, i32),
Shr(LuaIVec2, LuaUVec2, i32),
BAnd(LuaIVec2, i32),
BOr(LuaIVec2, i32),
BXor(LuaIVec2, i32),
Eq, Unm, BNot
)
);
wrap_math_vec_copy!(
math::IVec3,
derives(PartialEq, Eq, Hash),
fields(x, y, z),
metamethods(
Add(LuaIVec3, i32),
Sub(LuaIVec3, i32),
Div(LuaIVec3, i32),
Mul(LuaIVec3, i32),
Mod(LuaIVec3, i32),
Shl(LuaIVec3, LuaUVec3, i32),
Shr(LuaIVec3, LuaUVec3, i32),
BAnd(LuaIVec3, i32),
BOr(LuaIVec3, i32),
BXor(LuaIVec3, i32),
Eq, Unm, BNot
)
);
wrap_math_vec_copy!(
math::IVec4,
derives(PartialEq, Eq, Hash),
fields(w, x, y, z),
metamethods(
Add(LuaIVec4, i32),
Sub(LuaIVec4, i32),
Div(LuaIVec4, i32),
Mul(LuaIVec4, i32),
Mod(LuaIVec4, i32),
Shl(LuaIVec4, LuaUVec4, i32),
Shr(LuaIVec4, LuaUVec4, i32),
BAnd(LuaIVec4, i32),
BOr(LuaIVec4, i32),
BXor(LuaIVec4, i32),
Eq, Unm, BNot
)
);
// u32 types
wrap_math_vec_copy!(
math::UVec2,
derives(PartialEq, Eq, Hash),
fields(x, y),
metamethods(
Add(LuaUVec2, u32),
Sub(LuaUVec2, u32),
Div(LuaUVec2, u32),
Mul(LuaUVec2, u32),
Mod(LuaUVec2, u32),
Shl(LuaUVec2, LuaIVec2, i32),
Shr(LuaUVec2, LuaIVec2, i32),
BAnd(LuaUVec2, u32),
BOr(LuaUVec2, u32),
BXor(LuaUVec2, u32),
Eq, BNot
)
);
wrap_math_vec_copy!(
math::UVec3,
derives(PartialEq, Eq, Hash),
fields(x, y, z),
metamethods(
Add(LuaUVec3, u32),
Sub(LuaUVec3, u32),
Div(LuaUVec3, u32),
Mul(LuaUVec3, u32),
Mod(LuaUVec3, u32),
Shl(LuaUVec3, LuaIVec3, i32),
Shr(LuaUVec3, LuaIVec3, i32),
BAnd(LuaUVec3, u32),
BOr(LuaUVec3, u32),
BXor(LuaUVec3, u32),
Eq, BNot
)
);
wrap_math_vec_copy!(
math::UVec4,
derives(PartialEq, Eq, Hash),
fields(w, x, y, z),
metamethods(
Add(LuaUVec4, u32),
Sub(LuaUVec4, u32),
Div(LuaUVec4, u32),
Mul(LuaUVec4, u32),
Mod(LuaUVec4, u32),
Shl(LuaUVec4, LuaIVec4, i32),
Shr(LuaUVec4, LuaIVec4, i32),
BAnd(LuaUVec4, u32),
BOr(LuaUVec4, u32),
BXor(LuaUVec4, u32),
Eq, BNot
)
);
// i64 types
wrap_math_vec_copy!(
math::I64Vec2,
derives(PartialEq, Eq, Hash),
fields(x, y),
metamethods(
Add(LuaI64Vec2, i64),
Sub(LuaI64Vec2, i64),
Div(LuaI64Vec2, i64),
Mul(LuaI64Vec2, i64),
Mod(LuaI64Vec2, i64),
Shl(i64),
Shr(i64),
BAnd(LuaI64Vec2, i64),
BOr(LuaI64Vec2, i64),
BXor(LuaI64Vec2, i64),
Eq, BNot
)
);
wrap_math_vec_copy!(
math::I64Vec3,
derives(PartialEq, Eq, Hash),
fields(x, y, z),
metamethods(
Add(LuaI64Vec3, i64),
Sub(LuaI64Vec3, i64),
Div(LuaI64Vec3, i64),
Mul(LuaI64Vec3, i64),
Mod(LuaI64Vec3, i64),
Shl(i64),
Shr(i64),
BAnd(LuaI64Vec3, i64),
BOr(LuaI64Vec3, i64),
BXor(LuaI64Vec3, i64),
Eq, BNot
)
);
wrap_math_vec_copy!(
math::I64Vec4,
derives(PartialEq, Eq, Hash),
fields(w, x, y, z),
metamethods(
Add(LuaI64Vec4, i64),
Sub(LuaI64Vec4, i64),
Div(LuaI64Vec4, i64),
Mul(LuaI64Vec4, i64),
Mod(LuaI64Vec4, i64),
Shl(i64),
Shr(i64),
BAnd(LuaI64Vec4, i64),
BOr(LuaI64Vec4, i64),
BXor(LuaI64Vec4, i64),
Eq, BNot
)
);
// u64 types
wrap_math_vec_copy!(
math::U64Vec2,
derives(PartialEq, Eq, Hash),
fields(x, y),
metamethods(
Add(LuaU64Vec2, u64),
Sub(LuaU64Vec2, u64),
Div(LuaU64Vec2, u64),
Mul(LuaU64Vec2, u64),
Mod(LuaU64Vec2, u64),
Shl(i64),
Shr(i64),
BAnd(LuaU64Vec2, u64),
BOr(LuaU64Vec2, u64),
BXor(LuaU64Vec2, u64),
Eq, BNot
)
);
wrap_math_vec_copy!(
math::U64Vec3,
derives(PartialEq, Eq, Hash),
fields(x, y, z),
metamethods(
Add(LuaU64Vec3, u64),
Sub(LuaU64Vec3, u64),
Div(LuaU64Vec3, u64),
Mul(LuaU64Vec3, u64),
Mod(LuaU64Vec3, u64),
Shl(i64),
Shr(i64),
BAnd(LuaU64Vec3, u64),
BOr(LuaU64Vec3, u64),
BXor(LuaU64Vec3, u64),
Eq, BNot
)
);
wrap_math_vec_copy!(
math::U64Vec4,
derives(PartialEq, Eq, Hash),
fields(w, x, y, z),
metamethods(
Add(LuaU64Vec4, u64),
Sub(LuaU64Vec4, u64),
Div(LuaU64Vec4, u64),
Mul(LuaU64Vec4, u64),
Mod(LuaU64Vec4, u64),
Shl(i64),
Shr(i64),
BAnd(LuaU64Vec4, u64),
BOr(LuaU64Vec4, u64),
BXor(LuaU64Vec4, u64),
Eq, BNot
)
);
// bool types
wrap_math_vec_copy!(
math::BVec2,
derives(PartialEq, Eq, Hash),
fields(x, y),
metamethods(Eq, BAnd, BOr, BXor, BNot)
);
wrap_math_vec_copy!(
math::BVec3,
derives(PartialEq, Eq, Hash),
fields(x, y, z),
metamethods(Eq, BAnd, BOr, BXor, BNot)
);
wrap_math_vec_copy!(
math::BVec4,
derives(PartialEq, Eq, Hash),
fields(w, x, y, z),
metamethods(Eq, BAnd, BOr, BXor, BNot)
);
// mat2
wrap_math_vec_copy!(
math::Mat2,
derives(PartialEq),
no_new,
matrix {
col_type = LuaVec2
},
metamethods(
Eq,
Add,
Sub,
Mul(LuaMat2, f32),
Unm
)
); */
/* wrap_math_vec_copy!(
math::Mat4,
derives(PartialEq),
no_new,
matrix {
col_type = LuaVec4
},
metamethods(
Eq,
Add,
Sub,
Mul(LuaMat4, f32),
Unm
)
); */
wrap_math_vec_copy!(
math::Quat,
derives(PartialEq),
no_new,
metamethods(
Eq,
// __mul for LuaVec3 is manually implemented below since it doesn't return Self
Mul(LuaQuat, f32),
Add,
Sub,
Div(f32),
),
custom_methods {
methods.add_function("new", |_, (x, y, z, w)| {
Ok(Self(math::Quat::from_xyzw(x, y, z, w)))
});
methods.add_function("from_rotation_x", |_, (rad,)| {
let q = math::Quat::from_rotation_x(rad);
Ok(Self(q))
});
methods.add_function("from_rotation_y", |_, (rad,)| {
let q = math::Quat::from_rotation_y(rad);
Ok(Self(q))
});
methods.add_function("from_rotation_z", |_, (rad,)| {
let q = math::Quat::from_rotation_z(rad);
Ok(Self(q))
});
methods.add_method("dot", |_, this, (rhs,): (Self,)| {
Ok(this.dot(rhs.0))
});
methods.add_method("length", |_, this, ()| {
Ok(this.length())
});
methods.add_method("length_squared", |_, this, ()| {
Ok(this.length_squared())
});
methods.add_method("normalize", |_, this, ()| {
Ok(Self(this.normalize()))
});
methods.add_method("mult_quat", |_, this, (rhs,): (Self,)| {
Ok(Self(this.0 * rhs.0))
});
methods.add_method("mult_vec3", |_, this, (rhs,): (LuaVec3,)| {
Ok(LuaVec3(this.0 * rhs.0))
});
// manually implemented here since it doesn't return `Self`
methods.add_meta_method(mlua::MetaMethod::Mul, |_, this, (rhs,): (LuaVec3,)| {
Ok(LuaVec3(this.0 * rhs.0))
});
methods.add_method("lerp", |_, this, (rhs, alpha): (Self, f32)| {
Ok(Self(this.lerp(*rhs, alpha)))
});
}
);
wrap_math_vec_copy!(
math::Transform,
//derives(PartialEq),
no_new,
metamethods(ToString, Eq),
custom_fields {
fields.add_field_method_get("translation", |_, this| {
Ok(LuaVec3(this.translation))
});
fields.add_field_method_set("translation", |_, this, v: LuaVec3| {
this.translation = *v;
Ok(())
});
fields.add_field_method_get("rotation", |_, this| {
Ok(LuaQuat(this.rotation))
});
fields.add_field_method_set("rotation", |_, this, v: LuaQuat| {
this.rotation = *v;
Ok(())
});
fields.add_field_method_get("scale", |_, this| {
Ok(LuaVec3(this.scale))
});
fields.add_field_method_set("scale", |_, this, v: LuaVec3| {
this.scale = *v;
Ok(())
});
},
custom_methods {
methods.add_function("default", |_, ()| {
Ok(Self(math::Transform::default()))
});
methods.add_function("new", |_, (pos, rot, scale): (LuaVec3, LuaQuat, LuaVec3)| {
Ok(Self(math::Transform::new(*pos, *rot, *scale)))
});
methods.add_function("from_translation", |_, (pos,): (LuaVec3,)| {
Ok(Self(math::Transform::from_translation(*pos)))
});
methods.add_function("from_xyz", |_, (x, y, z)| {
Ok(Self(math::Transform::from_xyz(x, y, z)))
});
methods.add_method("forward", |_, this, ()| {
Ok(LuaVec3(this.forward()))
});
methods.add_method("left", |_, this, ()| {
Ok(LuaVec3(this.left()))
});
methods.add_method("up", |_, this, ()| {
Ok(LuaVec3(this.up()))
});
methods.add_method_mut("rotate", |_, this, (quat,): (LuaQuat,)| {
this.rotate(*quat);
Ok(())
});
methods.add_method_mut("rotate_x", |_, this, (deg,): (f32,)| {
this.rotate_x(math::Angle::Degrees(deg));
Ok(())
});
methods.add_method_mut("rotate_y", |_, this, (deg,): (f32,)| {
this.rotate_y(math::Angle::Degrees(deg));
Ok(())
});
methods.add_method_mut("rotate_z", |_, this, (deg,): (f32,)| {
this.rotate_z(math::Angle::Degrees(deg));
Ok(())
});
methods.add_method_mut("rotate_x_rad", |_, this, (rad,): (f32,)| {
this.rotate_x(math::Angle::Radians(rad));
Ok(())
});
methods.add_method_mut("rotate_y_rad", |_, this, (rad,): (f32,)| {
this.rotate_y(math::Angle::Radians(rad));
Ok(())
});
methods.add_method_mut("rotate_z_rad", |_, this, (rad,): (f32,)| {
this.rotate_z(math::Angle::Radians(rad));
Ok(())
});
methods.add_method("lerp", |_, this, (rhs, alpha): (Self, f32)| {
Ok(Self(this.lerp(*rhs, alpha)))
});
// rotate a transform
methods.add_meta_method(mlua::MetaMethod::Mul, |_, this, (quat,): (LuaQuat,)| {
let mut t = *this;
t.rotation *= *quat;
Ok(t)
});
// move a transform
methods.add_meta_method(mlua::MetaMethod::Add, |_, this, (pos,): (LuaVec3,)| {
let mut t = *this;
t.translation += *pos;
Ok(t)
});
}
);
pub mod delta_time;
pub use delta_time::*;