-
Notifications
You must be signed in to change notification settings - Fork 9
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This adds support for easily reading values from Unity games. It has support for both the Mono and IL2CPP backens. Support for Unity is available via the `unity` crate feature. # Example ```rust use asr::{ future::retry, game_engine::unity::il2cpp::{Module, Version}, Address, Address64, }; // We first attach to the Mono module. Here we know that the game is using IL2CPP 2020. let module = Module::wait_attach(&process, Version::V2020).await; // We access the .NET DLL that the game code is in. let image = module.wait_get_default_image(&process).await; // We access a class called "Timer" in that DLL. let timer_class = image.wait_get_class(&process, &module, "Timer").await; // We access a static field called "_instance" representing the singleton // instance of the class. let instance = timer_class.wait_get_static_instance(&process, &module, "_instance").await; // Once we have the address of the instance, we want to access one of its // fields, so we get the offset of the "currentTime" field. let current_time_offset = timer_class.wait_get_field(&process, &module, "currentTime").await; // Now we can add it to the address of the instance and read the current time. if let Ok(current_time) = process.read::<f32>(instance + current_time_offset) { // Use the current time. } ``` Alternatively you can use the `Class` derive macro to generate the bindings for you. It is available via the `derive` crate feature. This allows reading the contents of an instance of the class described by the struct from a process. Each field must match the name of the field in the class exactly and needs to be of a type that can be read from a process. ```rust #[derive(Class)] struct Timer { currentLevelTime: f32, timerStopped: bool, } ``` This will bind to a .NET class of the following shape: ```csharp class Timer { float currentLevelTime; bool timerStopped; // ... } ``` The class can then be bound to the process like so: ```rust let timer_class = Timer::bind(&process, &module, &image).await; ``` Once you have an instance, you can read the instance from the process like so: ```rust if let Ok(timer) = timer_class.read(&process, timer_instance) { // Do something with the instance. } ``` References: https://github.com/just-ero/asl-help/tree/4c87822df0125b027d1af75e8e348c485817592d/src/Unity https://github.com/Unity-Technologies/mono https://github.com/CryZe/lunistice-auto-splitter/blob/b8c01031991783f7b41044099ee69edd54514dba/asr-dotnet/src/lib.rs
- Loading branch information
Showing
16 changed files
with
1,726 additions
and
12 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -12,3 +12,6 @@ heck = "0.4.0" | |
|
||
[lib] | ||
proc-macro = true | ||
|
||
[features] | ||
unity = [] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
use proc_macro::TokenStream; | ||
use quote::{quote, quote_spanned, ToTokens}; | ||
use syn::{Data, DeriveInput, Ident}; | ||
|
||
pub fn process(input: TokenStream, mono_module: impl ToTokens) -> TokenStream { | ||
let ast: DeriveInput = syn::parse(input).unwrap(); | ||
|
||
let struct_data = match ast.data { | ||
Data::Struct(s) => s, | ||
_ => panic!("Only structs are supported"), | ||
}; | ||
|
||
let struct_name = ast.ident; | ||
let stuct_name_string = struct_name.to_string(); | ||
|
||
let binding_name = Ident::new(&format!("{struct_name}Binding"), struct_name.span()); | ||
|
||
let mut field_names = Vec::new(); | ||
let mut field_name_strings = Vec::new(); | ||
let mut field_types = Vec::new(); | ||
let mut field_reads = Vec::new(); | ||
for field in struct_data.fields { | ||
let field_name = field.ident.clone().unwrap(); | ||
let span = field_name.span(); | ||
field_reads.push(quote_spanned! { span => | ||
process.read(instance + self.#field_name).map_err(drop)? | ||
}); | ||
field_names.push(field_name); | ||
field_name_strings.push(field.ident.clone().unwrap().to_string()); | ||
field_types.push(field.ty); | ||
} | ||
|
||
quote! { | ||
struct #binding_name { | ||
class: #mono_module::Class, | ||
#(#field_names: u32,)* | ||
} | ||
|
||
impl #struct_name { | ||
async fn bind( | ||
process: &asr::Process, | ||
module: &#mono_module::Module, | ||
image: &#mono_module::Image, | ||
) -> #binding_name { | ||
let class = image.wait_get_class(process, module, #stuct_name_string).await; | ||
|
||
#( | ||
let #field_names = class.wait_get_field(process, module, #field_name_strings).await; | ||
)* | ||
|
||
#binding_name { | ||
class, | ||
#(#field_names,)* | ||
} | ||
} | ||
} | ||
|
||
impl #binding_name { | ||
fn class(&self) -> &#mono_module::Class { | ||
&self.class | ||
} | ||
|
||
fn read(&self, process: &asr::Process, instance: asr::Address) -> Result<#struct_name, ()> { | ||
Ok(#struct_name {#( | ||
#field_names: #field_reads, | ||
)*}) | ||
} | ||
} | ||
} | ||
.into() | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
//! Support for attaching to various game engines. | ||
|
||
#[cfg(feature = "unity")] | ||
pub mod unity; |
Oops, something went wrong.