1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
//! In an ideal world, this would just be a new thread doing `sleep`.
//! Alas, Wasm forces us to do this

use crate::prelude::YarnSpinnerSystemSet;
use bevy::prelude::*;
use bevy::utils::HashMap;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
use std::time::Duration;

pub(crate) fn wait_command_plugin(app: &mut App) {
    app.init_resource::<Wait>()
        .add_systems(Update, update_wait.in_set(YarnSpinnerSystemSet));
}

#[derive(Debug, Clone, Resource, Default)]
pub(crate) struct Wait(HashMap<Duration, WaitPeriod>);

#[derive(Debug, Clone)]
pub(crate) struct WaitPeriod {
    duration: Duration,
    done: Arc<AtomicBool>,
}

impl Wait {
    pub(crate) fn add(&mut self, duration: Duration) -> Arc<AtomicBool> {
        let done = Arc::new(AtomicBool::new(false));
        self.0.insert(
            duration,
            WaitPeriod {
                duration,
                done: done.clone(),
            },
        );
        done
    }
}

pub(crate) fn update_wait(time: Res<Time>, mut wait: ResMut<Wait>) {
    for period in wait.0.values_mut() {
        if period.duration <= time.delta() {
            period.duration = Duration::from_secs(0);
            period.done.store(true, Ordering::Relaxed);
        } else {
            period.duration -= time.delta();
        }
    }
    wait.0.remove(&Duration::from_secs(0));
}