Improve Lua ECS #30
|
@ -77,11 +77,9 @@ end
|
||||||
end ]]
|
end ]]
|
||||||
|
|
||||||
function on_update()
|
function on_update()
|
||||||
-- Although WorldTransform isn't used, I only want to
|
-- Get entities without WorldTransform
|
||||||
-- modify entities with that component.
|
local view = View.new(Transform, Not(Has(WorldTransform)), Res(DeltaTime))
|
||||||
local view = View.new(Transform, Has(WorldTransform), Res(DeltaTime))
|
|
||||||
local res = world:view_query(view)
|
local res = world:view_query(view)
|
||||||
|
|
||||||
---@param transform Transform
|
---@param transform Transform
|
||||||
---@param dt DeltaTime
|
---@param dt DeltaTime
|
||||||
for entity, transform, dt in res:iter() do
|
for entity, transform, dt in res:iter() do
|
||||||
|
|
|
@ -25,3 +25,12 @@ end
|
||||||
function Has(val)
|
function Has(val)
|
||||||
return HasQuery.new(val)
|
return HasQuery.new(val)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
---Create a `NotQuery` filter that will allow results if
|
||||||
|
---
|
||||||
|
---@see NotQuery
|
||||||
|
---@param val function|table|userdata
|
||||||
|
---@return NotQuery
|
||||||
|
function Not(val)
|
||||||
|
return NotQuery.new(val)
|
||||||
|
end
|
|
@ -7,14 +7,20 @@ pub use changed::*;
|
||||||
mod has;
|
mod has;
|
||||||
pub use has::*;
|
pub use has::*;
|
||||||
|
|
||||||
|
mod not;
|
||||||
|
pub use not::*;
|
||||||
|
|
||||||
use lyra_ecs::Entity;
|
use lyra_ecs::Entity;
|
||||||
|
|
||||||
use crate::{lua::{LuaComponent, FN_NAME_INTERNAL_ECS_QUERY_RESULT}, ScriptEntity, ScriptWorldPtr};
|
use crate::{
|
||||||
|
lua::{LuaComponent, FN_NAME_INTERNAL_ECS_QUERY_RESULT},
|
||||||
|
ScriptEntity, ScriptWorldPtr,
|
||||||
|
};
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
enum QueryInner {
|
enum QueryInner {
|
||||||
Component(LuaComponent),
|
Component(LuaComponent),
|
||||||
Function(mlua::Function)
|
Function(mlua::Function),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
@ -33,15 +39,39 @@ impl LuaQuery {
|
||||||
///
|
///
|
||||||
/// > WARNING: ensure that the world pointer is not locked. If its locked when you call this,
|
/// > WARNING: ensure that the world pointer is not locked. If its locked when you call this,
|
||||||
/// you WILL cause a deadlock.
|
/// you WILL cause a deadlock.
|
||||||
pub fn get_query_result(&self, world: ScriptWorldPtr, entity: Entity) -> mlua::Result<mlua::Value> {
|
pub fn get_query_result(
|
||||||
|
&self,
|
||||||
|
world: ScriptWorldPtr,
|
||||||
|
entity: Entity,
|
||||||
|
) -> mlua::Result<mlua::Value> {
|
||||||
let lua_en = ScriptEntity(entity);
|
let lua_en = ScriptEntity(entity);
|
||||||
match &self.0 {
|
match &self.0 {
|
||||||
QueryInner::Component(comp) => comp.call_method(FN_NAME_INTERNAL_ECS_QUERY_RESULT, (world, lua_en)),
|
QueryInner::Component(comp) => {
|
||||||
|
comp.call_method(FN_NAME_INTERNAL_ECS_QUERY_RESULT, (world, lua_en))
|
||||||
|
}
|
||||||
QueryInner::Function(function) => function.call((world, lua_en)),
|
QueryInner::Function(function) => function.call((world, lua_en)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl mlua::FromLua for LuaQuery {
|
||||||
|
fn from_lua(value: mlua::Value, lua: &mlua::Lua) -> mlua::Result<Self> {
|
||||||
|
let tyname = value.type_name();
|
||||||
|
|
||||||
|
if let Some(f) = value.as_function() {
|
||||||
|
Ok(Self(QueryInner::Function(f.clone())))
|
||||||
|
} else if let Ok(c) = LuaComponent::from_lua(value, lua) {
|
||||||
|
Ok(Self(QueryInner::Component(c)))
|
||||||
|
} else {
|
||||||
|
Err(mlua::Error::FromLuaConversionError {
|
||||||
|
from: tyname,
|
||||||
|
to: "Query".into(),
|
||||||
|
message: Some("expected query function, table, or user data".into()),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum LuaQueryResult {
|
pub enum LuaQueryResult {
|
||||||
None,
|
None,
|
||||||
|
@ -59,20 +89,20 @@ impl mlua::IntoLua for LuaQueryResult {
|
||||||
match self {
|
match self {
|
||||||
LuaQueryResult::None => {
|
LuaQueryResult::None => {
|
||||||
t.set("result", "none")?;
|
t.set("result", "none")?;
|
||||||
},
|
}
|
||||||
LuaQueryResult::AlwaysNone => {
|
LuaQueryResult::AlwaysNone => {
|
||||||
t.set("result", "always_none")?;
|
t.set("result", "always_none")?;
|
||||||
},
|
}
|
||||||
LuaQueryResult::FilterPass => {
|
LuaQueryResult::FilterPass => {
|
||||||
t.set("result", "filter_pass")?;
|
t.set("result", "filter_pass")?;
|
||||||
},
|
}
|
||||||
LuaQueryResult::FilterDeny => {
|
LuaQueryResult::FilterDeny => {
|
||||||
t.set("result", "filter_deny")?;
|
t.set("result", "filter_deny")?;
|
||||||
},
|
}
|
||||||
LuaQueryResult::Some(value) => {
|
LuaQueryResult::Some(value) => {
|
||||||
t.set("result", "some")?;
|
t.set("result", "some")?;
|
||||||
t.set("val", value)?;
|
t.set("val", value)?;
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
t.into_lua(lua)
|
t.into_lua(lua)
|
||||||
|
@ -93,17 +123,22 @@ fn malformed_table_error_query_result(ty: &'static str, missing_field: &str) ->
|
||||||
mlua::Error::FromLuaConversionError {
|
mlua::Error::FromLuaConversionError {
|
||||||
from: ty,
|
from: ty,
|
||||||
to: "QueryResult".into(),
|
to: "QueryResult".into(),
|
||||||
message: Some(format!("malformed table, cannot convert, failed to get field '{}'", missing_field)),
|
message: Some(format!(
|
||||||
|
"malformed table, cannot convert, failed to get field '{}'",
|
||||||
|
missing_field
|
||||||
|
)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl mlua::FromLua for LuaQueryResult {
|
impl mlua::FromLua for LuaQueryResult {
|
||||||
fn from_lua(value: mlua::Value, _: &mlua::Lua) -> mlua::Result<Self> {
|
fn from_lua(value: mlua::Value, _: &mlua::Lua) -> mlua::Result<Self> {
|
||||||
let ty = value.type_name();
|
let ty = value.type_name();
|
||||||
let table = value.as_table()
|
let table = value
|
||||||
|
.as_table()
|
||||||
.ok_or(from_lua_error_query_result(ty, "expected Table"))?;
|
.ok_or(from_lua_error_query_result(ty, "expected Table"))?;
|
||||||
|
|
||||||
let var_name: String = table.get("enum_ty")
|
let var_name: String = table
|
||||||
|
.get("enum_ty")
|
||||||
.map_err(|_| malformed_table_error_query_result(ty, "enum_ty"))?;
|
.map_err(|_| malformed_table_error_query_result(ty, "enum_ty"))?;
|
||||||
if var_name != "query_result" {
|
if var_name != "query_result" {
|
||||||
return Err(mlua::Error::FromLuaConversionError {
|
return Err(mlua::Error::FromLuaConversionError {
|
||||||
|
@ -113,7 +148,8 @@ impl mlua::FromLua for LuaQueryResult {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
let result: String = table.get("result")
|
let result: String = table
|
||||||
|
.get("result")
|
||||||
.map_err(|_| malformed_table_error_query_result(ty, "result"))?;
|
.map_err(|_| malformed_table_error_query_result(ty, "result"))?;
|
||||||
let result_str = result.as_str();
|
let result_str = result.as_str();
|
||||||
|
|
||||||
|
@ -123,17 +159,16 @@ impl mlua::FromLua for LuaQueryResult {
|
||||||
"filter_pass" => Ok(Self::FilterPass),
|
"filter_pass" => Ok(Self::FilterPass),
|
||||||
"filter_deny" => Ok(Self::FilterDeny),
|
"filter_deny" => Ok(Self::FilterDeny),
|
||||||
"value" => {
|
"value" => {
|
||||||
let val: mlua::Value = table.get("val")
|
let val: mlua::Value = table
|
||||||
|
.get("val")
|
||||||
.map_err(|_| malformed_table_error_query_result(ty, "val"))?;
|
.map_err(|_| malformed_table_error_query_result(ty, "val"))?;
|
||||||
Ok(Self::Some(val))
|
Ok(Self::Some(val))
|
||||||
},
|
}
|
||||||
_ => {
|
_ => Err(mlua::Error::FromLuaConversionError {
|
||||||
Err(mlua::Error::FromLuaConversionError {
|
|
||||||
from: ty,
|
from: ty,
|
||||||
to: "QueryResult".into(),
|
to: "QueryResult".into(),
|
||||||
message: Some(format!("unknown result type: '{}'", result_str)),
|
message: Some(format!("unknown result type: '{}'", result_str)),
|
||||||
})
|
}),
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,47 @@
|
||||||
|
use crate::{
|
||||||
|
lua::FN_NAME_INTERNAL_ECS_QUERY_RESULT,
|
||||||
|
ScriptEntity, ScriptWorldPtr,
|
||||||
|
};
|
||||||
|
|
||||||
|
use super::LuaQuery;
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct LuaNotQuery(LuaQuery);
|
||||||
|
|
||||||
|
impl mlua::FromLua for LuaNotQuery {
|
||||||
|
fn from_lua(value: mlua::Value, _: &mlua::Lua) -> mlua::Result<Self> {
|
||||||
|
let tyname = value.type_name();
|
||||||
|
value
|
||||||
|
.as_userdata()
|
||||||
|
.ok_or(mlua::Error::FromLuaConversionError {
|
||||||
|
from: tyname,
|
||||||
|
to: "NotQuery".into(),
|
||||||
|
message: None,
|
||||||
|
})
|
||||||
|
.and_then(|ud| ud.borrow::<Self>())
|
||||||
|
.map(|ud| ud.clone())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl mlua::UserData for LuaNotQuery {
|
||||||
|
fn add_methods<M: mlua::UserDataMethods<Self>>(methods: &mut M) {
|
||||||
|
methods.add_function("new", |_, q: LuaQuery| {
|
||||||
|
Ok(Self(q))
|
||||||
|
});
|
||||||
|
|
||||||
|
methods.add_method(
|
||||||
|
FN_NAME_INTERNAL_ECS_QUERY_RESULT,
|
||||||
|
|_, 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)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
use lyra_ecs::ResourceObject;
|
use lyra_ecs::ResourceObject;
|
||||||
use lyra_reflect::Reflect;
|
use lyra_reflect::Reflect;
|
||||||
|
|
||||||
use crate::{lua::{ecs::{query::{LuaChangedQuery, LuaHasQuery, LuaResQuery}, View}, wrappers::*, LuaContext, LuaWrapper, RegisterLuaType, FN_NAME_INTERNAL_REFLECT, FN_NAME_INTERNAL_REFLECT_TYPE}, ScriptApiProvider, ScriptBorrow, ScriptData, ScriptDynamicBundle, ScriptWorldPtr};
|
use crate::{lua::{ecs::{query::{LuaChangedQuery, LuaHasQuery, LuaNotQuery, LuaResQuery}, View}, wrappers::*, LuaContext, LuaWrapper, RegisterLuaType, FN_NAME_INTERNAL_REFLECT, FN_NAME_INTERNAL_REFLECT_TYPE}, ScriptApiProvider, ScriptBorrow, ScriptData, ScriptDynamicBundle, ScriptWorldPtr};
|
||||||
|
|
||||||
//fn register_lua_proxy::<T:
|
//fn register_lua_proxy::<T:
|
||||||
|
|
||||||
|
@ -48,6 +48,7 @@ impl ScriptApiProvider for LyraEcsApiProvider {
|
||||||
globals.set("ResQuery", ctx.create_proxy::<LuaResQuery>()?)?;
|
globals.set("ResQuery", ctx.create_proxy::<LuaResQuery>()?)?;
|
||||||
globals.set("ChangedQuery", ctx.create_proxy::<LuaChangedQuery>()?)?;
|
globals.set("ChangedQuery", ctx.create_proxy::<LuaChangedQuery>()?)?;
|
||||||
globals.set("HasQuery", ctx.create_proxy::<LuaHasQuery>()?)?;
|
globals.set("HasQuery", ctx.create_proxy::<LuaHasQuery>()?)?;
|
||||||
|
globals.set("NotQuery", ctx.create_proxy::<LuaNotQuery>()?)?;
|
||||||
|
|
||||||
expose_comp_table_wrapper::<LuaCamera>(&ctx, &globals, "Camera")?;
|
expose_comp_table_wrapper::<LuaCamera>(&ctx, &globals, "Camera")?;
|
||||||
expose_comp_table_wrapper::<LuaFreeFlyCamera>(&ctx, &globals, "FreeFlyCamera")?;
|
expose_comp_table_wrapper::<LuaFreeFlyCamera>(&ctx, &globals, "FreeFlyCamera")?;
|
||||||
|
|
Loading…
Reference in New Issue