Async Entity Component System based on the ideas of specs (https://github.com/amethyst/specs)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

208 lines
4.8 KiB

  1. use std::io::Error as IoError;
  2. use std::time::{Duration, Instant};
  3. use async_ecs::{
  4. dispatcher::Error as DispatcherError, AsyncSystem, Dispatcher, Join, ParJoin, ParallelIterator,
  5. ReadStorage, System, VecStorage, World, WriteStorage,
  6. };
  7. use async_ecs_derive::Component;
  8. use log::info;
  9. use rand::random;
  10. use thiserror::Error;
  11. use tokio::{runtime::Builder, task::LocalSet};
  12. fn main() -> Result<(), Error> {
  13. env_logger::builder()
  14. .filter_level(log::LevelFilter::Info)
  15. .format_timestamp_nanos()
  16. .init();
  17. let rt = Builder::new_multi_thread()
  18. .worker_threads(num_cpus::get() + 4)
  19. .enable_all()
  20. .build()?;
  21. rt.block_on(async move { LocalSet::new().run_until(run()).await })
  22. }
  23. async fn run() -> Result<(), Error> {
  24. info!("Application started!");
  25. info!(" num_cpus = {}", num_cpus::get());
  26. let mut world = World::default();
  27. world.register_component::<Position>();
  28. world.register_component::<Velocity>();
  29. world.register_component::<Acceleration>();
  30. for _ in 0..ENTITY_COUNT {
  31. world
  32. .create_entity()
  33. .with(Velocity::random())
  34. .with(Position::random())
  35. .with(Acceleration::random())
  36. .build();
  37. }
  38. info!("World initialized!");
  39. let mut dispatcher = Dispatcher::builder()
  40. .with(ParMove, "move", &[])?
  41. .with(ParAccelerate, "accelerate", &["move"])?
  42. .build();
  43. info!("Setup done!");
  44. let mut delta = Duration::from_secs(0);
  45. for _ in 0..REPEAT_COUNT {
  46. info!("Start iteration");
  47. let start = Instant::now();
  48. world = dispatcher.dispatch(world).await?;
  49. let end = Instant::now();
  50. info!("End iteration");
  51. delta += end - start;
  52. }
  53. let delta = delta / REPEAT_COUNT;
  54. info!("Average time per dispatch: {:?}", delta);
  55. Ok(())
  56. }
  57. const ENTITY_COUNT: usize = 1_000_000;
  58. const REPEAT_COUNT: u32 = 100;
  59. #[derive(Debug, Component)]
  60. #[storage(VecStorage)]
  61. struct Position {
  62. x: f64,
  63. y: f64,
  64. }
  65. #[derive(Debug, Component)]
  66. #[storage(VecStorage)]
  67. struct Velocity {
  68. x: f64,
  69. y: f64,
  70. }
  71. #[derive(Debug, Component)]
  72. #[storage(VecStorage)]
  73. struct Acceleration {
  74. x: f64,
  75. y: f64,
  76. }
  77. struct SeqMove;
  78. struct SeqAccelerate;
  79. struct ParMove;
  80. struct ParAccelerate;
  81. #[derive(Debug, Error)]
  82. enum Error {
  83. #[error("IO Error: {0}")]
  84. IoError(IoError),
  85. #[error("Dispatcher Error: {0}")]
  86. DispatcherError(DispatcherError),
  87. }
  88. impl Position {
  89. fn random() -> Self {
  90. Self {
  91. x: random::<f64>() - 0.5,
  92. y: random::<f64>() - 0.5,
  93. }
  94. }
  95. }
  96. impl Velocity {
  97. fn random() -> Self {
  98. Self {
  99. x: random::<f64>() - 0.5,
  100. y: random::<f64>() - 0.5,
  101. }
  102. }
  103. }
  104. impl Acceleration {
  105. fn random() -> Self {
  106. Self {
  107. x: random::<f64>() - 0.5,
  108. y: random::<f64>() - 0.5,
  109. }
  110. }
  111. }
  112. impl<'a> System<'a> for SeqMove {
  113. type SystemData = (WriteStorage<'a, Position>, ReadStorage<'a, Velocity>);
  114. fn run(&mut self, (mut position, velocity): Self::SystemData) {
  115. for (position, velocity) in (&mut position, &velocity).join() {
  116. position.x += velocity.x;
  117. position.y += velocity.y;
  118. }
  119. }
  120. }
  121. impl<'a> AsyncSystem<'a> for SeqAccelerate {
  122. type SystemData = (WriteStorage<'a, Velocity>, ReadStorage<'a, Acceleration>);
  123. type Future = futures::future::Ready<()>;
  124. fn run(&mut self, (mut velocity, acceleration): Self::SystemData) -> Self::Future {
  125. for (velocity, acceleration) in (&mut velocity, &acceleration).join() {
  126. velocity.x += acceleration.x;
  127. velocity.y += acceleration.y;
  128. }
  129. futures::future::ready(())
  130. }
  131. }
  132. impl<'a> System<'a> for ParMove {
  133. type SystemData = (WriteStorage<'a, Position>, ReadStorage<'a, Velocity>);
  134. fn run(&mut self, (mut position, velocity): Self::SystemData) {
  135. (&mut position, &velocity)
  136. .par_join()
  137. .for_each(|(position, velocity)| {
  138. position.x += velocity.x;
  139. position.y += velocity.y;
  140. });
  141. }
  142. }
  143. impl<'a> AsyncSystem<'a> for ParAccelerate {
  144. type SystemData = (WriteStorage<'a, Velocity>, ReadStorage<'a, Acceleration>);
  145. type Future = futures::future::Ready<()>;
  146. fn run(&mut self, (mut velocity, acceleration): Self::SystemData) -> Self::Future {
  147. (&mut velocity, &acceleration)
  148. .par_join()
  149. .for_each(|(velocity, acceleration)| {
  150. velocity.x += acceleration.x;
  151. velocity.y += acceleration.y;
  152. });
  153. futures::future::ready(())
  154. }
  155. }
  156. impl From<IoError> for Error {
  157. fn from(err: IoError) -> Self {
  158. Self::IoError(err)
  159. }
  160. }
  161. impl From<DispatcherError> for Error {
  162. fn from(err: DispatcherError) -> Self {
  163. Self::DispatcherError(err)
  164. }
  165. }