Create an early scripting engine #2

Merged
SeanOMik merged 42 commits from feature/early-scripting into main 2024-03-03 03:28:57 +00:00
10 changed files with 374 additions and 58 deletions
Showing only changes of commit e5599e1d27 - Show all commits

View File

@ -1,6 +1,6 @@
print("Hello World") print("Hello World")
function on_init() --[[ function on_init()
print("Lua script was initialized!") print("Lua script was initialized!")
end end
@ -10,16 +10,23 @@ end
function on_pre_update() function on_pre_update()
print("Lua's pre-update function was called") print("Lua's pre-update function was called")
end end ]]
function on_update() function on_update()
print("Lua's update function was called") --print("Lua's update function was called")
world:view(function (t)
print("Found entity at " .. tostring(t))
t.translation = t.translation + Vec3.new(0, 0.0008, 0)
return t
end, Transform)
end end
function on_post_update() --[[ function on_post_update()
print("Lua's post-update function was called") print("Lua's post-update function was called")
end end
function on_last() function on_last()
print("Lua's last function was called") print("Lua's last function was called")
end end ]]

View File

@ -1,6 +1,6 @@
use std::ptr::NonNull; use std::ptr::NonNull;
use lyra_engine::{math::{self, Vec3}, math::Transform, input::{KeyCode, ActionHandler, Action, ActionKind, LayoutId, ActionMapping, ActionSource, ActionMappingId, InputActionPlugin, MouseInput, MouseAxis, CommonActionLabel}, game::Game, render::{window::{CursorGrabMode, WindowOptions}, light::{PointLight, directional::DirectionalLight, SpotLight}}, change_tracker::Ct, ecs::{system::{Criteria, CriteriaSchedule, BatchedSystem, IntoSystem}, world::World, Component}, DeltaTime, scene::{TransformComponent, ModelComponent, CameraComponent}, lua::{LuaScriptingPlugin, LuaScript}, Script, ScriptList}; use lyra_engine::{math::{self, Vec3}, math::Transform, input::{KeyCode, ActionHandler, Action, ActionKind, LayoutId, ActionMapping, ActionSource, ActionMappingId, InputActionPlugin, MouseInput, MouseAxis, CommonActionLabel}, game::Game, render::{window::{CursorGrabMode, WindowOptions}, light::{PointLight, directional::DirectionalLight, SpotLight}}, change_tracker::Ct, ecs::{system::{Criteria, CriteriaSchedule, BatchedSystem, IntoSystem}, world::World, Component}, DeltaTime, scene::{ModelComponent, CameraComponent}, lua::{LuaScriptingPlugin, LuaScript}, Script, ScriptList};
use lyra_engine::assets::{ResourceManager, Model}; use lyra_engine::assets::{ResourceManager, Model};
mod free_fly_camera; mod free_fly_camera;
@ -77,9 +77,9 @@ struct CubeFlag;
async fn main() { async fn main() {
let setup_sys = |world: &mut World| -> anyhow::Result<()> { let setup_sys = |world: &mut World| -> anyhow::Result<()> {
{ {
let mut window_options = world.get_resource_mut::<Ct<WindowOptions>>(); /* let mut window_options = world.get_resource_mut::<Ct<WindowOptions>>();
window_options.cursor_grab = CursorGrabMode::Confined; window_options.cursor_grab = CursorGrabMode::Confined;
window_options.cursor_visible = false; window_options.cursor_visible = false; */
} }
let mut resman = world.get_resource_mut::<ResourceManager>(); let mut resman = world.get_resource_mut::<ResourceManager>();
@ -92,14 +92,14 @@ async fn main() {
world.spawn(( world.spawn((
ModelComponent(antique_camera_model), ModelComponent(antique_camera_model),
TransformComponent::from(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);
//cube_tran.rotate_y(math::Angle::Degrees(180.0)); //cube_tran.rotate_y(math::Angle::Degrees(180.0));
world.spawn(( world.spawn((
TransformComponent::from(cube_tran), cube_tran,
ModelComponent(crate_model.clone()), ModelComponent(crate_model.clone()),
CubeFlag, CubeFlag,
)); ));
@ -117,7 +117,7 @@ async fn main() {
diffuse: 1.0, diffuse: 1.0,
specular: 1.3, specular: 1.3,
}, },
TransformComponent::from(light_tran), light_tran,
ModelComponent(cube_model.clone()), ModelComponent(cube_model.clone()),
)); ));
} }
@ -139,7 +139,7 @@ async fn main() {
diffuse: 7.0, diffuse: 7.0,
specular: 1.0, specular: 1.0,
}, },
TransformComponent::from(light_tran), Transform::from(light_tran),
ModelComponent(cube_model.clone()), ModelComponent(cube_model.clone()),
)); ));
} }
@ -183,7 +183,7 @@ async fn main() {
diffuse: 1.0, diffuse: 1.0,
specular: 1.3, specular: 1.3,
}, },
TransformComponent::from(light_tran), Transform::from(light_tran),
ModelComponent(cube_model), ModelComponent(cube_model),
)); ));
} }
@ -214,13 +214,13 @@ async fn main() {
const SPEED: f32 = 4.0; const SPEED: f32 = 4.0;
let delta_time = **world.get_resource::<DeltaTime>(); let delta_time = **world.get_resource::<DeltaTime>();
for (mut transform, _) in world.view_iter::<(&mut TransformComponent, &CubeFlag)>() { for (mut transform, _) in world.view_iter::<(&mut Transform, &CubeFlag)>() {
let t = &mut transform.transform; let t = &mut transform;
t.rotate_y(math::Angle::Degrees(SPEED * delta_time)); t.rotate_y(math::Angle::Degrees(SPEED * delta_time));
} }
for (mut transform, _s) in world.view_iter::<(&mut TransformComponent, &mut SpotLight)>() { for (mut transform, _s) in world.view_iter::<(&mut Transform, &mut SpotLight)>() {
let t = &mut transform.transform; let t = &mut transform;
t.rotate_x(math::Angle::Degrees(SPEED * delta_time)); t.rotate_x(math::Angle::Degrees(SPEED * delta_time));
} }
@ -235,8 +235,8 @@ async fn main() {
sys.with_system(spin_system.into_system()); sys.with_system(spin_system.into_system());
//sys.with_system(fps_system); //sys.with_system(fps_system);
game.with_system("fixed", sys, &[]); //game.with_system("fixed", sys, &[]);
fps_plugin(game); //fps_plugin(game);
}; };
let action_handler_plugin = |game: &mut Game| { let action_handler_plugin = |game: &mut Game| {
@ -293,7 +293,9 @@ async fn main() {
Ok(()) Ok(())
}; */ }; */
game.world().add_resource(action_handler); let world = game.world();
world.add_resource(action_handler);
world.spawn((Vec3::new(0.5, 0.1, 3.0),));
game.with_plugin(InputActionPlugin); game.with_plugin(InputActionPlugin);
//game.with_system("input_test", test_system, &[]); //game.with_system("input_test", test_system, &[]);
}; };

