@rian8337/osu-base 1.0.0

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.
Files changed (57) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +11 -0
  3. package/dist/beatmap/Beatmap.js +223 -0
  4. package/dist/beatmap/Parser.js +620 -0
  5. package/dist/beatmap/hitobjects/Circle.js +20 -0
  6. package/dist/beatmap/hitobjects/HitObject.js +74 -0
  7. package/dist/beatmap/hitobjects/Slider.js +143 -0
  8. package/dist/beatmap/hitobjects/Spinner.js +26 -0
  9. package/dist/beatmap/hitobjects/sliderObjects/HeadCircle.js +10 -0
  10. package/dist/beatmap/hitobjects/sliderObjects/RepeatPoint.js +21 -0
  11. package/dist/beatmap/hitobjects/sliderObjects/SliderTick.js +21 -0
  12. package/dist/beatmap/hitobjects/sliderObjects/TailCircle.js +10 -0
  13. package/dist/beatmap/timings/BreakPoint.js +34 -0
  14. package/dist/beatmap/timings/DifficultyControlPoint.js +22 -0
  15. package/dist/beatmap/timings/TimingControlPoint.js +22 -0
  16. package/dist/beatmap/timings/TimingPoint.js +12 -0
  17. package/dist/constants/ParserConstants.js +19 -0
  18. package/dist/constants/PathType.js +13 -0
  19. package/dist/constants/modes.js +11 -0
  20. package/dist/constants/objectTypes.js +12 -0
  21. package/dist/constants/rankedStatus.js +16 -0
  22. package/dist/index.js +64 -0
  23. package/dist/mathutil/Interpolation.js +9 -0
  24. package/dist/mathutil/MathUtils.js +41 -0
  25. package/dist/mathutil/Vector2.js +79 -0
  26. package/dist/mods/Mod.js +9 -0
  27. package/dist/mods/ModAuto.js +21 -0
  28. package/dist/mods/ModAutopilot.js +21 -0
  29. package/dist/mods/ModDoubleTime.js +21 -0
  30. package/dist/mods/ModEasy.js +21 -0
  31. package/dist/mods/ModFlashlight.js +21 -0
  32. package/dist/mods/ModHalfTime.js +21 -0
  33. package/dist/mods/ModHardRock.js +21 -0
  34. package/dist/mods/ModHidden.js +21 -0
  35. package/dist/mods/ModNightCore.js +21 -0
  36. package/dist/mods/ModNoFail.js +21 -0
  37. package/dist/mods/ModPerfect.js +21 -0
  38. package/dist/mods/ModPrecise.js +21 -0
  39. package/dist/mods/ModReallyEasy.js +21 -0
  40. package/dist/mods/ModRelax.js +21 -0
  41. package/dist/mods/ModScoreV2.js +21 -0
  42. package/dist/mods/ModSmallCircle.js +21 -0
  43. package/dist/mods/ModSpunOut.js +21 -0
  44. package/dist/mods/ModSuddenDeath.js +21 -0
  45. package/dist/mods/ModTouchDevice.js +21 -0
  46. package/dist/tools/MapInfo.js +559 -0
  47. package/dist/utils/APIRequestBuilder.js +144 -0
  48. package/dist/utils/Accuracy.js +96 -0
  49. package/dist/utils/HitWindow.js +56 -0
  50. package/dist/utils/MapStats.js +212 -0
  51. package/dist/utils/ModUtil.js +137 -0
  52. package/dist/utils/PathApproximator.js +269 -0
  53. package/dist/utils/Precision.js +31 -0
  54. package/dist/utils/SliderPath.js +187 -0
  55. package/dist/utils/Utils.js +53 -0
  56. package/package.json +43 -0
  57. package/typings/index.d.ts +1951 -0
