Skip to content

Commit

Permalink
relations
Browse files Browse the repository at this point in the history
  • Loading branch information
BoxyUwU committed Jun 20, 2021
1 parent 00d8d5d commit ee94150
Show file tree
Hide file tree
Showing 34 changed files with 4,169 additions and 898 deletions.
4 changes: 4 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,10 @@ path = "examples/diagnostics/custom_diagnostic.rs"
name = "ecs_guide"
path = "examples/ecs/ecs_guide.rs"

[[example]]
name = "relations_grouping"
path = "examples/ecs/relations_grouping.rs"

[[example]]
name = "change_detection"
path = "examples/ecs/change_detection.rs"
Expand Down
4 changes: 2 additions & 2 deletions crates/bevy_core/src/time/fixed_timestep.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::Time;
use bevy_ecs::{
archetype::{Archetype, ArchetypeComponentId},
component::ComponentId,
component::RelationKindId,
query::Access,
schedule::ShouldRun,
system::{IntoSystem, Local, Res, ResMut, System, SystemId},
Expand Down Expand Up @@ -160,7 +160,7 @@ impl System for FixedTimestep {
self.internal_system.archetype_component_access()
}

fn component_access(&self) -> &Access<ComponentId> {
fn component_access(&self) -> &Access<RelationKindId> {
self.internal_system.component_access()
}

Expand Down
1 change: 1 addition & 0 deletions crates/bevy_ecs/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ bevy_tasks = { path = "../bevy_tasks", version = "0.5.0" }
bevy_utils = { path = "../bevy_utils", version = "0.5.0" }
bevy_ecs_macros = { path = "macros", version = "0.5.0" }

smallvec = { version = "1.4", features = ["serde"] }
async-channel = "1.4"
bitflags = "1.2"
fixedbitset = "0.4"
Expand Down
14 changes: 12 additions & 2 deletions crates/bevy_ecs/macros/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -258,7 +258,17 @@ pub fn impl_query_set(_input: TokenStream) -> TokenStream {
fn new_archetype(&mut self, archetype: &Archetype, system_meta: &mut SystemMeta) {
let (#(#query,)*) = &mut self.0;
#(
#query.new_archetype(archetype);
for (relation_filter, cache) in #query.relation_filter_accesses.iter_mut() {
QueryState::<#query, #filter>::new_archetype(
&#query.fetch_state,
&#query.filter_state,
&mut #query.archetype_component_access,
&*relation_filter,
cache,
archetype
);
}

system_meta
.archetype_component_access
.extend(&#query.archetype_component_access);
Expand All @@ -280,7 +290,7 @@ pub fn impl_query_set(_input: TokenStream) -> TokenStream {
world: &'a World,
change_tick: u32,
) -> Self::Item {
let (#(#query,)*) = &state.0;
let (#(#query,)*) = &mut state.0;
QuerySet((#(Query::new(world, #query, system_meta.last_change_tick, change_tick),)*))
}
}
Expand Down
149 changes: 105 additions & 44 deletions crates/bevy_ecs/src/archetype.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
use bevy_utils::HashMap;
use bevy_utils::StableHashMap;

use crate::{
bundle::BundleId,
component::{ComponentId, StorageType},
component::{RelationKindId, StorageType},
entity::{Entity, EntityLocation},
storage::{Column, SparseArray, SparseSet, SparseSetIndex, TableId},
};
use std::{
borrow::Cow,
collections::HashMap,
hash::Hash,
ops::{Index, IndexMut},
};
Expand Down Expand Up @@ -124,54 +126,73 @@ pub struct Archetype {
entities: Vec<Entity>,
edges: Edges,
table_info: TableInfo,
table_components: Cow<'static, [ComponentId]>,
sparse_set_components: Cow<'static, [ComponentId]>,
pub(crate) unique_components: SparseSet<ComponentId, Column>,
pub(crate) components: SparseSet<ComponentId, ArchetypeComponentInfo>,
table_components: Cow<'static, [(RelationKindId, Option<Entity>)]>,
sparse_set_components: Cow<'static, [(RelationKindId, Option<Entity>)]>,
pub(crate) unique_components: SparseSet<RelationKindId, Column>,
pub(crate) components: SparseSet<RelationKindId, ArchetypeComponentInfo>,
pub(crate) relations: SparseSet<RelationKindId, StableHashMap<Entity, ArchetypeComponentInfo>>,
}

impl Archetype {
pub fn new(
id: ArchetypeId,
table_id: TableId,
table_components: Cow<'static, [ComponentId]>,
sparse_set_components: Cow<'static, [ComponentId]>,
table_components: Cow<'static, [(RelationKindId, Option<Entity>)]>,
sparse_set_components: Cow<'static, [(RelationKindId, Option<Entity>)]>,
table_archetype_components: Vec<ArchetypeComponentId>,
sparse_set_archetype_components: Vec<ArchetypeComponentId>,
) -> Self {
// FIXME(Relationships) sort out this capacity weirdness
let mut components =
SparseSet::with_capacity(table_components.len() + sparse_set_components.len());
for (component_id, archetype_component_id) in
let mut relations = SparseSet::new();
for ((kind_id, target), archetype_component_id) in
table_components.iter().zip(table_archetype_components)
{
components.insert(
*component_id,
ArchetypeComponentInfo {
storage_type: StorageType::Table,
archetype_component_id,
},
);
let arch_comp_info = ArchetypeComponentInfo {
storage_type: StorageType::Table,
archetype_component_id,
};

match target {
None => {
components.insert(*kind_id, arch_comp_info);
}
Some(target) => {
let set = relations.get_or_insert_with(*kind_id, StableHashMap::default);
set.insert(*target, arch_comp_info);
}
};
}

for (component_id, archetype_component_id) in sparse_set_components
for ((kind_id, target), archetype_component_id) in sparse_set_components
.iter()
.zip(sparse_set_archetype_components)
{
components.insert(
*component_id,
ArchetypeComponentInfo {
storage_type: StorageType::SparseSet,
archetype_component_id,
},
);
let arch_comp_info = ArchetypeComponentInfo {
storage_type: StorageType::SparseSet,
archetype_component_id,
};

match target {
None => {
components.insert(*kind_id, arch_comp_info);
}
Some(target) => {
let set = relations.get_or_insert_with(*kind_id, StableHashMap::default);
set.insert(*target, arch_comp_info);
}
};
}

Self {
id,
table_info: TableInfo {
id: table_id,
entity_rows: Default::default(),
},
components,
relations,
table_components,
sparse_set_components,
unique_components: SparseSet::new(),
Expand Down Expand Up @@ -201,28 +222,38 @@ impl Archetype {
}

#[inline]
pub fn table_components(&self) -> &[ComponentId] {
pub fn table_components(&self) -> &[(RelationKindId, Option<Entity>)] {
&self.table_components
}

#[inline]
pub fn sparse_set_components(&self) -> &[ComponentId] {
pub fn sparse_set_components(&self) -> &[(RelationKindId, Option<Entity>)] {
&self.sparse_set_components
}

#[inline]
pub fn unique_components(&self) -> &SparseSet<ComponentId, Column> {
pub fn unique_components(&self) -> &SparseSet<RelationKindId, Column> {
&self.unique_components
}

#[inline]
pub fn unique_components_mut(&mut self) -> &mut SparseSet<ComponentId, Column> {
pub fn unique_components_mut(&mut self) -> &mut SparseSet<RelationKindId, Column> {
&mut self.unique_components
}

// FIXME(Relationships) this also yields relations which feels weird but also needed
#[inline]
pub fn components(&self) -> impl Iterator<Item = ComponentId> + '_ {
self.components.indices()
pub fn components(&self) -> impl Iterator<Item = (RelationKindId, Option<Entity>)> + '_ {
self.components
.indices()
.map(|kind| (kind, None))
.chain(self.relations.indices().flat_map(move |kind_id| {
self.relations
.get(kind_id)
.unwrap()
.keys()
.map(move |target| (kind_id, Some(*target)))
}))
}

#[inline]
Expand Down Expand Up @@ -289,25 +320,51 @@ impl Archetype {
}

#[inline]
pub fn contains(&self, component_id: ComponentId) -> bool {
self.components.contains(component_id)
pub fn contains(&self, relation_kind: RelationKindId, relation_target: Option<Entity>) -> bool {
match relation_target {
None => self.components.contains(relation_kind),
Some(target) => self
.relations
.get(relation_kind)
.map(|set| set.get(&target))
.flatten()
.is_some(),
}
}

// FIXME(Relationships) technically the target is unnecessary here as all `KindId` have the same storage type
#[inline]
pub fn get_storage_type(&self, component_id: ComponentId) -> Option<StorageType> {
self.components
.get(component_id)
.map(|info| info.storage_type)
pub fn get_storage_type(
&self,
relation_kind: RelationKindId,
relation_target: Option<Entity>,
) -> Option<StorageType> {
match relation_target {
None => self.components.get(relation_kind),
Some(target) => self
.relations
.get(relation_kind)
.map(|set| set.get(&target))
.flatten(),
}
.map(|info| info.storage_type)
}

#[inline]
pub fn get_archetype_component_id(
&self,
component_id: ComponentId,
relation_kind: RelationKindId,
relation_target: Option<Entity>,
) -> Option<ArchetypeComponentId> {
self.components
.get(component_id)
.map(|info| info.archetype_component_id)
match relation_target {
None => self.components.get(relation_kind),
Some(target) => self
.relations
.get(relation_kind)
.map(|set| set.get(&target))
.flatten(),
}
.map(|info| info.archetype_component_id)
}
}

Expand All @@ -329,8 +386,8 @@ impl ArchetypeGeneration {

#[derive(Hash, PartialEq, Eq)]
pub struct ArchetypeIdentity {
table_components: Cow<'static, [ComponentId]>,
sparse_set_components: Cow<'static, [ComponentId]>,
table_components: Cow<'static, [(RelationKindId, Option<Entity>)]>,
sparse_set_components: Cow<'static, [(RelationKindId, Option<Entity>)]>,
}

#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
Expand Down Expand Up @@ -453,6 +510,10 @@ impl Archetypes {
a: ArchetypeId,
b: ArchetypeId,
) -> (&mut Archetype, &mut Archetype) {
if a.0 == b.0 {
panic!("both indexes were the same");
}

if a.index() > b.index() {
let (b_slice, a_slice) = self.archetypes.split_at_mut(a.index());
(&mut a_slice[0], &mut b_slice[b.index()])
Expand All @@ -475,8 +536,8 @@ impl Archetypes {
pub(crate) fn get_id_or_insert(
&mut self,
table_id: TableId,
table_components: Vec<ComponentId>,
sparse_set_components: Vec<ComponentId>,
table_components: Vec<(RelationKindId, Option<Entity>)>,
sparse_set_components: Vec<(RelationKindId, Option<Entity>)>,
) -> ArchetypeId {
let table_components = Cow::from(table_components);
let sparse_set_components = Cow::from(sparse_set_components);
Expand Down
Loading

0 comments on commit ee94150

Please sign in to comment.