Skip to content

Commit

Permalink
Merge branch 'master' into sms
Browse files Browse the repository at this point in the history
  • Loading branch information
Jujstme authored Oct 26, 2023
2 parents 99a776f + d6d99f3 commit f546ac2
Show file tree
Hide file tree
Showing 21 changed files with 1,062 additions and 141 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ unity = ["signature", "asr-derive?/unity"]

# Emulators
sms = ["flags", "signature"]
gba = []
gba = ["flags", "signature"]
gcn = ["flags"]
genesis = ["flags", "signature"]
ps1 = ["flags", "signature"]
Expand Down
62 changes: 41 additions & 21 deletions asr-derive/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,15 @@ use proc_macro::TokenStream;
use quote::{quote, quote_spanned};
use syn::{spanned::Spanned, Data, DeriveInput, Expr, ExprLit, Lit, Meta};

/// Generates a `register` method for a struct that automatically registers its
/// fields as settings and returns the struct with the user's settings applied.
/// Implements the `Gui` trait for a struct that allows you to register its
/// fields as settings widgets and returns the struct with the user's settings
/// applied.
///
/// # Example
///
/// ```no_run
/// #[derive(Settings)]
/// struct MySettings {
/// #[derive(Gui)]
/// struct Settings {
/// /// General Settings
/// _general_settings: Title,
/// /// Use Game Time
Expand All @@ -20,19 +21,17 @@ use syn::{spanned::Spanned, Data, DeriveInput, Expr, ExprLit, Lit, Meta};
/// }
/// ```
///
/// This will generate the following code:
/// The type can then be used like so:
///
/// ```no_run
/// impl MySettings {
/// pub fn register() -> Self {
/// asr::user_settings::add_title("_general_settings", "General Settings", 0);
/// let use_game_time = asr::user_settings::add_bool("use_game_time", "Use Game Time", false);
/// asr::user_settings::set_tooltip("use_game_time", "This is the tooltip.");
/// Self { use_game_time }
/// }
/// let mut settings = Settings::register();
///
/// loop {
/// settings.update();
/// // Do something with the settings.
/// }
/// ```
#[proc_macro_derive(Settings, attributes(default, heading_level))]
#[proc_macro_derive(Gui, attributes(default, heading_level))]
pub fn settings_macro(input: TokenStream) -> TokenStream {
let ast: DeriveInput = syn::parse(input).unwrap();

Expand All @@ -58,14 +57,21 @@ pub fn settings_macro(input: TokenStream) -> TokenStream {
let mut tooltip_string = String::new();
let mut is_in_tooltip = false;
for attr in &field.attrs {
let Meta::NameValue(nv) = &attr.meta else { continue };
let Some(ident) = nv.path.get_ident() else { continue };
let Meta::NameValue(nv) = &attr.meta else {
continue;
};
let Some(ident) = nv.path.get_ident() else {
continue;
};
if ident != "doc" {
continue;
}
let Expr::Lit(ExprLit {
lit: Lit::Str(s), ..
}) = &nv.value else { continue };
}) = &nv.value
else {
continue;
};
let value = s.value();
let value = value.trim();
let target_string = if is_in_tooltip {
Expand Down Expand Up @@ -102,7 +108,9 @@ pub fn settings_macro(input: TokenStream) -> TokenStream {
.attrs
.iter()
.filter_map(|x| {
let Meta::NameValue(nv) = &x.meta else { return None };
let Meta::NameValue(nv) = &x.meta else {
return None;
};
let span = nv.span();
if nv.path.is_ident("default") {
let value = &nv.value;
Expand All @@ -119,18 +127,30 @@ pub fn settings_macro(input: TokenStream) -> TokenStream {
}

quote! {
impl #struct_name {
pub fn register() -> Self {
impl asr::settings::Gui for #struct_name {
fn register() -> Self {
Self {
#(#field_names: {
let mut args = <#field_tys as asr::user_settings::Setting>::Args::default();
let mut args = <#field_tys as asr::settings::gui::Widget>::Args::default();
#args_init
let mut value = asr::user_settings::Setting::register(#field_name_strings, #field_descs, args);
let mut value = asr::settings::gui::Widget::register(#field_name_strings, #field_descs, args);
#field_tooltips
value
},)*
}
}

fn update_from(&mut self, settings_map: &asr::settings::Map) {
#({
let mut args = <#field_tys as asr::settings::gui::Widget>::Args::default();
#args_init
asr::settings::gui::Widget::update_from(&mut self.#field_names, settings_map, #field_name_strings, args);
})*
}

fn update(&mut self) {
self.update_from(&asr::settings::Map::load());
}
}
}
.into()
Expand Down
18 changes: 13 additions & 5 deletions asr-derive/src/unity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,9 @@ pub fn process(input: TokenStream, mono_module: impl ToTokens) -> TokenStream {
let field_name = field.ident.clone().unwrap();
let span = field_name.span();
let is_static = field.attrs.iter().any(|x| {
let Meta::Path(path) = &x.meta else { return false };
let Meta::Path(path) = &x.meta else {
return false;
};
path.is_ident("static_field")
});
field_reads.push(if is_static {
Expand All @@ -42,13 +44,19 @@ pub fn process(input: TokenStream, mono_module: impl ToTokens) -> TokenStream {
.attrs
.iter()
.find_map(|x| {
let Meta::NameValue(name_value) = &x.meta else { return None };
let Meta::NameValue(name_value) = &x.meta else {
return None;
};
if !name_value.path.is_ident("rename") {
return None;
}
let Expr::Lit(ExprLit {
lit: Lit::Str(name), ..
}) = &name_value.value else { return None };
lit: Lit::Str(name),
..
}) = &name_value.value
else {
return None;
};
Some(name.value())
})
.unwrap_or_else(|| field.ident.clone().unwrap().to_string());
Expand Down Expand Up @@ -97,7 +105,7 @@ pub fn process(input: TokenStream, mono_module: impl ToTokens) -> TokenStream {
let class = image.wait_get_class(process, module, #stuct_name_string).await;

#(
let #field_names = class.wait_get_field(process, module, #lookup_names).await;
let #field_names = class.wait_get_field_offset(process, module, #lookup_names).await;
)*

#binding_name {
Expand Down
80 changes: 0 additions & 80 deletions src/emulator/gba.rs

This file was deleted.

36 changes: 36 additions & 0 deletions src/emulator/gba/emuhawk.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
use crate::{Address, MemoryRangeFlags, Process};

#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct State {
base_addr: Address,
}

impl State {
pub fn find_ram(&mut self, game: &Process) -> Option<[Address; 2]> {
self.base_addr = game.get_module_address("mgba.dll").ok()?;

let addr = game
.memory_ranges()
.find(|range| {
range.size().is_ok_and(|size| size == 0x48000)
&& range.flags().is_ok_and(|flag| {
flag.contains(MemoryRangeFlags::WRITE | MemoryRangeFlags::READ)
})
})?
.address()
.ok()?;

Some([addr, addr + 0x40000])
}

pub fn keep_alive(&self, game: &Process, ram_base: &Option<[Address; 2]>) -> bool {
ram_base.is_some_and(|[ewram, _]| game.read::<u8>(ewram).is_ok())
&& game.read::<u8>(self.base_addr).is_ok()
}

pub const fn new() -> Self {
Self {
base_addr: Address::NULL,
}
}
}
106 changes: 106 additions & 0 deletions src/emulator/gba/mednafen.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
use crate::{file_format::pe, signature::Signature, Address, Address32, Address64, Error, Process};

#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct State {
cached_ewram_pointer: Address,
cached_iwram_pointer: Address,
is_64_bit: bool,
}

impl State {
pub fn find_ram(&mut self, game: &Process) -> Option<[Address; 2]> {
let main_module_range = super::PROCESS_NAMES
.iter()
.filter(|(_, state)| matches!(state, super::State::Mednafen(_)))
.find_map(|(name, _)| game.get_module_range(name).ok())?;

self.is_64_bit =
pe::MachineType::read(game, main_module_range.0) == Some(pe::MachineType::X86_64);

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

if game.read::<u8>(ptr + 10).ok()? == 0x48 {
addr = game.read::<Address64>(addr).ok()?.into();
if addr.is_null() {
return None;
}
}

addr

Check failure on line 33 in src/emulator/gba/mednafen.rs

View workflow job for this annotation

GitHub Actions / Check formatting

Diff in /home/runner/work/asr/asr/src/emulator/gba/mednafen.rs
};


self.cached_iwram_pointer = {
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()?;

if game.read::<u8>(ptr + 10).ok()? == 0x48 {
addr = game.read::<Address64>(addr).ok()?.into();
if addr.is_null() {
return None;

Check failure on line 45 in src/emulator/gba/mednafen.rs

View workflow job for this annotation

GitHub Actions / Check formatting

Diff in /home/runner/work/asr/asr/src/emulator/gba/mednafen.rs
}
}

addr
};

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

Some([ewram.into(), iwram.into()])
} else {
self.cached_ewram_pointer = {
const SIG: Signature<11> = Signature::new("A1 ?? ?? ?? ?? 81 ?? FF FF 03 00");
let ptr = SIG.scan_process_range(game, main_module_range)?;
game.read::<Address32>(ptr + 1).ok()?.into()

Check failure on line 60 in src/emulator/gba/mednafen.rs

View workflow job for this annotation

GitHub Actions / Check formatting

Diff in /home/runner/work/asr/asr/src/emulator/gba/mednafen.rs
};


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()

Check failure on line 67 in src/emulator/gba/mednafen.rs

View workflow job for this annotation

GitHub Actions / Check formatting

Diff in /home/runner/work/asr/asr/src/emulator/gba/mednafen.rs
};

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

Some([ewram.into(), iwram.into()])
}
}

fn read_pointer(&self, game: &Process, address: Address) -> Result<Address, Error> {
Ok(match self.is_64_bit {
true => game.read::<Address64>(address)?.into(),
false => game.read::<Address32>(address)?.into(),
})
}

pub fn keep_alive(&self, game: &Process, ram: &mut Option<[Address; 2]>) -> bool {
let ewram = match self.read_pointer(game, self.cached_ewram_pointer) {
Ok(x) => x,
_ => return false,
};

let iwram = match self.read_pointer(game, self.cached_iwram_pointer) {
Ok(x) => x,
_ => return false,
};

*ram = Some([ewram, iwram]);
true
}

pub const fn new() -> Self {
Self {
cached_ewram_pointer: Address::NULL,
cached_iwram_pointer: Address::NULL,
is_64_bit: false,
}
}
}
Loading

0 comments on commit f546ac2

Please sign in to comment.