Skip to content

Commit 611894a

Browse files
Entity Relations :thepr:
Co-authored-by: Patrik Buhring <[email protected]>
1 parent 3a20462 commit 611894a

29 files changed

+4284
-822
lines changed

Cargo.toml

+4
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,10 @@ path = "examples/diagnostics/custom_diagnostic.rs"
261261
name = "ecs_guide"
262262
path = "examples/ecs/ecs_guide.rs"
263263

264+
[[example]]
265+
name = "relations_grouping"
266+
path = "examples/ecs/relations_grouping.rs"
267+
264268
[[example]]
265269
name = "component_change_detection"
266270
path = "examples/ecs/component_change_detection.rs"

crates/bevy_ecs/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ bevy_tasks = { path = "../bevy_tasks", version = "0.5.0" }
2323
bevy_utils = { path = "../bevy_utils", version = "0.5.0" }
2424
bevy_ecs_macros = { path = "macros", version = "0.5.0" }
2525

26+
smallvec = { version = "1.4", features = ["serde"] }
2627
async-channel = "1.4"
2728
fixedbitset = "0.4"
2829
fxhash = "0.2"

crates/bevy_ecs/macros/src/lib.rs

+12-2
Original file line numberDiff line numberDiff line change
@@ -258,7 +258,17 @@ pub fn impl_query_set(_input: TokenStream) -> TokenStream {
258258
fn new_archetype(&mut self, archetype: &Archetype, system_meta: &mut SystemMeta) {
259259
let (#(#query,)*) = &mut self.0;
260260
#(
261-
#query.new_archetype(archetype);
261+
for (target_filter, cache) in #query.target_filter_accesses.iter_mut() {
262+
QueryState::<#query, #filter>::new_archetype(
263+
&#query.fetch_state,
264+
&#query.filter_state,
265+
&mut #query.archetype_component_access,
266+
&*target_filter,
267+
cache,
268+
archetype
269+
);
270+
}
271+
262272
system_meta
263273
.archetype_component_access
264274
.extend(&#query.archetype_component_access);
@@ -280,7 +290,7 @@ pub fn impl_query_set(_input: TokenStream) -> TokenStream {
280290
world: &'a World,
281291
change_tick: u32,
282292
) -> Self::Item {
283-
let (#(#query,)*) = &state.0;
293+
let (#(#query,)*) = &mut state.0;
284294
QuerySet((#(Query::new(world, #query, system_meta.last_change_tick, change_tick),)*))
285295
}
286296
}

crates/bevy_ecs/src/archetype.rs

+160-45
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
1+
use bevy_utils::HashMap;
2+
use bevy_utils::StableHashMap;
3+
14
use crate::{
25
bundle::BundleId,
36
component::{ComponentId, StorageType},
47
entity::{Entity, EntityLocation},
5-
storage::{Column, SparseArray, SparseSet, SparseSetIndex, TableId},
8+
storage::{Column, SparseSet, SparseSetIndex, TableId},
69
};
710
use std::{
811
borrow::Cow,
9-
collections::HashMap,
1012
hash::Hash,
1113
ops::{Index, IndexMut},
1214
};
@@ -48,15 +50,41 @@ pub struct AddBundle {
4850

4951
#[derive(Default)]
5052
pub struct Edges {
51-
pub add_bundle: SparseArray<BundleId, AddBundle>,
52-
pub remove_bundle: SparseArray<BundleId, Option<ArchetypeId>>,
53-
pub remove_bundle_intersection: SparseArray<BundleId, Option<ArchetypeId>>,
53+
pub add_bundle: HashMap<BundleId, AddBundle>,
54+
pub remove_bundle: HashMap<BundleId, Option<ArchetypeId>>,
55+
pub remove_bundle_intersection: HashMap<BundleId, Option<ArchetypeId>>,
5456
}
5557

5658
impl Edges {
59+
pub fn debug_ram_usage(&self) -> usize {
60+
use std::mem::size_of;
61+
62+
let mut size = size_of::<Edges>();
63+
64+
let usage_of_hm = |cap: usize, k, v| (cap * 11 / 10).next_power_of_two() * (k + v + 8);
65+
66+
size += usage_of_hm(
67+
self.add_bundle.capacity(),
68+
size_of::<BundleId>(),
69+
size_of::<AddBundle>(),
70+
);
71+
size += usage_of_hm(
72+
self.remove_bundle.capacity(),
73+
size_of::<BundleId>(),
74+
size_of::<Option<ArchetypeId>>(),
75+
);
76+
size += usage_of_hm(
77+
self.remove_bundle_intersection.capacity(),
78+
size_of::<BundleId>(),
79+
size_of::<Option<ArchetypeId>>(),
80+
);
81+
82+
size
83+
}
84+
5785
#[inline]
5886
pub fn get_add_bundle(&self, bundle_id: BundleId) -> Option<&AddBundle> {
59-
self.add_bundle.get(bundle_id)
87+
self.add_bundle.get(&bundle_id)
6088
}
6189

6290
#[inline]
@@ -77,7 +105,7 @@ impl Edges {
77105

78106
#[inline]
79107
pub fn get_remove_bundle(&self, bundle_id: BundleId) -> Option<Option<ArchetypeId>> {
80-
self.remove_bundle.get(bundle_id).cloned()
108+
self.remove_bundle.get(&bundle_id).cloned()
81109
}
82110

83111
#[inline]
@@ -90,7 +118,7 @@ impl Edges {
90118
&self,
91119
bundle_id: BundleId,
92120
) -> Option<Option<ArchetypeId>> {
93-
self.remove_bundle_intersection.get(bundle_id).cloned()
121+
self.remove_bundle_intersection.get(&bundle_id).cloned()
94122
}
95123

96124
#[inline]
@@ -124,54 +152,103 @@ pub struct Archetype {
124152
entities: Vec<Entity>,
125153
edges: Edges,
126154
table_info: TableInfo,
127-
table_components: Cow<'static, [ComponentId]>,
128-
sparse_set_components: Cow<'static, [ComponentId]>,
155+
table_components: Cow<'static, [(ComponentId, Option<Entity>)]>,
156+
sparse_set_components: Cow<'static, [(ComponentId, Option<Entity>)]>,
129157
pub(crate) unique_components: SparseSet<ComponentId, Column>,
130158
pub(crate) components: SparseSet<ComponentId, ArchetypeComponentInfo>,
159+
pub(crate) relations: SparseSet<ComponentId, StableHashMap<Entity, ArchetypeComponentInfo>>,
131160
}
132161

133162
impl Archetype {
163+
pub fn debug_ram_usage(&self) -> (usize, usize) {
164+
use std::mem::size_of;
165+
let mut size = size_of::<Archetype>();
166+
167+
if let Cow::Owned(owned) = &self.table_components {
168+
size += size_of::<(ComponentId, Option<Entity>)>() * owned.len();
169+
}
170+
if let Cow::Owned(owned) = &self.sparse_set_components {
171+
size += size_of::<(ComponentId, Option<Entity>)>() * owned.len();
172+
}
173+
174+
size += size_of::<ArchetypeComponentInfo>() * self.components.dense_len();
175+
size += size_of::<ComponentId>() * self.components.indices_len();
176+
size += size_of::<Option<usize>>() * self.components.sparse_len();
177+
178+
size += size_of::<ComponentId>() * self.relations.indices_len();
179+
size += size_of::<Option<usize>>() * self.relations.sparse_len();
180+
181+
for v in self.relations.values() {
182+
let cap = v.capacity();
183+
let usage = (cap * 11 / 10).next_power_of_two()
184+
* (size_of::<Entity>() + size_of::<ArchetypeComponentInfo>() + 8);
185+
size += usage;
186+
}
187+
188+
size += size_of::<Entity>() * self.entities.len();
189+
190+
(size, self.edges.debug_ram_usage())
191+
}
192+
134193
pub fn new(
135194
id: ArchetypeId,
136195
table_id: TableId,
137-
table_components: Cow<'static, [ComponentId]>,
138-
sparse_set_components: Cow<'static, [ComponentId]>,
196+
table_components: Cow<'static, [(ComponentId, Option<Entity>)]>,
197+
sparse_set_components: Cow<'static, [(ComponentId, Option<Entity>)]>,
139198
table_archetype_components: Vec<ArchetypeComponentId>,
140199
sparse_set_archetype_components: Vec<ArchetypeComponentId>,
141200
) -> Self {
201+
// FIXME(Relationships) sort out this capacity weirdness
142202
let mut components =
143203
SparseSet::with_capacity(table_components.len() + sparse_set_components.len());
144-
for (component_id, archetype_component_id) in
204+
let mut relations = SparseSet::new();
205+
for ((component_id, target), archetype_component_id) in
145206
table_components.iter().zip(table_archetype_components)
146207
{
147-
components.insert(
148-
*component_id,
149-
ArchetypeComponentInfo {
150-
storage_type: StorageType::Table,
151-
archetype_component_id,
152-
},
153-
);
208+
let arch_comp_info = ArchetypeComponentInfo {
209+
storage_type: StorageType::Table,
210+
archetype_component_id,
211+
};
212+
213+
match target {
214+
None => {
215+
components.insert(*component_id, arch_comp_info);
216+
}
217+
Some(target) => {
218+
let set = relations.get_or_insert_with(*component_id, StableHashMap::default);
219+
set.insert(*target, arch_comp_info);
220+
}
221+
};
154222
}
155223

156-
for (component_id, archetype_component_id) in sparse_set_components
224+
for ((component_id, target), archetype_component_id) in sparse_set_components
157225
.iter()
158226
.zip(sparse_set_archetype_components)
159227
{
160-
components.insert(
161-
*component_id,
162-
ArchetypeComponentInfo {
163-
storage_type: StorageType::SparseSet,
164-
archetype_component_id,
165-
},
166-
);
228+
let arch_comp_info = ArchetypeComponentInfo {
229+
storage_type: StorageType::SparseSet,
230+
archetype_component_id,
231+
};
232+
233+
match target {
234+
None => {
235+
components.insert(*component_id, arch_comp_info);
236+
}
237+
Some(target) => {
238+
let set = relations.get_or_insert_with(*component_id, StableHashMap::default);
239+
set.insert(*target, arch_comp_info);
240+
}
241+
};
167242
}
243+
168244
Self {
169245
id,
170246
table_info: TableInfo {
171247
id: table_id,
172248
entity_rows: Default::default(),
173249
},
174250
components,
251+
relations,
175252
table_components,
176253
sparse_set_components,
177254
unique_components: SparseSet::new(),
@@ -201,12 +278,12 @@ impl Archetype {
201278
}
202279

203280
#[inline]
204-
pub fn table_components(&self) -> &[ComponentId] {
281+
pub fn table_components(&self) -> &[(ComponentId, Option<Entity>)] {
205282
&self.table_components
206283
}
207284

208285
#[inline]
209-
pub fn sparse_set_components(&self) -> &[ComponentId] {
286+
pub fn sparse_set_components(&self) -> &[(ComponentId, Option<Entity>)] {
210287
&self.sparse_set_components
211288
}
212289

@@ -221,8 +298,17 @@ impl Archetype {
221298
}
222299

223300
#[inline]
224-
pub fn components(&self) -> impl Iterator<Item = ComponentId> + '_ {
225-
self.components.indices()
301+
pub fn components(&self) -> impl Iterator<Item = (ComponentId, Option<Entity>)> + '_ {
302+
self.components
303+
.indices()
304+
.map(|kind| (kind, None))
305+
.chain(self.relations.indices().flat_map(move |component_id| {
306+
self.relations
307+
.get(component_id)
308+
.unwrap()
309+
.keys()
310+
.map(move |target| (component_id, Some(*target)))
311+
}))
226312
}
227313

228314
#[inline]
@@ -289,25 +375,50 @@ impl Archetype {
289375
}
290376

291377
#[inline]
292-
pub fn contains(&self, component_id: ComponentId) -> bool {
293-
self.components.contains(component_id)
378+
pub fn contains(&self, component_id: ComponentId, target: Option<Entity>) -> bool {
379+
match target {
380+
None => self.components.contains(component_id),
381+
Some(target) => self
382+
.relations
383+
.get(component_id)
384+
.map(|set| set.contains_key(&target))
385+
.unwrap_or(false),
386+
}
294387
}
295388

389+
// FIXME(Relationships) technically the target is unnecessary here as all `KindId` have the same storage type
296390
#[inline]
297-
pub fn get_storage_type(&self, component_id: ComponentId) -> Option<StorageType> {
298-
self.components
299-
.get(component_id)
300-
.map(|info| info.storage_type)
391+
pub fn get_storage_type(
392+
&self,
393+
component_id: ComponentId,
394+
target: Option<Entity>,
395+
) -> Option<StorageType> {
396+
match target {
397+
None => self.components.get(component_id),
398+
Some(target) => self
399+
.relations
400+
.get(component_id)
401+
.and_then(|set| set.get(&target)),
402+
}
403+
.map(|info| info.storage_type)
301404
}
302405

303406
#[inline]
304407
pub fn get_archetype_component_id(
305408
&self,
306409
component_id: ComponentId,
410+
// FIXME(Relationships) treat archetype componnet id the same as component id maybe?? see other fixme
411+
// then we oculd get rid of this `target` arg and same with fn above
412+
target: Option<Entity>,
307413
) -> Option<ArchetypeComponentId> {
308-
self.components
309-
.get(component_id)
310-
.map(|info| info.archetype_component_id)
414+
match target {
415+
None => self.components.get(component_id),
416+
Some(target) => self
417+
.relations
418+
.get(component_id)
419+
.and_then(|set| set.get(&target)),
420+
}
421+
.map(|info| info.archetype_component_id)
311422
}
312423
}
313424

@@ -329,8 +440,8 @@ impl ArchetypeGeneration {
329440

330441
#[derive(Hash, PartialEq, Eq)]
331442
pub struct ArchetypeIdentity {
332-
table_components: Cow<'static, [ComponentId]>,
333-
sparse_set_components: Cow<'static, [ComponentId]>,
443+
table_components: Cow<'static, [(ComponentId, Option<Entity>)]>,
444+
sparse_set_components: Cow<'static, [(ComponentId, Option<Entity>)]>,
334445
}
335446

336447
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
@@ -453,6 +564,10 @@ impl Archetypes {
453564
a: ArchetypeId,
454565
b: ArchetypeId,
455566
) -> (&mut Archetype, &mut Archetype) {
567+
if a.0 == b.0 {
568+
panic!("both indexes were the same");
569+
}
570+
456571
if a.index() > b.index() {
457572
let (b_slice, a_slice) = self.archetypes.split_at_mut(a.index());
458573
(&mut a_slice[0], &mut b_slice[b.index()])
@@ -475,8 +590,8 @@ impl Archetypes {
475590
pub(crate) fn get_id_or_insert(
476591
&mut self,
477592
table_id: TableId,
478-
table_components: Vec<ComponentId>,
479-
sparse_set_components: Vec<ComponentId>,
593+
table_components: Vec<(ComponentId, Option<Entity>)>,
594+
sparse_set_components: Vec<(ComponentId, Option<Entity>)>,
480595
) -> ArchetypeId {
481596
let table_components = Cow::from(table_components);
482597
let sparse_set_components = Cow::from(sparse_set_components);

0 commit comments

Comments
 (0)