use bevy::prelude::*; use notify_debouncer_mini::new_debouncer; use std::{ fs, sync::{Arc, Mutex}, thread, time::Duration, }; use crate::{database::Database, pokemon::*}; use super::{battle::parse_battle_party, inspector::*}; pub struct MemoryReaderPlugin; impl Plugin for MemoryReaderPlugin { fn build(&self, app: &mut App) { app.add_event::() .insert_resource(EventQueue::default()) .add_startup_system(init_memory_reader) .add_system(flush_updates) .add_system(update_inspector); } } #[derive(Default)] pub struct BattleEvent(Battle); #[derive(Resource, Default)] struct EventQueue { updates: Arc>>>, } fn flush_updates( queue: Res, pokedex: Res>, abilities: Res>, natures: Res>, mut events: EventWriter, ) { match queue.updates.lock() { Ok(mut updates) => { for update in updates.drain(..) { let mut battle = Battle::default(); for parsed in update.player_party.iter() { match PokemonInstance::from_parsed(parsed, &pokedex, &natures, &abilities) { Ok(instance) => battle.player_party.push(instance), Err(err) => warn!("{err}"), } } for parsed in update.enemy_party.iter() { match PokemonInstance::from_parsed(parsed, &pokedex, &natures, &abilities) { Ok(instance) => battle.enemy_party.push(instance), Err(err) => warn!("{err}"), } } events.send(BattleEvent(battle)) } } Err(err) => { error!("{err}"); } } } fn update_inspector(mut inspector: ResMut, mut events: EventReader) { for event in events.iter() { inspector.battle = event.0.clone(); } } fn init_memory_reader(queue: Res) { let updates = queue.updates.clone(); thread::spawn(move || { let watch_path = std::path::Path::new("/tmp/ivpeek/"); fs::create_dir_all(watch_path).expect("Failed to create path for {watch_path:?}"); let (tx, rx) = std::sync::mpsc::channel(); let mut debouncer = new_debouncer(Duration::from_millis(200), None, tx) .expect("Could not create notify debouncer"); debouncer .watcher() .watch(watch_path, notify::RecursiveMode::NonRecursive) .expect("Could not watch for {watch_path:?}"); for result in rx { match result { Ok(events) => { for event in events.iter() { match fs::read(&event.path) { Ok(data) => match parse_battle_party(&data) { Ok(battle) => match updates.lock() { Ok(mut updates) => updates.push(battle), Err(err) => error!("{err}"), }, Err(err) => error!("Failed to parse party data: ${err}"), }, _ => (), } } } Err(err) => error!("Watcher error: {err:?}"), } } }); }