View File

@ -210,6 +210,8 @@ impl ArchetypeId {
pub struct Archetype { pub struct Archetype {
pub id: ArchetypeId, pub id: ArchetypeId,
pub(crate) entities: HashMap<Entity, ArchetypeEntityId>, pub(crate) entities: HashMap<Entity, ArchetypeEntityId>,
/// map an Archetype entity id to an entity
pub(crate) ids_to_entity: HashMap<ArchetypeEntityId, Entity>,
pub(crate) columns: Vec<ComponentColumn>, pub(crate) columns: Vec<ComponentColumn>,
pub capacity: usize, pub capacity: usize,
} }
@ -226,6 +228,7 @@ impl Archetype {
Archetype { Archetype {
id: new_id, id: new_id,
entities: HashMap::new(), entities: HashMap::new(),
ids_to_entity: HashMap::new(),
columns, columns,
capacity: DEFAULT_CAPACITY, capacity: DEFAULT_CAPACITY,
} }
@ -246,16 +249,17 @@ impl Archetype {
self.capacity = new_cap; self.capacity = new_cap;
} }
let entity_index = self.entities.len(); let entity_index = ArchetypeEntityId(self.entities.len() as u64);
self.entities.insert(entity, ArchetypeEntityId(entity_index as u64)); self.entities.insert(entity, entity_index);
self.ids_to_entity.insert(entity_index, entity);
bundle.take(|data, type_id, _size| { bundle.take(|data, type_id, _size| {
let col = self.get_column_mut(type_id).unwrap(); let col = self.get_column_mut(type_id).unwrap();
unsafe { col.set_at(entity_index, data, *tick); } unsafe { col.set_at(entity_index.0 as usize, data, *tick); }
col.len += 1; col.len += 1;
}); });
ArchetypeEntityId(entity_index as u64) entity_index
} }
/// Removes an entity from the Archetype and frees its components. Returns the entity record that took its place in the component column. /// Removes an entity from the Archetype and frees its components. Returns the entity record that took its place in the component column.
@ -286,6 +290,7 @@ impl Archetype {
// safe from the .expect at the start of this method. // safe from the .expect at the start of this method.
self.entities.remove(&entity).unwrap(); self.entities.remove(&entity).unwrap();
self.ids_to_entity.remove(&entity_index).unwrap();
// now change the ArchetypeEntityId to be the index that the moved entity was moved into. // now change the ArchetypeEntityId to be the index that the moved entity was moved into.
removed_entity.map(|(e, _a)| (e, entity_index)) removed_entity.map(|(e, _a)| (e, entity_index))
@ -351,14 +356,15 @@ impl Archetype {
self.capacity = new_cap; self.capacity = new_cap;
} }
let entity_index = self.entities.len(); let entity_index = ArchetypeEntityId(self.entities.len() as u64);
self.entities.insert(entity, ArchetypeEntityId(entity_index as u64)); self.entities.insert(entity, entity_index);
self.ids_to_entity.insert(entity_index, entity);
for col in self.columns.iter_mut() { for col in self.columns.iter_mut() {
col.len += 1; col.len += 1;
} }
ArchetypeEntityId(entity_index as u64) entity_index
} }
/// Moves the entity from this archetype into another one. /// Moves the entity from this archetype into another one.
@ -401,6 +407,10 @@ impl Archetype {
pub fn entities(&self) -> &HashMap<Entity, ArchetypeEntityId> { pub fn entities(&self) -> &HashMap<Entity, ArchetypeEntityId> {
&self.entities &self.entities
} }
pub fn entity_of_index(&self, id: ArchetypeEntityId) -> Option<Entity> {
self.ids_to_entity.get(&id).cloned()
}
} }
#[cfg(test)] #[cfg(test)]

