@rian8337/osu-difficulty-calculator 4.0.0-beta.3 → 4.0.0-beta.30

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,4 +1,4 @@
1
- import { MapStats, Mod, PlaceableHitObject, Modes, Beatmap, HitObject, Accuracy } from '@rian8337/osu-base';
1
+ import { Mod, PlaceableHitObject, Modes, Beatmap, Accuracy } from '@rian8337/osu-base';
2
2
 
3
3
  /**
4
4
  * An evaluator for calculating aim skill.
@@ -20,16 +20,6 @@ declare abstract class AimEvaluator {
20
20
  protected static calculateAcuteAngleBonus(angle: number): number;
21
21
  }
22
22
 
23
- /**
24
- * The base of calculation options.
25
- */
26
- interface CalculationOptions {
27
- /**
28
- * Custom map statistics to apply custom speed multiplier as well as old statistics.
29
- */
30
- stats?: MapStats;
31
- }
32
-
33
23
  /**
34
24
  * Holds data that can be used to calculate performance points.
35
25
  */
@@ -69,11 +59,9 @@ interface DifficultyAttributes {
69
59
  */
70
60
  sliderFactor: number;
71
61
  /**
72
- * The perceived approach rate inclusive of rate-adjusting mods (DT/HT/etc).
73
- *
74
- * Rate-adjusting mods don't directly affect the approach rate difficulty value, but have a perceived effect as a result of adjusting audio timing.
62
+ * The overall clock rate that was applied to the beatmap.
75
63
  */
76
- approachRate: number;
64
+ clockRate: number;
77
65
  /**
78
66
  * The perceived overall difficulty inclusive of rate-adjusting mods (DT/HT/etc), based on osu!standard judgement.
79
67
  *
@@ -94,20 +82,34 @@ interface DifficultyAttributes {
94
82
  spinnerCount: number;
95
83
  }
96
84
 
85
+ /**
86
+ * Represents difficulty attributes that can be cached.
87
+ */
88
+ type CacheableDifficultyAttributes<T extends DifficultyAttributes> = Omit<T, "mods"> & {
89
+ /**
90
+ * The mods which were applied to the beatmap.
91
+ */
92
+ mods: string;
93
+ };
94
+
97
95
  /**
98
96
  * Represents options for difficulty calculation.
99
97
  */
100
- interface DifficultyCalculationOptions extends CalculationOptions {
98
+ interface DifficultyCalculationOptions {
101
99
  /**
102
100
  * The modifications to apply.
103
101
  */
104
- mods?: Mod[];
102
+ readonly mods?: Mod[];
103
+ /**
104
+ * The custom speed multiplier to apply. Defaults to 1.
105
+ */
106
+ readonly customSpeedMultiplier?: number;
105
107
  }
106
108
 
107
109
  /**
108
- * Represents an osu!standard hit object with difficulty calculation values.
110
+ * Represents a hit object with difficulty calculation values.
109
111
  */
110
- declare class DifficultyHitObject {
112
+ declare abstract class DifficultyHitObject {
111
113
  /**
112
114
  * The underlying hitobject.
113
115
  */
@@ -117,19 +119,7 @@ declare class DifficultyHitObject {
117
119
  *
118
120
  * This is one less than the actual index of the hitobject in the beatmap.
119
121
  */
120
- index: number;
121
- /**
122
- * The preempt time of the hitobject.
123
- */
124
- baseTimePreempt: number;
125
- /**
126
- * Adjusted preempt time of the hitobject, taking speed multiplier into account.
127
- */
128
- timePreempt: number;
129
- /**
130
- * The fade in time of the hitobject.
131
- */
132
- timeFadeIn: number;
122
+ readonly index: number;
133
123
  /**
134
124
  * The aim strain generated by the hitobject if sliders are considered.
135
125
  */
@@ -138,41 +128,10 @@ declare class DifficultyHitObject {
138
128
  * The aim strain generated by the hitobject if sliders are not considered.
139
129
  */
140
130
  aimStrainWithoutSliders: number;
141
- /**
142
- * The tap strain generated by the hitobject.
143
- *
144
- * This is also used for osu!standard as opposed to "speed strain".
145
- */
146
- tapStrain: number;
147
- /**
148
- * The tap strain generated by the hitobject if `strainTime` isn't modified by
149
- * OD. This is used in three-finger detection.
150
- */
151
- originalTapStrain: number;
152
131
  /**
153
132
  * The rhythm multiplier generated by the hitobject. This is used to alter tap strain.
154
133
  */
155
134
  rhythmMultiplier: number;
156
- /**
157
- * The rhythm strain generated by the hitobject.
158
- */
159
- rhythmStrain: number;
160
- /**
161
- * The flashlight strain generated by the hitobject if sliders are considered.
162
- */
163
- flashlightStrainWithSliders: number;
164
- /**
165
- * The flashlight strain generated by the hitobject if sliders are not considered.
166
- */
167
- flashlightStrainWithoutSliders: number;
168
- /**
169
- * The visual strain generated by the hitobject if sliders are considered.
170
- */
171
- visualStrainWithSliders: number;
172
- /**
173
- * The visual strain generated by the hitobject if sliders are not considered.
174
- */
175
- visualStrainWithoutSliders: number;
176
135
  /**
177
136
  * The normalized distance from the "lazy" end position of the previous hitobject to the start position of this hitobject.
178
137
  *
@@ -213,42 +172,56 @@ declare class DifficultyHitObject {
213
172
  /**
214
173
  * The amount of milliseconds elapsed between this hitobject and the last hitobject.
215
174
  */
216
- deltaTime: number;
175
+ readonly deltaTime: number;
217
176
  /**
218
177
  * The amount of milliseconds elapsed since the start time of the previous hitobject, with a minimum of 25ms.
219
178
  */
220
- strainTime: number;
179
+ readonly strainTime: number;
221
180
  /**
222
181
  * Adjusted start time of the hitobject, taking speed multiplier into account.
223
182
  */
224
- startTime: number;
183
+ readonly startTime: number;
225
184
  /**
226
185
  * Adjusted end time of the hitobject, taking speed multiplier into account.
227
186
  */
228
- endTime: number;
187
+ readonly endTime: number;
229
188
  /**
230
- * The note density of the hitobject.
189
+ * The full great window of the hitobject.
231
190
  */
232
- noteDensity: number;
191
+ readonly fullGreatWindow: number;
233
192
  /**
234
- * The overlapping factor of the hitobject.
235
- *
236
- * This is used to scale visual skill.
193
+ * Other hitobjects in the beatmap, including this hitobject.
237
194
  */
238
- overlappingFactor: number;
195
+ protected readonly hitObjects: readonly DifficultyHitObject[];
196
+ protected abstract readonly mode: Modes;
197
+ protected readonly normalizedRadius = 50;
198
+ protected readonly maximumSliderRadius: number;
199
+ protected readonly assumedSliderRadius: number;
239
200
  /**
240
- * Adjusted velocity of the hitobject, taking speed multiplier into account.
201
+ * The lowest possible delta time value.
241
202
  */
242
- velocity: number;
203
+ static readonly minDeltaTime = 25;
204
+ private readonly lastObject;
205
+ private readonly lastLastObject;
243
206
  /**
244
- * Other hitobjects in the beatmap, including this hitobject.
207
+ * Note: You **must** call `computeProperties` at some point due to how TypeScript handles
208
+ * overridden properties (see [this](https://github.com/microsoft/TypeScript/issues/1617) GitHub issue).
209
+ *
210
+ * @param object The underlying hitobject.
211
+ * @param lastObject The hitobject before this hitobject.
212
+ * @param lastLastObject The hitobject before the last hitobject.
213
+ * @param difficultyHitObjects All difficulty hitobjects in the processed beatmap.
214
+ * @param clockRate The clock rate of the beatmap.
215
+ * @param greatWindow The great window of the hitobject.
245
216
  */
246
- private readonly hitObjects;
217
+ constructor(object: PlaceableHitObject, lastObject: PlaceableHitObject | null, lastLastObject: PlaceableHitObject | null, difficultyHitObjects: readonly DifficultyHitObject[], clockRate: number, greatWindow: number);
247
218
  /**
248
- * @param object The underlying hitobject.
249
- * @param hitObjects All difficulty hitobjects in the processed beatmap.
219
+ * Computes the properties of this hitobject.
220
+ *
221
+ * @param clockRate The clock rate of the beatmap.
222
+ * @param hitObjects The hitobjects in the beatmap.
250
223
  */
251
- constructor(object: PlaceableHitObject, hitObjects: DifficultyHitObject[]);
224
+ computeProperties(clockRate: number, hitObjects: readonly PlaceableHitObject[]): void;
252
225
  /**
253
226
  * Gets the difficulty hitobject at a specific index with respect to the current
254
227
  * difficulty hitobject's index.
@@ -259,7 +232,7 @@ declare class DifficultyHitObject {
259
232
  * @returns The difficulty hitobject at the index with respect to the current
260
233
  * difficulty hitobject's index, `null` if the index is out of range.
261
234
  */
262
- previous(backwardsIndex: number): DifficultyHitObject | null;
235
+ previous(backwardsIndex: number): this | null;
263
236
  /**
264
237
  * Gets the difficulty hitobject at a specific index with respect to the current
265
238
  * difficulty hitobject's index.
@@ -270,26 +243,48 @@ declare class DifficultyHitObject {
270
243
  * @returns The difficulty hitobject at the index with respect to the current
271
244
  * difficulty hitobject's index, `null` if the index is out of range.
272
245
  */
273
- next(forwardsIndex: number): DifficultyHitObject | null;
246
+ next(forwardsIndex: number): this | null;
274
247
  /**
275
248
  * Calculates the opacity of the hitobject at a given time.
276
249
  *
277
250
  * @param time The time to calculate the hitobject's opacity at.
278
251
  * @param isHidden Whether Hidden mod is used.
279
- * @param mode The gamemode to calculate the opacity for.
280
252
  * @returns The opacity of the hitobject at the given time.
281
253
  */
282
- opacityAt(time: number, isHidden: boolean, mode: Modes): number;
254
+ opacityAt(time: number, isHidden: boolean): number;
283
255
  /**
284
- * Determines whether this hitobject is considered overlapping with the hitobject before it.
256
+ * How possible is it to doubletap this object together with the next one and get perfect
257
+ * judgement in range from 0 to 1.
285
258
  *
286
- * Keep in mind that "overlapping" in this case is overlapping to the point where both hitobjects
287
- * can be hit with just a single tap in osu!droid.
288
- *
289
- * @param considerDistance Whether to consider the distance between both hitobjects.
290
- * @returns Whether the hitobject is considered overlapping.
259
+ * A value closer to 1 indicates a higher possibility.
291
260
  */
292
- isOverlapping(considerDistance: boolean): boolean;
261
+ get doubletapness(): number;
262
+ protected abstract get scalingFactor(): number;
263
+ protected setDistances(clockRate: number): void;
264
+ private calculateSliderCursorPosition;
265
+ private getEndCursorPosition;
266
+ }
267
+
268
+ /**
269
+ * Represents the strain peaks of various calculated difficulties.
270
+ */
271
+ interface StrainPeaks {
272
+ /**
273
+ * The strain peaks of aim difficulty if sliders are considered.
274
+ */
275
+ aimWithSliders: number[];
276
+ /**
277
+ * The strain peaks of aim difficulty if sliders are not considered.
278
+ */
279
+ aimWithoutSliders: number[];
280
+ /**
281
+ * The strain peaks of speed difficulty.
282
+ */
283
+ speed: number[];
284
+ /**
285
+ * The strain peaks of flashlight difficulty.
286
+ */
287
+ flashlight: number[];
293
288
  }
294
289
 
295
290
  /**
@@ -316,103 +311,9 @@ declare abstract class Skill {
316
311
  }
317
312
 
318
313
  /**
319
- * Used to processes strain values of difficulty hitobjects, keep track of strain levels caused by the processed objects
320
- * and to calculate a final difficulty value representing the difficulty of hitting all the processed objects.
314
+ * The base of a difficulty calculator.
321
315
  */
322
- declare abstract class StrainSkill extends Skill {
323
- /**
324
- * The strain of currently calculated hitobject.
325
- */
326
- protected currentStrain: number;
327
- /**
328
- * The current section's strain peak.
329
- */
330
- protected currentSectionPeak: number;
331
- /**
332
- * Strain peaks are stored here.
333
- */
334
- readonly strainPeaks: number[];
335
- /**
336
- * The number of sections with the highest strains, which the peak strain reductions will apply to.
337
- * This is done in order to decrease their impact on the overall difficulty of the map for this skill.
338
- */
339
- protected abstract readonly reducedSectionCount: number;
340
- /**
341
- * The baseline multiplier applied to the section with the biggest strain.
342
- */
343
- protected abstract readonly reducedSectionBaseline: number;
344
- /**
345
- * Strain values are multiplied by this number for the given skill. Used to balance the value of different skills between each other.
346
- */
347
- protected abstract readonly skillMultiplier: number;
348
- /**
349
- * Determines how quickly strain decays for the given skill.
350
- *
351
- * For example, a value of 0.15 indicates that strain decays to 15% of its original value in one second.
352
- */
353
- protected abstract readonly strainDecayBase: number;
354
- private readonly sectionLength;
355
- private currentSectionEnd;
356
- private isFirstObject;
357
- /**
358
- * Calculates the strain value of a hitobject and stores the value in it. This value is affected by previously processed objects.
359
- *
360
- * @param current The hitobject to process.
361
- */
362
- process(current: DifficultyHitObject): void;
363
- /**
364
- * Saves the current peak strain level to the list of strain peaks, which will be used to calculate an overall difficulty.
365
- */
366
- saveCurrentPeak(): void;
367
- /**
368
- * Calculates strain decay for a specified time frame.
369
- *
370
- * @param ms The time frame to calculate.
371
- */
372
- protected strainDecay(ms: number): number;
373
- /**
374
- * Calculates the strain value at a hitobject.
375
- */
376
- protected abstract strainValueAt(current: DifficultyHitObject): number;
377
- /**
378
- * Saves the current strain to a hitobject.
379
- */
380
- protected abstract saveToHitObject(current: DifficultyHitObject): void;
381
- /**
382
- * Sets the initial strain level for a new section.
383
- *
384
- * @param offset The beginning of the new section in milliseconds, adjusted by speed multiplier.
385
- * @param current The current hitobject.
386
- */
387
- private startNewSectionFrom;
388
- }
389
-
390
- /**
391
- * Represents the strain peaks of various calculated difficulties.
392
- */
393
- interface StrainPeaks {
394
- /**
395
- * The strain peaks of aim difficulty if sliders are considered.
396
- */
397
- aimWithSliders: number[];
398
- /**
399
- * The strain peaks of aim difficulty if sliders are not considered.
400
- */
401
- aimWithoutSliders: number[];
402
- /**
403
- * The strain peaks of speed difficulty.
404
- */
405
- speed: number[];
406
- /**
407
- * The strain peaks of flashlight difficulty.
408
- */
409
- flashlight: number[];
410
- }
411
-
412
- /**
413
- * The base of difficulty calculators.
414
- */
415
- declare abstract class DifficultyCalculator {
316
+ declare abstract class DifficultyCalculator<THitObject extends DifficultyHitObject, TAttributes extends DifficultyAttributes> {
416
317
  /**
417
318
  * The calculated beatmap.
418
319
  */
@@ -420,7 +321,11 @@ declare abstract class DifficultyCalculator {
420
321
  /**
421
322
  * The difficulty objects of the beatmap.
422
323
  */
423
- readonly objects: DifficultyHitObject[];
324
+ private _objects;
325
+ /**
326
+ * The difficulty objects of the beatmap.
327
+ */
328
+ get objects(): readonly THitObject[];
424
329
  /**
425
330
  * The modifications applied.
426
331
  */
@@ -428,26 +333,25 @@ declare abstract class DifficultyCalculator {
428
333
  /**
429
334
  * The total star rating of the beatmap.
430
335
  */
431
- total: number;
432
- /**
433
- * The map statistics of the beatmap after modifications are applied.
434
- */
435
- stats: MapStats;
336
+ get total(): number;
436
337
  /**
437
338
  * The strain peaks of various calculated difficulties.
438
339
  */
439
340
  readonly strainPeaks: StrainPeaks;
440
341
  /**
441
- * Holds data that can be used to calculate performance points.
342
+ * The difficulty attributes that can be used to calculate performance points.
343
+ */
344
+ abstract readonly attributes: TAttributes;
345
+ /**
346
+ * The difficulty attributes that can be cached. It can also be used to calculate performance points.
442
347
  */
443
- abstract readonly attributes: DifficultyAttributes;
444
- protected readonly sectionLength: number;
348
+ abstract get cacheableAttributes(): CacheableDifficultyAttributes<TAttributes>;
445
349
  protected abstract readonly difficultyMultiplier: number;
446
350
  protected abstract readonly mode: Modes;
447
351
  /**
448
352
  * Constructs a new instance of the calculator.
449
353
  *
450
- * @param beatmap The beatmap to calculate. This beatmap will be deep-cloned to prevent reference changes.
354
+ * @param beatmap The beatmap to calculate.
451
355
  */
452
356
  constructor(beatmap: Beatmap);
453
357
  /**
@@ -468,14 +372,17 @@ declare abstract class DifficultyCalculator {
468
372
  calculate(options?: DifficultyCalculationOptions): this;
469
373
  /**
470
374
  * Generates difficulty hitobjects for this calculator.
375
+ *
376
+ * @param beatmap The beatmap to generate difficulty hitobjects from.
377
+ * @param clockRate The clock rate of the beatmap.
471
378
  */
472
- generateDifficultyHitObjects(): void;
379
+ protected abstract generateDifficultyHitObjects(beatmap: Beatmap, clockRate: number): THitObject[];
473
380
  /**
474
381
  * Calculates the skills provided.
475
382
  *
476
383
  * @param skills The skills to calculate.
477
384
  */
478
- protected calculateSkills(...skills: StrainSkill[]): void;
385
+ protected calculateSkills(...skills: Skill[]): void;
479
386
  /**
480
387
  * Calculates the total star rating of the beatmap and stores it in this instance.
481
388
  */
@@ -491,11 +398,21 @@ declare abstract class DifficultyCalculator {
491
398
  /**
492
399
  * Creates skills to be calculated.
493
400
  */
494
- protected abstract createSkills(): StrainSkill[];
401
+ protected abstract createSkills(): Skill[];
402
+ /**
403
+ * Obtains the clock rate of the beatmap.
404
+ *
405
+ * @param options The options to obtain the clock rate with.
406
+ * @returns The clock rate of the beatmap.
407
+ */
408
+ protected calculateClockRate(options?: DifficultyCalculationOptions): number;
495
409
  /**
496
410
  * Populates the stored difficulty attributes with necessary data.
411
+ *
412
+ * @param beatmap The beatmap to populate the attributes with.
413
+ * @param clockRate The clock rate of the beatmap.
497
414
  */
498
- protected populateDifficultyAttributes(): void;
415
+ protected populateDifficultyAttributes(beatmap: Beatmap, clockRate: number): void;
499
416
  /**
500
417
  * Calculates the star rating value of a difficulty.
501
418
  *
@@ -511,120 +428,241 @@ declare abstract class DifficultyCalculator {
511
428
  }
512
429
 
513
430
  /**
514
- * A converter used to convert normal hitobjects into difficulty hitobjects.
431
+ * Represents a slider that is considered difficult.
432
+ *
433
+ * This structure is a part of difficulty attributes and can be cached.
515
434
  */
516
- declare class DifficultyHitObjectCreator {
435
+ interface DifficultSlider {
436
+ /**
437
+ * The index of the slider in the beatmap.
438
+ */
439
+ readonly index: number;
517
440
  /**
518
- * The threshold for small circle buff for osu!droid.
441
+ * The difficulty rating of this slider compared to other sliders, based on the velocity of the slider.
442
+ *
443
+ * A value closer to 1 indicates that this slider is more difficult compared to most sliders.
444
+ *
445
+ * A value closer to 0 indicates that this slider is easier compared to most sliders.
519
446
  */
520
- private readonly DROID_CIRCLESIZE_BUFF_THRESHOLD;
447
+ readonly difficultyRating: number;
448
+ }
449
+
450
+ /**
451
+ * Used to processes strain values of difficulty hitobjects, keep track of strain levels caused by the processed objects
452
+ * and to calculate a final difficulty value representing the difficulty of hitting all the processed objects.
453
+ */
454
+ declare abstract class StrainSkill extends Skill {
521
455
  /**
522
- * The threshold for small circle buff for osu!standard.
456
+ * Strain peaks are stored here.
523
457
  */
524
- private readonly PC_CIRCLESIZE_BUFF_THRESHOLD;
458
+ readonly strainPeaks: number[];
525
459
  /**
526
- * The gamemode this creator is creating for.
460
+ * The number of sections with the highest strains, which the peak strain reductions will apply to.
461
+ * This is done in order to decrease their impact on the overall difficulty of the map for this skill.
527
462
  */
528
- private mode;
463
+ protected abstract readonly reducedSectionCount: number;
529
464
  /**
530
- * The base normalized radius of hitobjects.
465
+ * The baseline multiplier applied to the section with the biggest strain.
531
466
  */
532
- private readonly normalizedRadius;
533
- private maximumSliderRadius;
534
- private readonly assumedSliderRadius;
535
- private readonly minDeltaTime;
467
+ protected abstract readonly reducedSectionBaseline: number;
536
468
  /**
537
- * Generates difficulty hitobjects for difficulty calculation.
469
+ * Determines how quickly strain decays for the given skill.
470
+ *
471
+ * For example, a value of 0.15 indicates that strain decays to 15% of its original value in one second.
538
472
  */
539
- generateDifficultyObjects(params: {
540
- objects: readonly HitObject[];
541
- circleSize: number;
542
- mods: Mod[];
543
- speedMultiplier: number;
544
- mode: Modes;
545
- preempt?: number;
546
- }): DifficultyHitObject[];
473
+ protected abstract readonly strainDecayBase: number;
474
+ private readonly sectionLength;
475
+ private currentStrain;
476
+ private currentSectionPeak;
477
+ private currentSectionEnd;
478
+ process(current: DifficultyHitObject): void;
547
479
  /**
548
- * Calculates a slider's cursor position.
480
+ * Saves the current peak strain level to the list of strain peaks, which will be used to calculate an overall difficulty.
549
481
  */
550
- private calculateSliderCursorPosition;
482
+ saveCurrentPeak(): void;
551
483
  /**
552
- * Gets the scaling factor of a radius.
484
+ * Calculates strain decay for a specified time frame.
553
485
  *
554
- * @param radius The radius to get the scaling factor from.
486
+ * @param ms The time frame to calculate.
555
487
  */
556
- private getScalingFactor;
488
+ protected strainDecay(ms: number): number;
557
489
  /**
558
- * Returns the end cursor position of a hitobject.
490
+ * Calculates the starting time of a strain section at an object.
491
+ *
492
+ * @param current The object at which the strain section starts.
493
+ * @returns The start time of the strain section.
559
494
  */
560
- private getEndCursorPosition;
561
- private applyToOverlappingFactor;
495
+ protected calculateCurrentSectionStart(current: DifficultyHitObject): number;
496
+ /**
497
+ * Calculates the strain value at a hitobject.
498
+ *
499
+ * @param current The hitobject to calculate.
500
+ */
501
+ protected abstract strainValueAt(current: DifficultyHitObject): number;
502
+ /**
503
+ * Saves the current strain to a hitobject.
504
+ */
505
+ protected abstract saveToHitObject(current: DifficultyHitObject): void;
506
+ /**
507
+ * Retrieves the peak strain at a point in time.
508
+ *
509
+ * @param time The time to retrieve the peak strain at.
510
+ * @param current The current hit object.
511
+ * @returns The peak strain.
512
+ */
513
+ protected abstract calculateInitialStrain(time: number, current: DifficultyHitObject): number;
514
+ /**
515
+ * Sets the initial strain level for a new section.
516
+ *
517
+ * @param time The beginning of the new section in milliseconds.
518
+ * @param current The current hitobject.
519
+ */
520
+ private startNewSectionFrom;
562
521
  }
563
522
 
564
523
  /**
565
- * Represents a slider that is considered difficult.
566
- *
567
- * This structure is a part of difficulty attributes and can be cached.
524
+ * Used to processes strain values of difficulty hitobjects, keep track of strain levels caused by the processed objects
525
+ * and to calculate a final difficulty value representing the difficulty of hitting all the processed objects.
568
526
  */
569
- interface DifficultSlider {
527
+ declare abstract class DroidSkill extends StrainSkill {
528
+ /**
529
+ * The bonus multiplier that is given for a sequence of notes of equal difficulty.
530
+ */
531
+ protected abstract readonly starsPerDouble: number;
532
+ protected readonly _objectStrains: number[];
533
+ /**
534
+ * The strains of hitobjects.
535
+ */
536
+ get objectStrains(): readonly number[];
537
+ private difficulty;
538
+ /**
539
+ * Returns the number of strains weighed against the top strain.
540
+ *
541
+ * The result is scaled by clock rate as it affects the total number of strains.
542
+ */
543
+ countDifficultStrains(): number;
544
+ process(current: DifficultyHitObject): void;
545
+ difficultyValue(): number;
546
+ /**
547
+ * Gets the strain of a hitobject.
548
+ *
549
+ * @param current The hitobject to get the strain from.
550
+ * @returns The strain of the hitobject.
551
+ */
552
+ protected abstract getObjectStrain(current: DifficultyHitObject): number;
553
+ protected calculateCurrentSectionStart(current: DifficultyHitObject): number;
554
+ }
555
+
556
+ /**
557
+ * Represents an osu!droid hit object with difficulty calculation values.
558
+ */
559
+ declare class DroidDifficultyHitObject extends DifficultyHitObject {
560
+ /**
561
+ * The tap strain generated by the hitobject.
562
+ */
563
+ tapStrain: number;
564
+ /**
565
+ * The tap strain generated by the hitobject if `strainTime` isn't modified by
566
+ * OD. This is used in three-finger detection.
567
+ */
568
+ originalTapStrain: number;
569
+ /**
570
+ * The rhythm strain generated by the hitobject.
571
+ */
572
+ rhythmStrain: number;
573
+ /**
574
+ * The flashlight strain generated by the hitobject if sliders are considered.
575
+ */
576
+ flashlightStrainWithSliders: number;
577
+ /**
578
+ * The flashlight strain generated by the hitobject if sliders are not considered.
579
+ */
580
+ flashlightStrainWithoutSliders: number;
581
+ /**
582
+ * The visual strain generated by the hitobject if sliders are considered.
583
+ */
584
+ visualStrainWithSliders: number;
585
+ /**
586
+ * The visual strain generated by the hitobject if sliders are not considered.
587
+ */
588
+ visualStrainWithoutSliders: number;
589
+ /**
590
+ * The note density of the hitobject.
591
+ */
592
+ noteDensity: number;
593
+ /**
594
+ * The overlapping factor of the hitobject.
595
+ *
596
+ * This is used to scale visual skill.
597
+ */
598
+ overlappingFactor: number;
570
599
  /**
571
- * The index of the slider in the beatmap.
600
+ * Adjusted preempt time of the hitobject, taking speed multiplier into account.
572
601
  */
573
- readonly index: number;
602
+ readonly timePreempt: number;
603
+ private readonly radiusBuffThreshold;
604
+ protected readonly mode = Modes.droid;
605
+ protected readonly maximumSliderRadius: number;
606
+ protected get scalingFactor(): number;
574
607
  /**
575
- * The difficulty rating of this slider compared to other sliders, based on the velocity of the slider.
608
+ * Note: You **must** call `computeProperties` at some point due to how TypeScript handles
609
+ * overridden properties (see [this](https://github.com/microsoft/TypeScript/issues/1617) GitHub issue).
576
610
  *
577
- * A value closer to 1 indicates that this slider is more difficult compared to most sliders.
578
- *
579
- * A value closer to 0 indicates that this slider is easier compared to most sliders.
611
+ * @param object The underlying hitobject.
612
+ * @param lastObject The hitobject before this hitobject.
613
+ * @param lastLastObject The hitobject before the last hitobject.
614
+ * @param difficultyHitObjects All difficulty hitobjects in the processed beatmap.
615
+ * @param clockRate The clock rate of the beatmap.
616
+ * @param greatWindow The great window of the hitobject.
580
617
  */
581
- readonly difficultyRating: number;
582
- }
583
-
584
- /**
585
- * Used to processes strain values of difficulty hitobjects, keep track of strain levels caused by the processed objects
586
- * and to calculate a final difficulty value representing the difficulty of hitting all the processed objects.
587
- */
588
- declare abstract class DroidSkill extends StrainSkill {
618
+ constructor(object: PlaceableHitObject, lastObject: PlaceableHitObject | null, lastLastObject: PlaceableHitObject | null, difficultyHitObjects: readonly DifficultyHitObject[], clockRate: number, greatWindow: number);
619
+ computeProperties(clockRate: number, hitObjects: readonly PlaceableHitObject[]): void;
589
620
  /**
590
- * The bonus multiplier that is given for a sequence of notes of equal difficulty.
621
+ * Determines whether this hitobject is considered overlapping with the hitobject before it.
622
+ *
623
+ * Keep in mind that "overlapping" in this case is overlapping to the point where both hitobjects
624
+ * can be hit with just a single tap in osu!droid.
625
+ *
626
+ * In the case of sliders, it is considered overlapping if all nested hitobjects can be hit with
627
+ * one aim motion.
628
+ *
629
+ * @param considerDistance Whether to consider the distance between both hitobjects.
630
+ * @returns Whether the hitobject is considered overlapping.
591
631
  */
592
- protected abstract readonly starsPerDouble: number;
593
- difficultyValue(): number;
632
+ isOverlapping(considerDistance: boolean): boolean;
633
+ private setVisuals;
634
+ private applyToOverlappingFactor;
594
635
  }
595
636
 
596
637
  /**
597
638
  * Represents the skill required to correctly aim at every object in the map with a uniform CircleSize and normalized distances.
598
639
  */
599
640
  declare class DroidAim extends DroidSkill {
600
- protected readonly skillMultiplier: number;
601
- protected readonly strainDecayBase: number;
602
- protected readonly reducedSectionCount: number;
603
- protected readonly reducedSectionBaseline: number;
604
- protected readonly starsPerDouble: number;
641
+ protected readonly strainDecayBase = 0.15;
642
+ protected readonly reducedSectionCount = 10;
643
+ protected readonly reducedSectionBaseline = 0.75;
644
+ protected readonly starsPerDouble = 1.05;
645
+ private readonly skillMultiplier;
605
646
  private readonly withSliders;
647
+ private currentAimStrain;
606
648
  constructor(mods: Mod[], withSliders: boolean);
607
- /**
608
- * @param current The hitobject to calculate.
609
- */
610
- protected strainValueAt(current: DifficultyHitObject): number;
649
+ protected strainValueAt(current: DroidDifficultyHitObject): number;
650
+ protected calculateInitialStrain(time: number, current: DroidDifficultyHitObject): number;
651
+ protected getObjectStrain(): number;
611
652
  /**
612
653
  * @param current The hitobject to save to.
613
654
  */
614
- protected saveToHitObject(current: DifficultyHitObject): void;
655
+ protected saveToHitObject(current: DroidDifficultyHitObject): void;
615
656
  }
616
657
 
617
658
  /**
618
659
  * An evaluator for calculating osu!droid Aim skill.
619
660
  */
620
661
  declare abstract class DroidAimEvaluator extends AimEvaluator {
621
- protected static readonly wideAngleMultiplier: number;
622
- protected static readonly sliderMultiplier: number;
623
- protected static readonly velocityChangeMultiplier: number;
624
- /**
625
- * Spacing threshold for a single hitobject spacing.
626
- */
627
- private static readonly SINGLE_SPACING_THRESHOLD;
662
+ protected static readonly wideAngleMultiplier = 1.65;
663
+ protected static readonly sliderMultiplier = 1.5;
664
+ protected static readonly velocityChangeMultiplier = 0.85;
665
+ private static readonly singleSpacingThreshold;
628
666
  private static readonly minSpeedBonus;
629
667
  /**
630
668
  * Evaluates the difficulty of aiming the current object, based on:
@@ -637,15 +675,15 @@ declare abstract class DroidAimEvaluator extends AimEvaluator {
637
675
  * @param current The current object.
638
676
  * @param withSliders Whether to take slider difficulty into account.
639
677
  */
640
- static evaluateDifficultyOf(current: DifficultyHitObject, withSliders: boolean): number;
678
+ static evaluateDifficultyOf(current: DroidDifficultyHitObject, withSliders: boolean): number;
641
679
  /**
642
- * Calculates the aim strain of a hitobject.
680
+ * Calculates the snap aim strain of a hitobject.
643
681
  */
644
- private static aimStrainOf;
682
+ private static snapAimStrainOf;
645
683
  /**
646
- * Calculates the movement strain of a hitobject.
684
+ * Calculates the flow aim strain of a hitobject.
647
685
  */
648
- private static movementStrainOf;
686
+ private static flowAimStrainOf;
649
687
  }
650
688
 
651
689
  /**
@@ -664,6 +702,44 @@ interface DroidDifficultyAttributes extends DifficultyAttributes {
664
702
  * The difficulty corresponding to the visual skill.
665
703
  */
666
704
  visualDifficulty: number;
705
+ /**
706
+ * The amount of strains that are considered difficult with respect to the aim skill.
707
+ */
708
+ aimDifficultStrainCount: number;
709
+ /**
710
+ * The amount of strains that are considered difficult with respect to the tap skill.
711
+ */
712
+ tapDifficultStrainCount: number;
713
+ /**
714
+ * The amount of strains that are considered difficult with respect to the flashlight skill.
715
+ */
716
+ flashlightDifficultStrainCount: number;
717
+ /**
718
+ * The amount of strains that are considered difficult with respect to the visual skill.
719
+ */
720
+ visualDifficultStrainCount: number;
721
+ /**
722
+ * The average delta time of speed objects.
723
+ */
724
+ averageSpeedDeltaTime: number;
725
+ /**
726
+ * Describes how much of tap difficulty is contributed by notes that are "vibroable".
727
+ *
728
+ * A value closer to 1 indicates most of tap difficulty is contributed by notes that are not "vibroable".
729
+ *
730
+ * A value closer to 0 indicates most of tap difficulty is contributed by notes that are "vibroable".
731
+ */
732
+ vibroFactor: number;
733
+ }
734
+
735
+ /**
736
+ * Represents options for osu!droid difficulty calculation.
737
+ */
738
+ interface DroidDifficultyCalculationOptions extends DifficultyCalculationOptions {
739
+ /**
740
+ * Whether to calculate for old statistics (1.6.7 and older). Defaults to `false`.
741
+ */
742
+ readonly oldStatistics?: boolean;
667
743
  }
668
744
 
669
745
  /**
@@ -689,6 +765,10 @@ interface HighStrainSection {
689
765
  * as doing some analysis using the replay of a score.
690
766
  */
691
767
  interface ExtendedDroidDifficultyAttributes extends DroidDifficultyAttributes {
768
+ /**
769
+ * The mode of the difficulty calculation.
770
+ */
771
+ mode: "live";
692
772
  /**
693
773
  * Possible sections at which the player can use three fingers on.
694
774
  */
@@ -724,36 +804,38 @@ interface ExtendedDroidDifficultyAttributes extends DroidDifficultyAttributes {
724
804
  /**
725
805
  * A difficulty calculator for osu!droid gamemode.
726
806
  */
727
- declare class DroidDifficultyCalculator extends DifficultyCalculator {
807
+ declare class DroidDifficultyCalculator extends DifficultyCalculator<DroidDifficultyHitObject, DroidDifficultyAttributes> {
728
808
  /**
729
809
  * The aim star rating of the beatmap.
730
810
  */
731
- aim: number;
811
+ get aim(): number;
732
812
  /**
733
813
  * The tap star rating of the beatmap.
734
814
  */
735
- tap: number;
815
+ get tap(): number;
736
816
  /**
737
817
  * The rhythm star rating of the beatmap.
738
818
  */
739
- rhythm: number;
819
+ get rhythm(): number;
740
820
  /**
741
821
  * The flashlight star rating of the beatmap.
742
822
  */
743
- flashlight: number;
823
+ get flashlight(): number;
744
824
  /**
745
825
  * The visual star rating of the beatmap.
746
826
  */
747
- visual: number;
827
+ get visual(): number;
748
828
  /**
749
829
  * The strain threshold to start detecting for possible three-fingered section.
750
830
  *
751
831
  * Increasing this number will result in less sections being flagged.
752
832
  */
753
- static readonly threeFingerStrainThreshold: number;
833
+ static readonly threeFingerStrainThreshold = 175;
754
834
  readonly attributes: ExtendedDroidDifficultyAttributes;
755
- protected readonly difficultyMultiplier: number;
756
- protected readonly mode: Modes;
835
+ get cacheableAttributes(): CacheableDifficultyAttributes<DroidDifficultyAttributes>;
836
+ protected readonly difficultyMultiplier = 0.18;
837
+ protected readonly mode = Modes.droid;
838
+ calculate(options?: DroidDifficultyCalculationOptions): this;
757
839
  /**
758
840
  * Calculates the aim star rating of the beatmap and stores it in this instance.
759
841
  */
@@ -776,14 +858,10 @@ declare class DroidDifficultyCalculator extends DifficultyCalculator {
776
858
  calculateVisual(): void;
777
859
  calculateTotal(): void;
778
860
  calculateAll(): void;
779
- /**
780
- * Returns a string representative of the class.
781
- */
782
861
  toString(): string;
783
- /**
784
- * Creates skills to be calculated.
785
- */
862
+ protected generateDifficultyHitObjects(beatmap: Beatmap, clockRate: number): DroidDifficultyHitObject[];
786
863
  protected createSkills(): DroidSkill[];
864
+ protected calculateClockRate(options?: DroidDifficultyCalculationOptions): number;
787
865
  /**
788
866
  * Called after aim skill calculation.
789
867
  *
@@ -798,21 +876,14 @@ declare class DroidDifficultyCalculator extends DifficultyCalculator {
798
876
  /**
799
877
  * Called after tap skill calculation.
800
878
  *
801
- * @param tapSkill The tap skill.
879
+ * @param tapSkillCheese The tap skill that considers cheesing.
880
+ * @param tapSkillVibro The tap skill that considers vibro.
802
881
  */
803
882
  private postCalculateTap;
804
883
  /**
805
- * Calculates speed-related attributes.
806
- */
807
- private calculateSpeedAttributes;
808
- /**
809
- * Calculates the sum of strains for possible three-fingered sections.
810
- *
811
- * @param firstObjectIndex The index of the first object in the section.
812
- * @param lastObjectIndex The index of the last object in the section.
813
- * @returns The summed strain of the section.
884
+ * Calculates tap-related attributes.
814
885
  */
815
- private calculateThreeFingerSummedStrain;
886
+ private calculateTapAttributes;
816
887
  /**
817
888
  * Called after rhythm skill calculation.
818
889
  *
@@ -839,19 +910,20 @@ declare class DroidDifficultyCalculator extends DifficultyCalculator {
839
910
  * Represents the skill required to memorize and hit every object in a beatmap with the Flashlight mod enabled.
840
911
  */
841
912
  declare class DroidFlashlight extends DroidSkill {
842
- protected readonly skillMultiplier: number;
843
- protected readonly strainDecayBase: number;
844
- protected readonly reducedSectionCount: number;
845
- protected readonly reducedSectionBaseline: number;
846
- protected readonly starsPerDouble: number;
913
+ protected readonly strainDecayBase = 0.15;
914
+ protected readonly reducedSectionCount = 0;
915
+ protected readonly reducedSectionBaseline = 1;
916
+ protected readonly starsPerDouble = 1.06;
917
+ private readonly skillMultiplier;
847
918
  private readonly isHidden;
848
919
  private readonly withSliders;
920
+ private currentFlashlightStrain;
849
921
  constructor(mods: Mod[], withSliders: boolean);
850
- /**
851
- * @param current The hitobject to calculate.
852
- */
853
- protected strainValueAt(current: DifficultyHitObject): number;
854
- protected saveToHitObject(current: DifficultyHitObject): void;
922
+ protected strainValueAt(current: DroidDifficultyHitObject): number;
923
+ protected calculateInitialStrain(time: number, current: DifficultyHitObject): number;
924
+ protected getObjectStrain(): number;
925
+ protected saveToHitObject(current: DroidDifficultyHitObject): void;
926
+ difficultyValue(): number;
855
927
  }
856
928
 
857
929
  /**
@@ -884,7 +956,7 @@ declare abstract class DroidFlashlightEvaluator extends FlashlightEvaluator {
884
956
  * @param isHiddenMod Whether the Hidden mod is enabled.
885
957
  * @param withSliders Whether to take slider difficulty into account.
886
958
  */
887
- static evaluateDifficultyOf(current: DifficultyHitObject, isHiddenMod: boolean, withSliders: boolean): number;
959
+ static evaluateDifficultyOf(current: DroidDifficultyHitObject, isHiddenMod: boolean, withSliders: boolean): number;
888
960
  }
889
961
 
890
962
  /**
@@ -924,7 +996,7 @@ interface PerformanceCalculationOptions {
924
996
  /**
925
997
  * The base class of performance calculators.
926
998
  */
927
- declare abstract class PerformanceCalculator {
999
+ declare abstract class PerformanceCalculator<T extends DifficultyAttributes> {
928
1000
  /**
929
1001
  * The overall performance value.
930
1002
  */
@@ -936,7 +1008,7 @@ declare abstract class PerformanceCalculator {
936
1008
  /**
937
1009
  * The difficulty attributes that is being calculated.
938
1010
  */
939
- abstract readonly difficultyAttributes: DifficultyAttributes;
1011
+ readonly difficultyAttributes: T;
940
1012
  /**
941
1013
  * Penalty for combo breaks.
942
1014
  */
@@ -959,6 +1031,10 @@ declare abstract class PerformanceCalculator {
959
1031
  * Nerf factor used for nerfing beatmaps with very likely dropped sliderends.
960
1032
  */
961
1033
  protected sliderNerfFactor: number;
1034
+ /**
1035
+ * @param difficultyAttributes The difficulty attributes to calculate.
1036
+ */
1037
+ constructor(difficultyAttributes: T | CacheableDifficultyAttributes<T>);
962
1038
  /**
963
1039
  * Calculates the performance points of the beatmap.
964
1040
  *
@@ -978,7 +1054,7 @@ declare abstract class PerformanceCalculator {
978
1054
  /**
979
1055
  * Calculates the total performance value of the beatmap and stores it in this instance.
980
1056
  */
981
- protected abstract calculateTotalValue(): void;
1057
+ protected abstract calculateTotalValue(): number;
982
1058
  /**
983
1059
  * The total hits that can be done in the beatmap.
984
1060
  */
@@ -1001,12 +1077,19 @@ declare abstract class PerformanceCalculator {
1001
1077
  * Calculates the amount of misses + sliderbreaks from combo.
1002
1078
  */
1003
1079
  private calculateEffectiveMissCount;
1080
+ /**
1081
+ * Determines whether an attribute is a cacheable attribute.
1082
+ *
1083
+ * @param attributes The attributes to check.
1084
+ * @returns Whether the attributes are cacheable.
1085
+ */
1086
+ private isCacheableAttribute;
1004
1087
  }
1005
1088
 
1006
1089
  /**
1007
1090
  * A performance points calculator that calculates performance points for osu!droid gamemode.
1008
1091
  */
1009
- declare class DroidPerformanceCalculator extends PerformanceCalculator {
1092
+ declare class DroidPerformanceCalculator extends PerformanceCalculator<DroidDifficultyAttributes> {
1010
1093
  /**
1011
1094
  * The aim performance value.
1012
1095
  */
@@ -1059,19 +1142,14 @@ declare class DroidPerformanceCalculator extends PerformanceCalculator {
1059
1142
  * Can be properly obtained by analyzing the replay associated with the score.
1060
1143
  */
1061
1144
  get visualSliderCheesePenalty(): number;
1062
- readonly difficultyAttributes: DroidDifficultyAttributes;
1063
1145
  protected finalMultiplier: number;
1064
- protected readonly mode: Modes;
1146
+ protected readonly mode = Modes.droid;
1065
1147
  private _aimSliderCheesePenalty;
1066
1148
  private _flashlightSliderCheesePenalty;
1067
1149
  private _visualSliderCheesePenalty;
1068
1150
  private _tapPenalty;
1069
1151
  private _deviation;
1070
1152
  private _tapDeviation;
1071
- /**
1072
- * @param difficultyAttributes The difficulty attributes to calculate.
1073
- */
1074
- constructor(difficultyAttributes: DroidDifficultyAttributes);
1075
1153
  /**
1076
1154
  * Applies a tap penalty value to this calculator.
1077
1155
  *
@@ -1105,7 +1183,7 @@ declare class DroidPerformanceCalculator extends PerformanceCalculator {
1105
1183
  */
1106
1184
  applyVisualSliderCheesePenalty(value: number): void;
1107
1185
  protected calculateValues(): void;
1108
- protected calculateTotalValue(): void;
1186
+ protected calculateTotalValue(): number;
1109
1187
  protected handleOptions(options?: PerformanceCalculationOptions): void;
1110
1188
  /**
1111
1189
  * Calculates the aim performance value of the beatmap.
@@ -1127,6 +1205,27 @@ declare class DroidPerformanceCalculator extends PerformanceCalculator {
1127
1205
  * Calculates the visual performance value of the beatmap.
1128
1206
  */
1129
1207
  private calculateVisualValue;
1208
+ /**
1209
+ * Calculates a strain-based miss penalty.
1210
+ *
1211
+ * Strain-based miss penalty assumes that a player will miss on the hardest parts of a map,
1212
+ * so we use the amount of relatively difficult sections to adjust miss penalty
1213
+ * to make it more punishing on maps with lower amount of hard sections.
1214
+ */
1215
+ private calculateStrainBasedMissPenalty;
1216
+ /**
1217
+ * The object-based proportional miss penalty.
1218
+ */
1219
+ private get proportionalMissPenalty();
1220
+ /**
1221
+ * Calculates the object-based length scaling based on the deviation of a player for a full
1222
+ * combo in this beatmap, taking retries into account.
1223
+ *
1224
+ * @param objectCount The amount of objects to be considered. Defaults to the amount of
1225
+ * objects in this beatmap.
1226
+ * @param punishForMemorization Whether to punish the deviation for memorization. Defaults to `false`.
1227
+ */
1228
+ private calculateDeviationBasedLengthScaling;
1130
1229
  /**
1131
1230
  * Estimates the player's tap deviation based on the OD, number of circles and sliders,
1132
1231
  * and number of 300s, 100s, 50s, and misses, assuming the player's mean hit error is 0.
@@ -1156,63 +1255,69 @@ declare class DroidPerformanceCalculator extends PerformanceCalculator {
1156
1255
  * Represents the skill required to properly follow a beatmap's rhythm.
1157
1256
  */
1158
1257
  declare class DroidRhythm extends DroidSkill {
1159
- protected readonly skillMultiplier: number;
1160
- protected readonly reducedSectionCount: number;
1161
- protected readonly reducedSectionBaseline: number;
1162
- protected readonly strainDecayBase: number;
1163
- protected readonly starsPerDouble: number;
1164
- private currentRhythm;
1165
- private readonly hitWindow;
1166
- constructor(mods: Mod[], overallDifficulty: number);
1167
- protected strainValueAt(current: DifficultyHitObject): number;
1168
- protected saveToHitObject(current: DifficultyHitObject): void;
1169
- }
1170
-
1171
- /**
1172
- * An evaluator for calculating rhythm skill.
1173
- *
1174
- * This class should be considered an "evaluating" class and not persisted.
1175
- */
1176
- declare abstract class RhythmEvaluator {
1177
- protected static readonly rhythmMultiplier: number;
1178
- protected static readonly historyTimeMax: number;
1258
+ protected readonly reducedSectionCount = 5;
1259
+ protected readonly reducedSectionBaseline = 0.75;
1260
+ protected readonly strainDecayBase = 0.3;
1261
+ protected readonly starsPerDouble = 1.75;
1262
+ private currentRhythmStrain;
1263
+ private currentRhythmMultiplier;
1264
+ protected strainValueAt(current: DroidDifficultyHitObject): number;
1265
+ protected calculateInitialStrain(time: number, current: DroidDifficultyHitObject): number;
1266
+ protected getObjectStrain(): number;
1267
+ protected saveToHitObject(current: DroidDifficultyHitObject): void;
1179
1268
  }
1180
1269
 
1181
1270
  /**
1182
1271
  * An evaluator for calculating osu!droid Rhythm skill.
1183
1272
  */
1184
- declare abstract class DroidRhythmEvaluator extends RhythmEvaluator {
1273
+ declare abstract class DroidRhythmEvaluator {
1274
+ private static readonly historyTimeMax;
1275
+ private static readonly historyObjectsMax;
1276
+ private static readonly rhythmOverallMultiplier;
1277
+ private static readonly rhythmRatioMultiplier;
1185
1278
  /**
1186
1279
  * Calculates a rhythm multiplier for the difficulty of the tap associated
1187
1280
  * with historic data of the current object.
1188
1281
  *
1189
1282
  * @param current The current object.
1190
- * @param greatWindow The great hit window of the current object.
1191
1283
  */
1192
- static evaluateDifficultyOf(current: DifficultyHitObject, greatWindow: number): number;
1284
+ static evaluateDifficultyOf(current: DroidDifficultyHitObject): number;
1193
1285
  }
1194
1286
 
1195
1287
  /**
1196
1288
  * Represents the skill required to press keys or tap with regards to keeping up with the speed at which objects need to be hit.
1197
1289
  */
1198
1290
  declare class DroidTap extends DroidSkill {
1199
- protected readonly skillMultiplier: number;
1200
- protected readonly reducedSectionCount: number;
1201
- protected readonly reducedSectionBaseline: number;
1202
- protected readonly strainDecayBase: number;
1203
- protected readonly starsPerDouble: number;
1291
+ protected readonly reducedSectionCount = 10;
1292
+ protected readonly reducedSectionBaseline = 0.75;
1293
+ protected readonly strainDecayBase = 0.3;
1294
+ protected readonly starsPerDouble = 1.1;
1204
1295
  private currentTapStrain;
1205
- private currentOriginalTapStrain;
1206
- private readonly greatWindow;
1207
- constructor(mods: Mod[], overallDifficulty: number);
1296
+ private currentRhythmMultiplier;
1297
+ private readonly skillMultiplier;
1298
+ private readonly considerCheesability;
1299
+ private readonly strainTimeCap?;
1300
+ private readonly _objectDeltaTimes;
1208
1301
  /**
1209
- * @param current The hitobject to calculate.
1302
+ * The delta time of hitobjects.
1303
+ */
1304
+ get objectDeltaTimes(): readonly number[];
1305
+ constructor(mods: Mod[], considerCheesability: boolean, strainTimeCap?: number);
1306
+ /**
1307
+ * The amount of notes that are relevant to the difficulty.
1308
+ */
1309
+ relevantNoteCount(): number;
1310
+ /**
1311
+ * The delta time relevant to the difficulty.
1210
1312
  */
1211
- protected strainValueAt(current: DifficultyHitObject): number;
1313
+ relevantDeltaTime(): number;
1314
+ protected strainValueAt(current: DroidDifficultyHitObject): number;
1315
+ protected calculateInitialStrain(time: number, current: DroidDifficultyHitObject): number;
1316
+ protected getObjectStrain(): number;
1212
1317
  /**
1213
1318
  * @param current The hitobject to save to.
1214
1319
  */
1215
- protected saveToHitObject(current: DifficultyHitObject): void;
1320
+ protected saveToHitObject(current: DroidDifficultyHitObject): void;
1216
1321
  }
1217
1322
 
1218
1323
  /**
@@ -1233,33 +1338,39 @@ declare abstract class DroidTapEvaluator extends SpeedEvaluator {
1233
1338
  *
1234
1339
  * - time between pressing the previous and current object,
1235
1340
  * - distance between those objects,
1236
- * - and how easily they can be cheesed.
1341
+ * - how easily they can be cheesed,
1342
+ * - and the strain time cap.
1237
1343
  *
1238
1344
  * @param current The current object.
1239
1345
  * @param greatWindow The great hit window of the current object.
1240
1346
  * @param considerCheesability Whether to consider cheesability.
1347
+ * @param strainTimeCap The strain time to cap the object's strain time to.
1241
1348
  */
1242
- static evaluateDifficultyOf(current: DifficultyHitObject, greatWindow: number, considerCheesability: boolean): number;
1349
+ static evaluateDifficultyOf(current: DroidDifficultyHitObject, considerCheesability: boolean, strainTimeCap?: number): number;
1243
1350
  }
1244
1351
 
1245
1352
  /**
1246
1353
  * Represents the skill required to read every object in the map.
1247
1354
  */
1248
1355
  declare class DroidVisual extends DroidSkill {
1249
- protected readonly starsPerDouble: number;
1250
- protected readonly reducedSectionCount: number;
1251
- protected readonly reducedSectionBaseline: number;
1252
- protected readonly skillMultiplier: number;
1253
- protected readonly strainDecayBase: number;
1356
+ protected readonly starsPerDouble = 1.025;
1357
+ protected readonly reducedSectionCount = 10;
1358
+ protected readonly reducedSectionBaseline = 0.75;
1359
+ protected readonly strainDecayBase = 0.1;
1254
1360
  private readonly isHidden;
1255
1361
  private readonly withSliders;
1362
+ private currentVisualStrain;
1363
+ private currentRhythmMultiplier;
1364
+ private readonly skillMultiplier;
1256
1365
  constructor(mods: Mod[], withSliders: boolean);
1257
- protected strainValueAt(current: DifficultyHitObject): number;
1258
- protected saveToHitObject(current: DifficultyHitObject): void;
1366
+ protected strainValueAt(current: DroidDifficultyHitObject): number;
1367
+ protected calculateInitialStrain(time: number, current: DroidDifficultyHitObject): number;
1368
+ protected getObjectStrain(): number;
1369
+ protected saveToHitObject(current: DroidDifficultyHitObject): void;
1259
1370
  }
1260
1371
 
1261
1372
  /**
1262
- * An evaluator for calculating osu!droid Visual skill.
1373
+ * An evaluator for calculating osu!droid visual skill.
1263
1374
  */
1264
1375
  declare abstract class DroidVisualEvaluator {
1265
1376
  /**
@@ -1277,7 +1388,7 @@ declare abstract class DroidVisualEvaluator {
1277
1388
  * @param isHiddenMod Whether the Hidden mod is enabled.
1278
1389
  * @param withSliders Whether to take slider difficulty into account.
1279
1390
  */
1280
- static evaluateDifficultyOf(current: DifficultyHitObject, isHiddenMod: boolean, withSliders: boolean): number;
1391
+ static evaluateDifficultyOf(current: DroidDifficultyHitObject, isHiddenMod: boolean, withSliders: boolean): number;
1281
1392
  }
1282
1393
 
1283
1394
  /**
@@ -1302,10 +1413,71 @@ declare abstract class OsuSkill extends StrainSkill {
1302
1413
  difficultyValue(): number;
1303
1414
  }
1304
1415
 
1416
+ /**
1417
+ * Represents an osu!standard hit object with difficulty calculation values.
1418
+ */
1419
+ declare class OsuDifficultyHitObject extends DifficultyHitObject {
1420
+ /**
1421
+ * The speed strain generated by the hitobject.
1422
+ */
1423
+ speedStrain: number;
1424
+ /**
1425
+ * The flashlight strain generated by this hitobject.
1426
+ */
1427
+ flashlightStrain: number;
1428
+ private readonly radiusBuffThreshold;
1429
+ protected readonly mode = Modes.osu;
1430
+ protected get scalingFactor(): number;
1431
+ }
1432
+
1433
+ /**
1434
+ * Represents the skill required to correctly aim at every object in the map with a uniform CircleSize and normalized distances.
1435
+ */
1436
+ declare class OsuAim extends OsuSkill {
1437
+ protected readonly strainDecayBase: number;
1438
+ protected readonly reducedSectionCount: number;
1439
+ protected readonly reducedSectionBaseline: number;
1440
+ protected readonly decayWeight: number;
1441
+ private currentAimStrain;
1442
+ private readonly skillMultiplier;
1443
+ private readonly withSliders;
1444
+ constructor(mods: Mod[], withSliders: boolean);
1445
+ protected strainValueAt(current: OsuDifficultyHitObject): number;
1446
+ protected calculateInitialStrain(time: number, current: OsuDifficultyHitObject): number;
1447
+ /**
1448
+ * @param current The hitobject to save to.
1449
+ */
1450
+ protected saveToHitObject(current: OsuDifficultyHitObject): void;
1451
+ }
1452
+
1453
+ /**
1454
+ * An evaluator for calculating osu!standard Aim skill.
1455
+ */
1456
+ declare abstract class OsuAimEvaluator extends AimEvaluator {
1457
+ /**
1458
+ * Evaluates the difficulty of aiming the current object, based on:
1459
+ *
1460
+ * - cursor velocity to the current object,
1461
+ * - angle difficulty,
1462
+ * - sharp velocity increases,
1463
+ * - and slider difficulty.
1464
+ *
1465
+ * @param current The current object.
1466
+ * @param withSliders Whether to take slider difficulty into account.
1467
+ */
1468
+ static evaluateDifficultyOf(current: OsuDifficultyHitObject, withSliders: boolean): number;
1469
+ }
1470
+
1305
1471
  /**
1306
1472
  * Holds data that can be used to calculate osu!standard performance points.
1307
1473
  */
1308
1474
  interface OsuDifficultyAttributes extends DifficultyAttributes {
1475
+ /**
1476
+ * The perceived approach rate inclusive of rate-adjusting mods (DT/HT/etc).
1477
+ *
1478
+ * Rate-adjusting mods don't directly affect the approach rate difficulty value, but have a perceived effect as a result of adjusting audio timing.
1479
+ */
1480
+ approachRate: number;
1309
1481
  /**
1310
1482
  * The difficulty corresponding to the speed skill.
1311
1483
  */
@@ -1315,22 +1487,23 @@ interface OsuDifficultyAttributes extends DifficultyAttributes {
1315
1487
  /**
1316
1488
  * A difficulty calculator for osu!standard gamemode.
1317
1489
  */
1318
- declare class OsuDifficultyCalculator extends DifficultyCalculator {
1490
+ declare class OsuDifficultyCalculator extends DifficultyCalculator<OsuDifficultyHitObject, OsuDifficultyAttributes> {
1319
1491
  /**
1320
1492
  * The aim star rating of the beatmap.
1321
1493
  */
1322
- aim: number;
1494
+ get aim(): number;
1323
1495
  /**
1324
1496
  * The speed star rating of the beatmap.
1325
1497
  */
1326
- speed: number;
1498
+ get speed(): number;
1327
1499
  /**
1328
1500
  * The flashlight star rating of the beatmap.
1329
1501
  */
1330
- flashlight: number;
1502
+ get flashlight(): number;
1331
1503
  readonly attributes: OsuDifficultyAttributes;
1332
- protected readonly difficultyMultiplier: number;
1333
- protected readonly mode: Modes;
1504
+ get cacheableAttributes(): CacheableDifficultyAttributes<OsuDifficultyAttributes>;
1505
+ protected readonly difficultyMultiplier = 0.0675;
1506
+ protected readonly mode = Modes.osu;
1334
1507
  /**
1335
1508
  * Calculates the aim star rating of the beatmap and stores it in this instance.
1336
1509
  */
@@ -1345,14 +1518,10 @@ declare class OsuDifficultyCalculator extends DifficultyCalculator {
1345
1518
  calculateFlashlight(): void;
1346
1519
  calculateTotal(): void;
1347
1520
  calculateAll(): void;
1348
- /**
1349
- * Returns a string representative of the class.
1350
- */
1351
1521
  toString(): string;
1352
- /**
1353
- * Creates skills to be calculated.
1354
- */
1522
+ protected generateDifficultyHitObjects(beatmap: Beatmap, clockRate: number): OsuDifficultyHitObject[];
1355
1523
  protected createSkills(): OsuSkill[];
1524
+ protected populateDifficultyAttributes(beatmap: Beatmap, clockRate: number): void;
1356
1525
  /**
1357
1526
  * Called after aim skill calculation.
1358
1527
  *
@@ -1378,87 +1547,21 @@ declare class OsuDifficultyCalculator extends DifficultyCalculator {
1378
1547
  private postCalculateFlashlight;
1379
1548
  }
1380
1549
 
1381
- /**
1382
- * A difficulty calculator that calculates for both osu!droid and osu!standard gamemode.
1383
- */
1384
- declare class MapStars {
1385
- /**
1386
- * The osu!droid difficulty calculator of the beatmap.
1387
- */
1388
- readonly droid: DroidDifficultyCalculator;
1389
- /**
1390
- * The osu!standard difficulty calculator of the beatmap.
1391
- */
1392
- readonly osu: OsuDifficultyCalculator;
1393
- /**
1394
- * Constructs this instance and calculates the given beatmap's osu!droid and osu!standard difficulty.
1395
- *
1396
- * @param beatmap The beatmap to calculate.
1397
- * @param options Options for the difficulty calculation.
1398
- */
1399
- constructor(beatmap: Beatmap, options?: DifficultyCalculationOptions);
1400
- /**
1401
- * Returns a string representative of the class.
1402
- */
1403
- toString(): string;
1404
- }
1405
-
1406
- /**
1407
- * Represents the skill required to correctly aim at every object in the map with a uniform CircleSize and normalized distances.
1408
- */
1409
- declare class OsuAim extends OsuSkill {
1410
- protected readonly skillMultiplier: number;
1411
- protected readonly strainDecayBase: number;
1412
- protected readonly reducedSectionCount: number;
1413
- protected readonly reducedSectionBaseline: number;
1414
- protected readonly difficultyMultiplier: number;
1415
- protected readonly decayWeight: number;
1416
- private readonly withSliders;
1417
- constructor(mods: Mod[], withSliders: boolean);
1418
- /**
1419
- * @param current The hitobject to calculate.
1420
- */
1421
- protected strainValueAt(current: DifficultyHitObject): number;
1422
- /**
1423
- * @param current The hitobject to save to.
1424
- */
1425
- protected saveToHitObject(current: DifficultyHitObject): void;
1426
- }
1427
-
1428
- /**
1429
- * An evaluator for calculating osu!standard Aim skill.
1430
- */
1431
- declare abstract class OsuAimEvaluator extends AimEvaluator {
1432
- /**
1433
- * Evaluates the difficulty of aiming the current object, based on:
1434
- *
1435
- * - cursor velocity to the current object,
1436
- * - angle difficulty,
1437
- * - sharp velocity increases,
1438
- * - and slider difficulty.
1439
- *
1440
- * @param current The current object.
1441
- * @param withSliders Whether to take slider difficulty into account.
1442
- */
1443
- static evaluateDifficultyOf(current: DifficultyHitObject, withSliders: boolean): number;
1444
- }
1445
-
1446
1550
  /**
1447
1551
  * Represents the skill required to memorize and hit every object in a beatmap with the Flashlight mod enabled.
1448
1552
  */
1449
1553
  declare class OsuFlashlight extends OsuSkill {
1450
- protected readonly skillMultiplier: number;
1451
1554
  protected readonly strainDecayBase: number;
1452
1555
  protected readonly reducedSectionCount: number;
1453
1556
  protected readonly reducedSectionBaseline: number;
1454
1557
  protected readonly decayWeight: number;
1558
+ private currentFlashlightStrain;
1559
+ private readonly skillMultiplier;
1455
1560
  private readonly isHidden;
1456
1561
  constructor(mods: Mod[]);
1457
- /**
1458
- * @param current The hitobject to calculate.
1459
- */
1460
- protected strainValueAt(current: DifficultyHitObject): number;
1461
- protected saveToHitObject(current: DifficultyHitObject): void;
1562
+ protected strainValueAt(current: OsuDifficultyHitObject): number;
1563
+ protected calculateInitialStrain(time: number, current: OsuDifficultyHitObject): number;
1564
+ protected saveToHitObject(current: OsuDifficultyHitObject): void;
1462
1565
  }
1463
1566
 
1464
1567
  /**
@@ -1477,13 +1580,13 @@ declare abstract class OsuFlashlightEvaluator extends FlashlightEvaluator {
1477
1580
  * @param current The current object.
1478
1581
  * @param isHiddenMod Whether the Hidden mod is enabled.
1479
1582
  */
1480
- static evaluateDifficultyOf(current: DifficultyHitObject, isHiddenMod: boolean): number;
1583
+ static evaluateDifficultyOf(current: OsuDifficultyHitObject, isHiddenMod: boolean): number;
1481
1584
  }
1482
1585
 
1483
1586
  /**
1484
1587
  * A performance points calculator that calculates performance points for osu!standard gamemode.
1485
1588
  */
1486
- declare class OsuPerformanceCalculator extends PerformanceCalculator {
1589
+ declare class OsuPerformanceCalculator extends PerformanceCalculator<OsuDifficultyAttributes> {
1487
1590
  /**
1488
1591
  * The aim performance value.
1489
1592
  */
@@ -1500,15 +1603,10 @@ declare class OsuPerformanceCalculator extends PerformanceCalculator {
1500
1603
  * The flashlight performance value.
1501
1604
  */
1502
1605
  flashlight: number;
1503
- readonly difficultyAttributes: OsuDifficultyAttributes;
1504
1606
  protected finalMultiplier: number;
1505
1607
  protected readonly mode: Modes;
1506
- /**
1507
- * @param difficultyAttributes The difficulty attributes to calculate.
1508
- */
1509
- constructor(difficultyAttributes: OsuDifficultyAttributes);
1510
1608
  protected calculateValues(): void;
1511
- protected calculateTotalValue(): void;
1609
+ protected calculateTotalValue(): number;
1512
1610
  /**
1513
1611
  * Calculates the aim performance value of the beatmap.
1514
1612
  */
@@ -1531,7 +1629,9 @@ declare class OsuPerformanceCalculator extends PerformanceCalculator {
1531
1629
  /**
1532
1630
  * An evaluator for calculating osu!standard Rhythm skill.
1533
1631
  */
1534
- declare abstract class OsuRhythmEvaluator extends RhythmEvaluator {
1632
+ declare abstract class OsuRhythmEvaluator {
1633
+ private static readonly rhythmMultiplier;
1634
+ private static readonly historyTimeMax;
1535
1635
  /**
1536
1636
  * Calculates a rhythm multiplier for the difficulty of the tap associated
1537
1637
  * with historic data of the current object.
@@ -1539,31 +1639,30 @@ declare abstract class OsuRhythmEvaluator extends RhythmEvaluator {
1539
1639
  * @param current The current object.
1540
1640
  * @param greatWindow The great hit window of the current object.
1541
1641
  */
1542
- static evaluateDifficultyOf(current: DifficultyHitObject, greatWindow: number): number;
1642
+ static evaluateDifficultyOf(current: OsuDifficultyHitObject): number;
1543
1643
  }
1544
1644
 
1545
1645
  /**
1546
1646
  * Represents the skill required to press keys or tap with regards to keeping up with the speed at which objects need to be hit.
1547
1647
  */
1548
1648
  declare class OsuSpeed extends OsuSkill {
1549
- protected readonly skillMultiplier: number;
1550
- protected readonly strainDecayBase: number;
1551
- protected readonly reducedSectionCount: number;
1552
- protected readonly reducedSectionBaseline: number;
1553
- protected readonly difficultyMultiplier: number;
1554
- protected readonly decayWeight: number;
1649
+ protected readonly strainDecayBase = 0.3;
1650
+ protected readonly reducedSectionCount = 5;
1651
+ protected readonly reducedSectionBaseline = 0.75;
1652
+ protected readonly difficultyMultiplier = 1.04;
1653
+ protected readonly decayWeight = 0.9;
1555
1654
  private currentSpeedStrain;
1556
1655
  private currentRhythm;
1557
- private readonly greatWindow;
1558
- constructor(mods: Mod[], greatWindow: number);
1656
+ private readonly skillMultiplier;
1559
1657
  /**
1560
1658
  * @param current The hitobject to calculate.
1561
1659
  */
1562
- protected strainValueAt(current: DifficultyHitObject): number;
1660
+ protected strainValueAt(current: OsuDifficultyHitObject): number;
1661
+ protected calculateInitialStrain(time: number, current: OsuDifficultyHitObject): number;
1563
1662
  /**
1564
1663
  * @param current The hitobject to save to.
1565
1664
  */
1566
- protected saveToHitObject(current: DifficultyHitObject): void;
1665
+ protected saveToHitObject(current: OsuDifficultyHitObject): void;
1567
1666
  }
1568
1667
 
1569
1668
  /**
@@ -1582,9 +1681,8 @@ declare abstract class OsuSpeedEvaluator extends SpeedEvaluator {
1582
1681
  * - and how easily they can be cheesed.
1583
1682
  *
1584
1683
  * @param current The current object.
1585
- * @param greatWindow The great hit window of the current object.
1586
1684
  */
1587
- static evaluateDifficultyOf(current: DifficultyHitObject, greatWindow: number): number;
1685
+ static evaluateDifficultyOf(current: OsuDifficultyHitObject): number;
1588
1686
  }
1589
1687
 
1590
- export { AimEvaluator, CalculationOptions, DifficultSlider, DifficultyAttributes, DifficultyCalculationOptions, DifficultyCalculator, DifficultyHitObject, DifficultyHitObjectCreator, DroidAim, DroidAimEvaluator, DroidDifficultyAttributes, DroidDifficultyCalculator, DroidFlashlight, DroidFlashlightEvaluator, DroidPerformanceCalculator, DroidRhythm, DroidRhythmEvaluator, DroidTap, DroidTapEvaluator, DroidVisual, DroidVisualEvaluator, ExtendedDroidDifficultyAttributes, FlashlightEvaluator, HighStrainSection, MapStars, OsuAim, OsuAimEvaluator, OsuDifficultyAttributes, OsuDifficultyCalculator, OsuFlashlight, OsuFlashlightEvaluator, OsuPerformanceCalculator, OsuRhythmEvaluator, OsuSpeed, OsuSpeedEvaluator, PerformanceCalculationOptions, PerformanceCalculator, RhythmEvaluator, SpeedEvaluator, StrainPeaks };
1688
+ export { AimEvaluator, type CacheableDifficultyAttributes, type DifficultSlider, type DifficultyAttributes, type DifficultyCalculationOptions, DifficultyCalculator, DifficultyHitObject, DroidAim, DroidAimEvaluator, type DroidDifficultyAttributes, type DroidDifficultyCalculationOptions, DroidDifficultyCalculator, DroidDifficultyHitObject, DroidFlashlight, DroidFlashlightEvaluator, DroidPerformanceCalculator, DroidRhythm, DroidRhythmEvaluator, DroidTap, DroidTapEvaluator, DroidVisual, DroidVisualEvaluator, type ExtendedDroidDifficultyAttributes, FlashlightEvaluator, type HighStrainSection, OsuAim, OsuAimEvaluator, type OsuDifficultyAttributes, OsuDifficultyCalculator, OsuDifficultyHitObject, OsuFlashlight, OsuFlashlightEvaluator, OsuPerformanceCalculator, OsuRhythmEvaluator, OsuSpeed, OsuSpeedEvaluator, type PerformanceCalculationOptions, PerformanceCalculator, SpeedEvaluator, type StrainPeaks };