Skip to main content

oxide_engine/
watcher.rs

1//! Asset watcher for hot reloading
2
3use std::path::{Path, PathBuf};
4use std::sync::mpsc::{channel, Receiver};
5use std::time::Duration;
6
7use notify::{Config, Event, RecommendedWatcher, RecursiveMode, Watcher};
8
9/// Resource to watch asset files for hot-reloading
10pub struct AssetWatcher {
11    _watcher: RecommendedWatcher,
12    receiver: Receiver<notify::Result<Event>>,
13    changed_paths: Vec<PathBuf>,
14}
15
16impl AssetWatcher {
17    /// Creates a new AssetWatcher that watches a specific directory
18    pub fn new<P: AsRef<Path>>(watch_path: P) -> Result<Self, notify::Error> {
19        let (sender, receiver) = channel();
20
21        let mut watcher = RecommendedWatcher::new(
22            move |res| {
23                let _ = sender.send(res);
24            },
25            Config::default().with_poll_interval(Duration::from_millis(100)),
26        )?;
27
28        watcher.watch(watch_path.as_ref(), RecursiveMode::Recursive)?;
29
30        Ok(Self {
31            _watcher: watcher,
32            receiver,
33            changed_paths: Vec::new(),
34        })
35    }
36
37    /// Polls for changed files and returns a list of paths that were modified
38    pub fn poll_changed_files(&mut self) -> &[PathBuf] {
39        self.changed_paths.clear();
40
41        while let Ok(res) = self.receiver.try_recv() {
42            if let Ok(event) = res {
43                if event.kind.is_modify() || event.kind.is_create() {
44                    for path in event.paths {
45                        if !self.changed_paths.contains(&path) {
46                            self.changed_paths.push(path);
47                        }
48                    }
49                }
50            }
51        }
52
53        &self.changed_paths
54    }
55}