rosu_memory_lib/reader/beatmap/stable/
file.rs1
2
3
4use rosu_mem::process::{Process, ProcessTraits};
5use rosu_map::Beatmap as RmBeatmap;
6use rosu_map::section::hit_objects::HitObjectKind;
7use crate::reader::structs::State;
8use crate::reader::common::stable::memory::get_path_folder;
9use crate::reader::beatmap::common::{BeatmapInfo, BeatmapTechnicalInfo, BeatmapMetadata, BeatmapLocation, BeatmapStatus, BeatmapStats, BeatmapStarRating};
10use crate::reader::beatmap::stable::location::{get_audio, get_filename, get_folder};
11use crate::reader::beatmap::stable::{offset::BEATMAP_OFFSET, get_beatmap_addr};
12use crate::common::GameMode;
13
14
15
16
17pub fn get_beatmap_path(p: &Process, state: &mut State) -> eyre::Result<String>
18{
19 let folder = get_folder(p, state)?;
20 let filename = get_filename(p, state)?;
21 let song_path = get_path_folder(p, state)?;
22 Ok(format!("{song_path}/{folder}/{filename}"))
23}
24
25pub fn get_audio_path(p: &Process, state: &mut State) -> eyre::Result<String>
26{
27 let folder = get_folder(p, state)?;
28 let audio = get_audio(p, state)?;
29 let song_path = get_path_folder(p, state)?;
30 Ok(format!("{song_path}/{folder}/{audio}"))
31}
32
33pub fn get_beatmap_md5(p: &Process, state: &mut State) -> eyre::Result<String>
34{
35 crate::reader::beatmap::stable::memory::get_beatmap_md5(p, state)
37}
38
39pub fn get_beatmap_id(p: &Process, state: &mut State) -> eyre::Result<i32>
40{
41 let path = get_beatmap_path(p, state)?;
42 let b = RmBeatmap::from_path(path)?;
43 Ok(b.beatmap_id)
44}
45
46
47pub fn get_beatmap_set_id(p: &Process, state: &mut State) -> eyre::Result<i32>
48{
49 let path = get_beatmap_path(p, state)?;
50 let b = RmBeatmap::from_path(path)?;
51 Ok(b.beatmap_set_id)
52
53}
54
55pub fn get_beatmap_mode(p: &Process, state: &mut State) -> eyre::Result<GameMode>
56{
57 let path = get_beatmap_path(p, state)?;
58 let b = RmBeatmap::from_path(path)?;
59 Ok(GameMode::from(b.mode as u32))
60}
61
62pub fn get_beatmap_tags(p: &Process, state: &mut State) -> eyre::Result<String>
63{
64 let path = get_beatmap_path(p, state)?;
65 let b = RmBeatmap::from_path(path)?;
66 Ok(b.tags)
67}
68
69pub fn get_beatmap_length(p: &Process, state: &mut State) -> eyre::Result<i32>
70{
71
72 crate::reader::beatmap::stable::memory::get_beatmap_length(p, state)
74}
75
76pub fn get_beatmap_drain_time(p: &Process, state: &mut State) -> eyre::Result<i32>
77{
78 let path = get_beatmap_path(p, state)?;
79 let b = RmBeatmap::from_path(path)?;
80 let drain_time = b.hit_objects.last().unwrap().start_time - b.hit_objects.first().unwrap().start_time;
81 Ok(drain_time as i32)
82}
83
84pub fn get_beatmap_status(p: &Process, state: &mut State) -> eyre::Result<BeatmapStatus>
85{
86 crate::reader::beatmap::stable::memory::get_beatmap_status(p, state)
88}
89
90pub fn get_author(p: &Process, state: &mut State) -> eyre::Result<String>
91{
92 let path = get_beatmap_path(p, state)?;
93 let b = RmBeatmap::from_path(path)?;
94 Ok(b.artist)
95}
96
97pub fn get_creator(p: &Process, state: &mut State) -> eyre::Result<String>
98{
99 let path = get_beatmap_path(p, state)?;
100 let b = RmBeatmap::from_path(path)?;
101 Ok(b.creator)
102
103}
104
105pub fn get_title_romanized(p: &Process, state: &mut State) -> eyre::Result<String>
106{
107 let path = get_beatmap_path(p, state)?;
108 let b = RmBeatmap::from_path(path)?;
109 Ok(b.title)
110}
111
112pub fn get_title_original(p: &Process, state: &mut State) -> eyre::Result<String>
113{
114 let path = get_beatmap_path(p, state)?;
115 let b = RmBeatmap::from_path(path)?;
116 Ok(b.title_unicode)
117}
118
119pub fn get_difficulty(p: &Process, state: &mut State) -> eyre::Result<String>
120{
121 let path = get_beatmap_path(p, state)?;
122 let b = RmBeatmap::from_path(path)?;
123 Ok(b.version)
124}
125
126pub fn get_beatmap_od(p: &Process, state: &mut State) -> eyre::Result<f32>
127{
128 let path = get_beatmap_path(p, state)?;
129 let b = RmBeatmap::from_path(path)?;
130 Ok(b.overall_difficulty)
131}
132
133pub fn get_beatmap_ar(p: &Process, state: &mut State) -> eyre::Result<f32>
134{
135 let path = get_beatmap_path(p, state)?;
136 let b = RmBeatmap::from_path(path)?;
137 Ok(b.approach_rate)
138}
139
140pub fn get_beatmap_cs(p: &Process, state: &mut State) -> eyre::Result<f32>
141{
142 let path = get_beatmap_path(p, state)?;
143 let b = RmBeatmap::from_path(path)?;
144 Ok(b.circle_size)
145}
146
147pub fn get_beatmap_hp(p: &Process, state: &mut State) -> eyre::Result<f32>
148{
149 let path = get_beatmap_path(p, state)?;
150 let b = RmBeatmap::from_path(path)?;
151 Ok(b.hp_drain_rate)
152}
153
154pub fn get_beatmap_object_count(p: &Process, state: &mut State) -> eyre::Result<u32>
155{
156 let path = get_beatmap_path(p, state)?;
157 let b = RmBeatmap::from_path(path)?;
158 Ok(b.hit_objects.len() as u32)
159}
160
161pub fn get_beatmap_slider_count(p: &Process, state: &mut State) -> eyre::Result<i32>
162{
163 let path = get_beatmap_path(p, state)?;
164 let b = RmBeatmap::from_path(path)?;
165 Ok(b.hit_objects.iter().filter(|h| matches!(h.kind, HitObjectKind::Slider(_))).count() as i32)
166}
167
168
169pub fn get_beatmap_star_rating(p: &Process, state: &mut State) -> eyre::Result<BeatmapStarRating>
170{
171 let folder = get_folder(p, state)?;
172 let filename = get_filename(p, state)?;
173 let song_path = get_path_folder(p, state)?;
174 let path = format!("{song_path}/{folder}/{filename}");
175 let b = rosu_pp::Beatmap::from_path(path)?;
176 let diff_attrs = rosu_pp::Difficulty::new().calculate(&b);
177 let diff_dt = rosu_pp::Difficulty::new().mods(64).calculate(&b);
178 let diff_ht = rosu_pp::Difficulty::new().mods(256).calculate(&b);
179 let no_mod = diff_attrs.stars();
180 let dt = diff_dt.stars();
181 let ht = diff_ht.stars();
182 Ok(BeatmapStarRating{
183 no_mod,
184 dt,
185 ht,
186 })
187
188}
189
190pub fn get_beatmap_stats(p: &Process, state: &mut State) -> eyre::Result<BeatmapStats>
191{
192 let beatmap_addr = get_beatmap_path(p, state)?;
193 let b = RmBeatmap::from_path(beatmap_addr)?;
194 Ok(BeatmapStats{
195 ar: b.approach_rate,
196 od: b.overall_difficulty,
197 cs: b.circle_size,
198 hp: b.hp_drain_rate,
199 total_length: b.hit_objects.last().unwrap().start_time as i32 - b.hit_objects.first().unwrap().start_time as i32,
200 star_rating: get_beatmap_star_rating(p, state)?,
201 object_count: b.hit_objects.len() as i32,
202 slider_count: b.hit_objects.iter().filter(|h| matches!(h.kind, HitObjectKind::Slider(_))).count() as i32,
203 })
204}
205
206
207
208pub fn get_beatmap_info(p: &Process, state: &mut State) -> eyre::Result<BeatmapInfo>
209{
210 let beatmap_file = get_beatmap_path(p, state)?;
211 let beatmap_addr = get_beatmap_addr(p, state)?;
212 let b = RmBeatmap::from_path(beatmap_file)?;
213 Ok(BeatmapInfo {
215 technical: BeatmapTechnicalInfo{
216 md5: crate::reader::beatmap::stable::file::get_beatmap_md5(p, state)?,
217 id: b.beatmap_id,
218 set_id: b.beatmap_set_id,
219 mode: GameMode::Osu,
220 ranked_status: crate::reader::beatmap::stable::file::get_beatmap_status(p, state)?,
221 },
222 metadata: BeatmapMetadata{
223 author: b.artist,
224 creator: b.creator,
225 title_romanized: b.title,
226 title_original: b.title_unicode,
227 difficulty: b.version,
228 tags: b.tags,
229 },
230 stats: BeatmapStats{
231 ar: b.approach_rate,
232 od: b.overall_difficulty,
233 cs: b.circle_size,
234 hp: b.hp_drain_rate,
235 total_length: b.hit_objects.last().unwrap().start_time as i32 - b.hit_objects.first().unwrap().start_time as i32,
236 star_rating: get_beatmap_star_rating(p,state)?,
237 object_count: b.hit_objects.len() as i32,
238 slider_count: b.hit_objects.iter().filter(|h| matches!(h.kind, HitObjectKind::Slider(_))).count() as i32,
239 },
240 location: BeatmapLocation {
241 folder: p.read_string(beatmap_addr + BEATMAP_OFFSET.location.folder)?,
242 filename: p.read_string(beatmap_addr + BEATMAP_OFFSET.location.filename)?,
243 audio: p.read_string(beatmap_addr + BEATMAP_OFFSET.location.audio)?,
244 cover: p.read_string(beatmap_addr + BEATMAP_OFFSET.location.cover)?,
245 },
246 })
247
248}