#![deny(missing_docs)]
#[doc = include_str!("../README.md")]
use anymap::Map;
use rayon::iter::{IndexedParallelIterator, IntoParallelRefMutIterator, ParallelIterator};
use rustc_hash::FxHashMap;
use slotmap::{DefaultKey, SecondaryMap, SlotMap};
use std::any::{Any, TypeId};
mod macros;
pub use macros::*;
use rayon::prelude::ParallelSliceMut;
struct Children {
children: Vec<Entity>,
}
struct Parent(Entity);
#[derive(Clone, Copy, PartialEq, Debug, PartialOrd, Eq, Ord)]
pub struct Entity {
pub(crate) entity_id: DefaultKey,
}
pub trait Resource: 'static + Sized {
fn update(&mut self) {}
fn as_any(&self) -> &dyn Any {
self
}
fn as_any_mut(&mut self) -> &mut dyn Any {
self
}
}
trait ResourceWrapper {
fn update(&mut self);
fn as_any(&self) -> &dyn Any;
fn as_any_mut(&mut self) -> &mut dyn Any;
}
impl<T: Resource> ResourceWrapper for T {
fn update(&mut self) {
self.update();
}
fn as_any(&self) -> &dyn Any {
self
}
fn as_any_mut(&mut self) -> &mut dyn Any {
self
}
}
pub struct EntitiesAndComponents {
entities: SlotMap<DefaultKey, Entity>,
pub(crate) components: SlotMap<DefaultKey, Map<dyn Any + 'static>>, entities_with_components: FxHashMap<TypeId, SecondaryMap<DefaultKey, Entity>>,
pub(crate) resources: FxHashMap<TypeId, Box<dyn ResourceWrapper>>,
}
impl EntitiesAndComponents {
pub fn new() -> Self {
EntitiesAndComponents {
entities: SlotMap::with_capacity(100),
components: SlotMap::with_capacity(100),
entities_with_components: FxHashMap::with_capacity_and_hasher(3, Default::default()),
resources: FxHashMap::default(),
}
}
pub fn add_entity(&mut self) -> Entity {
let entity_id = self.components.insert(Map::new());
self.entities.insert(Entity { entity_id });
Entity { entity_id }
}
pub fn add_entity_with<T: OwnedComponents<Input = T>>(&mut self, components: T) -> Entity {
let entity = <T>::make_entity_with_components(self, components);
entity
}
pub fn remove_entity(&mut self, entity: Entity) {
self.remove_parent(entity);
let children = self
.try_get_components::<(Children,)>(entity)
.0
.unwrap_or(&Children { children: vec![] })
.children
.clone();
for child in children {
self.remove_entity(child);
}
match self.components.get(entity.entity_id) {
Some(components) => {
for type_id in components.as_raw().keys() {
match self.entities_with_components.get_mut(&type_id) {
Some(entities) => {
entities.remove(entity.entity_id);
}
None => {}
}
}
}
None => {}
}
self.components.remove(entity.entity_id);
self.entities.remove(entity.entity_id);
}
pub fn get_entities(&self) -> Vec<Entity> {
self.entities.values().cloned().collect::<Vec<Entity>>()
}
pub fn get_nth_entity(&self, index: usize) -> Option<Entity> {
if let Some(entity) = self.entities.values().nth(index) {
Some(entity.clone())
} else {
None
}
}
pub fn get_entity_count(&self) -> usize {
self.entities.len()
}
pub fn get_all_components(&self, entity: Entity) -> &anymap::Map<(dyn Any + 'static)> {
self.components.get(entity.entity_id).unwrap_or_else(|| {
panic!("Entity ID {entity:?} does not exist, was the Entity ID edited?");
})
}
pub fn get_all_components_mut(
&mut self,
entity: Entity,
) -> &mut anymap::Map<(dyn Any + 'static)> {
self.components
.get_mut(entity.entity_id)
.unwrap_or_else(|| {
panic!("Entity ID {entity:?} does not exist, was the Entity ID edited?");
})
}
pub fn try_get_component<T: Component>(&self, entity: Entity) -> Option<&Box<T>> {
self.components
.get(entity.entity_id)
.unwrap_or_else(|| {
panic!("Entity ID {entity:?} does not exist, was the Entity ID edited?");
})
.get::<Box<T>>()
}
pub fn try_get_component_mut<T: Component>(&mut self, entity: Entity) -> Option<&mut Box<T>> {
self.components
.get_mut(entity.entity_id)
.unwrap_or_else(|| {
panic!("Entity ID {entity:?} does not exist, was the Entity ID edited?");
})
.get_mut::<Box<T>>()
}
pub fn get_components<'a, T: ComponentsRef<'a> + 'static>(
&'a self,
entity: Entity,
) -> T::Result {
<T>::get_components(self, entity)
}
pub fn get_components_mut<'a, T: ComponentsMut<'a> + 'static>(
&'a mut self,
entity: Entity,
) -> T::Result {
<T>::get_components_mut(self, entity)
}
pub fn try_get_components<'a, T: TryComponentsRef<'a> + 'static>(
&'a self,
entity: Entity,
) -> T::Result {
<T>::try_get_components(self, entity)
}
pub fn try_get_components_mut<'a, T: TryComponentsMut<'a> + 'static>(
&'a mut self,
entity: Entity,
) -> T::Result {
<T>::try_get_components_mut(self, entity)
}
pub fn add_component_to<T: Component>(&mut self, entity: Entity, component: T) {
let components = self
.components
.get_mut(entity.entity_id)
.unwrap_or_else(|| {
panic!("Entity ID {entity:?} does not exist, was the Entity ID edited?");
});
components.insert(Box::new(component));
match self.entities_with_components.entry(TypeId::of::<Box<T>>()) {
std::collections::hash_map::Entry::Occupied(mut entry) => {
entry.get_mut().insert(entity.entity_id, entity);
}
std::collections::hash_map::Entry::Vacant(entry) => {
let mut new_map = SecondaryMap::new();
new_map.insert(entity.entity_id, entity);
entry.insert(new_map);
}
}
}
pub fn remove_component_from<T: Component>(&mut self, entity: Entity) {
let components = self
.components
.get_mut(entity.entity_id)
.unwrap_or_else(|| {
panic!("Entity ID {entity:?} does not exist, was the Entity ID edited?");
});
components.remove::<Box<T>>();
match self
.entities_with_components
.get_mut(&TypeId::of::<Box<T>>())
{
Some(entities) => {
entities.remove(entity.entity_id);
}
None => {}
}
}
pub fn get_entities_with_component<T: Component>(
&self,
) -> std::iter::Flatten<std::option::IntoIter<slotmap::secondary::Values<'_, DefaultKey, Entity>>>
{
match self.entities_with_components.get(&TypeId::of::<Box<T>>()) {
Some(entities) => Some(entities.values()).into_iter().flatten(),
None => None.into_iter().flatten(), }
}
pub fn get_entity_count_with_component<T: Component>(&self) -> usize {
match self.entities_with_components.get(&TypeId::of::<Box<T>>()) {
Some(entities) => entities.len(),
None => 0,
}
}
pub fn get_entity_with_component<T: Component>(&self, index: usize) -> Option<Entity> {
match self.entities_with_components.get(&TypeId::of::<Box<T>>()) {
Some(entities) => {
if let Some(entity) = entities.values().nth(index) {
Some(entity.clone())
} else {
None
}
}
None => None,
}
}
pub fn get_resource<T: Resource>(&self) -> Option<&T> {
match self.resources.get(&TypeId::of::<T>()) {
Some(resource) => {
let resource = (&**resource)
.as_any()
.downcast_ref::<T>()
.unwrap_or_else(|| {
panic!(
"Resource of type {type:?} does not exist, was the type edited?",
type = std::any::type_name::<T>()
);
});
Some(resource)
}
None => None,
}
}
pub fn add_resource<T: Resource>(&mut self, resource: T) {
self.resources.insert(TypeId::of::<T>(), Box::new(resource));
}
pub fn remove_resource<T: Resource>(&mut self) {
self.resources.remove(&TypeId::of::<T>());
}
pub fn get_resource_mut<T: Resource>(&mut self) -> Option<&mut T> {
match self.resources.get_mut(&TypeId::of::<T>()) {
Some(resource) => {
let resource = (&mut **resource)
.as_any_mut()
.downcast_mut::<T>()
.unwrap_or_else(|| {
panic!(
"Resource of type {type:?} does not exist, was the type edited?",
type = std::any::type_name::<T>()
);
});
Some(resource)
}
None => None,
}
}
pub fn does_entity_exist(&self, entity: Entity) -> bool {
self.entities.contains_key(entity.entity_id)
}
pub fn print_tree(&self) {
self.tree(0);
}
fn tree(&self, depth: usize) {
let mut all_entities = self.get_entities();
all_entities.sort();
if depth == 0 {
println!("Entities and Components Tree:");
}
for entity in all_entities {
let offset_string = " ".repeat(depth);
println!("{}Entity: {:?}", offset_string, entity);
for (type_id, _) in self.get_all_components(entity).as_raw() {
println!("{} TypeID: {:?}", offset_string, type_id);
}
}
}
pub fn get_children(&self, entity: Entity) -> Vec<Entity> {
let (children,) = self.try_get_components::<(Children,)>(entity);
if let Some(children) = children {
return children.children.clone();
} else {
return vec![];
}
}
pub fn get_parent(&self, entity: Entity) -> Option<Entity> {
let (parent,) = self.try_get_components::<(Parent,)>(entity);
if let Some(parent) = parent {
return Some(parent.0);
} else {
return None;
}
}
pub fn set_parent(&mut self, child_entity: Entity, parent_entity: Entity) -> bool {
if child_entity == parent_entity {
return false; }
self.remove_parent(child_entity);
if let (Some(children),) = self.try_get_components::<(Children,)>(parent_entity) {
if children.children.contains(&child_entity) {
return true; }
}
let mut current_parent = parent_entity;
while let Some(parent) = self.get_parent(current_parent) {
current_parent = parent;
if current_parent == child_entity {
return false; }
}
if let (Some(children),) = self.try_get_components_mut::<(Children,)>(parent_entity) {
children.children.push(child_entity);
} else {
let children = Children {
children: vec![child_entity],
};
self.add_component_to(parent_entity, children);
}
if let (Some(parent),) = self.try_get_components_mut::<(Parent,)>(child_entity) {
parent.0 = parent_entity;
} else {
let parent = Parent(parent_entity);
self.add_component_to(child_entity, parent);
}
true
}
pub fn remove_parent(&mut self, child_entity: Entity) {
if let (Some(parent),) = self.try_get_components::<(Parent,)>(child_entity) {
let (children,) = self.get_components_mut::<(Children,)>(parent.0);
children.children.retain(|&x| x != child_entity);
if children.children.is_empty() {
self.remove_component_from::<Parent>(child_entity);
}
self.remove_component_from::<Parent>(child_entity);
}
}
fn remove_all_children(&mut self, parent_entity: Entity) {
let children = self.get_children(parent_entity);
for child in children {
self.remove_parent(child);
}
}
pub fn get_entities_with_children(
&self,
) -> std::iter::Flatten<std::option::IntoIter<slotmap::secondary::Values<'_, DefaultKey, Entity>>>
{
self.get_entities_with_component::<Children>()
}
pub fn get_entities_with_parent(
&self,
) -> std::iter::Flatten<std::option::IntoIter<slotmap::secondary::Values<'_, DefaultKey, Entity>>>
{
self.get_entities_with_component::<Parent>()
}
}
pub struct EntitiesAndComponentsThreadSafe<'a> {
entities_and_components: &'a mut EntitiesAndComponents,
}
impl<'b> EntitiesAndComponentsThreadSafe<'b> {
fn new(entities_and_components: &'b mut EntitiesAndComponents) -> Self {
EntitiesAndComponentsThreadSafe {
entities_and_components: entities_and_components,
}
}
pub fn add_entity(&mut self) -> Entity {
self.entities_and_components.add_entity()
}
pub fn add_entity_with<T: OwnedComponents<Input = T> + Send + Sync>(
&mut self,
components: T,
) -> Entity {
self.entities_and_components.add_entity_with(components)
}
pub fn remove_entity(&mut self, entity: Entity) {
self.entities_and_components.remove_entity(entity)
}
pub fn get_entities(&self) -> Vec<Entity> {
self.entities_and_components.get_entities()
}
pub fn get_nth_entity(&self, index: usize) -> Option<Entity> {
self.entities_and_components.get_nth_entity(index)
}
pub fn get_entity_count(&self) -> usize {
self.entities_and_components.get_entity_count()
}
pub fn try_get_component<T: Component + Send + Sync>(&self, entity: Entity) -> Option<&Box<T>> {
self.entities_and_components.try_get_component(entity)
}
pub fn try_get_component_mut<T: Component + Send + Sync>(
&mut self,
entity: Entity,
) -> Option<&mut Box<T>> {
self.entities_and_components.try_get_component_mut(entity)
}
pub fn get_components<'a, T: ComponentsRef<'a> + Send + Sync + 'static>(
&'a self,
entity: Entity,
) -> T::Result {
self.entities_and_components.get_components::<T>(entity)
}
pub fn get_components_mut<'a, T: ComponentsMut<'a> + Send + Sync + 'static>(
&'a mut self,
entity: Entity,
) -> T::Result {
self.entities_and_components.get_components_mut::<T>(entity)
}
pub fn try_get_components<'a, T: TryComponentsRef<'a> + Send + Sync + 'static>(
&'a self,
entity: Entity,
) -> T::Result {
self.entities_and_components.try_get_components::<T>(entity)
}
pub fn try_get_components_mut<'a, T: TryComponentsMut<'a> + Send + Sync + 'static>(
&'a mut self,
entity: Entity,
) -> T::Result {
self.entities_and_components
.try_get_components_mut::<T>(entity)
}
pub fn add_component_to<T: Component + Send + Sync>(&mut self, entity: Entity, component: T) {
self.entities_and_components
.add_component_to(entity, component)
}
pub fn remove_component_from<T: Component + Send + Sync>(&mut self, entity: Entity) {
self.entities_and_components
.remove_component_from::<T>(entity)
}
pub fn get_entities_with_component<T: Component + Send + Sync>(
&self,
) -> std::iter::Flatten<std::option::IntoIter<slotmap::secondary::Values<'_, DefaultKey, Entity>>>
{
self.entities_and_components
.get_entities_with_component::<T>()
}
pub fn get_entity_count_with_component<T: Component + Send + Sync>(&self) -> usize {
self.entities_and_components
.get_entity_count_with_component::<T>()
}
pub fn get_entity_with_component<T: Component + Send + Sync>(
&self,
index: usize,
) -> Option<Entity> {
self.entities_and_components
.get_entity_with_component::<T>(index)
}
pub fn get_resource<T: Resource + Send + Sync>(&self) -> Option<&T> {
self.entities_and_components.get_resource::<T>()
}
pub fn add_resource<T: Resource + Send + Sync>(&mut self, resource: T) {
self.entities_and_components.add_resource(resource)
}
pub fn remove_resource<T: Resource + Send + Sync>(&mut self) {
self.entities_and_components.remove_resource::<T>()
}
pub fn get_resource_mut<T: Resource + Send + Sync>(&mut self) -> Option<&mut T> {
self.entities_and_components.get_resource_mut::<T>()
}
pub fn does_entity_exist(&self, entity: Entity) -> bool {
self.entities_and_components.does_entity_exist(entity)
}
pub fn get_children(&self, entity: Entity) -> Vec<Entity> {
self.entities_and_components.get_children(entity)
}
pub fn get_parent(&self, entity: Entity) -> Option<Entity> {
self.entities_and_components.get_parent(entity)
}
pub fn set_parent(&mut self, child_entity: Entity, parent_entity: Entity) -> bool {
self.entities_and_components
.set_parent(child_entity, parent_entity)
}
pub fn remove_parent(&mut self, child_entity: Entity) {
self.entities_and_components.remove_parent(child_entity)
}
pub fn get_entities_with_children(
&self,
) -> std::iter::Flatten<std::option::IntoIter<slotmap::secondary::Values<'_, DefaultKey, Entity>>>
{
self.entities_and_components.get_entities_with_children()
}
pub fn get_entities_with_parent(
&self,
) -> std::iter::Flatten<std::option::IntoIter<slotmap::secondary::Values<'_, DefaultKey, Entity>>>
{
self.entities_and_components.get_entities_with_parent()
}
}
pub struct SingleMutEntity<'a> {
entity: Entity,
entities_and_components: &'a mut EntitiesAndComponents,
}
impl<'a> SingleMutEntity<'a> {
pub fn get_component<T: Component + Send + Sync>(&self) -> &T {
self.entities_and_components
.try_get_component::<T>(self.entity)
.unwrap_or_else(|| {
panic!(
"Component of type {type:?} does not exist on entity {entity:?}",
type = std::any::type_name::<T>(),
entity = self.entity
);
})
}
pub fn get_resource<T: Resource + Send + Sync>(&self) -> &T {
self.entities_and_components
.get_resource::<T>()
.unwrap_or_else(|| {
panic!(
"Resource of type {type:?} does not exist, was the type edited?",
type = std::any::type_name::<T>()
);
})
}
pub fn try_get_component<T: Component + Send + Sync>(&self) -> Option<&Box<T>> {
self.entities_and_components
.try_get_component::<T>(self.entity)
}
pub fn get_component_mut<T: Component + Send + Sync>(&mut self) -> &mut T {
self.entities_and_components
.try_get_component_mut::<T>(self.entity)
.unwrap_or_else(|| {
panic!(
"Component of type {type:?} does not exist on entity {entity:?}",
type = std::any::type_name::<T>(),
entity = self.entity
);
})
}
pub fn try_get_component_mut<T: Component + Send + Sync>(&mut self) -> Option<&mut Box<T>> {
self.entities_and_components
.try_get_component_mut::<T>(self.entity)
}
pub fn get_components<'b, T: ComponentsRef<'b> + Send + Sync + 'static>(&'b self) -> T::Result {
<T>::get_components(self.entities_and_components, self.entity)
}
pub fn try_get_components<'b, T: TryComponentsRef<'b> + Send + Sync + 'static>(
&'b self,
) -> T::Result {
<T>::try_get_components(self.entities_and_components, self.entity)
}
pub fn get_components_mut<'b, T: ComponentsMut<'b> + Send + Sync + 'static>(
&'b mut self,
) -> T::Result {
<T>::get_components_mut(self.entities_and_components, self.entity)
}
pub fn try_get_components_mut<'b, T: TryComponentsMut<'b> + Send + Sync + 'static>(
&'b mut self,
) -> T::Result {
<T>::try_get_components_mut(self.entities_and_components, self.entity)
}
pub fn remove_component<T: Component + Send + Sync>(&mut self) {
self.entities_and_components
.remove_component_from::<T>(self.entity);
}
pub fn add_component<T: Component + Send + Sync>(&mut self, component: T) {
self.entities_and_components
.add_component_to(self.entity, component);
}
pub fn has_component<T: Component + Send + Sync>(&self) -> bool {
self.entities_and_components
.try_get_component::<T>(self.entity)
.is_some()
}
pub fn remove_entity(&mut self) {
self.entities_and_components.remove_entity(self.entity);
}
pub fn get_entity(&self) -> Entity {
self.entity
}
}
#[derive(Clone)]
struct EntitiesAndComponentPtr {
entities_and_components: *mut EntitiesAndComponents,
}
impl EntitiesAndComponentPtr {
pub(crate) unsafe fn as_mut(&mut self) -> &mut EntitiesAndComponents {
unsafe { &mut *self.entities_and_components }
}
}
unsafe impl Send for EntitiesAndComponentPtr {}
unsafe impl Sync for EntitiesAndComponentPtr {}
unsafe impl Send for EntitiesAndComponentsThreadSafe<'_> {}
unsafe impl Sync for EntitiesAndComponentsThreadSafe<'_> {}
pub struct SystemHandle {
system_id: DefaultKey,
}
pub struct World {
pub entities_and_components: EntitiesAndComponents,
systems: SlotMap<DefaultKey, Box<dyn SystemWrapper + Send + Sync>>,
}
impl World {
pub fn new() -> Self {
World {
entities_and_components: EntitiesAndComponents::new(),
systems: SlotMap::with_capacity(10),
}
}
pub fn add_system<T: System + Send + Sync + 'static>(&mut self, system: T) -> SystemHandle {
SystemHandle {
system_id: self.systems.insert(Box::new(system)),
}
}
pub fn remove_system(&mut self, system: SystemHandle) {
self.systems.remove(system.system_id);
}
pub fn remove_all_systems_of_type<T: System + Send + Sync + 'static>(&mut self) {
let mut systems_to_remove = Vec::new();
for (key, system) in self.systems.iter() {
if system.as_any().is::<T>() {
systems_to_remove.push(key);
}
}
for key in systems_to_remove {
self.systems.remove(key);
}
}
pub fn remove_all_systems(&mut self) {
self.systems.clear();
}
pub fn run(&mut self) {
for resource in self.entities_and_components.resources.values_mut() {
resource.update();
}
if self.systems.is_empty() {
return;
}
{
let thread_safe_entities_and_components =
EntitiesAndComponentsThreadSafe::new(&mut self.entities_and_components);
let mut systems_with_prestep = self
.systems
.values_mut()
.filter(|system| system.implements_prestep())
.collect::<Vec<&mut Box<dyn SystemWrapper + Sync + Send>>>();
systems_with_prestep
.par_iter_mut()
.for_each(|system| system.prestep(&thread_safe_entities_and_components));
}
{
let systems_with_single_entity_step = self
.systems
.values()
.filter(|system| system.implements_single_entity_step())
.collect::<Vec<&Box<dyn SystemWrapper + Sync + Send>>>();
if !systems_with_single_entity_step.is_empty() {
let entities_and_components_ptr = &mut self.entities_and_components as *mut _;
let entities_and_components_ptr = EntitiesAndComponentPtr {
entities_and_components: entities_and_components_ptr,
};
let chunk_size = 5;
let entities = &mut self.entities_and_components.get_entities();
let entity_len;
{
entity_len = entities.len();
}
let par_chunks = entities.par_chunks_mut(chunk_size);
let entities_and_components_ptr_iter =
std::iter::repeat(entities_and_components_ptr)
.take(entity_len)
.collect::<Vec<EntitiesAndComponentPtr>>();
par_chunks.zip(entities_and_components_ptr_iter).for_each(
|(entity_chunk, mut entities_and_components_ptr)| {
for entity in entity_chunk {
for system in systems_with_single_entity_step.as_slice() {
let mut single_entity = SingleMutEntity {
entity: *entity,
entities_and_components: unsafe {
entities_and_components_ptr.as_mut()
},
};
system.single_entity_step(&mut single_entity);
}
}
},
);
}
}
for system in &mut self.systems.values_mut() {
system.run(&mut self.entities_and_components);
}
}
}
impl Default for World {
fn default() -> Self {
Self::new()
}
}
pub trait Component: 'static {}
impl<T: 'static> Component for T {}
pub trait System: 'static + Sized {
fn prestep(&mut self, engine: &EntitiesAndComponentsThreadSafe) {}
fn implements_prestep(&self) -> bool {
false
}
fn single_entity_step(&self, single_entity: &mut SingleMutEntity) {}
fn implements_single_entity_step(&self) -> bool {
false
}
fn run(&mut self, engine: &mut EntitiesAndComponents) {}
fn as_any(&self) -> &dyn std::any::Any {
self
}
fn as_any_mut(&mut self) -> &mut dyn std::any::Any {
self
}
}
trait SystemWrapper {
fn prestep(&mut self, engine: &EntitiesAndComponentsThreadSafe);
fn implements_prestep(&self) -> bool;
fn single_entity_step(&self, single_entity: &mut SingleMutEntity);
fn implements_single_entity_step(&self) -> bool;
fn run(&mut self, engine: &mut EntitiesAndComponents);
fn as_any(&self) -> &dyn std::any::Any;
fn as_any_mut(&mut self) -> &mut dyn std::any::Any;
}
impl<T: System> SystemWrapper for T {
fn prestep(&mut self, engine: &EntitiesAndComponentsThreadSafe) {
System::prestep(self, engine);
}
fn implements_prestep(&self) -> bool {
System::implements_prestep(self)
}
fn single_entity_step(&self, single_entity: &mut SingleMutEntity) {
System::single_entity_step(self, single_entity);
}
fn implements_single_entity_step(&self) -> bool {
System::implements_single_entity_step(self)
}
fn run(&mut self, engine: &mut EntitiesAndComponents) {
System::run(self, engine);
}
fn as_any(&self) -> &dyn std::any::Any {
System::as_any(self)
}
fn as_any_mut(&mut self) -> &mut dyn std::any::Any {
System::as_any_mut(self)
}
}
#[cfg(test)]
mod tests {
use std::{
fs::{self, File, OpenOptions},
io::Write,
};
use super::*;
use rand::Rng;
#[derive(Debug, PartialEq, Clone)]
struct Position {
x: f32,
y: f32,
}
#[derive(Debug, PartialEq, Clone)]
struct Velocity {
x: f32,
y: f32,
}
struct MovementSystem {}
impl System for MovementSystem {
fn run(&mut self, engine: &mut EntitiesAndComponents) {
for i in 0..engine.entities.len() {
let entity = engine.get_nth_entity(i).unwrap(); let (position, velocity) =
engine.get_components_mut::<(Position, Velocity)>(entity);
position.x += velocity.x;
position.y += velocity.y;
}
}
}
struct ParallelMovementSystem {}
impl System for ParallelMovementSystem {
fn single_entity_step(&self, single_entity: &mut SingleMutEntity) {
let (position, velocity) = single_entity.get_components_mut::<(Position, Velocity)>();
position.x += velocity.x;
position.y += velocity.y;
}
fn implements_single_entity_step(&self) -> bool {
true
}
}
#[test]
fn test_components_mut() {
let mut engine = World::new();
let entities_and_components = &mut engine.entities_and_components;
let entity = entities_and_components.add_entity();
entities_and_components.add_component_to(entity, Position { x: 0.0, y: 0.0 });
entities_and_components.add_component_to(entity, Velocity { x: 1.0, y: 1.0 });
engine.add_system(MovementSystem {});
for _ in 0..5 {
engine.run();
}
}
#[test]
fn test_try_get_components() {
let mut engine = World::new();
let entities_and_components = &mut engine.entities_and_components;
let entity = entities_and_components.add_entity();
entities_and_components.add_component_to(entity, Position { x: 0.0, y: 0.0 });
entities_and_components.add_component_to(entity, Velocity { x: 1.0, y: 1.0 });
let (position, velocity) =
<(Position, Velocity)>::try_get_components(entities_and_components, entity);
assert_eq!(position.unwrap().x, 0.0);
assert_eq!(position.unwrap().y, 0.0);
assert_eq!(velocity.unwrap().x, 1.0);
assert_eq!(velocity.unwrap().y, 1.0);
}
#[test]
fn test_overriding_components() {
let mut engine = World::new();
let entities_and_components = &mut engine.entities_and_components;
let entity = entities_and_components.add_entity();
entities_and_components.add_component_to(entity, Position { x: 0.0, y: 0.0 });
entities_and_components.add_component_to(entity, Position { x: 6.0, y: 1.0 });
let (position,) = entities_and_components.get_components::<(Position,)>(entity);
assert_eq!(position.x, 6.0);
assert_eq!(position.y, 1.0);
}
#[test]
fn test_multiple_entities() {
let mut engine = World::new();
let entities_and_components = &mut engine.entities_and_components;
let entity = entities_and_components.add_entity();
let entity_2 = entities_and_components.add_entity();
entities_and_components.add_component_to(entity, Position { x: 0.0, y: 0.0 });
entities_and_components.add_component_to(entity, Velocity { x: 1.0, y: 1.0 });
entities_and_components.add_component_to(entity_2, Position { x: 0.0, y: 0.0 });
entities_and_components.add_component_to(entity_2, Velocity { x: 1.0, y: 1.0 });
let (position,) = entities_and_components.get_components_mut::<(Position,)>(entity);
println!("Position: {}, {}", position.x, position.y);
}
#[test]
fn test_add_entity_with_components() {
let mut engine = World::new();
let entities_and_components = &mut engine.entities_and_components;
let entity = entities_and_components
.add_entity_with((Position { x: 0.0, y: 0.0 }, Velocity { x: 1.0, y: 1.0 }));
let (position, velocity) =
entities_and_components.get_components::<(Position, Velocity)>(entity);
assert_eq!(position.x, 0.0);
assert_eq!(position.y, 0.0);
assert_eq!(velocity.x, 1.0);
assert_eq!(velocity.y, 1.0);
}
#[test]
fn test_entity_removal() {
let mut engine = World::new();
let entities_and_components = &mut engine.entities_and_components;
let entity = entities_and_components
.add_entity_with((Position { x: 0.0, y: 0.0 }, Velocity { x: 1.0, y: 1.0 }));
let (position, velocity) =
entities_and_components.get_components::<(Position, Velocity)>(entity);
assert_eq!(position.x, 0.0);
assert_eq!(position.y, 0.0);
assert_eq!(velocity.x, 1.0);
assert_eq!(velocity.y, 1.0);
entities_and_components.remove_entity(entity);
assert_eq!(entities_and_components.get_entity_count(), 0);
let entity = entities_and_components.add_entity();
let (position, velocity) =
entities_and_components.try_get_components::<(Position, Velocity)>(entity);
assert_eq!(position, None);
assert_eq!(velocity, None);
}
#[test]
fn test_get_entities_with_component() {
let mut engine = World::new();
let entities_and_components = &mut engine.entities_and_components;
let entity = entities_and_components.add_entity();
let entity_2 = entities_and_components.add_entity();
entities_and_components.add_component_to(entity, Position { x: 0.0, y: 0.0 });
entities_and_components.add_component_to(entity, Velocity { x: 1.0, y: 1.0 });
entities_and_components.add_component_to(entity_2, Position { x: 0.0, y: 0.0 });
entities_and_components.add_component_to(entity_2, Velocity { x: 1.0, y: 1.0 });
let entities = entities_and_components.get_entities_with_component::<Position>();
assert_eq!(entities.count(), 2);
}
#[test]
#[should_panic]
fn test_generation_values() {
let mut engine = World::new();
let entities_and_components = &mut engine.entities_and_components;
let entity_1 = entities_and_components.add_entity();
let entity_2 = entities_and_components.add_entity();
entities_and_components.add_component_to(entity_1, Position { x: 0.0, y: 0.0 });
entities_and_components.add_component_to(entity_1, Velocity { x: 1.0, y: 1.0 });
entities_and_components.add_component_to(entity_2, Position { x: 0.0, y: 0.0 });
entities_and_components.add_component_to(entity_2, Velocity { x: 1.0, y: 1.0 });
entities_and_components.remove_entity(entity_1);
let entity_3 = entities_and_components.add_entity();
let (position, velocity) =
entities_and_components.try_get_components::<(Position, Velocity)>(entity_3);
assert_eq!(position, None);
assert_eq!(velocity, None);
let (position, velocity) =
entities_and_components.try_get_components::<(Position, Velocity)>(entity_1);
}
#[test]
fn test_resources() {
struct TestResource {
value: i32,
}
impl Resource for TestResource {
fn update(&mut self) {
self.value += 1;
}
fn as_any(&self) -> &dyn Any {
self
}
fn as_any_mut(&mut self) -> &mut dyn Any {
self
}
}
let mut engine = World::new();
{
let entities_and_components = &mut engine.entities_and_components;
let resource = TestResource { value: 0 };
entities_and_components.add_resource(resource);
let resource = entities_and_components
.get_resource::<TestResource>()
.unwrap();
assert_eq!(resource.value, 0);
}
for _ in 0..5 {
engine.run();
}
{
let entities_and_components = &mut engine.entities_and_components;
let resource = entities_and_components
.get_resource::<TestResource>()
.unwrap();
assert_eq!(resource.value, 5);
}
}
#[test]
fn test_parallel_systems() {
let mut engine = World::new();
let entity;
{
let entities_and_components = &mut engine.entities_and_components;
entity = entities_and_components.add_entity();
let entity_2 = entities_and_components.add_entity();
entities_and_components.add_component_to(entity, Position { x: 0.0, y: 0.0 });
entities_and_components.add_component_to(entity, Velocity { x: 1.0, y: 1.0 });
entities_and_components.add_component_to(entity_2, Position { x: 0.0, y: 0.0 });
entities_and_components.add_component_to(entity_2, Velocity { x: 1.0, y: 1.0 });
engine.add_system(ParallelMovementSystem {});
}
for _ in 0..5 {
engine.run();
}
{
let entities_and_components = &mut engine.entities_and_components;
let (position, velocity) =
entities_and_components.get_components::<(Position, Velocity)>(entity);
assert_eq!(position.x, 5.0);
assert_eq!(position.y, 5.0);
assert_eq!(velocity.x, 1.0);
assert_eq!(velocity.y, 1.0);
}
}
struct PrestepSystem {
postions: Vec<Position>,
}
impl System for PrestepSystem {
fn prestep(&mut self, engine: &EntitiesAndComponentsThreadSafe) {
self.postions.clear();
for entity in engine.get_entities_with_component::<Position>() {
let (position,) = engine.get_components::<(Position,)>(*entity);
self.postions.push(position.clone());
}
}
fn implements_prestep(&self) -> bool {
true
}
fn run(&mut self, engine: &mut EntitiesAndComponents) {
for position in &self.postions {
engine.add_entity_with((position.clone(),));
}
}
}
#[test]
fn test_prestep() {
let mut engine = World::new();
{
let entities_and_components = &mut engine.entities_and_components;
let entity = entities_and_components.add_entity();
let entity_2 = entities_and_components.add_entity();
entities_and_components.add_component_to(entity, Position { x: 0.0, y: 1.0 });
entities_and_components.add_component_to(entity, Velocity { x: 1.0, y: 1.0 });
entities_and_components.add_component_to(entity_2, Position { x: 1.0, y: 0.0 });
entities_and_components.add_component_to(entity_2, Velocity { x: 1.0, y: 1.0 });
engine.add_system(PrestepSystem {
postions: Vec::new(),
});
}
for _ in 0..1 {
engine.run();
}
{
let entities_and_components = &mut engine.entities_and_components;
let first_added_entity = entities_and_components.get_nth_entity(0);
let second_added_entity = entities_and_components.get_nth_entity(1);
let (position,) =
entities_and_components.get_components::<(Position,)>(first_added_entity.unwrap());
let (position_2,) =
entities_and_components.get_components::<(Position,)>(second_added_entity.unwrap());
assert_eq!(position.x, 0.0);
assert_eq!(position.y, 1.0);
assert_eq!(position_2.x, 1.0);
assert_eq!(position_2.y, 0.0);
}
}
#[test]
fn test_race_conditions() {
const NUM_ENTITIES: usize = 100;
const NUM_RUNS: usize = 100;
#[derive(Debug, PartialEq, Clone)]
struct NonSendSync {
ptr: *const i32,
}
struct NonSendSyncSystem {}
impl System for NonSendSyncSystem {
fn run(&mut self, engine: &mut EntitiesAndComponents) {
for i in 0..engine.entities.len() {
let entity = engine.get_nth_entity(i).unwrap(); let (non_send_sync,) = engine.get_components_mut::<(NonSendSync,)>(entity);
non_send_sync.ptr = i as *const i32;
}
}
}
let mut data = vec![];
let mut positions = vec![];
let mut velocities = vec![];
let mut non_send_syncs = vec![];
let mut rng = rand::thread_rng();
for _ in 0..NUM_ENTITIES {
positions.push(Position {
x: rng.gen_range(0.0..100.0),
y: rng.gen_range(0.0..100.0),
});
velocities.push(Velocity {
x: rng.gen_range(0.0..100.0),
y: rng.gen_range(0.0..100.0),
});
non_send_syncs.push(NonSendSync {
ptr: &rng.gen_range(0..10000),
});
}
for _ in 0..NUM_RUNS {
let mut engine = World::new();
for i in 0..100 {
engine.entities_and_components.add_entity_with((
positions[i].clone(),
velocities[i].clone(),
non_send_syncs[i].clone(),
));
}
for i in 0..NUM_ENTITIES {
if i % 2 == 0 {
engine.add_system(ParallelMovementSystem {});
} else {
engine.add_system(MovementSystem {});
}
}
for _ in 0..5 {
engine.run();
}
let mut current_run_data = vec![];
for entity in engine.entities_and_components.get_entities() {
let (position, velocity, non_send_sync) = engine
.entities_and_components
.get_components::<(Position, Velocity, NonSendSync)>(entity);
current_run_data.push([
position.x,
position.y,
velocity.x,
velocity.y,
(non_send_sync.ptr as usize) as f32,
]);
}
data.push(current_run_data);
}
for data_1 in &data {
for data_2 in &data {
if data_1 != data_2 {
println!("Data 1: {:?} doesn't match Data 2: {:?}", data_1, data_2);
assert_eq!(data_1, data_2);
}
}
}
}
#[test]
fn test_add_non_send_sync() {
struct NonSendSync {
ptr: *const i32,
}
let mut world = World::new();
let entities_and_components = &mut world.entities_and_components;
let entity = entities_and_components.add_entity();
entities_and_components.add_component_to(entity, NonSendSync { ptr: &0 });
let (non_send_sync,) = entities_and_components.get_components::<(NonSendSync,)>(entity);
assert_eq!(non_send_sync.ptr, &0);
}
fn test_children() {
let mut engine = World::new();
let entities_and_components = &mut engine.entities_and_components;
let parent = entities_and_components.add_entity();
let child = entities_and_components.add_entity();
entities_and_components.add_component_to(
parent,
Children {
children: vec![child],
},
);
entities_and_components.add_component_to(child, Parent(parent));
let children = entities_and_components.get_children(parent);
assert_eq!(children.len(), 1);
assert_eq!(children[0], child);
let parent = entities_and_components.get_parent(child);
assert_eq!(parent, parent);
entities_and_components.remove_parent(child);
let parent = entities_and_components.get_parent(child);
assert_eq!(parent, None);
}
#[test]
fn bench_every_function() {
let mut engine = World::new();
let entities_and_components = &mut engine.entities_and_components;
let start = std::time::Instant::now();
for i in 0..10000000 {
let entity = entities_and_components.add_entity();
}
let add_entity_time = start.elapsed();
let start = std::time::Instant::now();
for (i, entity) in entities_and_components.get_entities().iter().enumerate() {
entities_and_components.add_component_to(*entity, Position { x: 0.0, y: 0.0 });
if i % 2 == 0 {
entities_and_components.add_component_to(*entity, Velocity { x: 1.0, y: 1.0 });
}
}
let add_component_time = start.elapsed();
let start = std::time::Instant::now();
for (i, entity) in entities_and_components.get_entities().iter().enumerate() {
let (position,) = entities_and_components.get_components::<(Position,)>(*entity);
if i % 2 == 0 {
let (velocity,) = entities_and_components.get_components::<(Velocity,)>(*entity);
}
}
let get_component_time = start.elapsed();
let start = std::time::Instant::now();
for (i, entity) in entities_and_components.get_entities().iter().enumerate() {
if i % 2 == 0 {
let (position, velocity) =
entities_and_components.get_components::<(Position, Velocity)>(*entity);
} else {
let (position,) = entities_and_components.get_components::<(Position,)>(*entity);
}
}
let get_components_time = start.elapsed();
let start = std::time::Instant::now();
for (i, entity) in entities_and_components.get_entities().iter().enumerate() {
if i % 2 == 0 {
let (position, velocity) =
entities_and_components.get_components_mut::<(Position, Velocity)>(*entity);
} else {
let (position,) =
entities_and_components.get_components_mut::<(Position,)>(*entity);
}
}
let get_components_mut_time = start.elapsed();
let start = std::time::Instant::now();
for (i, entity) in entities_and_components.get_entities().iter().enumerate() {
if i % 2 == 0 {
let (position, velocity) =
entities_and_components.try_get_components::<(Position, Velocity)>(*entity);
} else {
let (position,) =
entities_and_components.try_get_components::<(Position,)>(*entity);
}
}
let try_get_components_time = start.elapsed();
let start = std::time::Instant::now();
for (i, entity) in entities_and_components.get_entities().iter().enumerate() {
if i % 2 == 0 {
let (position, velocity) =
entities_and_components.try_get_components_mut::<(Position, Velocity)>(*entity);
} else {
let (position,) =
entities_and_components.try_get_components_mut::<(Position,)>(*entity);
}
}
let try_get_components_mut_time = start.elapsed();
let start = std::time::Instant::now();
for entity in entities_and_components.get_entities() {
entities_and_components.remove_entity(entity);
}
let remove_entity_time = start.elapsed();
File::create("bench.txt").unwrap();
let mut file = OpenOptions::new()
.write(true)
.append(true)
.open("bench.txt")
.unwrap();
let _ = file.write_all(format!("Add Entity: {:?}\n", add_entity_time).as_bytes());
write_bar(&mut file, add_entity_time.as_micros() as usize);
let _ = file.write_all(format!("Add Component: {:?}\n", add_component_time).as_bytes());
write_bar(&mut file, add_component_time.as_micros() as usize);
let _ = file.write_all(format!("Get Component: {:?}\n", get_component_time).as_bytes());
write_bar(&mut file, get_component_time.as_micros() as usize);
let _ = file.write_all(format!("Get Components: {:?}\n", get_components_time).as_bytes());
write_bar(&mut file, get_components_time.as_micros() as usize);
let _ = file
.write_all(format!("Get Components Mut: {:?}\n", get_components_mut_time).as_bytes());
write_bar(&mut file, get_components_mut_time.as_micros() as usize);
let _ = file
.write_all(format!("Try Get Components: {:?}\n", try_get_components_time).as_bytes());
write_bar(&mut file, try_get_components_time.as_micros() as usize);
let _ = file.write_all(
format!(
"Try Get Components Mut: {:?}\n",
try_get_components_mut_time
)
.as_bytes(),
);
write_bar(&mut file, try_get_components_mut_time.as_micros() as usize);
let _ = file.write_all(format!("Remove Entity: {:?}\n", remove_entity_time).as_bytes());
write_bar(&mut file, remove_entity_time.as_micros() as usize);
}
fn write_bar(file: &mut File, length: usize) {
const ADJUSTMENT: usize = 100000;
let length = length / ADJUSTMENT;
for _ in 0..length {
let _ = file.write_all(b"#");
}
let _ = file.write_all(b"\n");
}
}