Skip to content

Migrating from v1 to v2

Rian edited this page Jun 28, 2022 · 3 revisions

This wiki page contains directions for upgrading from v1 to v2.

Breaking Changes (semver:major)

osu-base

Removal of <MapInfo>.maxScore

The <MapInfo>.maxScore method has been removed as it requires a Beatmap instance to be able to function. Therefore, it makes sense to put this method in the Beatmap instance itself.

In v2, the equivalent method is <Beatmap>.maxDroidScore.

- <MapInfo>.maxScore()
+ <Beatmap>.maxDroidScore()

Return value of <MapInfo>.showStatistics

The return values of <MapInfo>.showStatistics for some options have been changed.

Option Value v1 v2
0 Returns map title and mods used if defined Returns map title and mods used if defined
1 Returns song source and map download link to beatmap mirrors Returns song source and map download link to beatmap mirrors
2 Returns CS, AR, OD, HP Returns circle, slider, and spinner count
3 Returns BPM, map length, max combo Returns CS, AR, OD, HP, and max score statistics for droid
4 Returns last update date and map status Returns CS, AR, OD, HP, and max score statistics for PC
5 Returns favorite count and play count Returns BPM, map length, and max combo
6 N/A Returns last update date and map status
7 N/A Returns favorite count and play count

<MapInfo>.getInformation changes

The <MapInfo>.getInformation method now returns null as opposed to a blank instance in one of these cases:

  • The beatmap is not found
  • The beatmap is not an osu!standard beatmap

Additionally, the method now expects two parameters as opposed to an object. The first parameter is the beatmap ID or hash. The second parameter is a download beatmap flag (indicating whether you want to download the beatmap or not).

- MapInfo.getInformation({
-    beatmapID: 901854,
-    file: true,
- })
+ MapInfo.getInformation(901854, true);

<MapInfo>.retrieveBeatmapFile returns void instead of instance

This method has been changed to return void instead of its instance.

<MapInfo>.map changes

The <MapInfo>.map getter has been renamed to <MapInfo>.beatmap. Additionally, it no longer returns a deep copy of the original Beatmap instance.

The use cases of a deep-cloned instance are rare, and it introduced an overhead. Users who expect the getter to return a deep-cloned instance must perform the deep clone operation by themselves using Utils.deepCopy.

Beatmap class rewrite

The Beatmap class has been rewritten to be able to store all informations necessary to encode an .osu file instead of only storing informations necessary for difficulty calculation.

Moved fields

Some old fields that have been moved are as follows:

  • ar, cs, od, hp, sv, and tickRate have been moved to difficulty
  • artist, artistUnicode, beatmapId, beatmapSetId, creator, title, and titleUnicode have been moved to metadata
  • circles, sliders, spinners, sliderEnds, sliderRepeatPoints, and sliderTicks have been moved to hitObjects
  • objects has been moved to hitObjects.objects
    • Directly adding hitobjects to the array is no longer supported. Use the add method to maintain the sorting order of hitobjects.
    • Use the hitObjects.removeAt method to remove a hitobject at a certain index.
  • timingPoints has been moved to controlPoints.timing
  • difficultyTimingPoints has been moved to controlPoints.difficulty
  • difficultyControlPointAt has been moved to controlPoints.difficulty.controlPointAt
  • timingControlPointAt has been moved to controlPoints.timing.controlPointAt

Adding and removing hitobjects or timing points

Directly adding hitobjects and timing points to respective arrays are no longer supported.

To do this in v2, use the hitObjects.add or controlPoints.<ControlPointManager>.add method. The method will maintain the sorting order of hitobjects or timing points.

To remove a hitobject or timing point at an index, use the hitObjects.removeAt or controlPoints.<ControlPointManager>.removeAt method.

For timing points, you can use the controlPoints.<ControlPointManager>.remove method to remove a timing point. This method will check for the equality of a timing point and remove the first timing point found in the array. Like the add method, this will maintain the sorting order of hitobjects or timing points.

