Skip to content

Commit

Permalink
Add settings maps and values (#72)
Browse files Browse the repository at this point in the history
This adds support for interacting with the settings maps and settings
values. This allows auto splitters to store additional custom settings
that are not exposed to the user and also allows the auto splitters to
react to changes to the settings without the auto splitter having to be
restarted.
  • Loading branch information
CryZe committed Oct 26, 2023
1 parent 1ae3c32 commit d6d99f3
Show file tree
Hide file tree
Showing 13 changed files with 358 additions and 68 deletions.
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
16 changes: 8 additions & 8 deletions src/emulator/gba/retroarch.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
use crate::{
file_format::pe, signature::Signature, Address, Address32, Address64, Process,
};
use crate::{file_format::pe, signature::Signature, Address, Address32, Address64, Process};

#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct State {
Expand Down Expand Up @@ -32,8 +30,10 @@ impl State {
self.core_base = core_address;

match core_name {
"vbam_libretro.dll" | "vba_next_libretro.dll" | "mednafen_gba_libretro.dll" => self.vba(game, is_64_bit, core_name),
"mgba_libretro.dll" => super::mgba::State::find_ram(&mut super::mgba::State, game),
"vbam_libretro.dll" | "vba_next_libretro.dll" | "mednafen_gba_libretro.dll" => {
self.vba(game, is_64_bit, core_name)
}
"mgba_libretro.dll" => super::mgba::State::find_ram(&super::mgba::State, game),
"gpsp_libretro.dll" => self.gpsp(game, is_64_bit, core_name),
_ => None,
}
Expand Down Expand Up @@ -70,8 +70,8 @@ impl State {
return None;
}
}
addr

addr
};

let ewram = game.read::<Address64>(ewram_pointer).ok()?;
Expand All @@ -93,7 +93,7 @@ impl State {
let ptr = SIG2.scan_process_range(game, module_range)?;
game.read::<Address32>(ptr + 1).ok()?.into()
};

let ewram = game.read::<Address32>(ewram_pointer).ok()?;
let iwram = game.read::<Address32>(iwram_pointer).ok()?;

Expand Down
3 changes: 1 addition & 2 deletions src/future/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -413,8 +413,7 @@ macro_rules! async_main {
let size = mem::size_of::<F>();
const PAGE_SIZE: usize = 64 << 10;
assert!(mem::align_of::<F>() <= PAGE_SIZE);
// TODO: div_ceil
let pages = (size + (PAGE_SIZE - 1)) / PAGE_SIZE;
let pages = size.div_ceil(PAGE_SIZE);

#[cfg(target_arch = "wasm32")]
let old_page_count = core::arch::wasm32::memory_grow(0, pages);
Expand Down
4 changes: 2 additions & 2 deletions src/game_engine/unity/il2cpp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -320,7 +320,7 @@ impl Image {
}
}

/// A .NET class that is part of an [`Image`](Image).
/// A .NET class that is part of an [`Image`].
pub struct Class {
class: Address,
}
Expand Down Expand Up @@ -420,7 +420,7 @@ impl Class {
/// the offset of the field from the start of an instance of the class. If
/// it's a static field, the offset will be from the start of the static
/// table. This is the `await`able version of the
/// [`get_field`](Self::get_field) function.
/// [`get_field_offset`](Self::get_field_offset) function.
pub async fn wait_get_field_offset(
&self,
process: &Process,
Expand Down
6 changes: 3 additions & 3 deletions src/game_engine/unity/mono.rs
Original file line number Diff line number Diff line change
Expand Up @@ -316,7 +316,7 @@ impl Image {
}
}

/// A .NET class that is part of an [`Image`](Image).
/// A .NET class that is part of an [`Image`].
pub struct Class {
class: Address,
}
Expand Down Expand Up @@ -464,7 +464,7 @@ impl Class {
/// the offset of the field from the start of an instance of the class. If
/// it's a static field, the offset will be from the start of the static
/// table. This is the `await`able version of the
/// [`get_field`](Self::get_field) function.
/// [`get_field_offset`](Self::get_field_offset) function.
pub async fn wait_get_field_offset(
&self,
process: &Process,
Expand Down Expand Up @@ -838,7 +838,7 @@ fn detect_version(process: &Process) -> Option<Version> {
const SIG_202X: Signature<6> = Signature::new("00 32 30 32 ?? 2E");

let Some(addr) = SIG_202X.scan_process_range(process, unity_module) else {
return Some(Version::V2)
return Some(Version::V2);
};

const ZERO: u8 = b'0';
Expand Down
12 changes: 6 additions & 6 deletions src/game_engine/unity/scene.rs
Original file line number Diff line number Diff line change
Expand Up @@ -124,9 +124,8 @@ impl SceneManager {
self.get_current_scene(process)?.index(process, self)
}

/// Returns the full path to the current scene. Use
/// [`get_scene_name`](Self::get_scene_name) afterwards to
/// get the scene name.
/// Returns the full path to the current scene. Use [`get_scene_name`]
/// afterwards to get the scene name.
pub fn get_current_scene_path<const N: usize>(
&self,
process: &Process,
Expand Down Expand Up @@ -336,9 +335,10 @@ impl Transform {
let name_ptr = {
match scene_manager.is_il2cpp {
true => {
let Ok(name_ptr) = scene_manager
.read_pointer(process, vtable + 2_u64.wrapping_mul(scene_manager.pointer_size() as _))
else {
let Ok(name_ptr) = scene_manager.read_pointer(
process,
vtable + 2_u64.wrapping_mul(scene_manager.pointer_size() as _),
) else {
return false;
};

Expand Down
6 changes: 3 additions & 3 deletions src/runtime/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ mod memory_range;
mod process;
mod sys;

pub mod settings;
pub mod timer;
pub mod user_settings;

/// An error returned by a runtime function.
#[derive(Debug)]
Expand Down Expand Up @@ -56,7 +56,7 @@ pub fn get_os() -> Result<arrayvec::ArrayString<16>, Error> {
let mut buf = arrayvec::ArrayString::<16>::new();
// SAFETY: We provide a valid pointer and length to the buffer. We check
// whether the buffer was successfully filled and set the length of the
// buffer accordingly.
// buffer accordingly. The buffer is guaranteed to be valid UTF-8.
unsafe {
let mut len = buf.capacity();
let success = sys::runtime_get_os(buf.as_mut_ptr(), &mut len);
Expand All @@ -80,7 +80,7 @@ pub fn get_arch() -> Result<arrayvec::ArrayString<16>, Error> {
let mut buf = arrayvec::ArrayString::<16>::new();
// SAFETY: We provide a valid pointer and length to the buffer. We check
// whether the buffer was successfully filled and set the length of the
// buffer accordingly.
// buffer accordingly. The buffer is guaranteed to be valid UTF-8.
unsafe {
let mut len = buf.capacity();
let success = sys::runtime_get_arch(buf.as_mut_ptr(), &mut len);
Expand Down
Loading

0 comments on commit d6d99f3

Please sign in to comment.