mirror of
https://github.com/natsukagami/youmubot.git
synced 2025-04-19 16:58:55 +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]]
|
[[package]]
|
||||||
name = "rosu-pp"
|
name = "rosu-map"
|
||||||
version = "0.9.5"
|
version = "0.1.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
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]]
|
[[package]]
|
||||||
name = "rosu-v2"
|
name = "rosu-v2"
|
||||||
|
|
|
@ -15,7 +15,7 @@ lazy_static = "1.4.0"
|
||||||
osuparse = { git = "https://github.com/eltrufas/osuparse", rev = "ad8f6e5e7771e7cbaa2ec96c376558f9731139af" }
|
osuparse = { git = "https://github.com/eltrufas/osuparse", rev = "ad8f6e5e7771e7cbaa2ec96c376558f9731139af" }
|
||||||
regex = "1.5.6"
|
regex = "1.5.6"
|
||||||
reqwest = "0.11.10"
|
reqwest = "0.11.10"
|
||||||
rosu-pp = "0.9.1"
|
rosu-pp = "1.0"
|
||||||
rosu-v2 = { git = "https://github.com/MaxOhn/rosu-v2", rev = "d2cd3ff8417e66890f0cd8ca38bc34717a9629dd" }
|
rosu-v2 = { git = "https://github.com/MaxOhn/rosu-v2", rev = "d2cd3ff8417e66890f0cd8ca38bc34717a9629dd" }
|
||||||
time = "0.3"
|
time = "0.3"
|
||||||
serde = { version = "1.0.137", features = ["derive"] }
|
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() {
|
let total_length = if !bm.hit_objects.is_empty() {
|
||||||
Duration::from_millis(
|
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,
|
as u64,
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
Duration::from_secs(0)
|
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 {
|
let diff = Difficulty {
|
||||||
stars: info.stars,
|
stars: info.stars,
|
||||||
aim: None, // TODO: this is currently unused
|
aim: None, // TODO: this is currently unused
|
||||||
|
@ -85,9 +98,9 @@ pub fn beatmap_offline_embed(
|
||||||
od: bm.od as f64,
|
od: bm.od as f64,
|
||||||
ar: bm.ar as f64,
|
ar: bm.ar as f64,
|
||||||
hp: bm.hp as f64,
|
hp: bm.hp as f64,
|
||||||
count_normal: bm.n_circles as u64,
|
count_normal: circles,
|
||||||
count_slider: bm.n_sliders as u64,
|
count_slider: sliders,
|
||||||
count_spinner: bm.n_spinners as u64,
|
count_spinner: spinners,
|
||||||
max_combo: Some(info.max_combo as u64),
|
max_combo: Some(info.max_combo as u64),
|
||||||
bpm: bm.bpm(),
|
bpm: bm.bpm(),
|
||||||
drain_length: total_length, // It's hard to calculate so maybe just skip...
|
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 std::sync::Arc;
|
||||||
|
|
||||||
use osuparse::MetadataSection;
|
use osuparse::MetadataSection;
|
||||||
use rosu_pp::catch::CatchDifficultyAttributes;
|
use rosu_pp::any::DifficultyAttributes;
|
||||||
use rosu_pp::mania::ManiaDifficultyAttributes;
|
use rosu_pp::Beatmap;
|
||||||
use rosu_pp::osu::OsuDifficultyAttributes;
|
|
||||||
use rosu_pp::taiko::TaikoDifficultyAttributes;
|
|
||||||
use rosu_pp::{AttributeProvider, Beatmap, CatchPP, DifficultyAttributes, ManiaPP, OsuPP, TaikoPP};
|
|
||||||
|
|
||||||
use youmubot_db_sql::{models::osu as models, Pool};
|
use youmubot_db_sql::{models::osu as models, Pool};
|
||||||
use youmubot_prelude::*;
|
use youmubot_prelude::*;
|
||||||
|
@ -32,7 +29,7 @@ impl BeatmapInfo {
|
||||||
fn extract(beatmap: &Beatmap, attrs: DifficultyAttributes) -> Self {
|
fn extract(beatmap: &Beatmap, attrs: DifficultyAttributes) -> Self {
|
||||||
BeatmapInfo {
|
BeatmapInfo {
|
||||||
objects: beatmap.hit_objects.len(),
|
objects: beatmap.hit_objects.len(),
|
||||||
max_combo: attrs.max_combo(),
|
max_combo: attrs.max_combo() as usize,
|
||||||
stars: attrs.stars(),
|
stars: attrs.stars(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -70,206 +67,6 @@ impl Accuracy {
|
||||||
/// Beatmap Info with attached 95/98/99/100% FC pp.
|
/// Beatmap Info with attached 95/98/99/100% FC pp.
|
||||||
pub type BeatmapInfoWithPP = (BeatmapInfo, [f64; 4]);
|
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 {
|
impl BeatmapContent {
|
||||||
/// Get pp given the combo and accuracy.
|
/// Get pp given the combo and accuracy.
|
||||||
pub fn get_pp_from(
|
pub fn get_pp_from(
|
||||||
|
@ -279,34 +76,55 @@ impl BeatmapContent {
|
||||||
accuracy: Accuracy,
|
accuracy: Accuracy,
|
||||||
mods: Mods,
|
mods: Mods,
|
||||||
) -> Result<f64> {
|
) -> Result<f64> {
|
||||||
let bm = self.content.as_ref();
|
let mut perf = self
|
||||||
Ok(match mode {
|
.content
|
||||||
Mode::Std => OsuPP::map_pp(bm, mods, combo, accuracy),
|
.performance()
|
||||||
Mode::Taiko => TaikoPP::map_pp(bm, mods, combo, accuracy),
|
.mode_or_ignore(mode.into())
|
||||||
Mode::Catch => CatchPP::map_pp(bm, mods, combo, accuracy),
|
.accuracy(accuracy.into())
|
||||||
Mode::Mania => ManiaPP::map_pp(bm, mods, combo, accuracy),
|
.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.
|
/// Get info given mods.
|
||||||
pub fn get_info_with(&self, mode: Mode, mods: Mods) -> Result<BeatmapInfo> {
|
pub fn get_info_with(&self, mode: Mode, mods: Mods) -> Result<BeatmapInfo> {
|
||||||
let bm = self.content.as_ref();
|
let attrs = self
|
||||||
Ok(match mode {
|
.content
|
||||||
Mode::Std => OsuPP::map_info(bm, mods),
|
.performance()
|
||||||
Mode::Taiko => TaikoPP::map_info(bm, mods),
|
.mode_or_ignore(mode.into())
|
||||||
Mode::Catch => CatchPP::map_info(bm, mods),
|
.mods(mods.bits() as u32)
|
||||||
Mode::Mania => ManiaPP::map_info(bm, mods),
|
.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> {
|
pub fn get_possible_pp_with(&self, mode: Mode, mods: Mods) -> Result<BeatmapInfoWithPP> {
|
||||||
let bm = self.content.as_ref();
|
let pp: [f64; 4] = [
|
||||||
Ok(match mode {
|
self.get_pp_from(mode, None, Accuracy::ByValue(95.0, 0), mods)?,
|
||||||
Mode::Std => OsuPP::map_info_with_pp(bm, mods),
|
self.get_pp_from(mode, None, Accuracy::ByValue(98.0, 0), mods)?,
|
||||||
Mode::Taiko => TaikoPP::map_info_with_pp(bm, mods),
|
self.get_pp_from(mode, None, Accuracy::ByValue(99.0, 0), mods)?,
|
||||||
Mode::Catch => CatchPP::map_info_with_pp(bm, mods),
|
self.get_pp_from(mode, None, Accuracy::ByValue(100.0, 0), mods)?,
|
||||||
Mode::Mania => ManiaPP::map_info_with_pp(bm, 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;
|
.metadata;
|
||||||
Ok(BeatmapContent {
|
Ok(BeatmapContent {
|
||||||
metadata,
|
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 chrono::{DateTime, Utc};
|
||||||
use rosu_pp::GameMode;
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::time::Duration;
|
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 {
|
impl fmt::Display for Mode {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
use Mode::*;
|
use Mode::*;
|
||||||
|
|
Loading…
Add table
Reference in a new issue