iv-tools/src/ivpeek/memory_reader.rs

113 lines
3.5 KiB
Rust

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::<BattleEvent>()
.insert_resource(EventQueue::default())
.add_startup_system(init_memory_reader)
.add_system(flush_updates)
.add_system(update_inspector);
}
}
#[derive(Default)]
pub struct BattleEvent(Battle<PokemonInstance>);
#[derive(Resource, Default)]
struct EventQueue {
updates: Arc<Mutex<Vec<Battle<ParsedPokemonInstance>>>>,
}
fn flush_updates(
queue: Res<EventQueue>,
pokedex: Res<Database<Pokemon>>,
abilities: Res<Database<Ability>>,
natures: Res<Database<Nature>>,
mut events: EventWriter<BattleEvent>,
) {
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<Inspector>, mut events: EventReader<BattleEvent>) {
for event in events.iter() {
inspector.battle = event.0.clone();
}
}
fn init_memory_reader(queue: Res<EventQueue>) {
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:?}"),
}
}
});
}