#osu #难度 #表现 #星数 #pp #

rosu-pp

osu! 难度和表现计算

24 个版本 (2 个稳定版)

1.1.0 2024年7月10日
0.10.0 2023年11月19日
0.9.4 2023年2月9日
0.9.2 2022年11月8日
0.2.0 2021年2月25日

#4 in 游戏

Download history 29/week @ 2024-04-29 7/week @ 2024-05-06 2/week @ 2024-05-13 26/week @ 2024-05-20 42/week @ 2024-05-27 20/week @ 2024-06-03 11/week @ 2024-06-10 25/week @ 2024-06-17 39/week @ 2024-06-24 34/week @ 2024-07-01 277/week @ 2024-07-08 26/week @ 2024-07-15 31/week @ 2024-07-22 39/week @ 2024-07-29 25/week @ 2024-08-05 14/week @ 2024-08-12

每月111 次下载
用于 simplebeatmapanalyzer

MIT 许可

645KB
14K SLoC

crates.io docs

rosu-pp

用于计算所有 osu! 游戏模式的难度和表现属性的库。

rosu-pp 的很大一部分是将 osu!lazer 的难度和表现计算移植过来,重点在于将代码精确地翻译为 Rust 以获得最精确的结果,同时提供显著的性能提升。

移植代码的最新提交

  • osu!lazer : 7342fb7f51b34533a42bffda89c3d6c569cc69ce (2022-10-11)
  • osu!tools : 146d5916937161ef65906aa97f85d367035f3712 (2022-10-08)

最新游戏模式更新新闻

使用方法

// Decode the map
let map = rosu_pp::Beatmap::from_path("./resources/2785319.osu").unwrap();

// Calculate difficulty attributes
let diff_attrs = rosu_pp::Difficulty::new()
    .mods(8 + 16) // HDHR
    .calculate(&map);

let stars = diff_attrs.stars();

// Calculate performance attributes
let perf_attrs = rosu_pp::Performance::new(diff_attrs)
    // To speed up the calculation, we used the previous attributes.
    // **Note** that this should only be done if the map and all difficulty
    // settings stay the same, otherwise the final attributes will be incorrect!
    .mods(24) // HDHR, must be the same as before
    .combo(789)
    .accuracy(99.2)
    .misses(2)
    .calculate();

let pp = perf_attrs.pp();

// Again, we re-use the previous attributes for maximum efficiency.
let max_pp = perf_attrs.performance()
    .mods(24) // Still the same
    .calculate()
    .pp();

println!("Stars: {stars} | PP: {pp}/{max_pp}");

逐步计算

逐步计算属性提供了一种有效的方法来单独处理每个 hitobject 并仅计算到该点的属性。

对于难度属性,有 GradualDifficulty 实现了 Iterator,而对于表现属性,有 GradualPerformance 需要当前的分数状态。

use rosu_pp::{Beatmap, GradualPerformance, Difficulty, any::ScoreState};

let map = Beatmap::from_path("./resources/1028484.osu").unwrap();

let mut gradual = Difficulty::new()
    .mods(16 + 64) // HRDT
    .clock_rate(1.2)
    .gradual_performance(&map);

let mut state = ScoreState::new(); // empty state, everything is on 0.

// The first 10 hitresults are 300s
for _ in 0..10 {
    state.n300 += 1;
    state.max_combo += 1;
    let attrs = gradual.next(state.clone()).unwrap();
    println!("PP: {}", attrs.pp());
}

// Fast-forward to the end
state.max_combo = ...
state.n300 = ...
state.n_katu = ...
...
let attrs = gradual.last(state).unwrap();
println!("PP: {}", attrs.pp());

准确性

rosu-pp 在多种 mod 组合下与所有当前 beatmap 进行了测试,并提供了与 osu!lazer 完全匹配的值,精确到小数点后最后一位。

然而,有一个小注意事项:只有在调试模式下,值才如此精确。在发布模式下,Rust编译器会进行优化,这可能导致由于浮点数不精确而产生微小的差异,最终可能会放大。考虑到这一点,rosu-pp在不针对.NET编译器本身的情况下,尽可能精确。实际上,发布模式下的不精确性可以忽略不计。

速度

rosu-pp的一个重要因素是计算速度。优化和精确翻译并不总是相辅相成。不过,仍然尽可能地进行了性能改进,提供了比原生C#代码显著更快的运行时。

osu!lazer和rosu-pp的简单基准测试结果

osu!lazer:
Decoding maps:            Median: 378.10ms | Mean: 381.47ms
Calculating difficulties: Median: 588.89ms | Mean: 597.11ms
Calculating performances: Median: 315.90µs | Mean: 310.60µs

rosu-pp:
Decoding maps:            Median: 46.94ms | Mean: 47.21ms
Calculating difficulties: Median: 72.90ms | Mean: 73.13ms
Calculating performances: Median: 44.13µs | Mean: 45.53µs

特性

标志 描述 依赖关系
默认 启用compact_strains特性
compact_strains 在Plain Vec中存储内部应变值会在恶意长地图上引入内存不足的风险(见/b/3739922)。此特性更紧凑地存储应变,但性能会损失约5%。
sync 如果启用此特性,一些逐渐的计算类型才能跨线程共享。这会带来性能惩罚,因此只有当真正需要时才启用。
tracing 在解码beatmap期间遇到的任何错误将通过tracing::error进行记录。如果此特性未启用,则错误将被忽略。 tracing

绑定

使用除Rust以外的语言使用rosu-pp

依赖关系

~1MB
~22K SLoC