Improve Lua ECS #30
|
@ -79,13 +79,12 @@ end ]]
|
||||||
function on_update()
|
function on_update()
|
||||||
-- Although WorldTransform isn't used, I only want to
|
-- Although WorldTransform isn't used, I only want to
|
||||||
-- modify entities with that component.
|
-- modify entities with that component.
|
||||||
local view = View.new(Transform, 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 _wt WorldTransform
|
|
||||||
---@param dt DeltaTime
|
---@param dt DeltaTime
|
||||||
for entity, transform, _wt, dt in res:iter() do
|
for entity, transform, dt in res:iter() do
|
||||||
transform:translate(0, 0.15 * dt, 0)
|
transform:translate(0, 0.15 * dt, 0)
|
||||||
entity:update(transform)
|
entity:update(transform)
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,13 +1,27 @@
|
||||||
---Create a Resource Query
|
---Create a Resource query that will return the specific ECS world resource.
|
||||||
|
---
|
||||||
|
---@see ResQuery
|
||||||
---@param resource table|userdata
|
---@param resource table|userdata
|
||||||
---@return ResQuery
|
---@return ResQuery
|
||||||
function Res(resource)
|
function Res(resource)
|
||||||
return ResQuery.new(resource)
|
return ResQuery.new(resource)
|
||||||
end
|
end
|
||||||
|
|
||||||
---Create a `ChangedQuery` of a resource or component.
|
---Create a `ChangedQuery` query that will return only if the resource or component has changed
|
||||||
|
---since last tick.
|
||||||
|
---
|
||||||
|
---@see ChangedQuery
|
||||||
---@param val table|userdata
|
---@param val table|userdata
|
||||||
---@return ChangedQuery
|
---@return ChangedQuery
|
||||||
function Changed(val)
|
function Changed(val)
|
||||||
return ChangedQuery.new(val)
|
return ChangedQuery.new(val)
|
||||||
|
end
|
||||||
|
|
||||||
|
---Create a `HasQuery` filter that will return only if the entity has a specific component.
|
||||||
|
---
|
||||||
|
---@see HasQuery
|
||||||
|
---@param val table|userdata
|
||||||
|
---@return HasQuery
|
||||||
|
function Has(val)
|
||||||
|
return HasQuery.new(val)
|
||||||
end
|
end
|
|
@ -38,6 +38,7 @@ impl ReflectBranch {
|
||||||
///
|
///
|
||||||
/// # Panics
|
/// # Panics
|
||||||
/// If `self` is not a variant of [`ReflectBranch::Component`].
|
/// If `self` is not a variant of [`ReflectBranch::Component`].
|
||||||
|
#[deprecated(note = "use ReflectBranch::as_component instead")]
|
||||||
pub fn as_component_unchecked(&self) -> &ReflectedComponent {
|
pub fn as_component_unchecked(&self) -> &ReflectedComponent {
|
||||||
match self {
|
match self {
|
||||||
ReflectBranch::Component(c) => c,
|
ReflectBranch::Component(c) => c,
|
||||||
|
@ -45,6 +46,16 @@ impl ReflectBranch {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Gets self as a [`ReflectedComponent`].
|
||||||
|
///
|
||||||
|
/// Returns `None` if `self` is not a component.
|
||||||
|
pub fn as_component(&self) -> Option<&ReflectedComponent> {
|
||||||
|
match self {
|
||||||
|
ReflectBranch::Component(c) => Some(c),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns a boolean indicating if `self` is a reflection of a Component.
|
/// Returns a boolean indicating if `self` is a reflection of a Component.
|
||||||
pub fn is_component(&self) -> bool {
|
pub fn is_component(&self) -> bool {
|
||||||
matches!(self, ReflectBranch::Component(_))
|
matches!(self, ReflectBranch::Component(_))
|
||||||
|
|
|
@ -42,7 +42,10 @@ impl mlua::UserData for LuaChangedQuery {
|
||||||
}
|
}
|
||||||
|
|
||||||
// get the pointer of the component in the archetype column.
|
// get the pointer of the component in the archetype column.
|
||||||
let arch = world.entity_archetype(*en).unwrap();
|
let arch = match world.entity_archetype(*en) {
|
||||||
|
Some(a) => a,
|
||||||
|
None => return Ok(mlua::Value::Boolean(false))
|
||||||
|
};
|
||||||
let arch_idx = *arch.entity_indexes().get(&en).unwrap();
|
let arch_idx = *arch.entity_indexes().get(&en).unwrap();
|
||||||
|
|
||||||
let col = match arch.get_column(tyid) {
|
let col = match arch.get_column(tyid) {
|
||||||
|
|
|
@ -0,0 +1,54 @@
|
||||||
|
use crate::{
|
||||||
|
lua::{LuaComponent, FN_NAME_INTERNAL_ECS_QUERY_RESULT},
|
||||||
|
ScriptEntity, ScriptWorldPtr,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct LuaHasQuery(LuaComponent);
|
||||||
|
|
||||||
|
impl mlua::FromLua for LuaHasQuery {
|
||||||
|
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: "HasQuery".into(),
|
||||||
|
message: None,
|
||||||
|
})
|
||||||
|
.and_then(|ud| ud.borrow::<Self>())
|
||||||
|
.map(|ud| ud.clone())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl mlua::UserData for LuaHasQuery {
|
||||||
|
fn add_methods<M: mlua::UserDataMethods<Self>>(methods: &mut M) {
|
||||||
|
methods.add_function("new", |_, comp: LuaComponent| {
|
||||||
|
let reflect = comp.reflect_type()?;
|
||||||
|
if !reflect.reflect_branch.is_component() {
|
||||||
|
Err(mlua::Error::runtime("provided type is not a component!"))
|
||||||
|
} else {
|
||||||
|
Ok(Self(comp))
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
methods.add_method(
|
||||||
|
FN_NAME_INTERNAL_ECS_QUERY_RESULT,
|
||||||
|
|_, this, (world, en): (ScriptWorldPtr, ScriptEntity)| {
|
||||||
|
let world = world.write();
|
||||||
|
let reflect = this.0.reflect_type()?;
|
||||||
|
|
||||||
|
let tyid = reflect.reflect_branch.reflect_type_id();
|
||||||
|
|
||||||
|
// 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),
|
||||||
|
};
|
||||||
|
let component_col = arch.get_column(tyid);
|
||||||
|
|
||||||
|
Ok(component_col.is_some())
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,6 +4,9 @@ pub use res::*;
|
||||||
mod changed;
|
mod changed;
|
||||||
pub use changed::*;
|
pub use changed::*;
|
||||||
|
|
||||||
|
mod has;
|
||||||
|
pub use has::*;
|
||||||
|
|
||||||
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};
|
||||||
|
|
|
@ -158,7 +158,8 @@ impl ViewResult {
|
||||||
let reflect = ud
|
let reflect = ud
|
||||||
.call_function::<ScriptBorrow>(FN_NAME_INTERNAL_REFLECT_TYPE, ())
|
.call_function::<ScriptBorrow>(FN_NAME_INTERNAL_REFLECT_TYPE, ())
|
||||||
.expect("Type does not implement 'reflect_type' properly");
|
.expect("Type does not implement 'reflect_type' properly");
|
||||||
let refl_comp = reflect.reflect_branch.as_component_unchecked();
|
let refl_comp = reflect.reflect_branch.as_component()
|
||||||
|
.expect("`self` is not an instance of `ReflectBranch::Component`");
|
||||||
|
|
||||||
let dyn_type = QueryDynamicType::from_info(refl_comp.info);
|
let dyn_type = QueryDynamicType::from_info(refl_comp.info);
|
||||||
view.push(dyn_type);
|
view.push(dyn_type);
|
||||||
|
@ -211,18 +212,25 @@ impl ViewResult {
|
||||||
fn get_query_results(&self, entity: Entity) -> mlua::Result<QueryResult> {
|
fn get_query_results(&self, entity: Entity) -> mlua::Result<QueryResult> {
|
||||||
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.
|
||||||
|
// this is used to remove the value of a filter without leaving a gap in the results.
|
||||||
|
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 let Some(val) = qres.as_boolean() {
|
||||||
// do not push a boolean to values, its considered a filter
|
|
||||||
if !val {
|
if !val {
|
||||||
return Ok(QueryResult::None);
|
return Ok(QueryResult::None);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
index_mod += 1;
|
||||||
|
// do not push a boolean to values, its considered a filter
|
||||||
|
continue;
|
||||||
} else if qres.is_nil() {
|
} else if qres.is_nil() {
|
||||||
return Ok(QueryResult::AlwaysNone);
|
return Ok(QueryResult::AlwaysNone);
|
||||||
}
|
}
|
||||||
|
|
||||||
query_vals.push((qres, *i));
|
let idx = (*i - index_mod).max(0);
|
||||||
|
query_vals.push((qres, idx));
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(QueryResult::Some(query_vals))
|
Ok(QueryResult::Some(query_vals))
|
||||||
|
|
|
@ -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, 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, 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:
|
||||||
|
|
||||||
|
@ -47,6 +47,7 @@ impl ScriptApiProvider for LyraEcsApiProvider {
|
||||||
globals.set("View", ctx.create_proxy::<View>()?)?;
|
globals.set("View", ctx.create_proxy::<View>()?)?;
|
||||||
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>()?)?;
|
||||||
|
|
||||||
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