Redundant timing points will be ignored

In v2, when adding a timing point, the timing point may not be added if the correct state is already present at the timing point's time.

Renamed slider objects classes and fields

Some slider object-related classes and fields have been renamed:

  • HeadCircle --> SliderHead
  • RepeatPoint --> SliderRepeat
  • TailCircle --> SliderTail
  • <Slider>.headCircle --> <Slider>.head
  • <Slider>.tailCircle --> <Slider>.tail
  • <Slider>.repeatPoints --> <Slider>.repeats

Renamed the Parser class

To avoid confusion with the new beatmap encoder, the Parser class in v1 has been renamed to BeatmapDecoder in v2. Similarly, the <Parser>.parse method has been renamed to <BeatmapDecoder>.decode.

Capped droid CS scale in MapStats

The droid CS scale when converting droid CS to standard CS in MapStats has been capped to 0.001, preventing incredibly high CS from breaking difficulty calculations and making behavior inline with the game.

osu-difficulty-calculator

Renamed *StarRating to *DifficultyCalculator

To keep naming convention inline with performance calculators, these classes have been renamed:

  • StarRating --> DifficultyCalculator
  • DroidStarRating --> DroidDifficultyCalculator
  • OsuStarRating --> OsuDifficultyCalculator

From this point onwards, these classes will be referred to their new name.

Changes on passing a Beatmap to DifficultyCalculators

In v1, you need to pass in a map property to <DifficultyCalculator>.calculate parameter object.

In v2, this has been moved to the constructor.

- new DroidStarRating().calculate({ map: beatmap });
+ new DroidDifficultyCalculator(beatmap).calculate();

Renamed <DifficultyCalculator>.map to <DifficultyCalculator>.beatmap

Uses full name to make the field clearer. Additionally, this field is now read-only.

<DifficultyCalculator>.generateDifficultyHitObjects no longer expects a mode parameter

This has been handled internally as it doesn't make sense to have it as a required parameter.

Changes on passing a DifficultyCalculator to PerformanceCalculators

In v1, you need to pass in a stars property to <PerformanceCalculator>.calculate parameter object.

In v2, this has been moved to the constructor.

- new DroidPerformanceCalculator().calculate({ stars: diffCalc });
+ new DroidPerformanceCalculator(diffCalc).calculate();

Renamed <PerformanceCalculator>.stars --> <PerformanceCalculator>.difficultyCalculator

Uses full name to make the field clearer. Additionally, this field is now read-only.

osu-droid-replay-analyzer

Rewritten the structure of cursor data movement

In v1, cursor data movement is stored as an array of CursorDatas. Each CursorData contains a time, x position, y position, and movement ID data in an array respectively. This process is rather complicated and often a waste of resource when you want to find connections between a cursor occurrence and another.

In v2, this has been simplified. Each CursorData contains an occurrences field, which contains all cursor occurrences of the cursor instance. Each cursor occurrence contains the time, position, and the movement ID of the occurrence.

Below is the difference in accessing a cursor occurrence in v1 compared to v2:

const firstCursorData = replayAnalyzer.data.cursorMovement[0];

- const index = 0;
- console.log(firstCursorData.time[0]);
- console.log(firstCursorData.x[0]);
- console.log(firstCursorData.y[0]);
- console.log(firstCursorData.id[0]);
+ const occurrence = firstCursorData.occurrences[0];
+ console.log(occurrence.time);
+ console.log(occurrence.position.x);
+ console.log(occurrence.position.y);
+ console.log(occurrence.id);

Renamed <ReplayAnalyzer>.map --> <ReplayAnalyzer>.beatmap

Uses full name to make the field clearer.

osu-rebalance-difficulty-calculator

Renamed *StarRating to *DifficultyCalculator

To keep naming convention inline with performance calculators, these classes have been renamed:

  • StarRating --> DifficultyCalculator
  • DroidStarRating --> DroidDifficultyCalculator
  • OsuStarRating --> OsuDifficultyCalculator

