engine/ecs/src/updates.rs

676 lines
21 KiB
Rust
Raw Normal View History

2024-08-23 11:22:09 +00:00
#![allow(clippy::type_complexity)]
use std::any::TypeId;
use std::marker::PhantomData;
#[cfg(feature = "timings")]
use std::time::Instant;
use anyhow::Result;
use indexmap::IndexMap;
#[cfg(feature = "timings")]
use super::super::timings::Timings;
2025-02-26 07:39:19 +00:00
use crate::*;
2024-08-23 11:22:09 +00:00
use scene_update_macros::implement_pair_update;
macro_rules! impl_singleton_update {
( $name: ident, $([$var: ident]$(,)?)+ ) => {
2025-02-26 11:22:32 +00:00
impl Archetype {
2024-08-23 11:22:09 +00:00
paste::item! {
pub fn [<create_ $name>]<F, Filter, $($var,)+>(f: F, filter: Filter) -> Self
where
2025-02-26 11:22:32 +00:00
F: Fn(&mut World, Entity, $(&mut $var,)+) -> Result<()> + Send + Sync + Clone + 'static,
Filter: CheckFilter + 'static,
2024-08-23 11:22:09 +00:00
$(
2025-02-26 11:22:32 +00:00
$var: EntityComponent + ComponentDebug,
2024-08-23 11:22:09 +00:00
)+
{
$(
filter.verify_dedup::<$var>();
)+
Self {
check_entity: Box::new({
move |entity| {
$(
if !entity.components.contains::<$var>() {
return false;
}
)+
if !filter.check(entity) {
return false;
}
true
}
}),
create_callback: Box::new(move |entity| {
$(
let [< $var:lower >] = UnsafeComponentStore::from(
entity.get_component::<$var>()?
);
)+
let f = f.clone();
Ok(Box::new(move |e, scene_contents| {
unsafe { f(scene_contents, e, $([< $var:lower >].as_mut(),)+) }
}))
}),
entities: IndexMap::new(),
}
}
}
}
2025-02-26 11:22:32 +00:00
impl<Func, Filter, $( $var, )+> AddUpdates2<( $( $var, )+ ), Func, Filter> for Updates
2024-08-23 11:22:09 +00:00
where
$(
2025-02-26 11:22:32 +00:00
$var: EntityComponent + ComponentDebug,
2024-08-23 11:22:09 +00:00
)+
2025-02-26 11:22:32 +00:00
Func: Fn(& mut World, Entity, $(&mut $var,)+) -> Result<()> + Send + Sync + Clone + 'static,
Filter: CheckFilter + 'static
2024-08-23 11:22:09 +00:00
{
fn add_update(
&mut self,
name: &str,
priority: u32,
func: Func,
2025-02-26 11:22:32 +00:00
filter: Filter
2024-08-23 11:22:09 +00:00
) -> Result<()> {
paste::item! {
2025-02-26 11:22:32 +00:00
self.add(name, priority, Update::Single(Archetype::[<create_ $name>](func, filter)))
2024-08-23 11:22:09 +00:00
}
}
}
2025-02-26 11:22:32 +00:00
impl<Func, Filter, $( $var, )+> AddUpdates<( $( $var, )+ ), Func, Filter> for WorldBuilder
2024-08-23 11:22:09 +00:00
where
$(
2025-02-26 11:22:32 +00:00
$var: EntityComponent + ComponentDebug,
2024-08-23 11:22:09 +00:00
)+
2025-02-26 11:22:32 +00:00
Func: Fn(& mut World, Entity, $(&mut $var,)+) -> Result<()> + Send + Sync + Clone + 'static,
Filter: CheckFilter + 'static
2024-08-23 11:22:09 +00:00
{
fn add_update(
&mut self,
name: &str,
priority: u32,
func: Func,
filter: Filter,
) -> Result<()> {
2025-02-26 11:22:32 +00:00
self.updates.add_update(name, priority, func, filter)
2024-08-23 11:22:09 +00:00
}
}
};
}
macro_rules! impl_pair_update {
(
$lhs_id: expr,
( $([$lhs_little: ident: $lhs_big: ident]$(,)?)+ ),
$rhs_id: expr,
( $([$rhs_little: ident: $rhs_big: ident]$(,)?)+ )
) => {
2025-02-26 11:22:32 +00:00
impl ArchetypePair {
2024-08-23 11:22:09 +00:00
paste::item! {
pub fn [<create_lhs_ $lhs_id _rhs_ $rhs_id>] <F, LeftFilter, RightFilter, $($lhs_big,)+ $($rhs_big,)+>
(f: F, left_filter: LeftFilter, right_filter: RightFilter) -> Self
where
2025-02-26 11:22:32 +00:00
F: Fn(&mut World, (Entity, $(&mut $lhs_big,)+), (Entity, $(&mut $rhs_big,)+)) -> Result<()> + Send + Sync + Clone + 'static,
LeftFilter: CheckFilter + 'static,
RightFilter: CheckFilter + 'static,
2024-08-23 11:22:09 +00:00
$(
2025-02-26 11:22:32 +00:00
$rhs_big: EntityComponent + ComponentDebug,
2024-08-23 11:22:09 +00:00
)+
$(
2025-02-26 11:22:32 +00:00
$lhs_big: EntityComponent + ComponentDebug,
2024-08-23 11:22:09 +00:00
)+
{
$(
left_filter.verify_dedup::<$lhs_big>();
)+
$(
right_filter.verify_dedup::<$rhs_big>();
)+
Self {
check_left_entity: Box::new({
move |entity| {
$(
if !entity.components.contains::<$lhs_big>() {
return false;
}
)+
if !left_filter.check(entity) {
return false;
}
true
}
}),
check_right_entity: Box::new({
move |entity| {
$(
if !entity.components.contains::<$rhs_big>() {
return false;
}
)+
if !right_filter.check(entity) {
return false;
}
true
}
}),
create_callback: Box::new(move |lhs_entity, rhs_entity| {
$(
let $lhs_little = UnsafeComponentStore::from(
lhs_entity.get_component::<$lhs_big>()?
);
)+
$(
let $rhs_little = UnsafeComponentStore::from(
rhs_entity.get_component::<$rhs_big>()?
);
)+
let f = f.clone();
Ok(Box::new(move |lhs_e, rhs_e, scene_contents| {
unsafe { f(scene_contents, (lhs_e, $($lhs_little.as_mut(),)+), (rhs_e, $($rhs_little.as_mut(),)+) ) }
}))
}),
entities: IndexMap::new(),
}
}
}
}
2025-02-26 11:22:32 +00:00
impl<Func, LhsFilter, RhsFilter, $( $lhs_big, )+ $($rhs_big,)+> AddUpdates2<( ($( $lhs_big, )+), ($($rhs_big,)+) ), Func, (LhsFilter, RhsFilter)> for Updates
2024-08-23 11:22:09 +00:00
where
$(
2025-02-26 11:22:32 +00:00
$rhs_big: EntityComponent + ComponentDebug,
2024-08-23 11:22:09 +00:00
)+
$(
2025-02-26 11:22:32 +00:00
$lhs_big: EntityComponent + ComponentDebug,
2024-08-23 11:22:09 +00:00
)+
2025-02-26 11:22:32 +00:00
Func: Fn(& mut World, (Entity, $(&mut $lhs_big,)+), (Entity, $(&mut $rhs_big,)+)) -> Result<()> + Send + Sync + Clone + 'static,
LhsFilter: CheckFilter + 'static,
RhsFilter: CheckFilter + 'static
2024-08-23 11:22:09 +00:00
{
fn add_update(
&mut self,
name: &str,
priority: u32,
func: Func,
2025-02-26 11:22:32 +00:00
filter: (LhsFilter, RhsFilter)
2024-08-23 11:22:09 +00:00
) -> Result<()> {
paste::item! {
2025-02-26 11:22:32 +00:00
self.add(name, priority, Update::Pair(ArchetypePair::[<create_lhs_ $lhs_id _rhs_ $rhs_id>](func, filter.0, filter.1)))?;
2024-08-23 11:22:09 +00:00
}
Ok(())
}
}
2025-02-26 11:22:32 +00:00
impl<Func, LhsFilter, RhsFilter, $( $lhs_big, )+ $($rhs_big,)+> AddUpdates<( ($( $lhs_big, )+), ($($rhs_big,)+) ), Func, (LhsFilter, RhsFilter)> for WorldBuilder
2024-08-23 11:22:09 +00:00
where
$(
2025-02-26 11:22:32 +00:00
$rhs_big: EntityComponent + ComponentDebug,
2024-08-23 11:22:09 +00:00
)+
$(
2025-02-26 11:22:32 +00:00
$lhs_big: EntityComponent + ComponentDebug,
2024-08-23 11:22:09 +00:00
)+
2025-02-26 11:22:32 +00:00
Func: Fn(& mut World, (Entity, $(&mut $lhs_big,)+), (Entity, $(&mut $rhs_big,)+)) -> Result<()> + Send + Sync + Clone + 'static,
LhsFilter: CheckFilter + 'static,
RhsFilter: CheckFilter + 'static
2024-08-23 11:22:09 +00:00
{
fn add_update(
&mut self,
name: &str,
priority: u32,
func: Func,
filter: (LhsFilter, RhsFilter),
) -> Result<()> {
2025-02-26 11:22:32 +00:00
self.updates.add_update(name, priority, func, filter)
2024-08-23 11:22:09 +00:00
}
}
};
}
macro_rules! impl_update_filter {
( $name: ident, $([$big: ident, $little: ident]$(,)?)+ ) => {
paste::item! {
2025-02-26 11:22:32 +00:00
pub struct [<$name Filter>]<$($big: EntityComponent,)+> {
2024-08-23 11:22:09 +00:00
$(
$little: std::marker::PhantomData<$big>,
)+
}
2025-02-26 11:22:32 +00:00
impl<$($big: EntityComponent,)+> Default for [<$name Filter>]<$($big,)+> {
2024-08-23 11:22:09 +00:00
fn default() -> Self {
Self {
$(
$little: std::marker::PhantomData,
)+
}
}
}
2025-02-26 11:22:32 +00:00
impl<$($big: EntityComponent,)+> CheckFilter for [<$name Filter>]<$($big,)+> {
fn check(&self, entity: &EntityObject) -> bool {
2024-08-23 11:22:09 +00:00
$(
if entity.contains_component::<$big>() {
return false;
}
)+
true
}
2025-02-26 11:22:32 +00:00
fn verify_dedup<O: EntityComponent>(&self) {
2024-08-23 11:22:09 +00:00
$(
if TypeId::of::<O>() == TypeId::of::<$big>() {
panic!("Type is used as input and filter at the same time");
}
)+
}
}
2025-02-26 11:22:32 +00:00
impl<$($big: EntityComponent,)+> Clone for [<$name Filter>]<$($big,)+> {
2024-08-23 11:22:09 +00:00
fn clone(&self) -> Self {
Self {
$(
$little: self.$little.clone(),
)+
}
}
}
}
};
}
2025-02-26 11:22:32 +00:00
pub struct Query<T, F = EmptyFilter>
2024-08-23 11:22:09 +00:00
where
2025-02-26 11:22:32 +00:00
F: CheckFilter,
2024-08-23 11:22:09 +00:00
{
pub components: T,
2025-02-26 07:39:19 +00:00
2024-08-23 11:22:09 +00:00
d: PhantomData<F>,
}
pub trait AddUpdates<T, Func, Filter> {
fn add_update(&mut self, name: &str, priority: u32, func: Func, filter: Filter) -> Result<()>;
}
2025-02-26 11:22:32 +00:00
trait AddUpdates2<T, Func, Filter> {
fn add_update(&mut self, name: &str, priority: u32, func: Func, filter: Filter) -> Result<()>;
2024-08-23 11:22:09 +00:00
}
2025-02-26 11:22:32 +00:00
pub trait CheckFilter: Send + Sync + Default + Clone {
fn check(&self, entity: &EntityObject) -> bool;
fn verify_dedup<O: EntityComponent>(&self);
2024-08-23 11:22:09 +00:00
}
#[derive(Default, Clone)]
pub struct EmptyFilter;
2025-02-26 11:22:32 +00:00
impl CheckFilter for EmptyFilter {
fn check(&self, _entity: &EntityObject) -> bool {
2024-08-23 11:22:09 +00:00
true
}
fn verify_dedup<O>(&self) {}
}
#[derive(Default, Clone, Debug)]
pub struct ArchetypeInfo {
entities: Vec<(Entity, Option<String>)>,
}
impl ArchetypeInfo {
2025-03-03 07:45:50 +00:00
pub fn new(entities: Vec<(Entity, Option<String>)>) -> Self {
2024-08-23 11:22:09 +00:00
Self { entities }
}
pub fn entities(&self) -> &[(Entity, Option<String>)] {
&self.entities
}
pub fn count(&self) -> usize {
self.entities.len()
}
}
2025-02-26 11:22:32 +00:00
pub struct Archetype {
check_entity: Box<dyn Fn(&EntityObject) -> bool + Send + Sync>,
2024-08-23 11:22:09 +00:00
create_callback: Box<
2025-02-26 11:22:32 +00:00
dyn Fn(&EntityObject) -> Result<Box<dyn Fn(Entity, &mut World) -> Result<()> + Send + Sync>>
2024-08-23 11:22:09 +00:00
+ Send
+ Sync,
>,
2025-02-26 11:22:32 +00:00
entities: IndexMap<Entity, Box<dyn Fn(Entity, &mut World) -> Result<()> + Send + Sync>>,
2024-08-23 11:22:09 +00:00
}
2025-02-26 11:22:32 +00:00
impl Archetype {
pub fn add_entity(&mut self, entity_object: &EntityObject) -> Result<()> {
2024-08-23 11:22:09 +00:00
if (self.check_entity)(entity_object) {
let cb = (self.create_callback)(entity_object)?;
self.entities.insert(entity_object.as_entity(), cb);
}
Ok(())
}
pub fn remove_entity(&mut self, entity: Entity) {
self.entities.swap_remove(&entity);
}
2025-02-26 11:22:32 +00:00
pub fn execute(&self, scene_contents: &mut World) -> Result<()> {
2024-08-23 11:22:09 +00:00
for (entity, callback) in self.entities.iter() {
callback(*entity, scene_contents)?;
}
Ok(())
}
2025-03-03 07:45:50 +00:00
pub fn entities(
2024-08-23 11:22:09 +00:00
&self,
2025-02-26 11:22:32 +00:00
) -> &IndexMap<Entity, Box<dyn Fn(Entity, &mut World) -> Result<()> + Send + Sync>> {
2024-08-23 11:22:09 +00:00
&self.entities
}
}
2025-02-26 11:22:32 +00:00
pub struct ArchetypePair {
check_left_entity: Box<dyn Fn(&EntityObject) -> bool + Send + Sync>,
check_right_entity: Box<dyn Fn(&EntityObject) -> bool + Send + Sync>,
2024-08-23 11:22:09 +00:00
create_callback: Box<
dyn Fn(
2025-02-26 11:22:32 +00:00
&EntityObject,
&EntityObject,
2025-02-26 07:39:19 +00:00
)
2025-02-26 11:22:32 +00:00
-> Result<Box<dyn Fn(Entity, Entity, &mut World) -> Result<()> + Send + Sync>>
2025-02-26 07:39:19 +00:00
+ Send
2024-08-23 11:22:09 +00:00
+ Sync,
>,
2025-02-26 11:22:32 +00:00
entities: IndexMap<
(Entity, Entity),
Box<dyn Fn(Entity, Entity, &mut World) -> Result<()> + Send + Sync>,
>,
2024-08-23 11:22:09 +00:00
}
2025-02-26 11:22:32 +00:00
impl ArchetypePair {
2024-08-23 11:22:09 +00:00
pub(crate) fn add_entity(
&mut self,
2025-02-26 11:22:32 +00:00
entity_object: &EntityObject,
entities: &IndexMap<Entity, EntityObject>,
2024-08-23 11:22:09 +00:00
) -> Result<()> {
for (other_entity, other_entity_object) in entities.iter() {
if entity_object.as_entity() == *other_entity {
continue;
}
// check if the entities can be on both sides
if (self.check_left_entity)(entity_object)
&& (self.check_right_entity)(other_entity_object)
{
let cb = (self.create_callback)(entity_object, other_entity_object)?;
self.entities
.insert((entity_object.as_entity(), *other_entity), cb);
}
if (self.check_left_entity)(other_entity_object)
&& (self.check_right_entity)(entity_object)
{
let cb = (self.create_callback)(other_entity_object, entity_object)?;
self.entities
.insert((*other_entity, entity_object.as_entity()), cb);
}
}
Ok(())
}
pub(crate) fn remove_entity(&mut self, entity: Entity) {
while let Some((left_entity, right_entity)) = self
.entities
.keys()
.find(|(left_entity, right_entity)| *left_entity == entity || *right_entity == entity)
.cloned()
{
self.entities.swap_remove(&(left_entity, right_entity));
}
}
2025-02-26 11:22:32 +00:00
pub(crate) fn execute(&self, scene_contents: &mut World) -> Result<()> {
2024-08-23 11:22:09 +00:00
for ((left_entity, right_entity), callback) in self.entities.iter() {
callback(*left_entity, *right_entity, scene_contents)?;
}
Ok(())
}
}
2025-02-26 11:22:32 +00:00
pub enum Update {
Single(Archetype),
Pair(ArchetypePair),
2024-08-23 11:22:09 +00:00
}
2025-02-26 11:22:32 +00:00
impl From<Archetype> for Update {
fn from(archetype: Archetype) -> Self {
2024-08-23 11:22:09 +00:00
Self::Single(archetype)
}
}
2025-02-26 11:22:32 +00:00
impl From<ArchetypePair> for Update {
fn from(pair: ArchetypePair) -> Self {
2024-08-23 11:22:09 +00:00
Self::Pair(pair)
}
}
2025-02-26 11:22:32 +00:00
pub struct Updates {
2024-08-23 11:22:09 +00:00
#[cfg(feature = "timings")]
timings: Timings,
2025-02-26 11:22:32 +00:00
updates: Vec<(String, u32, Update)>,
2025-02-26 07:39:19 +00:00
}
2025-02-26 11:22:32 +00:00
impl Default for Updates {
2025-02-26 07:39:19 +00:00
fn default() -> Self {
Self {
#[cfg(feature = "timings")]
timings: Timings::default,
updates: Vec::new(),
}
}
2024-08-23 11:22:09 +00:00
}
2025-02-26 11:22:32 +00:00
impl Updates {
pub(crate) fn update(&mut self, world: &mut World) -> Result<()> {
2024-08-23 11:22:09 +00:00
#[cfg(feature = "timings")]
2025-02-26 11:22:32 +00:00
if let Some(timings) = self.timings.check_timing(world.now(), None) {
2024-08-23 11:22:09 +00:00
if !timings.is_empty() {
println!("timings: {:#?}", timings);
}
}
#[cfg(feature = "timings")]
let timings = &mut self.timings;
self.updates
.iter()
.try_for_each(|(_name, _, update)| -> Result<()> {
#[cfg(feature = "timings")]
let before = Instant::now();
match update {
Update::Single(archetype) => {
2025-02-26 11:22:32 +00:00
archetype.execute(world)?;
2024-08-23 11:22:09 +00:00
}
Update::Pair(archetype_pair) => {
2025-02-26 11:22:32 +00:00
archetype_pair.execute(world)?;
2024-08-23 11:22:09 +00:00
}
}
#[cfg(feature = "timings")]
timings.add(_name, Instant::now().duration_since(before));
Ok(())
})?;
Ok(())
}
pub(crate) fn add_entity(
&mut self,
2025-02-26 11:22:32 +00:00
entity_object: &EntityObject,
entities: &IndexMap<Entity, EntityObject>,
2024-08-23 11:22:09 +00:00
) -> Result<()> {
for (_, _, update) in self.updates.iter_mut() {
match update {
Update::Single(archetype) => {
archetype.add_entity(entity_object)?;
}
Update::Pair(archetype_pair) => {
archetype_pair.add_entity(entity_object, entities)?;
}
}
}
Ok(())
}
pub(crate) fn remove_entity(&mut self, entity: Entity) {
for (_, _, update) in self.updates.iter_mut() {
match update {
Update::Single(archetype) => {
archetype.remove_entity(entity);
}
Update::Pair(archetype_pair) => {
archetype_pair.remove_entity(entity);
}
}
}
}
2025-03-03 07:45:50 +00:00
// pub(crate) fn clear(&mut self) {
// self.updates.clear();
2024-08-23 11:22:09 +00:00
2025-03-03 07:45:50 +00:00
// #[cfg(feature = "timings")]
// self.timings.clear();
// }
2024-08-23 11:22:09 +00:00
2025-02-26 11:22:32 +00:00
pub(crate) fn add(&mut self, name: &str, priority: u32, update: Update) -> Result<()> {
2024-08-23 11:22:09 +00:00
#[cfg(feature = "timings")]
self.timings.add_timing_afterwards(name);
self.updates.push((name.to_string(), priority, update));
self.updates
.sort_by(|(_, lhs_prio, _), (_, rhs_prio, _)| lhs_prio.cmp(rhs_prio));
Ok(())
}
}
2025-02-26 07:39:19 +00:00
// #[derive(Default)]
// pub struct Archetypes {
// archetypes: HashMap<String, Archetype>,
// }
// impl Archetypes {
// pub(crate) fn add_entity(&mut self, entity_object: &EntityObject) -> Result<()> {
// for archetype in self.archetypes.values_mut() {
// archetype.add_entity(entity_object)?;
// }
// Ok(())
// }
// pub(crate) fn remove_entity(&mut self, entity: Entity) {
// for archetype in self.archetypes.values_mut() {
// archetype.remove_entity(entity);
// }
// }
// pub(crate) fn clear(&mut self) {
// self.archetypes.clear();
// }
// pub(crate) fn insert(&mut self, name: String, archetype: Archetype) {
// assert!(self.archetypes.insert(name, archetype).is_none());
// }
// pub(crate) fn get(&self, name: &String) -> Option<&Archetype> {
// self.archetypes.get(name)
// }
// pub(crate) fn execute(
// &self,
// name: &String,
// scene_contents: &mut SceneContents<'_>,
// ) -> Result<()> {
// self.archetypes[name].execute(scene_contents)
// }
// }
2024-08-23 11:22:09 +00:00
#[rustfmt::skip]
impl_singleton_update!(single, [R]);
#[rustfmt::skip]
impl_singleton_update!(double, [R], [S]);
#[rustfmt::skip]
impl_singleton_update!(triple, [R], [S], [T]);
#[rustfmt::skip]
impl_singleton_update!(quadruple, [R], [S], [T], [U]);
#[rustfmt::skip]
impl_singleton_update!(quintuple, [R], [S], [T], [U], [V]);
#[rustfmt::skip]
impl_singleton_update!(sextuple, [R], [S], [T], [U], [V], [W]);
#[rustfmt::skip]
impl_singleton_update!(septuple, [R], [S], [T], [U], [V], [W], [X]);
#[rustfmt::skip]
impl_singleton_update!(octuple, [R], [S], [T], [U], [V], [W], [X], [Y]);
#[rustfmt::skip]
impl_singleton_update!(ninetuple, [R], [S], [T], [U], [V], [W], [X], [Y], [Z]);
implement_pair_update!(impl_pair_update, 1, 10);
#[rustfmt::skip]
impl_update_filter!(Monuple, [R, r]);
#[rustfmt::skip]
impl_update_filter!(Couple, [R, r], [S, s]);
#[rustfmt::skip]
impl_update_filter!(Triple, [R, r], [S, s], [T, t]);
#[rustfmt::skip]
impl_update_filter!(Quadruple, [R, r], [S, s], [T, t], [U, u]);
#[rustfmt::skip]
impl_update_filter!(Quintuple, [R, r], [S, s], [T, t], [U, u], [V, v]);
#[rustfmt::skip]
impl_update_filter!(Sextuple, [R, r], [S, s], [T, t], [U, u], [V, v], [W, w]);
#[rustfmt::skip]
impl_update_filter!(Septuple, [R, r], [S, s], [T, t], [U, u], [V, v], [W, w], [X, x]);
#[rustfmt::skip]
impl_update_filter!(Octuple, [R, r], [S, s], [T, t], [U, u], [V, v], [W, w], [X, x], [Y, y]);
#[rustfmt::skip]
impl_update_filter!(Nonuple, [R, r], [S, s], [T, t], [U, u], [V, v], [W, w], [X, x], [Y, y], [Z, z]);
#[rustfmt::skip]
impl_update_filter!(Decuple, [R, r], [S, s], [T, t], [U, u], [V, v], [W, w], [X, x], [Y, y], [Z, z], [A, a]);