rosu_memory_lib/reader/
structs.rs

1#[cfg(feature = "parallel-read")]
2use rayon::prelude::*;
3
4use crate::Error;
5use rosu_mem::{
6    process::{Process, ProcessTraits},
7    signature::Signature,
8};
9use std::collections::HashMap;
10use std::str::FromStr;
11use std::time::Instant;
12
13#[derive(Default, Clone)]
14pub struct StaticAddresses {
15    pub base: i32,
16    pub status: i32,
17    pub menu_mods: i32,
18    pub rulesets: i32,
19    pub playtime: i32,
20    pub skin: i32,
21    pub chat_checker: i32,
22    pub audio_time_base: i32,
23    pub ig_time_base: i32,
24    pub settings: i32,
25    pub user_profile: i32,
26}
27
28#[derive(Debug, Default, Clone)]
29pub struct Hit {
30    pub _geki: i16,
31    pub _300: i16,
32    pub _katu: i16,
33    pub _100: i16,
34    pub _50: i16,
35    pub _miss: i16,
36}
37
38#[derive(Debug, Clone)]
39pub(crate) struct SignatureBase {
40    base_sig: &'static str,
41    status_sig: &'static str,
42    menu_mods_sig: &'static str,
43    rulesets_sig: &'static str,
44    playtime_sig: &'static str,
45    skin_sig: &'static str,
46    chat_checker_sig: &'static str,
47    audio_time_base_sig: &'static str,
48    ig_time_base_sig: &'static str,
49    settings_sig: &'static str,
50    user_profile_sig: &'static str,
51}
52
53pub(crate) const SIGNATURES: SignatureBase = SignatureBase {
54    base_sig: "F8 01 74 04 83 65",
55    status_sig: "48 83 F8 04 73 1E",
56    menu_mods_sig: "C8 FF ?? ?? ?? ?? ?? 81 0D ?? ?? ?? ?? 00 08 00 00",
57    rulesets_sig: "7D 15 A1 ?? ?? ?? ?? 85 C0",
58    playtime_sig: "5E 5F 5D C3 A1 ?? ?? ?? ?? 89 ?? 04",
59    skin_sig: "75 21 8B 1D",
60    chat_checker_sig: "0A D7 23 3C 00 00 ?? 01",
61    audio_time_base_sig: "DB 5C 24 34 8B 44 24 34",
62    ig_time_base_sig: "EB 0A A1 ?? ?? ?? ?? A3",
63    settings_sig: "83 E0 20 85 C0 7E 2F",
64    user_profile_sig: "FF 15 ?? ?? ?? ?? A1 ?? ?? ?? ?? 8B 48 54 33 D2",
65};
66
67impl StaticAddresses {
68    pub fn new(p: &Process) -> Result<Self, Error> {
69        let start = Instant::now();
70        println!("Reading signatures...");
71
72        #[cfg(feature = "parallel-read")]
73        {
74            println!("Using parallel signature reading with rayon...");
75            Self::new_parallel(p, start)
76        }
77
78        #[cfg(not(feature = "parallel-read"))]
79        {
80            println!("Using sequential signature reading...");
81            Self::new_sequential(p, start)
82        }
83    }
84
85    #[cfg(feature = "parallel-read")]
86    fn new_parallel(p: &Process, start: Instant) -> Result<Self, Error> {
87        use rayon::prelude::*;
88
89        let signatures = [
90            ("base", SIGNATURES.base_sig),
91            ("status", SIGNATURES.status_sig),
92            ("menu_mods", SIGNATURES.menu_mods_sig),
93            ("rulesets", SIGNATURES.rulesets_sig),
94            ("playtime", SIGNATURES.playtime_sig),
95            ("skin", SIGNATURES.skin_sig),
96            ("chat_checker", SIGNATURES.chat_checker_sig),
97            ("audio_time_base", SIGNATURES.audio_time_base_sig),
98            ("ig_time_base", SIGNATURES.ig_time_base_sig),
99            ("settings", SIGNATURES.settings_sig),
100            ("user_profile", SIGNATURES.user_profile_sig),
101        ];
102
103        let results: HashMap<&str, i32> = signatures
104            .par_iter()
105            .map(|(name, sig)| {
106                let signature = Signature::from_str(sig)?;
107                let addr = p.read_signature(&signature)?;
108                Ok::<_, Error>((*name, addr))
109            })
110            .collect::<Result<_, Error>>()?;
111
112        println!("Time taken: {:?}", start.elapsed());
113
114        Ok(Self {
115            base: results["base"],
116            status: results["status"],
117            menu_mods: results["menu_mods"],
118            rulesets: results["rulesets"],
119            playtime: results["playtime"],
120            skin: results["skin"],
121            chat_checker: results["chat_checker"],
122            audio_time_base: results["audio_time_base"],
123            ig_time_base: results["ig_time_base"],
124            settings: results["settings"],
125            user_profile: results["user_profile"],
126        })
127    }
128
129    #[cfg(not(feature = "parallel-read"))]
130    fn new_sequential(p: &Process, start: Instant) -> Result<Self, Error> {
131        let signatures = [
132            ("base", SIGNATURES.base_sig),
133            ("status", SIGNATURES.status_sig),
134            ("menu_mods", SIGNATURES.menu_mods_sig),
135            ("rulesets", SIGNATURES.rulesets_sig),
136            ("playtime", SIGNATURES.playtime_sig),
137            ("skin", SIGNATURES.skin_sig),
138            ("chat_checker", SIGNATURES.chat_checker_sig),
139            ("audio_time_base", SIGNATURES.audio_time_base_sig),
140            ("ig_time_base", SIGNATURES.ig_time_base_sig),
141            ("settings", SIGNATURES.settings_sig),
142            ("user_profile", SIGNATURES.user_profile_sig),
143        ];
144
145        let mut results = HashMap::new();
146        for (name, sig) in signatures.iter() {
147            let signature = Signature::from_str(sig)?;
148            let addr = p.read_signature(&signature)?;
149            results.insert(*name, addr);
150        }
151
152        println!("Time taken: {:?}", start.elapsed());
153
154        Ok(Self {
155            base: results["base"],
156            status: results["status"],
157            menu_mods: results["menu_mods"],
158            rulesets: results["rulesets"],
159            playtime: results["playtime"],
160            skin: results["skin"],
161            chat_checker: results["chat_checker"],
162            audio_time_base: results["audio_time_base"],
163            ig_time_base: results["ig_time_base"],
164            settings: results["settings"],
165            user_profile: results["user_profile"],
166        })
167    }
168}
169
170#[derive(Default, Clone)]
171pub struct State {
172    pub addresses: StaticAddresses,
173}