added method Beatmap::from_path
This commit is contained in:
+3
-3
@@ -1,6 +1,6 @@
|
||||
## 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
|
||||
|
||||
@@ -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 `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
|
||||
- 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-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
|
||||
- osu: Updated up to commit [9fb2402781ad91c197d51aeec716b0000f52c4d1](https://github.com/ppy/osu/commit/9fb2402781ad91c197d51aeec716b0000f52c4d1) (2021-11-12)
|
||||
|
||||
## v0.2.3
|
||||
|
||||
@@ -11,16 +11,10 @@ Async is supported through features, see below.
|
||||
### Usage
|
||||
|
||||
```rust
|
||||
use std::fs::File;
|
||||
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
|
||||
let map = match Beatmap::parse(file) {
|
||||
let map = match Beatmap::from_path("/path/to/file.osu") {
|
||||
Ok(map) => map,
|
||||
Err(why) => panic!("Error while parsing map: {}", why),
|
||||
};
|
||||
@@ -45,7 +39,6 @@ let next_result = map.pp()
|
||||
.combo(543)
|
||||
.misses(5)
|
||||
.n50(3)
|
||||
.passed_objects(600)
|
||||
.accuracy(96.5)
|
||||
.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.
|
||||
|
||||
```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
|
||||
let map = match Beatmap::parse(file).await {
|
||||
let map = match Beatmap::from_path("/path/to/file.osu").await {
|
||||
Ok(map) => map,
|
||||
Err(why) => panic!("Error while parsing map: {}", why),
|
||||
};
|
||||
|
||||
+2
-3
@@ -670,13 +670,12 @@ impl From<FruitsPerformanceAttributes> for FruitsDifficultyAttributes {
|
||||
#[test]
|
||||
// #[ignore]
|
||||
fn custom_fruits() {
|
||||
use std::{fs::File, time::Instant};
|
||||
use std::time::Instant;
|
||||
|
||||
use crate::{Beatmap, FruitsPP};
|
||||
|
||||
let path = "E:Games/osu!/beatmaps/2919116_.osu";
|
||||
let file = File::open(path).unwrap();
|
||||
let map = Beatmap::parse(file).unwrap();
|
||||
let map = Beatmap::from_path(path).unwrap();
|
||||
|
||||
let start = Instant::now();
|
||||
let result = FruitsPP::new(&map).mods(256).calculate();
|
||||
|
||||
+2
-18
@@ -7,17 +7,11 @@
|
||||
//! ## Usage
|
||||
//!
|
||||
//! ```no_run
|
||||
//! use std::fs::File;
|
||||
//! 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
|
||||
//! let map = match Beatmap::parse(file) {
|
||||
//! let map = match Beatmap::from_path("/path/to/file.osu") {
|
||||
//! Ok(map) => map,
|
||||
//! Err(why) => panic!("Error while parsing map: {}", why),
|
||||
//! };
|
||||
@@ -43,7 +37,6 @@
|
||||
//! .combo(543)
|
||||
//! .misses(5)
|
||||
//! .n50(3)
|
||||
//! .passed_objects(600)
|
||||
//! .accuracy(96.5)
|
||||
//! .calculate();
|
||||
//!
|
||||
@@ -60,19 +53,10 @@
|
||||
//!
|
||||
//! ```no_run
|
||||
//! 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
|
||||
//! let map = match Beatmap::parse(file).await {
|
||||
//! let map = match Beatmap::from_path("/path/to/file.osu").await {
|
||||
//! Ok(map) => map,
|
||||
//! Err(why) => panic!("Error while parsing map: {}", why),
|
||||
//! };
|
||||
|
||||
+2
-3
@@ -601,15 +601,14 @@ fn difficulty_range_od(od: f64) -> f64 {
|
||||
#[test]
|
||||
// #[ignore]
|
||||
fn custom_osu() {
|
||||
use std::{fs::File, time::Instant};
|
||||
use std::time::Instant;
|
||||
|
||||
use crate::{Beatmap, OsuPP};
|
||||
|
||||
let path = "E:Games/osu!/beatmaps/116169_.osu";
|
||||
let file = File::open(path).unwrap();
|
||||
|
||||
let start = Instant::now();
|
||||
let map = Beatmap::parse(file).unwrap();
|
||||
let map = Beatmap::from_path(path).unwrap();
|
||||
|
||||
let iters = 100;
|
||||
let accum = start.elapsed();
|
||||
|
||||
+75
-23
@@ -17,13 +17,26 @@ use sort::legacy_sort;
|
||||
use std::cmp::Ordering;
|
||||
|
||||
#[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")]
|
||||
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")]
|
||||
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")]
|
||||
pub use osu_fruits::*;
|
||||
@@ -173,10 +186,10 @@ macro_rules! parse_general_body {
|
||||
}
|
||||
|
||||
macro_rules! parse_general {
|
||||
($reader:ident<$inner:ident>) => {
|
||||
fn parse_general<R: $inner>(
|
||||
() => {
|
||||
fn parse_general<R: Read>(
|
||||
&mut self,
|
||||
reader: &mut $reader<R>,
|
||||
reader: &mut BufReader<R>,
|
||||
buf: &mut String,
|
||||
section: &mut Section,
|
||||
) -> ParseResult<bool> {
|
||||
@@ -244,10 +257,10 @@ macro_rules! parse_difficulty_body {
|
||||
}
|
||||
|
||||
macro_rules! parse_difficulty {
|
||||
($reader:ident<$inner:ident>) => {
|
||||
fn parse_difficulty<R: $inner>(
|
||||
() => {
|
||||
fn parse_difficulty<R: Read>(
|
||||
&mut self,
|
||||
reader: &mut $reader<R>,
|
||||
reader: &mut BufReader<R>,
|
||||
buf: &mut String,
|
||||
section: &mut Section,
|
||||
) -> ParseResult<bool> {
|
||||
@@ -356,10 +369,10 @@ macro_rules! parse_timingpoints_body {
|
||||
}
|
||||
|
||||
macro_rules! parse_timingpoints {
|
||||
($reader:ident<$inner:ident>) => {
|
||||
fn parse_timingpoints<R: $inner>(
|
||||
() => {
|
||||
fn parse_timingpoints<R: Read>(
|
||||
&mut self,
|
||||
reader: &mut $reader<R>,
|
||||
reader: &mut BufReader<R>,
|
||||
buf: &mut String,
|
||||
section: &mut Section,
|
||||
) -> ParseResult<bool> {
|
||||
@@ -606,10 +619,10 @@ macro_rules! parse_hitobjects_body {
|
||||
}
|
||||
|
||||
macro_rules! parse_hitobjects {
|
||||
($reader:ident<$inner:ident>) => {
|
||||
fn parse_hitobjects<R: $inner>(
|
||||
() => {
|
||||
fn parse_hitobjects<R: Read>(
|
||||
&mut self,
|
||||
reader: &mut $reader<R>,
|
||||
reader: &mut BufReader<R>,
|
||||
buf: &mut String,
|
||||
section: &mut Section,
|
||||
) -> ParseResult<bool> {
|
||||
@@ -688,19 +701,52 @@ macro_rules! parse_body {
|
||||
}
|
||||
|
||||
macro_rules! parse {
|
||||
($reader:ident<$inner:ident>) => {
|
||||
pub fn parse<R: $inner>(input: R) -> ParseResult<Self> {
|
||||
parse_body!($reader<$inner>: input)
|
||||
() => {
|
||||
/// Parse a beatmap from a `.osu` file.
|
||||
///
|
||||
/// 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>) => {
|
||||
/// 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> {
|
||||
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.
|
||||
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
|
||||
#[allow(clippy::upper_case_acronyms)]
|
||||
@@ -911,11 +957,13 @@ mod osu_fruits {
|
||||
|
||||
#[cfg(not(any(feature = "async_std", feature = "async_tokio")))]
|
||||
impl Beatmap {
|
||||
parse!(BufReader<Read>);
|
||||
parse_general!(BufReader<Read>);
|
||||
parse_difficulty!(BufReader<Read>);
|
||||
parse_timingpoints!(BufReader<Read>);
|
||||
parse_hitobjects!(BufReader<Read>);
|
||||
parse!();
|
||||
parse_general!();
|
||||
parse_difficulty!();
|
||||
parse_timingpoints!();
|
||||
parse_hitobjects!();
|
||||
|
||||
from_path!();
|
||||
}
|
||||
|
||||
#[cfg(feature = "async_tokio")]
|
||||
@@ -925,6 +973,8 @@ impl Beatmap {
|
||||
parse_difficulty!(async BufReader<AsyncRead>);
|
||||
parse_timingpoints!(async BufReader<AsyncRead>);
|
||||
parse_hitobjects!(async BufReader<AsyncRead>);
|
||||
|
||||
from_path!(async Path);
|
||||
}
|
||||
|
||||
#[cfg(feature = "async_std")]
|
||||
@@ -934,6 +984,8 @@ impl Beatmap {
|
||||
parse_difficulty!(async AsyncBufReader<AsyncRead>);
|
||||
parse_timingpoints!(async AsyncBufReader<AsyncRead>);
|
||||
parse_hitobjects!(async AsyncBufReader<AsyncRead>);
|
||||
|
||||
from_path!(async Path);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
||||
Reference in New Issue
Block a user