ecs/ecs/src/updates.rs
2025-04-15 10:29:00 +02:00

303 lines
8 KiB
Rust

#![allow(clippy::type_complexity)]
use std::ops::{Deref, DerefMut};
use std::{any::TypeId, marker::PhantomData};
use anyhow::Result;
use indexmap::IndexMap;
use itertools::Itertools;
use update_macros::implement_updates;
use crate::resources::Resource as ResourceTrait;
use crate::*;
macro_rules! impl_update_filter {
( $name: ident, $([$big: ident, $little: ident]$(,)?)+ ) => {
paste::item! {
pub struct [<$name Filter>]<$($big: EntityComponent,)+> {
$(
$little: std::marker::PhantomData<$big>,
)+
}
impl<$($big: EntityComponent,)+> Default for [<$name Filter>]<$($big,)+> {
fn default() -> Self {
Self {
$(
$little: std::marker::PhantomData,
)+
}
}
}
impl<$($big: EntityComponent,)+> CheckFilter for [<$name Filter>]<$($big,)+> {
fn check(entity: &EntityObject) -> bool {
$(
if entity.contains_component::<$big>() {
return false;
}
)+
true
}
fn verify_dedup<O: EntityComponent>() {
$(
if TypeId::of::<O>() == TypeId::of::<$big>() {
panic!("Type is used as input and filter at the same time");
}
)+
}
}
impl<$($big: EntityComponent,)+> Clone for [<$name Filter>]<$($big,)+> {
fn clone(&self) -> Self {
Self {
$(
$little: self.$little.clone(),
)+
}
}
}
}
};
}
#[derive(Copy, Clone)]
pub struct Query<C, F = EmptyFilter>
where
F: CheckFilter,
{
entity: Entity,
c: C,
filter: PhantomData<F>,
}
impl<C, F: CheckFilter> Query<C, F> {
pub fn new(entity: Entity, c: C) -> Self {
Self {
entity,
c,
filter: PhantomData,
}
}
pub fn entity(&self) -> Entity {
self.entity
}
}
impl<C, F: CheckFilter> Deref for Query<C, F> {
type Target = C;
fn deref(&self) -> &Self::Target {
&self.c
}
}
impl<C, F: CheckFilter> DerefMut for Query<C, F> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.c
}
}
pub trait AddUpdates<T, R, Func, Filter> {
fn add_update(&mut self, priority: u32, func: Func) -> Result<()>;
}
pub trait CreateArchetype<T, R, Func, Filter> {
fn create(f: Func) -> Self;
}
pub trait CheckFilter: Send + Sync + Default + Clone {
fn check(entity: &EntityObject) -> bool;
fn verify_dedup<O: EntityComponent>();
}
#[derive(Default, Clone)]
pub struct EmptyFilter;
impl CheckFilter for EmptyFilter {
fn check(_entity: &EntityObject) -> bool {
true
}
fn verify_dedup<O>() {}
}
#[derive(Default, Clone, Debug)]
pub struct ArchetypeInfo {
entities: Vec<(Entity, Option<String>)>,
}
impl ArchetypeInfo {
pub fn new(entities: Vec<(Entity, Option<String>)>) -> Self {
Self { entities }
}
pub fn entities(&self) -> &[(Entity, Option<String>)] {
&self.entities
}
pub fn count(&self) -> usize {
self.entities.len()
}
}
pub struct Archetype {
queries: usize,
check_entity: Box<dyn Fn(&EntityObject) -> Option<Vec<usize>> + Send + Sync>,
create_callback: Box<
dyn Fn(
&[&EntityObject],
)
-> Result<Box<dyn Fn(&mut Commands, &mut World) -> Result<()> + Send + Sync>>
+ Send
+ Sync,
>,
entities:
IndexMap<Vec<Entity>, Box<dyn Fn(&mut Commands, &mut World) -> Result<()> + Send + Sync>>,
}
impl Archetype {
pub fn add_entities(
&mut self,
new_entity: &EntityObject,
entity_objects: &IndexMap<Entity, EntityObject>,
) -> Result<()> {
let mut complying_entities: Vec<Vec<&EntityObject>> = vec![Vec::new(); self.queries];
match (self.check_entity)(new_entity) {
Some(complying_queries) => complying_queries
.into_iter()
.for_each(|q| complying_entities[q].push(new_entity)),
None => return Ok(()),
}
for old_entity in entity_objects.values() {
if let Some(complying_queries) = (self.check_entity)(old_entity) {
complying_queries
.into_iter()
.for_each(|q| complying_entities[q].push(old_entity));
}
}
// check if one of the queries could not be fullfilled
for queryable_entities in complying_entities.iter() {
if queryable_entities.is_empty() {
return Ok(());
}
}
for combinations in complying_entities.into_iter().multi_cartesian_product() {
let cb = (self.create_callback)(&combinations)?;
self.entities
.insert(combinations.iter().map(|e| e.as_entity()).collect(), cb);
}
Ok(())
}
pub fn remove_entity(&mut self, entity: Entity) {
while let Some(index) = self
.entities
.keys()
.position(|entities| entities.contains(&entity))
{
self.entities.swap_remove_index(index);
}
}
pub fn execute(&self, world: &mut World) -> Result<()> {
let mut commands = Commands::new(world.now());
for callback in self.entities.values() {
callback(&mut commands, world)?;
}
commands.apply_deferred(world)?;
Ok(())
}
pub fn entities(
&self,
) -> impl Iterator<
Item = (
&Vec<Entity>,
&Box<dyn Fn(&mut Commands, &mut World) -> Result<()> + Send + Sync>,
),
> {
self.entities.iter()
}
}
pub struct Updates {
updates: Vec<(u32, Archetype)>,
}
impl Default for Updates {
fn default() -> Self {
Self {
updates: Vec::new(),
}
}
}
impl Updates {
pub(crate) fn update(&mut self, world: &mut World) -> Result<()> {
self.updates
.iter()
.try_for_each(|(_, archetype)| archetype.execute(world))
}
pub(crate) fn add_entity(
&mut self,
entity_object: &EntityObject,
entities: &IndexMap<Entity, EntityObject>,
) -> Result<()> {
for (_, archetype) in self.updates.iter_mut() {
archetype.add_entities(entity_object, entities)?;
}
Ok(())
}
pub(crate) fn remove_entity(&mut self, entity: Entity) {
for (_, archetype) in self.updates.iter_mut() {
archetype.remove_entity(entity);
}
}
pub(crate) fn add(&mut self, priority: u32, archetype: Archetype) -> Result<()> {
self.updates.push((priority, archetype));
self.updates.sort_by_key(|(prio, _)| *prio);
Ok(())
}
}
#[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]);
implement_updates!(5, 10);