diff --git a/.cargo/config.toml b/.cargo/config.toml index 7e54b9a..5dc9c3c 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -1,3 +1,13 @@ [build] target = "wasm32-unknown-unknown" -rustflags = ["-C", "target-feature=+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,+simd128"] +rustflags = [ + # The auto splitting runtime supports all the following WASM features. + "-C", "target-feature=+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,+simd128", +] + +[alias] +# Alias for building an optimized version of the auto splitter. +# Command: cargo b +b = [ + "build", "--release", +] diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..d78b03d --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,69 @@ +name: Build + +on: + pull_request: + push: + branches: + - 'master' + tags: + - '*' + +jobs: + build: + name: Build + runs-on: ubuntu-latest + steps: + - name: Checkout Commit + uses: actions/checkout@v3 + + - name: Install Rust + uses: hecrj/setup-rust-action@v1 + with: + components: rust-src + rust-version: nightly + targets: wasm32-unknown-unknown + + - name: Build + env: + RUSTFLAGS: -Z virtual-function-elimination -C lto -C target-feature=+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,+simd128 + run: | + cargo +nightly build --locked --release --features nightly -Z build-std=std,panic_abort -Z build-std-features=panic_immediate_abort + + - name: Release + if: github.ref == 'refs/heads/master' + uses: softprops/action-gh-release@v1 + with: + files: target/wasm32-unknown-unknown/release/lunistice_auto_splitter.wasm + name: Latest + tag_name: latest + + clippy: + name: Check clippy lints + runs-on: ubuntu-latest + steps: + - name: Checkout Commit + uses: actions/checkout@v3 + + - name: Install Rust + uses: hecrj/setup-rust-action@v1 + with: + components: clippy + targets: wasm32-unknown-unknown + + - name: Run Clippy + run: cargo clippy + + format: + name: Check formatting + runs-on: ubuntu-latest + steps: + - name: Checkout Commit + uses: actions/checkout@v3 + + - name: Install Rust + uses: hecrj/setup-rust-action@v1 + with: + components: rustfmt + + - name: Run cargo fmt + run: cargo fmt -- --check || true diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 0000000..2414269 --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,40 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "label": "Build nightly", + "type": "process", + "command": "cargo", + "args": [ + "+nightly", + "build", + "--release", + "--features", + "nightly", + "-Z", + "build-std=std,panic_abort", + "-Z", + "build-std-features=panic_immediate_abort" + ], + "options": { + "env": { + "RUSTFLAGS": "-Z virtual-function-elimination -C lto -C target-feature=+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,+simd128" + } + }, + "problemMatcher": [ + "$rustc" + ] + }, + { + "label": "Build stable", + "type": "process", + "command": "cargo", + "args": [ + "b" + ], + "problemMatcher": [ + "$rustc" + ] + } + ] +} diff --git a/Cargo.lock b/Cargo.lock index 7f66905..ce3b414 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -11,7 +11,7 @@ checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" [[package]] name = "asr" version = "0.1.0" -source = "git+https://github.com/LiveSplit/asr#186ea6a55b387d403be84286270ce2f36e9fde62" +source = "git+https://github.com/LiveSplit/asr#6518875820f53af6ac051625fb3abd0942c25e76" dependencies = [ "arrayvec", "bytemuck", @@ -64,7 +64,7 @@ checksum = "fdde5c9cd29ebd706ce1b35600920a33550e402fc998a2e53ad3b42c3c47a192" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.22", ] [[package]] @@ -91,18 +91,18 @@ checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" [[package]] name = "proc-macro2" -version = "1.0.60" +version = "1.0.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dec2b086b7a862cf4de201096214fa870344cf922b2b30c167badb3af3195406" +checksum = "7b368fba921b0dce7e60f5e04ec15e565b3303972b42bcfde1d0713b881959eb" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.28" +version = "1.0.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b9ab9c7eadfd8df19006f1cf1a4aed13540ed5cbc047010ece5826e10825488" +checksum = "573015e8ab27661678357f27dc26460738fd2b6c86e46f386fde94cb5d913105" dependencies = [ "proc-macro2", ] @@ -120,9 +120,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.18" +version = "2.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32d41677bcbe24c20c52e7c70b0d8db04134c5d1066bf98662e2871ad200ea3e" +checksum = "2efbeae7acf4eabd6bcdcbd11c92f45231ddda7539edc7806bd1a04a03b24616" dependencies = [ "proc-macro2", "quote", diff --git a/Cargo.toml b/Cargo.toml index b96a24b..9f2a6d9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,3 +22,6 @@ strip = true [profile.release.build-override] opt-level = 0 + +[features] +nightly = [] diff --git a/README.md b/README.md new file mode 100644 index 0000000..4db8772 --- /dev/null +++ b/README.md @@ -0,0 +1,29 @@ +# Lunistice Auto Splitter + +An auto splitter for Lunistice. + +## Compilation + +This auto splitter is written in Rust. In order to compile it, you need to +install the Rust compiler: [Install Rust](https://www.rust-lang.org/tools/install). + +Afterwards install the WebAssembly target: +```sh +rustup target add wasm32-unknown-unknown --toolchain stable +``` + +The auto splitter can now be compiled: +```sh +cargo b +``` + +The auto splitter is then available at: +``` +target/wasm32-unknown-unknown/release/lunistice_auto_splitter.wasm +``` + +Make sure too look into the [API documentation](https://livesplit.org/asr/asr/) for the `asr` crate. + +You can use the [debugger](https://github.com/CryZe/asr-debugger) while +developing the auto splitter to more easily see the log messages, statistics, +dump memory and more. diff --git a/asr-dotnet/src/lib.rs b/asr-dotnet/src/lib.rs index eab0089..5508174 100644 --- a/asr-dotnet/src/lib.rs +++ b/asr-dotnet/src/lib.rs @@ -11,7 +11,7 @@ use asr::{future::retry, signature::Signature, Address, Address64, Process}; pub use asr; pub use asr_dotnet_derive::*; -use bytemuck::{Pod, Zeroable}; +use bytemuck::{AnyBitPattern, Pod, Zeroable}; #[derive(Debug, Copy, Clone, Pod, Zeroable)] #[repr(transparent)] @@ -49,7 +49,7 @@ impl Ptr { } } -impl Ptr { +impl Ptr { pub fn read(self, process: &Process) -> Result { process.read(self.addr()).map_err(drop) } @@ -180,30 +180,28 @@ unsafe impl Pod for GList {} unsafe impl Zeroable for GList {} #[cfg(not(feature = "il2cpp"))] -#[derive(Debug, Copy, Clone, Pod, Zeroable)] +#[derive(Debug, Copy, Clone, AnyBitPattern)] #[repr(C)] pub struct MonoAssembly { pub ref_count: i32, - _padding: [u8; 4], pub basedir: Ptr, pub aname: MonoAssemblyName, pub image: Ptr, } #[cfg(feature = "il2cpp")] -#[derive(Debug, Copy, Clone, Pod, Zeroable)] +#[derive(Debug, Copy, Clone, AnyBitPattern)] #[repr(C)] pub struct MonoAssembly { pub image: Ptr, pub token: u32, pub referenced_assembly_start: i32, pub referenced_assembly_count: i32, - _padding: [u8; 4], pub aname: MonoAssemblyName, } #[cfg(not(feature = "il2cpp"))] -#[derive(Debug, Copy, Clone, Pod, Zeroable)] +#[derive(Debug, Copy, Clone, AnyBitPattern)] #[repr(C)] pub struct MonoAssemblyName { pub name: Ptr, @@ -211,7 +209,6 @@ pub struct MonoAssemblyName { pub hash_value: Ptr, pub public_key: Ptr, pub public_key_token: [u8; 17], - _padding1: [u8; 3], pub hash_alg: u32, pub hash_len: u32, pub flags: u32, @@ -223,11 +220,10 @@ pub struct MonoAssemblyName { pub without_version: MonoBoolean, pub without_culture: MonoBoolean, pub without_public_key_token: MonoBoolean, - _padding2: [u8; 3], } #[cfg(feature = "il2cpp")] -#[derive(Debug, Copy, Clone, Pod, Zeroable)] +#[derive(Debug, Copy, Clone, AnyBitPattern)] #[repr(C)] pub struct MonoAssemblyName { pub name: Ptr, @@ -244,7 +240,6 @@ pub struct MonoAssemblyName { pub revision: i32, pub public_key_token: [u8; 8], - _padding: [u8; 4], } #[cfg(not(feature = "il2cpp"))] @@ -255,11 +250,10 @@ type MonoBoolean = u8; type MonoAssemblyNameInt = u16; #[cfg(not(feature = "il2cpp"))] -#[derive(Debug, Copy, Clone, Pod, Zeroable)] +#[derive(Debug, Copy, Clone, AnyBitPattern)] #[repr(C)] pub struct MonoImage { ref_count: i32, - _padding: [u8; 4], raw_data_handle: Ptr, raw_data: Ptr, raw_data_len: u32, @@ -270,7 +264,6 @@ pub struct MonoImage { version: Ptr, md_version_major: i16, md_version_minor: i16, - _padding2: [u8; 4], guid: Ptr, image_info: Ptr, mempool: Ptr, @@ -287,14 +280,11 @@ pub struct MonoImage { tables: [MonoTableInfo; MONO_TABLE_NUM], references: Ptr>, nreferences: i32, - _padding3: [u8; 4], modules: Ptr>, module_count: u32, - _padding4: [u8; 4], modules_loaded: Ptr, // to gboolean files: Ptr>, file_count: u32, - _padding5: [u8; 4], aot_module: Ptr, aotid: [u8; 16], assembly: Ptr, @@ -303,7 +293,7 @@ pub struct MonoImage { } #[cfg(feature = "il2cpp")] -#[derive(Debug, Copy, Clone, Pod, Zeroable)] +#[derive(Debug, Copy, Clone, AnyBitPattern)] #[repr(C)] pub struct MonoImage { name: Ptr, @@ -314,15 +304,11 @@ pub struct MonoImage { exported_type_count: u32, custom_attribute_count: u32, - _padding1: [u8; 4], - metadata_handle: Ptr, name_to_class_hash_table: Ptr, code_gen_module: Ptr, token: u32, dynamic: u8, - - _padding2: [u8; 3], } impl MonoImage { @@ -379,12 +365,11 @@ unsafe impl Zeroable for MonoInternalHashTable {} #[cfg(not(feature = "il2cpp"))] const MONO_TABLE_NUM: usize = 56; -#[derive(Debug, Copy, Clone, Pod, Zeroable)] +#[derive(Debug, Copy, Clone, AnyBitPattern)] #[repr(C)] pub struct MonoStreamHeader { data: Ptr, size: u32, - _padding: [u8; 4], } #[derive(Debug, Copy, Clone, Pod, Zeroable)] @@ -396,7 +381,7 @@ pub struct MonoTableInfo { size_bitfield: u32, } -#[derive(Debug, Copy, Clone, Pod, Zeroable)] +#[derive(Debug, Copy, Clone, AnyBitPattern)] #[repr(C)] pub struct MonoClassDef { pub klass: MonoClass, @@ -405,7 +390,6 @@ pub struct MonoClassDef { pub first_field_idx: u32, pub method_count: u32, pub field_count: u32, - _padding: [u8; 4], pub next_class_cache: Ptr, } @@ -442,7 +426,7 @@ impl MonoClassDef { } #[cfg(not(feature = "il2cpp"))] -#[derive(Debug, Copy, Clone, Pod, Zeroable)] +#[derive(Debug, Copy, Clone, AnyBitPattern)] #[repr(C)] pub struct MonoClass { pub element_class: Ptr, @@ -450,13 +434,10 @@ pub struct MonoClass { pub supertypes: Ptr>, pub idepth: u16, pub rank: u8, - _padding1: u8, pub instance_size: i32, pub flags1: u32, pub min_align: u8, - _padding2: [u8; 3], pub flags2: u32, - _padding3: [u8; 4], pub parent: Ptr, pub nested_in: Ptr, pub image: Ptr, @@ -465,17 +446,14 @@ pub struct MonoClass { pub type_token: u32, pub vtable_size: i32, pub interface_count: u16, - _padding4: [u8; 2], pub interface_id: u32, pub max_interface_id: u32, pub interface_offsets_count: u16, - _padding5: [u8; 2], pub interfaces_packed: Ptr>, pub interface_offsets_packed: Ptr, pub interface_bitmap: Ptr, pub interfaces: Ptr>, pub sizes: i32, - _padding6: [u8; 4], pub fields: Ptr, pub methods: Ptr, pub this_arg: MonoType, @@ -488,7 +466,7 @@ pub struct MonoClass { } #[cfg(feature = "il2cpp")] -#[derive(Debug, Copy, Clone, Pod, Zeroable)] +#[derive(Debug, Copy, Clone, AnyBitPattern)] #[repr(C)] pub struct MonoClass { image: Ptr, @@ -523,7 +501,6 @@ pub struct MonoClass { initialization_exception_gc_handle: u32, cctor_started: u32, cctor_finished: u32, - _padding1: [u8; 4], cctor_thread: u64, generic_container_handle: Ptr, @@ -570,7 +547,6 @@ pub struct MonoClass { // is_import_or_windows_runtime: u8:1, // is_vtable_initialized: u8:1, // has_initialization_error: u8:1, - _padding2: [u8; 4], } impl MonoClass { @@ -580,9 +556,11 @@ impl MonoClass { process: &Process, f: impl FnOnce(&[u8]) -> R, ) -> Result { - let mut buf = [0; 4 << 10]; + let mut buf = [MaybeUninit::uninit(); 4 << 10]; let buf = buf.get_mut(..self.instance_size as usize).ok_or(())?; - process.read_into_buf(instance.addr(), buf).map_err(drop)?; + let buf = process + .read_into_uninit_buf(instance.addr(), buf) + .map_err(drop)?; Ok(f(buf)) } @@ -631,14 +609,13 @@ impl MonoClass { type MonoGCDescriptor = Ptr; -#[derive(Debug, Copy, Clone, Pod, Zeroable)] +#[derive(Debug, Copy, Clone, AnyBitPattern)] #[repr(C)] pub struct MonoType { data: Ptr, attrs: u16, r#type: u8, flags: u8, - _padding: [u8; 4], } #[derive(Debug, Copy, Clone, Pod, Zeroable)] @@ -655,14 +632,13 @@ pub struct MonoClassRuntimeInfo { } #[cfg(not(feature = "il2cpp"))] -#[derive(Debug, Copy, Clone, Pod, Zeroable)] +#[derive(Debug, Copy, Clone, AnyBitPattern)] #[repr(C)] pub struct MonoClassField { pub r#type: Ptr, pub name: Ptr, pub parent: Ptr, pub offset: i32, - _padding: [u8; 4], } #[cfg(feature = "il2cpp")] @@ -676,7 +652,7 @@ pub struct MonoClassField { pub token: u32, } -#[derive(Debug, Copy, Clone, Pod, Zeroable)] +#[derive(Debug, Copy, Clone, AnyBitPattern)] #[repr(C)] pub struct MonoVTable { klass: Ptr, @@ -688,9 +664,7 @@ pub struct MonoVTable { rank: u8, initialized: u8, flags: u8, - _padding1: u8, imt_collisions_bitmap: u32, - _padding2: [u8; 4], runtime_generic_context: Ptr, } diff --git a/src/lib.rs b/src/lib.rs index 3250cdc..a229798 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,5 +1,9 @@ #![no_std] #![allow(non_snake_case)] // TODO: Fix +#![cfg_attr( + feature = "nightly", + feature(type_alias_impl_trait, const_async_blocks) +)] use arrayvec::ArrayString; use asr_dotnet::{ @@ -156,7 +160,10 @@ impl Timer { } } +#[cfg(not(feature = "nightly"))] asr::async_main!(stable); +#[cfg(feature = "nightly")] +asr::async_main!(nightly); async fn main() { let mut run_time = Duration::ZERO;