Improve Lua ECS #30
|
@ -6,6 +6,8 @@ use crate::{
|
|||
ReflectBranch, ScriptEntity, ScriptWorldPtr,
|
||||
};
|
||||
|
||||
use super::LuaQueryResult;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct LuaChangedQuery(LuaComponent);
|
||||
|
||||
|
@ -38,13 +40,13 @@ impl mlua::UserData for LuaChangedQuery {
|
|||
match &reflect.reflect_branch {
|
||||
ReflectBranch::Component(comp) => {
|
||||
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.
|
||||
let arch = match world.entity_archetype(*en) {
|
||||
Some(a) => a,
|
||||
None => return Ok(mlua::Value::Boolean(false))
|
||||
None => return Ok(LuaQueryResult::FilterDeny),
|
||||
};
|
||||
let arch_idx = *arch.entity_indexes().get(&en).unwrap();
|
||||
|
||||
|
@ -52,7 +54,7 @@ impl mlua::UserData for LuaChangedQuery {
|
|||
Some(col) => col,
|
||||
None => {
|
||||
// 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
|
||||
// attempts to get the type data before it is tried here
|
||||
.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) => {
|
||||
// Check if the resource was changed. Per API spec, must return false.
|
||||
match res.reflect_is_changed(&world) {
|
||||
Some(false) => {
|
||||
return Ok(mlua::Value::Boolean(false));
|
||||
return Ok(LuaQueryResult::FilterDeny);
|
||||
}
|
||||
None => {
|
||||
// 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>()
|
||||
.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,
|
||||
};
|
||||
|
||||
use super::LuaQueryResult;
|
||||
|
||||
#[derive(Clone)]
|
||||
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
|
||||
let arch = match world.entity_archetype(*en) {
|
||||
Some(a) => a,
|
||||
None => return Ok(false),
|
||||
None => return Ok(LuaQueryResult::FilterDeny)
|
||||
};
|
||||
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,
|
||||
world: ScriptWorldPtr,
|
||||
entity: Entity,
|
||||
) -> mlua::Result<mlua::Value> {
|
||||
) -> mlua::Result<LuaQueryResult> {
|
||||
let lua_en = ScriptEntity(entity);
|
||||
match &self.0 {
|
||||
QueryInner::Component(comp) => {
|
||||
|
@ -158,7 +158,7 @@ impl mlua::FromLua for LuaQueryResult {
|
|||
"always_none" => Ok(Self::AlwaysNone),
|
||||
"filter_pass" => Ok(Self::FilterPass),
|
||||
"filter_deny" => Ok(Self::FilterDeny),
|
||||
"value" => {
|
||||
"some" => {
|
||||
let val: mlua::Value = table
|
||||
.get("val")
|
||||
.map_err(|_| malformed_table_error_query_result(ty, "val"))?;
|
||||
|
|
|
@ -3,7 +3,7 @@ use crate::{
|
|||
ScriptEntity, ScriptWorldPtr,
|
||||
};
|
||||
|
||||
use super::LuaQuery;
|
||||
use super::{LuaQuery, LuaQueryResult};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct LuaNotQuery(LuaQuery);
|
||||
|
@ -34,12 +34,12 @@ impl mlua::UserData for LuaNotQuery {
|
|||
|_, this, (world, en): (ScriptWorldPtr, ScriptEntity)| {
|
||||
let res = this.0.get_query_result(world, en.0)?;
|
||||
|
||||
if let Some(res_bool) = res.as_boolean() {
|
||||
Ok(!res_bool)
|
||||
} else if res.is_nil() {
|
||||
Ok(true)
|
||||
} else {
|
||||
Ok(false)
|
||||
match res {
|
||||
LuaQueryResult::None => Ok(LuaQueryResult::FilterPass),
|
||||
super::LuaQueryResult::AlwaysNone => Ok(LuaQueryResult::FilterPass),
|
||||
super::LuaQueryResult::FilterPass => Ok(LuaQueryResult::FilterDeny),
|
||||
super::LuaQueryResult::FilterDeny => Ok(LuaQueryResult::FilterPass),
|
||||
super::LuaQueryResult::Some(_) => Ok(LuaQueryResult::FilterDeny),
|
||||
}
|
||||
},
|
||||
);
|
||||
|
|
|
@ -2,9 +2,12 @@ use lyra_reflect::{ReflectWorldExt, RegisteredType};
|
|||
use mlua::IntoLua;
|
||||
|
||||
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)]
|
||||
pub struct LuaResQuery {
|
||||
ty: LuaComponent,
|
||||
|
@ -27,30 +30,34 @@ impl mlua::FromLua for LuaResQuery {
|
|||
|
||||
impl mlua::UserData for LuaResQuery {
|
||||
fn add_methods<M: mlua::UserDataMethods<Self>>(methods: &mut M) {
|
||||
methods.add_function("new", |_, comp: LuaComponent| {
|
||||
Ok(Self {
|
||||
ty: comp
|
||||
})
|
||||
});
|
||||
methods.add_function("new", |_, comp: LuaComponent| Ok(Self { ty: comp }));
|
||||
|
||||
methods.add_method(FN_NAME_INTERNAL_ECS_QUERY_RESULT, |lua, this, (world, _): (ScriptWorldPtr, ScriptEntity)| {
|
||||
let mut world = world.write();
|
||||
let reflect = this.ty.reflect_type()?;
|
||||
methods.add_method(
|
||||
FN_NAME_INTERNAL_ECS_QUERY_RESULT,
|
||||
|lua, this, (world, _): (ScriptWorldPtr, ScriptEntity)| {
|
||||
let mut world = world.write();
|
||||
let reflect = this.ty.reflect_type()?;
|
||||
|
||||
let res = reflect.reflect_branch.as_resource_unchecked();
|
||||
if let Some(res_ptr) = res.reflect_ptr(&mut world) {
|
||||
let reg_type = world
|
||||
.get_type::<RegisteredType>(reflect.reflect_branch.reflect_type_id())
|
||||
.expect("Resource is not type registered!");
|
||||
let proxy = reg_type
|
||||
.get_data::<ReflectLuaProxy>()
|
||||
.expect("Type does not have ReflectLuaProxy as a TypeData");
|
||||
let res = reflect.reflect_branch.as_resource_unchecked();
|
||||
if let Some(res_ptr) = res.reflect_ptr(&mut world) {
|
||||
let reg_type = world
|
||||
.get_type::<RegisteredType>(reflect.reflect_branch.reflect_type_id())
|
||||
.expect("Resource is not type registered!");
|
||||
let proxy = reg_type
|
||||
.get_data::<ReflectLuaProxy>()
|
||||
.expect("Type does not have ReflectLuaProxy as a TypeData");
|
||||
|
||||
proxy.as_lua(lua, res_ptr.cast()).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::Some(
|
||||
proxy
|
||||
.as_lua(lua, res_ptr.cast())
|
||||
.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)
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@ use crate::{
|
|||
ScriptBorrow, ScriptWorldPtr,
|
||||
};
|
||||
|
||||
use super::query::LuaQuery;
|
||||
use super::query::{LuaQuery, LuaQueryResult};
|
||||
|
||||
#[derive(Clone)]
|
||||
enum ViewQueryItem {
|
||||
|
@ -104,10 +104,12 @@ impl mlua::UserData for View {
|
|||
}
|
||||
}
|
||||
|
||||
enum QueryResult {
|
||||
#[derive(Debug, Clone)]
|
||||
enum QueryRowResult {
|
||||
None,
|
||||
AlwaysNone,
|
||||
Some(Vec<(mlua::Value, u32)>)
|
||||
FilterDeny,
|
||||
Some(Vec<(mlua::Value, u32)>),
|
||||
}
|
||||
|
||||
#[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
|
||||
/// 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![];
|
||||
|
||||
// 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;
|
||||
for (query, i) in &self.queries {
|
||||
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;
|
||||
// do not push a boolean to values, its considered a filter
|
||||
continue;
|
||||
} else if qres.is_nil() {
|
||||
return Ok(QueryResult::AlwaysNone);
|
||||
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
|
||||
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)) => {
|
||||
loop {
|
||||
let query_vals = match this.get_query_results(en)? {
|
||||
QueryResult::Some(v) => v,
|
||||
QueryResult::AlwaysNone => {
|
||||
QueryRowResult::Some(v) => v,
|
||||
QueryRowResult::AlwaysNone => {
|
||||
return mlua::Value::Nil.into_lua_multi(lua);
|
||||
},
|
||||
QueryResult::None => {
|
||||
QueryRowResult::None | QueryRowResult::FilterDeny => {
|
||||
// try to get it next loop
|
||||
continue;
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
// 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)?;
|
||||
|
||||
let query_vals = match this.get_query_results(en)? {
|
||||
QueryResult::Some(v) => v,
|
||||
QueryResult::AlwaysNone => {
|
||||
QueryRowResult::Some(v) => v,
|
||||
QueryRowResult::AlwaysNone => {
|
||||
return mlua::Value::Nil.into_lua_multi(lua);
|
||||
},
|
||||
QueryResult::None => {
|
||||
QueryRowResult::None | QueryRowResult::FilterDeny => {
|
||||
// try to get it next loop
|
||||
continue;
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
// insert query values to the result row
|
||||
|
|
Loading…
Reference in New Issue