use std::fmt::Display; use bincode::Decode; use bincode::Encode; use serde::Deserialize; use serde::Serialize; use crate::helper::level_name; use crate::helper::query_music; use crate::helper::query_music_level; #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct GetUserRatingApi { pub user_id: u32, } impl From for GetUserRatingApi { fn from(user_id: u32) -> Self { Self { user_id } } } #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Encode, Decode)] #[serde(rename_all = "camelCase")] pub struct GetUserRatingApiResp { pub user_id: u32, pub user_rating: UserRating, } #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Encode, Decode)] #[serde(rename_all = "camelCase")] pub struct UserRating { /// total rating, now it's 0 pub rating: i64, /// b35 pub rating_list: Vec, /// b15 pub new_rating_list: Vec, /// 候补 b35 pub next_rating_list: Vec, /// 候补 b15 pub next_new_rating_list: Vec, pub udemae: Udemae, } #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Encode, Decode)] #[serde(rename_all = "camelCase")] pub struct MusicRating { /// Maimai music id pub music_id: u32, /// - 0: BASIC /// - 1: ADVANCED /// - 2: EXPERT /// - 3: MASTER /// - 4: RE: MASTER /// - 5: Utage 宴会场 pub level: u32, /// 歌曲 ROM 版本 /// /// - `1mmpp` -> `1.mm.pp` /// - `2mmpp` -> `1.mm.pp` DX pub rom_version: i64, /// 达成率 * 10000 的整数 pub achievement: i32, } #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Encode, Decode)] #[serde(rename_all = "camelCase")] pub struct Udemae { pub max_lose_num: i64, pub npc_total_win_num: i64, pub npc_total_lose_num: i64, pub npc_max_win_num: i64, pub npc_max_lose_num: i64, pub npc_win_num: i64, pub npc_lose_num: i64, pub rate: i64, pub class_value: i64, pub max_rate: i64, pub max_class_value: i64, pub total_win_num: i64, pub total_lose_num: i64, pub max_win_num: i64, pub win_num: i64, pub lose_num: i64, #[serde(rename = "MaxLoseNum")] pub max_lose_num2: i64, #[serde(rename = "NpcTotalWinNum")] pub npc_total_win_num2: i64, #[serde(rename = "NpcTotalLoseNum")] pub npc_total_lose_num2: i64, #[serde(rename = "NpcMaxWinNum")] pub npc_max_win_num2: i64, #[serde(rename = "NpcMaxLoseNum")] pub npc_max_lose_num2: i64, #[serde(rename = "NpcWinNum")] pub npc_win_num2: i64, #[serde(rename = "NpcLoseNum")] pub npc_lose_num2: i64, } impl Display for GetUserRatingApiResp { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let b35 = &self.user_rating.rating_list; let b15 = &self.user_rating.new_rating_list; f.write_fmt(format_args!("用户ID: {}\n", self.user_id))?; f.write_str("\n--------- B35 ---------\n")?; for music in b35 { f.write_fmt(format_args!("{music}\n---\n"))?; } f.write_str("\n--------- B15 ---------\n")?; for music in b15 { f.write_fmt(format_args!("{music}\n---\n"))?; } let b35_rating: u32 = b35.iter().filter_map(|m| m.dx_rating()).sum(); let b15_rating: u32 = b15.iter().filter_map(|m| m.dx_rating()).sum(); f.write_str("\n--------- Total ---------\n")?; f.write_fmt(format_args!("B35 Rating: {b35_rating}\n"))?; f.write_fmt(format_args!("B15 Rating: {b15_rating}\n"))?; f.write_fmt(format_args!("总 Rating: {}\n", b35_rating + b15_rating))?; Ok(()) } } impl Display for MusicRating { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.write_fmt(format_args!("歌曲ID: \t{}\n", self.music_id))?; if let Some(title) = self.music_title() { f.write_fmt(format_args!("曲目标题: \t{title}\n"))?; } f.write_fmt(format_args!( "谱面版本: \t{}\n", match (self.music_id / 10000) % 10 { 0 => "SD", 1 => "DX", _ => "宴", } ))?; f.write_fmt(format_args!("游玩难度: \t{}\n", level_name(self.level)))?; f.write_fmt(format_args!( "达成率: \t{}.{:04}%\n", self.achievement / 10000, self.achievement % 10000 ))?; if self.rom_version >= 20000 { f.write_fmt(format_args!( "谱面版本: \tDX 1.{:02}.{:02}\n", (self.rom_version / 100) % 100, self.rom_version % 100, ))?; } else { f.write_fmt(format_args!( "谱面版本: \tSD 1.{:02}.{:02}\n", (self.rom_version / 100) % 100, self.rom_version % 100, ))?; } if let Some(dx_rating) = self.dx_rating() { f.write_fmt(format_args!("DX RATING: \t{dx_rating}"))?; } Ok(()) } } impl MusicRating { pub fn music_title(&self) -> Option { Some(query_music(self.music_id).as_ref()?.name.clone()) } pub fn dx_rating(&self) -> Option { Some(query_music_level(self.music_id, self.level)?.dx_rating(self.achievement)) } }