extern crate nalgebra;
use crate::integrator::Timestep;
use rand;
use rand::Rng;
use serde::{Deserialize, Serialize};
use specs::prelude::*;
#[derive(Serialize, Deserialize, Clone)]
pub struct EmitNumberPerFrame {
pub number: i32,
}
impl Component for EmitNumberPerFrame {
type Storage = HashMapStorage<Self>;
}
#[derive(Serialize, Deserialize, Clone)]
pub struct EmitFixedRate {
pub rate: f64,
}
impl Component for EmitFixedRate {
type Storage = HashMapStorage<Self>;
}
#[derive(Serialize, Deserialize, Clone)]
pub struct EmitOnce {}
impl Component for EmitOnce {
type Storage = HashMapStorage<Self>;
}
pub struct AtomNumberToEmit {
pub number: i32,
}
impl Component for AtomNumberToEmit {
type Storage = HashMapStorage<Self>;
}
pub struct EmitNumberPerFrameSystem;
impl<'a> System<'a> for EmitNumberPerFrameSystem {
type SystemData = (
ReadStorage<'a, EmitNumberPerFrame>,
WriteStorage<'a, AtomNumberToEmit>,
);
fn run(&mut self, (emit_numbers, mut numbers_to_emit): Self::SystemData) {
for (emit_number, mut number_to_emit) in (&emit_numbers, &mut numbers_to_emit).join() {
number_to_emit.number = emit_number.number;
}
}
}
pub struct EmitFixedRateSystem;
impl<'a> System<'a> for EmitFixedRateSystem {
type SystemData = (
ReadStorage<'a, EmitFixedRate>,
ReadExpect<'a, Timestep>,
WriteStorage<'a, AtomNumberToEmit>,
);
fn run(&mut self, (rates, timestep, mut emit_numbers): Self::SystemData) {
let mut rng = rand::thread_rng();
for (rate, mut emit_numbers) in (&rates, &mut emit_numbers).join() {
let avg_number_to_emit = rate.rate * timestep.delta;
let guaranteed_number = avg_number_to_emit.floor();
let number: i32;
if rng.gen::<f64>() < avg_number_to_emit - guaranteed_number {
number = guaranteed_number as i32 + 1;
} else {
number = guaranteed_number as i32;
}
emit_numbers.number = number;
}
}
}
pub struct EmitOnceSystem;
impl<'a> System<'a> for EmitOnceSystem {
type SystemData = (
ReadStorage<'a, EmitOnce>,
WriteStorage<'a, AtomNumberToEmit>,
);
fn run(&mut self, (emit_onces, mut emit_numbers): Self::SystemData) {
for (_, mut emit_numbers) in (&emit_onces, &mut emit_numbers).join() {
emit_numbers.number = 0;
}
}
}
pub mod tests {
#[allow(unused_imports)]
use super::*;
extern crate specs;
#[allow(unused_imports)]
use specs::{Builder, Entity, RunNow, World};
extern crate nalgebra;
#[allow(unused_imports)]
use nalgebra::Vector3;
#[test]
fn test_fixed_rate_emitter() {
let mut test_world = World::new();
test_world.register::<EmitFixedRate>();
test_world.register::<AtomNumberToEmit>();
let rate = 3.3;
let emitter = test_world
.create_entity()
.with(EmitFixedRate { rate })
.with(AtomNumberToEmit { number: 0 })
.build();
test_world.insert(Timestep { delta: 1.0 });
let mut system = EmitFixedRateSystem;
let n = 1000;
let mut total = 0;
for _ in 1..n {
system.run_now(&test_world);
let emits = test_world.read_storage::<AtomNumberToEmit>();
let number = emits.get(emitter).expect("Could not get entity").number;
assert!(number == 3 || number == 4);
total += number;
}
assert!(total > (n as f64 * 0.9 * rate) as i32);
assert!(total < (n as f64 * 1.1 * rate) as i32);
}
#[test]
fn test_fixed_number_emitter() {
let mut test_world = World::new();
test_world.register::<EmitNumberPerFrame>();
test_world.register::<AtomNumberToEmit>();
let number = 10;
let emitter = test_world
.create_entity()
.with(EmitNumberPerFrame { number })
.with(AtomNumberToEmit { number: 0 })
.build();
let mut system = EmitNumberPerFrameSystem;
system.run_now(&test_world);
let emits = test_world.read_storage::<AtomNumberToEmit>();
let emitted_number = emits.get(emitter).expect("Could not get entity").number;
assert_eq!(number, emitted_number);
}
}