Skip to content

Commit bd57f95

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

File tree

2 files changed

+50
-8
lines changed

2 files changed

+50
-8
lines changed

feather/ecs/src/lib.rs

+15-2
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

+35-6
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,28 @@ impl<'a> ComponentVisitor<anyhow::Result<WrittenComponentData>> for WriteCompone
103106
}
104107
}
105108

109+
fn matching_archetypes<'a>(
110+
ecs: &'a Ecs,
111+
types: &'a [HostComponent],
112+
) -> impl Iterator<Item = &'a Archetype> + 'a {
113+
struct Has<'a>(&'a Archetype);
114+
impl ComponentVisitor<bool> for Has<'_> {
115+
fn visit<T: Component>(self) -> bool {
116+
self.0.has::<T>()
117+
}
118+
}
119+
ecs.archetypes()
120+
.filter(move |archetype| types.iter().all(|t| t.visit(Has(archetype))))
121+
}
122+
106123
fn create_query_data(
107124
cx: &PluginContext,
108125
ecs: &Ecs,
109126
types: &[HostComponent],
110127
) -> anyhow::Result<QueryData> {
111-
let num_entities = todo!();
128+
let num_entities = matching_archetypes(ecs, types)
129+
.map(|archetype| archetype.ids().len())
130+
.sum();
112131
if num_entities == 0 {
113132
return Ok(QueryData {
114133
num_entities: 0,
@@ -122,6 +141,8 @@ fn create_query_data(
122141
let component_lens = cx.bump_allocate(Layout::array::<u32>(types.len())?)?;
123142
for (i, &typ) in types.iter().enumerate() {
124143
let data = typ.visit(WriteComponentsVisitor {
144+
ecs,
145+
types,
125146
cx,
126147
num_entities,
127148
})?;
@@ -133,7 +154,15 @@ fn create_query_data(
133154
}
134155

135156
let entities_ptr = cx.bump_allocate(Layout::array::<EntityId>(num_entities)?)?;
136-
for (i, entity) in todo!().enumerate() {
157+
for (i, entity) in matching_archetypes(ecs, types)
158+
.flat_map(|archetype| {
159+
archetype
160+
.ids()
161+
.iter()
162+
.map(|id| unsafe { ecs.find_entity_from_id(*id) })
163+
})
164+
.enumerate()
165+
{
137166
let bits = entity.to_bits().get();
138167
unsafe {
139168
cx.write_pod(entities_ptr.cast().add(i), bits)?;

0 commit comments

Comments
 (0)