From this point onwards, these classes will be referred to their new name.

Changes on passing a Beatmap to DifficultyCalculators

In v1, you need to pass in a map property to <DifficultyCalculator>.calculate parameter object.

In v2, this has been moved to the constructor.

- new DroidStarRating().calculate({ map: beatmap });
+ new DroidDifficultyCalculator(beatmap).calculate();

Renamed <DifficultyCalculator>.map to <DifficultyCalculator>.beatmap

Uses full name to make the field clearer. Additionally, this field is now read-only.

<DifficultyCalculator>.generateDifficultyHitObjects no longer expects a mode parameter

This has been handled internally as it doesn't make sense to have it as a required parameter.

Changes on passing a DifficultyCalculator to PerformanceCalculators

In v1, you need to pass in a stars property to <PerformanceCalculator>.calculate parameter object.

In v2, this has been moved to the constructor.

- new DroidPerformanceCalculator().calculate({ stars: diffCalc });
+ new DroidPerformanceCalculator(diffCalc).calculate();

Renamed <PerformanceCalculator>.stars --> <PerformanceCalculator>.difficultyCalculator

Uses full name to make the field clearer. Additionally, this field is now read-only.

Additions and Changes (semver:minor)

osu-base

<Beatmap>.maxOsuScore

Since maximum score calculations have been moved to Beatmap level, it is now convenient to add another maximum score calculation method that calculates for osu!standard instead of osu!droid.

This method accepts an array of Mods as opposed to a MapStats instance like in <Beatmap>.maxDroidScore.

Support for decoding entire .osu and .osb files

The new beatmap decoder (BeatmapDecoder) can now decode an entire .osu file (including storyboard, using StoryboardDecoder which also supports .osb files).

With this, the Beatmap class has been restructured with respect to .osu file contents (i.e. <Beatmap>.editor, <Beatmap>.general, etc) to be able to serve these additions nicely.

Timing point redundancy check

Each ControlPoint classes now have an isRedundant method to check whether a timing point will cause a meaningful change when added to the list of current timing points.

Support for encoding .osu and .osb files

Now that a beatmap and storyboard decoder exist, it is possible to make a beatmap and storyboard encoder.

Keep in mind that equality with the original file is not guaranteed, especially if the beatmap or storyboard's format version is older than 14.

Angle conversion methods

The MathUtils class now has static methods to convert angles from radians to degrees and vice versa.

Most common beat length getter in Beatmap

The Beatmap class now has a getter that will return the most common beat length in the beatmap. This can be used to calculate BPM with the following formula: 60000 / <Beatmap>.mostCommonBeatLength.

Hit window value to OD conversions

The DroidHitWindow and OsuHitWindow classes now have static methods that can convert a judgement hit window value to its respective OD value.

DroidHitWindow.hitWindow300ToOD(10);
DroidHitWindow.hitWindow100ToOD(10);
DroidHitWindow.hitWindow50ToOD(10);

OsuHitWindow.hitWindow300ToOD(10);
OsuHitWindow.hitWindow100ToOD(10);
OsuHitWindow.hitWindow50ToOD(10);

Fade multipliers in ModHidden

The ModHidden class now have static fade multipliers.

This is used in difficulty calculation in MBMasher's FL opacity change.

Options for mod parsing in ModUtil

You can now specify options in ModUtil parsing methods to determine the behavior of the parser. For example, you can set the parser to ignore duplicate and incompatible mods. By default, the parser will do both operations to keep the behavior consistent with v1.

ModUtil.pcStringToMods("HDHR", {
    checkDuplicate: false,
    checkIncompatible: false,
});

<MapInfo>.map type narrowing

In v1, there is no way to narrow the type of <MapInfo>.map without checking for the value of the field.

In v2, the MapInfo.getInformation method will automatically narrow the type of <MapInfo>.map depending on whether you downloaded the beatmap file.