View File

@ -209,6 +209,16 @@ impl World {
current_arch.remove_entity(entity, &tick); current_arch.remove_entity(entity, &tick);
} }
pub fn entity_archetype(&self, entity: Entity) -> Option<&Archetype> {
self.entity_index.get(&entity.id)
.and_then(|record| self.archetypes.get(&record.id))
}
pub fn entity_archetype_mut(&mut self, entity: Entity) -> Option<&mut Archetype> {
self.entity_index.get_mut(&entity.id)
.and_then(|record| self.archetypes.get_mut(&record.id))
}
/// View into the world for a set of entities that satisfy the queries. /// View into the world for a set of entities that satisfy the queries.
pub fn view_iter<T: 'static + AsQuery>(&self) -> ViewIter<T::Query> { pub fn view_iter<T: 'static + AsQuery>(&self) -> ViewIter<T::Query> {
let archetypes = self.archetypes.values().collect(); let archetypes = self.archetypes.values().collect();

View File

@ -21,6 +21,7 @@ tracing = "0.1.37"
# enabled with lua feature # enabled with lua feature
mlua = { version = "0.9.2", features = ["lua54"], optional = true } # luajit maybe? mlua = { version = "0.9.2", features = ["lua54"], optional = true } # luajit maybe?
itertools = "0.12.0"
[dev-dependencies] [dev-dependencies]

View File

@ -220,6 +220,9 @@ pub(crate) struct WrapUsage {
pub matrix: Option<MatWrapper>, pub matrix: Option<MatWrapper>,
pub vec: Option<VecWrapper>, pub vec: Option<VecWrapper>,
pub custom_methods: Option<syn::Block>,
pub custom_fields: Option<syn::Block>,
} }
impl syn::parse::Parse for WrapUsage { impl syn::parse::Parse for WrapUsage {
@ -234,6 +237,8 @@ impl syn::parse::Parse for WrapUsage {
meta_method_idents: Punctuated::default(), meta_method_idents: Punctuated::default(),
matrix: None, matrix: None,
vec: None, vec: None,
custom_methods: None,
custom_fields: None,
}; };
/* let mut derive_idents = None; /* let mut derive_idents = None;
let mut field_idents = None; let mut field_idents = None;
@ -298,6 +303,14 @@ impl syn::parse::Parse for WrapUsage {
s.meta_method_idents = meta_methods; s.meta_method_idents = meta_methods;
} }
}, },
"custom_methods" => {
let methods_block = input.parse()?;
s.custom_methods = Some(methods_block);
},
"custom_fields" => {
let block = input.parse()?;
s.custom_fields = Some(block);
}
_ => { _ => {
return Err(syn::Error::new_spanned(ident, "unknown wrapper command")); return Err(syn::Error::new_spanned(ident, "unknown wrapper command"));
} }
@ -335,6 +348,8 @@ pub fn wrap_math_vec_copy(input: proc_macro::TokenStream) -> proc_macro::TokenSt
vec.to_method_tokens(&path, &wrapper_typename)); vec.to_method_tokens(&path, &wrapper_typename));
let derive_idents_iter = input.derive_idents.iter(); let derive_idents_iter = input.derive_idents.iter();
let custom_methods = input.custom_methods;
let custom_fields = input.custom_fields;
let field_get_set_pairs = input.field_idents.iter().map(|i| { let field_get_set_pairs = input.field_idents.iter().map(|i| {
let is = i.to_string(); let is = i.to_string();
@ -566,7 +581,7 @@ pub fn wrap_math_vec_copy(input: proc_macro::TokenStream) -> proc_macro::TokenSt
fn from_lua(value: mlua::Value<'lua>, _lua: &'lua mlua::Lua) -> mlua::Result<Self> { fn from_lua(value: mlua::Value<'lua>, _lua: &'lua mlua::Lua) -> mlua::Result<Self> {
match value { match value {
mlua::Value::UserData(ud) => Ok(*ud.borrow::<Self>()?), mlua::Value::UserData(ud) => Ok(*ud.borrow::<Self>()?),
_ => unreachable!(), _ => panic!("Attempt to get {} from a {} value", stringify!(#wrapper_typename), value.type_name()),
} }
} }
} }
@ -577,6 +592,8 @@ pub fn wrap_math_vec_copy(input: proc_macro::TokenStream) -> proc_macro::TokenSt
#matrix_wrapper_fields #matrix_wrapper_fields
#vec_wrapper_fields #vec_wrapper_fields
#custom_fields
} }
fn add_methods<'lua, M: mlua::prelude::LuaUserDataMethods<'lua, Self>>(methods: &mut M) { fn add_methods<'lua, M: mlua::prelude::LuaUserDataMethods<'lua, Self>>(methods: &mut M) {
@ -594,12 +611,16 @@ pub fn wrap_math_vec_copy(input: proc_macro::TokenStream) -> proc_macro::TokenSt
#matrix_wrapper_methods #matrix_wrapper_methods
#vec_wrapper_methods #vec_wrapper_methods
#custom_methods
} }
} }
impl lyra_scripting::lua::LuaWrapper for #wrapper_typename { impl lyra_scripting::lua::LuaWrapper for #wrapper_typename {
fn wrapped_type_id() -> std::any::TypeId { fn wrapped_type_id() -> std::any::TypeId {
std::any::TypeId::of::<#path>() let t = std::any::TypeId::of::<#path>();
println!("Got id of {}, it is {:?}", stringify!(#path), t);
t
} }
} }
}) })

View File

@ -1,6 +1,6 @@
use std::{ptr::NonNull, ops::{Range, Deref}}; use std::{ptr::NonNull, ops::{Range, Deref}};
use lyra_ecs::{ComponentColumn, ComponentInfo, Archetype, ArchetypeId, ArchetypeEntityId, query::dynamic::{DynamicType, QueryDynamicType}, query::Fetch}; use lyra_ecs::{ComponentColumn, ComponentInfo, Archetype, ArchetypeId, ArchetypeEntityId, query::dynamic::{DynamicType, QueryDynamicType}, query::Fetch, Entity};
use lyra_reflect::TypeRegistry; use lyra_reflect::TypeRegistry;
#[cfg(feature = "lua")] #[cfg(feature = "lua")]
@ -45,6 +45,11 @@ impl<'a> From<lyra_ecs::query::dynamic::FetchDynamicType<'a>> for FetchDynamicTy
} }
} }
pub struct DynamicViewRow {
entity: Entity,
item: Vec<DynamicType>,
}
#[derive(Clone)] #[derive(Clone)]
pub struct DynamicViewIter { pub struct DynamicViewIter {
world_ptr: ScriptWorldPtr, world_ptr: ScriptWorldPtr,
@ -69,15 +74,15 @@ impl<'a> From<lyra_ecs::query::dynamic::DynamicViewIter<'a>> for DynamicViewIter
} }
impl Iterator for DynamicViewIter { impl Iterator for DynamicViewIter {
type Item = Vec<DynamicType>; type Item = DynamicViewRow;
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
loop { loop {
if let Some(entity_index) = self.component_indices.next() { if let Some(entity_index) = self.component_indices.next() {
let mut fetch_res = vec![]; let mut fetch_res = vec![];
let entity_index = ArchetypeEntityId(entity_index);
for fetcher in self.fetchers.iter_mut() { for fetcher in self.fetchers.iter_mut() {
let entity_index = ArchetypeEntityId(entity_index);
if !fetcher.can_visit_item(entity_index) { if !fetcher.can_visit_item(entity_index) {
break; break;
} else { } else {
@ -90,7 +95,14 @@ impl Iterator for DynamicViewIter {
continue; continue;
} }
return Some(fetch_res); let arch = unsafe { self.archetypes.get_unchecked(self.next_archetype - 1).as_ref() };
let entity = arch.entity_of_index(entity_index).unwrap();
let row = DynamicViewRow {
entity,
item: fetch_res,
};
return Some(row);
} else { } else {
if self.next_archetype >= self.archetypes.len() { if self.next_archetype >= self.archetypes.len() {
return None; // ran out of archetypes to go through return None; // ran out of archetypes to go through
@ -121,6 +133,19 @@ impl Iterator for DynamicViewIter {
} }
} }
#[cfg(feature = "lua")]
pub struct ReflectedItem<'a> {
pub proxy: &'a ReflectLuaProxy,
pub comp_ptr: NonNull<u8>,
pub comp_ud: mlua::AnyUserData<'a>,
}
#[cfg(feature = "lua")]
pub struct ReflectedRow<'a> {
pub entity: Entity,
pub row: Vec<ReflectedItem<'a>>,
}
pub struct ReflectedIterator { pub struct ReflectedIterator {
pub world: ScriptWorldPtr, pub world: ScriptWorldPtr,
pub dyn_view: DynamicViewIter, pub dyn_view: DynamicViewIter,
@ -131,7 +156,7 @@ impl ReflectedIterator {
#[cfg(feature = "lua")] #[cfg(feature = "lua")]
pub fn next_lua<'a>(&mut self, lua: &'a mlua::Lua) -> Option<Vec<( (&'a ReflectLuaProxy, NonNull<u8>), mlua::AnyUserData<'a>)>> { pub fn next_lua<'a>(&mut self, lua: &'a mlua::Lua) -> Option<ReflectedRow<'a>> {
let n = self.dyn_view.next(); let n = self.dyn_view.next();
@ -142,8 +167,13 @@ impl ReflectedIterator {
.map(|r| NonNull::from(r.deref())); .map(|r| NonNull::from(r.deref()));
} }
let mut dynamic_row = Vec::new(); /* let mut row = ReflectedRow {
for d in row.iter() { entity: row.entity,
row: row.item,
}; */
let mut dynamic_row = vec![];
for d in row.item.iter() {
let id = d.info.type_id.as_rust(); let id = d.info.type_id.as_rust();
let reflected_components = let reflected_components =
unsafe { self.reflected_components.as_ref().unwrap().as_ref() }; unsafe { self.reflected_components.as_ref().unwrap().as_ref() };
@ -155,10 +185,20 @@ impl ReflectedIterator {
let userdata = (proxy.fn_as_uservalue)(lua, d.ptr).unwrap(); let userdata = (proxy.fn_as_uservalue)(lua, d.ptr).unwrap();
dynamic_row.push(( (proxy, d.ptr), userdata)); dynamic_row.push(ReflectedItem {
proxy,
comp_ptr: d.ptr,
comp_ud: userdata
});
//dynamic_row.push(( (proxy, d.ptr), userdata));
} }
Some(dynamic_row) let row = ReflectedRow {
entity: row.entity,
row: dynamic_row
};
Some(row)
} else { } else {
None None
} }

