Skip to content

Commit 3744235

Browse files
committed
reimplement dynamic archetype queries
1 parent bd30e34 commit 3744235

File tree

2 files changed

+47
-8
lines changed

2 files changed

+47
-8
lines changed

feather/ecs/src/lib.rs

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@ use hecs::{Component, DynamicBundle, Fetch, Query, World};
1616

1717
#[doc(inline)]
1818
pub use hecs::{
19-
BuiltEntity, ComponentError, Entity, EntityBuilder,
20-
MissingComponent, NoSuchEntity, QueryBorrow, Ref, RefMut,
19+
Archetype, BuiltEntity, ComponentError, Entity, EntityBuilder, MissingComponent, NoSuchEntity,
20+
QueryBorrow, Ref, RefMut,
2121
};
2222

2323
mod system;
@@ -151,6 +151,19 @@ impl Ecs {
151151
self.world.query()
152152
}
153153

154+
pub fn archetypes(&self) -> impl Iterator<Item = &Archetype> {
155+
self.world.archetypes()
156+
}
157+
158+
///
159+
/// # Safety
160+
///
161+
/// `id` must correspond to a currently live [`Entity`].
162+
/// A despawned or never-allocated `id` will produce undefined behavior.
163+
pub unsafe fn find_entity_from_id(&self, id: u32) -> Entity {
164+
self.world.find_entity_from_id(id)
165+
}
166+
154167
/// Sets the index of the currently executing system,
155168
/// used for event tracking.
156169
pub fn set_current_system_index(&mut self, index: usize) {

feather/plugin-host/src/host_calls/query.rs

Lines changed: 32 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
use std::{alloc::Layout, any::TypeId, mem::size_of, ptr};
44

55
use anyhow::Context;
6-
use feather_ecs::{Ecs};
6+
use feather_ecs::{Archetype, Ecs};
77
use feather_plugin_host_macros::host_function;
88
use quill_common::{
99
component::{ComponentVisitor, SerializationMethod},
@@ -44,13 +44,16 @@ struct WrittenComponentData {
4444
/// `ComponentVisitor` implementation used to write
4545
/// component data to plugin memory.
4646
struct WriteComponentsVisitor<'a> {
47+
ecs: &'a Ecs,
48+
types: &'a [HostComponent],
4749
cx: &'a PluginContext,
4850
num_entities: usize,
4951
}
5052

5153
impl<'a> ComponentVisitor<anyhow::Result<WrittenComponentData>> for WriteComponentsVisitor<'a> {
5254
fn visit<T: Component>(self) -> anyhow::Result<WrittenComponentData> {
53-
let components = todo!();
55+
let components = matching_archetypes(self.ecs, self.types)
56+
.map(|archetype| archetype.get::<T>().unwrap());
5457

5558
// Write each component.
5659
// We use a different strategy depending
@@ -65,7 +68,7 @@ impl<'a> ComponentVisitor<anyhow::Result<WrittenComponentData>> for WriteCompone
6568
// Copy the components into the buffer.
6669
let mut byte_index = 0;
6770
for component_slice in components {
68-
for component in component_slice.as_slice::<T>() {
71+
for component in component_slice.iter() {
6972
let bytes = component.as_bytes();
7073

7174
unsafe {
@@ -86,7 +89,7 @@ impl<'a> ComponentVisitor<anyhow::Result<WrittenComponentData>> for WriteCompone
8689

8790
// Write components into the buffer.
8891
for component_slice in components {
89-
for component in component_slice.as_slice::<T>() {
92+
for component in component_slice.iter() {
9093
component.to_bytes(&mut bytes);
9194
}
9295
}
@@ -103,12 +106,25 @@ impl<'a> ComponentVisitor<anyhow::Result<WrittenComponentData>> for WriteCompone
103106
}
104107
}
105108

109+
fn matching_archetypes<'a>(ecs: &'a Ecs, types: &'a [HostComponent]) -> impl Iterator<Item = &'a Archetype> + 'a {
110+
struct Has<'a>(&'a Archetype);
111+
impl ComponentVisitor<bool> for Has<'_> {
112+
fn visit<T: Component>(self) -> bool {
113+
self.0.has::<T>()
114+
}
115+
}
116+
ecs.archetypes()
117+
.filter(move |archetype| types.iter().all(|t| t.visit(Has(archetype))))
118+
}
119+
106120
fn create_query_data(
107121
cx: &PluginContext,
108122
ecs: &Ecs,
109123
types: &[HostComponent],
110124
) -> anyhow::Result<QueryData> {
111-
let num_entities = todo!();
125+
let num_entities = matching_archetypes(ecs, types)
126+
.map(|archetype| archetype.ids().len())
127+
.sum();
112128
if num_entities == 0 {
113129
return Ok(QueryData {
114130
num_entities: 0,
@@ -122,6 +138,8 @@ fn create_query_data(
122138
let component_lens = cx.bump_allocate(Layout::array::<u32>(types.len())?)?;
123139
for (i, &typ) in types.iter().enumerate() {
124140
let data = typ.visit(WriteComponentsVisitor {
141+
ecs,
142+
types,
125143
cx,
126144
num_entities,
127145
})?;
@@ -133,7 +151,15 @@ fn create_query_data(
133151
}
134152

135153
let entities_ptr = cx.bump_allocate(Layout::array::<EntityId>(num_entities)?)?;
136-
for (i, entity) in todo!().enumerate() {
154+
for (i, entity) in matching_archetypes(ecs, types)
155+
.flat_map(|archetype| {
156+
archetype
157+
.ids()
158+
.iter()
159+
.map(|id| unsafe { ecs.find_entity_from_id(*id) })
160+
})
161+
.enumerate()
162+
{
137163
let bits = entity.to_bits().get();
138164
unsafe {
139165
cx.write_pod(entities_ptr.cast().add(i), bits)?;

0 commit comments

Comments
 (0)