mirror of
https://github.com/natsukagami/youmubot.git
synced 2025-04-19 08:48:54 +00:00
Update to rosu-pp 1.0
This commit is contained in:
parent
22fc980a51
commit
0b111d5b26
5 changed files with 75 additions and 247 deletions
15
Cargo.lock
generated
15
Cargo.lock
generated
|
@ -1795,10 +1795,19 @@ dependencies = [
|
|||
]
|
||||
|
||||
[[package]]
|
||||
name = "rosu-pp"
|
||||
version = "0.9.5"
|
||||
name = "rosu-map"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "be9e281b71d3797817a1e6615dd8fb081dd61359b4c41d08792cc7c3c1c13b4e"
|
||||
checksum = "3c55926c8f0fed1db12fbe96f7a6083a2c4186443dd32532ab34e6902467a4f3"
|
||||
|
||||
[[package]]
|
||||
name = "rosu-pp"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "26f146c66bed5900ee1fa2b55ef5cc5dd2dbd45e6cac0f7bee5cae535980afbc"
|
||||
dependencies = [
|
||||
"rosu-map",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rosu-v2"
|
||||
|
|
|
@ -15,7 +15,7 @@ lazy_static = "1.4.0"
|
|||
osuparse = { git = "https://github.com/eltrufas/osuparse", rev = "ad8f6e5e7771e7cbaa2ec96c376558f9731139af" }
|
||||
regex = "1.5.6"
|
||||
reqwest = "0.11.10"
|
||||
rosu-pp = "0.9.1"
|
||||
rosu-pp = "1.0"
|
||||
rosu-v2 = { git = "https://github.com/MaxOhn/rosu-v2", rev = "d2cd3ff8417e66890f0cd8ca38bc34717a9629dd" }
|
||||
time = "0.3"
|
||||
serde = { version = "1.0.137", features = ["derive"] }
|
||||
|
|
|
@ -70,13 +70,26 @@ pub fn beatmap_offline_embed(
|
|||
|
||||
let total_length = if !bm.hit_objects.is_empty() {
|
||||
Duration::from_millis(
|
||||
(bm.hit_objects.last().unwrap().end_time() - bm.hit_objects.first().unwrap().start_time)
|
||||
(bm.hit_objects.last().unwrap().start_time - bm.hit_objects.first().unwrap().start_time)
|
||||
as u64,
|
||||
)
|
||||
} else {
|
||||
Duration::from_secs(0)
|
||||
};
|
||||
|
||||
let (circles, sliders, spinners) = {
|
||||
let (mut circles, mut sliders, mut spinners) = (0u64, 0u64, 0u64);
|
||||
for obj in bm.hit_objects.iter() {
|
||||
match obj.kind {
|
||||
rosu_pp::model::hit_object::HitObjectKind::Circle => circles += 1,
|
||||
rosu_pp::model::hit_object::HitObjectKind::Slider(_) => sliders += 1,
|
||||
rosu_pp::model::hit_object::HitObjectKind::Spinner(_) => spinners += 1,
|
||||
rosu_pp::model::hit_object::HitObjectKind::Hold(_) => sliders += 1,
|
||||
}
|
||||
}
|
||||
(circles, sliders, spinners)
|
||||
};
|
||||
|
||||
let diff = Difficulty {
|
||||
stars: info.stars,
|
||||
aim: None, // TODO: this is currently unused
|
||||
|
@ -85,9 +98,9 @@ pub fn beatmap_offline_embed(
|
|||
od: bm.od as f64,
|
||||
ar: bm.ar as f64,
|
||||
hp: bm.hp as f64,
|
||||
count_normal: bm.n_circles as u64,
|
||||
count_slider: bm.n_sliders as u64,
|
||||
count_spinner: bm.n_spinners as u64,
|
||||
count_normal: circles,
|
||||
count_slider: sliders,
|
||||
count_spinner: spinners,
|
||||
max_combo: Some(info.max_combo as u64),
|
||||
bpm: bm.bpm(),
|
||||
drain_length: total_length, // It's hard to calculate so maybe just skip...
|
||||
|
|
|
@ -2,11 +2,8 @@ use std::io::Read;
|
|||
use std::sync::Arc;
|
||||
|
||||
use osuparse::MetadataSection;
|
||||
use rosu_pp::catch::CatchDifficultyAttributes;
|
||||
use rosu_pp::mania::ManiaDifficultyAttributes;
|
||||
use rosu_pp::osu::OsuDifficultyAttributes;
|
||||
use rosu_pp::taiko::TaikoDifficultyAttributes;
|
||||
use rosu_pp::{AttributeProvider, Beatmap, CatchPP, DifficultyAttributes, ManiaPP, OsuPP, TaikoPP};
|
||||
use rosu_pp::any::DifficultyAttributes;
|
||||
use rosu_pp::Beatmap;
|
||||
|
||||
use youmubot_db_sql::{models::osu as models, Pool};
|
||||
use youmubot_prelude::*;
|
||||
|
@ -32,7 +29,7 @@ impl BeatmapInfo {
|
|||
fn extract(beatmap: &Beatmap, attrs: DifficultyAttributes) -> Self {
|
||||
BeatmapInfo {
|
||||
objects: beatmap.hit_objects.len(),
|
||||
max_combo: attrs.max_combo(),
|
||||
max_combo: attrs.max_combo() as usize,
|
||||
stars: attrs.stars(),
|
||||
}
|
||||
}
|
||||
|
@ -70,206 +67,6 @@ impl Accuracy {
|
|||
/// Beatmap Info with attached 95/98/99/100% FC pp.
|
||||
pub type BeatmapInfoWithPP = (BeatmapInfo, [f64; 4]);
|
||||
|
||||
trait PPCalc<'a>: Sized {
|
||||
type Attrs: rosu_pp::AttributeProvider + Clone;
|
||||
|
||||
fn new(beatmap: &'a Beatmap) -> Self;
|
||||
fn mods(self, mods: u32) -> Self;
|
||||
fn attributes(self, attrs: Self::Attrs) -> Self;
|
||||
|
||||
/* For pp calculation */
|
||||
fn combo(self, combo: usize) -> Self;
|
||||
fn accuracy(self, accuracy: f64) -> Self;
|
||||
fn misses(self, misses: usize) -> Self;
|
||||
fn get_pp(self) -> f64;
|
||||
|
||||
/* For difficulty calculation */
|
||||
fn get_attrs(self) -> Self::Attrs;
|
||||
|
||||
fn combo_opt(self, combo: Option<usize>) -> Self {
|
||||
match combo {
|
||||
Some(c) => self.combo(c),
|
||||
None => self,
|
||||
}
|
||||
}
|
||||
fn accuracy_from(self, accuracy: Accuracy) -> Self {
|
||||
self.misses(accuracy.misses()).accuracy(accuracy.into())
|
||||
}
|
||||
|
||||
fn map_attributes(beatmap: &'a Beatmap, mods: Mods) -> Self::Attrs {
|
||||
Self::new(beatmap).mods(mods.bits() as u32).get_attrs()
|
||||
}
|
||||
fn map_pp(beatmap: &'a Beatmap, mods: Mods, combo: Option<usize>, accuracy: Accuracy) -> f64 {
|
||||
Self::new(beatmap)
|
||||
.mods(mods.bits() as u32)
|
||||
.combo_opt(combo)
|
||||
.accuracy_from(accuracy)
|
||||
.get_pp()
|
||||
}
|
||||
fn map_info(beatmap: &'a Beatmap, mods: Mods) -> BeatmapInfo {
|
||||
let attrs = Self::map_attributes(beatmap, mods).attributes();
|
||||
BeatmapInfo::extract(beatmap, attrs)
|
||||
}
|
||||
|
||||
fn map_info_with_pp(beatmap: &'a Beatmap, mods: Mods) -> BeatmapInfoWithPP {
|
||||
let attrs = Self::map_attributes(beatmap, mods);
|
||||
let nw = || {
|
||||
Self::new(beatmap)
|
||||
.mods(mods.bits() as u32)
|
||||
.attributes(attrs.clone())
|
||||
};
|
||||
let pps = [
|
||||
nw().accuracy_from(Accuracy::ByValue(95.0, 0)).get_pp(),
|
||||
nw().accuracy_from(Accuracy::ByValue(98.0, 0)).get_pp(),
|
||||
nw().accuracy_from(Accuracy::ByValue(99.0, 0)).get_pp(),
|
||||
nw().accuracy_from(Accuracy::ByValue(100.0, 0)).get_pp(),
|
||||
];
|
||||
let info = BeatmapInfo::extract(beatmap, attrs.attributes());
|
||||
(info, pps)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> PPCalc<'a> for OsuPP<'a> {
|
||||
type Attrs = OsuDifficultyAttributes;
|
||||
|
||||
fn new(beatmap: &'a Beatmap) -> Self {
|
||||
Self::new(beatmap)
|
||||
}
|
||||
fn mods(self, mods: u32) -> Self {
|
||||
self.mods(mods)
|
||||
}
|
||||
|
||||
fn attributes(self, attrs: Self::Attrs) -> Self {
|
||||
self.attributes(attrs)
|
||||
}
|
||||
|
||||
fn combo(self, combo: usize) -> Self {
|
||||
self.combo(combo)
|
||||
}
|
||||
|
||||
fn accuracy(self, accuracy: f64) -> Self {
|
||||
self.accuracy(accuracy)
|
||||
}
|
||||
|
||||
fn misses(self, misses: usize) -> Self {
|
||||
self.n_misses(misses)
|
||||
}
|
||||
|
||||
fn get_pp(self) -> f64 {
|
||||
self.calculate().pp()
|
||||
}
|
||||
|
||||
fn get_attrs(self) -> Self::Attrs {
|
||||
self.calculate().difficulty
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> PPCalc<'a> for TaikoPP<'a> {
|
||||
type Attrs = TaikoDifficultyAttributes;
|
||||
|
||||
fn new(beatmap: &'a Beatmap) -> Self {
|
||||
Self::new(beatmap)
|
||||
}
|
||||
fn mods(self, mods: u32) -> Self {
|
||||
self.mods(mods)
|
||||
}
|
||||
|
||||
fn attributes(self, attrs: Self::Attrs) -> Self {
|
||||
self.attributes(attrs)
|
||||
}
|
||||
|
||||
fn combo(self, combo: usize) -> Self {
|
||||
self.combo(combo)
|
||||
}
|
||||
|
||||
fn accuracy(self, accuracy: f64) -> Self {
|
||||
self.accuracy(accuracy)
|
||||
}
|
||||
|
||||
fn misses(self, misses: usize) -> Self {
|
||||
self.n_misses(misses)
|
||||
}
|
||||
|
||||
fn get_pp(self) -> f64 {
|
||||
self.calculate().pp()
|
||||
}
|
||||
|
||||
fn get_attrs(self) -> Self::Attrs {
|
||||
self.calculate().difficulty
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> PPCalc<'a> for CatchPP<'a> {
|
||||
type Attrs = CatchDifficultyAttributes;
|
||||
|
||||
fn new(beatmap: &'a Beatmap) -> Self {
|
||||
Self::new(beatmap)
|
||||
}
|
||||
fn mods(self, mods: u32) -> Self {
|
||||
self.mods(mods)
|
||||
}
|
||||
|
||||
fn attributes(self, attrs: Self::Attrs) -> Self {
|
||||
self.attributes(attrs)
|
||||
}
|
||||
|
||||
fn combo(self, combo: usize) -> Self {
|
||||
self.combo(combo)
|
||||
}
|
||||
|
||||
fn accuracy(self, accuracy: f64) -> Self {
|
||||
self.accuracy(accuracy)
|
||||
}
|
||||
|
||||
fn misses(self, misses: usize) -> Self {
|
||||
self.misses(misses)
|
||||
}
|
||||
|
||||
fn get_pp(self) -> f64 {
|
||||
self.calculate().pp()
|
||||
}
|
||||
|
||||
fn get_attrs(self) -> Self::Attrs {
|
||||
self.calculate().difficulty
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> PPCalc<'a> for ManiaPP<'a> {
|
||||
type Attrs = ManiaDifficultyAttributes;
|
||||
|
||||
fn new(beatmap: &'a Beatmap) -> Self {
|
||||
Self::new(beatmap)
|
||||
}
|
||||
fn mods(self, mods: u32) -> Self {
|
||||
self.mods(mods)
|
||||
}
|
||||
|
||||
fn attributes(self, attrs: Self::Attrs) -> Self {
|
||||
self.attributes(attrs)
|
||||
}
|
||||
|
||||
fn combo(self, _combo: usize) -> Self {
|
||||
// Mania doesn't seem to care about combo?
|
||||
self
|
||||
}
|
||||
|
||||
fn accuracy(self, accuracy: f64) -> Self {
|
||||
self.accuracy(accuracy)
|
||||
}
|
||||
|
||||
fn misses(self, misses: usize) -> Self {
|
||||
self.n_misses(misses)
|
||||
}
|
||||
|
||||
fn get_pp(self) -> f64 {
|
||||
self.calculate().pp()
|
||||
}
|
||||
|
||||
fn get_attrs(self) -> Self::Attrs {
|
||||
self.calculate().difficulty
|
||||
}
|
||||
}
|
||||
|
||||
impl BeatmapContent {
|
||||
/// Get pp given the combo and accuracy.
|
||||
pub fn get_pp_from(
|
||||
|
@ -279,34 +76,55 @@ impl BeatmapContent {
|
|||
accuracy: Accuracy,
|
||||
mods: Mods,
|
||||
) -> Result<f64> {
|
||||
let bm = self.content.as_ref();
|
||||
Ok(match mode {
|
||||
Mode::Std => OsuPP::map_pp(bm, mods, combo, accuracy),
|
||||
Mode::Taiko => TaikoPP::map_pp(bm, mods, combo, accuracy),
|
||||
Mode::Catch => CatchPP::map_pp(bm, mods, combo, accuracy),
|
||||
Mode::Mania => ManiaPP::map_pp(bm, mods, combo, accuracy),
|
||||
})
|
||||
let mut perf = self
|
||||
.content
|
||||
.performance()
|
||||
.mode_or_ignore(mode.into())
|
||||
.accuracy(accuracy.into())
|
||||
.misses(accuracy.misses() as u32)
|
||||
.mods(mods.bits() as u32);
|
||||
if let Some(combo) = combo {
|
||||
perf = perf.combo(combo as u32);
|
||||
}
|
||||
let attrs = perf.calculate();
|
||||
Ok(attrs.pp())
|
||||
}
|
||||
|
||||
/// Get info given mods.
|
||||
pub fn get_info_with(&self, mode: Mode, mods: Mods) -> Result<BeatmapInfo> {
|
||||
let bm = self.content.as_ref();
|
||||
Ok(match mode {
|
||||
Mode::Std => OsuPP::map_info(bm, mods),
|
||||
Mode::Taiko => TaikoPP::map_info(bm, mods),
|
||||
Mode::Catch => CatchPP::map_info(bm, mods),
|
||||
Mode::Mania => ManiaPP::map_info(bm, mods),
|
||||
let attrs = self
|
||||
.content
|
||||
.performance()
|
||||
.mode_or_ignore(mode.into())
|
||||
.mods(mods.bits() as u32)
|
||||
.calculate();
|
||||
Ok(BeatmapInfo {
|
||||
objects: self.content.hit_objects.len(),
|
||||
max_combo: attrs.max_combo() as usize,
|
||||
stars: attrs.stars(),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn get_possible_pp_with(&self, mode: Mode, mods: Mods) -> Result<BeatmapInfoWithPP> {
|
||||
let bm = self.content.as_ref();
|
||||
Ok(match mode {
|
||||
Mode::Std => OsuPP::map_info_with_pp(bm, mods),
|
||||
Mode::Taiko => TaikoPP::map_info_with_pp(bm, mods),
|
||||
Mode::Catch => CatchPP::map_info_with_pp(bm, mods),
|
||||
Mode::Mania => ManiaPP::map_info_with_pp(bm, mods),
|
||||
})
|
||||
let pp: [f64; 4] = [
|
||||
self.get_pp_from(mode, None, Accuracy::ByValue(95.0, 0), mods)?,
|
||||
self.get_pp_from(mode, None, Accuracy::ByValue(98.0, 0), mods)?,
|
||||
self.get_pp_from(mode, None, Accuracy::ByValue(99.0, 0), mods)?,
|
||||
self.get_pp_from(mode, None, Accuracy::ByValue(100.0, 0), mods)?,
|
||||
];
|
||||
Ok((self.get_info_with(mode, mods)?, pp))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Mode> for rosu_pp::model::mode::GameMode {
|
||||
fn from(value: Mode) -> Self {
|
||||
use rosu_pp::model::mode::GameMode;
|
||||
match value {
|
||||
Mode::Std => GameMode::Osu,
|
||||
Mode::Taiko => GameMode::Taiko,
|
||||
Mode::Catch => GameMode::Catch,
|
||||
Mode::Mania => GameMode::Mania,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -337,7 +155,7 @@ impl BeatmapCache {
|
|||
.metadata;
|
||||
Ok(BeatmapContent {
|
||||
metadata,
|
||||
content: Arc::new(Beatmap::parse(content.as_bytes())?),
|
||||
content: Arc::new(Beatmap::from_bytes(content.as_bytes())?),
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
use chrono::{DateTime, Utc};
|
||||
use rosu_pp::GameMode;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
use std::time::Duration;
|
||||
|
@ -275,17 +274,6 @@ impl From<u8> for Mode {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<Mode> for GameMode {
|
||||
fn from(n: Mode) -> Self {
|
||||
match n {
|
||||
Mode::Std => GameMode::Osu,
|
||||
Mode::Taiko => GameMode::Taiko,
|
||||
Mode::Catch => GameMode::Catch,
|
||||
Mode::Mania => GameMode::Mania,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Mode {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
use Mode::*;
|
||||
|
|
Loading…
Add table
Reference in a new issue