lua: start using LuaQueryResult in all lua ecs queries

This commit is contained in:
SeanOMik 2024-10-29 09:10:14 -04:00
parent 7c2efe3c6f
commit f2ff2a9855
Signed by: SeanOMik
GPG Key ID: FEC9E2FC15235964
6 changed files with 89 additions and 67 deletions

View File

@ -6,6 +6,8 @@ use crate::{
ReflectBranch, ScriptEntity, ScriptWorldPtr, ReflectBranch, ScriptEntity, ScriptWorldPtr,
}; };
use super::LuaQueryResult;
#[derive(Clone)] #[derive(Clone)]
pub struct LuaChangedQuery(LuaComponent); pub struct LuaChangedQuery(LuaComponent);
@ -38,13 +40,13 @@ impl mlua::UserData for LuaChangedQuery {
match &reflect.reflect_branch { match &reflect.reflect_branch {
ReflectBranch::Component(comp) => { ReflectBranch::Component(comp) => {
if !comp.reflect_is_changed(&world, *en).unwrap_or(false) { if !comp.reflect_is_changed(&world, *en).unwrap_or(false) {
return Ok(mlua::Value::Boolean(false)); return Ok(LuaQueryResult::FilterDeny);
} }
// get the pointer of the component in the archetype column. // get the pointer of the component in the archetype column.
let arch = match world.entity_archetype(*en) { let arch = match world.entity_archetype(*en) {
Some(a) => a, Some(a) => a,
None => return Ok(mlua::Value::Boolean(false)) None => return Ok(LuaQueryResult::FilterDeny),
}; };
let arch_idx = *arch.entity_indexes().get(&en).unwrap(); let arch_idx = *arch.entity_indexes().get(&en).unwrap();
@ -52,7 +54,7 @@ impl mlua::UserData for LuaChangedQuery {
Some(col) => col, Some(col) => col,
None => { None => {
// the entity doesn't have the component // the entity doesn't have the component
return Ok(mlua::Value::Boolean(false)); return Ok(LuaQueryResult::FilterDeny);
} }
}; };
@ -67,17 +69,17 @@ impl mlua::UserData for LuaChangedQuery {
// this should actually be safe since the ReflectedIterator // this should actually be safe since the ReflectedIterator
// attempts to get the type data before it is tried here // attempts to get the type data before it is tried here
.expect("Type does not have ReflectLuaProxy as a TypeData"); .expect("Type does not have ReflectLuaProxy as a TypeData");
proxy.as_lua(lua, col_ptr) Ok(LuaQueryResult::Some(proxy.as_lua(lua, col_ptr)?))
} }
ReflectBranch::Resource(res) => { ReflectBranch::Resource(res) => {
// Check if the resource was changed. Per API spec, must return false. // Check if the resource was changed. Per API spec, must return false.
match res.reflect_is_changed(&world) { match res.reflect_is_changed(&world) {
Some(false) => { Some(false) => {
return Ok(mlua::Value::Boolean(false)); return Ok(LuaQueryResult::FilterDeny);
} }
None => { None => {
// the resource was not found // the resource was not found
return Ok(mlua::Value::Nil); return Ok(LuaQueryResult::AlwaysNone);
} }
_ => {} _ => {}
} }
@ -92,7 +94,11 @@ impl mlua::UserData for LuaChangedQuery {
.get_data::<ReflectLuaProxy>() .get_data::<ReflectLuaProxy>()
.expect("Type does not have ReflectLuaProxy as a TypeData"); .expect("Type does not have ReflectLuaProxy as a TypeData");
proxy.as_lua(lua, res_ptr.cast()).and_then(|ud| ud.into_lua(lua)) Ok(LuaQueryResult::Some(
proxy
.as_lua(lua, res_ptr.cast())
.and_then(|ud| ud.into_lua(lua))?,
))
} }
} }
}, },

View File

@ -3,6 +3,8 @@ use crate::{
ScriptEntity, ScriptWorldPtr, ScriptEntity, ScriptWorldPtr,
}; };
use super::LuaQueryResult;
#[derive(Clone)] #[derive(Clone)]
pub struct LuaHasQuery(LuaComponent); pub struct LuaHasQuery(LuaComponent);
@ -43,11 +45,15 @@ impl mlua::UserData for LuaHasQuery {
// try to find the entity's archetype and the component column in the archetype // try to find the entity's archetype and the component column in the archetype
let arch = match world.entity_archetype(*en) { let arch = match world.entity_archetype(*en) {
Some(a) => a, Some(a) => a,
None => return Ok(false), None => return Ok(LuaQueryResult::FilterDeny)
}; };
let component_col = arch.get_column(tyid); let component_col = arch.get_column(tyid);
Ok(component_col.is_some()) if component_col.is_some() {
Ok(LuaQueryResult::FilterPass)
} else {
Ok(LuaQueryResult::FilterDeny)
}
}, },
); );
} }

View File

