use crate::{
core::entities::Entities, Archetype, BatchedIter, Bundle, ComponentFlags, DynamicBundle,
Entity, EntityFilter, EntityReserver, Fetch, Location, MissingComponent, Mut, NoSuchEntity,
QueryFilter, QueryIter, ReadOnlyFetch, Ref, RefMut, WorldQuery,
};
use bevy_utils::{HashMap, HashSet};
use std::{any::TypeId, fmt, mem, ptr};
use super::borrow::EntityRef;
#[derive(Debug)]
pub struct World {
entities: Entities,
index: HashMap<Vec<TypeId>, u32>,
removed_components: HashMap<TypeId, Vec<Entity>>,
#[allow(missing_docs)]
pub archetypes: Vec<Archetype>,
archetype_generation: u64,
}
impl World {
pub fn new() -> Self {
let mut archetypes = Vec::new();
archetypes.push(Archetype::new(Vec::new()));
let mut index = HashMap::default();
index.insert(Vec::new(), 0);
Self {
entities: Entities::default(),
index,
archetypes,
archetype_generation: 0,
removed_components: HashMap::default(),
}
}
pub fn spawn(&mut self, bundle: impl DynamicBundle) -> Entity {
self.flush();
let entity = self.entities.alloc();
let archetype_id = bundle.with_ids(|ids| {
self.index.get(ids).copied().unwrap_or_else(|| {
let x = self.archetypes.len() as u32;
self.archetypes.push(Archetype::new(bundle.type_info()));
self.index.insert(ids.to_vec(), x);
self.archetype_generation += 1;
x
})
});
let archetype = &mut self.archetypes[archetype_id as usize];
unsafe {
let index = archetype.allocate(entity);
bundle.put(|ptr, ty, size| {
archetype.put_dynamic(ptr, ty, size, index, ComponentFlags::ADDED);
true
});
self.entities.meta[entity.id as usize].location = Location {
archetype: archetype_id,
index,
};
}
entity
}
pub fn spawn_batch<I>(&mut self, iter: I) -> SpawnBatchIter<'_, I::IntoIter>
where
I: IntoIterator,
I::Item: Bundle,
{
self.flush();
let iter = iter.into_iter();
let (lower, upper) = iter.size_hint();
let archetype_id = self.reserve_inner::<I::Item>(upper.unwrap_or(lower) as u32);
SpawnBatchIter {
inner: iter,
entities: &mut self.entities,
archetype_id,
archetype: &mut self.archetypes[archetype_id as usize],
}
}
pub fn despawn(&mut self, entity: Entity) -> Result<(), NoSuchEntity> {
self.flush();
let loc = self.entities.free(entity)?;
let archetype = &mut self.archetypes[loc.archetype as usize];
if let Some(moved) = unsafe { archetype.remove(loc.index) } {
self.entities.get_mut(moved).unwrap().index = loc.index;
}
for ty in archetype.types() {
let removed_entities = self
.removed_components
.entry(ty.id())
.or_insert_with(Vec::new);
removed_entities.push(entity);
}
Ok(())
}
pub fn reserve<T: Bundle>(&mut self, additional: u32) {
self.reserve_inner::<T>(additional);
}
pub fn reserve_entity(&self) -> Entity {
self.entities.reserve_entity()
}
fn reserve_inner<T: Bundle>(&mut self, additional: u32) -> u32 {
self.flush();
self.entities.reserve(additional);
let archetype_id = T::with_static_ids(|ids| {
self.index.get(ids).copied().unwrap_or_else(|| {
let x = self.archetypes.len() as u32;
self.archetypes.push(Archetype::new(T::static_type_info()));
self.index.insert(ids.to_vec(), x);
self.archetype_generation += 1;
x
})
});
self.archetypes[archetype_id as usize].reserve(additional as usize);
archetype_id
}
pub fn clear(&mut self) {
for archetype in &mut self.archetypes {
for ty in archetype.types() {
let removed_entities = self
.removed_components
.entry(ty.id())
.or_insert_with(Vec::new);
removed_entities.extend(archetype.iter_entities().copied());
}
archetype.clear();
}
self.entities.clear();
}
pub fn contains(&self, entity: Entity) -> bool {
self.entities.contains(entity)
}
pub fn has_component_type(&self, entity: Entity, ty: TypeId) -> bool {
self.get_entity_location(entity)
.map(|location| &self.archetypes[location.archetype as usize])
.map(|archetype| archetype.has_type(ty))
.unwrap_or(false)
}
#[inline]
pub fn query<Q: WorldQuery>(&self) -> QueryIter<'_, Q, ()>
where
Q::Fetch: ReadOnlyFetch,
{
unsafe { self.query_unchecked() }
}
#[inline]
pub fn query_filtered<Q: WorldQuery, F: QueryFilter>(&self) -> QueryIter<'_, Q, F>
where
Q::Fetch: ReadOnlyFetch,
{
unsafe { self.query_unchecked() }
}
#[inline]
pub fn query_mut<Q: WorldQuery>(&mut self) -> QueryIter<'_, Q, ()> {
unsafe { self.query_unchecked() }
}
#[inline]
pub fn query_filtered_mut<Q: WorldQuery, F: QueryFilter>(&mut self) -> QueryIter<'_, Q, F> {
unsafe { self.query_unchecked() }
}
#[inline]
pub fn query_batched<Q: WorldQuery>(&self, batch_size: usize) -> BatchedIter<'_, Q, ()>
where
Q::Fetch: ReadOnlyFetch,
{
unsafe { self.query_batched_unchecked(batch_size) }
}
#[inline]
pub fn query_batched_filtered<Q: WorldQuery, F: QueryFilter>(
&self,
batch_size: usize,
) -> BatchedIter<'_, Q, F>
where
Q::Fetch: ReadOnlyFetch,
{
unsafe { self.query_batched_unchecked(batch_size) }
}
#[inline]
pub fn query_batched_mut<Q: WorldQuery>(
&mut self,
batch_size: usize,
) -> BatchedIter<'_, Q, ()> {
unsafe { self.query_batched_unchecked(batch_size) }
}
#[inline]
pub fn query_batched_filtered_mut<Q: WorldQuery, F: QueryFilter>(
&mut self,
batch_size: usize,
) -> BatchedIter<'_, Q, F> {
unsafe { self.query_batched_unchecked(batch_size) }
}
#[inline]
pub unsafe fn query_unchecked<Q: WorldQuery, F: QueryFilter>(&self) -> QueryIter<'_, Q, F> {
QueryIter::new(&self.archetypes)
}
#[inline]
pub unsafe fn query_batched_unchecked<Q: WorldQuery, F: QueryFilter>(
&self,
batch_size: usize,
) -> BatchedIter<'_, Q, F> {
BatchedIter::new(&self.archetypes, batch_size)
}
#[inline]
pub fn query_one<Q: WorldQuery>(
&self,
entity: Entity,
) -> Result<<Q::Fetch as Fetch>::Item, NoSuchEntity>
where
Q::Fetch: ReadOnlyFetch,
{
unsafe { self.query_one_unchecked::<Q, ()>(entity) }
}
#[inline]
pub fn query_one_filtered<Q: WorldQuery, F: QueryFilter>(
&self,
entity: Entity,
) -> Result<<Q::Fetch as Fetch>::Item, NoSuchEntity>
where
Q::Fetch: ReadOnlyFetch,
{
unsafe { self.query_one_unchecked::<Q, F>(entity) }
}
#[inline]
pub fn query_one_mut<Q: WorldQuery>(
&mut self,
entity: Entity,
) -> Result<<Q::Fetch as Fetch>::Item, NoSuchEntity> {
unsafe { self.query_one_unchecked::<Q, ()>(entity) }
}
#[inline]
pub fn query_one_filtered_mut<Q: WorldQuery, F: QueryFilter>(
&mut self,
entity: Entity,
) -> Result<<Q::Fetch as Fetch>::Item, NoSuchEntity> {
unsafe { self.query_one_unchecked::<Q, F>(entity) }
}
#[inline]
pub unsafe fn query_one_unchecked<Q: WorldQuery, F: QueryFilter>(
&self,
entity: Entity,
) -> Result<<Q::Fetch as Fetch>::Item, NoSuchEntity> {
let loc = self.entities.get(entity)?;
let archetype = &self.archetypes[loc.archetype as usize];
let matches_filter = F::get_entity_filter(archetype)
.map(|entity_filter| entity_filter.matches_entity(loc.index))
.unwrap_or(false);
if matches_filter {
<Q::Fetch as Fetch>::get(archetype, 0)
.map(|fetch| fetch.fetch(loc.index))
.ok_or(NoSuchEntity)
} else {
Err(NoSuchEntity)
}
}
#[inline]
pub fn get<T: Component>(&self, entity: Entity) -> Result<&'_ T, ComponentError> {
unsafe {
let loc = self.entities.get(entity)?;
if loc.archetype == 0 {
return Err(MissingComponent::new::<T>().into());
}
Ok(&*self.archetypes[loc.archetype as usize]
.get::<T>()
.ok_or_else(MissingComponent::new::<T>)?
.as_ptr()
.add(loc.index as usize))
}
}
#[inline]
pub fn get_mut<T: Component>(&mut self, entity: Entity) -> Result<Mut<'_, T>, ComponentError> {
unsafe { self.get_mut_unchecked(entity) }
}
pub fn entity(&mut self, entity: Entity) -> Result<EntityRef<'_>, NoSuchEntity> {
Ok(match self.entities.get(entity)? {
Location { archetype: 0, .. } => EntityRef::empty(),
loc => unsafe { EntityRef::new(&self.archetypes[loc.archetype as usize], loc.index) },
})
}
#[inline]
pub unsafe fn get_mut_unchecked<T: Component>(
&self,
entity: Entity,
) -> Result<Mut<'_, T>, ComponentError> {
let loc = self.entities.get(entity)?;
if loc.archetype == 0 {
return Err(MissingComponent::new::<T>().into());
}
Ok(Mut::new(
&self.archetypes[loc.archetype as usize],
loc.index,
)?)
}
pub fn iter(&mut self) -> Iter<'_> {
Iter::new(&self.archetypes, &self.entities)
}
#[allow(missing_docs)]
pub fn removed<C: Component>(&self) -> &[Entity] {
self.removed_components
.get(&TypeId::of::<C>())
.map_or(&[], |entities| entities.as_slice())
}
pub fn insert(
&mut self,
entity: Entity,
bundle: impl DynamicBundle,
) -> Result<(), NoSuchEntity> {
use std::collections::hash_map::Entry;
self.flush();
let loc = self.entities.get_mut(entity)?;
unsafe {
let arch = &mut self.archetypes[loc.archetype as usize];
let mut info = arch.types().to_vec();
for ty in bundle.type_info() {
if let Some(ptr) = arch.get_dynamic(ty.id(), ty.layout().size(), loc.index) {
ty.drop(ptr.as_ptr());
} else {
info.push(ty);
}
}
info.sort();
let elements = info.iter().map(|x| x.id()).collect::<Vec<_>>();
let target = match self.index.entry(elements) {
Entry::Occupied(x) => *x.get(),
Entry::Vacant(x) => {
let index = self.archetypes.len() as u32;
self.archetypes.push(Archetype::new(info));
x.insert(index);
self.archetype_generation += 1;
index
}
};
if target == loc.archetype {
let arch = &mut self.archetypes[loc.archetype as usize];
bundle.put(|ptr, ty, size| {
arch.put_dynamic(ptr, ty, size, loc.index, ComponentFlags::MUTATED);
true
});
return Ok(());
}
let (source_arch, target_arch) = index2(
&mut self.archetypes,
loc.archetype as usize,
target as usize,
);
let target_index = target_arch.allocate(entity);
loc.archetype = target;
let old_index = mem::replace(&mut loc.index, target_index);
if let Some(moved) = source_arch.move_to(old_index, |ptr, ty, size, flags| {
target_arch.put_dynamic(ptr, ty, size, target_index, ComponentFlags::empty());
let type_state = target_arch.get_type_state_mut(ty).unwrap();
*type_state.component_flags().as_ptr().add(target_index) = flags;
}) {
self.entities.get_mut(moved).unwrap().index = old_index;
}
bundle.put(|ptr, ty, size| {
let had_component = source_arch.has_dynamic(ty);
let flags = if had_component {
ComponentFlags::MUTATED
} else {
ComponentFlags::ADDED
};
target_arch.put_dynamic(ptr, ty, size, target_index, flags);
true
});
}
Ok(())
}
pub fn insert_one(
&mut self,
entity: Entity,
component: impl Component,
) -> Result<(), NoSuchEntity> {
self.insert(entity, (component,))
}
pub fn remove<T: Bundle>(&mut self, entity: Entity) -> Result<T, ComponentError> {
self.flush();
let loc = self.entities.get_mut(entity)?;
unsafe {
let to_remove = T::with_static_ids(|ids| ids.iter().copied().collect::<HashSet<_>>());
let old_index = loc.index;
let source_arch = &self.archetypes[loc.archetype as usize];
let bundle = T::get(|ty, size| source_arch.get_dynamic(ty, size, old_index))?;
match self.remove_bundle_internal(entity, to_remove) {
Ok(_) => Ok(bundle),
Err(err) => Err(err),
}
}
}
fn remove_bundle_internal<S: core::hash::BuildHasher>(
&mut self,
entity: Entity,
to_remove: std::collections::HashSet<TypeId, S>,
) -> Result<(), ComponentError> {
use std::collections::hash_map::Entry;
let loc = self.entities.get_mut(entity)?;
let info = self.archetypes[loc.archetype as usize]
.types()
.iter()
.cloned()
.filter(|x| !to_remove.contains(&x.id()))
.collect::<Vec<_>>();
let elements = info.iter().map(|x| x.id()).collect::<Vec<_>>();
let target = match self.index.entry(elements) {
Entry::Occupied(x) => *x.get(),
Entry::Vacant(x) => {
self.archetypes.push(Archetype::new(info));
let index = (self.archetypes.len() - 1) as u32;
x.insert(index);
self.archetype_generation += 1;
index
}
};
let old_index = loc.index;
let (source_arch, target_arch) = index2(
&mut self.archetypes,
loc.archetype as usize,
target as usize,
);
let target_index = unsafe { target_arch.allocate(entity) };
loc.archetype = target;
loc.index = target_index;
let removed_components = &mut self.removed_components;
if let Some(moved) = unsafe {
source_arch.move_to(old_index, |src, ty, size, flags| {
if let Some(dst) = target_arch.get_dynamic(ty, size, target_index) {
ptr::copy_nonoverlapping(src, dst.as_ptr(), size);
let state = target_arch.get_type_state_mut(ty).unwrap();
*state.component_flags().as_ptr().add(target_index) = flags;
} else {
let removed_entities = removed_components.entry(ty).or_insert_with(Vec::new);
removed_entities.push(entity);
}
})
} {
self.entities.get_mut(moved).unwrap().index = old_index;
}
Ok(())
}
pub fn remove_one_by_one<T: Bundle>(&mut self, entity: Entity) -> Result<(), ComponentError> {
self.flush();
let to_remove = T::with_static_ids(|ids| ids.iter().copied().collect::<HashSet<_>>());
for component_to_remove in to_remove.into_iter() {
let loc = self.entities.get(entity)?;
if loc.archetype == 0 {
return Err(ComponentError::NoSuchEntity);
}
if self.archetypes[loc.archetype as usize].has_dynamic(component_to_remove) {
let mut single_component_hashset = std::collections::HashSet::new();
single_component_hashset.insert(component_to_remove);
match self.remove_bundle_internal(entity, single_component_hashset) {
Ok(_) | Err(ComponentError::MissingComponent(_)) => (),
Err(err) => return Err(err),
};
}
}
Ok(())
}
pub fn remove_one<T: Component>(&mut self, entity: Entity) -> Result<T, ComponentError> {
self.remove::<(T,)>(entity).map(|(x,)| x)
}
pub unsafe fn get_ref_at_location_unchecked<T: Component>(
&self,
location: Location,
) -> Result<Ref<T>, ComponentError> {
if location.archetype == 0 {
return Err(MissingComponent::new::<T>().into());
}
Ok(Ref::new(
&self.archetypes[location.archetype as usize],
location.index,
)?)
}
pub unsafe fn get_ref_mut_at_location_unchecked<T: Component>(
&self,
location: Location,
) -> Result<RefMut<T>, ComponentError> {
if location.archetype == 0 {
return Err(MissingComponent::new::<T>().into());
}
Ok(RefMut::new(
&self.archetypes[location.archetype as usize],
location.index,
)?)
}
pub unsafe fn get_at_location_unchecked<T: Component>(
&self,
location: Location,
) -> Result<&T, ComponentError> {
if location.archetype == 0 {
return Err(MissingComponent::new::<T>().into());
}
Ok(&*self.archetypes[location.archetype as usize]
.get::<T>()
.ok_or_else(MissingComponent::new::<T>)?
.as_ptr()
.add(location.index as usize))
}
pub unsafe fn get_mut_at_location_unchecked<T: Component>(
&self,
location: Location,
) -> Result<Mut<T>, ComponentError> {
if location.archetype == 0 {
return Err(MissingComponent::new::<T>().into());
}
Ok(Mut::new(
&self.archetypes[location.archetype as usize],
location.index,
)?)
}
pub unsafe fn get_unchecked_mut<T: Component>(
&self,
entity: Entity,
) -> Result<&mut T, ComponentError> {
let loc = self.entities.get(entity)?;
if loc.archetype == 0 {
return Err(MissingComponent::new::<T>().into());
}
Ok(&mut *self.archetypes[loc.archetype as usize]
.get::<T>()
.ok_or_else(MissingComponent::new::<T>)?
.as_ptr()
.add(loc.index as usize))
}
pub fn flush(&mut self) {
let arch = &mut self.archetypes[0];
for entity_id in self.entities.flush() {
self.entities.meta[entity_id as usize].location.index = unsafe {
arch.allocate(Entity {
id: entity_id,
generation: self.entities.meta[entity_id as usize].generation,
})
};
}
for i in 0..self.entities.reserved_len() {
let id = self.entities.reserved(i);
self.entities.meta[id as usize].location.index = unsafe {
arch.allocate(Entity {
id,
generation: self.entities.meta[id as usize].generation,
})
};
}
self.entities.clear_reserved();
}
pub fn archetypes(&self) -> impl ExactSizeIterator<Item = &'_ Archetype> + '_ {
self.archetypes.iter()
}
pub fn archetypes_generation(&self) -> ArchetypesGeneration {
ArchetypesGeneration(self.archetype_generation)
}
pub fn get_entity_location(&self, entity: Entity) -> Option<Location> {
self.entities.get(entity).ok()
}
pub fn clear_trackers(&mut self) {
for archetype in self.archetypes.iter_mut() {
archetype.clear_trackers();
}
self.removed_components.clear();
}
pub fn get_entity_reserver(&self) -> EntityReserver {
self.entities.get_reserver()
}
}
unsafe impl Send for World {}
unsafe impl Sync for World {}
impl Default for World {
fn default() -> Self {
Self::new()
}
}
impl<'a> IntoIterator for &'a mut World {
type IntoIter = Iter<'a>;
type Item = (Entity, EntityRef<'a>);
fn into_iter(self) -> Iter<'a> {
self.iter()
}
}
fn index2<T>(x: &mut [T], i: usize, j: usize) -> (&mut T, &mut T) {
assert!(i != j);
assert!(i < x.len());
assert!(j < x.len());
let ptr = x.as_mut_ptr();
unsafe { (&mut *ptr.add(i), &mut *ptr.add(j)) }
}
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub enum ComponentError {
NoSuchEntity,
MissingComponent(MissingComponent),
}
#[cfg(feature = "std")]
impl Error for ComponentError {}
impl fmt::Display for ComponentError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use ComponentError::*;
match *self {
NoSuchEntity => f.write_str("no such entity"),
MissingComponent(ref x) => x.fmt(f),
}
}
}
impl From<NoSuchEntity> for ComponentError {
fn from(NoSuchEntity: NoSuchEntity) -> Self {
ComponentError::NoSuchEntity
}
}
impl From<MissingComponent> for ComponentError {
fn from(x: MissingComponent) -> Self {
ComponentError::MissingComponent(x)
}
}
pub trait Component: Send + Sync + 'static {}
impl<T: Send + Sync + 'static> Component for T {}
pub struct Iter<'a> {
archetypes: core::slice::Iter<'a, Archetype>,
entities: &'a Entities,
current: Option<&'a Archetype>,
index: usize,
}
impl<'a> Iter<'a> {
fn new(archetypes: &'a [Archetype], entities: &'a Entities) -> Self {
Self {
archetypes: archetypes.iter(),
entities,
current: None,
index: 0,
}
}
}
unsafe impl Send for Iter<'_> {}
unsafe impl Sync for Iter<'_> {}
impl<'a> Iterator for Iter<'a> {
type Item = (Entity, EntityRef<'a>);
fn next(&mut self) -> Option<Self::Item> {
loop {
match self.current {
None => {
self.current = Some(self.archetypes.next()?);
self.index = 0;
}
Some(current) => {
if self.index == current.len() {
self.current = None;
continue;
}
let index = self.index;
self.index += 1;
let id = current.get_entity(index);
return Some((id, unsafe { EntityRef::new(current, index) }));
}
}
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
(0, Some(self.entities.meta.len()))
}
}
impl<A: DynamicBundle> Extend<A> for World {
fn extend<T>(&mut self, iter: T)
where
T: IntoIterator<Item = A>,
{
for x in iter {
self.spawn(x);
}
}
}
impl<A: DynamicBundle> core::iter::FromIterator<A> for World {
fn from_iter<I: IntoIterator<Item = A>>(iter: I) -> Self {
let mut world = World::new();
world.extend(iter);
world
}
}
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub struct ArchetypesGeneration(pub u64);
pub struct SpawnBatchIter<'a, I>
where
I: Iterator,
I::Item: Bundle,
{
inner: I,
entities: &'a mut Entities,
archetype_id: u32,
archetype: &'a mut Archetype,
}
impl<I> Drop for SpawnBatchIter<'_, I>
where
I: Iterator,
I::Item: Bundle,
{
fn drop(&mut self) {
for _ in self {}
}
}
impl<I> Iterator for SpawnBatchIter<'_, I>
where
I: Iterator,
I::Item: Bundle,
{
type Item = Entity;
fn next(&mut self) -> Option<Entity> {
let components = self.inner.next()?;
let entity = self.entities.alloc();
unsafe {
let index = self.archetype.allocate(entity);
components.put(|ptr, ty, size| {
self.archetype
.put_dynamic(ptr, ty, size, index, ComponentFlags::ADDED);
true
});
self.entities.meta[entity.id as usize].location = Location {
archetype: self.archetype_id,
index,
};
}
Some(entity)
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.inner.size_hint()
}
}
impl<I, T> ExactSizeIterator for SpawnBatchIter<'_, I>
where
I: ExactSizeIterator<Item = T>,
T: Bundle,
{
fn len(&self) -> usize {
self.inner.len()
}
}