Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

50 Allow systems to access components from multiple entities at once #83

Merged
merged 7 commits into from
Apr 3, 2023
73 changes: 69 additions & 4 deletions crates/ecs/src/systems/mod.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
//! Systems are one of the core parts of ECS, which are responsible for operating on data
//! in the form of [`crate::Entity`]s and components.
//! in the form of [`Entity`]s and components.

pub mod iteration;

use crate::systems::iteration::SequentiallyIterable;
use crate::{
intersection_of_multiple_sets, ArchetypeIndex, ReadComponentVec, World, WorldError,
intersection_of_multiple_sets, ArchetypeIndex, Entity, ReadComponentVec, World, WorldError,
WriteComponentVec,
};
use paste::paste;
Expand Down Expand Up @@ -254,14 +254,25 @@ pub trait SystemParameter: Send + Sync + Sized {

/// Perform a filter operation on a set of archetype indices.
/// The `universe` is a set with all archetype indices used by the `base_signature`.
fn filter(universe: &HashSet<ArchetypeIndex>, _world: &World) -> HashSet<ArchetypeIndex> {
fn filter(universe: &HashSet<ArchetypeIndex>, world: &World) -> HashSet<ArchetypeIndex> {
let _ = world;
universe.clone()
}

/// If a system with this [`SystemParameter`] can use intra-system parallelization.
fn support_parallelization() -> bool {
true
}

/// Modify `borrowed` so the next fetched parameter will be the entity at the requested
/// archetype and component index.
fn set_archetype_and_component_index(
borrowed: &mut Self::BorrowedData<'_>,
borrowed_archetype_index: BorrowedArchetypeIndex,
component_index: ComponentIndex,
) {
let (_, _, _) = (borrowed, borrowed_archetype_index, component_index);
}
EdvinNilsson marked this conversation as resolved.
Show resolved Hide resolved
}

trait SystemParameterFunction<Parameters: SystemParameters>: 'static {}
Expand Down Expand Up @@ -339,6 +350,18 @@ impl<Component: Debug + Send + Sync + 'static + Sized> SystemParameter for Read<
fn base_signature() -> Option<TypeId> {
Some(TypeId::of::<Component>())
}

fn set_archetype_and_component_index(
borrowed: &mut Self::BorrowedData<'_>,
borrowed_archetype_index: BorrowedArchetypeIndex,
component_index: ComponentIndex,
) {
let (ref mut current_archetype, archetypes) = borrowed;
*current_archetype = borrowed_archetype_index;
if let Some((old_component_index, _)) = archetypes.get_mut(*current_archetype) {
*old_component_index = component_index;
}
}
}

impl<Component: Debug + Send + Sync + 'static + Sized> SystemParameter for Write<'_, Component> {
Expand Down Expand Up @@ -397,6 +420,18 @@ impl<Component: Debug + Send + Sync + 'static + Sized> SystemParameter for Write
fn base_signature() -> Option<TypeId> {
Some(TypeId::of::<Component>())
}

fn set_archetype_and_component_index(
borrowed: &mut Self::BorrowedData<'_>,
borrowed_archetype_index: BorrowedArchetypeIndex,
component_index: ComponentIndex,
) {
let (ref mut current_archetype, archetypes) = borrowed;
*current_archetype = borrowed_archetype_index;
if let Some((old_component_index, _)) = archetypes.get_mut(*current_archetype) {
*old_component_index = component_index;
}
}
}

/// A read-only access to a component of the given type.
Expand Down Expand Up @@ -438,12 +473,19 @@ impl<'a, Component> DerefMut for Write<'a, Component> {
/// println!("The largest momentum of all entities is {largest_momentum} kg*m/s.");
/// }
/// ```
#[derive(Debug)]
pub struct Query<'world, P: SystemParameters> {
phantom: PhantomData<P>,
world: &'world World,
}

impl<'world, P: Debug + SystemParameters> Debug for Query<'world, P> {
fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
fmt.debug_struct("Query")
.field("phantom", &self.phantom)
.finish()
}
}

/// Iterator for [`Query`].
#[derive(Debug)]
pub struct QueryIterator<'components, P: SystemParameters> {
Expand Down Expand Up @@ -514,6 +556,29 @@ macro_rules! impl_system_parameter_function {
}
}

impl<'a, $([<P$parameter>]: SystemParameter,)*> Query<'a, ($([<P$parameter>],)*)> {
/// Get the queried data from a specific entity.
pub fn get_entity(&self, entity: Entity) -> Option<($([<P$parameter>],)*)> {
let archetype_index = self.world.entity_to_archetype_index.get(&entity)?;
let archetype = self.world.archetypes.get(*archetype_index)?;
let component_index = archetype.entity_to_component_index.get(&entity)?;

$(let mut [<borrowed_$parameter>] = [<P$parameter>]::borrow(self.world, &[*archetype_index])
.expect("`borrow` should work if the archetypes are in a valid state");)*

$([<P$parameter>]::set_archetype_and_component_index(&mut [<borrowed_$parameter>], 0, *component_index);)*

unsafe {
if let ($(Some(Some([<parameter_$parameter>])),)*) = (
$([<P$parameter>]::fetch_parameter(&mut [<borrowed_$parameter>]),)*
) {
return Some(($([<parameter_$parameter>],)*));
}
}
None
}
}

impl<'a, $([<P$parameter>]: SystemParameter,)*> IntoIterator for Query<'a, ($([<P$parameter>],)*)> {
type Item = ($([<P$parameter>],)*);
type IntoIter = QueryIterator<'a, ($([<P$parameter>],)*)>;
Expand Down