use std::fmt::Display;
use itertools::Itertools;
use super::*;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ArchetypeFilter {
components: ComponentSet,
not_components: ComponentSet,
}
impl ArchetypeFilter {
pub fn new() -> Self {
Self {
components: ComponentSet::new(),
not_components: ComponentSet::new(),
}
}
pub fn incl_ref(mut self, component: impl Into<ComponentDesc>) -> Self {
self.components.insert(component.into());
self
}
pub fn incl(self, component: impl Into<ComponentDesc>) -> Self {
self.incl_ref(component.into())
}
pub fn excl_ref(mut self, component: impl Into<ComponentDesc>) -> Self {
self.not_components.insert(component.into());
self
}
pub fn excl(self, component: impl Into<ComponentDesc>) -> Self {
self.excl_ref(component.into())
}
pub(crate) fn matches(&self, components: &ComponentSet) -> bool {
components.is_superset(&self.components) && components.is_disjoint(&self.not_components)
}
pub fn matches_entity(&self, world: &World, id: EntityId) -> bool {
if let Some(loc) = world.locs.get(&id) {
let arch = world
.archetypes
.get(loc.archetype)
.expect("Archetype doesn't exist");
self.matches(&arch.active_components)
} else {
false
}
}
pub fn matches_archetype(&self, arch: &Archetype) -> bool {
self.matches(&arch.active_components)
}
pub fn iter_archetypes<'a>(&self, world: &'a World) -> impl Iterator<Item = &'a Archetype> {
self.iter_by_archetypes(&world.archetypes)
}
fn iter_by_archetypes<'a>(
&self,
archetypes: &'a [Archetype],
) -> impl Iterator<Item = &'a Archetype> {
let f = self.clone();
archetypes
.iter()
.filter(move |arch| f.matches(&arch.active_components))
}
pub fn iter_entities<'a>(&self, world: &'a World) -> impl Iterator<Item = EntityAccessor> + 'a {
self.iter_by_archetypes(&world.archetypes).flat_map(|arch| {
arch.entity_indices_to_ids
.iter()
.map(move |&id| EntityAccessor::World { id })
})
}
}
impl Default for ArchetypeFilter {
fn default() -> Self {
Self::new()
}
}
pub trait ComponentQuery<'a>: Send + Sync {
type Data;
type DataMut;
type DataCloned;
fn write_component_ids(&self, set: &mut ComponentSet);
fn get_change_filtered(&self, out: &mut Vec<ComponentDesc>);
fn get_data(&self, world: &'a World, acc: &EntityAccessor) -> Self::Data;
fn get_data_mut(&self, world: &'a World, acc: &EntityAccessor) -> Self::DataMut;
fn get_data_cloned(&self, world: &'a World, acc: &EntityAccessor) -> Self::DataCloned;
}
pub trait ComponentsTupleAppend<T: ComponentValue> {
type Output;
fn append(&self, component: Component<T>) -> Self::Output;
}
macro_rules! tuple_impls {
( $( $name:ident )* ) => {
impl<'a, $($name: ComponentQuery<'a>),*> ComponentQuery<'a> for ($($name,)*) {
type Data = ($($name::Data,)*);
type DataMut = ($($name::DataMut,)*);
type DataCloned = ($($name::DataCloned,)*);
fn write_component_ids(&self, set: &mut ComponentSet) {
#[allow(non_snake_case)]
let ($($name,)*) = self;
$($name.write_component_ids(set);)*
}
fn get_change_filtered(&self, out: &mut Vec<ComponentDesc>) {
#[allow(non_snake_case)]
let ($($name,)*) = self;
$($name.get_change_filtered(out);)*
}
fn get_data(&self, world: &'a World, acc: &EntityAccessor) -> Self::Data {
#[allow(non_snake_case)]
let ($($name,)*) = self;
($($name.get_data(world, acc),)*)
}
fn get_data_mut(&self, world: &'a World, acc: &EntityAccessor) -> Self::DataMut {
#[allow(non_snake_case)]
let ($($name,)*) = self;
($($name.get_data_mut(world, acc),)*)
}
fn get_data_cloned(&self, world: &'a World, acc: &EntityAccessor) -> Self::DataCloned {
#[allow(non_snake_case)]
let ($($name,)*) = self;
($($name.get_data_cloned(world, acc),)*)
}
}
impl<T: ComponentValue, $($name: Clone),*> ComponentsTupleAppend<T> for ($($name,)*) {
type Output = ($($name,)* Component<T>);
fn append(&self, component: Component<T>) -> Self::Output {
#[allow(non_snake_case)]
let ($($name,)*) = self.clone();
($($name,)* component)
}
}
};
}
tuple_impls! { A }
tuple_impls! { A B }
tuple_impls! { A B C }
tuple_impls! { A B C D }
tuple_impls! { A B C D E }
tuple_impls! { A B C D E F }
tuple_impls! { A B C D E F G }
tuple_impls! { A B C D E F G H }
tuple_impls! { A B C D E F G H I }
impl<T: ComponentValue> Component<T> {
pub fn changed(self) -> ChangedQuery<T> {
ChangedQuery { component: self }
}
}
pub struct ChangedQuery<T: 'static> {
component: Component<T>,
}
impl<T> Clone for ChangedQuery<T> {
fn clone(&self) -> Self {
Self {
component: self.component,
}
}
}
impl<T> Debug for ChangedQuery<T> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.debug_struct("ChangedQuery")
.field("component", &self.component)
.finish()
}
}
impl<T> Copy for ChangedQuery<T> {}
impl<'a, T: ComponentValue> ComponentQuery<'a> for ChangedQuery<T> {
type Data = &'a T;
type DataMut = &'a mut T;
type DataCloned = T;
fn write_component_ids(&self, set: &mut ComponentSet) {
self.component.write_component_ids(set)
}
fn get_change_filtered(&self, out: &mut Vec<ComponentDesc>) {
out.push(self.component.desc())
}
fn get_data(&self, world: &'a World, acc: &EntityAccessor) -> Self::Data {
self.component.get_data(world, acc)
}
fn get_data_mut(&self, world: &'a World, acc: &EntityAccessor) -> Self::DataMut {
self.component.get_data_mut(world, acc)
}
fn get_data_cloned(&self, world: &'a World, acc: &EntityAccessor) -> Self::DataCloned {
self.component.get_data_cloned(world, acc)
}
}
impl<'a, T: ComponentValue> ComponentQuery<'a> for Component<T> {
type Data = &'a T;
type DataMut = &'a mut T;
type DataCloned = T;
fn write_component_ids(&self, set: &mut ComponentSet) {
set.insert(self.desc());
}
fn get_change_filtered(&self, _: &mut Vec<ComponentDesc>) {}
fn get_data(&self, world: &'a World, acc: &EntityAccessor) -> Self::Data {
acc.get(world, *self)
}
fn get_data_mut(&self, world: &'a World, acc: &EntityAccessor) -> Self::DataMut {
acc.get_mut(world, *self)
}
fn get_data_cloned(&self, world: &'a World, acc: &EntityAccessor) -> Self::DataCloned {
acc.get(world, *self).clone()
}
}
impl<'a> ComponentQuery<'a> for () {
type Data = ();
type DataMut = ();
type DataCloned = ();
fn write_component_ids(&self, _: &mut ComponentSet) {}
fn get_change_filtered(&self, _: &mut Vec<ComponentDesc>) {}
fn get_data(&self, _: &World, _: &EntityAccessor) -> Self::Data {}
fn get_data_mut(&self, _: &World, _: &EntityAccessor) -> Self::DataMut {}
fn get_data_cloned(&self, _: &World, _: &EntityAccessor) -> Self::DataCloned {}
}
impl<T: ComponentValue> ComponentsTupleAppend<T> for () {
type Output = (Component<T>,);
fn append(&self, component: Component<T>) -> Self::Output {
(component,)
}
}
#[derive(Debug, Clone)]
struct ArchetypesQueryState {
archetypes: Vec<usize>,
archetype_index: usize,
}
impl ArchetypesQueryState {
fn new() -> Self {
Self {
archetypes: Vec::new(),
archetype_index: 0,
}
}
fn update_archetypes(&mut self, world: &World, filter: &ArchetypeFilter) {
for i in self.archetype_index..world.archetypes.len() {
if filter.matches(&world.archetypes[i].active_components) {
self.archetypes.push(i);
}
}
self.archetype_index = world.archetypes.len();
}
}
#[derive(Debug, Clone)]
pub(super) struct ChangeReaders(SparseVec<SparseVec<FramedEventsReader<EntityId>>>);
impl ChangeReaders {
pub(super) fn get(&mut self, arch: usize, comp: usize) -> &mut FramedEventsReader<EntityId> {
let a = self.0.get_mut_or_insert_with(arch, SparseVec::new);
a.get_mut_or_insert_with(comp, FramedEventsReader::new)
}
}
#[derive(Debug, Clone)]
struct MoveinReaders(SparseVec<FramedEventsReader<EntityId>>);
impl MoveinReaders {
pub(super) fn get(&mut self, arch: usize) -> &mut FramedEventsReader<EntityId> {
self.0.get_mut_or_insert_with(arch, FramedEventsReader::new)
}
}
#[derive(Debug, Clone)]
struct MoveoutReaders(SparseVec<FramedEventsReader<(EntityId, Entity)>>);
impl MoveoutReaders {
pub(super) fn get(&mut self, arch: usize) -> &mut FramedEventsReader<(EntityId, Entity)> {
self.0.get_mut_or_insert_with(arch, FramedEventsReader::new)
}
}
#[derive(Debug, Clone)]
pub struct QueryState {
inited: bool,
pub(super) change_readers: ChangeReaders,
movein_readers: MoveinReaders,
moveout_readers: MoveoutReaders,
ticker: u64,
entered: HashSet<EntityId>,
world_version: u64,
entities: Vec<EntityAccessor>,
archetypes: ArchetypesQueryState,
}
impl QueryState {
pub fn new() -> Self {
Self {
inited: false,
change_readers: ChangeReaders(SparseVec::new()),
movein_readers: MoveinReaders(SparseVec::new()),
moveout_readers: MoveoutReaders(SparseVec::new()),
ticker: 0,
entered: Default::default(),
world_version: 0,
entities: Vec::new(),
archetypes: ArchetypesQueryState::new(),
}
}
pub(super) fn prepare_for_query(&mut self, world: &World) {
self.ticker = world.query_ticker.0.fetch_add(1, Ordering::SeqCst) + 1;
}
}
#[derive(Clone, Debug)]
pub enum QueryEvent {
Frame,
Changed { components: Vec<ComponentDesc> },
Spawned,
Despawned,
}
impl QueryEvent {
pub fn is_frame(&self) -> bool {
matches!(self, QueryEvent::Frame)
}
pub fn is_spawned(&self) -> bool {
matches!(self, QueryEvent::Spawned)
}
pub fn is_despawned(&self) -> bool {
matches!(self, QueryEvent::Despawned)
}
}
#[derive(Debug, Clone)]
pub struct Query {
pub filter: ArchetypeFilter,
pub event: QueryEvent,
}
impl Query {
pub fn new(filter: ArchetypeFilter) -> Self {
Self {
filter,
event: QueryEvent::Frame,
}
}
pub fn all() -> Self {
Self::new(ArchetypeFilter::new())
}
pub fn any_changed(components: Vec<ComponentDesc>) -> Self {
let mut q = Self::all();
for comp in components {
q = q.when_changed_ref(comp);
}
q
}
fn new_for_typed_query(
component_ids: ComponentSet,
changed_components: Vec<ComponentDesc>,
) -> Self {
Query {
filter: ArchetypeFilter {
components: component_ids,
not_components: ComponentSet::new(),
},
event: if !changed_components.is_empty() {
QueryEvent::Changed {
components: changed_components,
}
} else {
QueryEvent::Frame
},
}
}
pub fn when_changed_ref(mut self, component: impl Into<ComponentDesc>) -> Self {
if let QueryEvent::Changed { components } = &mut self.event {
components.push(component.into());
} else {
self.event = QueryEvent::Changed {
components: vec![component.into()],
};
}
self
}
pub fn when_changed(self, component: impl Into<ComponentDesc>) -> Self {
self.when_changed_ref(component)
}
pub fn incl_ref(mut self, component: impl Into<ComponentDesc>) -> Self {
self.filter = self.filter.incl_ref(component.into());
self
}
pub fn incl(self, component: impl Into<ComponentDesc>) -> Self {
self.incl_ref(component)
}
pub fn excl_ref(mut self, component: impl Into<ComponentDesc>) -> Self {
self.filter = self.filter.excl_ref(component.into());
self
}
pub fn excl(self, component: impl Into<ComponentDesc>) -> Self {
self.excl_ref(component)
}
pub fn optional_changed_ref(mut self, component: impl Into<ComponentDesc>) -> Self {
let event = std::mem::replace(&mut self.event, QueryEvent::Frame);
self.event = match event {
QueryEvent::Frame => QueryEvent::Changed {
components: vec![component.into()],
},
QueryEvent::Changed { mut components } => {
components.push(component.into());
QueryEvent::Changed { components }
}
_ => {
panic!("optional_changed can only be applied to Frame or Change queries (not Spawn or Despawn queries)")
}
};
self
}
pub fn optional_changed(self, component: impl Into<ComponentDesc>) -> Self {
self.optional_changed_ref(component.into())
}
pub fn spawned(mut self) -> Self {
self.event = QueryEvent::Spawned;
self
}
pub fn despawned(mut self) -> Self {
self.event = QueryEvent::Despawned;
self
}
pub fn filter(mut self, filter: &ArchetypeFilter) -> Self {
self.filter.components.union_with(&filter.components);
self.filter
.not_components
.union_with(&filter.not_components);
self
}
fn get_changed(&self, world: &World, state: &mut QueryState, components: &Vec<ComponentDesc>) {
if !state.inited && !world.ignore_query_inits {
for arch in state
.archetypes
.archetypes
.iter()
.map(|i| &world.archetypes[*i])
{
for comp in components {
if let Some(arch_comp) = arch.components.get(comp.index() as _) {
let events = &*arch_comp.changes.borrow();
let read = state.change_readers.get(arch.id, comp.index() as _);
read.move_to_end(events);
}
}
}
return;
}
for arch in state
.archetypes
.archetypes
.iter()
.map(|i| &world.archetypes[*i])
{
for comp in components {
if let Some(arch_comp) = arch.components.get(comp.index() as _) {
let read = state.change_readers.get(arch.id, comp.index() as _);
let events = &*arch_comp.changes.borrow();
for (_, &entity_id) in read.iter(events) {
if let Some(loc) = world.locs.get(&entity_id) {
if loc.archetype == arch.id
&& arch_comp.get_content_version(loc.index) > state.world_version
&& arch.query_mark(loc.index, state.ticker)
{
state.entities.push(EntityAccessor::World { id: entity_id });
}
}
}
}
}
}
}
fn get_spawned(&self, world: &World, state: &mut QueryState) {
if self.init_state_event_readers(world, state) {
state.entities.extend(self.filter.iter_entities(world));
for ea in state.entities.iter() {
let id = ea.id();
state.entered.insert(id);
}
return;
}
state.entities.clear();
for arch in state
.archetypes
.archetypes
.iter()
.map(|i| &world.archetypes[*i])
{
let read = state.movein_readers.get(arch.id);
for (_, id) in read.iter(&arch.movein_events) {
if let Some(loc) = world.locs.get(id) {
if loc.archetype == arch.id && state.entered.insert(*id) {
let process =
world.archetypes[loc.archetype].query_mark(loc.index, state.ticker);
if process {
state.entities.push(EntityAccessor::World { id: *id });
}
}
}
}
let read = state.moveout_readers.get(arch.id);
for (_, (id, _)) in read.iter(&arch.moveout_events) {
if !self.filter.matches_entity(world, *id) {
state.entered.remove(id);
}
}
}
}
fn get_despawned(&self, world: &World, state: &mut QueryState) {
if self.init_state_event_readers(world, state) {
return;
}
state.entities.clear();
for arch in state
.archetypes
.archetypes
.iter()
.map(|i| &world.archetypes[*i])
{
let read = state.moveout_readers.get(arch.id);
for (event_id, (id, _)) in read.iter(&arch.moveout_events) {
let next_matched = if let Some(loc) = world.locs.get(id) {
self.filter
.matches(&world.archetypes[loc.archetype].active_components)
} else {
false
};
if !next_matched {
state.entities.push(EntityAccessor::Despawned {
id: *id,
archetype: arch.id,
event_id,
});
}
}
}
}
fn init_state_event_readers(&self, world: &World, state: &mut QueryState) -> bool {
if state.inited || world.ignore_query_inits {
return false;
}
for arch in state
.archetypes
.archetypes
.iter()
.map(|i| &world.archetypes[*i])
{
let read_in = state.movein_readers.get(arch.id);
read_in.move_to_end(&arch.movein_events);
let read_out = state.moveout_readers.get(arch.id);
read_out.move_to_end(&arch.moveout_events);
}
true
}
pub fn iter<'a>(
&self,
world: &'a World,
mut state: Option<&'a mut QueryState>,
) -> Box<dyn Iterator<Item = EntityAccessor> + 'a> {
if let Some(state) = &mut state {
state.archetypes.update_archetypes(world, &self.filter);
}
if let QueryEvent::Frame = &self.event {
if let Some(state) = state {
return Box::new(state.archetypes.archetypes.iter().flat_map(|i| {
world.archetypes[*i]
.entity_indices_to_ids
.iter()
.map(move |&id| EntityAccessor::World { id })
}));
} else {
return Box::new(self.filter.iter_entities(world));
}
}
let state = state.expect("Spawn/despawn/change queries must have a query state");
if !self.event.is_frame() {
state.prepare_for_query(world);
}
match &self.event {
QueryEvent::Changed { components } => {
self.get_spawned(world, state);
self.get_changed(world, state, components);
}
QueryEvent::Spawned => self.get_spawned(world, state),
QueryEvent::Despawned => self.get_despawned(world, state),
_ => unreachable!(),
};
state.inited = true;
state.world_version = world.version();
Box::new(state.entities.iter().copied())
}
pub fn to_system<
F: Fn(&Self, &mut World, &mut QueryState, &E) + Send + Sync + 'static,
E: 'static,
>(
self,
update: F,
) -> Box<dyn System<E> + Sync + Send> {
self.to_system_with_name("Unknown system", update)
}
pub fn to_system_with_name<
F: Fn(&Self, &mut World, &mut QueryState, &E) + Send + Sync + 'static,
E: 'static,
>(
self,
name: &'static str,
update: F,
) -> Box<dyn System<E> + Sync + Send> {
let mut state = QueryState::new();
Box::new(FnSystem(Box::new(move |world, event| {
ambient_profiling::scope!(name);
update(&self, world, &mut state, event);
})))
}
pub fn with_commands<F, E>(self, update: F) -> Box<dyn System<E>>
where
F: Fn(&Self, &mut World, Option<&mut QueryState>, &E, &mut Commands)
+ Send
+ Sync
+ 'static,
E: 'static,
{
let mut state = QueryState::new();
let mut commands = Commands::new();
Box::new(FnSystem(Box::new(move |world, event| {
update(&self, world, Some(&mut state), event, &mut commands);
commands.soft_apply(world);
})))
}
fn add_component(&mut self, query: &Self, component: ComponentDesc) {
self.filter = query.filter.clone().incl(component);
if query.event.is_spawned() {
self.event = QueryEvent::Spawned;
} else if query.event.is_despawned() {
self.event = QueryEvent::Despawned;
}
}
}
#[derive(Debug, Clone, Copy)]
pub enum EntityAccessor {
World {
id: EntityId,
},
Despawned {
id: EntityId,
archetype: usize,
event_id: DBEventId,
},
}
impl EntityAccessor {
pub fn id(&self) -> EntityId {
match self {
Self::World { id } => *id,
Self::Despawned { id, .. } => *id,
}
}
pub fn get<'a, T: ComponentValue>(&self, world: &'a World, component: Component<T>) -> &'a T {
match self {
Self::World { id } => world.get_ref(*id, component).unwrap(),
Self::Despawned {
archetype,
event_id,
..
} => world.archetypes[*archetype]
.moveout_events
.get(*event_id)
.unwrap()
.1
.get_ref(component)
.unwrap(),
}
}
pub fn get_mut<'a, T: ComponentValue>(
&self,
world: &'a World,
component: Component<T>,
) -> &'a mut T {
match self {
Self::World { id } => world.get_mut_unsafe(*id, component).unwrap(),
Self::Despawned { .. } => panic!("Can't mutate despawned entities"),
}
}
}
pub fn query<'a, R: ComponentQuery<'a> + Clone + 'static>(read_components: R) -> TypedReadQuery<R> {
TypedReadQuery::new(read_components)
}
pub fn query_mut<
'a,
RW: ComponentQuery<'a> + Clone + 'static,
R: ComponentQuery<'a> + Clone + 'static,
>(
read_write_components: RW,
read_components: R,
) -> TypedReadWriteQuery<RW, R> {
TypedReadWriteQuery::new(read_write_components, read_components)
}
#[derive(Clone)]
pub struct TypedReadQuery<R> {
read_components: R,
pub query: Query,
}
impl<R> Debug for TypedReadQuery<R>
where
R: Debug,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("TypedReadQuery")
.field("read_components", &self.read_components)
.finish_non_exhaustive()
}
}
impl<'a, R: ComponentQuery<'a> + Clone + 'static> TypedReadQuery<R> {
pub fn new(read_components: R) -> Self {
let mut component_ids = ComponentSet::new();
read_components.write_component_ids(&mut component_ids);
let mut changed_components = Vec::new();
read_components.get_change_filtered(&mut changed_components);
Self {
query: Query::new_for_typed_query(component_ids, changed_components),
read_components,
}
}
pub fn read<T: ComponentValue>(
&self,
component: Component<T>,
) -> TypedReadQuery<<R as ComponentsTupleAppend<T>>::Output>
where
R: ComponentsTupleAppend<T>,
<R as ComponentsTupleAppend<T>>::Output: ComponentQuery<'a> + Clone + 'static,
{
let mut q = TypedReadQuery::new(self.read_components.append(component));
q.query.add_component(&self.query, component.desc());
q
}
pub fn filter(mut self, filter: &ArchetypeFilter) -> Self {
self.query = self.query.filter(filter);
self
}
pub fn incl(mut self, component: impl Into<ComponentDesc>) -> Self {
self.query.filter = self.query.filter.incl(component.into());
self
}
pub fn excl(mut self, component: impl Into<ComponentDesc>) -> Self {
self.query.filter = self.query.filter.excl(component.into());
self
}
pub fn optional_changed(mut self, component: impl Into<ComponentDesc>) -> Self {
self.query = self.query.optional_changed(component.into());
self
}
pub fn spawned(mut self) -> Self {
self.query.event = QueryEvent::Spawned;
self
}
pub fn despawned(mut self) -> Self {
self.query.event = QueryEvent::Despawned;
self
}
pub fn iter(
&self,
world: &'a World,
state: Option<&'a mut QueryState>,
) -> impl Iterator<Item = (EntityId, <R as ComponentQuery<'a>>::Data)> + 'a {
let r = self.read_components.clone();
self.query
.iter(world, state)
.map(move |acc| (acc.id(), r.get_data(world, &acc)))
}
pub fn iter_cloned(
&self,
world: &'a World,
state: Option<&'a mut QueryState>,
) -> impl Iterator<Item = (EntityId, <R as ComponentQuery<'a>>::DataCloned)> + 'a {
let r = self.read_components.clone();
self.query
.iter(world, state)
.map(move |acc| (acc.id(), r.get_data_cloned(world, &acc)))
}
pub fn collect_ids(
&self,
world: &'a World,
state: Option<&'a mut QueryState>,
) -> Vec<EntityId> {
self.query
.iter(world, state)
.map(move |acc| acc.id())
.collect_vec()
}
pub fn collect_cloned(
&self,
world: &'a World,
state: Option<&'a mut QueryState>,
) -> Vec<(EntityId, <R as ComponentQuery<'a>>::DataCloned)> {
self.iter_cloned(world, state).collect_vec()
}
pub fn read_one_cloned(
&self,
world: &'a World,
state: Option<&'a mut QueryState>,
) -> Option<(EntityId, <R as ComponentQuery<'a>>::DataCloned)> {
self.iter_cloned(world, state).next()
}
pub fn to_system<
F: FnMut(&Self, &mut World, Option<&mut QueryState>, &E) + Send + Sync + 'static,
E: 'static,
>(
self,
update: F,
) -> DynSystem<E> {
self.to_system_with_name("Unknown System", update)
}
pub fn to_system_with_name<
F: FnMut(&Self, &mut World, Option<&mut QueryState>, &E) + Send + Sync + 'static,
E: 'static,
>(
self,
name: &'static str,
mut update: F,
) -> DynSystem<E> {
let mut state = QueryState::new();
Box::new(FnSystem(Box::new(move |world, event| {
ambient_profiling::scope!(name);
update(&self, world, Some(&mut state), event);
})))
}
pub fn with_commands<F, E>(self, update: F) -> DynSystem<E>
where
F: Fn(&Self, &mut World, Option<&mut QueryState>, &E, &mut Commands)
+ Send
+ Sync
+ 'static,
E: 'static,
{
let mut state = QueryState::new();
let mut commands = Commands::new();
Box::new(FnSystem(Box::new(move |world, event| {
update(&self, world, Some(&mut state), event, &mut commands);
commands.soft_apply(world);
})))
}
}
pub struct TypedReadWriteQuery<RW, R> {
read_write_components: RW,
read_components: R,
query: Query,
}
impl<'a, RW: ComponentQuery<'a> + Clone + 'static, R: ComponentQuery<'a> + Clone + 'static>
TypedReadWriteQuery<RW, R>
{
pub fn new(read_write_components: RW, read_components: R) -> Self {
let mut write_set = ComponentSet::new();
let mut read_set = ComponentSet::new();
read_write_components.write_component_ids(&mut write_set);
read_components.write_component_ids(&mut read_set);
if let Some(id) = write_set.intersection(&read_set).next() {
panic!("Non disjoint query component: {id}")
}
let mut component_ids = ComponentSet::new();
read_write_components.write_component_ids(&mut component_ids);
read_components.write_component_ids(&mut component_ids);
let mut changed_components = Vec::new();
read_write_components.get_change_filtered(&mut changed_components);
read_components.get_change_filtered(&mut changed_components);
Self {
query: Query::new_for_typed_query(component_ids, changed_components),
read_write_components,
read_components,
}
}
pub fn read_write<T: ComponentValue>(
&self,
component: Component<T>,
) -> TypedReadWriteQuery<<RW as ComponentsTupleAppend<T>>::Output, R>
where
RW: ComponentsTupleAppend<T>,
<RW as ComponentsTupleAppend<T>>::Output: ComponentQuery<'a> + Clone + 'static,
{
let mut q = TypedReadWriteQuery::new(
self.read_write_components.append(component),
self.read_components.clone(),
);
q.query.add_component(&self.query, component.desc());
q
}
pub fn read<T: ComponentValue>(
&self,
component: Component<T>,
) -> TypedReadWriteQuery<RW, <R as ComponentsTupleAppend<T>>::Output>
where
R: ComponentsTupleAppend<T>,
<R as ComponentsTupleAppend<T>>::Output: ComponentQuery<'a> + Clone + 'static,
{
let mut q = TypedReadWriteQuery::new(
self.read_write_components.clone(),
self.read_components.append(component),
);
q.query.add_component(&self.query, component.desc());
q
}
pub fn filter(mut self, filter: &ArchetypeFilter) -> Self {
self.query.filter.components.union_with(&filter.components);
self.query
.filter
.not_components
.union_with(&filter.not_components);
self
}
pub fn incl<T: ComponentValue>(mut self, component: Component<T>) -> Self {
self.query.filter = self.query.filter.incl(component.desc());
self
}
pub fn excl<T: ComponentValue>(mut self, component: Component<T>) -> Self {
self.query.filter = self.query.filter.excl(component.desc());
self
}
pub fn optional_changed<T: ComponentValue>(mut self, component: Component<T>) -> Self {
self.query = self.query.optional_changed(component.desc());
self
}
pub fn spawned(mut self) -> Self {
self.query.event = QueryEvent::Spawned;
self
}
pub fn despawned(mut self) -> Self {
self.query.event = QueryEvent::Despawned;
self
}
pub fn iter(
&self,
world: &'a mut World,
state: Option<&'a mut QueryState>,
) -> impl Iterator<
Item = (
EntityId,
<RW as ComponentQuery<'a>>::DataMut,
<R as ComponentQuery<'a>>::Data,
),
> + 'a {
let rw = self.read_write_components.clone();
let r = self.read_components.clone();
let world = &*world;
self.query.iter(world, state).map(move |acc| {
(
acc.id(),
rw.get_data_mut(world, &acc),
r.get_data(world, &acc),
)
})
}
pub fn to_system<
F: Fn(&Self, &mut World, Option<&mut QueryState>, &E) + Send + Sync + 'static,
E: 'static,
>(
self,
update: F,
) -> DynSystem<E> {
self.to_system_with_name("Default", update)
}
pub fn to_system_with_name<
F: Fn(&Self, &mut World, Option<&mut QueryState>, &E) + Send + Sync + 'static,
E: 'static,
>(
self,
name: &'static str,
update: F,
) -> DynSystem<E> {
let mut state = QueryState::new();
Box::new(FnSystem(Box::new(move |world, event| {
ambient_profiling::scope!(name);
update(&self, world, Some(&mut state), event);
})))
}
pub fn with_commands<F, E>(self, update: F) -> DynSystem<E>
where
F: Fn(&Self, &mut World, Option<&mut QueryState>, &E, &mut Commands)
+ Sync
+ Send
+ 'static,
E: 'static,
{
let mut state = QueryState::new();
let mut commands = Commands::new();
Box::new(FnSystem(Box::new(move |world, event| {
update(&self, world, Some(&mut state), event, &mut commands);
commands.soft_apply(world);
}))) as Box<dyn System<E> + Send + Sync + 'static>
}
}
pub struct FrameEvent;
pub trait System<E = FrameEvent>: Send + std::fmt::Debug {
fn run(&mut self, world: &mut World, event: &E);
}
pub struct FnSystem<E = FrameEvent>(Box<dyn FnMut(&mut World, &E) + Sync + Send>);
impl<E> FnSystem<E> {
pub fn new<F>(func: F) -> Self
where
F: FnMut(&mut World, &E) + Send + Sync + 'static,
{
Self(Box::new(func))
}
}
impl<E> System<E> for FnSystem<E> {
fn run(&mut self, world: &mut World, event: &E) {
self.0(world, event);
}
}
impl<E> std::fmt::Debug for FnSystem<E> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "FnSystem")
}
}
enum Label {
Static(&'static str),
Dynamic(String),
}
impl Display for Label {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(match self {
Label::Static(s) => s,
Label::Dynamic(s) => s,
})
}
}
pub type DynSystem<E = FrameEvent> = Box<dyn System<E> + Send + Sync>;
pub struct SystemGroup<E = FrameEvent>(Label, Vec<DynSystem<E>>);
impl<E> SystemGroup<E> {
pub fn new(label: &'static str, systems: Vec<DynSystem<E>>) -> Self {
Self(Label::Static(label), systems)
}
pub fn new_with_dynamic_label(label: String, systems: Vec<DynSystem<E>>) -> Self {
Self(Label::Dynamic(label), systems)
}
pub fn add(&mut self, system: DynSystem<E>) -> &mut Self {
self.1.push(system);
self
}
}
impl<E> System<E> for SystemGroup<E> {
fn run(&mut self, world: &mut World, event: &E) {
let mut execute = || {
for system in self.1.iter_mut() {
system.run(world, event);
}
};
match &self.0 {
Label::Static(s) => {
ambient_profiling::scope!(s);
let _span = tracing::debug_span!("SystemGroup::run", label = s).entered();
execute();
}
Label::Dynamic(s) => {
ambient_profiling::scope!("Dynamic", &s);
let _span = tracing::debug_span!("SystemGroup::run", label = s).entered();
execute();
}
}
}
}
impl<E> std::fmt::Debug for SystemGroup<E> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "SystemGroup({}, _)", self.0)
}
}
pub fn ensure_has_component<X: ComponentValue + 'static, T: ComponentValue + Clone + 'static>(
if_has_component: Component<X>,
ensure_this_component_too: Component<T>,
value: T,
) -> DynSystem {
Query::new(
ArchetypeFilter::new()
.incl(if_has_component)
.excl(ensure_this_component_too),
)
.to_system_with_name("ensure_has_component", move |q, world, qs, _| {
let ids = q.iter(world, Some(qs)).map(|ea| ea.id()).collect_vec();
for id in ids {
world
.add_component(id, ensure_this_component_too, value.clone())
.unwrap();
}
})
}
pub fn ensure_has_component_with_default<
X: ComponentValue + 'static,
T: ComponentValue + Default + Clone + 'static,
>(
if_has_component: Component<X>,
ensure_this_component_too: Component<T>,
) -> DynSystem {
ensure_has_component(if_has_component, ensure_this_component_too, T::default())
}
pub fn ensure_has_component_with_make_default<
X: ComponentValue + 'static,
T: ComponentValue + Clone + 'static,
>(
if_has_component: Component<X>,
ensure_this_component_too: Component<T>,
) -> DynSystem {
let default = Entity::from_iter([ensure_this_component_too
.attribute::<MakeDefault>()
.unwrap()
.make_default(ensure_this_component_too.desc())]);
query(if_has_component)
.excl(ensure_this_component_too)
.to_system_with_name(
"ensure_has_component_with_make_default",
move |q, world, qs, _| {
for (id, _) in q.collect_cloned(world, qs) {
world.add_components(id, default.clone()).unwrap();
}
},
)
}