Compare commits

..

2 Commits

Author SHA1 Message Date
SeanOMik 964c4ec423
lua: create LuaOptionalQuery 2024-10-29 14:22:03 -04:00
SeanOMik 23a215ba46
lua: create LuaTickOfQuery 2024-10-29 09:32:32 -04:00
6 changed files with 141 additions and 4 deletions

View File

@ -93,6 +93,13 @@ function on_update()
for _, transform in changed_res:iter() do for _, transform in changed_res:iter() do
print("Entity transform changed to: '" .. tostring(transform) .. "' on tick " .. tostring(world:get_tick())) print("Entity transform changed to: '" .. tostring(transform) .. "' on tick " .. tostring(world:get_tick()))
end end
local tick_view = View.new(TickOf(Transform))
local tick_res = world:view_query(tick_view)
---@param tick number
for _, tick in tick_res:iter() do
print("Entity transform last changed on tick " .. tostring(tick))
end
end end
--[[ function on_post_update() --[[ function on_post_update()

View File

@ -7,6 +7,8 @@ function Res(resource)
return ResQuery.new(resource) return ResQuery.new(resource)
end end
---@alias Query function|table|userdata
---Create a `ChangedQuery` query that will return only if the resource or component has changed ---Create a `ChangedQuery` query that will return only if the resource or component has changed
---since last tick. ---since last tick.
--- ---
@ -30,7 +32,7 @@ end
---filter denies. ---filter denies.
--- ---
---@see NotQuery ---@see NotQuery
---@param val function|table|userdata ---@param val Query
---@return NotQuery ---@return NotQuery
function Not(val) function Not(val)
return NotQuery.new(val) return NotQuery.new(val)
@ -40,8 +42,30 @@ end
---The queries are evaluated in the order they were provided. ---The queries are evaluated in the order they were provided.
--- ---
---@see OrQuery ---@see OrQuery
---@param ... function|table|userdata ---@param ... Query
---@return OrQuery ---@return OrQuery
function Not(...) function Or(...)
return OrQuery.new(...) return OrQuery.new(...)
end
---Create a `TickOfQuery` for retrieving the tick of the resource or component on the entity.
---
---@see TickOfQuery
---@param ... table|userdata
---@return TickOfQuery
function TickOf(...)
return TickOfQuery.new(...)
end
---Create any `OptionalQuery` that allows for a query to return nothing.
---
---If the query is a filter, its result will essentially be ignored. If the query returns `None`
---or `AlwaysNone`, this query will return `Nil`. If the query results in a value, its value
---will be the result of this query.
---
---@see OptionalQuery
---@param q Query
---@return OptionalQuery
function Optional(q)
return OptionalQuery.new(q)
end end

View File

@ -13,6 +13,12 @@ pub use not::*;
mod or; mod or;
pub use or::*; pub use or::*;
mod tick_of;
pub use tick_of::*;
mod optional;
pub use optional::*;
use lyra_ecs::Entity; use lyra_ecs::Entity;
use crate::{ use crate::{

View File

@ -0,0 +1,44 @@
use crate::{
lua::FN_NAME_INTERNAL_ECS_QUERY_RESULT, ScriptEntity, ScriptWorldPtr,
};
use super::{LuaQuery, LuaQueryResult};
#[derive(Clone)]
pub struct LuaOptionalQuery(LuaQuery);
impl mlua::FromLua for LuaOptionalQuery {
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: "OptionalQuery".into(),
message: None,
})
.and_then(|ud| ud.borrow::<Self>())
.map(|ud| ud.clone())
}
}
impl mlua::UserData for LuaOptionalQuery {
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)?;
match res {
LuaQueryResult::None => Ok(LuaQueryResult::Some(mlua::Value::Nil)),
LuaQueryResult::AlwaysNone => Ok(LuaQueryResult::Some(mlua::Value::Nil)),
LuaQueryResult::FilterPass => Ok(LuaQueryResult::FilterPass),
LuaQueryResult::FilterDeny => Ok(LuaQueryResult::FilterPass),
LuaQueryResult::Some(v) => Ok(LuaQueryResult::Some(v)),
}
},
);
}
}

View File

@ -0,0 +1,54 @@
use crate::{
lua::{LuaComponent, FN_NAME_INTERNAL_ECS_QUERY_RESULT},
ReflectBranch, ScriptEntity, ScriptWorldPtr,
};
use super::LuaQueryResult;
#[derive(Clone)]
pub struct LuaTickOfQuery(LuaComponent);
impl mlua::FromLua for LuaTickOfQuery {
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: "TickOfQuery".into(),
message: None,
})
.and_then(|ud| ud.borrow::<Self>())
.map(|ud| ud.clone())
}
}
impl mlua::UserData for LuaTickOfQuery {
fn add_methods<M: mlua::UserDataMethods<Self>>(methods: &mut M) {
methods.add_function("new", |_, comp: LuaComponent| Ok(Self(comp)));
methods.add_method(
FN_NAME_INTERNAL_ECS_QUERY_RESULT,
|_, this, (world, en): (ScriptWorldPtr, ScriptEntity)| {
let world = world.read();
let reflect = this.0.reflect_type()?;
match &reflect.reflect_branch {
ReflectBranch::Component(comp) => {
if let Some(tick) = comp.reflect_tick(&world, *en) {
Ok(LuaQueryResult::Some(mlua::Value::Number(*tick as _)))
} else {
Ok(LuaQueryResult::FilterDeny)
}
}
ReflectBranch::Resource(res) => {
if let Some(tick) = res.reflect_tick(&world) {
Ok(LuaQueryResult::Some(mlua::Value::Number(*tick as _)))
} else {
Ok(LuaQueryResult::FilterDeny)
}
}
}
},
);
}
}

View File

@ -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, LuaNotQuery, LuaOrQuery, 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, LuaOptionalQuery, LuaOrQuery, LuaResQuery, LuaTickOfQuery}, 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:
@ -50,6 +50,8 @@ impl ScriptApiProvider for LyraEcsApiProvider {
globals.set("HasQuery", ctx.create_proxy::<LuaHasQuery>()?)?; globals.set("HasQuery", ctx.create_proxy::<LuaHasQuery>()?)?;
globals.set("NotQuery", ctx.create_proxy::<LuaNotQuery>()?)?; globals.set("NotQuery", ctx.create_proxy::<LuaNotQuery>()?)?;
globals.set("OrQuery", ctx.create_proxy::<LuaOrQuery>()?)?; globals.set("OrQuery", ctx.create_proxy::<LuaOrQuery>()?)?;
globals.set("TickOfQuery", ctx.create_proxy::<LuaTickOfQuery>()?)?;
globals.set("OptionalQuery", ctx.create_proxy::<LuaOptionalQuery>()?)?;
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")?;