rosu_memory_lib/reader/resultscreen/stable/
memory.rs1use crate::generate_offset_getter;
2use crate::reader::common::stable::memory::check_game_state;
3use crate::reader::common::GameMode;
4use crate::reader::common::GameState;
5use crate::reader::helpers::{calculate_accuracy, read_i16, read_i32, read_string};
6use crate::reader::resultscreen::common::ResultScreenInfo;
7use crate::reader::resultscreen::stable::offset::RESULT_SCREEN_OFFSET;
8use crate::reader::structs::{Hit, State};
9use crate::Error;
10use rosu_mem::process::{Process, ProcessTraits};
11
12pub fn result_screen_ptr(p: &Process, state: &mut State) -> Result<i32, Error> {
13 if check_game_state(p, state, GameState::ResultScreen)? {
14 Ok(p.read_i32(state.addresses.rulesets - RESULT_SCREEN_OFFSET.ptr)?)
15 } else {
16 Err(Error::NotAvailable("Not in ResultScreen".to_string()))
17 }
18}
19
20pub fn hits(p: &Process, state: &mut State) -> Result<Hit, Error> {
21 let score_base = result_screen_base(p, state)?;
22 let mut hits_buffer = [0u8; size_of::<i16>() * 6];
24 p.read(
25 score_base + RESULT_SCREEN_OFFSET.hits._100,
26 size_of::<i16>() * 6,
27 &mut hits_buffer,
28 )?;
29
30 Ok(Hit {
33 _100: i16::from_le_bytes(hits_buffer[0..2].try_into().unwrap()),
34 _300: i16::from_le_bytes(hits_buffer[2..4].try_into().unwrap()),
35 _50: i16::from_le_bytes(hits_buffer[4..6].try_into().unwrap()),
36 _geki: i16::from_le_bytes(hits_buffer[6..8].try_into().unwrap()),
37 _katu: i16::from_le_bytes(hits_buffer[8..10].try_into().unwrap()),
38 _miss: i16::from_le_bytes(hits_buffer[10..12].try_into().unwrap()),
39 })
40}
41
42pub fn accuracy(p: &Process, state: &mut State) -> Result<f64, Error> {
43 calculate_accuracy(&mode(p, state)?, &hits(p, state)?)
44}
45
46generate_offset_getter! {
47 result_screen_addr: i32 = read_i32(RESULT_SCREEN_OFFSET.addr, result_screen_ptr);
48 result_screen_base: i32 = read_i32(RESULT_SCREEN_OFFSET.base, result_screen_addr);
49 username: String = read_string(RESULT_SCREEN_OFFSET.username, result_screen_base);
50 score: i32 = read_i32(RESULT_SCREEN_OFFSET.score, result_screen_base);
51 max_combo: i16 = read_i16(RESULT_SCREEN_OFFSET.max_combo, result_screen_base);
52 mode: GameMode = read_i32(RESULT_SCREEN_OFFSET.mode, result_screen_base);
53 hits_300: i16 = read_i16(RESULT_SCREEN_OFFSET.hits._300, result_screen_base);
54 hits_100: i16 = read_i16(RESULT_SCREEN_OFFSET.hits._100, result_screen_base);
55 hits_50: i16 = read_i16(RESULT_SCREEN_OFFSET.hits._50, result_screen_base);
56 hits_miss: i16 = read_i16(RESULT_SCREEN_OFFSET.hits._miss, result_screen_base);
57 hits_geki: i16 = read_i16(RESULT_SCREEN_OFFSET.hits._geki, result_screen_base);
58 hits_katu: i16 = read_i16(RESULT_SCREEN_OFFSET.hits._katu, result_screen_base);
59}
60
61pub fn info(p: &Process, state: &mut State) -> Result<ResultScreenInfo, Error> {
62 let hits = hits(p, state)?;
63 let mode = mode(p, state)?;
64 let accuracy = calculate_accuracy(&mode, &hits)?;
65 let base = result_screen_base(p, state)?;
66 Ok(ResultScreenInfo {
67 username: p.read_string(base + RESULT_SCREEN_OFFSET.username)?,
68 mode,
69 max_combo: p.read_i16(base + RESULT_SCREEN_OFFSET.max_combo)?,
70 score: p.read_i32(base + RESULT_SCREEN_OFFSET.score)?,
71 hits,
72 accuracy,
73 })
74}