feat: keep track of steps and gil, too
This commit is contained in:
parent
be511e15f9
commit
00949fb2b5
|
@ -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<u8>,
|
||||
proc_mem: ProcessMemory,
|
||||
|
||||
story_pattern: Vec<u8>,
|
||||
location_pattern: Vec<u8>,
|
||||
data_pattern: Vec<u8>,
|
||||
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<Self> {
|
||||
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<usize> {
|
||||
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<usize> {
|
||||
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<const SIZE: usize>(&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(())
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue