Difficulty and performance calculation for all osu! modes.
This is a js binding to the Rust library rosu-pp which was bootstrapped through neon. Since all the heavy lifting is done by Rust, rosu-pp-js comes with a very fast performance. Check out rosu-pp's README for more info.
The library exposes two classes: Beatmap
and Calculator
.
The constructor takes an optional object of the following form:
{
path?: string, // path to a .osu file
content?: string | Uint8Array, // content of a .osu file
bytes?: Uint8Array, // content of a .osu file
ar?: number, // modify the approach rate
cs?: number, // modify the circle size
hp?: number, // modify the drain rate
od?: number, // modify the overall difficulty
}
Additionally, it can be modified through the following builder methods:
fromPath(path: string)
fromContent(content: string | Uint8Array)
fromBytes(bytes: Uint8Array)
ar(ar: number)
cs(cs: number)
hp(hp: number)
od(od: number)
import { Beatmap } from require('rosu-pp');
let params = {
path: './maps/100.osu',
od: 10.0,
};
let map = new Beatmap(params).ar(9);
require('fs').readFile('./maps/100.osu', (_, data) => {
let map = new Beatmap().fromBytes(data);
map = map.cs(0);
});
The constructor takes an optional object of the following form:
{
mode?: number | string, // 0/1/2/3 or "osu"/"taiko"/"catch"/"mania"
mods?: number, // bit value for mods, see https://github.com/ppy/osu-api/wiki#mods
acc?: number, // accuracy between 0 and 100
nGeki?: number, // amount of n320 for mania, otherwise irrelevant
nKatu?: number, // amount of n200 for mania and tiny droplet misses for catch, otherwise irrelevant
n300?: number,
n100?: number,
n50?: number, // irrelevant for taiko
nMisses?: number,
combo?: number,
passedObjects?: number, // only consider this many objects, handy for partial plays like fails
clockRate?: number, // custom clock rate
}
Additionally, it can be modified through the following builder methods:
mode(mode: number | string)
mods(mods: number)
acc(acc: number)
nGeki(nGeki: number)
nKatu(nKatu: number)
n300(n300: number)
n100(n100: number)
n50(n50: number)
nMisses(nMisses: number)
combo(combo: number)
passedObjects(passedObjects: number)
clockRate(clockRate: number)
Finally, use one of the following methods to calculate values:
mapAttributes(map: Beatmap)
returns an object of the form
{
mode: number,
version: number,
nCircles: number,
nSliders: number,
nSpinners: number,
ar: number,
cs: number,
hp: number,
od: number,
arHitWindow: number,
odHitWindow: number,
clockRate: number,
bpm: number,
}
difficulty(map: Beatmap)
returns an object of the form
{
// all modes:
mode: number,
stars: number,
maxCombo: number,
// only osu!:
aim: number,
speed: number,
flashlight: number,
sliderFactor: number,
speedNoteCount: number,
ar: number,
od: number,
nCircles: number,
nSliders: number,
nSpinners: number,
// only taiko:
stamina: number,
rhythm: number,
color: number,
peak: number,
hitWindow: number,
// only catch:
ar: number,
nFruits: number,
nDroplets: number,
nTinyDroplets: number,
// only mania:
hitWindow: number,
}
performance(map: Beatmap)
returns an object of the form
{
// all modes:
mode: number,
pp: number,
difficulty: Object, // same structure as above
// only osu!:
ppAcc: number,
ppAim: number,
ppFlashlight: number,
ppSpeed: number,
effectiveMissCount: number,
// only taiko:
ppAcc: number,
ppDifficulty: number,
effectiveMissCount: number,
// only catch:
ppDifficulty: number,
// nothing additional for mania
}
strains(map: Beatmap)
returns an object of the form
{
// all modes:
mode: number,
sectionLength: number, // milliseconds between two strain points
// only osu!:
aim: Array<number>,
aimNoSliders: Array<number>,
speed: Array<number>,
flashlight: Array<number>,
// only taiko:
color: Array<number>,
rhythm: Array<number>,
stamina: Array<number>,
// only catch:
movement: Array<number>,
// only mania:
strains: Array<number>,
}
import { Beatmap, Calculator } from require('rosu-pp');
let map = new Beatmap({ path: './maps/100.osu' });
let score = {
mode: 2, // osu!catch
mods: 8 + 64, // HDDT
};
let calc = new Calculator(score);
let maxAttrs = calc.performance(map);
let currAttrs = calc.n300(150)
.n100(10)
.nMisses(20)
.passedObjects(200)
.performance(map);
console.log(`stars: ${maxAttrs.difficulty.stars}`);
console.log(`pp: ${currAttrs.pp}/${maxAttrs.pp}`);
Installing rosu-pp-js requires a supported version of Node and Rust.
Once Node and Rust are ready to go, you can install the project with npm. In your project directory, run:
$ npm install rosu-pp
or
$ npm install https://github.com/MaxOhn/rosu-pp-js
This fully installs the project, including installing any dependencies and running the build.