rosu_memory_lib/reader/beatmap/stable/
memory.rs

1use crate::common::GameMode;
2use crate::generate_offset_getter;
3use crate::reader::beatmap::common::{
4    BeatmapInfo, BeatmapLocation, BeatmapMetadata, BeatmapStats, BeatmapStatus,
5    BeatmapTechnicalInfo,
6};
7use crate::reader::beatmap::stable::{beatmap_addr, offset::BEATMAP_OFFSET};
8use crate::reader::helpers::{read_f32, read_i32, read_string, read_u32};
9use crate::reader::structs::State;
10use crate::Error;
11use rosu_mem::process::{Process, ProcessTraits};
12
13generate_offset_getter! {
14    id: i32 = read_i32(BEATMAP_OFFSET.technical.id, beatmap_addr);
15    set_id: i32 = read_i32(BEATMAP_OFFSET.technical.set_id, beatmap_addr);
16    tags: String = read_string(BEATMAP_OFFSET.metadata.tags, beatmap_addr);
17    length: i32 = read_i32(BEATMAP_OFFSET.stats.total_length, beatmap_addr);
18    drain_time: i32 = read_i32(BEATMAP_OFFSET.stats.drain_time, beatmap_addr);
19    author: String = read_string(BEATMAP_OFFSET.metadata.author, beatmap_addr);
20    creator: String = read_string(BEATMAP_OFFSET.metadata.creator, beatmap_addr);
21    md5: String = read_string(BEATMAP_OFFSET.technical.md5, beatmap_addr);
22    title_romanized: String = read_string(BEATMAP_OFFSET.metadata.title_romanized, beatmap_addr);
23    title: String = read_string(BEATMAP_OFFSET.metadata.title_original, beatmap_addr);
24    difficulty: String = read_string(BEATMAP_OFFSET.metadata.difficulty, beatmap_addr);
25    od: f32 = read_f32(BEATMAP_OFFSET.stats.od, beatmap_addr);
26    ar: f32 = read_f32(BEATMAP_OFFSET.stats.ar, beatmap_addr);
27    cs: f32 = read_f32(BEATMAP_OFFSET.stats.cs, beatmap_addr);
28    hp: f32 = read_f32(BEATMAP_OFFSET.stats.hp, beatmap_addr);
29    object_count: u32 = read_u32(BEATMAP_OFFSET.stats.object_count, beatmap_addr);
30    slider_count: i32 = read_i32(BEATMAP_OFFSET.stats.slider_count, beatmap_addr);
31    folder: String = read_string(BEATMAP_OFFSET.location.folder, beatmap_addr);
32    filename: String = read_string(BEATMAP_OFFSET.location.filename, beatmap_addr);
33    audio: String = read_string(BEATMAP_OFFSET.location.audio, beatmap_addr);
34    cover: String = read_string(BEATMAP_OFFSET.location.cover, beatmap_addr);
35    mode: GameMode = read_i32(BEATMAP_OFFSET.technical.mode, beatmap_addr);
36    status: BeatmapStatus = read_i32(BEATMAP_OFFSET.technical.ranked_status, beatmap_addr);
37}
38
39pub fn stats(p: &Process, state: &mut State) -> Result<BeatmapStats, Error> {
40    let beatmap_addr = beatmap_addr(p, state)?;
41    let mut buffer = [0u8; size_of::<f32>() * 4];
42    p.read(
43        beatmap_addr + 0x2c,
44        size_of::<f32>() * 4,
45        &mut buffer,
46    )?;
47
48    Ok(BeatmapStats {
49        ar: f32::from_le_bytes(buffer[0..4].try_into().unwrap()),
50        cs: f32::from_le_bytes(buffer[4..8].try_into().unwrap()),
51        hp: f32::from_le_bytes(buffer[8..12].try_into().unwrap()),
52        od: f32::from_le_bytes(buffer[12..].try_into().unwrap()),
53        length: p.read_i32(beatmap_addr + BEATMAP_OFFSET.stats.total_length)?,
54        star_rating: crate::reader::beatmap::stable::file::star_rating(p, state)?,
55        object_count: p.read_i32(beatmap_addr + BEATMAP_OFFSET.stats.object_count)?,
56        slider_count: p.read_i32(beatmap_addr + BEATMAP_OFFSET.stats.slider_count)?,
57    })
58}
59
60pub fn info(p: &Process, state: &mut State) -> Result<BeatmapInfo, Error> {
61    let beatmap_addr = beatmap_addr(p, state)?;
62
63    let mut buffer = [0u8; size_of::<f32>() * 4];
64    p.read(
65        beatmap_addr + 0x2c,
66        size_of::<f32>() * 4,
67        &mut buffer,
68    )?;
69
70
71    let stats =BeatmapStats {
72        ar: f32::from_le_bytes(buffer[0..4].try_into().unwrap()),
73        cs: f32::from_le_bytes(buffer[4..8].try_into().unwrap()),
74        hp: f32::from_le_bytes(buffer[8..12].try_into().unwrap()),
75        od: f32::from_le_bytes(buffer[12..].try_into().unwrap()),
76        length: p.read_i32(beatmap_addr + BEATMAP_OFFSET.stats.total_length)?,
77        star_rating: crate::reader::beatmap::stable::file::star_rating(p, state)?,
78        object_count: p.read_i32(beatmap_addr + BEATMAP_OFFSET.stats.object_count)?,
79        slider_count: p.read_i32(beatmap_addr + BEATMAP_OFFSET.stats.slider_count)?,
80    };
81    Ok(BeatmapInfo {
82        technical: BeatmapTechnicalInfo {
83            md5: p.read_string(beatmap_addr + BEATMAP_OFFSET.technical.md5)?,
84            id: p.read_i32(beatmap_addr + BEATMAP_OFFSET.technical.id)?,
85            set_id: p.read_i32(beatmap_addr + BEATMAP_OFFSET.technical.set_id)?,
86            mode: GameMode::Osu,
87            ranked_status: BeatmapStatus::from(
88                p.read_i32(beatmap_addr + BEATMAP_OFFSET.technical.ranked_status)?,
89            ),
90        },
91        metadata: BeatmapMetadata {
92            author: p.read_string(beatmap_addr + BEATMAP_OFFSET.metadata.author)?,
93            creator: p.read_string(beatmap_addr + BEATMAP_OFFSET.metadata.creator)?,
94            title_romanized: p
95                .read_string(beatmap_addr + BEATMAP_OFFSET.metadata.title_romanized)?,
96            title_original: p.read_string(beatmap_addr + BEATMAP_OFFSET.metadata.title_original)?,
97            difficulty: p.read_string(beatmap_addr + BEATMAP_OFFSET.metadata.difficulty)?,
98            tags: p.read_string(beatmap_addr + BEATMAP_OFFSET.metadata.tags)?,
99        },
100        stats,
101        location: BeatmapLocation {
102            folder: p.read_string(beatmap_addr + BEATMAP_OFFSET.location.folder)?,
103            filename: p.read_string(beatmap_addr + BEATMAP_OFFSET.location.filename)?,
104            audio: p.read_string(beatmap_addr + BEATMAP_OFFSET.location.audio)?,
105            cover: p.read_string(beatmap_addr + BEATMAP_OFFSET.location.cover)?,
106        },
107    })
108}