added method Beatmap::from_path
This commit is contained in:
+3
-3
@@ -1,6 +1,6 @@
|
|||||||
## Upcoming
|
## Upcoming
|
||||||
|
|
||||||
- Nothing as of now
|
- Added method `Beatmap::from_path` so the file does not have to be created manually for `Beatmap::parse`
|
||||||
|
|
||||||
# v0.3.0
|
# v0.3.0
|
||||||
|
|
||||||
@@ -9,8 +9,8 @@
|
|||||||
- [BREAKING] Instead of returning `PpResult`, performance calculations now return `{Mode}PerformanceAttributes` and `PpResult` has been renamed to `PerformanceAttributes`.
|
- [BREAKING] Instead of returning `PpResult`, performance calculations now return `{Mode}PerformanceAttributes` and `PpResult` has been renamed to `PerformanceAttributes`.
|
||||||
- [BREAKING] Instead of returning `StarResult`, difficulty calculations now return `{Mode}DifficultyAttributes` and `StarResult` has been renamed to `DifficultyAttributes`.
|
- [BREAKING] Instead of returning `StarResult`, difficulty calculations now return `{Mode}DifficultyAttributes` and `StarResult` has been renamed to `DifficultyAttributes`.
|
||||||
- [BREAKING] Various fields and methods now include `f64` instead of `f32` to stay true to osu!'s original code
|
- [BREAKING] Various fields and methods now include `f64` instead of `f32` to stay true to osu!'s original code
|
||||||
- added internal binary crate `pp-gen` to calculate difficulty & pp values via `PerformanceCalculator.dll`
|
- Added internal binary crate `pp-gen` to calculate difficulty & pp values via `PerformanceCalculator.dll`
|
||||||
- added internal binary crate `pp-plot` to plot out differences between `pp-gen`'s output and `rosu-pp` values
|
- Added internal binary crate `pp-plot` to plot out differences between `pp-gen`'s output and `rosu-pp` values
|
||||||
- osu: Updated up to commit [9fb2402781ad91c197d51aeec716b0000f52c4d1](https://github.com/ppy/osu/commit/9fb2402781ad91c197d51aeec716b0000f52c4d1) (2021-11-12)
|
- osu: Updated up to commit [9fb2402781ad91c197d51aeec716b0000f52c4d1](https://github.com/ppy/osu/commit/9fb2402781ad91c197d51aeec716b0000f52c4d1) (2021-11-12)
|
||||||
|
|
||||||
## v0.2.3
|
## v0.2.3
|
||||||
|
|||||||
@@ -11,16 +11,10 @@ Async is supported through features, see below.
|
|||||||
### Usage
|
### Usage
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
use std::fs::File;
|
|
||||||
use rosu_pp::{Beatmap, BeatmapExt};
|
use rosu_pp::{Beatmap, BeatmapExt};
|
||||||
|
|
||||||
let file = match File::open("/path/to/file.osu") {
|
|
||||||
Ok(file) => file,
|
|
||||||
Err(why) => panic!("Could not open file: {}", why),
|
|
||||||
};
|
|
||||||
|
|
||||||
// Parse the map yourself
|
// Parse the map yourself
|
||||||
let map = match Beatmap::parse(file) {
|
let map = match Beatmap::from_path("/path/to/file.osu") {
|
||||||
Ok(map) => map,
|
Ok(map) => map,
|
||||||
Err(why) => panic!("Error while parsing map: {}", why),
|
Err(why) => panic!("Error while parsing map: {}", why),
|
||||||
};
|
};
|
||||||
@@ -45,7 +39,6 @@ let next_result = map.pp()
|
|||||||
.combo(543)
|
.combo(543)
|
||||||
.misses(5)
|
.misses(5)
|
||||||
.n50(3)
|
.n50(3)
|
||||||
.passed_objects(600)
|
|
||||||
.accuracy(96.5)
|
.accuracy(96.5)
|
||||||
.calculate();
|
.calculate();
|
||||||
|
|
||||||
@@ -61,16 +54,8 @@ println!("Stars: {} | Max PP: {}", stars, max_pp);
|
|||||||
If either the `async_tokio` or `async_std` feature is enabled, beatmap parsing will be async.
|
If either the `async_tokio` or `async_std` feature is enabled, beatmap parsing will be async.
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
use async_std::fs::File;
|
|
||||||
// use tokio::fs::File;
|
|
||||||
|
|
||||||
let file = match File::open("/path/to/file.osu").await {
|
|
||||||
Ok(file) => file,
|
|
||||||
Err(why) => panic!("Could not open file: {}", why),
|
|
||||||
};
|
|
||||||
|
|
||||||
// Parse the map asynchronously
|
// Parse the map asynchronously
|
||||||
let map = match Beatmap::parse(file).await {
|
let map = match Beatmap::from_path("/path/to/file.osu").await {
|
||||||
Ok(map) => map,
|
Ok(map) => map,
|
||||||
Err(why) => panic!("Error while parsing map: {}", why),
|
Err(why) => panic!("Error while parsing map: {}", why),
|
||||||
};
|
};
|
||||||
|
|||||||
+2
-3
@@ -670,13 +670,12 @@ impl From<FruitsPerformanceAttributes> for FruitsDifficultyAttributes {
|
|||||||
#[test]
|
#[test]
|
||||||
// #[ignore]
|
// #[ignore]
|
||||||
fn custom_fruits() {
|
fn custom_fruits() {
|
||||||
use std::{fs::File, time::Instant};
|
use std::time::Instant;
|
||||||
|
|
||||||
use crate::{Beatmap, FruitsPP};
|
use crate::{Beatmap, FruitsPP};
|
||||||
|
|
||||||
let path = "E:Games/osu!/beatmaps/2919116_.osu";
|
let path = "E:Games/osu!/beatmaps/2919116_.osu";
|
||||||
let file = File::open(path).unwrap();
|
let map = Beatmap::from_path(path).unwrap();
|
||||||
let map = Beatmap::parse(file).unwrap();
|
|
||||||
|
|
||||||
let start = Instant::now();
|
let start = Instant::now();
|
||||||
let result = FruitsPP::new(&map).mods(256).calculate();
|
let result = FruitsPP::new(&map).mods(256).calculate();
|
||||||
|
|||||||
+2
-18
@@ -7,17 +7,11 @@
|
|||||||
//! ## Usage
|
//! ## Usage
|
||||||
//!
|
//!
|
||||||
//! ```no_run
|
//! ```no_run
|
||||||
//! use std::fs::File;
|
|
||||||
//! use rosu_pp::{Beatmap, BeatmapExt};
|
//! use rosu_pp::{Beatmap, BeatmapExt};
|
||||||
//!
|
//!
|
||||||
//! # /*
|
//! # /*
|
||||||
//! let file = match File::open("/path/to/file.osu") {
|
|
||||||
//! Ok(file) => file,
|
|
||||||
//! Err(why) => panic!("Could not open file: {}", why),
|
|
||||||
//! };
|
|
||||||
//!
|
|
||||||
//! // Parse the map yourself
|
//! // Parse the map yourself
|
||||||
//! let map = match Beatmap::parse(file) {
|
//! let map = match Beatmap::from_path("/path/to/file.osu") {
|
||||||
//! Ok(map) => map,
|
//! Ok(map) => map,
|
||||||
//! Err(why) => panic!("Error while parsing map: {}", why),
|
//! Err(why) => panic!("Error while parsing map: {}", why),
|
||||||
//! };
|
//! };
|
||||||
@@ -43,7 +37,6 @@
|
|||||||
//! .combo(543)
|
//! .combo(543)
|
||||||
//! .misses(5)
|
//! .misses(5)
|
||||||
//! .n50(3)
|
//! .n50(3)
|
||||||
//! .passed_objects(600)
|
|
||||||
//! .accuracy(96.5)
|
//! .accuracy(96.5)
|
||||||
//! .calculate();
|
//! .calculate();
|
||||||
//!
|
//!
|
||||||
@@ -60,19 +53,10 @@
|
|||||||
//!
|
//!
|
||||||
//! ```no_run
|
//! ```no_run
|
||||||
//! use rosu_pp::{Beatmap, BeatmapExt};
|
//! use rosu_pp::{Beatmap, BeatmapExt};
|
||||||
//! # /*
|
|
||||||
//! use async_std::fs::File;
|
|
||||||
//! # */
|
|
||||||
//! // use tokio::fs::File;
|
|
||||||
//!
|
//!
|
||||||
//! # /*
|
//! # /*
|
||||||
//! let file = match File::open("/path/to/file.osu").await {
|
|
||||||
//! Ok(file) => file,
|
|
||||||
//! Err(why) => panic!("Could not open file: {}", why),
|
|
||||||
//! };
|
|
||||||
//!
|
|
||||||
//! // Parse the map asynchronously
|
//! // Parse the map asynchronously
|
||||||
//! let map = match Beatmap::parse(file).await {
|
//! let map = match Beatmap::from_path("/path/to/file.osu").await {
|
||||||
//! Ok(map) => map,
|
//! Ok(map) => map,
|
||||||
//! Err(why) => panic!("Error while parsing map: {}", why),
|
//! Err(why) => panic!("Error while parsing map: {}", why),
|
||||||
//! };
|
//! };
|
||||||
|
|||||||
+2
-3
@@ -601,15 +601,14 @@ fn difficulty_range_od(od: f64) -> f64 {
|
|||||||
#[test]
|
#[test]
|
||||||
// #[ignore]
|
// #[ignore]
|
||||||
fn custom_osu() {
|
fn custom_osu() {
|
||||||
use std::{fs::File, time::Instant};
|
use std::time::Instant;
|
||||||
|
|
||||||
use crate::{Beatmap, OsuPP};
|
use crate::{Beatmap, OsuPP};
|
||||||
|
|
||||||
let path = "E:Games/osu!/beatmaps/116169_.osu";
|
let path = "E:Games/osu!/beatmaps/116169_.osu";
|
||||||
let file = File::open(path).unwrap();
|
|
||||||
|
|
||||||
let start = Instant::now();
|
let start = Instant::now();
|
||||||
let map = Beatmap::parse(file).unwrap();
|
let map = Beatmap::from_path(path).unwrap();
|
||||||
|
|
||||||
let iters = 100;
|
let iters = 100;
|
||||||
let accum = start.elapsed();
|
let accum = start.elapsed();
|
||||||
|
|||||||
+75
-23
@@ -17,13 +17,26 @@ use sort::legacy_sort;
|
|||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
|
|
||||||
#[cfg(not(any(feature = "async_std", feature = "async_tokio")))]
|
#[cfg(not(any(feature = "async_std", feature = "async_tokio")))]
|
||||||
use std::io::{BufRead, BufReader, Read};
|
use std::{
|
||||||
|
fs::File,
|
||||||
|
io::{BufRead, BufReader, Read},
|
||||||
|
};
|
||||||
|
|
||||||
#[cfg(feature = "async_tokio")]
|
#[cfg(feature = "async_tokio")]
|
||||||
use tokio::io::{AsyncBufReadExt, AsyncRead, BufReader};
|
use tokio::{
|
||||||
|
fs::File,
|
||||||
|
io::{AsyncBufReadExt, AsyncRead, BufReader},
|
||||||
|
};
|
||||||
|
|
||||||
|
#[cfg(not(feature = "async_std"))]
|
||||||
|
use std::path::Path;
|
||||||
|
|
||||||
#[cfg(feature = "async_std")]
|
#[cfg(feature = "async_std")]
|
||||||
use async_std::io::{prelude::BufReadExt, BufReader as AsyncBufReader, Read as AsyncRead};
|
use async_std::{
|
||||||
|
fs::File,
|
||||||
|
io::{prelude::BufReadExt, BufReader as AsyncBufReader, Read as AsyncRead},
|
||||||
|
path::Path,
|
||||||
|
};
|
||||||
|
|
||||||
#[cfg(feature = "sliders")]
|
#[cfg(feature = "sliders")]
|
||||||
pub use osu_fruits::*;
|
pub use osu_fruits::*;
|
||||||
@@ -173,10 +186,10 @@ macro_rules! parse_general_body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! parse_general {
|
macro_rules! parse_general {
|
||||||
($reader:ident<$inner:ident>) => {
|
() => {
|
||||||
fn parse_general<R: $inner>(
|
fn parse_general<R: Read>(
|
||||||
&mut self,
|
&mut self,
|
||||||
reader: &mut $reader<R>,
|
reader: &mut BufReader<R>,
|
||||||
buf: &mut String,
|
buf: &mut String,
|
||||||
section: &mut Section,
|
section: &mut Section,
|
||||||
) -> ParseResult<bool> {
|
) -> ParseResult<bool> {
|
||||||
@@ -244,10 +257,10 @@ macro_rules! parse_difficulty_body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! parse_difficulty {
|
macro_rules! parse_difficulty {
|
||||||
($reader:ident<$inner:ident>) => {
|
() => {
|
||||||
fn parse_difficulty<R: $inner>(
|
fn parse_difficulty<R: Read>(
|
||||||
&mut self,
|
&mut self,
|
||||||
reader: &mut $reader<R>,
|
reader: &mut BufReader<R>,
|
||||||
buf: &mut String,
|
buf: &mut String,
|
||||||
section: &mut Section,
|
section: &mut Section,
|
||||||
) -> ParseResult<bool> {
|
) -> ParseResult<bool> {
|
||||||
@@ -356,10 +369,10 @@ macro_rules! parse_timingpoints_body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! parse_timingpoints {
|
macro_rules! parse_timingpoints {
|
||||||
($reader:ident<$inner:ident>) => {
|
() => {
|
||||||
fn parse_timingpoints<R: $inner>(
|
fn parse_timingpoints<R: Read>(
|
||||||
&mut self,
|
&mut self,
|
||||||
reader: &mut $reader<R>,
|
reader: &mut BufReader<R>,
|
||||||
buf: &mut String,
|
buf: &mut String,
|
||||||
section: &mut Section,
|
section: &mut Section,
|
||||||
) -> ParseResult<bool> {
|
) -> ParseResult<bool> {
|
||||||
@@ -606,10 +619,10 @@ macro_rules! parse_hitobjects_body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! parse_hitobjects {
|
macro_rules! parse_hitobjects {
|
||||||
($reader:ident<$inner:ident>) => {
|
() => {
|
||||||
fn parse_hitobjects<R: $inner>(
|
fn parse_hitobjects<R: Read>(
|
||||||
&mut self,
|
&mut self,
|
||||||
reader: &mut $reader<R>,
|
reader: &mut BufReader<R>,
|
||||||
buf: &mut String,
|
buf: &mut String,
|
||||||
section: &mut Section,
|
section: &mut Section,
|
||||||
) -> ParseResult<bool> {
|
) -> ParseResult<bool> {
|
||||||
@@ -688,19 +701,52 @@ macro_rules! parse_body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! parse {
|
macro_rules! parse {
|
||||||
($reader:ident<$inner:ident>) => {
|
() => {
|
||||||
pub fn parse<R: $inner>(input: R) -> ParseResult<Self> {
|
/// Parse a beatmap from a `.osu` file.
|
||||||
parse_body!($reader<$inner>: input)
|
///
|
||||||
|
/// As argument you can give anything that implements [`std::io::Read`].
|
||||||
|
/// You'll likely want to pass (a reference of) a [`File`](std::fs::File)
|
||||||
|
/// or the file's content as a slice of bytes (`&[u8]`).
|
||||||
|
pub fn parse<R: Read>(input: R) -> ParseResult<Self> {
|
||||||
|
parse_body!(BufReader<Read>: input)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
(async $reader:ident<$inner:ident>) => {
|
(async $reader:ident<$inner:ident>) => {
|
||||||
|
/// Parse a beatmap from a `.osu` file.
|
||||||
|
///
|
||||||
|
/// As argument you can give anything that implements `tokio::io::AsyncRead`
|
||||||
|
/// or `async_std::io::Read`, depending which feature you chose.
|
||||||
|
/// You'll likely want to pass a `File`
|
||||||
|
/// or the file's content as a slice of bytes (`&[u8]`).
|
||||||
pub async fn parse<R: $inner + Unpin>(input: R) -> ParseResult<Self> {
|
pub async fn parse<R: $inner + Unpin>(input: R) -> ParseResult<Self> {
|
||||||
parse_body!($reader<$inner>: input)
|
parse_body!($reader<$inner>: input)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
macro_rules! from_path {
|
||||||
|
() => {
|
||||||
|
/// Pass the path to a `.osu` file.
|
||||||
|
///
|
||||||
|
/// Useful when you don't want to create the [`File`](std::fs::File) manually.
|
||||||
|
/// If you have the file lying around already though (and plan on re-using it),
|
||||||
|
/// passing `&file` to [`parse`](Beatmap::parse) should be preferred.
|
||||||
|
pub fn from_path<P: AsRef<Path>>(path: P) -> ParseResult<Self> {
|
||||||
|
Self::parse(File::open(path)?)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
(async $path:ident) => {
|
||||||
|
/// Pass the path to a `.osu` file.
|
||||||
|
///
|
||||||
|
/// Useful when you don't want to create the file manually.
|
||||||
|
pub async fn from_path<P: AsRef<$path>>(path: P) -> ParseResult<Self> {
|
||||||
|
Self::parse(File::open(path).await?).await
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/// The mode of a beatmap.
|
/// The mode of a beatmap.
|
||||||
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
|
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
|
||||||
#[allow(clippy::upper_case_acronyms)]
|
#[allow(clippy::upper_case_acronyms)]
|
||||||
@@ -911,11 +957,13 @@ mod osu_fruits {
|
|||||||
|
|
||||||
#[cfg(not(any(feature = "async_std", feature = "async_tokio")))]
|
#[cfg(not(any(feature = "async_std", feature = "async_tokio")))]
|
||||||
impl Beatmap {
|
impl Beatmap {
|
||||||
parse!(BufReader<Read>);
|
parse!();
|
||||||
parse_general!(BufReader<Read>);
|
parse_general!();
|
||||||
parse_difficulty!(BufReader<Read>);
|
parse_difficulty!();
|
||||||
parse_timingpoints!(BufReader<Read>);
|
parse_timingpoints!();
|
||||||
parse_hitobjects!(BufReader<Read>);
|
parse_hitobjects!();
|
||||||
|
|
||||||
|
from_path!();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "async_tokio")]
|
#[cfg(feature = "async_tokio")]
|
||||||
@@ -925,6 +973,8 @@ impl Beatmap {
|
|||||||
parse_difficulty!(async BufReader<AsyncRead>);
|
parse_difficulty!(async BufReader<AsyncRead>);
|
||||||
parse_timingpoints!(async BufReader<AsyncRead>);
|
parse_timingpoints!(async BufReader<AsyncRead>);
|
||||||
parse_hitobjects!(async BufReader<AsyncRead>);
|
parse_hitobjects!(async BufReader<AsyncRead>);
|
||||||
|
|
||||||
|
from_path!(async Path);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "async_std")]
|
#[cfg(feature = "async_std")]
|
||||||
@@ -934,6 +984,8 @@ impl Beatmap {
|
|||||||
parse_difficulty!(async AsyncBufReader<AsyncRead>);
|
parse_difficulty!(async AsyncBufReader<AsyncRead>);
|
||||||
parse_timingpoints!(async AsyncBufReader<AsyncRead>);
|
parse_timingpoints!(async AsyncBufReader<AsyncRead>);
|
||||||
parse_hitobjects!(async AsyncBufReader<AsyncRead>);
|
parse_hitobjects!(async AsyncBufReader<AsyncRead>);
|
||||||
|
|
||||||
|
from_path!(async Path);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
|||||||
Reference in New Issue
Block a user