@@ -0,0 +1,269 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PathApproximator = void 0;
4
+ const Vector2_1 = require("../mathutil/Vector2");
5
+ const Precision_1 = require("./Precision");
6
+ const Utils_1 = require("./Utils");
7
+ /**
8
+ * Path approximator for sliders.
9
+ */
10
+ class PathApproximator {
11
+ /**
12
+ * Approximates a bezier slider's path.
13
+ *
14
+ * Creates a piecewise-linear approximation of a bezier curve by adaptively repeatedly subdividing
15
+ * the control points until their approximation error vanishes below a given threshold.
16
+ *
17
+ * @param controlPoints The anchor points of the slider.
18
+ */
19
+ static approximateBezier(controlPoints) {
20
+ const output = [];
21
+ const count = controlPoints.length - 1;
22
+ if (count < 0) {
23
+ return output;
24
+ }
25
+ const subdivisionBuffer1 = new Array(count + 1);
26
+ const subdivisionBuffer2 = new Array(count * 2 + 1);
27
+ // "toFlatten" contains all the curves which are not yet approximated well enough.
28
+ // We use a stack to emulate recursion without the risk of running into a stack overflow.
29
+ // (More specifically, we iteratively and adaptively refine our curve with a
30
+ // depth-first search (https://en.wikipedia.org/wiki/Depth-first_search)
31
+ // over the tree resulting from the subdivisions we make.)
32
+ const toFlatten = [Utils_1.Utils.deepCopy(controlPoints)];
33
+ const freeBuffers = [];
34
+ const leftChild = subdivisionBuffer2;
35
+ while (toFlatten.length > 0) {
36
+ const parent = toFlatten.pop();
37
+ if (this.bezierIsFlatEnough(parent)) {
38
+ // If the control points we currently operate on are sufficiently "flat", we use
39
+ // an extension to De Casteljau's algorithm to obtain a piecewise-linear approximation
40
+ // of the bezier curve represented by our control points, consisting of the same amount
41
+ // of points as there are control points.
42
+ this.bezierApproximate(parent, output, subdivisionBuffer1, subdivisionBuffer2, count + 1);
43
+ freeBuffers.push(parent);
44
+ continue;
45
+ }
46
+ // If we do not yet have a sufficiently "flat" (in other words, detailed) approximation we keep
47
+ // subdividing the curve we are currently operating on.
48
+ const rightChild = freeBuffers.length > 0
49
+ ? freeBuffers.pop()
50
+ : new Array(count + 1);
51
+ this.bezierSubdivide(parent, leftChild, rightChild, subdivisionBuffer1, count + 1);
52
+ // We re-use the buffer of the parent for one of the children, so that we save one allocation per iteration.
53
+ for (let i = 0; i < count + 1; ++i) {
54
+ parent[i] = leftChild[i];
55
+ }
56
+ toFlatten.push(rightChild);
57
+ toFlatten.push(parent);
58
+ }
59
+ output.push(controlPoints[count]);
60
+ return output;
61
+ }
62
+ /**
63
+ * Approximates a catmull slider's path.
64
+ *
65
+ * Creates a piecewise-linear approximation of a Catmull-Rom spline.
66
+ *
67
+ * @param controlPoints The anchor points of the slider.
68
+ */
69
+ static approximateCatmull(controlPoints) {
70
+ const result = [];
71
+ for (let i = 0; i < controlPoints.length - 1; ++i) {
72
+ const v1 = i > 0 ? controlPoints[i - 1] : controlPoints[i];
73
+ const v2 = controlPoints[i];
74
+ const v3 = i < controlPoints.length - 1
75
+ ? controlPoints[i + 1]
76
+ : v2.add(v2).subtract(v1);
77
+ const v4 = i < controlPoints.length - 2
78
+ ? controlPoints[i + 2]
79
+ : v3.add(v3).subtract(v2);
80
+ for (let c = 0; c < this.catmullDetail; ++c) {
81
+ result.push(this.catmullFindPoint(v1, v2, v3, v4, c / this.catmullDetail));
82
+ result.push(this.catmullFindPoint(v1, v2, v3, v4, (c + 1) / this.catmullDetail));
83
+ }
84
+ }
85
+ return result;
86
+ }
87
+ /**
88
+ * Approximates a slider's circular arc.
89
+ *
90
+ * Creates a piecewise-linear approximation of a circular arc curve.
91
+ *
92
+ * @param controlPoints The anchor points of the slider.
93
+ */
94
+ static approximateCircularArc(controlPoints) {
95
+ const a = controlPoints[0];
96
+ const b = controlPoints[1];
97
+ const c = controlPoints[2];
98
+ // If we have a degenerate triangle where a side-length is almost zero, then give up and fall
99
+ // back to a more numerically stable method.
100
+ if (Precision_1.Precision.almostEqualsNumber(0, (b.y - a.y) * (c.x - a.x) - (b.x - a.x) * (c.y - a.y))) {
101
+ return [];
102
+ }
103
+ // See: https://en.wikipedia.org/wiki/Circumscribed_circle#Cartesian_coordinates_2
104
+ const d = 2 *
105
+ (a.x * b.subtract(c).y +
106
+ b.x * c.subtract(a).y +
107
+ c.x * a.subtract(b).y);
108
+ const aSq = Math.pow(a.length, 2);
109
+ const bSq = Math.pow(b.length, 2);
110
+ const cSq = Math.pow(c.length, 2);
111
+ const center = new Vector2_1.Vector2(aSq * b.subtract(c).y +
112
+ bSq * c.subtract(a).y +
113
+ cSq * a.subtract(b).y, aSq * c.subtract(b).x +
114
+ bSq * a.subtract(c).x +
115
+ cSq * b.subtract(a).x).divide(d);
116
+ const dA = a.subtract(center);
117
+ const dC = c.subtract(center);
118
+ const r = dA.length;
119
+ const thetaStart = Math.atan2(dA.y, dA.x);
120
+ let thetaEnd = Math.atan2(dC.y, dC.x);
121
+ while (thetaEnd < thetaStart) {
122
+ thetaEnd += 2 * Math.PI;
123
+ }
124
+ let dir = 1;
125
+ let thetaRange = thetaEnd - thetaStart;
126
+ // Decide in which direction to draw the circle, depending on which side of
127
+ // AC B lies.
128
+ let orthoAtoC = c.subtract(a);
129
+ orthoAtoC = new Vector2_1.Vector2(orthoAtoC.y, -orthoAtoC.x);
130
+ if (orthoAtoC.dot(b.subtract(a)) < 0) {
131
+ dir = -dir;
132
+ thetaRange = 2 * Math.PI - thetaRange;
133
+ }
134
+ // We select the amount of points for the approximation by requiring the discrete curvature
135
+ // to be smaller than the provided tolerance. The exact angle required to meet the tolerance
136
+ // is: 2 * Math.Acos(1 - TOLERANCE / r)
137
+ // The special case is required for extremely short sliders where the radius is smaller than
138
+ // the tolerance. This is a pathological rather than a realistic case.
139
+ const amountPoints = 2 * r <= this.circularArcTolerance
140
+ ? 2
141
+ : Math.max(2, Math.ceil(thetaRange /
142
+ (2 * Math.acos(1 - this.circularArcTolerance / r))));
143
+ const output = [];
144
+ for (let i = 0; i < amountPoints; ++i) {
145
+ const fract = i / (amountPoints - 1);
146
+ const theta = thetaStart + dir * fract * thetaRange;
147
+ const o = new Vector2_1.Vector2(Math.cos(theta), Math.sin(theta)).scale(r);
148
+ output.push(center.add(o));
149
+ }
150
+ return output;
151
+ }
152
+ /**
153
+ * Approximates a linear slider's path.
154
+ *
155
+ * Creates a piecewise-linear approximation of a linear curve.
156
+ * Basically, returns the input.
157
+ *
158
+ * @param controlPoints The anchor points of the slider.
159
+ */
160
+ static approximateLinear(controlPoints) {
161
+ return controlPoints;
162
+ }
163
+ /**
164
+ * Checks if a bezier slider is flat enough to be approximated.
165
+ *
166
+ * Make sure the 2nd order derivative (approximated using finite elements) is within tolerable bounds.
167
+ *
168
+ * NOTE: The 2nd order derivative of a 2D curve represents its curvature, so intuitively this function
169
+ * checks (as the name suggests) whether our approximation is _locally_ "flat". More curvy parts
170
+ * need to have a denser approximation to be more "flat".
171
+ *
172
+ * @param controlPoints The anchor points of the slider.
173
+ */
174
+ static bezierIsFlatEnough(controlPoints) {
175
+ for (let i = 1; i < controlPoints.length - 1; ++i) {
176
+ const prev = controlPoints[i - 1];
177
+ const current = controlPoints[i];
178
+ const next = controlPoints[i + 1];
179
+ const final = prev.subtract(current.scale(2)).add(next);
180
+ if (Math.pow(final.length, 2) >
181
+ Math.pow(this.bezierTolerance, 2) * 4) {
182
+ return false;
183
+ }
184
+ }
185
+ return true;
186
+ }
187
+ /**
188
+ * Approximates a bezier slider's path.
189
+ *
190
+ * This uses {@link https://en.wikipedia.org/wiki/De_Casteljau%27s_algorithm De Casteljau's algorithm} to obtain an optimal
191
+ * piecewise-linear approximation of the bezier curve with the same amount of points as there are control points.
192
+ *
193
+ * @param controlPoints The control points describing the bezier curve to be approximated.
194
+ * @param output The points representing the resulting piecewise-linear approximation.
195
+ * @param subdivisionBuffer1 The first buffer containing the current subdivision state.
196
+ * @param subdivisionBuffer2 The second buffer containing the current subdivision state.
197
+ * @param count The number of control points in the original array.
198
+ */
199
+ static bezierApproximate(controlPoints, output, subdivisionBuffer1, subdivisionBuffer2, count) {
200
+ const l = subdivisionBuffer2;
201
+ const r = subdivisionBuffer1;
202
+ this.bezierSubdivide(controlPoints, l, r, subdivisionBuffer1, count);
203
+ for (let i = 0; i < count - 1; ++i) {
204
+ l[count + i] = r[i + 1];
205
+ }
206
+ output.push(controlPoints[0]);
207
+ for (let i = 1; i < count - 1; ++i) {
208
+ const index = 2 * i;
209
+ const p = l[index - 1]
210
+ .add(l[index].scale(2))
211
+ .add(l[index + 1])
212
+ .scale(0.25);
213
+ output.push(p);
214
+ }
215
+ }
216
+ /**
217
+ * Subdivides `n` control points representing a bezier curve into 2 sets of `n` control points, each
218
+ * describing a bezier curve equivalent to a half of the original curve. Effectively this splits
219
+ * the original curve into 2 curves which result in the original curve when pieced back together.
220
+ *
221
+ * @param controlPoints The anchor points of the slider.
222
+ * @param l Parts of the slider for approximation.
223
+ * @param r Parts of the slider for approximation.
224
+ * @param subdivisionBuffer Parts of the slider for approximation.
225
+ * @param count The amount of anchor points in the slider.
226
+ */
227
+ static bezierSubdivide(controlPoints, l, r, subdivisionBuffer, count) {
228
+ const midpoints = subdivisionBuffer;
229
+ for (let i = 0; i < count; ++i) {
230
+ midpoints[i] = controlPoints[i];
231
+ }
232
+ for (let i = 0; i < count; ++i) {
233
+ l[i] = midpoints[0];
234
+ r[count - i - 1] = midpoints[count - i - 1];
235
+ for (let j = 0; j < count - i - 1; ++j) {
236
+ midpoints[j] = midpoints[j].add(midpoints[j + 1]).divide(2);
237
+ }
238
+ }
239
+ }
240
+ /**
241
+ * Finds a point on the spline at the position of a parameter.
242
+ *
243
+ * @param vec1 The first vector.
244
+ * @param vec2 The second vector.
245
+ * @param vec3 The third vector.
246
+ * @param vec4 The fourth vector.
247
+ * @param t The parameter at which to find the point on the spline, in the range [0, 1].
248
+ */
249
+ static catmullFindPoint(vec1, vec2, vec3, vec4, t) {
250
+ const t2 = Math.pow(t, 2);
251
+ const t3 = Math.pow(t, 3);
252
+ return new Vector2_1.Vector2(0.5 *
253
+ (2 * vec2.x +
254
+ (-vec1.x + vec3.x) * t +
255
+ (2 * vec1.x - 5 * vec2.x + 4 * vec3.x - vec4.x) * t2 +
256
+ (-vec1.x + 3 * vec2.x - 3 * vec3.x + vec4.x) * t3), 0.5 *
257
+ (2 * vec2.y +
258
+ (-vec1.y + vec3.y) * t +
259
+ (2 * vec1.y - 5 * vec2.y + 4 * vec3.y - vec4.y) * t2 +
260
+ (-vec1.y + 3 * vec2.y - 3 * vec3.y + vec4.y) * t3));
261
+ }
262
+ }
263
+ exports.PathApproximator = PathApproximator;
264
+ PathApproximator.bezierTolerance = 0.25;
265
+ /**
266
+ * The amount of pieces to calculate for each control point quadruplet.
267
+ */
268
+ PathApproximator.catmullDetail = 50;
269
+ PathApproximator.circularArcTolerance = 0.1;
@@ -0,0 +1,31 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Precision = void 0;
4
+ /**
5
+ * Precision utilities.
6
+ */
7
+ class Precision {
8
+ /**
9
+ * Checks if two numbers are equal with a given tolerance.
10
+ *
11
+ * @param value1 The first number.
12
+ * @param value2 The second number.
13
+ * @param acceptableDifference The acceptable difference as threshold. Default is `Precision.FLOAT_EPSILON = 1e-3`.
14
+ */
15
+ static almostEqualsNumber(value1, value2, acceptableDifference = this.FLOAT_EPSILON) {
16
+ return Math.abs(value1 - value2) <= acceptableDifference;
17
+ }
18
+ /**
19
+ * Checks if two vectors are equal with a given tolerance.
20
+ *
21
+ * @param vec1 The first vector.
22
+ * @param vec2 The second vector.
23
+ * @param acceptableDifference The acceptable difference as threshold. Default is `Precision.FLOAT_EPSILON = 1e-3`.
24
+ */
25
+ static almostEqualsVector(vec1, vec2, acceptableDifference = this.FLOAT_EPSILON) {
26
+ return (this.almostEqualsNumber(vec1.x, vec2.x, acceptableDifference) &&
27
+ this.almostEqualsNumber(vec1.y, vec2.y, acceptableDifference));
28
+ }
29
+ }
30
+ exports.Precision = Precision;
31
+ Precision.FLOAT_EPSILON = 1e-3;
@@ -0,0 +1,187 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SliderPath = void 0;
4
+ const PathType_1 = require("../constants/PathType");
5
+ const PathApproximator_1 = require("../utils/PathApproximator");
6
+ const Vector2_1 = require("../mathutil/Vector2");
7
+ const Precision_1 = require("./Precision");
8
+ /**
9
+ * Represents a slider's path.
10
+ */
11
+ class SliderPath {
12
+ constructor(values) {
13
+ /**
14
+ * Whether or not the instance has been initialized.
15
+ */
16
+ this.isInitialized = false;
17
+ /**
18
+ * The calculated path of the slider.
19
+ */
20
+ this.calculatedPath = [];
21
+ /**
22
+ * The cumulative length of the slider.
23
+ */
24
+ this.cumulativeLength = [];
25
+ this.pathType = values.pathType;
26
+ this.controlPoints = values.controlPoints;
27
+ this.expectedDistance = values.expectedDistance;
28
+ this.ensureInitialized();
29
+ }
30
+ /**
31
+ * Initializes the instance.
32
+ */
33
+ ensureInitialized() {
34
+ if (this.isInitialized) {
35
+ return;
36
+ }
37
+ this.isInitialized = true;
38
+ this.calculatedPath.length = 0;
39
+ this.cumulativeLength.length = 0;
40
+ this.calculatePath();
41
+ this.calculateCumulativeLength();
42
+ }
43
+ /**
44
+ * Calculates the slider's path.
45
+ */
46
+ calculatePath() {
47
+ this.calculatedPath.length = 0;
48
+ let spanStart = 0;
49
+ for (let i = 0; i < this.controlPoints.length; i++) {
50
+ if (i === this.controlPoints.length - 1 ||
51
+ this.controlPoints[i].equals(this.controlPoints[i + 1])) {
52
+ const spanEnd = i + 1;
53
+ const cpSpan = this.controlPoints.slice(spanStart, spanEnd);
54
+ this.calculateSubPath(cpSpan).forEach((t) => {
55
+ if (this.calculatedPath.length === 0 ||
56
+ !this.calculatedPath.at(-1).equals(t)) {
57
+ this.calculatedPath.push(t);
58
+ }
59
+ });
60
+ spanStart = spanEnd;
61
+ }
62
+ }
63
+ }
64
+ /**
65
+ * Calculates the slider's subpath.
66
+ */
67
+ calculateSubPath(subControlPoints) {
68
+ switch (this.pathType) {
69
+ case PathType_1.PathType.Linear:
70
+ return PathApproximator_1.PathApproximator.approximateLinear(subControlPoints);
71
+ case PathType_1.PathType.PerfectCurve: {
72
+ if (subControlPoints.length !== 3) {
73
+ break;
74
+ }
75
+ const subPath = PathApproximator_1.PathApproximator.approximateCircularArc(subControlPoints);
76
+ // If for some reason a circular arc could not be fit to the 3 given points, fall back to a numerically stable bezier approximation.
77
+ if (subPath.length === 0) {
78
+ break;
79
+ }
80
+ return subPath;
81
+ }
82
+ case PathType_1.PathType.Catmull:
83
+ return PathApproximator_1.PathApproximator.approximateCatmull(subControlPoints);
84
+ }
85
+ return PathApproximator_1.PathApproximator.approximateBezier(subControlPoints);
86
+ }
87
+ /**
88
+ * Calculates the slider's cumulative length.
89
+ */
90
+ calculateCumulativeLength() {
91
+ let calculatedLength = 0;
92
+ this.cumulativeLength.length = 0;
93
+ this.cumulativeLength.push(0);
94
+ for (let i = 0; i < this.calculatedPath.length - 1; ++i) {
95
+ const diff = this.calculatedPath[i + 1].subtract(this.calculatedPath[i]);
96
+ calculatedLength += diff.length;
97
+ this.cumulativeLength.push(calculatedLength);
98
+ }
99
+ if (calculatedLength !== this.expectedDistance) {
100
+ // In osu-stable, if the last two control points of a slider are equal, extension is not performed.
101
+ if (this.controlPoints.length >= 2 &&
102
+ this.controlPoints.at(-1).equals(this.controlPoints.at(-2)) &&
103
+ this.expectedDistance > calculatedLength) {
104
+ this.cumulativeLength.push(calculatedLength);
105
+ return;
106
+ }
107
+ // The last length is always incorrect
108
+ this.cumulativeLength.pop();
109
+ let pathEndIndex = this.calculatedPath.length - 1;
110
+ if (calculatedLength > this.expectedDistance) {
111
+ // The path will be shortened further, in which case we should trim any more unnecessary lengths and their associated path segments
112
+ while (this.cumulativeLength.length > 0 &&
113
+ this.cumulativeLength.at(-1) >= this.expectedDistance) {
114
+ this.cumulativeLength.pop();
115
+ this.calculatedPath.splice(pathEndIndex--, 1);
116
+ }
117
+ }
118
+ if (pathEndIndex <= 0) {
119
+ // The expected distance is negative or zero
120
+ this.cumulativeLength.push(0);
121
+ return;
122
+ }
123
+ // The direction of the segment to shorten or lengthen
124
+ const dir = this.calculatedPath[pathEndIndex].subtract(this.calculatedPath[pathEndIndex - 1]);
125
+ dir.normalize();
126
+ this.calculatedPath[pathEndIndex] = this.calculatedPath[pathEndIndex - 1].add(dir.scale(this.expectedDistance - this.cumulativeLength.at(-1)));
127
+ this.cumulativeLength.push(this.expectedDistance);
128
+ }
129
+ }
130
+ /**
131
+ * Computes the position on the slider at a given progress that ranges from 0 (beginning of the path)
132
+ * to 1 (end of the path).
133
+ *
134
+ * @param progress Ranges from 0 (beginning of the path) to 1 (end of the path).
135
+ */
136
+ positionAt(progress) {
137
+ this.ensureInitialized();
138
+ const d = this.progressToDistance(progress);
139
+ return this.interpolateVerticles(this.indexOfDistance(d), d);
140
+ }
141
+ /**
142
+ * Returns the progress of reaching expected distance.
143
+ */
144
+ progressToDistance(progress) {
145
+ return Math.min(Math.max(progress, 0), 1) * this.expectedDistance;
146
+ }
147
+ /**
148
+ * Interpolates verticles of the slider.
149
+ */
150
+ interpolateVerticles(i, d) {
151
+ if (this.calculatedPath.length === 0) {
152
+ return new Vector2_1.Vector2(0, 0);
153
+ }
154
+ if (i <= 0) {
155
+ return this.calculatedPath[0];
156
+ }
157
+ if (i >= this.calculatedPath.length) {
158
+ return this.calculatedPath.at(-1);
159
+ }
160
+ const p0 = this.calculatedPath[i - 1];
161
+ const p1 = this.calculatedPath[i];
162
+ const d0 = this.cumulativeLength[i - 1];
163
+ const d1 = this.cumulativeLength[i];
164
+ // Avoid division by and almost-zero number in case two points are extremely close to each other.
165
+ if (Precision_1.Precision.almostEqualsNumber(d0, d1)) {
166
+ return p0;
167
+ }
168
+ const w = (d - d0) / (d1 - d0);
169
+ return p0.add(p1.subtract(p0).scale(w));
170
+ }
171
+ /**
172
+ * Returns the index of distance.
173
+ */
174
+ indexOfDistance(d) {
175
+ const index = this.cumulativeLength.indexOf(d);
176
+ if (index < 0) {
177
+ for (let i = 0; i < this.cumulativeLength.length; ++i) {
178
+ if (this.cumulativeLength[i] > d) {
179
+ return i;
180
+ }
181
+ }
182
+ return this.cumulativeLength.length;
183
+ }
184
+ return index;
185
+ }
186
+ }
187
+ exports.SliderPath = SliderPath;
@@ -0,0 +1,53 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.Utils = void 0;
7
+ const lodash_clonedeep_1 = __importDefault(require("lodash.clonedeep"));
8
+ /**
9
+ * Some utilities, no biggie.
10
+ */
11
+ class Utils {
12
+ /**
13
+ * Returns a random element of an array.
14
+ *
15
+ * @param array The array to get the element from.
16
+ */
17
+ static getRandomArrayElement(array) {
18
+ return array[Math.floor(Math.random() * array.length)];
19
+ }
20
+ /**
21
+ * Deep copies an object.
22
+ *
23
+ * @param obj The object to deep copy.
24
+ */
25
+ static deepCopy(obj) {
26
+ return (0, lodash_clonedeep_1.default)(obj);
27
+ }
28
+ /**
29
+ * Creates an array with specific length that's prefilled with an initial value.
30
+ *
31
+ * @param length The length of the array.
32
+ * @param initialValue The initial value of each array value.
33
+ */
34
+ static initializeArray(length, initialValue) {
35
+ const array = new Array(length);
36
+ if (initialValue !== undefined) {
37
+ for (let i = 0; i < length; ++i) {
38
+ array[i] = initialValue;
39
+ }
40
+ }
41
+ return array;
42
+ }
43
+ /**
44
+ * Pauses the execution of a function for
45
+ * the specified duration.
46
+ *
47
+ * @param duration The duration to pause for, in seconds.
48
+ */
49
+ static sleep(duration) {
50
+ return new Promise((resolve) => setTimeout(resolve, duration * 1000));
51
+ }
52
+ }
53
+ exports.Utils = Utils;
package/package.json ADDED
@@ -0,0 +1,43 @@
1
+ {
2
+ "name": "@rian8337/osu-base",
3
+ "version": "1.0.0",
4
+ "description": "Base module for all osu! related modules.",
5
+ "keywords": [
6
+ "osu",
7
+ "beatmap-parser"
8
+ ],
9
+ "author": "Rian8337 <52914632+Rian8337@users.noreply.github.com>",
10
+ "homepage": "https://github.com/Rian8337/osu-droid-module#readme",
11
+ "license": "MIT",
12
+ "main": "dist/index.js",
13
+ "types": "typings/index.d.ts",
14
+ "files": [
15
+ "dist/**",
16
+ "typings/**"
17
+ ],
18
+ "scripts": {
19
+ "build": "tsc",
20
+ "prepare": "npm run build",
21
+ "test": "jest -i"
22
+ },
23
+ "repository": {
24
+ "type": "git",
25
+ "url": "git+https://github.com/Rian8337/osu-droid-module.git"
26
+ },
27
+ "bugs": {
28
+ "url": "https://github.com/Rian8337/osu-droid-module/issues"
29
+ },
30
+ "dependencies": {
31
+ "@types/lodash.clonedeep": "^4.5.6",
32
+ "dotenv": "^14.2.0",
33
+ "lodash.clonedeep": "^4.5.0",
34
+ "request": "^2.88.2"
35
+ },
36
+ "devDependencies": {
37
+ "@types/request": "^2.48.8"
38
+ },
39
+ "publishConfig": {
40
+ "access": "public"
41
+ },
42
+ "gitHead": "e4fdb9c1ed6f90e70651c1aedfdb964b61cb240d"
43
+ }