#![deny(missing_docs)]
#[doc = include_str!("../README.md")]
use anymap::Map;
use rayon::iter::{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;
#[derive(Clone, Copy, PartialEq, Debug)]
pub struct Entity {
pub(crate) entity_id: DefaultKey,
}
pub trait Resource: 'static {
fn update(&mut self) {}
fn as_any(&self) -> &dyn Any;
}
pub struct EntitiesAndComponents {
entities: SlotMap<DefaultKey, Entity>,
pub(crate) components: SlotMap<DefaultKey, Map<dyn Any + 'static>>, entities_with_components: FxHashMap<TypeId, SecondaryMap<DefaultKey, Entity>>,
type_ids_on_entity: SecondaryMap<DefaultKey, Vec<TypeId>>,
pub(crate) resources: FxHashMap<TypeId, Box<dyn Resource>>,
}
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()),
type_ids_on_entity: SecondaryMap::new(),
resources: FxHashMap::default(),
}
}
pub fn add_entity(&mut self) -> Entity {
let entity_id = self.components.insert(Map::new());
self.entities.insert(Entity { entity_id });
self.type_ids_on_entity.insert(entity_id, vec![]);
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) {
for type_id in self.type_ids_on_entity[entity.entity_id].clone() {
match self.entities_with_components.get_mut(&type_id) {
Some(entities) => {
entities.remove(entity.entity_id);
}
None => {}
}
}
self.type_ids_on_entity.remove(entity.entity_id);
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::<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);
}
}
self.type_ids_on_entity[entity.entity_id].push(TypeId::of::<T>());
}
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::<T>()) {
Some(entities) => {
entities.remove(entity.entity_id);
}
None => {}
}
self.type_ids_on_entity[entity.entity_id].retain(|t| *t != TypeId::of::<T>());
}
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::<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::<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::<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 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 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 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);
}
}
struct EntitiesAndComponentPtr {
entities_and_components: *mut EntitiesAndComponents,
}
impl EntitiesAndComponentPtr {
pub fn as_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 World {
pub entities_and_components: EntitiesAndComponents,
systems: Vec<Box<dyn System + Sync + Send>>,
}
impl World {
pub fn new() -> Self {
World {
entities_and_components: EntitiesAndComponents::new(),
systems: vec![],
}
}
pub fn add_system<T: System + Send + Sync + 'static>(&mut self, system: T) {
self.systems.push(Box::new(system));
}
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
.iter_mut()
.filter(|system| system.implements_prestep())
.collect::<Vec<&mut Box<dyn System + 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
.iter()
.filter(|system| system.implements_single_entity_step())
.collect::<Vec<&Box<dyn System + Sync + Send>>>();
if !systems_with_single_entity_step.is_empty() {
let entities_and_components_ptr = &mut self.entities_and_components as *mut _;
let mut 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 par_chunks = entities.par_chunks_mut(chunk_size);
par_chunks.for_each(|entity_chunk| {
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: entities_and_components_ptr.as_mut(),
};
system.single_entity_step(&mut single_entity);
}
}
});
}
}
for system in &mut self.systems {
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 {
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) {}
}
#[cfg(test)]
mod tests {
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
}
}
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);
}
}