@ -43,7 +43,7 @@ impl LuaQuery {
&self, &self,
world: ScriptWorldPtr, world: ScriptWorldPtr,
entity: Entity, entity: Entity,
) -> mlua::Result<mlua::Value> { ) -> mlua::Result<LuaQueryResult> {
let lua_en = ScriptEntity(entity); let lua_en = ScriptEntity(entity);
match &self.0 { match &self.0 {
QueryInner::Component(comp) => { QueryInner::Component(comp) => {
@ -158,7 +158,7 @@ impl mlua::FromLua for LuaQueryResult {
"always_none" => Ok(Self::AlwaysNone), "always_none" => Ok(Self::AlwaysNone),
"filter_pass" => Ok(Self::FilterPass), "filter_pass" => Ok(Self::FilterPass),
"filter_deny" => Ok(Self::FilterDeny), "filter_deny" => Ok(Self::FilterDeny),
"value" => { "some" => {
let val: mlua::Value = table let val: mlua::Value = table
.get("val") .get("val")
.map_err(|_| malformed_table_error_query_result(ty, "val"))?; .map_err(|_| malformed_table_error_query_result(ty, "val"))?;

View File

@ -3,7 +3,7 @@ use crate::{
ScriptEntity, ScriptWorldPtr, ScriptEntity, ScriptWorldPtr,
}; };
use super::LuaQuery; use super::{LuaQuery, LuaQueryResult};
#[derive(Clone)] #[derive(Clone)]
pub struct LuaNotQuery(LuaQuery); pub struct LuaNotQuery(LuaQuery);
@ -34,12 +34,12 @@ impl mlua::UserData for LuaNotQuery {
|_, this, (world, en): (ScriptWorldPtr, ScriptEntity)| { |_, this, (world, en): (ScriptWorldPtr, ScriptEntity)| {
let res = this.0.get_query_result(world, en.0)?; let res = this.0.get_query_result(world, en.0)?;
if let Some(res_bool) = res.as_boolean() { match res {
Ok(!res_bool) LuaQueryResult::None => Ok(LuaQueryResult::FilterPass),
} else if res.is_nil() { super::LuaQueryResult::AlwaysNone => Ok(LuaQueryResult::FilterPass),
Ok(true) super::LuaQueryResult::FilterPass => Ok(LuaQueryResult::FilterDeny),
} else { super::LuaQueryResult::FilterDeny => Ok(LuaQueryResult::FilterPass),
Ok(false) super::LuaQueryResult::Some(_) => Ok(LuaQueryResult::FilterDeny),
} }
}, },
); );

View File

@ -2,9 +2,12 @@ use lyra_reflect::{ReflectWorldExt, RegisteredType};
use mlua::IntoLua; use mlua::IntoLua;
use crate::{ use crate::{
lua::{LuaComponent, ReflectLuaProxy, FN_NAME_INTERNAL_ECS_QUERY_RESULT}, ScriptEntity, ScriptWorldPtr lua::{LuaComponent, ReflectLuaProxy, FN_NAME_INTERNAL_ECS_QUERY_RESULT},
ScriptEntity, ScriptWorldPtr,
}; };
use super::LuaQueryResult;
#[derive(Clone)] #[derive(Clone)]
pub struct LuaResQuery { pub struct LuaResQuery {
ty: LuaComponent, ty: LuaComponent,
@ -27,30 +30,34 @@ impl mlua::FromLua for LuaResQuery {
impl mlua::UserData for LuaResQuery { impl mlua::UserData for LuaResQuery {
fn add_methods<M: mlua::UserDataMethods<Self>>(methods: &mut M) { fn add_methods<M: mlua::UserDataMethods<Self>>(methods: &mut M) {
methods.add_function("new", |_, comp: LuaComponent| { methods.add_function("new", |_, comp: LuaComponent| Ok(Self { ty: comp }));
Ok(Self {
ty: comp
})
});
methods.add_method(FN_NAME_INTERNAL_ECS_QUERY_RESULT, |lua, this, (world, _): (ScriptWorldPtr, ScriptEntity)| { methods.add_method(
let mut world = world.write(); FN_NAME_INTERNAL_ECS_QUERY_RESULT,
let reflect = this.ty.reflect_type()?; |lua, this, (world, _): (ScriptWorldPtr, ScriptEntity)| {
let mut world = world.write();
let reflect = this.ty.reflect_type()?;
let res = reflect.reflect_branch.as_resource_unchecked(); let res = reflect.reflect_branch.as_resource_unchecked();
if let Some(res_ptr) = res.reflect_ptr(&mut world) { if let Some(res_ptr) = res.reflect_ptr(&mut world) {
let reg_type = world let reg_type = world
.get_type::<RegisteredType>(reflect.reflect_branch.reflect_type_id()) .get_type::<RegisteredType>(reflect.reflect_branch.reflect_type_id())
.expect("Resource is not type registered!"); .expect("Resource is not type registered!");
let proxy = reg_type let proxy = reg_type
.get_data::<ReflectLuaProxy>() .get_data::<ReflectLuaProxy>()
.expect("Type does not have ReflectLuaProxy as a TypeData"); .expect("Type does not have ReflectLuaProxy as a TypeData");
proxy.as_lua(lua, res_ptr.cast()).and_then(|ud| ud.into_lua(lua)) Ok(LuaQueryResult::Some(
} else { proxy
// if the resource is not found in the world, return nil .as_lua(lua, res_ptr.cast())
Ok(mlua::Value::Nil) .and_then(|ud| ud.into_lua(lua))?,
} ))
}); } else {
// if the resource is not found in the world, return nil
//Ok(mlua::Value::Nil)
Ok(LuaQueryResult::AlwaysNone)
}
},
);
} }
} }

View File

@ -15,7 +15,7 @@ use crate::{
ScriptBorrow, ScriptWorldPtr, ScriptBorrow, ScriptWorldPtr,
}; };
use super::query::LuaQuery; use super::query::{LuaQuery, LuaQueryResult};
#[derive(Clone)] #[derive(Clone)]
enum ViewQueryItem { enum ViewQueryItem {
@ -104,10 +104,12 @@ impl mlua::UserData for View {
} }
} }
enum QueryResult { #[derive(Debug, Clone)]
enum QueryRowResult {
None, None,
AlwaysNone, AlwaysNone,
Some(Vec<(mlua::Value, u32)>) FilterDeny,
Some(Vec<(mlua::Value, u32)>),
} }
#[derive(Clone)] #[derive(Clone)]
@ -209,7 +211,7 @@ impl ViewResult {
/// ///
/// The indexes are used to make sure that the results are in the same order that the script /// The indexes are used to make sure that the results are in the same order that the script
/// requested them in. /// requested them in.
fn get_query_results(&self, entity: Entity) -> mlua::Result<QueryResult> { fn get_query_results(&self, entity: Entity) -> mlua::Result<QueryRowResult> {
let mut query_vals = vec![]; let mut query_vals = vec![];
// A modifier is used that will be incremented every time a filter allowed the query. // A modifier is used that will be incremented every time a filter allowed the query.
@ -217,23 +219,23 @@ impl ViewResult {
let mut index_mod = 0; let mut index_mod = 0;
for (query, i) in &self.queries { for (query, i) in &self.queries {
let qres = query.get_query_result(self.world.clone(), entity)?; let qres = query.get_query_result(self.world.clone(), entity)?;
if let Some(val) = qres.as_boolean() {
if !val {
return Ok(QueryResult::None);
}
index_mod += 1; match qres {
// do not push a boolean to values, its considered a filter LuaQueryResult::None => return Ok(QueryRowResult::None),
continue; LuaQueryResult::AlwaysNone => return Ok(QueryRowResult::AlwaysNone),
} else if qres.is_nil() { LuaQueryResult::FilterPass => {
return Ok(QueryResult::AlwaysNone); // do not push a boolean to values, its considered a filter
index_mod += 1;
},
LuaQueryResult::FilterDeny => return Ok(QueryRowResult::FilterDeny),
LuaQueryResult::Some(value) => {
let idx = (*i - index_mod).max(0);
query_vals.push((value, idx));
},
} }
let idx = (*i - index_mod).max(0);
query_vals.push((qres, idx));
} }
Ok(QueryResult::Some(query_vals)) Ok(QueryRowResult::Some(query_vals))
} }
} }
@ -259,14 +261,14 @@ impl mlua::UserData for ViewResult {
Some((en, mut vals)) => { Some((en, mut vals)) => {
loop { loop {
let query_vals = match this.get_query_results(en)? { let query_vals = match this.get_query_results(en)? {
QueryResult::Some(v) => v, QueryRowResult::Some(v) => v,
QueryResult::AlwaysNone => { QueryRowResult::AlwaysNone => {
return mlua::Value::Nil.into_lua_multi(lua); return mlua::Value::Nil.into_lua_multi(lua);
}, },
QueryResult::None => { QueryRowResult::None | QueryRowResult::FilterDeny => {
// try to get it next loop // try to get it next loop
continue; continue;
} },
}; };
// insert query values to the result row // insert query values to the result row
@ -300,13 +302,14 @@ impl mlua::UserData for ViewResult {
LuaEntityRef::new(this.world.clone(), en).into_lua(lua)?; LuaEntityRef::new(this.world.clone(), en).into_lua(lua)?;
let query_vals = match this.get_query_results(en)? { let query_vals = match this.get_query_results(en)? {
QueryResult::Some(v) => v, QueryRowResult::Some(v) => v,
QueryResult::AlwaysNone => { QueryRowResult::AlwaysNone => {
return mlua::Value::Nil.into_lua_multi(lua); return mlua::Value::Nil.into_lua_multi(lua);
}, },
QueryResult::None => { QueryRowResult::None | QueryRowResult::FilterDeny => {
// try to get it next loop
continue; continue;
} },
}; };
// insert query values to the result row // insert query values to the result row