186 lines
5.3 KiB
Rust
186 lines
5.3 KiB
Rust
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<u32> 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<MusicRating>,
|
|
/// b15
|
|
pub new_rating_list: Vec<MusicRating>,
|
|
/// 候补 b35
|
|
pub next_rating_list: Vec<MusicRating>,
|
|
/// 候补 b15
|
|
pub next_new_rating_list: Vec<MusicRating>,
|
|
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<String> {
|
|
Some(query_music(self.music_id).as_ref()?.name.clone())
|
|
}
|
|
|
|
pub fn dx_rating(&self) -> Option<u32> {
|
|
Some(query_music_level(self.music_id, self.level)?.dx_rating(self.achievement))
|
|
}
|
|
}
|