Skip to content

Commit

Permalink
Porting DeepPointer over from classic LiveSplit (#64)
Browse files Browse the repository at this point in the history
Despite the runtime already allows to resolve pointer paths with `process.read_pointer_path32()` and `process.read_pointer_path64()`, sometimes it's more convenient to define pointer paths, store them in a struct and dereference them when needed inside the autosplitter logic. This provides an essentially equal implementation of `DeepPointer` from OG LiveSplit, allowing for easier retrieval of memory addresses or values via the defined `deref_offset()` or `deeref::<T>()` functions.
  • Loading branch information
Jujstme authored Oct 14, 2023
1 parent 68ce739 commit 8b08b0e
Show file tree
Hide file tree
Showing 2 changed files with 82 additions and 0 deletions.
81 changes: 81 additions & 0 deletions src/deep_pointer.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
//! Support for storing pointer paths for easy dereferencing inside the autosplitter logic.
use arrayvec::ArrayVec;
use bytemuck::CheckedBitPattern;

use crate::{Address, Address32, Address64, Error, Process};

/// An abstraction of a pointer path, usable for easy dereferencing inside an autosplitter logic.
///
/// The maximum depth of the pointer path is given by the generic parameter `CAP`.
/// Of note, `CAP` must be higher or equal to the number of offsets provided in `path`,
/// otherwise calling `new()` on this struct will trigger a ***Panic***.
#[derive(Clone)]
pub struct DeepPointer<const CAP: usize> {
base_address: Address,
path: ArrayVec<u64, CAP>,
deref_type: DerefType,
}

impl<const CAP: usize> Default for DeepPointer<CAP> {
/// Creates a new empty DeepPointer.
#[inline]
fn default() -> Self {
Self {
base_address: Address::default(),
path: ArrayVec::default(),
deref_type: DerefType::default(),
}
}
}

impl<const CAP: usize> DeepPointer<CAP> {
/// Creates a new DeepPointer and specify the pointer size dereferencing
#[inline]
pub fn new(base_address: Address, deref_type: DerefType, path: &[u64]) -> Self {
assert!(CAP != 0 && CAP >= path.len());
Self {
base_address,
path: path.iter().cloned().collect(),
deref_type,
}
}

/// Creates a new DeepPointer with 32bit pointer size dereferencing
pub fn new_32bit(base_address: Address, path: &[u64]) -> Self {
Self::new(base_address, DerefType::Bit32, path)
}

/// Creates a new DeepPointer with 64bit pointer size dereferencing
pub fn new_64bit(base_address: Address, path: &[u64]) -> Self {
Self::new(base_address, DerefType::Bit64, path)
}

/// Dereferences the pointer path, returning the memory address of the value of interest
pub fn deref_offsets(&self, process: &Process) -> Result<Address, Error> {
let mut address = self.base_address;
let (&last, path) = self.path.split_last().ok_or(Error {})?;
for &offset in path {
address = match self.deref_type {
DerefType::Bit32 => process.read::<Address32>(address + offset)?.into(),
DerefType::Bit64 => process.read::<Address64>(address + offset)?.into(),
};
}
Ok(address + last)
}

/// Dereferences the pointer path, returning the value stored at the final memory address
pub fn deref<T: CheckedBitPattern>(&self, process: &Process) -> Result<T, Error> {
process.read(self.deref_offsets(process)?)
}
}

/// Describes the pointer size that should be used while deferecencing a pointer path
#[derive(Copy, Clone, Default)]
pub enum DerefType {
/// 4-byte pointer size, used in 32bit processes
Bit32,
/// 8-byte pointer size, used in 64bit processes
#[default]
Bit64,
}
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ pub mod time_util;
#[cfg(all(feature = "wasi-no-std", target_os = "wasi"))]

Check failure on line 143 in src/lib.rs

View workflow job for this annotation

GitHub Actions / Check formatting

Diff in /home/runner/work/asr/asr/src/lib.rs
mod wasi_no_std;
pub mod watcher;
pub mod deep_pointer;

pub use self::{primitives::*, runtime::*};
pub use arrayvec;
Expand Down

0 comments on commit 8b08b0e

Please sign in to comment.