let beatmapInfo = await MapInfo.getInformation(901854);

console.log(beatmapInfo.map); // type is `Beatmap`

beatmapInfo = await MapInfo.getInformation(901854, false);

console.log(beatmapInfo.map); // type is `null`

Unfortunately, type-narrowing with promises is not supported. Therefore, the <MapInfo>.hasDownloadedBeatmap method has been added to allow manual type-narrowing.

osu-difficulty-calculator

<StarRating>.calculate is public

This method shouldn't be protected in the first place albeit it's in an abstract class.

Droid visual skill (DroidVisual)

This skill attempts to quantify the skill required to read every object in a beatmap.

Post-adjustment preempt time and fade in time to DifficultyHitObject

This is required to port MBMasher's FL opacity change.

<DifficultyHitObject>.opacityAt

This method is used to calculate a hitobject's opacity at a given time. This is required to port MBMasher's FL opacity change.

Moved object history to the object itself as opposed to skills

In the same way as osu!lazer does it.

Moved individual object difficulty calculations to separate methods

In the same way as osu!lazer does it.

Ported MBMasher's FL opacity change to droid

In the same way as osu!lazer does it, however it excludes hitobjects that overlap with each other.

osu-droid-replay-analyzer

Revamped two hand detection

This feature is still in beta. However, there are too many cases to consider, hence I decided to stop here for now.

Increased finger factor penalty in three finger detection

Penalty for more three-finger usage should be more harsh.

osu-rebalance-difficulty-calculator

<StarRating>.calculate is public

This method shouldn't be protected in the first place albeit it's in an abstract class.

Droid visual skill (DroidVisual)

This skill attempts to quantify the skill required to read every object in a beatmap.

Post-adjustment preempt time and fade in time to DifficultyHitObject

This is required to port MBMasher's FL opacity change.

<DifficultyHitObject>.opacityAt

This method is used to calculate a hitobject's opacity at a given time. This is required to port MBMasher's FL opacity change.

Moved object history to the object itself as opposed to skills

In the same way as osu!lazer does it.

Moved individual object difficulty calculations to separate methods

In the same way as osu!lazer does it.

Ported MBMasher's FL opacity change to droid and standard

In the same way as osu!lazer does it, however in droid it excludes hitobjects that overlap with each other.

Ported MBMasher's doubletap detection rework to droid and standard

In the same way as osu!lazer does it.

Reworked droid's small circle bonus

Small circles in droid have always been underrated. This is because it is still based on PC small circle bonus, which will never be hit unless the Small Circle (SC) mod is used.

This rework aims to solve that problem while buffing smaller circles as they inch towards 0 radius.

Given a bonus for AR between 9.5 and 10 in droid visual skill

The introduction of droid visual skill has solved numerous problems, however one problem that became noticeable is that using HR in some beatmaps can cause the final pp value to be lower than NM due to the skill being based mainly on note density. This is especially noticeable when a beatmap is set at OD 10 in NM.

In beatmaps that specialize in low AR reading, this is reasonable, however it doesn't make sense for beatmaps that don't do so. Therefore, in order to help alleviate this problem, a small bonus is given for AR value between 9.5 and 10.

Bug Fixes (semver:patch)

osu-base

Fixed beatmap AR defaulting to beatmap OD when decoding an AR 0 beatmap

In very old beatmaps, AR is equal to OD. Therefore, the beatmap decoder has been adjusted to account for this. However, the check uses the bang operator (!), which converts 0 to a truthy value. As a result, the beatmap's AR is assigned as its OD.

osu-difficulty-calculator

Fixed Relax mod not affecting tap star rating calculation in DroidDifficultyCalculator

The tap star rating when calculating with the Relax mod should be 0.

osu-rebalance-difficulty-calculator

Fixed Relax mod not affecting tap star rating calculation in DroidDifficultyCalculator

The tap star rating when calculating with the Relax mod should be 0.

Clone this wiki locally