UNPKG

@fukutotojido/osu-classes

Version:

Basic classes, interfaces and utils for creating new osu! rulesets

1,957 lines (1,718 loc) 160 kB
class BeatmapColorSection { comboColors = []; sliderTrackColor; sliderBorderColor; clone() { const cloned = new BeatmapColorSection(); cloned.comboColors = this.comboColors.map((c) => c.clone()); if (this.sliderTrackColor) { cloned.sliderTrackColor = this.sliderTrackColor; } if (this.sliderBorderColor) { cloned.sliderBorderColor = this.sliderBorderColor; } return cloned; } } class BeatmapDifficultySection { static BASE_DIFFICULTY = 5; _CS = BeatmapDifficultySection.BASE_DIFFICULTY; _HP = BeatmapDifficultySection.BASE_DIFFICULTY; _OD = BeatmapDifficultySection.BASE_DIFFICULTY; _AR; _multiplier = 1; _tickRate = 1; _rate = 1; get circleSize() { return Math.fround(this._CS); } set circleSize(value) { this._CS = value; } get drainRate() { return Math.fround(this._HP); } set drainRate(value) { this._HP = value; } get overallDifficulty() { return Math.fround(this._OD); } set overallDifficulty(value) { this._OD = value; } get approachRate() { return Math.fround(this._AR ?? this._OD); } set approachRate(value) { this._AR = value; } get sliderMultiplier() { return this._multiplier; } set sliderMultiplier(value) { this._multiplier = value; } get sliderTickRate() { return this._tickRate; } set sliderTickRate(value) { this._tickRate = value; } get clockRate() { return this._rate; } set clockRate(value) { this._rate = value; } clone() { const cloned = new BeatmapDifficultySection(); cloned.circleSize = this._CS; cloned.drainRate = this._HP; cloned.overallDifficulty = this._OD; if (typeof this._AR === 'number') { cloned.approachRate = this._AR; } cloned.sliderMultiplier = this._multiplier; cloned.sliderTickRate = this._tickRate; cloned.clockRate = this._rate; return cloned; } static range(diff, min, mid, max) { if (diff > 5) { return mid + ((max - mid) * (diff - 5)) / 5; } if (diff < 5) { return mid - ((mid - min) * (5 - diff)) / 5; } return mid; } } class BeatmapEditorSection { bookmarks = []; distanceSpacing = 1; beatDivisor = 4; gridSize = 1; timelineZoom = 2; clone() { const cloned = new BeatmapEditorSection(); cloned.bookmarks = this.bookmarks.slice(); cloned.distanceSpacing = this.distanceSpacing; cloned.beatDivisor = this.beatDivisor; cloned.gridSize = this.gridSize; cloned.timelineZoom = this.timelineZoom; return cloned; } } let BlendingMode; (function(BlendingMode) { BlendingMode[BlendingMode['AdditiveBlending'] = 0] = 'AdditiveBlending'; BlendingMode[BlendingMode['AlphaBlending'] = 1] = 'AlphaBlending'; })(BlendingMode || (BlendingMode = {})); class BlendingParameters { source; destination; sourceAlpha; destinationAlpha; rgbEquation; alphaEquation; static None = new BlendingParameters({ source: 5, destination: 15, sourceAlpha: 5, destinationAlpha: 15, rgbEquation: 1, alphaEquation: 1, }); static Inherit = new BlendingParameters({ source: 0, destination: 0, sourceAlpha: 0, destinationAlpha: 0, rgbEquation: 0, alphaEquation: 0, }); static Mixture = new BlendingParameters({ source: 12, destination: 10, sourceAlpha: 5, destinationAlpha: 5, rgbEquation: 1, alphaEquation: 1, }); static Additive = new BlendingParameters({ source: 12, destination: 5, sourceAlpha: 5, destinationAlpha: 5, rgbEquation: 1, alphaEquation: 1, }); constructor(params) { this.source = params.source || 0; this.destination = params.destination || 0; this.sourceAlpha = params.sourceAlpha || 0; this.destinationAlpha = params.destinationAlpha || 0; this.rgbEquation = params.rgbEquation || 0; this.alphaEquation = params.alphaEquation || 0; } copyFromParent(parent) { if (this.source === 0) { this.source = parent.source; } if (this.destination === 0) { this.destination = parent.destination; } if (this.sourceAlpha === 0) { this.sourceAlpha = parent.sourceAlpha; } if (this.destinationAlpha === 0) { this.destinationAlpha = parent.destinationAlpha; } if (this.rgbEquation === 0) { this.rgbEquation = parent.rgbEquation; } if (this.alphaEquation === 0) { this.alphaEquation = parent.alphaEquation; } } applyDefaultToInherited() { if (this.source === 0) { this.source = 12; } if (this.destination === 0) { this.destination = 10; } if (this.sourceAlpha === 0) { this.sourceAlpha = 5; } if (this.destinationAlpha === 0) { this.destinationAlpha = 5; } if (this.rgbEquation === 0) { this.rgbEquation = 1; } if (this.alphaEquation === 0) { this.alphaEquation = 1; } } equals(other) { return other.source === this.source && other.destination === this.destination && other.sourceAlpha === this.sourceAlpha && other.destinationAlpha === this.destinationAlpha && other.rgbEquation === this.rgbEquation && other.alphaEquation === this.alphaEquation; } get isDisabled() { return this.source === 5 && this.destination === 15 && this.sourceAlpha === 5 && this.destinationAlpha === 15 && this.rgbEquation === 1 && this.alphaEquation === 1; } get rgbEquationMode() { return BlendingParameters._translateEquation(this.rgbEquation); } get alphaEquationMode() { return BlendingParameters._translateEquation(this.alphaEquation); } get sourceBlendingFactor() { return BlendingParameters._translateBlendingFactorSrc(this.source); } get destinationBlendingFactor() { return BlendingParameters._translateBlendingFactorDest(this.destination); } get sourceAlphaBlendingFactor() { return BlendingParameters._translateBlendingFactorSrc(this.sourceAlpha); } get destinationAlphaBlendingFactor() { return BlendingParameters._translateBlendingFactorDest(this.destinationAlpha); } static _translateBlendingFactorSrc(factor) { switch (factor) { case 1: return 32771; case 2: return 32769; case 3: return 772; case 4: return 774; case 5: return 1; case 6: return 32772; case 7: return 32770; case 8: return 773; case 9: return 775; case 10: return 769; case 12: return 770; case 13: return 776; case 14: return 768; default: case 15: return 0; } } static _translateBlendingFactorDest(factor) { switch (factor) { case 1: return 32771; case 2: return 32769; case 3: return 772; case 4: return 774; case 5: return 1; case 6: return 32772; case 7: return 32770; case 8: return 773; case 9: return 775; case 10: return 771; case 11: return 769; case 12: return 770; case 13: return 776; case 14: return 768; default: case 15: return 0; } } static _translateEquation(equation) { switch (equation) { default: case 0: case 1: return 32774; case 2: return 32775; case 3: return 32776; case 4: return 32778; case 5: return 32779; } } } let Anchor; (function(Anchor) { Anchor[Anchor['y0'] = 1] = 'y0'; Anchor[Anchor['y1'] = 2] = 'y1'; Anchor[Anchor['y2'] = 4] = 'y2'; Anchor[Anchor['x0'] = 8] = 'x0'; Anchor[Anchor['x1'] = 16] = 'x1'; Anchor[Anchor['x2'] = 32] = 'x2'; Anchor[Anchor['Custom'] = 64] = 'Custom'; Anchor[Anchor['TopLeft'] = 9] = 'TopLeft'; Anchor[Anchor['TopCentre'] = 17] = 'TopCentre'; Anchor[Anchor['TopRight'] = 33] = 'TopRight'; Anchor[Anchor['CentreLeft'] = 10] = 'CentreLeft'; Anchor[Anchor['Centre'] = 18] = 'Centre'; Anchor[Anchor['CentreRight'] = 34] = 'CentreRight'; Anchor[Anchor['BottomLeft'] = 12] = 'BottomLeft'; Anchor[Anchor['BottomCentre'] = 20] = 'BottomCentre'; Anchor[Anchor['BottomRight'] = 36] = 'BottomRight'; })(Anchor || (Anchor = {})); let CommandType; (function(CommandType) { CommandType['None'] = ''; CommandType['Movement'] = 'M'; CommandType['MovementX'] = 'MX'; CommandType['MovementY'] = 'MY'; CommandType['Fade'] = 'F'; CommandType['Scale'] = 'S'; CommandType['VectorScale'] = 'V'; CommandType['Rotation'] = 'R'; CommandType['Color'] = 'C'; CommandType['Parameter'] = 'P'; })(CommandType || (CommandType = {})); let CompoundType; (function(CompoundType) { CompoundType['None'] = ''; CompoundType['Loop'] = 'L'; CompoundType['Trigger'] = 'T'; })(CompoundType || (CompoundType = {})); let EventType; (function(EventType) { EventType[EventType['Background'] = 0] = 'Background'; EventType[EventType['Video'] = 1] = 'Video'; EventType[EventType['Break'] = 2] = 'Break'; EventType[EventType['Colour'] = 3] = 'Colour'; EventType[EventType['Sprite'] = 4] = 'Sprite'; EventType[EventType['Sample'] = 5] = 'Sample'; EventType[EventType['Animation'] = 6] = 'Animation'; EventType[EventType['StoryboardCommand'] = 7] = 'StoryboardCommand'; })(EventType || (EventType = {})); let LayerType; (function(LayerType) { LayerType[LayerType['Background'] = 0] = 'Background'; LayerType[LayerType['Fail'] = 1] = 'Fail'; LayerType[LayerType['Pass'] = 2] = 'Pass'; LayerType[LayerType['Foreground'] = 3] = 'Foreground'; LayerType[LayerType['Overlay'] = 4] = 'Overlay'; LayerType[LayerType['Video'] = 5] = 'Video'; })(LayerType || (LayerType = {})); let LoopType; (function(LoopType) { LoopType[LoopType['LoopForever'] = 0] = 'LoopForever'; LoopType[LoopType['LoopOnce'] = 1] = 'LoopOnce'; })(LoopType || (LoopType = {})); let Origins; (function(Origins) { Origins[Origins['TopLeft'] = 0] = 'TopLeft'; Origins[Origins['Centre'] = 1] = 'Centre'; Origins[Origins['CentreLeft'] = 2] = 'CentreLeft'; Origins[Origins['TopRight'] = 3] = 'TopRight'; Origins[Origins['BottomCentre'] = 4] = 'BottomCentre'; Origins[Origins['TopCentre'] = 5] = 'TopCentre'; Origins[Origins['Custom'] = 6] = 'Custom'; Origins[Origins['CentreRight'] = 7] = 'CentreRight'; Origins[Origins['BottomLeft'] = 8] = 'BottomLeft'; Origins[Origins['BottomRight'] = 9] = 'BottomRight'; })(Origins || (Origins = {})); let ParameterType; (function(ParameterType) { ParameterType['None'] = ''; ParameterType['HorizontalFlip'] = 'H'; ParameterType['VerticalFlip'] = 'V'; ParameterType['BlendingMode'] = 'A'; })(ParameterType || (ParameterType = {})); class Color4 { red; green; blue; alpha; constructor(red, green, blue, alpha) { this.red = red ?? 255; this.green = green ?? 255; this.blue = blue ?? 255; this.alpha = alpha ?? 1; } get hex() { const alpha = Math.round(this.alpha * 255); return ('#' + this.red.toString(16).padStart(2, '0') + this.green.toString(16).padStart(2, '0') + this.blue.toString(16).padStart(2, '0') + alpha.toString(16).padStart(2, '0')); } equals(color) { return this.red === color.red && this.green === color.green && this.blue === color.blue && this.alpha === color.alpha; } clone() { return new Color4(this.red, this.green, this.blue, this.alpha); } toString() { return `${this.red},${this.green},${this.blue},${this.alpha}`; } } class Vector2 { x; y; constructor(x, y) { this.x = x; this.y = isFinite(y) ? y : x; } get floatX() { return Math.fround(this.x); } get floatY() { return Math.fround(this.y); } add(vec) { return new Vector2(this.x + vec.x, this.y + vec.y); } fadd(vec) { return new Vector2(Math.fround(this.floatX + vec.floatX), Math.fround(this.floatY + vec.floatY)); } subtract(vec) { return new Vector2(this.x - vec.x, this.y - vec.y); } fsubtract(vec) { return new Vector2(Math.fround(this.floatX - vec.floatX), Math.fround(this.floatY - vec.floatY)); } scale(multiplier) { return new Vector2(this.x * multiplier, this.y * multiplier); } fscale(multiplier) { const floatMultiplier = Math.fround(multiplier); return new Vector2(Math.fround(this.floatX * floatMultiplier), Math.fround(this.floatY * floatMultiplier)); } divide(divisor) { return new Vector2(this.x / divisor, this.y / divisor); } fdivide(divisor) { const floatDivisor = Math.fround(divisor); return new Vector2(Math.fround(this.floatX / floatDivisor), Math.fround(this.floatY / floatDivisor)); } dot(vec) { return this.x * vec.x + this.y * vec.y; } fdot(vec) { return Math.fround(Math.fround(Math.fround(this.floatX * vec.floatX) + Math.fround(this.floatY * vec.floatY))); } length() { return Math.sqrt(this.x * this.x + this.y * this.y); } flength() { return Math.fround(Math.sqrt(Math.fround(Math.fround(this.floatX * this.floatX) + Math.fround(this.floatY * this.floatY)))); } distance(vec) { const x = this.x - vec.x; const y = this.y - vec.y; return Math.sqrt(x * x + y * y); } fdistance(vec) { const x = Math.fround(this.floatX - vec.floatX); const y = Math.fround(this.floatY - vec.floatY); return Math.fround(Math.sqrt(Math.fround(Math.fround(x * x) + Math.fround(y * y)))); } normalize() { const scale = 1 / this.length(); return new Vector2(this.x * scale, this.y * scale); } fnormalize() { const scale = Math.fround(1 / this.flength()); return new Vector2(Math.fround(this.floatX * scale), Math.fround(this.floatY * scale)); } equals(vec) { return this.x === vec.x && this.y === vec.y; } clone() { return new Vector2(this.x, this.y); } toString() { return `${this.x},${this.y}`; } } function clamp(value, min, max) { return Math.max(min, Math.min(max, value)); } function clamp01(value) { return clamp(value, 0, 1); } function map(value, from1, to1, from2, to2) { if (value < from1) { return from2; } if (value >= to1) { return to2; } return (value - from1) / (to1 - from1) * (to2 - from2) + from2; } function map01(value, from1, to1) { return map(value, from1, to1, 0, 1); } function lerp(value, a, b) { return a * (1 - value) + b * value; } function lerpClamped01(value, a, b) { return lerp(clamp01(value), a, b); } function lerpVector2(value, a, b) { const x = lerpClamped01(value, a.floatX, b.floatX); const y = lerpClamped01(value, a.floatY, b.floatY); return new Vector2(x, y); } function lerpColor4(value, a, b) { const red = lerpClamped01(value, a.red, b.red); const green = lerpClamped01(value, a.green, b.green); const blue = lerpClamped01(value, a.blue, b.blue); const alpha = lerpClamped01(value, a.alpha, b.alpha); return new Color4(red, green, blue, alpha); } let MathUtils = /* #__PURE__*/Object.freeze({ __proto__: null, clamp, clamp01, lerp, lerpClamped01, lerpColor4, lerpVector2, map, map01, }); let EasingType; (function(EasingType) { EasingType[EasingType['None'] = 0] = 'None'; EasingType[EasingType['Out'] = 1] = 'Out'; EasingType[EasingType['In'] = 2] = 'In'; EasingType[EasingType['InQuad'] = 3] = 'InQuad'; EasingType[EasingType['OutQuad'] = 4] = 'OutQuad'; EasingType[EasingType['InOutQuad'] = 5] = 'InOutQuad'; EasingType[EasingType['InCubic'] = 6] = 'InCubic'; EasingType[EasingType['OutCubic'] = 7] = 'OutCubic'; EasingType[EasingType['InOutCubic'] = 8] = 'InOutCubic'; EasingType[EasingType['InQuart'] = 9] = 'InQuart'; EasingType[EasingType['OutQuart'] = 10] = 'OutQuart'; EasingType[EasingType['InOutQuart'] = 11] = 'InOutQuart'; EasingType[EasingType['InQuint'] = 12] = 'InQuint'; EasingType[EasingType['OutQuint'] = 13] = 'OutQuint'; EasingType[EasingType['InOutQuint'] = 14] = 'InOutQuint'; EasingType[EasingType['InSine'] = 15] = 'InSine'; EasingType[EasingType['OutSine'] = 16] = 'OutSine'; EasingType[EasingType['InOutSine'] = 17] = 'InOutSine'; EasingType[EasingType['InExpo'] = 18] = 'InExpo'; EasingType[EasingType['OutExpo'] = 19] = 'OutExpo'; EasingType[EasingType['InOutExpo'] = 20] = 'InOutExpo'; EasingType[EasingType['InCirc'] = 21] = 'InCirc'; EasingType[EasingType['OutCirc'] = 22] = 'OutCirc'; EasingType[EasingType['InOutCirc'] = 23] = 'InOutCirc'; EasingType[EasingType['InElastic'] = 24] = 'InElastic'; EasingType[EasingType['OutElastic'] = 25] = 'OutElastic'; EasingType[EasingType['OutElasticHalf'] = 26] = 'OutElasticHalf'; EasingType[EasingType['OutElasticQuarter'] = 27] = 'OutElasticQuarter'; EasingType[EasingType['InOutElastic'] = 28] = 'InOutElastic'; EasingType[EasingType['InBack'] = 29] = 'InBack'; EasingType[EasingType['OutBack'] = 30] = 'OutBack'; EasingType[EasingType['InOutBack'] = 31] = 'InOutBack'; EasingType[EasingType['InBounce'] = 32] = 'InBounce'; EasingType[EasingType['OutBounce'] = 33] = 'OutBounce'; EasingType[EasingType['InOutBounce'] = 34] = 'InOutBounce'; EasingType[EasingType['OutPow10'] = 35] = 'OutPow10'; })(EasingType || (EasingType = {})); const ELASTIC_CONST = 2 * Math.PI / 0.3; const ELASTIC_CONST2 = 0.3 / 4; const BACK_CONST = 1.70158; const BACK_CONST2 = BACK_CONST * 1.525; const BOUNCE_CONST = 1 / 2.75; const EXPO_OFFSET = Math.pow(2, -10); const ELASTIC_OFFSET_FULL = Math.pow(2, -11); const ELASTIC_OFFSET_HALF = Math.pow(2, -10) * Math.sin((0.5 - ELASTIC_CONST2) * ELASTIC_CONST); const ELASTIC_OFFSET_QUARTER = Math.pow(2, -10) * Math.sin((0.25 - ELASTIC_CONST2) * ELASTIC_CONST); const IN_OUT_ELASTIC_OFFSET = Math.pow(2, -10) * Math.sin(((1 - ELASTIC_CONST2 * 1.5) * ELASTIC_CONST) / 1.5); const clampEase = (fn) => (p) => fn(clamp01(p)); const linear = clampEase((p) => p); const inQuad = clampEase((p) => p * p); const outQuad = clampEase((p) => p * (2 - p)); const inOutQuad = clampEase((p) => { if (p < 0.5) { return p * p * 2; } return --p * p * -2 + 1; }); const inCubic = clampEase((p) => p * p * p); const outCubic = clampEase((p) => --p * p * p + 1); const inOutCubic = clampEase((p) => { if (p < 0.5) { return p * p * p * 4; } return --p * p * p * 4 + 1; }); const inQuart = clampEase((p) => p * p * p * p); const outQuart = clampEase((p) => 1 - --p * p * p * p); const inOutQuart = clampEase((p) => { if (p < 0.5) { return p * p * p * p * 8; } return --p * p * p * p * -8 + 1; }); const inQuint = clampEase((p) => { return p * p * p * p * p; }); const outQuint = clampEase((p) => { return --p * p * p * p * p + 1; }); const inOutQuint = clampEase((p) => { if (p < 0.5) { return p * p * p * p * p * 16; } return --p * p * p * p * p * 16 + 1; }); const inSine = clampEase((p) => { return 1 - Math.cos(p * Math.PI * 0.5); }); const outSine = clampEase((p) => { return Math.sin(p * Math.PI * 0.5); }); const inOutSine = clampEase((p) => { return 0.5 - 0.5 * Math.cos(Math.PI * p); }); const inExpo = clampEase((p) => { return Math.pow(2, 10 * (p - 1)) + EXPO_OFFSET * (p - 1); }); const outExpo = clampEase((p) => { return -Math.pow(2, -10 * p) + 1 + EXPO_OFFSET * p; }); const inOutExpo = clampEase((p) => { if (p < 0.5) { return 0.5 * (Math.pow(2, 20 * p - 10) + EXPO_OFFSET * (2 * p - 1)); } return 1 - 0.5 * (Math.pow(2, -20 * p + 10) + EXPO_OFFSET * (-2 * p + 1)); }); const inCirc = clampEase((p) => { return 1 - Math.sqrt(1 - p * p); }); const outCirc = clampEase((p) => { return Math.sqrt(1 - --p * p); }); const inOutCirc = clampEase((p) => { if ((p *= 2) < 1) { return 0.5 - 0.5 * Math.sqrt(1 - p * p); } return 0.5 * Math.sqrt(1 - (p -= 2) * p) + 0.5; }); const inElastic = clampEase((p) => { return -Math.pow(2, -10 + 10 * p) * Math.sin((1 - ELASTIC_CONST2 - p) * ELASTIC_CONST) + ELASTIC_OFFSET_FULL * (1 - p); }); const outElastic = clampEase((p) => { return Math.pow(2, -10 * p) * Math.sin((p - ELASTIC_CONST2) * ELASTIC_CONST) + 1 - ELASTIC_OFFSET_FULL * p; }); const outElasticHalf = clampEase((p) => { return Math.pow(2, -10 * p) * Math.sin((0.5 * p - ELASTIC_CONST2) * ELASTIC_CONST) + 1 - ELASTIC_OFFSET_HALF * p; }); const outElasticQuarter = clampEase((p) => { return Math.pow(2, -10 * p) * Math.sin((0.25 * p - ELASTIC_CONST2) * ELASTIC_CONST) + 1 - ELASTIC_OFFSET_QUARTER * p; }); const inOutElastic = clampEase((p) => { if ((p *= 2) < 1) { return -0.5 * (Math.pow(2, -10 + 10 * p) * Math.sin(((1 - ELASTIC_CONST2 * 1.5 - p) * ELASTIC_CONST) / 1.5) - IN_OUT_ELASTIC_OFFSET * (1 - p)); } return 0.5 * (Math.pow(2, -10 * --p) * Math.sin(((p - ELASTIC_CONST2 * 1.5) * ELASTIC_CONST) / 1.5) - IN_OUT_ELASTIC_OFFSET * p) + 1; }); const inBack = clampEase((p) => { return p * p * ((BACK_CONST + 1) * p - BACK_CONST); }); const outBack = clampEase((p) => { return --p * p * ((BACK_CONST + 1) * p + BACK_CONST) + 1; }); const inOutBack = clampEase((p) => { if ((p *= 2) < 1) { return 0.5 * p * p * ((BACK_CONST2 + 1) * p - BACK_CONST2); } return 0.5 * ((p -= 2) * p * ((BACK_CONST2 + 1) * p + BACK_CONST2) + 2); }); const inBounce = clampEase((p) => { p = 1 - p; if (p < BOUNCE_CONST) { return 1 - 7.5625 * p * p; } if (p < 2 * BOUNCE_CONST) { return 1 - (7.5625 * (p -= 1.5 * BOUNCE_CONST) * p + 0.75); } if (p < 2.5 * BOUNCE_CONST) { return 1 - (7.5625 * (p -= 2.25 * BOUNCE_CONST) * p + 0.9375); } return 1 - (7.5625 * (p -= 2.625 * BOUNCE_CONST) * p + 0.984375); }); const outBounce = clampEase((p) => { if (p < BOUNCE_CONST) { return 7.5625 * p * p; } if (p < 2 * BOUNCE_CONST) { return 7.5625 * (p -= 1.5 * BOUNCE_CONST) * p + 0.75; } if (p < 2.5 * BOUNCE_CONST) { return 7.5625 * (p -= 2.25 * BOUNCE_CONST) * p + 0.9375; } return 7.5625 * (p -= 2.625 * BOUNCE_CONST) * p + 0.984375; }); const inOutBounce = clampEase((p) => { if (p < 0.5) { return 0.5 - 0.5 * outBounce(1 - p * 2); } return outBounce((p - 0.5) * 2) * 0.5 + 0.5; }); const outPow10 = clampEase((p) => { return --p * Math.pow(p, 10) + 1; }); function getEasingFn(easing) { switch (easing) { case EasingType.In: case EasingType.InQuad: return inQuad; case EasingType.Out: case EasingType.OutQuad: return outQuad; case EasingType.InOutQuad: return inOutQuad; case EasingType.InCubic: return inCubic; case EasingType.OutCubic: return outCubic; case EasingType.InOutCubic: return inOutCubic; case EasingType.InQuart: return inQuart; case EasingType.OutQuart: return outQuart; case EasingType.InOutQuart: return inOutQuart; case EasingType.InQuint: return inQuint; case EasingType.OutQuint: return outQuint; case EasingType.InOutQuint: return inOutQuint; case EasingType.InSine: return inSine; case EasingType.OutSine: return outSine; case EasingType.InOutSine: return inOutSine; case EasingType.InExpo: return inExpo; case EasingType.OutExpo: return outExpo; case EasingType.InOutExpo: return inOutExpo; case EasingType.InCirc: return inCirc; case EasingType.OutCirc: return outCirc; case EasingType.InOutCirc: return inOutCirc; case EasingType.InElastic: return inElastic; case EasingType.OutElastic: return outElastic; case EasingType.OutElasticHalf: return outElasticHalf; case EasingType.OutElasticQuarter: return outElasticQuarter; case EasingType.InOutElastic: return inOutElastic; case EasingType.InBack: return inBack; case EasingType.OutBack: return outBack; case EasingType.InOutBack: return inOutBack; case EasingType.InBounce: return inBounce; case EasingType.OutBounce: return outBounce; case EasingType.InOutBounce: return inOutBounce; case EasingType.OutPow10: return outPow10; } return linear; } let Easing = /* #__PURE__*/Object.freeze({ __proto__: null, getEasingFn, inBack, inBounce, inCirc, inCubic, inElastic, inExpo, inOutBack, inOutBounce, inOutCirc, inOutCubic, inOutElastic, inOutExpo, inOutQuad, inOutQuart, inOutQuint, inOutSine, inQuad, inQuart, inQuint, inSine, linear, outBack, outBounce, outCirc, outCubic, outElastic, outElasticHalf, outElasticQuarter, outExpo, outPow10, outQuad, outQuart, outQuint, outSine, }); class Command { type; parameter; easing; startTime; endTime; constructor(params) { this.type = params?.type ?? CommandType.None; this.parameter = params?.parameter ?? ParameterType.None; this.easing = params?.easing ?? EasingType.None; this.startTime = params?.startTime ?? 0; this.endTime = params?.endTime ?? 0; this.startValue = params?.startValue ?? null; this.endValue = params?.endValue ?? null; } get duration() { return this.endTime - this.startTime; } getProgress(time) { const clamped = map01(time, this.startTime, this.endTime); return getEasingFn(this.easing)(clamped); } getValueAtProgress(progress) { const getNumber = (progress, start, end) => { return start + progress * (end - start); }; const getBoolean = (time, start, end) => { return start === end || time >= start && time < end; }; if (typeof this.startValue === 'number') { const startValue = this.startValue; const endValue = this.endValue; return getNumber(progress, startValue, endValue); } if (this.startValue instanceof Vector2) { const startValue = this.startValue; const endValue = this.endValue; return new Vector2(getNumber(progress, startValue.floatX, endValue.floatX), getNumber(progress, startValue.floatY, endValue.floatY)); } if (this.startValue instanceof Color4) { const startValue = this.startValue; const endValue = this.endValue; return new Color4(getNumber(progress, startValue.red, endValue.red), getNumber(progress, startValue.green, endValue.green), getNumber(progress, startValue.blue, endValue.blue), getNumber(progress, startValue.alpha, endValue.alpha)); } const time = this.startTime + this.duration * progress; if (typeof this.startValue === 'boolean') { return getBoolean(time, this.startTime, this.endTime); } if (this.startValue instanceof BlendingParameters) { const startValue = this.startValue; const endValue = this.endValue; const isAdditive = getBoolean(time, this.startTime, this.endTime); return isAdditive ? startValue : endValue; } return this.endValue; } getValueAtTime(time) { return this.getValueAtProgress(this.getProgress(time)); } equals(other) { return this.type === other.type && this.startTime === other.startTime && this.endTime === other.endTime && this.startValue === other.startValue && this.endValue === other.endValue && this.easing === other.easing && this.parameter === other.parameter; } } class CommandTimeline { _commands = []; startTime = Infinity; endTime = -Infinity; [Symbol.iterator]() { const data = this.commands; let i = -1; return { next: () => ({ value: data[++i], done: !(i in data) }), }; } get commands() { return this._commands.sort((a, b) => { return a.startTime - b.startTime || a.endTime - b.endTime; }); } add(type, easing, startTime, endTime, startValue, endValue, parameter) { if (endTime < startTime) { [startTime, endTime] = [endTime, startTime]; [startValue, endValue] = [endValue, startValue]; } this._commands.push(new Command({ type, easing, startTime, endTime, startValue, endValue, parameter, })); if (startTime < this.startTime) { this.startValue = startValue; this.startTime = startTime; } if (endTime > this.endTime) { this.endValue = endValue; this.endTime = endTime; } } get hasCommands() { return this._commands.length > 0; } } class CommandTimelineGroup { x = new CommandTimeline(); y = new CommandTimeline(); scale = new CommandTimeline(); vectorScale = new CommandTimeline(); rotation = new CommandTimeline(); color = new CommandTimeline(); alpha = new CommandTimeline(); blendingParameters = new CommandTimeline(); flipH = new CommandTimeline(); flipV = new CommandTimeline(); _timelines; constructor() { this._timelines = [ this.x, this.y, this.scale, this.vectorScale, this.rotation, this.color, this.alpha, this.blendingParameters, this.flipH, this.flipV, ]; } get timelines() { return this._timelines; } get totalCommands() { return this._timelines.reduce((c, t) => c + t.commands.length, 0); } get commands() { return this._timelines .flatMap((t) => t.commands) .sort((a, b) => a.startTime - b.startTime || a.endTime - b.endTime); } get commandsStartTime() { let min = Infinity; for (let i = 0; i < this._timelines.length; ++i) { min = Math.min(min, this._timelines[i].startTime); } return min; } get commandsEndTime() { let max = -Infinity; for (let i = 0; i < this._timelines.length; ++i) { max = Math.max(max, this._timelines[i].endTime); } return max; } get commandsDuration() { return this.commandsEndTime - this.commandsStartTime; } get startTime() { return this.commandsStartTime; } get endTime() { return this.commandsEndTime; } get duration() { return this.endTime - this.startTime; } get hasCommands() { for (let i = 0; i < this._timelines.length; ++i) { if (this._timelines[i].hasCommands) { return true; } } return false; } } class CommandLoop extends CommandTimelineGroup { type = CompoundType.Loop; loopStartTime; loopCount; constructor(loopStartTime, loopCount) { super(); this.loopStartTime = loopStartTime || 0; this.loopCount = loopCount || 0; } get totalIterations() { return this.loopCount + 1; } get startTime() { return this.loopStartTime + this.commandsStartTime; } get endTime() { return this.startTime + this.commandsDuration * this.totalIterations; } unrollCommands() { const commands = this.commands; if (commands.length === 0) { return []; } const { commandsDuration, totalIterations, loopStartTime } = this; const unrolledCommands = new Array(totalIterations * commands.length); for (let i = 0; i < totalIterations; i++) { const iterationStartTime = loopStartTime + i * commandsDuration; for (let j = 0; j < commands.length; j++) { const currentIndex = i * commands.length + j; const command = commands[j]; unrolledCommands[currentIndex] = new Command({ ...command, startTime: command.startTime + iterationStartTime, endTime: command.endTime + iterationStartTime, }); } } return unrolledCommands; } } class CommandTrigger extends CommandTimelineGroup { type = CompoundType.Trigger; triggerName; triggerStartTime; triggerEndTime; groupNumber; constructor(triggerName, startTime, endTime, groupNumber) { super(); this.triggerName = triggerName || ''; this.triggerStartTime = startTime || 0; this.triggerEndTime = endTime || 0; this.groupNumber = groupNumber || 0; } unrollCommands() { const commands = this.commands; if (commands.length === 0) { return []; } const unrolledCommands = new Array(commands.length); for (let i = 0; i < commands.length; i++) { unrolledCommands[i] = new Command({ ...commands[i], startTime: commands[i].startTime + this.triggerStartTime, endTime: commands[i].endTime + this.triggerStartTime, }); } return unrolledCommands; } } class StoryboardSprite { origin; anchor; startTime = Infinity; endTime = -Infinity; filePath; commands = []; timelineGroup = new CommandTimelineGroup(); loops = []; triggers = []; startPosition; scale = new Vector2(1, 1); color = new Color4(); rotation = 0; flipX = false; flipY = false; isAdditive = false; constructor(path, origin, anchor, position) { this.filePath = path ?? ''; this.origin = origin ?? Origins.TopLeft; this.anchor = anchor ?? Anchor.TopLeft; this.startPosition = position ?? new Vector2(0, 0); } get startX() { return this.startPosition.floatX; } set startX(value) { this.startPosition.x = value; } get startY() { return this.startPosition.floatY; } set startY(value) { this.startPosition.y = value; } get duration() { return this.endTime - this.startTime; } get hasCommands() { return this.timelineGroup.hasCommands || this.loops.some((l) => l.hasCommands) || this.triggers.some((t) => t.hasCommands); } get isDrawable() { return this.color.alpha >= 0.01 && this.hasCommands; } addLoop(startTime, repeatCount) { const loop = new CommandLoop(startTime, repeatCount); this.loops.push(loop); return loop; } addTrigger(triggerName, startTime, endTime, groupNumber) { const trigger = new CommandTrigger(triggerName, startTime, endTime, groupNumber); this.triggers.push(trigger); return trigger; } updateCommands() { const unwinded = [ ...this.timelineGroup.commands, ...this.loops.flatMap((l) => l.unrollCommands()), ]; this.commands = unwinded.sort((a, b) => a.startTime - b.startTime); return this.commands; } adjustTimesToCommands() { let earliestStartTime = this.startTime; let latestEndTime = this.endTime; for (const command of this.commands) { earliestStartTime = Math.min(earliestStartTime, command.startTime); latestEndTime = Math.max(latestEndTime, command.endTime); } this.startTime = earliestStartTime; this.endTime = latestEndTime; } resetValuesToCommands() { const applied = {}; for (const command of this.commands) { if (!applied[command.type]) { this.setValueFromCommand(command, 0); applied[command.type] = true; } } } setValueFromCommand(command, progress) { const value = command.getValueAtProgress(progress); switch (command.type) { case CommandType.Movement: this.startPosition.x = value.x; this.startPosition.y = value.y; break; case CommandType.MovementX: this.startPosition.x = value; break; case CommandType.MovementY: this.startPosition.y = value; break; case CommandType.Fade: this.color.alpha = value; break; case CommandType.Scale: this.scale.x = value; this.scale.y = value; break; case CommandType.VectorScale: this.scale.x = value.x; this.scale.y = value.y; break; case CommandType.Rotation: this.rotation = value; break; case CommandType.Color: this.color.red = value.red; this.color.green = value.green; this.color.blue = value.blue; break; } if (command.type !== CommandType.Parameter) { return; } switch (command.parameter) { case ParameterType.BlendingMode: this.isAdditive = value.rgbEquation === 1; break; case ParameterType.HorizontalFlip: this.flipX = value; break; case ParameterType.VerticalFlip: this.flipY = value; } } } class StoryboardAnimation extends StoryboardSprite { frameCount; frameDelay; loopType; constructor(path, origin, anchor, position, frameCount, frameDelay, loopType) { super(path, origin, anchor, position); this.frameCount = frameCount ?? 0; this.frameDelay = frameDelay ?? 0; this.loopType = loopType ?? LoopType.LoopForever; } } class StoryboardSample { startTime; volume; filePath; get isDrawable() { return true; } constructor(path, time, volume) { this.filePath = path ?? ''; this.startTime = time ?? 0; this.volume = volume ?? 100; } } class StoryboardVideo { startTime; filePath; get isDrawable() { return true; } constructor(path, time) { this.filePath = path ?? ''; this.startTime = time ?? 0; } } class StoryboardLayer { name; depth; masking; visibleWhenPassing = true; visibleWhenFailing = true; elements = []; constructor(params) { this.name = params.name; this.depth = params.depth; this.masking = params.masking ?? true; } } class Storyboard { variables = new Map(); colors = new BeatmapColorSection(); useSkinSprites = false; minimumLayerDepth = 0; fileFormat = 14; _layers = new Map(); constructor() { this.addLayer(new StoryboardLayer({ name: 'Video', depth: 4, masking: false })); this.addLayer(new StoryboardLayer({ name: 'Background', depth: 3 })); this.addLayer(new StoryboardLayer({ name: 'Fail', depth: 2, visibleWhenPassing: false })); this.addLayer(new StoryboardLayer({ name: 'Pass', depth: 1, visibleWhenFailing: false })); this.addLayer(new StoryboardLayer({ name: 'Foreground', depth: 0 })); this.addLayer(new StoryboardLayer({ name: 'Overlay', depth: -2147483648 })); } get layers() { return this._layers; } get hasDrawable() { for (const layer of this.layers.values()) { if (layer.elements.find((e) => e.isDrawable)) { return true; } } return false; } get hasVariables() { for (const _ in this.variables) { return true; } return false; } get earliestEventTime() { let time = Infinity; this._layers.forEach((layer) => { const elements = layer.elements; const min = elements.reduce((m, el) => Math.min(m, el.startTime), 0); time = Math.min(min, time); }); return time === Infinity ? null : time; } get latestEventTime() { let time = -Infinity; this._layers.forEach((layer) => { const elements = layer.elements; const max = elements.reduce((max, element) => { const durationElement = element; return Math.max(max, durationElement?.endTime ?? element.startTime); }, 0); time = Math.max(max, time); }); return time === -Infinity ? null : time; } addLayer(layer) { if (this._layers.has(layer.name)) { return; } this._layers.set(layer.name, layer); } getLayerByType(type) { return this.getLayerByName(LayerType[type] ?? 'Background'); } getLayerByName(name) { const layer = this._layers.get(name) ?? new StoryboardLayer({ name, depth: --this.minimumLayerDepth }); if (!this._layers.has(name)) { this._layers.set(name, layer); } return layer; } } class BeatmapEventSection { backgroundPath = null; breaks = []; storyboard = null; get isBackgroundReplaced() { if (!this.backgroundPath || !this.storyboard) { return false; } const filePath = this.backgroundPath.trim().toLowerCase(); const layer = this.storyboard.getLayerByType(LayerType.Background); return layer.elements.some((e) => e.filePath.toLowerCase() === filePath); } clone() { const cloned = new BeatmapEventSection(); cloned.backgroundPath = this.backgroundPath; cloned.breaks = this.breaks; cloned.storyboard = this.storyboard; return cloned; } } let SampleSet; (function(SampleSet) { SampleSet[SampleSet['None'] = 0] = 'None'; SampleSet[SampleSet['Normal'] = 1] = 'Normal'; SampleSet[SampleSet['Soft'] = 2] = 'Soft'; SampleSet[SampleSet['Drum'] = 3] = 'Drum'; })(SampleSet || (SampleSet = {})); class BeatmapGeneralSection { audioFilename = ''; audioHash; overlayPosition = 'NoChange'; skinPreference = ''; audioLeadIn = 0; previewTime = -1; countdown = 1; stackLeniency = 0.7; countdownOffset = 0; sampleSet = SampleSet.Normal; letterboxInBreaks = false; storyFireInFront; useSkinSprites = false; alwaysShowPlayfield; epilepsyWarning = false; specialStyle = false; widescreenStoryboard = false; samplesMatchPlaybackRate = false; clone() { const cloned = new BeatmapGeneralSection(); cloned.audioFilename = this.audioFilename; if (this.audioHash) { cloned.audioHash = this.audioHash; } cloned.overlayPosition = this.overlayPosition; cloned.skinPreference = this.skinPreference; cloned.audioLeadIn = this.audioLeadIn; cloned.previewTime = this.previewTime; cloned.countdown = this.countdown; cloned.stackLeniency = this.stackLeniency; cloned.countdownOffset = this.countdownOffset; cloned.sampleSet = this.sampleSet; cloned.letterboxInBreaks = this.letterboxInBreaks; if (this.storyFireInFront) { cloned.storyFireInFront = this.storyFireInFront; } cloned.useSkinSprites = this.useSkinSprites; if (this.alwaysShowPlayfield) { cloned.alwaysShowPlayfield = this.alwaysShowPlayfield; } cloned.epilepsyWarning = this.epilepsyWarning; cloned.specialStyle = this.specialStyle; cloned.widescreenStoryboard = this.widescreenStoryboard; cloned.samplesMatchPlaybackRate = this.samplesMatchPlaybackRate; return cloned; } } class BeatmapMetadataSection { title = 'Unknown Title'; artist = 'Unknown Artist'; creator = 'Unknown Creator'; version = 'Normal'; source = ''; tags = []; beatmapId = 0; beatmapSetId = 0; _titleUnicode = 'Unknown Title'; get titleUnicode() { return this._titleUnicode !== 'Unknown Title' ? this._titleUnicode : this.title; } set titleUnicode(value) { this._titleUnicode = value; } _artistUnicode = 'Unknown Artist'; get artistUnicode() { return this._artistUnicode !== 'Unknown Artist' ? this._artistUnicode : this.artist; } set artistUnicode(value) { this._artistUnicode = value; } clone() { const cloned = new BeatmapMetadataSection(); cloned.title = this.title; cloned.titleUnicode = this.titleUnicode; cloned.artist = this.artist; cloned.artistUnicode = this.artistUnicode; cloned.creator = this.creator; cloned.version = this.version; cloned.source = this.source; cloned.tags = this.tags.slice(); cloned.beatmapId = this.beatmapId; cloned.beatmapSetId = this.beatmapSetId; return cloned; } } class ControlPoint { group; constructor(group) { this.group = group || null; } attachGroup(group) { this.group = group; } dettachGroup() { this.group = null; } get startTime() { if (this.group) { return this.group.startTime; } return 0; } } class ControlPointGroup { controlPoints = []; startTime; constructor(time) { this.startTime = time; } add(point) { const existing = this.controlPoints.find((p) => { return p.pointType === point.pointType; }); if (existing) { this.remove(existing); } point.attachGroup(this); this.controlPoints.push(point); } remove(point) { const index = this.controlPoints.findIndex((p) => { return p.pointType === point.pointType; }); if (index !== -1) { this.controlPoints.splice(index, 1); point.dettachGroup(); } } } function findNumber(arr, x) { let start = 0, mid, end = arr.length - 1; while (start <= end) { mid = start + ((end - start) >> 1); if (arr[mid] === x) { return mid; } if (arr[mid] < x) { start = mid + 1; } else { end = mid - 1; } } return ~start; } function findControlPointIndex(arr, time) { if (!arr.length) { return -1; } if (time < arr[0].startTime) { return -1; } if (time >= arr[arr.length - 1].startTime) { return arr.length - 1; } let l = 0; let r = arr.length - 2; while (l <= r) { const pivot = l + ((r - l) >> 1); if (arr[pivot].startTime < time) { l = pivot + 1; } else if (arr[pivot].startTime > time) { r = pivot - 1; } else { return pivot; } } return l - 1; } function findControlPoint(arr, time) { const index = findControlPointIndex(arr, time); if (index === -1) { return null; } return arr[index]; } function findIndex(arr, predicate) { let l = -1; let r = arr.length - 1; while (1 + l < r) { const mid = l + ((r - l) >> 1); const cmp = predicate(arr[mid], mid, arr); cmp ? (r = mid) : (l = mid); } return r; } let BinarySearch = /* #__PURE__*/Object.freeze({ __proto__: null, findControlPoint, findControlPointIndex, findIndex, findNumber, }); function barycentricWeights(points) { const n = points.length; const w = []; for (let i = 0; i < n; i++) { w[i] = 1; for (let j = 0; j < n; j++) { if (i !== j) { w[i] *= points[i].floatX - points[j].floatX; } } w[i] = 1.0 / w[i]; } return w; } function barycentricLagrange(points, weights, time) { if (points === null || points.length === 0) { throw new Error('points must contain at least one point'); } if (points.length !== weights.length) { throw new Error('points must contain exactly as many items as weights'); } let numerator = 0; let denominator = 0; for (let i = 0, len = points.length; i < len; ++i) { if (time === points[i].floatX) { return points[i].floatY; } const li = weights[i] / (time - points[i].floatX); numerator += li * points[i].floatY; denominator += li; } return numerator / denominator; } let Interpolation = /* #__PURE__*/Object.freeze({ __proto__: null, barycentricLagrange, barycentricWeights, }); class FastRandom { static MAX_INT32 = 2147483647; static MAX_UINT32 = 4294967295; static INT_MASK = 0x7fffffff >> 0; static INT_TO_REAL = 1 / (FastRandom.MAX_INT32 + 1); _y = 842502087 >>> 0; _z = 3579807591 >>> 0; _w = 273326509 >>> 0; _x = 0; _bitBuffer = 0; _bitIndex = 32; constructor(seed) { this._x = seed; } _next() { const t = (this._x ^ ((this._x << 11) >>> 0)) >>> 0; this._x = this._y >>> 0; this._y = this._z >>> 0; this._z = this._w >>> 0; this._w = (this._w ^ (this._w >>> 19)) >>> 0; this._w = (this._w ^ t) >>> 0; this._w = (this._w ^ (t >>> 8)) >>> 0; return this._w; } next() { return (FastRandom.INT_MASK & this._next()) >> 0; } nextUInt(lowerBound = 0, upperBound = FastRandom.MAX_INT32) { if (lowerBound === 0 && upperBound === FastRandom.MAX_INT32) { return this._next(); } return (lowerBound + this.nextDouble() * (upperBound - lowerBound)) >>> 0; } nextInt(lowerBound = 0, upperBound = FastRandom.MAX_INT32) { return (lowerBound + this.nextDouble() * (upperBound - lowerBound)) >> 0; } nextDouble() { return FastRandom.INT_TO_REAL * this.next(); } nextBool() { if (this._bitIndex === 32) { this._bitBuffer = this.nextUInt(); this._bitIndex = 1; return (this._bitBuffer & 1) === 1; } this._bitIndex = (this._bitIndex + 1) >> 0; return ((this._bitBuffer >>= 1) & 1) === 1; } } class RoundHelper { static PRECISION_ERROR = 1e-15; static round(x, mode = 1) { return mode ? this.roundToEven(x) : this.roundAwayFromZero(x); } static roundToEven(x) { return this.isAtMidPoint(x) ? 2 * Math.round(x / 2) : Math.round(x); } static roundAwayFromZero(x) { return this.isAtMidPoint(x) ? (x > 0 ? Math.ceil(x) : Math.floor(x)) : Math.round(x); } static isAtMidPoint(x) { return Math.abs(0.5 - Math.abs(x - (x >> 0))) <= this.PRECISION_ERROR; } } class SortHelper { static _QUICK_SORT_DEPTH_THRESHOLD = 32; static _INTRO_SORT_SIZE_THRESHOLD = 16; static depthSort(keys, comparerFn) { if (!keys || keys.length === 0) { return keys; } comparerFn ??= this.defaultCompare; this._depthLimitedQuickSort(keys, 0, keys.length - 1, comparerFn, this._QUICK_SORT_DEPTH_THRESHOLD); return keys; } static introSort(keys, comparerFn) { if (!keys || keys.length < 2) { return keys; } comparerFn ??= this.defaultCompare; this._introSort(keys, 0, keys.length - 1, comparerFn, 2 * this._floorLog2(keys.length)); return keys; } static _depthLimitedQuickSort(keys, left, right, comparerFn, depthLimit) { do { if (depthLimit === 0) { return this._heapsort(keys, left, right, comparerFn); } let i = left; let j = right; const middle = i + ((j - i) >> 1); this._swapIfGreater(keys, comparerFn, i, middle); this._swapIfGreater(keys, comparerFn, i, j); this._swapIfGreater(keys, comparerFn, middle, j); const x = keys[middle]; do { while (comparerFn(keys[i], x) < 0) { i++; } while (comparerFn(x, keys[j]) < 0) { j--; } if (i > j) { break; } if (i < j) { [keys[i], keys[j]] = [keys[j], keys[i]]; } i++; j--; } while (i <= j); depthLimit--; if (j - left <= right - i) { if (left < j) { this._depthLimitedQuickSort(keys, left, j, comparerFn, depthLimit); } left = i; continue; } if (i < right) { this._depthLimitedQuickSort(keys, i, right, comparerFn, depthLimit); } right = j; } while (left < right); } static _introSort(keys, left, right, comparerFn, depthLimit) { while (right > left) { const partitionSize = right - left + 1; if (partitionSize <= this._INTRO_SORT_SIZE_THRESHOLD) { if