Create queries and views
This commit is contained in:
parent
f62f21e69f
commit
92e284e625
|
@ -31,7 +31,9 @@
|
||||||
"test",
|
"test",
|
||||||
"--no-run",
|
"--no-run",
|
||||||
"--bin=lyra-ecs",
|
"--bin=lyra-ecs",
|
||||||
"--package=lyra-ecs"
|
"--package=lyra-ecs",
|
||||||
|
"--",
|
||||||
|
"--nocapture"
|
||||||
],
|
],
|
||||||
"filter": {
|
"filter": {
|
||||||
"name": "lyra-ecs",
|
"name": "lyra-ecs",
|
||||||
|
|
|
@ -1,55 +1,96 @@
|
||||||
use std::any::{Any, TypeId};
|
use std::{any::{Any, TypeId, type_name}, ptr::{NonNull, self}, alloc::{self, Layout, alloc}, mem::size_of};
|
||||||
|
|
||||||
use crate::{world::{Entity, ArchetypeEntityId}, bundle::Bundle, component::Component};
|
use crate::{world::{Entity, ArchetypeEntityId}, bundle::Bundle, component::Component, component_info::ComponentInfo};
|
||||||
|
|
||||||
pub trait ComponentColumn: Any {
|
pub struct ComponentColumn {
|
||||||
fn as_any(&self) -> &dyn Any;
|
pub data: NonNull<u8>,
|
||||||
fn as_any_mut(&mut self) -> &mut dyn Any;
|
pub capacity: usize,
|
||||||
fn new_empty_column(&self) -> Box<dyn ComponentColumn>;
|
pub info: ComponentInfo,
|
||||||
fn is_same_type(&self, column: &dyn ComponentColumn) -> bool;
|
pub entry_size: usize,
|
||||||
fn len(&self) -> usize;
|
|
||||||
fn append(&mut self, column: &mut dyn ComponentColumn);
|
|
||||||
|
|
||||||
fn component_type_id(&self) -> TypeId;
|
|
||||||
// used for debugging
|
|
||||||
fn component_type_name(&self) -> String;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Component> ComponentColumn for Vec<T> {
|
impl ComponentColumn {
|
||||||
fn as_any(&self) -> &dyn Any {
|
/// Creates an invalid component column. Do not attempt to use it.
|
||||||
self
|
pub unsafe fn dangling() -> Self {
|
||||||
|
ComponentColumn {
|
||||||
|
data: NonNull::dangling(),
|
||||||
|
capacity: 0,
|
||||||
|
info: ComponentInfo::new::<()>(),
|
||||||
|
entry_size: 0,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn as_any_mut(&mut self) -> &mut dyn Any {
|
pub unsafe fn alloc(component_layout: Layout, capacity: usize) -> NonNull<u8> {
|
||||||
self
|
let new_layout = Layout::from_size_align(
|
||||||
|
component_layout.size().checked_mul(capacity).unwrap(),
|
||||||
|
component_layout.align()
|
||||||
|
).unwrap();
|
||||||
|
|
||||||
|
if let Some(data) = NonNull::new(alloc(new_layout)) {
|
||||||
|
data
|
||||||
|
} else {
|
||||||
|
alloc::handle_alloc_error(new_layout)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new_empty_column(&self) -> Box<dyn ComponentColumn> {
|
pub unsafe fn new(info: ComponentInfo, capacity: usize) -> Self {
|
||||||
Box::new(Vec::<T>::new())
|
let data = ComponentColumn::alloc(info.layout, capacity);
|
||||||
|
|
||||||
|
let size = info.layout.size();
|
||||||
|
Self {
|
||||||
|
data,
|
||||||
|
capacity,
|
||||||
|
info,
|
||||||
|
entry_size: size,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_same_type(&self, column: &dyn ComponentColumn) -> bool {
|
/// Creates an empty column of the same type
|
||||||
column.as_any().downcast_ref::<Self>().is_some()
|
pub unsafe fn create_empty(&self, capacity: usize) -> Self {
|
||||||
|
let data = ComponentColumn::alloc(self.info.layout, capacity);
|
||||||
|
|
||||||
|
let size = self.info.layout.size();
|
||||||
|
Self {
|
||||||
|
data,
|
||||||
|
capacity,
|
||||||
|
info: self.info.clone(),
|
||||||
|
entry_size: size,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn len(&self) -> usize {
|
/// Set a component from pointer at an entity index.
|
||||||
Vec::len(self)
|
///
|
||||||
|
/// # Safety
|
||||||
|
///
|
||||||
|
/// This column must have space to fit the component, if it does not have room it will panic.
|
||||||
|
pub unsafe fn set_at(&mut self, entity_index: usize, comp_src: NonNull<u8>) {
|
||||||
|
assert!(entity_index < self.capacity);
|
||||||
|
let dest = NonNull::new_unchecked(self.data.as_ptr().add(entity_index * self.entry_size));
|
||||||
|
ptr::copy_nonoverlapping(comp_src.as_ptr(), dest.as_ptr(), self.entry_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn append(&mut self, column: &mut dyn ComponentColumn) {
|
/// Get a component at an entities index.
|
||||||
let column: &mut Self = column.as_any_mut().downcast_mut()
|
///
|
||||||
.expect("Attempt at appending an different column type!");
|
/// # Safety
|
||||||
|
///
|
||||||
self.append(column);
|
/// This column MUST have the entity. If it does not, it WILL NOT panic and will cause UB.
|
||||||
|
pub unsafe fn get<T>(&self, entity_index: usize) -> &T {
|
||||||
|
let p = self.data.as_ptr()
|
||||||
|
.cast::<T>()
|
||||||
|
.add(entity_index * self.entry_size);
|
||||||
|
&*p
|
||||||
}
|
}
|
||||||
|
|
||||||
fn component_type_id(&self) -> TypeId {
|
/// Get a component at an entities index.
|
||||||
self.first().unwrap().type_id()
|
///
|
||||||
}
|
/// # Safety
|
||||||
|
///
|
||||||
fn component_type_name(&self) -> String {
|
/// This column must have the entity.
|
||||||
//self.first().unwrap().type_id()
|
pub unsafe fn get_mut<T>(&mut self, entity_index: usize) -> &mut T {
|
||||||
std::any::type_name::<T>().to_string()
|
let p = self.data.as_ptr()
|
||||||
|
.cast::<T>()
|
||||||
|
.add(entity_index * self.entry_size);
|
||||||
|
&mut *p
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -68,24 +109,25 @@ impl ArchetypeId {
|
||||||
|
|
||||||
pub struct Archetype {
|
pub struct Archetype {
|
||||||
pub(crate) id: ArchetypeId,
|
pub(crate) id: ArchetypeId,
|
||||||
entities: Vec<Entity>,
|
pub(crate) entities: Vec<Entity>,
|
||||||
pub(crate) columns: Vec<Box<dyn ComponentColumn>>,
|
pub(crate) columns: Vec<ComponentColumn>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The default capacity of the columns
|
||||||
|
const DEFAULT_CAPACITY: usize = 32;
|
||||||
|
|
||||||
impl Archetype {
|
impl Archetype {
|
||||||
/// Create a new archetype from another archetype and add a column
|
/// Create a new archetype from another archetype and add a column
|
||||||
pub fn new_archetype_add<T: Component>(new_id: ArchetypeId, archetype: &Archetype) -> Archetype {
|
pub fn new_archetype_add<T: Component>(new_id: ArchetypeId, archetype: &Archetype) -> Archetype {
|
||||||
let mut columns: Vec<_> = archetype
|
let mut columns: Vec<_> = archetype
|
||||||
.columns
|
.columns
|
||||||
.iter()
|
.iter()
|
||||||
.map(|c| c.new_empty_column())
|
.map(|c| unsafe { c.create_empty(DEFAULT_CAPACITY) })
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
assert!(columns
|
// Make sure a column for the new component does not exist
|
||||||
.iter()
|
assert_ne!(true, columns.iter().any(|c| c.info.type_id == TypeId::of::<T>()) );
|
||||||
.find(|column| column.as_any().is::<Vec<T>>())
|
columns.push(unsafe { ComponentColumn::new(ComponentInfo::new::<T>(), DEFAULT_CAPACITY) });
|
||||||
.is_none());
|
|
||||||
columns.push(Box::new(Vec::<T>::new()));
|
|
||||||
|
|
||||||
Archetype {
|
Archetype {
|
||||||
id: new_id,
|
id: new_id,
|
||||||
|
@ -99,12 +141,12 @@ impl Archetype {
|
||||||
let mut columns: Vec<_> = archetype
|
let mut columns: Vec<_> = archetype
|
||||||
.columns
|
.columns
|
||||||
.iter()
|
.iter()
|
||||||
.map(|c| c.new_empty_column())
|
.map(|c| unsafe { c.create_empty(DEFAULT_CAPACITY) })
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let idx = columns
|
let idx = columns
|
||||||
.iter()
|
.iter()
|
||||||
.position(|column| column.as_any().is::<Vec<T>>())
|
.position(|column| column.info.type_id == TypeId::of::<T>())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
columns.remove(idx);
|
columns.remove(idx);
|
||||||
|
|
||||||
|
@ -115,7 +157,11 @@ impl Archetype {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_columns(new_id: ArchetypeId, columns: Vec<Box<dyn ComponentColumn>>) -> Archetype {
|
pub fn from_bundle_info(new_id: ArchetypeId, bundle_info: Vec<ComponentInfo>) -> Archetype {
|
||||||
|
let columns = bundle_info.into_iter().map(|i| {
|
||||||
|
unsafe { ComponentColumn::new(i, DEFAULT_CAPACITY) }
|
||||||
|
}).collect();
|
||||||
|
|
||||||
Archetype {
|
Archetype {
|
||||||
id: new_id,
|
id: new_id,
|
||||||
entities: Vec::new(),
|
entities: Vec::new(),
|
||||||
|
@ -124,64 +170,42 @@ impl Archetype {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_component_mut<T: Component>(&mut self, entity: ArchetypeEntityId) -> Option<&mut T> {
|
pub fn get_component_mut<T: Component>(&mut self, entity: ArchetypeEntityId) -> Option<&mut T> {
|
||||||
for col in self.columns.iter_mut() {
|
todo!()
|
||||||
if col.as_any().is::<Vec<T>>() {
|
|
||||||
let components: &mut Vec<T> = col.as_any_mut().downcast_mut().unwrap();
|
|
||||||
|
|
||||||
return components.get_mut(entity.0 as usize);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
None
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_component<T: Component>(&self, entity: ArchetypeEntityId) -> Option<&T> {
|
pub fn get_entity_component<T: Component>(&self, entity: ArchetypeEntityId) -> Option<&T> {
|
||||||
for col in self.columns.iter() {
|
let type_id = TypeId::of::<T>();
|
||||||
if col.as_ref().as_any().is::<Vec<T>>() {
|
|
||||||
let components: &Vec<T> = col.as_any().downcast_ref().unwrap();
|
self.columns.iter().find(|c| c.info.type_id == type_id)
|
||||||
|
.map(|c| unsafe { c.get(entity.0 as usize) })
|
||||||
return components.get(entity.0 as usize);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
None
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_component_column<T: Component>(&self) -> Option<&Vec<T>> {
|
pub fn get_component_column<T: Component>(&self) -> Option<&Vec<T>> {
|
||||||
let col = self.columns.iter().find(|c| c.as_any().is::<Vec<T>>())?;
|
todo!()
|
||||||
col.as_any().downcast_ref()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn add_entity(&mut self, components: Vec<Box<dyn ComponentColumn>>) -> ArchetypeEntityId {
|
/// Add an entity and its component bundle to the Archetype
|
||||||
let mut created_entity: Option<ArchetypeEntityId> = None;
|
///
|
||||||
|
/// # Safety:
|
||||||
|
///
|
||||||
|
/// Archetype must contain all of the components
|
||||||
|
pub(crate) fn add_entity<B>(&mut self, entity: Entity, bundle: B) -> ArchetypeEntityId
|
||||||
|
where
|
||||||
|
B: Bundle
|
||||||
|
{
|
||||||
|
let entity_index = self.entities.len();
|
||||||
|
self.entities.push(entity);
|
||||||
|
|
||||||
for mut component in components.into_iter() {
|
bundle.takefn(|data, type_id, size| {
|
||||||
for col in self.columns.iter_mut() {
|
let col = self.columns.iter_mut().find(|c| c.info.type_id == type_id).unwrap();
|
||||||
if col.is_same_type(component.as_ref()) {
|
unsafe { col.set_at(entity_index, data); }
|
||||||
match created_entity {
|
});
|
||||||
Some(e) => {
|
|
||||||
assert!(e.0 == col.len() as u64);
|
ArchetypeEntityId(entity_index as u64)
|
||||||
},
|
|
||||||
None => {
|
|
||||||
created_entity = Some(ArchetypeEntityId(col.len() as u64));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
col.append(component.as_mut());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
created_entity.expect("Failure to create entity!")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// returns a boolean indicating whether this archetype can store the TypeIds given
|
/// returns a boolean indicating whether this archetype can store the TypeIds given
|
||||||
pub(crate) fn is_archetype_for(&self, types: Vec<TypeId>) -> bool {
|
pub(crate) fn is_archetype_for(&self, types: Vec<TypeId>) -> bool {
|
||||||
let types_iter = types.into_iter();
|
self.columns.iter().all(|c| types.contains(&c.info.type_id))
|
||||||
|
|
||||||
self.columns
|
|
||||||
.iter()
|
|
||||||
.map(|c| c.component_type_id())
|
|
||||||
.eq(types_iter)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
use std::any::{TypeId, Any};
|
use std::{any::{TypeId, Any}, cell::Ref, ptr::NonNull, mem::size_of};
|
||||||
|
|
||||||
use crate::{archetype::ComponentColumn, component::Component};
|
use crate::{archetype::{ComponentColumn, Archetype}, component::Component, component_info::ComponentInfo};
|
||||||
|
|
||||||
pub trait Bundle {
|
pub trait Bundle {
|
||||||
// Get a list of type ids that this bundle is storing
|
// Get a list of type ids that this bundle is storing
|
||||||
|
@ -8,10 +8,35 @@ pub trait Bundle {
|
||||||
/// Take components into a list.
|
/// Take components into a list.
|
||||||
/// The return value could be seen as a list of a list of components, but that inner list
|
/// The return value could be seen as a list of a list of components, but that inner list
|
||||||
/// only contains a single value to make it easier to add it to an archetype.
|
/// only contains a single value to make it easier to add it to an archetype.
|
||||||
fn take_components(self) -> Vec<Box<dyn ComponentColumn>>;
|
//fn take_components(self) -> Vec<Box<dyn ComponentColumn>>;
|
||||||
|
|
||||||
|
//fn from_component_columns(columns: Vec<&Box<dyn ComponentColumn>>) -> Self;
|
||||||
|
//fn from_archetype(archetype: &Archetype) -> Self;
|
||||||
|
|
||||||
|
fn info(&self) -> Vec<ComponentInfo>;
|
||||||
|
|
||||||
|
/// Take the bundle by calling the closure with pointers to each component, its type and size.
|
||||||
|
/// The closure is expected to take ownership of the pointer.
|
||||||
|
fn takefn(self, cb: impl FnMut(NonNull<u8>, TypeId, usize));
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! impl_bundle_tuple {
|
impl<C1: Component> Bundle for (C1,) {
|
||||||
|
fn types(&self) -> Vec<TypeId> {
|
||||||
|
vec![self.0.type_id()]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn info(&self) -> Vec<ComponentInfo> {
|
||||||
|
vec![ComponentInfo::new::<C1>()]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn takefn(self, mut cb: impl FnMut(NonNull<u8>, TypeId, usize)) {
|
||||||
|
let (c1, ) = self;
|
||||||
|
|
||||||
|
cb(NonNull::from(&c1).cast(), TypeId::of::<C1>(), size_of::<C1>());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* macro_rules! impl_bundle_tuple {
|
||||||
( $(($name: ident, $index: tt))+ ) => (
|
( $(($name: ident, $index: tt))+ ) => (
|
||||||
impl<$($name: Component),+> Bundle for ($($name,)+) {
|
impl<$($name: Component),+> Bundle for ($($name,)+) {
|
||||||
fn types(&self) -> Vec<TypeId> {
|
fn types(&self) -> Vec<TypeId> {
|
||||||
|
@ -21,13 +46,23 @@ macro_rules! impl_bundle_tuple {
|
||||||
fn take_components(self) -> Vec<Box<dyn ComponentColumn>> {
|
fn take_components(self) -> Vec<Box<dyn ComponentColumn>> {
|
||||||
vec![$(Box::new(vec![self.$index])),+]
|
vec![$(Box::new(vec![self.$index])),+]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn from_component_columns(columns: Vec<&Box<dyn ComponentColumn>>) -> Self {
|
||||||
|
let mut chains = Vec::new();
|
||||||
|
|
||||||
|
for col in columns.iter() {
|
||||||
|
col.
|
||||||
|
}
|
||||||
|
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
} */
|
||||||
|
|
||||||
// hopefully 16 components in a bundle is enough
|
// hopefully 16 components in a bundle is enough
|
||||||
impl_bundle_tuple! { (C1, 0) }
|
//impl_bundle_tuple! { (C1, 0) }
|
||||||
impl_bundle_tuple! { (C1, 0) (C2, 1) }
|
/* impl_bundle_tuple! { (C1, 0) (C2, 1) }
|
||||||
impl_bundle_tuple! { (C1, 0) (C2, 1) (C3, 2) }
|
impl_bundle_tuple! { (C1, 0) (C2, 1) (C3, 2) }
|
||||||
impl_bundle_tuple! { (C1, 0) (C2, 1) (C3, 2) (C4, 3) }
|
impl_bundle_tuple! { (C1, 0) (C2, 1) (C3, 2) (C4, 3) }
|
||||||
impl_bundle_tuple! { (C1, 0) (C2, 1) (C3, 2) (C4, 3) (C5, 4) }
|
impl_bundle_tuple! { (C1, 0) (C2, 1) (C3, 2) (C4, 3) (C5, 4) }
|
||||||
|
@ -41,3 +76,4 @@ impl_bundle_tuple! { (C1, 0) (C2, 1) (C3, 2) (C4, 3) (C5, 4) (C6, 5) (C7, 6) (C8
|
||||||
impl_bundle_tuple! { (C1, 0) (C2, 1) (C3, 2) (C4, 3) (C5, 4) (C6, 5) (C7, 6) (C8, 7) (C9, 8) (C10, 9) (C11, 10) (C12, 11) (C13, 12) }
|
impl_bundle_tuple! { (C1, 0) (C2, 1) (C3, 2) (C4, 3) (C5, 4) (C6, 5) (C7, 6) (C8, 7) (C9, 8) (C10, 9) (C11, 10) (C12, 11) (C13, 12) }
|
||||||
impl_bundle_tuple! { (C1, 0) (C2, 1) (C3, 2) (C4, 3) (C5, 4) (C6, 5) (C7, 6) (C8, 7) (C9, 8) (C10, 9) (C11, 10) (C12, 11) (C13, 12) (C14, 13) }
|
impl_bundle_tuple! { (C1, 0) (C2, 1) (C3, 2) (C4, 3) (C5, 4) (C6, 5) (C7, 6) (C8, 7) (C9, 8) (C10, 9) (C11, 10) (C12, 11) (C13, 12) (C14, 13) }
|
||||||
impl_bundle_tuple! { (C1, 0) (C2, 1) (C3, 2) (C4, 3) (C5, 4) (C6, 5) (C7, 6) (C8, 7) (C9, 8) (C10, 9) (C11, 10) (C12, 11) (C13, 12) (C14, 13) (C15, 14) }
|
impl_bundle_tuple! { (C1, 0) (C2, 1) (C3, 2) (C4, 3) (C5, 4) (C6, 5) (C7, 6) (C8, 7) (C9, 8) (C10, 9) (C11, 10) (C12, 11) (C13, 12) (C14, 13) (C15, 14) }
|
||||||
|
*/
|
|
@ -0,0 +1,18 @@
|
||||||
|
use std::{any::{TypeId, type_name}, alloc::Layout};
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct ComponentInfo {
|
||||||
|
pub type_id: TypeId,
|
||||||
|
pub name: String,
|
||||||
|
pub layout: Layout,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ComponentInfo {
|
||||||
|
pub fn new<T: 'static>() -> Self {
|
||||||
|
Self {
|
||||||
|
type_id: TypeId::of::<T>(),
|
||||||
|
name: type_name::<T>().to_string(),
|
||||||
|
layout: Layout::new::<T>(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,9 +1,12 @@
|
||||||
|
//#![feature(cell_leak)]
|
||||||
use crate::world::World;
|
use crate::world::World;
|
||||||
|
|
||||||
mod archetype;
|
mod archetype;
|
||||||
mod world;
|
mod world;
|
||||||
mod bundle;
|
mod bundle;
|
||||||
mod component;
|
mod component;
|
||||||
|
mod query;
|
||||||
|
mod component_info;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Position2d(i32, i32);
|
pub struct Position2d(i32, i32);
|
||||||
|
@ -25,7 +28,14 @@ fn main() {
|
||||||
|
|
||||||
println!("\nstart of querying!\n");
|
println!("\nstart of querying!\n");
|
||||||
|
|
||||||
for pos in world.query::<Position2d>() {
|
/* for pos in world.query::<Position2d>() {
|
||||||
|
println!("Queried Position2d: {:?}", pos);
|
||||||
|
} */
|
||||||
|
|
||||||
|
let mut q = world.query_better();
|
||||||
|
q.with_component::<Position2d>();
|
||||||
|
|
||||||
|
for pos in q.run::<Position2d>() {
|
||||||
println!("Queried Position2d: {:?}", pos);
|
println!("Queried Position2d: {:?}", pos);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,204 @@
|
||||||
|
use std::{marker::PhantomData, any::TypeId, ptr::NonNull};
|
||||||
|
|
||||||
|
use super::{Fetch, Query};
|
||||||
|
|
||||||
|
pub struct FetchBorrow<'a, T> {
|
||||||
|
ptr: NonNull<u8>,
|
||||||
|
size: usize,
|
||||||
|
_phantom: PhantomData<&'a T>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T> Fetch<'a> for FetchBorrow<'a, T>
|
||||||
|
where
|
||||||
|
T: 'a,
|
||||||
|
{
|
||||||
|
type Item = &'a T;
|
||||||
|
|
||||||
|
fn create_empty() -> Self {
|
||||||
|
FetchBorrow {
|
||||||
|
ptr: NonNull::dangling(),
|
||||||
|
size: 0,
|
||||||
|
_phantom: PhantomData::default()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn get_item(&mut self, entity: crate::world::ArchetypeEntityId) -> Self::Item {
|
||||||
|
let ptr = NonNull::new_unchecked(self.ptr.as_ptr()
|
||||||
|
.add(entity.0 as usize * self.size))
|
||||||
|
.cast();
|
||||||
|
&*ptr.as_ptr()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct QueryBorrow<T> {
|
||||||
|
type_id: TypeId,
|
||||||
|
_phantom: PhantomData<T>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Query for QueryBorrow<T>
|
||||||
|
where
|
||||||
|
T: 'static
|
||||||
|
{
|
||||||
|
type Item<'a> = &'a T;
|
||||||
|
|
||||||
|
type Fetch<'a> = FetchBorrow<'a, T>;
|
||||||
|
|
||||||
|
fn can_visit_archetype(&self, archetype: &crate::archetype::Archetype) -> bool {
|
||||||
|
archetype.columns.iter().any(|c| c.info.type_id == self.type_id)
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn fetch<'a>(&self, _arch_id: crate::archetype::ArchetypeId, archetype: &'a crate::archetype::Archetype) -> Self::Fetch<'a> {
|
||||||
|
let col = archetype.columns.iter().find(|c| c.info.type_id == self.type_id)
|
||||||
|
.expect("You ignored 'can_visit_archetype'!");
|
||||||
|
let col_data = col.data;
|
||||||
|
|
||||||
|
FetchBorrow {
|
||||||
|
ptr: NonNull::new_unchecked(col_data.as_ptr()),
|
||||||
|
size: col.info.layout.size(),
|
||||||
|
_phantom: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct FetchBorrowMut<'a, T> {
|
||||||
|
ptr: NonNull<u8>,
|
||||||
|
size: usize,
|
||||||
|
_phantom: PhantomData<&'a T>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T> Fetch<'a> for FetchBorrowMut<'a, T>
|
||||||
|
where
|
||||||
|
T: 'a,
|
||||||
|
{
|
||||||
|
type Item = &'a mut T;
|
||||||
|
|
||||||
|
fn create_empty() -> Self {
|
||||||
|
FetchBorrowMut {
|
||||||
|
ptr: NonNull::dangling(),
|
||||||
|
size: 0,
|
||||||
|
_phantom: PhantomData::default()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn get_item(&mut self, entity: crate::world::ArchetypeEntityId) -> Self::Item {
|
||||||
|
let ptr = NonNull::new_unchecked(self.ptr.as_ptr()
|
||||||
|
.add(entity.0 as usize * self.size))
|
||||||
|
.cast();
|
||||||
|
&mut *ptr.as_ptr()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct QueryBorrowMut<T> {
|
||||||
|
type_id: TypeId,
|
||||||
|
_phantom: PhantomData<T>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Query for QueryBorrowMut<T>
|
||||||
|
where
|
||||||
|
T: 'static
|
||||||
|
{
|
||||||
|
type Item<'a> = &'a mut T;
|
||||||
|
|
||||||
|
type Fetch<'a> = FetchBorrowMut<'a, T>;
|
||||||
|
|
||||||
|
fn can_visit_archetype(&self, archetype: &crate::archetype::Archetype) -> bool {
|
||||||
|
archetype.columns.iter().any(|c| c.info.type_id == self.type_id)
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn fetch<'a>(&self, _arch_id: crate::archetype::ArchetypeId, archetype: &'a crate::archetype::Archetype) -> Self::Fetch<'a> {
|
||||||
|
let col = archetype.columns.iter().find(|c| c.info.type_id == self.type_id)
|
||||||
|
.expect("You ignored 'can_visit_archetype'!");
|
||||||
|
let col_data = col.data;
|
||||||
|
|
||||||
|
FetchBorrowMut {
|
||||||
|
ptr: NonNull::new_unchecked(col_data.as_ptr()),
|
||||||
|
size: col.info.layout.size(),
|
||||||
|
_phantom: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use std::any::TypeId;
|
||||||
|
|
||||||
|
use crate::{world::World, archetype::Archetype, query::View};
|
||||||
|
|
||||||
|
use super::{QueryBorrow, QueryBorrowMut};
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, Default)]
|
||||||
|
struct Vec2 {
|
||||||
|
x: f32,
|
||||||
|
y: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Vec2 {
|
||||||
|
pub fn new(x: f32, y: f32) -> Self {
|
||||||
|
Self {
|
||||||
|
x,
|
||||||
|
y,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a world with two entities, one at Vec(10, 50) and
|
||||||
|
/// the other at Vec2(25, 30).
|
||||||
|
fn prepare_world() -> World {
|
||||||
|
let mut world = World::new();
|
||||||
|
|
||||||
|
world.spawn((Vec2::new(10.0, 50.0),));
|
||||||
|
world.spawn((Vec2::new(25.0, 30.0),));
|
||||||
|
world
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn borrow_query() {
|
||||||
|
let world = prepare_world();
|
||||||
|
|
||||||
|
let borrow = QueryBorrow::<Vec2> {
|
||||||
|
type_id: TypeId::of::<Vec2>(),
|
||||||
|
_phantom: std::marker::PhantomData,
|
||||||
|
};
|
||||||
|
let archetypes: Vec<&Archetype> = world.archetypes.values().collect();
|
||||||
|
let v = View::new(borrow, archetypes);
|
||||||
|
|
||||||
|
for e in v.into_iter() {
|
||||||
|
println!("Found entity at {:?}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn borrow_mut_query() {
|
||||||
|
let world = prepare_world();
|
||||||
|
|
||||||
|
let borrow = QueryBorrowMut::<Vec2> {
|
||||||
|
type_id: TypeId::of::<Vec2>(),
|
||||||
|
_phantom: std::marker::PhantomData,
|
||||||
|
};
|
||||||
|
let archetypes: Vec<&Archetype> = world.archetypes.values().collect();
|
||||||
|
let v = View::new(borrow, archetypes);
|
||||||
|
|
||||||
|
let mut orig = vec![];
|
||||||
|
|
||||||
|
for v in v.into_iter() {
|
||||||
|
orig.push(v.clone());
|
||||||
|
v.x += 10.0;
|
||||||
|
v.y += 10.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now make sure the changes were actually made
|
||||||
|
|
||||||
|
let borrow = QueryBorrow::<Vec2> {
|
||||||
|
type_id: TypeId::of::<Vec2>(),
|
||||||
|
_phantom: std::marker::PhantomData,
|
||||||
|
};
|
||||||
|
let archetypes: Vec<&Archetype> = world.archetypes.values().collect();
|
||||||
|
let v = View::new(borrow, archetypes);
|
||||||
|
|
||||||
|
for (new, orig) in v.into_iter().zip(orig.iter()) {
|
||||||
|
assert!(new.x - orig.x == 10.0);
|
||||||
|
assert!(new.y - orig.y == 10.0);
|
||||||
|
}
|
||||||
|
println!("They were modified!");
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,40 @@
|
||||||
|
use crate::{world::Entity, archetype::{Archetype, ArchetypeId}};
|
||||||
|
|
||||||
|
use super::{Fetch, Query};
|
||||||
|
|
||||||
|
pub struct EntitiesFetch<'a> {
|
||||||
|
entities: &'a [Entity],
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Fetch<'a> for EntitiesFetch<'a> {
|
||||||
|
type Item = Entity;
|
||||||
|
|
||||||
|
unsafe fn get_item(&mut self, entity: crate::world::ArchetypeEntityId) -> Self::Item {
|
||||||
|
let e = *self.entities.get_unchecked(entity.0 as usize);
|
||||||
|
e
|
||||||
|
}
|
||||||
|
|
||||||
|
fn create_empty() -> Self {
|
||||||
|
Self {
|
||||||
|
entities: &[],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Entities;
|
||||||
|
|
||||||
|
impl Query for Entities {
|
||||||
|
type Item<'a> = Entity;
|
||||||
|
|
||||||
|
type Fetch<'a> = EntitiesFetch<'a>;
|
||||||
|
|
||||||
|
fn can_visit_archetype(&self, archetype: &Archetype) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn fetch<'a>(&self, arch_id: ArchetypeId, archetype: &'a Archetype) -> Self::Fetch<'a> {
|
||||||
|
EntitiesFetch {
|
||||||
|
entities: &archetype.entities,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,152 @@
|
||||||
|
use std::{any::{TypeId, Any}, cell::RefCell, rc::Rc, collections::{HashMap, VecDeque}, io::Read, slice::Iter, ops::Range};
|
||||||
|
|
||||||
|
use crate::{archetype::{Archetype, ComponentColumn, ArchetypeId}, bundle::Bundle, component::Component, world::{Record, EntityId, ArchetypeEntityId}};
|
||||||
|
|
||||||
|
pub mod view;
|
||||||
|
pub use view::*;
|
||||||
|
|
||||||
|
pub mod entities;
|
||||||
|
pub use entities::*;
|
||||||
|
|
||||||
|
pub mod borrow;
|
||||||
|
pub use borrow::*;
|
||||||
|
|
||||||
|
pub struct QuerySimple<'a> {
|
||||||
|
//entities: Iter<Entity
|
||||||
|
archetypes: Vec<&'a Archetype>,
|
||||||
|
type_ids: Vec<TypeId>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> QuerySimple<'a> {
|
||||||
|
pub fn new(archetypes: Vec<&'a Archetype>) -> Self {
|
||||||
|
Self {
|
||||||
|
archetypes,
|
||||||
|
type_ids: Vec::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn with_component<T: Any>(&mut self) {
|
||||||
|
let type_id = TypeId::of::<T>();
|
||||||
|
self.type_ids.push(type_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn run<C1: Component>(&self) -> impl Iterator<Item = &C1>
|
||||||
|
{
|
||||||
|
//let mut columns = Vec::new();
|
||||||
|
|
||||||
|
/* for type_id in self.type_ids.iter() {
|
||||||
|
for arch in self.archetypes.iter() {
|
||||||
|
if let Some(col) = arch.columns
|
||||||
|
.iter().find(|c| c.component_type_id() == type_id.clone()) {
|
||||||
|
|
||||||
|
columns.push(col);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut entities: Vec<&C1> = columns.iter().map(|bx| bx.as_any().downcast_ref::<C1>()
|
||||||
|
.expect("Failure to downcast component column"))
|
||||||
|
.collect(); */
|
||||||
|
|
||||||
|
let entities = self.archetypes
|
||||||
|
.iter()
|
||||||
|
.filter_map(|a| a.get_component_column::<C1>())
|
||||||
|
.flatten();
|
||||||
|
|
||||||
|
|
||||||
|
/* let columns = self.type_ids
|
||||||
|
.iter()
|
||||||
|
.map(|type_id| {
|
||||||
|
let a = self.archetypes
|
||||||
|
.iter()
|
||||||
|
.filter_map(|arch| {
|
||||||
|
arch.columns
|
||||||
|
.iter()
|
||||||
|
.find(|c| c.component_type_id() == type_id.clone())
|
||||||
|
});
|
||||||
|
}); */
|
||||||
|
|
||||||
|
/* self.type_ids
|
||||||
|
.iter()
|
||||||
|
.map(|type_id| {
|
||||||
|
self.archetypes
|
||||||
|
.iter()
|
||||||
|
.map(|arch| {
|
||||||
|
arch.get_component_column_typeid(type_id.clone())
|
||||||
|
})
|
||||||
|
}); */
|
||||||
|
|
||||||
|
|
||||||
|
return entities;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A [`Fetch`]er implementation gets data out of an archetype.
|
||||||
|
pub trait Fetch<'a> {
|
||||||
|
/// The type that this Fetch yields
|
||||||
|
type Item: 'a;
|
||||||
|
|
||||||
|
/// Returns true if the entity should be visited or skipped.
|
||||||
|
fn can_visit_item(&mut self, entity: ArchetypeEntityId) -> bool {
|
||||||
|
let _ = entity; // ignore compiler warning
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates an empty Fetch. DO NOT try to `get_item` on this
|
||||||
|
fn create_empty() -> Self;
|
||||||
|
|
||||||
|
unsafe fn get_item(&mut self, entity: ArchetypeEntityId) -> Self::Item;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait Query {
|
||||||
|
/// The item that this query yields
|
||||||
|
type Item<'a>: 'a;
|
||||||
|
|
||||||
|
/// The fetcher used for this query
|
||||||
|
type Fetch<'a>: Fetch<'a, Item = Self::Item<'a>>;
|
||||||
|
|
||||||
|
/// Returns true if the archetype should be visited or skipped.
|
||||||
|
fn can_visit_archetype(&self, archetype: &Archetype) -> bool;
|
||||||
|
|
||||||
|
unsafe fn fetch<'a>(&self, arch_id: ArchetypeId, archetype: &'a Archetype) -> Self::Fetch<'a>;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use crate::{world::World, archetype::Archetype};
|
||||||
|
|
||||||
|
use super::{View, Entities};
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, Default)]
|
||||||
|
struct Vec2 {
|
||||||
|
x: f32,
|
||||||
|
y: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Vec2 {
|
||||||
|
pub fn new(x: f32, y: f32) -> Self {
|
||||||
|
Self {
|
||||||
|
x,
|
||||||
|
y,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn simple_view() {
|
||||||
|
let mut world = World::new();
|
||||||
|
|
||||||
|
world.spawn((Vec2::new(10.0, 50.0),));
|
||||||
|
world.spawn((Vec2::new(25.0, 30.0),));
|
||||||
|
|
||||||
|
let entities = Entities {};
|
||||||
|
|
||||||
|
let archetypes: Vec<&Archetype> = world.archetypes.values().collect();
|
||||||
|
|
||||||
|
let v = View::new(entities, archetypes);
|
||||||
|
|
||||||
|
for e in v.into_iter() {
|
||||||
|
println!("Got entity! {:?}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,89 @@
|
||||||
|
use std::ops::Range;
|
||||||
|
|
||||||
|
use crate::{archetype::{Archetype, ArchetypeId}, world::ArchetypeEntityId};
|
||||||
|
|
||||||
|
use super::{Query, Fetch};
|
||||||
|
|
||||||
|
pub struct View<'a, Q: Query> {
|
||||||
|
query: Q,
|
||||||
|
archetypes: Vec<&'a Archetype>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, Q> View<'a, Q>
|
||||||
|
where
|
||||||
|
Q: Query,
|
||||||
|
{
|
||||||
|
pub fn new(query: Q, archetypes: Vec<&'a Archetype>) -> Self {
|
||||||
|
Self {
|
||||||
|
query,
|
||||||
|
archetypes,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, Q> IntoIterator for View<'a, Q>
|
||||||
|
where
|
||||||
|
Q: Query,
|
||||||
|
{
|
||||||
|
type Item = Q::Item<'a>;
|
||||||
|
|
||||||
|
type IntoIter = ViewIter<'a, Q>;
|
||||||
|
|
||||||
|
fn into_iter(self) -> Self::IntoIter {
|
||||||
|
ViewIter {
|
||||||
|
query: self.query,
|
||||||
|
fetcher: Q::Fetch::create_empty(),
|
||||||
|
archetypes: self.archetypes,
|
||||||
|
next_archetype: 0,
|
||||||
|
component_indices: 0..0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct ViewIter<'a, Q: Query> {
|
||||||
|
query: Q,
|
||||||
|
fetcher: Q::Fetch<'a>,
|
||||||
|
archetypes: Vec<&'a Archetype>,
|
||||||
|
next_archetype: usize,
|
||||||
|
component_indices: Range<u64>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, Q> Iterator for ViewIter<'a, Q>
|
||||||
|
where
|
||||||
|
Q: Query,
|
||||||
|
{
|
||||||
|
type Item = Q::Item<'a>;
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
loop {
|
||||||
|
if let Some(entity_index) = self.component_indices.next() {
|
||||||
|
let entity_index = ArchetypeEntityId(entity_index);
|
||||||
|
if !self.fetcher.can_visit_item(entity_index) {
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
let i = unsafe { self.fetcher.get_item(entity_index) };
|
||||||
|
return Some(i);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if self.next_archetype >= self.archetypes.len() {
|
||||||
|
return None; // ran out of archetypes to go through
|
||||||
|
}
|
||||||
|
|
||||||
|
let arch_id = self.next_archetype;
|
||||||
|
self.next_archetype += 1;
|
||||||
|
let arch = unsafe { self.archetypes.get_unchecked(arch_id) };
|
||||||
|
|
||||||
|
if arch.entities.len() == 0 {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if !self.query.can_visit_archetype(arch) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.fetcher = unsafe { self.query.fetch(ArchetypeId(arch_id as u64), arch) };
|
||||||
|
self.component_indices = 0..arch.entities.len() as u64;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
use std::{collections::{HashMap, VecDeque}, any::{Any, TypeId}};
|
use std::{collections::{HashMap, VecDeque}, any::{Any, TypeId}};
|
||||||
use std::slice::Iter;
|
use std::slice::Iter;
|
||||||
|
|
||||||
use crate::{archetype::{ArchetypeId, Archetype}, bundle::Bundle, component::Component};
|
use crate::{archetype::{ArchetypeId, Archetype}, bundle::Bundle, component::Component, query::QuerySimple};
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
||||||
pub struct EntityId(pub u64);
|
pub struct EntityId(pub u64);
|
||||||
|
@ -11,18 +11,19 @@ pub struct EntityId(pub u64);
|
||||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
||||||
pub struct ArchetypeEntityId(pub u64);
|
pub struct ArchetypeEntityId(pub u64);
|
||||||
|
|
||||||
|
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
||||||
pub struct Entity {
|
pub struct Entity {
|
||||||
id: EntityId,
|
id: EntityId,
|
||||||
generation: u64,
|
generation: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Record {
|
pub struct Record {
|
||||||
id: ArchetypeId,
|
id: ArchetypeId,
|
||||||
index: ArchetypeEntityId,
|
index: ArchetypeEntityId,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct World {
|
pub struct World {
|
||||||
archetypes: HashMap<ArchetypeId, Archetype>,
|
pub(crate) archetypes: HashMap<ArchetypeId, Archetype>,
|
||||||
next_archetype_id: ArchetypeId,
|
next_archetype_id: ArchetypeId,
|
||||||
entity_index: HashMap<EntityId, Record>,
|
entity_index: HashMap<EntityId, Record>,
|
||||||
dead_entities: VecDeque<Entity>,
|
dead_entities: VecDeque<Entity>,
|
||||||
|
@ -68,9 +69,7 @@ impl World {
|
||||||
.find(|a| a.is_archetype_for(bundle_types.clone()));
|
.find(|a| a.is_archetype_for(bundle_types.clone()));
|
||||||
|
|
||||||
if let Some(archetype) = archetype {
|
if let Some(archetype) = archetype {
|
||||||
// take components from the bundle and add it to the archetype
|
let arche_idx = archetype.add_entity(new_entity, bundle);
|
||||||
let columns = bundle.take_components();
|
|
||||||
let arche_idx = archetype.add_entity(columns);
|
|
||||||
|
|
||||||
// Create entity record and store it
|
// Create entity record and store it
|
||||||
let record = Record {
|
let record = Record {
|
||||||
|
@ -82,11 +81,10 @@ impl World {
|
||||||
}
|
}
|
||||||
// create a new archetype if one isn't found
|
// create a new archetype if one isn't found
|
||||||
else {
|
else {
|
||||||
let columns = bundle.take_components();
|
|
||||||
|
|
||||||
// create archetype
|
// create archetype
|
||||||
let new_arch_id = self.next_archetype_id.increment();
|
let new_arch_id = self.next_archetype_id.increment();
|
||||||
let archetype = Archetype::from_columns(new_arch_id, columns);
|
let mut archetype = Archetype::from_bundle_info(new_arch_id, bundle.info());
|
||||||
|
let entity_arch_id = archetype.add_entity(new_entity, bundle);
|
||||||
|
|
||||||
// store archetype
|
// store archetype
|
||||||
self.archetypes.insert(new_arch_id, archetype);
|
self.archetypes.insert(new_arch_id, archetype);
|
||||||
|
@ -95,7 +93,7 @@ impl World {
|
||||||
let record = Record {
|
let record = Record {
|
||||||
id: new_arch_id,
|
id: new_arch_id,
|
||||||
// this is the first entity in the archetype
|
// this is the first entity in the archetype
|
||||||
index: ArchetypeEntityId(0),
|
index: entity_arch_id,
|
||||||
};
|
};
|
||||||
|
|
||||||
self.entity_index.insert(new_entity.id, record);
|
self.entity_index.insert(new_entity.id, record);
|
||||||
|
@ -108,7 +106,7 @@ impl World {
|
||||||
let record = self.entity_index.get(&entity.id)?;
|
let record = self.entity_index.get(&entity.id)?;
|
||||||
let archetype = self.archetypes.get(&record.id)?;
|
let archetype = self.archetypes.get(&record.id)?;
|
||||||
|
|
||||||
archetype.get_component(record.index)
|
archetype.get_entity_component(record.index)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn query<T: Component>(&self) -> impl Iterator<Item = &T> {
|
pub fn query<T: Component>(&self) -> impl Iterator<Item = &T> {
|
||||||
|
@ -118,10 +116,34 @@ impl World {
|
||||||
.flatten()
|
.flatten()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn query_better(&self) -> QuerySimple {
|
||||||
|
let archetypes = self.archetypes.values().collect();
|
||||||
|
QuerySimple::new(archetypes)
|
||||||
|
}
|
||||||
|
|
||||||
/* pub fn query_m<B: Bundle>(&self) -> impl Iterator<Item = &T> {
|
/* pub fn query_m<B: Bundle>(&self) -> impl Iterator<Item = &T> {
|
||||||
self.archetypes
|
self.archetypes
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|(_, a)| a.get_component_column::<T>())
|
.filter_map(|(_, a)| a.get_component_column::<T>())
|
||||||
.flatten()
|
.flatten()
|
||||||
} */
|
} */
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::World;
|
||||||
|
|
||||||
|
struct Vec2 {
|
||||||
|
x: f32,
|
||||||
|
y: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn spawning_entity() {
|
||||||
|
let mut world = World::new();
|
||||||
|
let _e = world.spawn((Vec2 {
|
||||||
|
x: 10.0,
|
||||||
|
y: 15.0,
|
||||||
|
}, ));
|
||||||
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue