Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for Settings Lists #77

Merged
merged 1 commit into from
Nov 12, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 5 additions & 6 deletions src/emulator/gba/mednafen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,9 @@ impl State {
addr
};


self.cached_iwram_pointer = {
const SIG2: Signature<13> = Signature::new("48 8B 05 ?? ?? ?? ?? 81 E1 FF 7F 00 00");
const SIG2: Signature<13> =
Signature::new("48 8B 05 ?? ?? ?? ?? 81 E1 FF 7F 00 00");
let ptr: Address = SIG2.scan_process_range(game, main_module_range)? + 3;
let mut addr: Address = ptr + 0x4 + game.read::<i32>(ptr).ok()?;

Expand All @@ -45,8 +45,8 @@ impl State {
return None;
}
}
addr

addr
};

let ewram = game.read::<Address64>(self.cached_ewram_pointer).ok()?;
Expand All @@ -60,13 +60,12 @@ impl State {
game.read::<Address32>(ptr + 1).ok()?.into()
};


self.cached_iwram_pointer = {
const SIG2: Signature<11> = Signature::new("A1 ?? ?? ?? ?? 81 ?? FF 7F 00 00");
let ptr = SIG2.scan_process_range(game, main_module_range)?;
game.read::<Address32>(ptr + 1).ok()?.into()
};

let ewram = game.read::<Address32>(self.cached_ewram_pointer).ok()?;
let iwram = game.read::<Address32>(self.cached_iwram_pointer).ok()?;

Expand Down
6 changes: 3 additions & 3 deletions src/emulator/gba/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@
use crate::{Address, Error, Process};
use bytemuck::CheckedBitPattern;

mod emuhawk;
mod mednafen;
mod mgba;
mod nocashgba;
mod retroarch;
mod vba;
mod emuhawk;
mod mednafen;

/// A Nintendo Gameboy Advance emulator that the auto splitter is attached to.
pub struct Emulator {
Expand Down Expand Up @@ -84,7 +84,7 @@ impl Emulator {
false => {
self.ram_base = None;
false
},
}
}
}

Expand Down
34 changes: 19 additions & 15 deletions src/emulator/gba/vba.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,24 +48,24 @@ impl State {
return None;
}
}

addr
};

addr
};

self.is_emulating = {
const SIG_RUNNING: Signature<19> = Signature::new("83 3D ?? ?? ?? ?? 00 74 ?? 80 3D ?? ?? ?? ?? 00 75 ?? 66");
const SIG_RUNNING2: Signature<16> = Signature::new("48 8B 15 ?? ?? ?? ?? 31 C0 8B 12 85 D2 74 ?? 48");
const SIG_RUNNING: Signature<19> =
Signature::new("83 3D ?? ?? ?? ?? 00 74 ?? 80 3D ?? ?? ?? ?? 00 75 ?? 66");
const SIG_RUNNING2: Signature<16> =
Signature::new("48 8B 15 ?? ?? ?? ?? 31 C0 8B 12 85 D2 74 ?? 48");

if let Some(ptr) = SIG_RUNNING.scan_process_range(game, main_module_range) {
let ptr = ptr + 2;
ptr + 0x4 + game.read::<i32>(ptr).ok()? + 0x1
ptr + 0x4 + game.read::<i32>(ptr).ok()? + 0x1
} else {
let ptr = SIG_RUNNING2.scan_process_range(game, main_module_range)? + 3;
let ptr = ptr + 0x4 + game.read::<i32>(ptr).ok()?;
game.read::<Address64>(ptr).ok()?.into()
}

};

let ewram = game.read::<Address64>(self.cached_ewram_pointer).ok()?;
Expand All @@ -75,25 +75,28 @@ impl State {
} else {
const SIG: Signature<11> = Signature::new("A1 ?? ?? ?? ?? 81 ?? FF FF 03 00");
const SIG_OLD: Signature<12> = Signature::new("81 E6 FF FF 03 00 8B 15 ?? ?? ?? ??");

if let Some(ptr) = SIG.scan_process_range(game, main_module_range) {
self.cached_ewram_pointer = game.read::<Address32>(ptr + 1).ok()?.into();
self.cached_iwram_pointer = {
const SIG2: Signature<11> = Signature::new("A1 ?? ?? ?? ?? 81 ?? FF 7F 00 00");
let ptr = SIG2.scan_process_range(game, main_module_range)?;
game.read::<Address32>(ptr + 1).ok()?.into()
};

self.is_emulating = {
const SIG: Signature<19> = Signature::new("83 3D ?? ?? ?? ?? 00 74 ?? 80 3D ?? ?? ?? ?? 00 75 ?? 66");
const SIG_OLD: Signature<13> = Signature::new("8B 15 ?? ?? ?? ?? 31 C0 85 D2 74 ?? 0F");
const SIG: Signature<19> =
Signature::new("83 3D ?? ?? ?? ?? 00 74 ?? 80 3D ?? ?? ?? ?? 00 75 ?? 66");
const SIG_OLD: Signature<13> =
Signature::new("8B 15 ?? ?? ?? ?? 31 C0 85 D2 74 ?? 0F");

let ptr = SIG.scan_process_range(game, main_module_range)
let ptr = SIG
.scan_process_range(game, main_module_range)
.or_else(|| SIG_OLD.scan_process_range(game, main_module_range))?;

game.read::<Address32>(ptr + 2).ok()?.into()
};

let ewram = game.read::<Address32>(self.cached_ewram_pointer).ok()?;
let iwram = game.read::<Address32>(self.cached_iwram_pointer).ok()?;

Expand All @@ -104,11 +107,12 @@ impl State {
self.cached_iwram_pointer = self.cached_ewram_pointer.add_signed(0x4);

self.is_emulating = {
const SIG_RUNNING: Signature<11> = Signature::new("8B 0D ?? ?? ?? ?? 85 C9 74 ?? 8A");
const SIG_RUNNING: Signature<11> =
Signature::new("8B 0D ?? ?? ?? ?? 85 C9 74 ?? 8A");
let ptr = SIG_RUNNING.scan_process_range(game, main_module_range)? + 2;
game.read::<Address32>(ptr).ok()?.into()
};

let ewram = game.read::<Address32>(self.cached_ewram_pointer).ok()?;
let iwram = game.read::<Address32>(self.cached_iwram_pointer).ok()?;

Expand Down
1 change: 0 additions & 1 deletion src/runtime/process.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ use super::{sys, Error, MemoryRange};
pub use super::sys::ProcessId;

/// A process that the auto splitter is attached to.
#[derive(Debug)]
#[repr(transparent)]
pub struct Process(pub(super) sys::Process);

Expand Down
109 changes: 109 additions & 0 deletions src/runtime/settings/list.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
use core::fmt;

use crate::{runtime::sys, Error};

use super::Value;

/// A list of [`Value`]s that can itself be a [`Value`] and thus be stored in a
/// [`Map`](super::Map).
#[repr(transparent)]
pub struct List(pub(super) sys::SettingsList);

impl fmt::Debug for List {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_list().entries(self.iter()).finish()
}
}

impl Drop for List {
#[inline]
fn drop(&mut self) {
// SAFETY: The handle is valid and we own it, so it's our responsibility
// to free it.
unsafe { sys::settings_list_free(self.0) }
}
}

impl Clone for List {
#[inline]
fn clone(&self) -> Self {
// SAFETY: The handle is valid, so we can safely copy it.
Self(unsafe { sys::settings_list_copy(self.0) })
}
}

impl Default for List {
#[inline]
fn default() -> Self {
Self::new()
}
}

impl List {
/// Creates a new empty settings list.
#[inline]
pub fn new() -> Self {
// SAFETY: This is always safe to call.
Self(unsafe { sys::settings_list_new() })
}

/// Returns the number of values in the list.
#[inline]
pub fn len(&self) -> u64 {
// SAFETY: The handle is valid, so we can safely call this function.
unsafe { sys::settings_list_len(self.0) }
}

/// Returns [`true`] if the list has a length of 0.
#[inline]
pub fn is_empty(&self) -> bool {
self.len() == 0
}

/// Returns a copy of the value at the given index. Returns [`None`] if the
/// index is out of bounds. Any changes to it are only perceived if it's
/// stored back.
#[inline]
pub fn get(&self, index: u64) -> Option<Value> {
// SAFETY: The settings list handle is valid.
unsafe { sys::settings_list_get(self.0, index).map(Value) }
}

/// Pushes a copy of the value to the end of the list.
#[inline]
pub fn push(&self, value: &Value) {
// SAFETY: The settings list handle is valid and the value handle is
// valid.
unsafe { sys::settings_list_push(self.0, value.0) }
}

/// Inserts a copy of the value at the given index, pushing all values at
/// and after the index one position further. Returns an error if the index
/// is out of bounds. You may specify an index that is equal to the length
/// of the list to append the value to the end of the list.
#[inline]
pub fn insert(&self, index: u64, value: &Value) -> Result<(), Error> {
// SAFETY: The settings list handle is valid and the value handle is
// valid.
unsafe {
if sys::settings_list_insert(self.0, index, value.0) {
Ok(())
} else {
Err(Error {})
}
}
}

/// Returns an iterator over the values in the list. Every value is a copy,
/// so any changes to them are only perceived if they are stored back. The
/// iterator is double-ended, so it can be iterated backwards as well. While
/// it's possible to modify the list while iterating over it, it's not
/// recommended to do so, as the iterator might skip values or return
/// duplicate values. In that case it's better to clone the list before and
/// iterate over the clone or use [`get`](Self::get) to manually handle the
/// iteration.
#[inline]
pub fn iter(&self) -> impl DoubleEndedIterator<Item = Value> + '_ {
(0..self.len()).flat_map(|i| self.get(i))
}
}
Loading
Loading