rosu_memory_lib/reader/beatmap/stable/
file.rs

1
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    // TODO: implement this for now will get from memory
36    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    // implement this later for now will get from memory
73    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    // cant do this in file mode 
87    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       // done like that to be more efficient reading the string one by one would need to reload addr everytime which cost more
214       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}