added a bunch of documentation
This commit is contained in:
@@ -632,18 +632,26 @@ impl<I: Iterator<Item = CatchObject>> Iterator for FruitOrJuice<I> {
|
|||||||
/// The result of a difficulty calculation on an osu!ctb map.
|
/// The result of a difficulty calculation on an osu!ctb map.
|
||||||
#[derive(Clone, Debug, Default)]
|
#[derive(Clone, Debug, Default)]
|
||||||
pub struct FruitsDifficultyAttributes {
|
pub struct FruitsDifficultyAttributes {
|
||||||
|
/// The final star rating
|
||||||
pub stars: f64,
|
pub stars: f64,
|
||||||
|
/// The maximum combo.
|
||||||
pub max_combo: usize,
|
pub max_combo: usize,
|
||||||
|
/// The approach rate.
|
||||||
pub ar: f64,
|
pub ar: f64,
|
||||||
|
/// The amount of fruits.
|
||||||
pub n_fruits: usize,
|
pub n_fruits: usize,
|
||||||
|
/// The amount of droplets.
|
||||||
pub n_droplets: usize,
|
pub n_droplets: usize,
|
||||||
|
/// The amount of tiny droplets.
|
||||||
pub n_tiny_droplets: usize,
|
pub n_tiny_droplets: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The result of a performance calculation on an osu!ctb map.
|
/// The result of a performance calculation on an osu!ctb map.
|
||||||
#[derive(Clone, Debug, Default)]
|
#[derive(Clone, Debug, Default)]
|
||||||
pub struct FruitsPerformanceAttributes {
|
pub struct FruitsPerformanceAttributes {
|
||||||
|
/// The difficulty attributes that were used for the performance calculation
|
||||||
pub attributes: FruitsDifficultyAttributes,
|
pub attributes: FruitsDifficultyAttributes,
|
||||||
|
/// The final performance points.
|
||||||
pub pp: f64,
|
pub pp: f64,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+9
-5
@@ -6,11 +6,13 @@ use crate::{Beatmap, DifficultyAttributes, Mods, PerformanceAttributes};
|
|||||||
/// # Example
|
/// # Example
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # use rosu_pp::{FruitsPP, PpResult, Beatmap};
|
/// use rosu_pp::{FruitsPP, Beatmap};
|
||||||
|
///
|
||||||
/// # /*
|
/// # /*
|
||||||
/// let map: Beatmap = ...
|
/// let map: Beatmap = ...
|
||||||
/// # */
|
/// # */
|
||||||
/// # let map = Beatmap::default();
|
/// # let map = Beatmap::default();
|
||||||
|
///
|
||||||
/// let pp_result = FruitsPP::new(&map)
|
/// let pp_result = FruitsPP::new(&map)
|
||||||
/// .mods(8 + 64) // HDDT
|
/// .mods(8 + 64) // HDDT
|
||||||
/// .combo(1234)
|
/// .combo(1234)
|
||||||
@@ -30,8 +32,8 @@ use crate::{Beatmap, DifficultyAttributes, Mods, PerformanceAttributes};
|
|||||||
/// ```
|
/// ```
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
#[allow(clippy::upper_case_acronyms)]
|
#[allow(clippy::upper_case_acronyms)]
|
||||||
pub struct FruitsPP<'m> {
|
pub struct FruitsPP<'map> {
|
||||||
map: &'m Beatmap,
|
map: &'map Beatmap,
|
||||||
attributes: Option<FruitsDifficultyAttributes>,
|
attributes: Option<FruitsDifficultyAttributes>,
|
||||||
mods: u32,
|
mods: u32,
|
||||||
combo: Option<usize>,
|
combo: Option<usize>,
|
||||||
@@ -44,9 +46,10 @@ pub struct FruitsPP<'m> {
|
|||||||
passed_objects: Option<usize>,
|
passed_objects: Option<usize>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'m> FruitsPP<'m> {
|
impl<'map> FruitsPP<'map> {
|
||||||
|
/// Create a new performance calculator for osu!ctb maps.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn new(map: &'m Beatmap) -> Self {
|
pub fn new(map: &'map Beatmap) -> Self {
|
||||||
Self {
|
Self {
|
||||||
map,
|
map,
|
||||||
attributes: None,
|
attributes: None,
|
||||||
@@ -372,6 +375,7 @@ impl FruitsPPInner {
|
|||||||
|
|
||||||
/// Abstract type to provide flexibility when passing difficulty attributes to a performance calculation.
|
/// Abstract type to provide flexibility when passing difficulty attributes to a performance calculation.
|
||||||
pub trait FruitsAttributeProvider {
|
pub trait FruitsAttributeProvider {
|
||||||
|
/// Provide the actual difficulty attributes.
|
||||||
fn attributes(self) -> Option<FruitsDifficultyAttributes>;
|
fn attributes(self) -> Option<FruitsDifficultyAttributes>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+25
-5
@@ -87,24 +87,37 @@
|
|||||||
//!
|
//!
|
||||||
|
|
||||||
#![cfg_attr(docsrs, feature(doc_cfg), deny(broken_intra_doc_links))]
|
#![cfg_attr(docsrs, feature(doc_cfg), deny(broken_intra_doc_links))]
|
||||||
#![deny(clippy::all, nonstandard_style, rust_2018_idioms, unused, warnings)]
|
#![deny(
|
||||||
|
clippy::all,
|
||||||
|
nonstandard_style,
|
||||||
|
rust_2018_idioms,
|
||||||
|
unused,
|
||||||
|
warnings,
|
||||||
|
missing_debug_implementations,
|
||||||
|
missing_docs
|
||||||
|
)]
|
||||||
|
|
||||||
#[cfg(feature = "fruits")]
|
#[cfg(feature = "fruits")]
|
||||||
#[cfg_attr(docsrs, doc(cfg(feature = "fruits")))]
|
#[cfg_attr(docsrs, doc(cfg(feature = "fruits")))]
|
||||||
|
/// Everything about osu!ctb.
|
||||||
pub mod fruits;
|
pub mod fruits;
|
||||||
|
|
||||||
#[cfg(feature = "mania")]
|
#[cfg(feature = "mania")]
|
||||||
#[cfg_attr(docsrs, doc(cfg(feature = "mania")))]
|
#[cfg_attr(docsrs, doc(cfg(feature = "mania")))]
|
||||||
|
/// Everything about osu!mania.
|
||||||
pub mod mania;
|
pub mod mania;
|
||||||
|
|
||||||
#[cfg(feature = "osu")]
|
#[cfg(feature = "osu")]
|
||||||
#[cfg_attr(docsrs, doc(cfg(feature = "osu")))]
|
#[cfg_attr(docsrs, doc(cfg(feature = "osu")))]
|
||||||
|
/// Everything about osu!standard.
|
||||||
pub mod osu;
|
pub mod osu;
|
||||||
|
|
||||||
#[cfg(feature = "taiko")]
|
#[cfg(feature = "taiko")]
|
||||||
#[cfg_attr(docsrs, doc(cfg(feature = "taiko")))]
|
#[cfg_attr(docsrs, doc(cfg(feature = "taiko")))]
|
||||||
|
/// Everything about osu!taiko.
|
||||||
pub mod taiko;
|
pub mod taiko;
|
||||||
|
|
||||||
|
/// Beatmap parsing and the contained types.
|
||||||
pub mod parse;
|
pub mod parse;
|
||||||
|
|
||||||
mod pp;
|
mod pp;
|
||||||
@@ -265,13 +278,11 @@ impl BeatmapExt for Beatmap {
|
|||||||
|
|
||||||
/// The result of calculating the strains on a map.
|
/// The result of calculating the strains on a map.
|
||||||
/// Suitable to plot the difficulty of a map over time.
|
/// Suitable to plot the difficulty of a map over time.
|
||||||
///
|
|
||||||
/// `strains` will be the summed strains for each skill of the map's mode.
|
|
||||||
///
|
|
||||||
/// `section_length` is the time in ms inbetween two strains.
|
|
||||||
#[derive(Clone, Debug, Default)]
|
#[derive(Clone, Debug, Default)]
|
||||||
pub struct Strains {
|
pub struct Strains {
|
||||||
|
/// Time in ms inbetween two strains.
|
||||||
pub section_length: f64,
|
pub section_length: f64,
|
||||||
|
/// Summed strains for each skill of the map's mode.
|
||||||
pub strains: Vec<f64>,
|
pub strains: Vec<f64>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -279,12 +290,16 @@ pub struct Strains {
|
|||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub enum DifficultyAttributes {
|
pub enum DifficultyAttributes {
|
||||||
#[cfg(feature = "fruits")]
|
#[cfg(feature = "fruits")]
|
||||||
|
/// osu!ctb difficulty calculation reseult.
|
||||||
Fruits(fruits::FruitsDifficultyAttributes),
|
Fruits(fruits::FruitsDifficultyAttributes),
|
||||||
#[cfg(feature = "mania")]
|
#[cfg(feature = "mania")]
|
||||||
|
/// osu!mania difficulty calculation reseult.
|
||||||
Mania(mania::ManiaDifficultyAttributes),
|
Mania(mania::ManiaDifficultyAttributes),
|
||||||
#[cfg(feature = "osu")]
|
#[cfg(feature = "osu")]
|
||||||
|
/// osu!standard difficulty calculation reseult.
|
||||||
Osu(osu::OsuDifficultyAttributes),
|
Osu(osu::OsuDifficultyAttributes),
|
||||||
#[cfg(feature = "taiko")]
|
#[cfg(feature = "taiko")]
|
||||||
|
/// osu!taiko difficulty calculation reseult.
|
||||||
Taiko(taiko::TaikoDifficultyAttributes),
|
Taiko(taiko::TaikoDifficultyAttributes),
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -337,12 +352,16 @@ impl From<taiko::TaikoDifficultyAttributes> for DifficultyAttributes {
|
|||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub enum PerformanceAttributes {
|
pub enum PerformanceAttributes {
|
||||||
#[cfg(feature = "fruits")]
|
#[cfg(feature = "fruits")]
|
||||||
|
/// osu!ctb performance calculation result.
|
||||||
Fruits(fruits::FruitsPerformanceAttributes),
|
Fruits(fruits::FruitsPerformanceAttributes),
|
||||||
#[cfg(feature = "mania")]
|
#[cfg(feature = "mania")]
|
||||||
|
/// osu!mania performance calculation result.
|
||||||
Mania(mania::ManiaPerformanceAttributes),
|
Mania(mania::ManiaPerformanceAttributes),
|
||||||
#[cfg(feature = "osu")]
|
#[cfg(feature = "osu")]
|
||||||
|
/// osu!standard performance calculation result.
|
||||||
Osu(osu::OsuPerformanceAttributes),
|
Osu(osu::OsuPerformanceAttributes),
|
||||||
#[cfg(feature = "taiko")]
|
#[cfg(feature = "taiko")]
|
||||||
|
/// osu!taiko performance calculation result.
|
||||||
Taiko(taiko::TaikoPerformanceAttributes),
|
Taiko(taiko::TaikoPerformanceAttributes),
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -377,6 +396,7 @@ impl PerformanceAttributes {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Difficulty attributes that were used for the performance calculation.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn difficulty_attributes(&self) -> DifficultyAttributes {
|
pub fn difficulty_attributes(&self) -> DifficultyAttributes {
|
||||||
match self {
|
match self {
|
||||||
|
|||||||
+7
-2
@@ -172,16 +172,21 @@ impl<'o> DifficultyHitObject<'o> {
|
|||||||
/// The result of a difficulty calculation on an osu!mania map.
|
/// The result of a difficulty calculation on an osu!mania map.
|
||||||
#[derive(Copy, Clone, Debug, Default)]
|
#[derive(Copy, Clone, Debug, Default)]
|
||||||
pub struct ManiaDifficultyAttributes {
|
pub struct ManiaDifficultyAttributes {
|
||||||
|
/// The final star rating.
|
||||||
pub stars: f64,
|
pub stars: f64,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The result of a performance calculation on an osu!mania map.
|
/// The result of a performance calculation on an osu!mania map.
|
||||||
#[derive(Copy, Clone, Debug, Default)]
|
#[derive(Copy, Clone, Debug, Default)]
|
||||||
pub struct ManiaPerformanceAttributes {
|
pub struct ManiaPerformanceAttributes {
|
||||||
|
/// The difficulty attributes that were used for the performance calculation
|
||||||
pub attributes: ManiaDifficultyAttributes,
|
pub attributes: ManiaDifficultyAttributes,
|
||||||
pub pp_acc: f64,
|
/// The final performance points.
|
||||||
pub pp_strain: f64,
|
|
||||||
pub pp: f64,
|
pub pp: f64,
|
||||||
|
/// The accuracy portion of the final pp.
|
||||||
|
pub pp_acc: f64,
|
||||||
|
/// The strain portion of the final pp.
|
||||||
|
pub pp_strain: f64,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ManiaPerformanceAttributes {
|
impl ManiaPerformanceAttributes {
|
||||||
|
|||||||
+10
-6
@@ -6,11 +6,13 @@ use crate::{Beatmap, DifficultyAttributes, Mods, PerformanceAttributes};
|
|||||||
/// # Example
|
/// # Example
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # use rosu_pp::{ManiaPP, PpResult, Beatmap};
|
/// use rosu_pp::{ManiaPP, Beatmap};
|
||||||
|
///
|
||||||
/// # /*
|
/// # /*
|
||||||
/// let map: Beatmap = ...
|
/// let map: Beatmap = ...
|
||||||
/// # */
|
/// # */
|
||||||
/// # let map = Beatmap::default();
|
/// # let map = Beatmap::default();
|
||||||
|
///
|
||||||
/// let pp_result = ManiaPP::new(&map)
|
/// let pp_result = ManiaPP::new(&map)
|
||||||
/// .mods(64) // DT
|
/// .mods(64) // DT
|
||||||
/// .score(765_432)
|
/// .score(765_432)
|
||||||
@@ -28,17 +30,18 @@ use crate::{Beatmap, DifficultyAttributes, Mods, PerformanceAttributes};
|
|||||||
/// ```
|
/// ```
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
#[allow(clippy::upper_case_acronyms)]
|
#[allow(clippy::upper_case_acronyms)]
|
||||||
pub struct ManiaPP<'m> {
|
pub struct ManiaPP<'map> {
|
||||||
map: &'m Beatmap,
|
map: &'map Beatmap,
|
||||||
stars: Option<f64>,
|
stars: Option<f64>,
|
||||||
mods: u32,
|
mods: u32,
|
||||||
score: Option<f64>,
|
score: Option<f64>,
|
||||||
passed_objects: Option<usize>,
|
passed_objects: Option<usize>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'m> ManiaPP<'m> {
|
impl<'map> ManiaPP<'map> {
|
||||||
|
/// Create a new performance calculator for osu!mania maps.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn new(map: &'m Beatmap) -> Self {
|
pub fn new(map: &'map Beatmap) -> Self {
|
||||||
Self {
|
Self {
|
||||||
map,
|
map,
|
||||||
stars: None,
|
stars: None,
|
||||||
@@ -48,7 +51,7 @@ impl<'m> ManiaPP<'m> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Provide the result of previous a difficulty or performance calculation.
|
/// Provide the result of previous difficulty or performance calculation.
|
||||||
/// If you already calculated the attributes for the current map-mod combination,
|
/// If you already calculated the attributes for the current map-mod combination,
|
||||||
/// be sure to put them in here so that they don't have to be recalculated.
|
/// be sure to put them in here so that they don't have to be recalculated.
|
||||||
#[inline]
|
#[inline]
|
||||||
@@ -169,6 +172,7 @@ impl<'m> ManiaPP<'m> {
|
|||||||
|
|
||||||
/// Abstract type to provide flexibility when passing difficulty attributes to a performance calculation.
|
/// Abstract type to provide flexibility when passing difficulty attributes to a performance calculation.
|
||||||
pub trait ManiaAttributeProvider {
|
pub trait ManiaAttributeProvider {
|
||||||
|
/// Provide the star rating (only difficulty attribute for osu!mania).
|
||||||
fn attributes(self) -> Option<f64>;
|
fn attributes(self) -> Option<f64>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ macro_rules! impl_mods {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Abstract type to define mods.
|
/// Abstract type to define mods.
|
||||||
|
#[allow(missing_docs)]
|
||||||
pub trait Mods: Copy {
|
pub trait Mods: Copy {
|
||||||
const NF: u32 = 1 << 0;
|
const NF: u32 = 1 << 0;
|
||||||
const EZ: u32 = 1 << 1;
|
const EZ: u32 = 1 << 1;
|
||||||
@@ -20,9 +21,13 @@ pub trait Mods: Copy {
|
|||||||
const FL: u32 = 1 << 10;
|
const FL: u32 = 1 << 10;
|
||||||
const SO: u32 = 1 << 12;
|
const SO: u32 = 1 << 12;
|
||||||
|
|
||||||
|
/// If the clock rate is affected by the mods.
|
||||||
fn change_speed(self) -> bool;
|
fn change_speed(self) -> bool;
|
||||||
|
/// If object time's or positions are affected by the mods.
|
||||||
fn change_map(self) -> bool;
|
fn change_map(self) -> bool;
|
||||||
|
/// The clock rate with the mods.
|
||||||
fn speed(self) -> f64;
|
fn speed(self) -> f64;
|
||||||
|
/// Multiplier for beatmap attributes with respect to the mods.
|
||||||
fn od_ar_hp_multiplier(self) -> f64;
|
fn od_ar_hp_multiplier(self) -> f64;
|
||||||
fn nf(self) -> bool;
|
fn nf(self) -> bool;
|
||||||
fn ez(self) -> bool;
|
fn ez(self) -> bool;
|
||||||
|
|||||||
+22
-4
@@ -548,29 +548,47 @@ fn lerp(start: f64, end: f64, percent: f64) -> f64 {
|
|||||||
/// The result of a difficulty calculation on an osu!standard map.
|
/// The result of a difficulty calculation on an osu!standard map.
|
||||||
#[derive(Clone, Debug, Default)]
|
#[derive(Clone, Debug, Default)]
|
||||||
pub struct OsuDifficultyAttributes {
|
pub struct OsuDifficultyAttributes {
|
||||||
|
/// The aim portion of the total strain.
|
||||||
pub aim_strain: f64,
|
pub aim_strain: f64,
|
||||||
|
/// The speed portion of the total strain.
|
||||||
pub speed_strain: f64,
|
pub speed_strain: f64,
|
||||||
|
/// The flashlight portion of the total strain.
|
||||||
pub flashlight_rating: f64,
|
pub flashlight_rating: f64,
|
||||||
|
/// The ratio of the aim strain with and without considering sliders
|
||||||
pub slider_factor: f64,
|
pub slider_factor: f64,
|
||||||
|
/// The approach rate.
|
||||||
pub ar: f64,
|
pub ar: f64,
|
||||||
|
/// The overall difficulty
|
||||||
pub od: f64,
|
pub od: f64,
|
||||||
|
/// The health drain rate.
|
||||||
pub hp: f64,
|
pub hp: f64,
|
||||||
|
/// The amount of circles.
|
||||||
pub n_circles: usize,
|
pub n_circles: usize,
|
||||||
|
/// The amount of sliders.
|
||||||
pub n_sliders: usize,
|
pub n_sliders: usize,
|
||||||
|
/// The amount of spinners.
|
||||||
pub n_spinners: usize,
|
pub n_spinners: usize,
|
||||||
|
/// The final star rating
|
||||||
pub stars: f64,
|
pub stars: f64,
|
||||||
|
/// The maximum combo.
|
||||||
pub max_combo: usize,
|
pub max_combo: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The result of a performance calculation on an osu!standard map.
|
/// The result of a performance calculation on an osu!standard map.
|
||||||
#[derive(Clone, Debug, Default)]
|
#[derive(Clone, Debug, Default)]
|
||||||
pub struct OsuPerformanceAttributes {
|
pub struct OsuPerformanceAttributes {
|
||||||
|
/// The difficulty attributes that were used for the performance calculation
|
||||||
pub attributes: OsuDifficultyAttributes,
|
pub attributes: OsuDifficultyAttributes,
|
||||||
pub pp_acc: f64,
|
/// The final performance points.
|
||||||
pub pp_aim: f64,
|
|
||||||
pub pp_flashlight: f64,
|
|
||||||
pub pp_speed: f64,
|
|
||||||
pub pp: f64,
|
pub pp: f64,
|
||||||
|
/// The accuracy portion of the final pp.
|
||||||
|
pub pp_acc: f64,
|
||||||
|
/// The aim portion of the final pp.
|
||||||
|
pub pp_aim: f64,
|
||||||
|
/// The flashlight portion of the final pp.
|
||||||
|
pub pp_flashlight: f64,
|
||||||
|
/// The speed portion of the final pp.
|
||||||
|
pub pp_speed: f64,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl OsuPerformanceAttributes {
|
impl OsuPerformanceAttributes {
|
||||||
|
|||||||
+10
-6
@@ -6,11 +6,13 @@ use crate::{Beatmap, DifficultyAttributes, Mods, PerformanceAttributes};
|
|||||||
/// # Example
|
/// # Example
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # use rosu_pp::{OsuPP, PpResult, Beatmap};
|
/// use rosu_pp::{OsuPP, Beatmap};
|
||||||
|
///
|
||||||
/// # /*
|
/// # /*
|
||||||
/// let map: Beatmap = ...
|
/// let map: Beatmap = ...
|
||||||
/// # */
|
/// # */
|
||||||
/// # let map = Beatmap::default();
|
/// # let map = Beatmap::default();
|
||||||
|
///
|
||||||
/// let pp_result = OsuPP::new(&map)
|
/// let pp_result = OsuPP::new(&map)
|
||||||
/// .mods(8 + 64) // HDDT
|
/// .mods(8 + 64) // HDDT
|
||||||
/// .combo(1234)
|
/// .combo(1234)
|
||||||
@@ -30,8 +32,8 @@ use crate::{Beatmap, DifficultyAttributes, Mods, PerformanceAttributes};
|
|||||||
/// ```
|
/// ```
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
#[allow(clippy::upper_case_acronyms)]
|
#[allow(clippy::upper_case_acronyms)]
|
||||||
pub struct OsuPP<'m> {
|
pub struct OsuPP<'map> {
|
||||||
map: &'m Beatmap,
|
map: &'map Beatmap,
|
||||||
attributes: Option<OsuDifficultyAttributes>,
|
attributes: Option<OsuDifficultyAttributes>,
|
||||||
mods: u32,
|
mods: u32,
|
||||||
combo: Option<usize>,
|
combo: Option<usize>,
|
||||||
@@ -44,9 +46,10 @@ pub struct OsuPP<'m> {
|
|||||||
passed_objects: Option<usize>,
|
passed_objects: Option<usize>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'m> OsuPP<'m> {
|
impl<'map> OsuPP<'map> {
|
||||||
|
/// Create a new performance calculator for osu!standard maps.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn new(map: &'m Beatmap) -> Self {
|
pub fn new(map: &'map Beatmap) -> Self {
|
||||||
Self {
|
Self {
|
||||||
map,
|
map,
|
||||||
attributes: None,
|
attributes: None,
|
||||||
@@ -62,7 +65,7 @@ impl<'m> OsuPP<'m> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Provide the result of previous a difficulty or performance calculation.
|
/// Provide the result of previous difficulty or performance calculation.
|
||||||
/// If you already calculated the attributes for the current map-mod combination,
|
/// If you already calculated the attributes for the current map-mod combination,
|
||||||
/// be sure to put them in here so that they don't have to be recalculated.
|
/// be sure to put them in here so that they don't have to be recalculated.
|
||||||
#[inline]
|
#[inline]
|
||||||
@@ -590,6 +593,7 @@ fn calculate_effective_misses(
|
|||||||
|
|
||||||
/// Abstract type to provide flexibility when passing difficulty attributes to a performance calculation.
|
/// Abstract type to provide flexibility when passing difficulty attributes to a performance calculation.
|
||||||
pub trait OsuAttributeProvider {
|
pub trait OsuAttributeProvider {
|
||||||
|
/// Provide the actual difficulty attributes.
|
||||||
fn attributes(self) -> Option<OsuDifficultyAttributes>;
|
fn attributes(self) -> Option<OsuDifficultyAttributes>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,10 +3,15 @@ use crate::Mods;
|
|||||||
/// Summary struct for a [`Beatmap`](crate::Beatmap)'s attributes.
|
/// Summary struct for a [`Beatmap`](crate::Beatmap)'s attributes.
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct BeatmapAttributes {
|
pub struct BeatmapAttributes {
|
||||||
|
/// The approach rate.
|
||||||
pub ar: f64,
|
pub ar: f64,
|
||||||
|
/// The overall difficulty.
|
||||||
pub od: f64,
|
pub od: f64,
|
||||||
|
/// The circle size.
|
||||||
pub cs: f64,
|
pub cs: f64,
|
||||||
|
/// The health drain rate
|
||||||
pub hp: f64,
|
pub hp: f64,
|
||||||
|
/// The clock rate with respect to mods.
|
||||||
pub clock_rate: f64,
|
pub clock_rate: f64,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,9 @@ use std::cmp::Ordering;
|
|||||||
/// New rhythm speed change.
|
/// New rhythm speed change.
|
||||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||||
pub struct TimingPoint {
|
pub struct TimingPoint {
|
||||||
|
/// The beat length for this timing section
|
||||||
pub beat_len: f64,
|
pub beat_len: f64,
|
||||||
|
/// The start time of this timing section
|
||||||
pub time: f64,
|
pub time: f64,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -16,7 +18,9 @@ impl PartialOrd for TimingPoint {
|
|||||||
/// [`TimingPoint`](crate::parse::TimingPoint) that depends on a previous one.
|
/// [`TimingPoint`](crate::parse::TimingPoint) that depends on a previous one.
|
||||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||||
pub struct DifficultyPoint {
|
pub struct DifficultyPoint {
|
||||||
|
/// The start time for the current speed multiplier
|
||||||
pub time: f64,
|
pub time: f64,
|
||||||
|
/// The speed multiplier until the next timing point
|
||||||
pub speed_multiplier: f64,
|
pub speed_multiplier: f64,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -20,17 +20,29 @@ pub type ParseResult<T> = Result<T, ParseError>;
|
|||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
#[allow(clippy::upper_case_acronyms)]
|
#[allow(clippy::upper_case_acronyms)]
|
||||||
pub enum ParseError {
|
pub enum ParseError {
|
||||||
|
/// Some IO operation failed.
|
||||||
IOError(IOError),
|
IOError(IOError),
|
||||||
|
/// The initial data of an `.osu` file was incorrect.
|
||||||
IncorrectFileHeader,
|
IncorrectFileHeader,
|
||||||
|
/// Line in `.osu` was unexpectedly not of the form `key:value`.
|
||||||
BadLine,
|
BadLine,
|
||||||
|
/// Line in `.osu` that contains a slider was not in the proper format.
|
||||||
InvalidCurvePoints,
|
InvalidCurvePoints,
|
||||||
|
/// Expected an integer, got something else.
|
||||||
InvalidInteger,
|
InvalidInteger,
|
||||||
|
/// Expected a decimal number, got something else.
|
||||||
InvalidFloatingPoint,
|
InvalidFloatingPoint,
|
||||||
|
/// Failed to parse game mode.
|
||||||
InvalidMode,
|
InvalidMode,
|
||||||
|
/// Failed to parse the path type of a slider.
|
||||||
InvalidPathType,
|
InvalidPathType,
|
||||||
|
/// Failed to parse timing point.
|
||||||
InvalidTimingSignature,
|
InvalidTimingSignature,
|
||||||
|
/// Expected an additional field.
|
||||||
MissingField(&'static str),
|
MissingField(&'static str),
|
||||||
|
/// Reject maps with too many repeat points.
|
||||||
TooManyRepeats,
|
TooManyRepeats,
|
||||||
|
/// Failed to recognized specified type for hitobjects.
|
||||||
UnknownHitObjectKind,
|
UnknownHitObjectKind,
|
||||||
|
|
||||||
#[cfg(not(all(
|
#[cfg(not(all(
|
||||||
@@ -39,6 +51,7 @@ pub enum ParseError {
|
|||||||
feature = "fruits",
|
feature = "fruits",
|
||||||
feature = "mania"
|
feature = "mania"
|
||||||
)))]
|
)))]
|
||||||
|
/// Tried to parse a map with a game mode who's feature was not enabled
|
||||||
UnincludedMode(GameMode),
|
UnincludedMode(GameMode),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,13 +6,18 @@ use std::cmp::Ordering;
|
|||||||
/// Each mode will handle them differently.
|
/// Each mode will handle them differently.
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
pub struct HitObject {
|
pub struct HitObject {
|
||||||
|
/// The position of the object.
|
||||||
pub pos: Pos2,
|
pub pos: Pos2,
|
||||||
|
/// The start time of the object.
|
||||||
pub start_time: f64,
|
pub start_time: f64,
|
||||||
|
/// The type of the object.
|
||||||
pub kind: HitObjectKind,
|
pub kind: HitObjectKind,
|
||||||
|
/// The hitsound of the object. Used as color in osu!taiko.
|
||||||
pub sound: u8,
|
pub sound: u8,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl HitObject {
|
impl HitObject {
|
||||||
|
/// The end time of the object.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn end_time(&self) -> f64 {
|
pub fn end_time(&self) -> f64 {
|
||||||
match &self.kind {
|
match &self.kind {
|
||||||
@@ -24,16 +29,19 @@ impl HitObject {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// If the object is a circle.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn is_circle(&self) -> bool {
|
pub fn is_circle(&self) -> bool {
|
||||||
matches!(self.kind, HitObjectKind::Circle { .. })
|
matches!(self.kind, HitObjectKind::Circle { .. })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// If the object is a slider.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn is_slider(&self) -> bool {
|
pub fn is_slider(&self) -> bool {
|
||||||
matches!(self.kind, HitObjectKind::Slider { .. })
|
matches!(self.kind, HitObjectKind::Slider { .. })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// If the object is a spinner.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn is_spinner(&self) -> bool {
|
pub fn is_spinner(&self) -> bool {
|
||||||
matches!(self.kind, HitObjectKind::Spinner { .. })
|
matches!(self.kind, HitObjectKind::Spinner { .. })
|
||||||
@@ -41,6 +49,7 @@ impl HitObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl PartialOrd for HitObject {
|
impl PartialOrd for HitObject {
|
||||||
|
#[inline]
|
||||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||||
self.start_time.partial_cmp(&other.start_time)
|
self.start_time.partial_cmp(&other.start_time)
|
||||||
}
|
}
|
||||||
@@ -49,23 +58,36 @@ impl PartialOrd for HitObject {
|
|||||||
/// Further data related to specific object types.
|
/// Further data related to specific object types.
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
pub enum HitObjectKind {
|
pub enum HitObjectKind {
|
||||||
|
/// A circle object.
|
||||||
Circle,
|
Circle,
|
||||||
#[cfg(feature = "sliders")]
|
#[cfg(feature = "sliders")]
|
||||||
|
/// A full slider object.
|
||||||
Slider {
|
Slider {
|
||||||
|
/// Total length of the slider in pixels.
|
||||||
pixel_len: f64,
|
pixel_len: f64,
|
||||||
|
/// The amount of repeat points of the slider.
|
||||||
repeats: usize,
|
repeats: usize,
|
||||||
|
/// The control points of the slider.
|
||||||
control_points: Vec<super::PathControlPoint>,
|
control_points: Vec<super::PathControlPoint>,
|
||||||
},
|
},
|
||||||
#[cfg(not(feature = "sliders"))]
|
#[cfg(not(feature = "sliders"))]
|
||||||
|
/// A partial slider object.
|
||||||
Slider {
|
Slider {
|
||||||
|
/// Total length of the slider in pixels.
|
||||||
pixel_len: f64,
|
pixel_len: f64,
|
||||||
|
/// The amount of spans of the slider.
|
||||||
span_count: usize,
|
span_count: usize,
|
||||||
|
/// The position of the last control point.
|
||||||
last_control_point: Pos2,
|
last_control_point: Pos2,
|
||||||
},
|
},
|
||||||
|
/// A spinner object.
|
||||||
Spinner {
|
Spinner {
|
||||||
|
/// The end time of the spinner.
|
||||||
end_time: f64,
|
end_time: f64,
|
||||||
},
|
},
|
||||||
|
/// A hold note object for osu!mania.
|
||||||
Hold {
|
Hold {
|
||||||
|
/// The end time of the hold object.
|
||||||
end_time: f64,
|
end_time: f64,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
/// Abstract type to define hitsounds.
|
||||||
|
#[allow(missing_docs)]
|
||||||
pub trait HitSound {
|
pub trait HitSound {
|
||||||
const HITSOUND_WHISTLE: u8 = 1 << 1;
|
const HITSOUND_WHISTLE: u8 = 1 << 1;
|
||||||
const HITSOUND_FINISH: u8 = 1 << 2;
|
const HITSOUND_FINISH: u8 = 1 << 2;
|
||||||
|
|||||||
@@ -751,9 +751,13 @@ macro_rules! from_path {
|
|||||||
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
|
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
|
||||||
#[allow(clippy::upper_case_acronyms)]
|
#[allow(clippy::upper_case_acronyms)]
|
||||||
pub enum GameMode {
|
pub enum GameMode {
|
||||||
|
/// osu!standard
|
||||||
STD = 0,
|
STD = 0,
|
||||||
|
/// osu!taiko
|
||||||
TKO = 1,
|
TKO = 1,
|
||||||
|
/// osu!ctb
|
||||||
CTB = 2,
|
CTB = 2,
|
||||||
|
/// osu!mania
|
||||||
MNA = 3,
|
MNA = 3,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -768,28 +772,44 @@ impl Default for GameMode {
|
|||||||
/// for difficulty and pp calculation
|
/// for difficulty and pp calculation
|
||||||
#[derive(Clone, Default, Debug)]
|
#[derive(Clone, Default, Debug)]
|
||||||
pub struct Beatmap {
|
pub struct Beatmap {
|
||||||
|
/// The game mode.
|
||||||
pub mode: GameMode,
|
pub mode: GameMode,
|
||||||
|
/// The version of the .osu file.
|
||||||
pub version: u8,
|
pub version: u8,
|
||||||
|
|
||||||
|
/// The amount of circles.
|
||||||
pub n_circles: u32,
|
pub n_circles: u32,
|
||||||
|
/// The amount of sliders.
|
||||||
pub n_sliders: u32,
|
pub n_sliders: u32,
|
||||||
|
/// The amount of spinners.
|
||||||
pub n_spinners: u32,
|
pub n_spinners: u32,
|
||||||
|
|
||||||
|
/// The approach rate.
|
||||||
pub ar: f32,
|
pub ar: f32,
|
||||||
|
/// The overall difficulty.
|
||||||
pub od: f32,
|
pub od: f32,
|
||||||
|
/// The circle size.
|
||||||
pub cs: f32,
|
pub cs: f32,
|
||||||
|
/// The health drain rate.
|
||||||
pub hp: f32,
|
pub hp: f32,
|
||||||
|
/// Base slider velocity in pixels per beat
|
||||||
pub slider_mult: f64,
|
pub slider_mult: f64,
|
||||||
|
/// Amount of slider ticks per beat.
|
||||||
pub tick_rate: f64,
|
pub tick_rate: f64,
|
||||||
|
/// All hitobjects of the beatmap.
|
||||||
pub hit_objects: Vec<HitObject>,
|
pub hit_objects: Vec<HitObject>,
|
||||||
|
|
||||||
#[cfg(any(feature = "osu", feature = "fruits"))]
|
#[cfg(any(feature = "osu", feature = "fruits"))]
|
||||||
|
/// Timing points that indicate a new timing section.
|
||||||
pub timing_points: Vec<TimingPoint>,
|
pub timing_points: Vec<TimingPoint>,
|
||||||
|
|
||||||
#[cfg(any(feature = "osu", feature = "fruits"))]
|
#[cfg(any(feature = "osu", feature = "fruits"))]
|
||||||
|
/// Timing point for the current timing section.
|
||||||
pub difficulty_points: Vec<DifficultyPoint>,
|
pub difficulty_points: Vec<DifficultyPoint>,
|
||||||
|
|
||||||
#[cfg(feature = "osu")]
|
#[cfg(feature = "osu")]
|
||||||
|
/// The stack leniency that is used to calculate
|
||||||
|
/// the stack offset for stacked positions.
|
||||||
pub stack_leniency: f32,
|
pub stack_leniency: f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -803,6 +823,7 @@ impl Beatmap {
|
|||||||
// const COMBO_OFFSET_FLAG: u8 = (1 << 4) | (1 << 5) | (1 << 6);
|
// const COMBO_OFFSET_FLAG: u8 = (1 << 4) | (1 << 5) | (1 << 6);
|
||||||
const HOLD_FLAG: u8 = 1 << 7;
|
const HOLD_FLAG: u8 = 1 << 7;
|
||||||
|
|
||||||
|
/// Extract a beatmap's attributes into their own type.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn attributes(&self) -> BeatmapAttributes {
|
pub fn attributes(&self) -> BeatmapAttributes {
|
||||||
BeatmapAttributes::new(self.ar, self.od, self.cs, self.hp)
|
BeatmapAttributes::new(self.ar, self.od, self.cs, self.hp)
|
||||||
@@ -922,7 +943,10 @@ mod osu_fruits {
|
|||||||
/// Control point for slider curve calculation
|
/// Control point for slider curve calculation
|
||||||
#[derive(Copy, Clone, Debug, Default, PartialEq)]
|
#[derive(Copy, Clone, Debug, Default, PartialEq)]
|
||||||
pub struct PathControlPoint {
|
pub struct PathControlPoint {
|
||||||
|
/// Control point position.
|
||||||
pub pos: Pos2,
|
pub pos: Pos2,
|
||||||
|
/// Path type of the control point.
|
||||||
|
/// Only present for the first element of each segment.
|
||||||
pub kind: Option<PathType>,
|
pub kind: Option<PathType>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -934,6 +958,7 @@ mod osu_fruits {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// The type of curve of a slider.
|
/// The type of curve of a slider.
|
||||||
|
#[allow(missing_docs)]
|
||||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||||
pub enum PathType {
|
pub enum PathType {
|
||||||
Catmull = 0,
|
Catmull = 0,
|
||||||
|
|||||||
@@ -4,41 +4,50 @@ use std::ops;
|
|||||||
/// Simple (x, y) coordinate / vector
|
/// Simple (x, y) coordinate / vector
|
||||||
#[derive(Clone, Copy, Default, PartialEq)]
|
#[derive(Clone, Copy, Default, PartialEq)]
|
||||||
pub struct Pos2 {
|
pub struct Pos2 {
|
||||||
|
/// Position on the x-axis.
|
||||||
pub x: f32,
|
pub x: f32,
|
||||||
|
/// Position on the y-axis.
|
||||||
pub y: f32,
|
pub y: f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Pos2 {
|
impl Pos2 {
|
||||||
|
/// Return the null vector.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn zero() -> Self {
|
pub fn zero() -> Self {
|
||||||
Self::default()
|
Self::default()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Return a position with both coordinates on the given value.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn new(value: f32) -> Self {
|
pub fn new(value: f32) -> Self {
|
||||||
Self { x: value, y: value }
|
Self { x: value, y: value }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Return the position's length squared.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn length_squared(&self) -> f32 {
|
pub fn length_squared(&self) -> f32 {
|
||||||
self.dot(*self)
|
self.dot(*self)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Return the position's length.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn length(&self) -> f32 {
|
pub fn length(&self) -> f32 {
|
||||||
self.x.hypot(self.y)
|
self.x.hypot(self.y)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Return the dot product.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn dot(&self, other: Self) -> f32 {
|
pub fn dot(&self, other: Self) -> f32 {
|
||||||
self.x.mul_add(other.x, self.y * other.y)
|
self.x.mul_add(other.x, self.y * other.y)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Return the distance to another position.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn distance(&self, other: Self) -> f32 {
|
pub fn distance(&self, other: Self) -> f32 {
|
||||||
(*self - other).length()
|
(*self - other).length()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Normalize the coordinates with respect to the vector's length.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn normalize(self) -> Pos2 {
|
pub fn normalize(self) -> Pos2 {
|
||||||
self / self.length()
|
self / self.length()
|
||||||
|
|||||||
@@ -17,21 +17,55 @@ use crate::OsuPP;
|
|||||||
use crate::TaikoPP;
|
use crate::TaikoPP;
|
||||||
|
|
||||||
/// Performance calculator on maps of any mode.
|
/// Performance calculator on maps of any mode.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use rosu_pp::{AnyPP, Beatmap};
|
||||||
|
///
|
||||||
|
/// # /*
|
||||||
|
/// let map: Beatmap = ...
|
||||||
|
/// # */
|
||||||
|
///
|
||||||
|
/// # let map = Beatmap::default();
|
||||||
|
/// let pp_result = AnyPP::new(&map)
|
||||||
|
/// .mods(8 + 64) // HDDT
|
||||||
|
/// .combo(1234)
|
||||||
|
/// .misses(1)
|
||||||
|
/// .accuracy(98.5) // should be set last
|
||||||
|
/// .calculate();
|
||||||
|
///
|
||||||
|
/// println!("PP: {} | Stars: {}", pp_result.pp(), pp_result.stars());
|
||||||
|
///
|
||||||
|
/// let next_result = AnyPP::new(&map)
|
||||||
|
/// .attributes(pp_result) // reusing previous results for performance
|
||||||
|
/// .mods(8 + 64) // has to be the same to reuse attributes
|
||||||
|
/// .accuracy(99.5)
|
||||||
|
/// .calculate();
|
||||||
|
///
|
||||||
|
/// println!("PP: {} | Stars: {}", next_result.pp(), next_result.stars());
|
||||||
|
/// ```
|
||||||
#[allow(clippy::upper_case_acronyms)]
|
#[allow(clippy::upper_case_acronyms)]
|
||||||
pub enum AnyPP<'m> {
|
#[derive(Clone, Debug)]
|
||||||
|
pub enum AnyPP<'map> {
|
||||||
#[cfg(feature = "fruits")]
|
#[cfg(feature = "fruits")]
|
||||||
Fruits(FruitsPP<'m>),
|
/// osu!ctb performance calculator
|
||||||
|
Fruits(FruitsPP<'map>),
|
||||||
#[cfg(feature = "mania")]
|
#[cfg(feature = "mania")]
|
||||||
Mania(ManiaPP<'m>),
|
/// osu!mania performance calculator
|
||||||
|
Mania(ManiaPP<'map>),
|
||||||
#[cfg(feature = "osu")]
|
#[cfg(feature = "osu")]
|
||||||
Osu(OsuPP<'m>),
|
/// osu!standard performance calculator
|
||||||
|
Osu(OsuPP<'map>),
|
||||||
#[cfg(feature = "taiko")]
|
#[cfg(feature = "taiko")]
|
||||||
Taiko(TaikoPP<'m>),
|
/// osu!taiko performance calculator
|
||||||
|
Taiko(TaikoPP<'map>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'m> AnyPP<'m> {
|
impl<'map> AnyPP<'map> {
|
||||||
|
/// Create a new performance calculator for maps of any mode.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn new(map: &'m Beatmap) -> Self {
|
pub fn new(map: &'map Beatmap) -> Self {
|
||||||
match map.mode {
|
match map.mode {
|
||||||
#[cfg(feature = "fruits")]
|
#[cfg(feature = "fruits")]
|
||||||
GameMode::CTB => Self::Fruits(FruitsPP::new(map)),
|
GameMode::CTB => Self::Fruits(FruitsPP::new(map)),
|
||||||
@@ -46,6 +80,8 @@ impl<'m> AnyPP<'m> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Consume the performance calculator and calculate
|
||||||
|
/// performance attributes for the given parameters.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn calculate(self) -> PerformanceAttributes {
|
pub fn calculate(self) -> PerformanceAttributes {
|
||||||
match self {
|
match self {
|
||||||
@@ -60,7 +96,7 @@ impl<'m> AnyPP<'m> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Provide the result of previous a difficulty or performance calculation.
|
/// Provide the result of previous difficulty or performance calculation.
|
||||||
/// If you already calculated the attributes for the current map-mod combination,
|
/// If you already calculated the attributes for the current map-mod combination,
|
||||||
/// be sure to put them in here so that they don't have to be recalculated.
|
/// be sure to put them in here so that they don't have to be recalculated.
|
||||||
#[inline]
|
#[inline]
|
||||||
@@ -262,6 +298,7 @@ impl<'m> AnyPP<'m> {
|
|||||||
|
|
||||||
/// Abstract type to provide flexibility when passing difficulty attributes to a performance calculation.
|
/// Abstract type to provide flexibility when passing difficulty attributes to a performance calculation.
|
||||||
pub trait AttributeProvider {
|
pub trait AttributeProvider {
|
||||||
|
/// Provide the actual difficulty attributes.
|
||||||
fn attributes(self) -> DifficultyAttributes;
|
fn attributes(self) -> DifficultyAttributes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -266,15 +266,20 @@ fn norm(p: f64, a: f64, b: f64, c: f64) -> f64 {
|
|||||||
/// The result of a difficulty calculation on an osu!taiko map.
|
/// The result of a difficulty calculation on an osu!taiko map.
|
||||||
#[derive(Copy, Clone, Debug, Default)]
|
#[derive(Copy, Clone, Debug, Default)]
|
||||||
pub struct TaikoDifficultyAttributes {
|
pub struct TaikoDifficultyAttributes {
|
||||||
|
/// The final star rating.
|
||||||
pub stars: f64,
|
pub stars: f64,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The result of a performance calculation on an osu!taiko map.
|
/// The result of a performance calculation on an osu!taiko map.
|
||||||
#[derive(Copy, Clone, Debug, Default)]
|
#[derive(Copy, Clone, Debug, Default)]
|
||||||
pub struct TaikoPerformanceAttributes {
|
pub struct TaikoPerformanceAttributes {
|
||||||
|
/// The difficulty attributes that were used for the performance calculation
|
||||||
pub attributes: TaikoDifficultyAttributes,
|
pub attributes: TaikoDifficultyAttributes,
|
||||||
|
/// The final performance points.
|
||||||
pub pp: f64,
|
pub pp: f64,
|
||||||
|
/// The accuracy portion of the final pp.
|
||||||
pub pp_acc: f64,
|
pub pp_acc: f64,
|
||||||
|
/// The strain portion of the final pp.
|
||||||
pub pp_strain: f64,
|
pub pp_strain: f64,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+12
-8
@@ -6,11 +6,13 @@ use crate::{Beatmap, DifficultyAttributes, Mods, PerformanceAttributes};
|
|||||||
/// # Example
|
/// # Example
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # use rosu_pp::{TaikoPP, PpResult, Beatmap};
|
/// use rosu_pp::{TaikoPP, Beatmap};
|
||||||
|
///
|
||||||
/// # /*
|
/// # /*
|
||||||
/// let map: Beatmap = ...
|
/// let map: Beatmap = ...
|
||||||
/// # */
|
/// # */
|
||||||
/// # let map = Beatmap::default();
|
/// # let map = Beatmap::default();
|
||||||
|
///
|
||||||
/// let pp_result = TaikoPP::new(&map)
|
/// let pp_result = TaikoPP::new(&map)
|
||||||
/// .mods(8 + 64) // HDDT
|
/// .mods(8 + 64) // HDDT
|
||||||
/// .combo(1234)
|
/// .combo(1234)
|
||||||
@@ -30,8 +32,8 @@ use crate::{Beatmap, DifficultyAttributes, Mods, PerformanceAttributes};
|
|||||||
/// ```
|
/// ```
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
#[allow(clippy::upper_case_acronyms)]
|
#[allow(clippy::upper_case_acronyms)]
|
||||||
pub struct TaikoPP<'m> {
|
pub struct TaikoPP<'map> {
|
||||||
map: &'m Beatmap,
|
map: &'map Beatmap,
|
||||||
stars: Option<f64>,
|
stars: Option<f64>,
|
||||||
mods: u32,
|
mods: u32,
|
||||||
max_combo: usize,
|
max_combo: usize,
|
||||||
@@ -44,9 +46,10 @@ pub struct TaikoPP<'m> {
|
|||||||
n100: Option<usize>,
|
n100: Option<usize>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'m> TaikoPP<'m> {
|
impl<'map> TaikoPP<'map> {
|
||||||
|
/// Create a new performance calculator for osu!taiko maps.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn new(map: &'m Beatmap) -> Self {
|
pub fn new(map: &'map Beatmap) -> Self {
|
||||||
Self {
|
Self {
|
||||||
map,
|
map,
|
||||||
stars: None,
|
stars: None,
|
||||||
@@ -172,8 +175,8 @@ impl<'m> TaikoPP<'m> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct TaikoPPInner<'m> {
|
struct TaikoPPInner<'map> {
|
||||||
map: &'m Beatmap,
|
map: &'map Beatmap,
|
||||||
stars: f64,
|
stars: f64,
|
||||||
mods: u32,
|
mods: u32,
|
||||||
max_combo: usize,
|
max_combo: usize,
|
||||||
@@ -181,7 +184,7 @@ struct TaikoPPInner<'m> {
|
|||||||
n_misses: usize,
|
n_misses: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'m> TaikoPPInner<'m> {
|
impl<'map> TaikoPPInner<'map> {
|
||||||
fn calculate(self) -> TaikoPerformanceAttributes {
|
fn calculate(self) -> TaikoPerformanceAttributes {
|
||||||
let mut multiplier = 1.1;
|
let mut multiplier = 1.1;
|
||||||
|
|
||||||
@@ -257,6 +260,7 @@ fn difficulty_range_od(od: f64) -> f64 {
|
|||||||
|
|
||||||
/// Abstract type to provide flexibility when passing difficulty attributes to a performance calculation.
|
/// Abstract type to provide flexibility when passing difficulty attributes to a performance calculation.
|
||||||
pub trait TaikoAttributeProvider {
|
pub trait TaikoAttributeProvider {
|
||||||
|
/// Provide the star rating (only difficulty attribute for osu!taiko).
|
||||||
fn attributes(self) -> Option<f64>;
|
fn attributes(self) -> Option<f64>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user