113 lines
3.5 KiB
Rust
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:?}"),
|
|
}
|
|
}
|
|
});
|
|
}
|