rosu_memory_lib/reader/
helpers.rs

1use crate::reader::common::GameMode;
2use crate::reader::structs::Hit;
3use crate::reader::structs::State;
4use crate::Error;
5use rosu_mem::process::{Process, ProcessTraits};
6
7macro_rules! generate_reader_fn {
8    (
9        $name:ident, $ret_ty:ty, $read_fn:ident
10    ) => {
11        pub(crate) fn $name(
12            p: &Process,
13            state: &mut State,
14            offset: i32,
15            get_base_addr: fn(&Process, &mut State) -> Result<i32, Error>,
16        ) -> Result<$ret_ty, Error> {
17            let base_addr = get_base_addr(p, state)?;
18            Ok(p.$read_fn(base_addr + offset)?)
19        }
20    };
21}
22generate_reader_fn!(read_string, String, read_string);
23generate_reader_fn!(read_i16, i16, read_i16);
24generate_reader_fn!(read_i32, i32, read_i32);
25generate_reader_fn!(read_u32, u32, read_u32);
26generate_reader_fn!(read_i64, i64, read_i64);
27generate_reader_fn!(read_u64, u64, read_u64);
28generate_reader_fn!(read_f32, f32, read_f32);
29generate_reader_fn!(read_f64, f64, read_f64);
30
31#[macro_export]
32macro_rules! generate_offset_getter {
33    (
34        $( $fn_name:ident : $ret_ty:ty = $read_fn:ident ( $offset:expr , $get_base:ident ); )*
35    ) => {
36        $(
37            pub fn $fn_name(p: &Process, state: &mut State) -> Result<$ret_ty, Error> {
38                Ok(<$ret_ty>::from($read_fn(p, state, $offset, $get_base)?))
39            }
40        )*
41    };
42}
43// macro to gen wrappers for reader
44#[macro_export]
45macro_rules! impl_osu_accessor {
46    ($(fn $name:ident() -> $ret:ty => $call:path),* $(,)?) => {
47        $(
48            pub fn $name(&mut self) -> Result<$ret, Error> {
49                match self.osu_type {
50                    OsuClientKind::Stable => $call(self.process, self.state),
51                    _ => Err(Error::Unsupported(
52                        "Unsupported osu type for now".to_string(),
53                    )),
54                }
55            }
56        )*
57    };
58}
59
60// TODO : idk where to put this
61#[inline]
62pub fn calculate_accuracy(gamemode: &GameMode, hit: &Hit) -> Result<f64, Error> {
63    let acc = match gamemode {
64        GameMode::Osu => {
65            let total = (hit._300 + hit._100 + hit._50 + hit._miss) as f64;
66            if total == 0.0 {
67                return Ok(0.0);
68            }
69            let score = hit._300 as f64 * 6.0 + hit._100 as f64 * 2.0 + hit._50 as f64;
70            (score / (total * 6.0)) * 100.0
71        }
72        GameMode::Taiko => {
73            let total = (hit._300 + hit._100 + hit._50 + hit._miss) as f64;
74            if total == 0.0 {
75                return Ok(0.0);
76            }
77            let score = hit._300 as f64 * 2.0 + hit._100 as f64;
78            (score / (total * 2.0)) * 100.0
79        }
80        GameMode::Catch => {
81            let caught = (hit._300 + hit._100 + hit._50) as f64;
82            let total = (hit._300 + hit._100 + hit._50 + hit._katu + hit._miss) as f64;
83            if total == 0.0 {
84                return Ok(0.0);
85            }
86            (caught / total) * 100.0
87        }
88        GameMode::Mania => {
89            let total = (hit._geki + hit._300 + hit._katu + hit._100 + hit._50 + hit._miss) as f64;
90            if total == 0.0 {
91                return Ok(0.0);
92            }
93            let score = (hit._geki + hit._300) as f64 * 6.0
94                + hit._katu as f64 * 4.0
95                + hit._100 as f64 * 2.0
96                + hit._50 as f64;
97            (score / (total * 6.0)) * 100.0
98        }
99        _ => return Ok(0.0),
100    };
101
102    Ok(acc)
103}