Improve Lua ECS #30
|
@ -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))?,
|
||||||
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -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)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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"))?;
|
||||||
|
|
|
@ -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),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
|
@ -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,13 +30,11 @@ 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(
|
||||||
|
FN_NAME_INTERNAL_ECS_QUERY_RESULT,
|
||||||
|
|lua, this, (world, _): (ScriptWorldPtr, ScriptEntity)| {
|
||||||
let mut world = world.write();
|
let mut world = world.write();
|
||||||
let reflect = this.ty.reflect_type()?;
|
let reflect = this.ty.reflect_type()?;
|
||||||
|
|
||||||
|
@ -46,11 +47,17 @@ impl mlua::UserData for LuaResQuery {
|
||||||
.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))?,
|
||||||
|
))
|
||||||
} else {
|
} else {
|
||||||
// if the resource is not found in the world, return nil
|
// if the resource is not found in the world, return nil
|
||||||
Ok(mlua::Value::Nil)
|
//Ok(mlua::Value::Nil)
|
||||||
|
Ok(LuaQueryResult::AlwaysNone)
|
||||||
}
|
}
|
||||||
});
|
},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 {
|
||||||
|
LuaQueryResult::None => return Ok(QueryRowResult::None),
|
||||||
|
LuaQueryResult::AlwaysNone => return Ok(QueryRowResult::AlwaysNone),
|
||||||
|
LuaQueryResult::FilterPass => {
|
||||||
// do not push a boolean to values, its considered a filter
|
// do not push a boolean to values, its considered a filter
|
||||||
continue;
|
index_mod += 1;
|
||||||
} else if qres.is_nil() {
|
},
|
||||||
return Ok(QueryResult::AlwaysNone);
|
LuaQueryResult::FilterDeny => return Ok(QueryRowResult::FilterDeny),
|
||||||
}
|
LuaQueryResult::Some(value) => {
|
||||||
|
|
||||||
let idx = (*i - index_mod).max(0);
|
let idx = (*i - index_mod).max(0);
|
||||||
query_vals.push((qres, idx));
|
query_vals.push((value, 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
|
||||||
|
|
Loading…
Reference in New Issue