From 00949fb2b5a8344c78b8597eee718633b8c2ba65 Mon Sep 17 00:00:00 2001 From: Anna Clemens Date: Sat, 5 Mar 2022 20:04:15 -0500 Subject: [PATCH] feat: keep track of steps and gil, too --- src/game_state.rs | 82 ++++++++++++++++++++++++++++++---------------- src/notes_state.rs | 8 ++--- 2 files changed, 58 insertions(+), 32 deletions(-) diff --git a/src/game_state.rs b/src/game_state.rs index 03f7da2..e83ac05 100644 --- a/src/game_state.rs +++ b/src/game_state.rs @@ -3,8 +3,10 @@ use sysinfo::{PidExt, ProcessExt, ProcessRefreshKind, RefreshKind, System, Syste use vmemory::ProcessMemory; pub struct GameState { - pub story: u16, pub location: u16, + pub gil: u32, + pub steps: u32, + pub stage: u16, pid: u32, base: usize, @@ -12,13 +14,18 @@ pub struct GameState { mem: Vec, proc_mem: ProcessMemory, - story_pattern: Vec, - location_pattern: Vec, + data_pattern: Vec, + data_addr: usize, } impl GameState { + const LOCATION_OFFSET: isize = -0x90; + const GIL_OFFSET: isize = 0x8; + const STEPS_OFFSET: isize = 0xC; + const STAGE_OFFSET: isize = 0x200; + pub fn new() -> Result { - let mut sys = System::new_with_specifics(RefreshKind::new().with_processes(ProcessRefreshKind::new())); + let sys = System::new_with_specifics(RefreshKind::new().with_processes(ProcessRefreshKind::new())); let proc = sys.processes() .iter() .find(|(_, proc)| proc.name() == "FFXII_TZA.exe"); @@ -42,12 +49,13 @@ impl GameState { } let tza_mem = mem.read_memory(base, base_size, false); - let story_ptr_pattern = crate::util::parse_pattern("48 8B 05 ?? ?? ?? ?? 48 85 C0 74 03 66 89 08 C3").unwrap(); - let location_pattern = crate::util::parse_pattern("8B 0D ?? ?? ?? ?? FF D0 4C 89 3D ?? ?? ?? ?? 48 83 C4 30 41 5F C3").unwrap(); + let data_pattern = crate::util::parse_pattern("48 8D 0D ?? ?? ?? ?? 41 B8 ?? ?? ?? ?? E8 ?? ?? ?? ?? 33 C9 E8").unwrap(); - Ok(Self { - story: 0, + let mut state = Self { location: 0, + gil: 0, + steps: 0, + stage: 0, pid: pid.as_u32(), base, @@ -55,39 +63,57 @@ impl GameState { mem: tza_mem, proc_mem: mem, - story_pattern: story_ptr_pattern, - location_pattern, - }) + data_pattern, + data_addr: 0, + }; + + state.set_addresses()?; + + Ok(state) } - pub fn refresh(&mut self) -> Result<()> { - let story_ptr_ptr = match crate::util::find_pattern(&self.mem, &self.story_pattern) { + fn find_address_indirect(&self, pattern: &[u8]) -> Result { + let ptr_ptr = match crate::util::find_pattern(&self.mem, pattern) { Some(ptr) => ptr, - None => anyhow::bail!("could not find story pointer"), + None => anyhow::bail!("could not find pointer"), }; - let location_ptr = match crate::util::find_pattern(&self.mem, &self.location_pattern) { + let ptr_offset = match crate::util::get_static_address(&self.mem, ptr_ptr, self.base) { + Some(addr) => addr, + None => anyhow::bail!("could not find pointer offset"), + }; + let ptr_vec = self.proc_mem.read_memory(ptr_offset, 8, true); + let ptr_array: [u8; 8] = ptr_vec.try_into().unwrap(); + Ok(u64::from_le_bytes(ptr_array) as usize - self.base) + } + + fn find_address(&self, pattern: &[u8]) -> Result { + let ptr = match crate::util::find_pattern(&self.mem, pattern) { Some(ptr) => ptr, None => anyhow::bail!("could not find location pointer"), }; - let story_ptr_offset = match crate::util::get_static_address(&self.mem, story_ptr_ptr, self.base) { - Some(addr) => addr, - None => anyhow::bail!("could not find story pointer offset"), - }; - let location_ptr_offset = match crate::util::get_static_address(&self.mem, location_ptr, self.base) { + let ptr_offset = match crate::util::get_static_address(&self.mem, ptr, self.base) { Some(addr) => addr, None => anyhow::bail!("could not find location pointer offset"), }; + Ok(ptr_offset) + } - let story_ptr_array: [u8; 8] = self.mem[story_ptr_offset..story_ptr_offset + 8].try_into().unwrap(); - let story_ptr = u64::from_le_bytes(story_ptr_array) as usize - self.base; + fn set_addresses(&mut self) -> Result<()> { + self.data_addr = self.find_address(&self.data_pattern)?; + Ok(()) + } - let story_vec = self.proc_mem.read_memory(self.base + story_ptr, 2, false); - let story_array: [u8; 2] = story_vec.try_into().map_err(|_| anyhow::anyhow!("not enough story bytes"))?; - self.story = u16::from_le_bytes(story_array); + fn read_data(&self, offset: isize) -> [u8; SIZE] { + let addr = self.data_addr as isize + offset; + let vec = self.proc_mem.read_memory(addr as usize, SIZE, true); + vec.try_into().unwrap() + } - let location_vec = self.proc_mem.read_memory(self.base + location_ptr_offset, 2, false); - let location_array: [u8; 2] = location_vec.try_into().map_err(|_| anyhow::anyhow!("not enough location bytes"))?; - self.location = u16::from_le_bytes(location_array); + pub fn refresh(&mut self) -> Result<()> { + self.location = u16::from_le_bytes(self.read_data(Self::LOCATION_OFFSET)); + self.gil = u32::from_le_bytes(self.read_data(Self::GIL_OFFSET)); + self.steps = u32::from_le_bytes(self.read_data(Self::STEPS_OFFSET)); + self.stage = u16::from_le_bytes(self.read_data(Self::STAGE_OFFSET)); Ok(()) } diff --git a/src/notes_state.rs b/src/notes_state.rs index 71d14a7..92774c5 100644 --- a/src/notes_state.rs +++ b/src/notes_state.rs @@ -22,7 +22,7 @@ impl<'a> NotesState<'a> { // find first step with a matching story stage let steps = notes.steps .iter() - .take_while(|step| step.stage <= game.story) + .take_while(|step| step.stage <= game.stage) .count(); let (step, step_idx, force) = if steps <= 1 { // nothing previous OR first step @@ -51,11 +51,11 @@ impl<'a> NotesState<'a> { } pub fn tick(&mut self, game: &mut GameState) -> Result<()> { - self.last_stage = game.story; + self.last_stage = game.stage; self.last_location = game.location; game.refresh()?; - let stage_changed = self.last_stage != game.story; + let stage_changed = self.last_stage != game.stage; let location_changed = self.last_location != game.location; let step_advanced = stage_changed && self.change_step(game); @@ -99,7 +99,7 @@ impl<'a> NotesState<'a> { None => return false, }; - if next.stage == game.story { + if next.stage == game.stage { self.current_step = next; self.step_idx += 1; self.area_idx = 0;