From 785d9a1d2eeb8ebd02fd7fc8ea5b1776ab7d19ad Mon Sep 17 00:00:00 2001 From: OctopuSSX Date: Wed, 1 Nov 2023 22:31:41 +0300 Subject: [PATCH 1/7] Implement struct read --- src/memory/process.rs | 99 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 99 insertions(+) diff --git a/src/memory/process.rs b/src/memory/process.rs index 6bacedf..598e05e 100644 --- a/src/memory/process.rs +++ b/src/memory/process.rs @@ -12,6 +12,7 @@ #![allow(clippy::size_of_in_element_count)] +use std::mem::{size_of, align_of}; use std::path::PathBuf; use super::error::ProcessError; @@ -106,6 +107,104 @@ pub trait ProcessTraits where Self: Sized { buff: &mut [u8] ) -> Result<(), ProcessError>; + fn read_struct( + &self, + addr: usize + ) -> Result { + let mut buff = vec![0u8; size_of::()]; + + let byte_buff = unsafe { + std::slice::from_raw_parts_mut( + buff.as_mut_ptr() as *mut u8, + buff.len() + ) + }; + + self.read(addr, byte_buff.len(), byte_buff)?; + + let s: T = unsafe { std::ptr::read(buff.as_ptr() as *const _) }; + + Ok(s) + } + + fn read_struct_array( + &self, + addr: usize, + len: usize + ) -> Result, ProcessError> { + let size = size_of::() + align_of::(); + let mut buff = vec![0u8; size * len]; + + let mut byte_buff = unsafe { + std::slice::from_raw_parts_mut( + buff.as_mut_ptr() as *mut u8, + buff.len() + ) + }; + + self.read(addr, byte_buff.len(), byte_buff)?; + + let mut arr = Vec::with_capacity(len); + + while byte_buff.len() >= size_of::() { + let (head, tail) = byte_buff.split_at_mut(size); + let s: T = unsafe { std::ptr::read(head.as_ptr() as *const T) }; + arr.push(s); + byte_buff = tail; + } + + Ok(arr) + } + + fn read_struct_ptr_array( + &self, + addr: usize + ) -> Result, ProcessError> { + let mut ptrs = Vec::new(); + self.read_u32_array(addr, &mut ptrs)?; + + let mut arr = Vec::with_capacity(ptrs.len()); + if ptrs.len() == 0 { + return Ok(arr) + } + let size = size_of::(); + let size_with_align = size + align_of::(); + let mut chunk: usize = 1; + let mut last_ptr = 0; + + // Reading all values one-by-one is slow and wasteful + // but List<> elements are stored in chunks + // so we can find those and read multiple values at once + for (i, ptr) in ptrs.iter().enumerate() { + if i == 0 { last_ptr = *ptr; continue } + // BRUH + if (ptr.overflowing_sub(last_ptr).0) as usize == size_with_align { + chunk += 1; + } else { + if chunk > 1 { + let mut a = self.read_struct_array(last_ptr as usize - size_with_align * (chunk - 1), chunk)?; + arr.append(&mut a); + chunk = 1; + } else { + let a = self.read_struct(last_ptr as usize)?; + arr.push(a); + } + } + last_ptr = *ptr; + } + + if chunk > 1 { + let mut a = self.read_struct_array(last_ptr as usize - size_with_align * (chunk - 1), chunk)?; + assert!(a.len() == chunk); + arr.append(&mut a); + } else { + let a = self.read_struct(last_ptr as usize)?; + arr.push(a); + } + + Ok(arr) + } + fn read_uleb128( &self, mut addr: usize From 007296e42ae809a1991d264eecd18a0a2ed308cc Mon Sep 17 00:00:00 2001 From: OctopuSSX Date: Wed, 1 Nov 2023 22:31:53 +0300 Subject: [PATCH 2/7] Update main.rs --- src/main.rs | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/src/main.rs b/src/main.rs index f574ae5..0045bb5 100644 --- a/src/main.rs +++ b/src/main.rs @@ -270,6 +270,35 @@ fn process_reading_loop( values.fc_pp = fc_pp.pp(); } + + let a = Instant::now(); + let frames_addr = p.read_i32(score_base + 0x34)? as usize; + { + #[repr(C)] + #[derive(Debug, Clone)] + struct ReplayFrame { + v_table: u32, + mouse_x: f32, + mouse_y: f32, + mouse_bits: i32, + time: i32, + mouse_left: u8, + mouse_right: u8, + mouse_left1: u8, + mouse_right1: u8, + mouse_left2: u8, + mouse_right2: u8, + } + + let frames = p.read_struct_ptr_array::(frames_addr)?; + let b = a.elapsed(); + + println!("{}", b.as_millis()); + if frames.len() > 0 { + let frame = frames.last().unwrap(); + println!("{} {} {}", frame.mouse_x, frame.mouse_y, frame.mouse_bits); + } + } } Ok(()) From 7d0b05852ef3d759a53e54c459cde72f598c332f Mon Sep 17 00:00:00 2001 From: OctopuSSX Date: Wed, 1 Nov 2023 22:39:28 +0300 Subject: [PATCH 3/7] HOW --- src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main.rs b/src/main.rs index 8a75ab5..e24fb7b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -9,7 +9,7 @@ use crate::structs::{ use std::{ borrow::Cow, str::FromStr, - collections::HashMap, net::TcpStream, path::PathBuf + collections::HashMap, net::TcpStream, path::PathBuf, time::Instant }; use clap::Parser; From e1cfeea5ecf56899f885d12938bf6f65ff8105b9 Mon Sep 17 00:00:00 2001 From: OctopuSSX Date: Thu, 2 Nov 2023 18:08:20 +0300 Subject: [PATCH 4/7] Update main.rs --- src/main.rs | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/src/main.rs b/src/main.rs index e24fb7b..7b4df06 100644 --- a/src/main.rs +++ b/src/main.rs @@ -9,7 +9,7 @@ use crate::structs::{ use std::{ borrow::Cow, str::FromStr, - collections::HashMap, net::TcpStream, path::PathBuf, time::Instant + collections::HashMap, net::TcpStream, path::PathBuf }; use clap::Parser; @@ -294,7 +294,6 @@ fn process_reading_loop( .beat_len; } - let a = Instant::now(); let frames_addr = p.read_i32(score_base + 0x34)? as usize; { #[repr(C)] @@ -314,13 +313,6 @@ fn process_reading_loop( } let frames = p.read_struct_ptr_array::(frames_addr)?; - let b = a.elapsed(); - - println!("{}", b.as_millis()); - if frames.len() > 0 { - let frame = frames.last().unwrap(); - println!("{} {} {}", frame.mouse_x, frame.mouse_y, frame.mouse_bits); - } } } From 4820d3ac93e8dc9d46a11a78fe5ddcb265a9a5c9 Mon Sep 17 00:00:00 2001 From: OctopuSSX Date: Thu, 2 Nov 2023 23:23:31 +0300 Subject: [PATCH 5/7] Magic bytefuckery from bade --- src/memory/process.rs | 38 ++++++++++++++++++-------------------- 1 file changed, 18 insertions(+), 20 deletions(-) diff --git a/src/memory/process.rs b/src/memory/process.rs index d57c5bc..a111f86 100644 --- a/src/memory/process.rs +++ b/src/memory/process.rs @@ -111,20 +111,19 @@ pub trait ProcessTraits where Self: Sized { &self, addr: usize ) -> Result { - let mut buff = vec![0u8; size_of::()]; - + let mut uninit = std::mem::MaybeUninit::::uninit(); + let ptr: *mut u8 = uninit.as_mut_ptr().cast(); + let byte_buff = unsafe { std::slice::from_raw_parts_mut( - buff.as_mut_ptr() as *mut u8, - buff.len() + ptr, + std::mem::size_of::() ) }; self.read(addr, byte_buff.len(), byte_buff)?; - let s: T = unsafe { std::ptr::read(buff.as_ptr() as *const _) }; - - Ok(s) + Ok(unsafe { uninit.assume_init() }) } fn read_struct_array( @@ -132,28 +131,27 @@ pub trait ProcessTraits where Self: Sized { addr: usize, len: usize ) -> Result, ProcessError> { - let size = size_of::() + align_of::(); - let mut buff = vec![0u8; size * len]; + let mut buff: Vec<_> = std::iter::repeat_with(std::mem::MaybeUninit::::uninit) + .take(len) + .collect(); - let mut byte_buff = unsafe { + let ptr: *mut u8 = buff.as_mut_ptr().cast(); + let byte_buff = unsafe { std::slice::from_raw_parts_mut( - buff.as_mut_ptr() as *mut u8, - buff.len() + ptr, + size_of::() * len ) }; self.read(addr, byte_buff.len(), byte_buff)?; - let mut arr = Vec::with_capacity(len); + let ptr: *mut T = buff.as_mut_ptr().cast(); + let len = buff.len(); + let cap = buff.capacity(); - while byte_buff.len() >= size_of::() { - let (head, tail) = byte_buff.split_at_mut(size); - let s: T = unsafe { std::ptr::read(head.as_ptr() as *const T) }; - arr.push(s); - byte_buff = tail; - } + std::mem::forget(buff); - Ok(arr) + Ok(unsafe { Vec::from_raw_parts(ptr, len, cap) }) } fn read_struct_ptr_array( From cecd391ac248199bd4ed8fb653e6fc5fc131c6a9 Mon Sep 17 00:00:00 2001 From: OctopuSSX Date: Tue, 7 Nov 2023 18:31:17 +0300 Subject: [PATCH 6/7] Move frames to Values and optimize read --- src/main.rs | 19 +++---------------- src/memory/process.rs | 13 ++++++++----- src/structs.rs | 21 +++++++++++++++++++++ 3 files changed, 32 insertions(+), 21 deletions(-) diff --git a/src/main.rs b/src/main.rs index b8117d8..d39082d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,6 @@ mod structs; +use structs::ReplayFrame; use tracy_client::*; use crate::structs::{ @@ -319,23 +320,9 @@ fn process_reading_loop( let frames_addr = p.read_i32(score_base + 0x34)? as usize; { - #[repr(C)] - #[derive(Debug, Clone)] - struct ReplayFrame { - v_table: u32, - mouse_x: f32, - mouse_y: f32, - mouse_bits: i32, - time: i32, - mouse_left: u8, - mouse_right: u8, - mouse_left1: u8, - mouse_right1: u8, - mouse_left2: u8, - mouse_right2: u8, - } - let frames = p.read_struct_ptr_array::(frames_addr)?; + let mut frames = p.read_struct_ptr_array::(frames_addr, values.frames.len())?; + values.frames.append(&mut frames); } // Placing at the very end cuz we should diff --git a/src/memory/process.rs b/src/memory/process.rs index 370529c..71e523a 100644 --- a/src/memory/process.rs +++ b/src/memory/process.rs @@ -156,24 +156,27 @@ pub trait ProcessTraits where Self: Sized { fn read_struct_ptr_array( &self, - addr: usize + addr: usize, + skip: usize ) -> Result, ProcessError> { let mut ptrs = Vec::new(); self.read_u32_array(addr, &mut ptrs)?; - let mut arr = Vec::with_capacity(ptrs.len()); - if ptrs.len() == 0 { + let len = ptrs.len() - skip; + + let mut arr = Vec::with_capacity(len); + if len == 0 { return Ok(arr) } let size = size_of::(); let size_with_align = size + align_of::(); let mut chunk: usize = 1; - let mut last_ptr = 0; + let mut last_ptr = 0; // Reading all values one-by-one is slow and wasteful // but List<> elements are stored in chunks // so we can find those and read multiple values at once - for (i, ptr) in ptrs.iter().enumerate() { + for (i, ptr) in ptrs.iter().skip(skip).enumerate() { if i == 0 { last_ptr = *ptr; continue } // BRUH if (ptr.overflowing_sub(last_ptr).0) as usize == size_with_align { diff --git a/src/structs.rs b/src/structs.rs index 694d64b..e1979e5 100644 --- a/src/structs.rs +++ b/src/structs.rs @@ -65,6 +65,22 @@ impl From for BeatmapStatus { } } +#[repr(C)] +#[derive(Debug, Clone)] +pub struct ReplayFrame { + pub v_table: u32, + pub mouse_x: f32, + pub mouse_y: f32, + pub mouse_bits: i32, + pub time: i32, + pub mouse_left: u8, + pub mouse_right: u8, + pub mouse_left1: u8, + pub mouse_right1: u8, + pub mouse_left2: u8, + pub mouse_right2: u8, +} + #[derive(Default)] pub struct StaticAddresses { pub base: usize, @@ -134,6 +150,9 @@ pub struct Values { pub current_bpm: f64, pub kiai_now: bool, + #[serde(skip)] + pub frames: Vec, + // Calculated each iteration pub current_pp: f64, pub fc_pp: f64, @@ -182,6 +201,8 @@ impl Values { self.bpm = 0.0; self.current_bpm = 0.0; self.kiai_now = false; + + self.frames.clear(); } // TODO PR to rosu-pp to add From trait? From 5640e0b3e3693399a6766361dcf54b4e7aa12bb0 Mon Sep 17 00:00:00 2001 From: OctopuSSX Date: Tue, 7 Nov 2023 18:31:23 +0300 Subject: [PATCH 7/7] Add tracy span --- src/main.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main.rs b/src/main.rs index d39082d..22490e2 100644 --- a/src/main.rs +++ b/src/main.rs @@ -320,6 +320,7 @@ fn process_reading_loop( let frames_addr = p.read_i32(score_base + 0x34)? as usize; { + let _span = span!("reading replay frames"); let mut frames = p.read_struct_ptr_array::(frames_addr, values.frames.len())?; values.frames.append(&mut frames);