@rian8337/osu-droid-replay-analyzer 4.0.0-beta.76 → 4.0.0-beta.78
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.
- package/dist/index.js +223 -10
- package/package.json +5 -5
- package/typings/index.d.ts +44 -6
package/dist/index.js
CHANGED
|
@@ -709,6 +709,222 @@ class RebalanceThreeFingerChecker {
|
|
|
709
709
|
}
|
|
710
710
|
}
|
|
711
711
|
|
|
712
|
+
/**
|
|
713
|
+
* Utility to check whether relevant sliders in a beatmap are cheesed for rebalance scores..
|
|
714
|
+
*/
|
|
715
|
+
class RebalanceSliderCheeseChecker {
|
|
716
|
+
/**
|
|
717
|
+
* @param beatmap The beatmap to analyze.
|
|
718
|
+
* @param data The data of the replay.
|
|
719
|
+
* @param difficultyAttributes The difficulty attributes of the beatmap.
|
|
720
|
+
*/
|
|
721
|
+
constructor(beatmap, data, difficultyAttributes) {
|
|
722
|
+
this.beatmap = beatmap;
|
|
723
|
+
this.data = data;
|
|
724
|
+
this.difficultyAttributes = difficultyAttributes;
|
|
725
|
+
this.hitWindow50 = difficultyAttributes.mods.has(osuBase.ModPrecise)
|
|
726
|
+
? new osuBase.PreciseDroidHitWindow(beatmap.difficulty.od).mehWindow
|
|
727
|
+
: new osuBase.DroidHitWindow(beatmap.difficulty.od).mehWindow;
|
|
728
|
+
this.isHardRock = difficultyAttributes.mods.has(osuBase.ModHardRock);
|
|
729
|
+
}
|
|
730
|
+
/**
|
|
731
|
+
* Checks if relevant sliders in the given beatmap was cheesed.
|
|
732
|
+
*/
|
|
733
|
+
check() {
|
|
734
|
+
if (this.difficultyAttributes.difficultSliders.length === 0 ||
|
|
735
|
+
(this.difficultyAttributes.sliderFactor === 1 &&
|
|
736
|
+
this.difficultyAttributes.flashlightSliderFactor === 1)) {
|
|
737
|
+
return {
|
|
738
|
+
aimPenalty: 1,
|
|
739
|
+
flashlightPenalty: 1,
|
|
740
|
+
};
|
|
741
|
+
}
|
|
742
|
+
const cheesedDifficultyRatings = this.checkSliderCheesing();
|
|
743
|
+
return this.calculateSliderCheesePenalty(cheesedDifficultyRatings);
|
|
744
|
+
}
|
|
745
|
+
/**
|
|
746
|
+
* Checks for sliders that were cheesed.
|
|
747
|
+
*/
|
|
748
|
+
checkSliderCheesing() {
|
|
749
|
+
const { objects } = this.beatmap.hitObjects;
|
|
750
|
+
const cheesedDifficultyRatings = [];
|
|
751
|
+
// Current loop indices are stored for efficiency.
|
|
752
|
+
const cursorLoopIndices = osuBase.Utils.initializeArray(this.data.cursorMovement.length, 0);
|
|
753
|
+
const acceptableRadius = objects[0].radius * 2;
|
|
754
|
+
// Sort difficult sliders by index so that cursor loop indices work properly.
|
|
755
|
+
for (const difficultSlider of this.difficultyAttributes.difficultSliders
|
|
756
|
+
.slice()
|
|
757
|
+
.sort((a, b) => a.index - b.index)) {
|
|
758
|
+
if (difficultSlider.index >= this.data.hitObjectData.length) {
|
|
759
|
+
continue;
|
|
760
|
+
}
|
|
761
|
+
const object = objects[difficultSlider.index];
|
|
762
|
+
const objectData = this.data.hitObjectData[difficultSlider.index];
|
|
763
|
+
// If a miss or slider break occurs, we disregard the check for that slider.
|
|
764
|
+
if (objectData.result === exports.HitResult.miss ||
|
|
765
|
+
-this.hitWindow50 > objectData.accuracy ||
|
|
766
|
+
objectData.accuracy >
|
|
767
|
+
Math.min(this.hitWindow50, object.duration)) {
|
|
768
|
+
continue;
|
|
769
|
+
}
|
|
770
|
+
const objectStartPosition = object.stackedPosition;
|
|
771
|
+
// These time boundaries should consider the delta time between the previous and next
|
|
772
|
+
// object as well as their hit accuracy. However, they are somewhat complicated to
|
|
773
|
+
// compute and the accuracy gain is small. As such, let's settle with 50 hit window.
|
|
774
|
+
const minTimeLimit = object.startTime - this.hitWindow50;
|
|
775
|
+
const maxTimeLimit = object.startTime + this.hitWindow50;
|
|
776
|
+
// Get the closest tap distance across all cursors.
|
|
777
|
+
const closestDistances = [];
|
|
778
|
+
const closestGroupIndices = [];
|
|
779
|
+
for (let i = 0; i < this.data.cursorMovement.length; ++i) {
|
|
780
|
+
const cursorGroups = this.data.cursorMovement[i].occurrenceGroups;
|
|
781
|
+
let closestDistance = Number.POSITIVE_INFINITY;
|
|
782
|
+
let closestIndex = cursorGroups.length;
|
|
783
|
+
for (let j = cursorLoopIndices[i]; j < cursorGroups.length; j = ++cursorLoopIndices[i]) {
|
|
784
|
+
const group = cursorGroups[j];
|
|
785
|
+
if (group.endTime < minTimeLimit) {
|
|
786
|
+
continue;
|
|
787
|
+
}
|
|
788
|
+
if (group.startTime > maxTimeLimit) {
|
|
789
|
+
break;
|
|
790
|
+
}
|
|
791
|
+
if (group.startTime >= minTimeLimit) {
|
|
792
|
+
const position = this.getCursorPosition(group.down);
|
|
793
|
+
const distance = position.getDistance(objectStartPosition);
|
|
794
|
+
if (closestDistance > distance) {
|
|
795
|
+
closestDistance = distance;
|
|
796
|
+
closestIndex = j;
|
|
797
|
+
}
|
|
798
|
+
if (closestDistance <= acceptableRadius / 2) {
|
|
799
|
+
break;
|
|
800
|
+
}
|
|
801
|
+
}
|
|
802
|
+
// Normally, we check if there are cursor presses within the group's active time.
|
|
803
|
+
// However, some funky workarounds are used throughout the game for replays, so
|
|
804
|
+
// for the time being we only check for cursor distances across the group.
|
|
805
|
+
const { allOccurrences } = group;
|
|
806
|
+
for (let k = 1; k < allOccurrences.length; ++k) {
|
|
807
|
+
const cursor = allOccurrences[k];
|
|
808
|
+
const prevCursor = allOccurrences[k - 1];
|
|
809
|
+
let distance = Number.POSITIVE_INFINITY;
|
|
810
|
+
const currentPosition = this.getCursorPosition(cursor);
|
|
811
|
+
const prevPosition = this.getCursorPosition(prevCursor);
|
|
812
|
+
switch (cursor.id) {
|
|
813
|
+
case exports.MovementType.up:
|
|
814
|
+
distance =
|
|
815
|
+
prevPosition.getDistance(objectStartPosition);
|
|
816
|
+
break;
|
|
817
|
+
case exports.MovementType.move:
|
|
818
|
+
for (let mSecPassed = Math.max(prevCursor.time, minTimeLimit); mSecPassed <=
|
|
819
|
+
Math.min(cursor.time, maxTimeLimit); ++mSecPassed) {
|
|
820
|
+
const t = (mSecPassed - prevCursor.time) /
|
|
821
|
+
(cursor.time - prevCursor.time);
|
|
822
|
+
const cursorPosition = osuBase.Interpolation.lerp(prevPosition, currentPosition, t);
|
|
823
|
+
distance =
|
|
824
|
+
cursorPosition.getDistance(objectStartPosition);
|
|
825
|
+
if (closestDistance > distance) {
|
|
826
|
+
closestDistance = distance;
|
|
827
|
+
closestIndex = j;
|
|
828
|
+
}
|
|
829
|
+
if (closestDistance <=
|
|
830
|
+
acceptableRadius / 2) {
|
|
831
|
+
break;
|
|
832
|
+
}
|
|
833
|
+
}
|
|
834
|
+
}
|
|
835
|
+
if (closestDistance > distance) {
|
|
836
|
+
closestDistance = distance;
|
|
837
|
+
closestIndex = j;
|
|
838
|
+
}
|
|
839
|
+
if (closestDistance <= acceptableRadius / 2) {
|
|
840
|
+
break;
|
|
841
|
+
}
|
|
842
|
+
}
|
|
843
|
+
}
|
|
844
|
+
closestDistances.push(closestDistance);
|
|
845
|
+
closestGroupIndices.push(closestIndex);
|
|
846
|
+
if (cursorLoopIndices[i] > 0) {
|
|
847
|
+
// Decrement the index. The previous group may also have a role on the next slider.
|
|
848
|
+
--cursorLoopIndices[i];
|
|
849
|
+
}
|
|
850
|
+
}
|
|
851
|
+
const cursorIndex = closestDistances.indexOf(Math.min(...closestDistances));
|
|
852
|
+
const closestDistance = closestDistances[cursorIndex];
|
|
853
|
+
if (closestDistance > acceptableRadius / 2) {
|
|
854
|
+
cheesedDifficultyRatings.push(difficultSlider.difficultyRating);
|
|
855
|
+
continue;
|
|
856
|
+
}
|
|
857
|
+
const group = this.data.cursorMovement[cursorIndex].occurrenceGroups[closestGroupIndices[cursorIndex]];
|
|
858
|
+
let isCheesed = false;
|
|
859
|
+
// Track cursor movement to see if it lands on every tick.
|
|
860
|
+
let occurrenceLoopIndex = 1;
|
|
861
|
+
const { allOccurrences } = group;
|
|
862
|
+
for (let i = 1; i < object.nestedHitObjects.length; ++i) {
|
|
863
|
+
if (isCheesed) {
|
|
864
|
+
break;
|
|
865
|
+
}
|
|
866
|
+
const tickWasHit = objectData.tickset[i - 1];
|
|
867
|
+
if (!tickWasHit) {
|
|
868
|
+
continue;
|
|
869
|
+
}
|
|
870
|
+
const nestedObject = object.nestedHitObjects[i];
|
|
871
|
+
const nestedPosition = nestedObject.stackedPosition;
|
|
872
|
+
while (occurrenceLoopIndex < allOccurrences.length &&
|
|
873
|
+
allOccurrences[occurrenceLoopIndex].time <
|
|
874
|
+
nestedObject.startTime) {
|
|
875
|
+
++occurrenceLoopIndex;
|
|
876
|
+
}
|
|
877
|
+
if (occurrenceLoopIndex === allOccurrences.length) {
|
|
878
|
+
continue;
|
|
879
|
+
}
|
|
880
|
+
const cursor = allOccurrences[occurrenceLoopIndex];
|
|
881
|
+
const prevCursor = allOccurrences[occurrenceLoopIndex - 1];
|
|
882
|
+
const currentPosition = this.getCursorPosition(cursor);
|
|
883
|
+
const prevPosition = this.getCursorPosition(prevCursor);
|
|
884
|
+
switch (cursor.id) {
|
|
885
|
+
case exports.MovementType.move: {
|
|
886
|
+
// Interpolate cursor position during nested object time.
|
|
887
|
+
const t = (nestedObject.startTime - prevCursor.time) /
|
|
888
|
+
(cursor.time - prevCursor.time);
|
|
889
|
+
const cursorPosition = osuBase.Interpolation.lerp(prevPosition, currentPosition, t);
|
|
890
|
+
const distance = cursorPosition.getDistance(nestedPosition);
|
|
891
|
+
isCheesed = distance > acceptableRadius;
|
|
892
|
+
break;
|
|
893
|
+
}
|
|
894
|
+
case exports.MovementType.up:
|
|
895
|
+
isCheesed =
|
|
896
|
+
prevPosition.getDistance(nestedPosition) >
|
|
897
|
+
acceptableRadius;
|
|
898
|
+
}
|
|
899
|
+
}
|
|
900
|
+
if (isCheesed) {
|
|
901
|
+
cheesedDifficultyRatings.push(difficultSlider.difficultyRating);
|
|
902
|
+
}
|
|
903
|
+
}
|
|
904
|
+
return cheesedDifficultyRatings;
|
|
905
|
+
}
|
|
906
|
+
/**
|
|
907
|
+
* Calculates the slider cheese penalty.
|
|
908
|
+
*/
|
|
909
|
+
calculateSliderCheesePenalty(cheesedDifficultyRatings) {
|
|
910
|
+
const summedDifficultyRating = Math.min(1, cheesedDifficultyRatings.reduce((a, v) => a + v, 0));
|
|
911
|
+
return {
|
|
912
|
+
aimPenalty: Math.max(this.difficultyAttributes.sliderFactor, Math.pow(1 -
|
|
913
|
+
summedDifficultyRating *
|
|
914
|
+
this.difficultyAttributes.sliderFactor, 2)),
|
|
915
|
+
flashlightPenalty: Math.max(this.difficultyAttributes.flashlightSliderFactor, Math.pow(1 -
|
|
916
|
+
summedDifficultyRating *
|
|
917
|
+
this.difficultyAttributes.flashlightSliderFactor, 2)),
|
|
918
|
+
};
|
|
919
|
+
}
|
|
920
|
+
getCursorPosition(cursor) {
|
|
921
|
+
if (this.isHardRock) {
|
|
922
|
+
return new osuBase.Vector2(cursor.position.x, osuBase.Playfield.baseSize.y - cursor.position.y);
|
|
923
|
+
}
|
|
924
|
+
return cursor.position;
|
|
925
|
+
}
|
|
926
|
+
}
|
|
927
|
+
|
|
712
928
|
/******************************************************************************
|
|
713
929
|
Copyright (c) Microsoft Corporation.
|
|
714
930
|
|
|
@@ -742,7 +958,7 @@ typeof SuppressedError === "function" ? SuppressedError : function (error, suppr
|
|
|
742
958
|
};
|
|
743
959
|
|
|
744
960
|
/**
|
|
745
|
-
* Utility to check whether relevant sliders in a beatmap are cheesed.
|
|
961
|
+
* Utility to check whether relevant sliders in a beatmap are cheesed for live scores.
|
|
746
962
|
*/
|
|
747
963
|
class SliderCheeseChecker {
|
|
748
964
|
/**
|
|
@@ -765,12 +981,10 @@ class SliderCheeseChecker {
|
|
|
765
981
|
check() {
|
|
766
982
|
if (this.difficultyAttributes.difficultSliders.length === 0 ||
|
|
767
983
|
(this.difficultyAttributes.sliderFactor === 1 &&
|
|
768
|
-
this.difficultyAttributes.flashlightSliderFactor === 1
|
|
769
|
-
this.difficultyAttributes.visualSliderFactor === 1)) {
|
|
984
|
+
this.difficultyAttributes.flashlightSliderFactor === 1)) {
|
|
770
985
|
return {
|
|
771
986
|
aimPenalty: 1,
|
|
772
987
|
flashlightPenalty: 1,
|
|
773
|
-
visualPenalty: 1,
|
|
774
988
|
};
|
|
775
989
|
}
|
|
776
990
|
const cheesedDifficultyRatings = this.checkSliderCheesing();
|
|
@@ -949,9 +1163,6 @@ class SliderCheeseChecker {
|
|
|
949
1163
|
flashlightPenalty: Math.max(this.difficultyAttributes.flashlightSliderFactor, Math.pow(1 -
|
|
950
1164
|
summedDifficultyRating *
|
|
951
1165
|
this.difficultyAttributes.flashlightSliderFactor, 2)),
|
|
952
|
-
visualPenalty: Math.max(this.difficultyAttributes.visualSliderFactor, Math.pow(1 -
|
|
953
|
-
summedDifficultyRating *
|
|
954
|
-
this.difficultyAttributes.visualSliderFactor, 2)),
|
|
955
1166
|
};
|
|
956
1167
|
}
|
|
957
1168
|
getCursorPosition(cursor) {
|
|
@@ -1494,7 +1705,7 @@ class TwoHandChecker {
|
|
|
1494
1705
|
// );
|
|
1495
1706
|
// }
|
|
1496
1707
|
return {
|
|
1497
|
-
is2Hand: 0 > this.attributes.aimNoteCount * 0.15,
|
|
1708
|
+
is2Hand: false, // 0 > this.attributes.aimNoteCount * 0.15,
|
|
1498
1709
|
twoHandedNoteCount: 0,
|
|
1499
1710
|
};
|
|
1500
1711
|
}
|
|
@@ -2076,7 +2287,6 @@ class ReplayAnalyzer {
|
|
|
2076
2287
|
this.sliderCheesePenalty = {
|
|
2077
2288
|
aimPenalty: 1,
|
|
2078
2289
|
flashlightPenalty: 1,
|
|
2079
|
-
visualPenalty: 1,
|
|
2080
2290
|
};
|
|
2081
2291
|
/**
|
|
2082
2292
|
* Whether this replay has been checked against 3 finger usage.
|
|
@@ -2342,7 +2552,9 @@ class ReplayAnalyzer {
|
|
|
2342
2552
|
return;
|
|
2343
2553
|
}
|
|
2344
2554
|
(_a = this.playableBeatmap) !== null && _a !== void 0 ? _a : (this.playableBeatmap = this.constructPlayableBeatmap());
|
|
2345
|
-
const sliderCheeseChecker =
|
|
2555
|
+
const sliderCheeseChecker = this.difficultyAttributes.mode === "rebalance"
|
|
2556
|
+
? new RebalanceSliderCheeseChecker(this.playableBeatmap, this.data, this.difficultyAttributes)
|
|
2557
|
+
: new SliderCheeseChecker(this.playableBeatmap, this.data, this.difficultyAttributes);
|
|
2346
2558
|
this.sliderCheesePenalty = sliderCheeseChecker.check();
|
|
2347
2559
|
this.hasBeenCheckedForSliderCheesing = true;
|
|
2348
2560
|
}
|
|
@@ -2725,6 +2937,7 @@ class ReplayObjectData {
|
|
|
2725
2937
|
exports.CursorData = CursorData;
|
|
2726
2938
|
exports.CursorOccurrence = CursorOccurrence;
|
|
2727
2939
|
exports.CursorOccurrenceGroup = CursorOccurrenceGroup;
|
|
2940
|
+
exports.RebalanceSliderCheeseChecker = RebalanceSliderCheeseChecker;
|
|
2728
2941
|
exports.RebalanceThreeFingerChecker = RebalanceThreeFingerChecker;
|
|
2729
2942
|
exports.ReplayAnalyzer = ReplayAnalyzer;
|
|
2730
2943
|
exports.ReplayData = ReplayData;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rian8337/osu-droid-replay-analyzer",
|
|
3
|
-
"version": "4.0.0-beta.
|
|
3
|
+
"version": "4.0.0-beta.78",
|
|
4
4
|
"description": "A replay analyzer for analyzing osu!droid replay files.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"osu",
|
|
@@ -34,9 +34,9 @@
|
|
|
34
34
|
"url": "https://github.com/Rian8337/osu-droid-module/issues"
|
|
35
35
|
},
|
|
36
36
|
"dependencies": {
|
|
37
|
-
"@rian8337/osu-base": "^4.0.0-beta.
|
|
38
|
-
"@rian8337/osu-difficulty-calculator": "^4.0.0-beta.
|
|
39
|
-
"@rian8337/osu-rebalance-difficulty-calculator": "^4.0.0-beta.
|
|
37
|
+
"@rian8337/osu-base": "^4.0.0-beta.78",
|
|
38
|
+
"@rian8337/osu-difficulty-calculator": "^4.0.0-beta.78",
|
|
39
|
+
"@rian8337/osu-rebalance-difficulty-calculator": "^4.0.0-beta.78",
|
|
40
40
|
"java-deserialization": "^0.1.0",
|
|
41
41
|
"unzipper": "^0.10.11"
|
|
42
42
|
},
|
|
@@ -46,5 +46,5 @@
|
|
|
46
46
|
"publishConfig": {
|
|
47
47
|
"access": "public"
|
|
48
48
|
},
|
|
49
|
-
"gitHead": "
|
|
49
|
+
"gitHead": "9b8c41ad3aeb0b98cb0818c9169ad3ad4e98b95e"
|
|
50
50
|
}
|
package/typings/index.d.ts
CHANGED
|
@@ -720,10 +720,48 @@ interface SliderCheeseInformation {
|
|
|
720
720
|
* The value used to penalize the flashlight performance value, from 0 to 1.
|
|
721
721
|
*/
|
|
722
722
|
flashlightPenalty: number;
|
|
723
|
+
}
|
|
724
|
+
|
|
725
|
+
/**
|
|
726
|
+
* Utility to check whether relevant sliders in a beatmap are cheesed for rebalance scores..
|
|
727
|
+
*/
|
|
728
|
+
declare class RebalanceSliderCheeseChecker {
|
|
729
|
+
/**
|
|
730
|
+
* The beatmap that is being analyzed.
|
|
731
|
+
*/
|
|
732
|
+
readonly beatmap: DroidPlayableBeatmap;
|
|
733
|
+
/**
|
|
734
|
+
* The data of the replay.
|
|
735
|
+
*/
|
|
736
|
+
readonly data: ReplayData;
|
|
737
|
+
/**
|
|
738
|
+
* The difficulty attributes of the beatmap.
|
|
739
|
+
*/
|
|
740
|
+
readonly difficultyAttributes: IExtendedDroidDifficultyAttributes;
|
|
741
|
+
/**
|
|
742
|
+
* The 50 osu!droid hit window of the analyzed beatmap.
|
|
743
|
+
*/
|
|
744
|
+
private readonly hitWindow50;
|
|
745
|
+
private readonly isHardRock;
|
|
746
|
+
/**
|
|
747
|
+
* @param beatmap The beatmap to analyze.
|
|
748
|
+
* @param data The data of the replay.
|
|
749
|
+
* @param difficultyAttributes The difficulty attributes of the beatmap.
|
|
750
|
+
*/
|
|
751
|
+
constructor(beatmap: DroidPlayableBeatmap, data: ReplayData, difficultyAttributes: IExtendedDroidDifficultyAttributes);
|
|
752
|
+
/**
|
|
753
|
+
* Checks if relevant sliders in the given beatmap was cheesed.
|
|
754
|
+
*/
|
|
755
|
+
check(): SliderCheeseInformation;
|
|
756
|
+
/**
|
|
757
|
+
* Checks for sliders that were cheesed.
|
|
758
|
+
*/
|
|
759
|
+
private checkSliderCheesing;
|
|
723
760
|
/**
|
|
724
|
-
*
|
|
761
|
+
* Calculates the slider cheese penalty.
|
|
725
762
|
*/
|
|
726
|
-
|
|
763
|
+
private calculateSliderCheesePenalty;
|
|
764
|
+
private getCursorPosition;
|
|
727
765
|
}
|
|
728
766
|
|
|
729
767
|
/**
|
|
@@ -919,7 +957,7 @@ declare class ReplayAnalyzer {
|
|
|
919
957
|
}
|
|
920
958
|
|
|
921
959
|
/**
|
|
922
|
-
* Utility to check whether relevant sliders in a beatmap are cheesed.
|
|
960
|
+
* Utility to check whether relevant sliders in a beatmap are cheesed for live scores.
|
|
923
961
|
*/
|
|
924
962
|
declare class SliderCheeseChecker {
|
|
925
963
|
/**
|
|
@@ -933,7 +971,7 @@ declare class SliderCheeseChecker {
|
|
|
933
971
|
/**
|
|
934
972
|
* The difficulty attributes of the beatmap.
|
|
935
973
|
*/
|
|
936
|
-
readonly difficultyAttributes: IExtendedDroidDifficultyAttributes$1
|
|
974
|
+
readonly difficultyAttributes: IExtendedDroidDifficultyAttributes$1;
|
|
937
975
|
/**
|
|
938
976
|
* The 50 osu!droid hit window of the analyzed beatmap.
|
|
939
977
|
*/
|
|
@@ -944,7 +982,7 @@ declare class SliderCheeseChecker {
|
|
|
944
982
|
* @param data The data of the replay.
|
|
945
983
|
* @param difficultyAttributes The difficulty attributes of the beatmap.
|
|
946
984
|
*/
|
|
947
|
-
constructor(beatmap: DroidPlayableBeatmap, data: ReplayData, difficultyAttributes: IExtendedDroidDifficultyAttributes$1
|
|
985
|
+
constructor(beatmap: DroidPlayableBeatmap, data: ReplayData, difficultyAttributes: IExtendedDroidDifficultyAttributes$1);
|
|
948
986
|
/**
|
|
949
987
|
* Checks if relevant sliders in the given beatmap was cheesed.
|
|
950
988
|
*/
|
|
@@ -1161,4 +1199,4 @@ declare class TwoHandChecker {
|
|
|
1161
1199
|
private getCursorPosition;
|
|
1162
1200
|
}
|
|
1163
1201
|
|
|
1164
|
-
export { CursorData, type CursorInformation, CursorOccurrence, CursorOccurrenceGroup, type ExportedReplayJSON, type ExportedReplayJSONDataV1, type ExportedReplayJSONDataV2, type ExportedReplayJSONDataV3, type ExportedReplayJSONV1, type ExportedReplayJSONV2, type ExportedReplayJSONV3, type HitErrorInformation, HitResult, MovementType, RebalanceThreeFingerChecker, ReplayAnalyzer, ReplayData, ReplayObjectData, ReplayV3Data, SliderCheeseChecker, type SliderCheeseInformation, type SliderHitInformation, type SliderNestedHitObjectInformation, ThreeFingerChecker, type ThreeFingerInformation, TwoHandChecker, type TwoHandInformation };
|
|
1202
|
+
export { CursorData, type CursorInformation, CursorOccurrence, CursorOccurrenceGroup, type ExportedReplayJSON, type ExportedReplayJSONDataV1, type ExportedReplayJSONDataV2, type ExportedReplayJSONDataV3, type ExportedReplayJSONV1, type ExportedReplayJSONV2, type ExportedReplayJSONV3, type HitErrorInformation, HitResult, MovementType, RebalanceSliderCheeseChecker, RebalanceThreeFingerChecker, ReplayAnalyzer, ReplayData, ReplayObjectData, ReplayV3Data, SliderCheeseChecker, type SliderCheeseInformation, type SliderHitInformation, type SliderNestedHitObjectInformation, ThreeFingerChecker, type ThreeFingerInformation, TwoHandChecker, type TwoHandInformation };
|