View File

@ -1,7 +1,7 @@
use lyra_ecs::World; use lyra_ecs::World;
use lyra_game::math; use lyra_game::math;
use crate::lua::RegisterLuaType; use crate::lua::RegisterLuaType;
use crate::lua::wrappers::LuaVec3; use crate::lua::wrappers::{LuaVec3, LuaTransform};
use crate::{ScriptApiProvider, lua::LuaContext}; use crate::{ScriptApiProvider, lua::LuaContext};
@ -13,6 +13,7 @@ impl ScriptApiProvider for LyraMathApiProvider {
fn prepare_world(&mut self, world: &mut World) { fn prepare_world(&mut self, world: &mut World) {
world.register_lua_wrapper::<LuaVec3>(); world.register_lua_wrapper::<LuaVec3>();
world.register_lua_wrapper::<LuaTransform>();
} }
fn expose_api(&mut self, ctx: &mut Self::ScriptContext) -> Result<(), crate::ScriptError> { fn expose_api(&mut self, ctx: &mut Self::ScriptContext) -> Result<(), crate::ScriptError> {
@ -29,6 +30,7 @@ impl ScriptApiProvider for LyraMathApiProvider {
let globals = ctx.globals(); let globals = ctx.globals();
globals.set("Vec3", ctx.create_proxy::<LuaVec3>()?)?; globals.set("Vec3", ctx.create_proxy::<LuaVec3>()?)?;
globals.set("Transform", ctx.create_proxy::<LuaTransform>()?)?;
//globals.set("Vec3", LuaVec3(math::Vec3::ZERO).into_lua(&ctx)?)?; //globals.set("Vec3", LuaVec3(math::Vec3::ZERO).into_lua(&ctx)?)?;
Ok(()) Ok(())

View File

@ -1,4 +1,4 @@
use std::sync::Arc; use std::{sync::Arc, ptr::NonNull};
use lyra_ecs::query::dynamic::QueryDynamicType; use lyra_ecs::query::dynamic::QueryDynamicType;
use lyra_reflect::TypeRegistry; use lyra_reflect::TypeRegistry;
@ -62,7 +62,7 @@ impl mlua::UserData for ScriptWorldPtr {
let f = lua.create_function_mut(move |lua, ()| { let f = lua.create_function_mut(move |lua, ()| {
if let Some(row) = reflected_iter.next_lua(lua) { if let Some(row) = reflected_iter.next_lua(lua) {
let row = row.into_iter().map(|(_, ud)| ud.into_lua(lua)) let row = row.row.into_iter().map(|i| i.comp_ud.into_lua(lua))
.collect::<mlua::Result<Vec<mlua::Value>>>()?; .collect::<mlua::Result<Vec<mlua::Value>>>()?;
Ok(mlua::MultiValue::from_vec(row)) Ok(mlua::MultiValue::from_vec(row))
} else { } else {
@ -73,7 +73,7 @@ impl mlua::UserData for ScriptWorldPtr {
Ok(f) Ok(f)
}); });
methods.add_method("view", |lua, this, (system, queries): (mlua::Function, mlua::Variadic<mlua::AnyUserData>)| { 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(mlua::Error::BadArgument { to: Some("world:view".to_string()), pos: 2, name: Some("...".to_string()), cause:
Arc::new(mlua::Error::external(WorldError::LuaInvalidUsage("no component types provided".to_string()))) Arc::new(mlua::Error::external(WorldError::LuaInvalidUsage("no component types provided".to_string())))
@ -99,29 +99,51 @@ impl mlua::UserData for ScriptWorldPtr {
reflected_components: None, reflected_components: None,
}; };
let reg = this.as_ref().get_resource::<TypeRegistry>(); let mut current = world.current_tick();
let mut has_ticked = false;
while let Some(row) = reflected_iter.next_lua(lua) { while let Some(row) = reflected_iter.next_lua(lua) {
let (reflects, values): (Vec<(_, _)>, Vec<_>) = row.into_iter().unzip();
let r = row.row.into_iter()
.map(|r| (r.proxy, r.comp_ud, r.comp_ptr))
.collect::<Vec<_>>();
let (reflects, values, ptrs):
(Vec<&ReflectLuaProxy>, Vec<mlua::AnyUserData>, Vec<NonNull<u8>>)
= itertools::multiunzip(r);
let value_row: Vec<_> = values.into_iter().map(|ud| ud.into_lua(lua)).collect::<mlua::Result<Vec<mlua::Value>>>()?; let 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 mult_val = mlua::MultiValue::from_vec(value_row);
let res: mlua::MultiValue = system.call(mult_val)?; 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() <= reflects.len() {
// we only want to tick one time per system
if !has_ticked {
current = world.tick();
has_ticked = true;
}
for (i, comp) in res.into_iter().enumerate() { for (i, comp) in res.into_iter().enumerate() {
let (_proxy, ptr) = reflects[i]; let ptr = ptrs[i];
match comp.as_userdata() { match comp.as_userdata() {
Some(ud) => { Some(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();
// 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(refl_comp.type_id.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(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>().unwrap();
(proxy.fn_apply)(lua, ptr, ud)? (proxy.fn_apply)(lua, ptr, ud)?;
} }
None => { None => {
panic!("A userdata value was not returned!"); panic!("A userdata value was not returned!");

View File

@ -5,7 +5,7 @@ use crate::lyra_engine;
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),
@ -17,23 +17,27 @@ use crate as lyra_scripting;
Mod(LuaVec2, f32), Mod(LuaVec2, f32),
Eq, Unm Eq, Unm
) )
); */ );
wrap_math_vec_copy!( wrap_math_vec_copy!(
math::Vec3, math::Vec3,
derives(PartialEq), derives(PartialEq),
fields(x, y, z), fields(x, y, z),
metamethods( metamethods(
ToString, Add(LuaVec3),
Eq, Unm
)
/* metamethods(
Add(LuaVec3, f32),
Sub(LuaVec3, f32), Sub(LuaVec3, f32),
Div(LuaVec3, f32), Div(LuaVec3, f32),
Mul(LuaVec3, f32), Mul(LuaVec3, f32),
Mod(LuaVec3, f32), Mod(LuaVec3, f32),
Eq, Unm 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!( /* wrap_math_vec_copy!(
math::Vec3A, math::Vec3A,
@ -363,3 +367,200 @@ wrap_math_vec_copy!(
Unm 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)
});
}
);