kipphi 2.1.2 → 2.1.3-beta.2
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/bpm.ts +26 -6
- package/chart.ts +42 -2
- package/chartTypes.ts +26 -5
- package/easing.ts +31 -2
- package/env.ts +6 -0
- package/evaluator.ts +39 -14
- package/event.ts +50 -9
- package/index.d.ts +77 -11
- package/index.js +240 -79
- package/judgeline.ts +100 -43
- package/note.ts +19 -21
- package/operation/easy.ts +136 -0
- package/operation/event.ts +7 -0
- package/package.json +1 -1
- package/rpeChartCompiler.ts +39 -10
- package/tsconfig.json +2 -2
- package/util.ts +4 -2
- package/version.ts +1 -1
package/index.js
CHANGED
|
@@ -35,8 +35,9 @@ var rgb2hex = (rgb) => {
|
|
|
35
35
|
var hex2rgb = (hex) => {
|
|
36
36
|
return [hex >> 16, hex >> 8 & 255, hex & 255];
|
|
37
37
|
};
|
|
38
|
+
var DENO = 324324000;
|
|
38
39
|
var numberToRatio = (num) => {
|
|
39
|
-
return [Math.round(num *
|
|
40
|
+
return [Math.round(num * DENO), DENO];
|
|
40
41
|
};
|
|
41
42
|
var toTimeString = (beaT) => `${beaT[0]}:${beaT[1]}/${beaT[2]}`;
|
|
42
43
|
|
|
@@ -77,6 +78,8 @@ var ERROR_IDS;
|
|
|
77
78
|
ERROR_IDS2[ERROR_IDS2["NODES_NOT_CONTINUOUS"] = EASING | INVALID_USAGE | 1] = "NODES_NOT_CONTINUOUS";
|
|
78
79
|
ERROR_IDS2[ERROR_IDS2["NODES_NOT_BELONG_TO_SAME_SEQUENCE"] = EASING | INVALID_USAGE | 2] = "NODES_NOT_BELONG_TO_SAME_SEQUENCE";
|
|
79
80
|
ERROR_IDS2[ERROR_IDS2["NODES_HAS_ZERO_DELTA"] = EASING | INVALID_USAGE | 3] = "NODES_HAS_ZERO_DELTA";
|
|
81
|
+
ERROR_IDS2[ERROR_IDS2["TEMPLATE_EASING_CIRCULAR_REFERENCE"] = EASING | INVALID_USAGE | 4] = "TEMPLATE_EASING_CIRCULAR_REFERENCE";
|
|
82
|
+
ERROR_IDS2[ERROR_IDS2["EASING_DELTA_CANNOT_BE_ZERO"] = EASING | INVALID_USAGE | 5] = "EASING_DELTA_CANNOT_BE_ZERO";
|
|
80
83
|
ERROR_IDS2[ERROR_IDS2["CANNOT_DIVIDE_EXPRESSION_EVALUATOR"] = EVALUATOR | INVALID_USAGE | 0] = "CANNOT_DIVIDE_EXPRESSION_EVALUATOR";
|
|
81
84
|
ERROR_IDS2[ERROR_IDS2["MISSING_MACRO_EVALUATOR_KEY"] = EVALUATOR | INVALID_DATA | 0] = "MISSING_MACRO_EVALUATOR_KEY";
|
|
82
85
|
ERROR_IDS2[ERROR_IDS2["MACRO_EVALUATOR_NOT_FOUND"] = EVALUATOR | INVALID_DATA | 1] = "MACRO_EVALUATOR_NOT_FOUND";
|
|
@@ -126,7 +129,9 @@ var ERRORS = {
|
|
|
126
129
|
PARAMETRIC_MACRO_REQUIRES_PROTO_KEY: (pos) => `Parametric Macro requires key. At ${pos}`,
|
|
127
130
|
MACRO_NOT_PARAMETRIC: (macroId, pos) => `Macro '${macroId}' is not parametric. At ${pos}`,
|
|
128
131
|
EVENT_NODE_NOT_DENSE: (pos) => `EventNode is not dense. At ${pos}`,
|
|
129
|
-
HOLD_HAS_NO_DURATION: () => `Hold should have a duration
|
|
132
|
+
HOLD_HAS_NO_DURATION: () => `Hold should have a duration.`,
|
|
133
|
+
TEMPLATE_EASING_CIRCULAR_REFERENCE: (temEasName) => `Template Easing '${temEasName}' has circular reference`,
|
|
134
|
+
EASING_DELTA_CANNOT_BE_ZERO: (seqName, time) => `Easing delta cannot be zero. (at ${seqName}, ${toTimeString(time)}`
|
|
130
135
|
};
|
|
131
136
|
|
|
132
137
|
class KPAError extends Error {
|
|
@@ -548,6 +553,9 @@ class TemplateEasing extends Easing {
|
|
|
548
553
|
this.name = name;
|
|
549
554
|
}
|
|
550
555
|
getValue(t) {
|
|
556
|
+
if (t === 1) {
|
|
557
|
+
return 1;
|
|
558
|
+
}
|
|
551
559
|
const seq = this.eventNodeSequence;
|
|
552
560
|
const delta = this.valueDelta;
|
|
553
561
|
if (delta === 0) {
|
|
@@ -569,6 +577,28 @@ class TemplateEasing extends Easing {
|
|
|
569
577
|
get headValue() {
|
|
570
578
|
return this.eventNodeSequence.head.next.value;
|
|
571
579
|
}
|
|
580
|
+
segmentedValueGetter(easingLeft, easingRight) {
|
|
581
|
+
return (t) => {
|
|
582
|
+
const leftValue = this.getValue(easingLeft);
|
|
583
|
+
const rightValue = this.getValue(easingRight);
|
|
584
|
+
const timeDelta = easingRight - easingLeft;
|
|
585
|
+
const delta = rightValue - leftValue;
|
|
586
|
+
if (delta === 0) {
|
|
587
|
+
return 0;
|
|
588
|
+
}
|
|
589
|
+
return (this.getValue(easingLeft + timeDelta * t) - leftValue) / delta;
|
|
590
|
+
};
|
|
591
|
+
}
|
|
592
|
+
static checkCircularReference(seq, template) {
|
|
593
|
+
const seq2 = template.eventNodeSequence;
|
|
594
|
+
if (seq === seq2) {
|
|
595
|
+
return true;
|
|
596
|
+
}
|
|
597
|
+
if (seq2.hasReferenceTo(seq)) {
|
|
598
|
+
return true;
|
|
599
|
+
}
|
|
600
|
+
return false;
|
|
601
|
+
}
|
|
572
602
|
}
|
|
573
603
|
|
|
574
604
|
class WrapperEasing extends Easing {
|
|
@@ -952,16 +982,24 @@ class EasedEvaluator extends Evaluator {
|
|
|
952
982
|
super();
|
|
953
983
|
this.easing = easing;
|
|
954
984
|
}
|
|
955
|
-
eval(startNode,
|
|
985
|
+
eval(startNode, beatsOrSeconds, timeCalculator) {
|
|
956
986
|
const next = startNode.next;
|
|
957
|
-
const timeDelta = TC2.getDelta(next.time, startNode.time);
|
|
958
|
-
const current = beats - TC2.toBeats(startNode.time);
|
|
959
987
|
const nextValue = startNode.next.value;
|
|
960
988
|
const value = startNode.value;
|
|
961
989
|
if (nextValue === value) {
|
|
962
990
|
return value;
|
|
963
991
|
}
|
|
964
|
-
|
|
992
|
+
if (timeCalculator) {
|
|
993
|
+
const startSecs = timeCalculator.toSeconds(TC2.toBeats(startNode.time));
|
|
994
|
+
const endSecs = timeCalculator.toSeconds(TC2.toBeats(next.time));
|
|
995
|
+
const current = beatsOrSeconds - startSecs;
|
|
996
|
+
const timeDelta = endSecs - startSecs;
|
|
997
|
+
return this.convert(value, nextValue, this.easing.getValue(current / timeDelta));
|
|
998
|
+
} else {
|
|
999
|
+
const timeDelta = TC2.getDelta(next.time, startNode.time);
|
|
1000
|
+
const current = beatsOrSeconds - TC2.toBeats(startNode.time);
|
|
1001
|
+
return this.convert(value, nextValue, this.easing.getValue(current / timeDelta));
|
|
1002
|
+
}
|
|
965
1003
|
}
|
|
966
1004
|
static getEvaluatorFromEasing(type, easing, interpretedAs) {
|
|
967
1005
|
const easingIsNormal = easing instanceof NormalEasing;
|
|
@@ -1046,11 +1084,11 @@ class TextEasedEvaluator extends EasedEvaluator {
|
|
|
1046
1084
|
if (interpretedAs === 2 /* float */) {
|
|
1047
1085
|
const start = parseFloat(value);
|
|
1048
1086
|
const delta = parseFloat(nextValue) - start;
|
|
1049
|
-
return start + progress * delta + "";
|
|
1087
|
+
return (start + progress * delta).toFixed(3) + "";
|
|
1050
1088
|
} else if (interpretedAs === 1 /* int */) {
|
|
1051
1089
|
const start = parseInt(value);
|
|
1052
1090
|
const delta = parseInt(nextValue) - start;
|
|
1053
|
-
return start + Math.
|
|
1091
|
+
return start + Math.floor(progress * delta) + "";
|
|
1054
1092
|
} else if (value.startsWith(nextValue)) {
|
|
1055
1093
|
const startLen = nextValue.length;
|
|
1056
1094
|
const deltaLen = value.length - startLen;
|
|
@@ -1104,8 +1142,8 @@ class MacroEvaluator extends Evaluator {
|
|
|
1104
1142
|
node.evaluator = this;
|
|
1105
1143
|
this.consumers.set(node, this.compile(node, chart));
|
|
1106
1144
|
}
|
|
1107
|
-
eval(event, beats) {
|
|
1108
|
-
return this.consumers.get(event).eval(event, beats);
|
|
1145
|
+
eval(event, beats, timeCalculator) {
|
|
1146
|
+
return this.consumers.get(event).eval(event, beats, timeCalculator);
|
|
1109
1147
|
}
|
|
1110
1148
|
dumpFor(node) {
|
|
1111
1149
|
return {
|
|
@@ -1130,11 +1168,19 @@ class ExpressionEvaluator extends Evaluator {
|
|
|
1130
1168
|
this.jsExpr = jsExpr;
|
|
1131
1169
|
this.func = new Function("t", "return " + jsExpr);
|
|
1132
1170
|
}
|
|
1133
|
-
eval(startNode,
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1171
|
+
eval(startNode, beatsOrSecs, timeCalculator) {
|
|
1172
|
+
if (timeCalculator) {
|
|
1173
|
+
const startSecs = timeCalculator.toSeconds(TC2.toBeats(startNode.time));
|
|
1174
|
+
const endSecs = timeCalculator.toSeconds(TC2.toBeats(startNode.next.time));
|
|
1175
|
+
const current = beatsOrSecs - startSecs;
|
|
1176
|
+
const timeDelta = endSecs - startSecs;
|
|
1177
|
+
return this.func(current / timeDelta);
|
|
1178
|
+
} else {
|
|
1179
|
+
const next = startNode.next;
|
|
1180
|
+
const timeDelta = TC2.getDelta(next.time, startNode.time);
|
|
1181
|
+
const current = beatsOrSecs - TC2.toBeats(startNode.time);
|
|
1182
|
+
return this.func(current / timeDelta);
|
|
1183
|
+
}
|
|
1138
1184
|
}
|
|
1139
1185
|
dumpFor() {
|
|
1140
1186
|
return {
|
|
@@ -1352,11 +1398,6 @@ class EventNode extends EventNodeLike {
|
|
|
1352
1398
|
return ret;
|
|
1353
1399
|
}
|
|
1354
1400
|
static getEasing(data, templates, notSegmented = false) {
|
|
1355
|
-
const left = data.easingLeft;
|
|
1356
|
-
const right = data.easingRight;
|
|
1357
|
-
if (!notSegmented && (left && right) && (left !== 0 || right !== 1)) {
|
|
1358
|
-
return new SegmentedEasing(EventNode.getEasing(data, templates, true), left, right);
|
|
1359
|
-
}
|
|
1360
1401
|
if (data.bezier) {
|
|
1361
1402
|
const bp = data.bezierPoints;
|
|
1362
1403
|
const easing = new BezierEasing([bp[0], bp[1]], [bp[2], bp[3]]);
|
|
@@ -1563,11 +1604,11 @@ class EventStartNode extends EventNode {
|
|
|
1563
1604
|
linkedMacro: [...this.linkedMacros].map((macro) => macro.dumpLinkForNode(this))
|
|
1564
1605
|
};
|
|
1565
1606
|
}
|
|
1566
|
-
getValueAt(
|
|
1607
|
+
getValueAt(beatsOrSecs, timeCalculator) {
|
|
1567
1608
|
if (this.next.type === 1 /* TAIL */) {
|
|
1568
1609
|
return this.value;
|
|
1569
1610
|
}
|
|
1570
|
-
return this.evaluator.eval(this,
|
|
1611
|
+
return this.evaluator.eval(this, beatsOrSecs, timeCalculator);
|
|
1571
1612
|
}
|
|
1572
1613
|
getSpeedValueAt(beats) {
|
|
1573
1614
|
if (this.next.type === 1 /* TAIL */) {
|
|
@@ -1732,6 +1773,10 @@ class EventNodeSequence {
|
|
|
1732
1773
|
for (let index = 0;index < length; index++) {
|
|
1733
1774
|
const event = data[index];
|
|
1734
1775
|
const [start, end] = chart.createEventFromData(event, valueType, `${pos}.events[${index}]`);
|
|
1776
|
+
const evaluator = start.evaluator;
|
|
1777
|
+
if (evaluator instanceof EasedEvaluator && evaluator.easing instanceof SegmentedEasing && evaluator.easing.easing instanceof TemplateEasing) {
|
|
1778
|
+
chart.segmentedTemplates.set(evaluator.easing, [pos, start.time]);
|
|
1779
|
+
}
|
|
1735
1780
|
if (TC2.lt(event.startTime, lastEndTime)) {
|
|
1736
1781
|
err.EVENT_NODE_TIME_NOT_INCREMENTAL(`${pos}.events[${index}] and the previous`).warn();
|
|
1737
1782
|
}
|
|
@@ -1845,6 +1890,9 @@ class EventNodeSequence {
|
|
|
1845
1890
|
getValueAt(beats, usePrev = false) {
|
|
1846
1891
|
return this.getNodeAt(beats, usePrev).getValueAt(beats);
|
|
1847
1892
|
}
|
|
1893
|
+
getValueAtBySecs(beats, seconds, timeCalculator, usePrev = false) {
|
|
1894
|
+
return this.getNodeAt(beats, usePrev).getValueAt(seconds, timeCalculator);
|
|
1895
|
+
}
|
|
1848
1896
|
getFloorPositionAt(beats, timeCalculator) {
|
|
1849
1897
|
const node = this.getNodeAt(beats);
|
|
1850
1898
|
const value = node.getLocalFloorPos(beats, timeCalculator) + node.floorPosition;
|
|
@@ -1861,7 +1909,7 @@ class EventNodeSequence {
|
|
|
1861
1909
|
const prevStart = node.previous.previous;
|
|
1862
1910
|
currentFP = prevStart.floorPosition + prevStart.getFullLocalFloorPos(tc);
|
|
1863
1911
|
} else {
|
|
1864
|
-
currentFP = 0;
|
|
1912
|
+
node.floorPosition = currentFP = 0;
|
|
1865
1913
|
}
|
|
1866
1914
|
while (true) {
|
|
1867
1915
|
const canBeEnd = node.next;
|
|
@@ -1969,35 +2017,69 @@ class EventNodeSequence {
|
|
|
1969
2017
|
return;
|
|
1970
2018
|
}
|
|
1971
2019
|
let lastEnd = endNode;
|
|
2020
|
+
currentNode = endNode.next;
|
|
1972
2021
|
while (true) {
|
|
2022
|
+
const evaluator = currentNode.evaluator;
|
|
2023
|
+
if (this.type === 5 /* easing */ && evaluator instanceof EasedEvaluator && evaluator.easing instanceof TemplateEasing) {
|
|
2024
|
+
if (TemplateEasing.checkCircularReference(this, evaluator.easing)) {
|
|
2025
|
+
err.TEMPLATE_EASING_CIRCULAR_REFERENCE(this.id).warn();
|
|
2026
|
+
}
|
|
2027
|
+
}
|
|
2028
|
+
if (evaluator instanceof EasedEvaluator && evaluator.easing instanceof SegmentedEasing) {
|
|
2029
|
+
const easing = evaluator.easing;
|
|
2030
|
+
const inner = easing.easing;
|
|
2031
|
+
if (inner.getValue(easing.left) === inner.getValue(easing.right)) {
|
|
2032
|
+
err.EASING_DELTA_CANNOT_BE_ZERO(this.id, currentNode.time).warn();
|
|
2033
|
+
}
|
|
2034
|
+
}
|
|
1973
2035
|
const endNode2 = currentNode.next;
|
|
1974
2036
|
if (endNode2.type === 1 /* TAIL */) {
|
|
1975
2037
|
break;
|
|
1976
2038
|
}
|
|
2039
|
+
if (!TC2.gt(endNode2.time, currentNode.time)) {
|
|
2040
|
+
err.EVENT_NODE_TIME_NOT_INCREMENTAL(`${this.id}, ${currentNode.time}`).warn();
|
|
2041
|
+
}
|
|
1977
2042
|
if (TC2.ne(lastEnd.time, currentNode.time)) {
|
|
1978
2043
|
err.EVENT_NODE_NOT_DENSE(`${this.id}, ${currentNode.time}`).warn();
|
|
1979
2044
|
}
|
|
1980
2045
|
currentNode = currentNode.next.next;
|
|
2046
|
+
lastEnd = endNode2;
|
|
2047
|
+
}
|
|
2048
|
+
}
|
|
2049
|
+
hasReferenceTo(seq) {
|
|
2050
|
+
let node = this.head.next;
|
|
2051
|
+
while (true) {
|
|
2052
|
+
const endNode = node.next;
|
|
2053
|
+
if (endNode.type === 1 /* TAIL */) {
|
|
2054
|
+
break;
|
|
2055
|
+
}
|
|
2056
|
+
const evaluator = node.evaluator;
|
|
2057
|
+
if (evaluator instanceof EasedEvaluator && evaluator.easing instanceof TemplateEasing) {
|
|
2058
|
+
if (TemplateEasing.checkCircularReference(seq, evaluator.easing)) {
|
|
2059
|
+
return true;
|
|
2060
|
+
}
|
|
2061
|
+
}
|
|
2062
|
+
node = endNode.next;
|
|
1981
2063
|
}
|
|
1982
2064
|
}
|
|
1983
2065
|
}
|
|
1984
2066
|
// src/note.ts
|
|
1985
2067
|
var notePropTypes = {
|
|
1986
2068
|
above: "boolean",
|
|
1987
|
-
alpha: "
|
|
2069
|
+
alpha: "int[0,255]",
|
|
1988
2070
|
endTime: ["number", "number", "number"],
|
|
1989
2071
|
isFake: "boolean",
|
|
1990
2072
|
positionX: "number",
|
|
1991
|
-
size: "number",
|
|
2073
|
+
size: "number(0,+)",
|
|
1992
2074
|
speed: "number",
|
|
1993
2075
|
startTime: ["number", "number", "number"],
|
|
1994
|
-
type: "
|
|
1995
|
-
visibleTime: "number",
|
|
1996
|
-
visibleBeats: "number",
|
|
2076
|
+
type: "int[1,4]",
|
|
2077
|
+
visibleTime: "number(0,+)",
|
|
2078
|
+
visibleBeats: "number(0,+)",
|
|
1997
2079
|
yOffset: "number",
|
|
1998
|
-
tint: ["
|
|
1999
|
-
tintHitEffects: ["
|
|
2000
|
-
judgeSize: "number"
|
|
2080
|
+
tint: ["int[0,255]", "int[0,255]", "int[0,255]"],
|
|
2081
|
+
tintHitEffects: ["int[0,255]", "int[0,255]", "int[0,255]"],
|
|
2082
|
+
judgeSize: "number(0,+)"
|
|
2001
2083
|
};
|
|
2002
2084
|
|
|
2003
2085
|
class Note {
|
|
@@ -2030,9 +2112,10 @@ class Note {
|
|
|
2030
2112
|
this.visibleTime = data.visibleTime;
|
|
2031
2113
|
this.yOffset = data.absoluteYOffset ?? data.yOffset * this.speed;
|
|
2032
2114
|
this.visibleBeats = data.visibleBeats;
|
|
2033
|
-
|
|
2115
|
+
const color = data.tint ?? data.color;
|
|
2116
|
+
this.tint = color ? rgb2hex(color) : undefined;
|
|
2034
2117
|
this.tintHitEffects = data.tintHitEffects ? rgb2hex(data.tintHitEffects) : undefined;
|
|
2035
|
-
this.judgeSize = data.judgeSize ?? this.size;
|
|
2118
|
+
this.judgeSize = data.judgeSize ?? data.judgeArea ?? this.size;
|
|
2036
2119
|
}
|
|
2037
2120
|
static fromKPAJSON(data, timeCalculator) {
|
|
2038
2121
|
const note = new Note(data);
|
|
@@ -2078,8 +2161,9 @@ class Note {
|
|
|
2078
2161
|
visibleTime,
|
|
2079
2162
|
yOffset: this.yOffset / this.speed,
|
|
2080
2163
|
speed: this.speed,
|
|
2081
|
-
tint: this.tint !== undefined ? hex2rgb(this.tint) : undefined,
|
|
2082
|
-
tintHitEffects: this.
|
|
2164
|
+
tint: this.tint !== undefined && this.tint !== 16777215 ? hex2rgb(this.tint) : undefined,
|
|
2165
|
+
tintHitEffects: this.tintHitEffects !== undefined && this.tintHitEffects !== 16777215 ? hex2rgb(this.tintHitEffects) : undefined,
|
|
2166
|
+
judgeArea: this.judgeSize
|
|
2083
2167
|
};
|
|
2084
2168
|
}
|
|
2085
2169
|
dumpKPA() {
|
|
@@ -2096,8 +2180,8 @@ class Note {
|
|
|
2096
2180
|
yOffset: this.yOffset / this.speed,
|
|
2097
2181
|
absoluteYOffset: this.yOffset,
|
|
2098
2182
|
speed: this.speed,
|
|
2099
|
-
tint: this.tint !== undefined ? hex2rgb(this.tint) : undefined,
|
|
2100
|
-
tintHitEffects: this.
|
|
2183
|
+
tint: this.tint !== undefined && this.tint !== 16777215 ? hex2rgb(this.tint) : undefined,
|
|
2184
|
+
tintHitEffects: this.tintHitEffects !== undefined && this.tintHitEffects !== 16777215 ? hex2rgb(this.tintHitEffects) : undefined,
|
|
2101
2185
|
judgeSize: this.judgeSize && this.judgeSize !== 1 ? this.judgeSize : undefined
|
|
2102
2186
|
};
|
|
2103
2187
|
}
|
|
@@ -2636,17 +2720,17 @@ class JudgeLine {
|
|
|
2636
2720
|
line.speedSequence = speedSequences[0];
|
|
2637
2721
|
chart.registerEventNodeSequence(4 /* speed */, `#${id}.speed`, speedSequences[0]);
|
|
2638
2722
|
}
|
|
2723
|
+
if (data.extended?.scaleXEvents) {
|
|
2724
|
+
line.extendedLayer.scaleX = createExtendedSequence(7 /* scaleX */, data.extended.scaleXEvents);
|
|
2725
|
+
} else {
|
|
2726
|
+
line.extendedLayer.scaleX = chart.createEventNodeSequence(7 /* scaleX */, `#${id}.ex.scaleX`);
|
|
2727
|
+
}
|
|
2728
|
+
if (data.extended?.scaleYEvents) {
|
|
2729
|
+
line.extendedLayer.scaleY = createExtendedSequence(8 /* scaleY */, data.extended.scaleYEvents);
|
|
2730
|
+
} else {
|
|
2731
|
+
line.extendedLayer.scaleY = chart.createEventNodeSequence(8 /* scaleY */, `#${id}.ex.scaleY`);
|
|
2732
|
+
}
|
|
2639
2733
|
if (data.extended) {
|
|
2640
|
-
if (data.extended.scaleXEvents) {
|
|
2641
|
-
line.extendedLayer.scaleX = createExtendedSequence(7 /* scaleX */, data.extended.scaleXEvents);
|
|
2642
|
-
} else {
|
|
2643
|
-
line.extendedLayer.scaleX = chart.createEventNodeSequence(7 /* scaleX */, `#${id}.ex.scaleX`);
|
|
2644
|
-
}
|
|
2645
|
-
if (data.extended.scaleYEvents) {
|
|
2646
|
-
line.extendedLayer.scaleY = createExtendedSequence(8 /* scaleY */, data.extended.scaleYEvents);
|
|
2647
|
-
} else {
|
|
2648
|
-
line.extendedLayer.scaleY = chart.createEventNodeSequence(8 /* scaleY */, `#${id}.ex.scaleY`);
|
|
2649
|
-
}
|
|
2650
2734
|
if (data.extended.textEvents) {
|
|
2651
2735
|
line.extendedLayer.text = createExtendedSequence(9 /* text */, data.extended.textEvents);
|
|
2652
2736
|
}
|
|
@@ -2815,7 +2899,7 @@ class JudgeLine {
|
|
|
2815
2899
|
if (lineMonotonicity === 0 /* increasing */ && startY >= 0 && endY > 0) {
|
|
2816
2900
|
return result;
|
|
2817
2901
|
}
|
|
2818
|
-
const computeTime = (speed, currentPos, fore) => timeCalculator.secondsToBeats(currentPos / (speed * 120) + timeCalculator.toSeconds(fore));
|
|
2902
|
+
const computeTime = (speed, currentPos, fore) => speed * currentPos <= 0 ? fore : timeCalculator.secondsToBeats(currentPos / (speed * 120) + timeCalculator.toSeconds(fore));
|
|
2819
2903
|
while (true) {
|
|
2820
2904
|
const thisTime = TC2.toBeats(startNode.time);
|
|
2821
2905
|
const endNode = startNode.next;
|
|
@@ -2823,17 +2907,21 @@ class JudgeLine {
|
|
|
2823
2907
|
if (endNode.type === 1 /* TAIL */) {
|
|
2824
2908
|
const thisPosY2 = startNode.floorPosition - currentJudgeLineFloorPos;
|
|
2825
2909
|
const thisSpeed2 = startNode.value;
|
|
2826
|
-
const inf = thisSpeed2 > 0 ? Infinity : thisSpeed2 < 0 ? -Infinity : thisPosY2;
|
|
2827
2910
|
if (range[0] === undefined) {
|
|
2828
|
-
if (
|
|
2829
|
-
range[0] = computeTime(thisSpeed2,
|
|
2830
|
-
} else if (thisSpeed2
|
|
2831
|
-
range[0] =
|
|
2911
|
+
if (thisSpeed2 > 0 && endY > thisPosY2) {
|
|
2912
|
+
range[0] = computeTime(thisSpeed2, startY - thisPosY2, thisTime);
|
|
2913
|
+
} else if (thisSpeed2 < 0 && startY < thisPosY2) {
|
|
2914
|
+
range[0] = computeTime(thisSpeed2, endY - thisPosY2, thisTime);
|
|
2915
|
+
} else if (thisSpeed2 === 0 && startY <= thisPosY2 && thisPosY2 <= endY) {
|
|
2916
|
+
range[0] = thisTime;
|
|
2832
2917
|
}
|
|
2833
2918
|
}
|
|
2834
2919
|
if (range[0] !== undefined) {
|
|
2835
|
-
if (
|
|
2836
|
-
range[1] = computeTime(thisSpeed2,
|
|
2920
|
+
if (thisSpeed2 > 0 && endY > thisPosY2) {
|
|
2921
|
+
range[1] = computeTime(thisSpeed2, endY - thisPosY2, thisTime);
|
|
2922
|
+
result.push(range);
|
|
2923
|
+
} else if (thisSpeed2 < 0 && startY < thisPosY2) {
|
|
2924
|
+
range[1] = computeTime(thisSpeed2, startY - thisPosY2, thisTime);
|
|
2837
2925
|
result.push(range);
|
|
2838
2926
|
} else if (thisSpeed2 === 0) {
|
|
2839
2927
|
range[1] = Infinity;
|
|
@@ -2846,7 +2934,7 @@ class JudgeLine {
|
|
|
2846
2934
|
const thisPosY = startNode.floorPosition - currentJudgeLineFloorPos;
|
|
2847
2935
|
const nextPosY = nextStart.floorPosition - currentJudgeLineFloorPos;
|
|
2848
2936
|
let thisSpeed = startNode.value;
|
|
2849
|
-
let nextSpeed =
|
|
2937
|
+
let nextSpeed = endNode.value;
|
|
2850
2938
|
if (Math.abs(thisSpeed) < 0.00000001) {
|
|
2851
2939
|
thisSpeed = 0;
|
|
2852
2940
|
}
|
|
@@ -2858,15 +2946,13 @@ class JudgeLine {
|
|
|
2858
2946
|
const zeroPosY = speedSequence.getFloorPositionAt(zeroTime, timeCalculator) - currentJudgeLineFloorPos;
|
|
2859
2947
|
const zeroSpeed = 0;
|
|
2860
2948
|
if (range[0] === undefined) {
|
|
2861
|
-
if (
|
|
2862
|
-
range[0] = thisSpeed !== zeroSpeed ? thisTime : computeTime(thisSpeed, (thisPosY < zeroPosY ? startY : endY) - thisPosY, thisTime);
|
|
2863
|
-
} else if (startY <= thisPosY && thisPosY <= endY) {
|
|
2949
|
+
if (thisSpeed > 0 && endY >= thisPosY || thisSpeed < 0 && startY <= thisPosY) {
|
|
2864
2950
|
range[0] = thisTime;
|
|
2865
2951
|
}
|
|
2866
2952
|
}
|
|
2867
2953
|
if (range[0] !== undefined) {
|
|
2868
|
-
if (
|
|
2869
|
-
range[1] =
|
|
2954
|
+
if (thisSpeed > 0 && endY <= zeroPosY || thisSpeed < 0 && startY >= zeroPosY) {
|
|
2955
|
+
range[1] = zeroTime;
|
|
2870
2956
|
result.push(range);
|
|
2871
2957
|
if (lineMonotonicity !== 2 /* swinging */) {
|
|
2872
2958
|
return result;
|
|
@@ -2875,15 +2961,13 @@ class JudgeLine {
|
|
|
2875
2961
|
}
|
|
2876
2962
|
}
|
|
2877
2963
|
if (range[0] === undefined) {
|
|
2878
|
-
if (
|
|
2879
|
-
range[0] = zeroSpeed !== nextSpeed ? zeroTime : computeTime(nextSpeed, (zeroPosY < nextPosY ? startY : endY) - zeroPosY, zeroTime);
|
|
2880
|
-
} else if (startY <= zeroPosY && zeroPosY <= endY) {
|
|
2964
|
+
if (nextSpeed > 0 && endY >= zeroPosY || nextSpeed < 0 && startY <= zeroPosY) {
|
|
2881
2965
|
range[0] = zeroTime;
|
|
2882
2966
|
}
|
|
2883
2967
|
}
|
|
2884
2968
|
if (range[0] !== undefined) {
|
|
2885
|
-
if (
|
|
2886
|
-
range[1] =
|
|
2969
|
+
if (nextSpeed > 0 && endY <= nextPosY || nextSpeed < 0 && startY >= nextPosY) {
|
|
2970
|
+
range[1] = nextTime;
|
|
2887
2971
|
result.push(range);
|
|
2888
2972
|
if (lineMonotonicity !== 2 /* swinging */) {
|
|
2889
2973
|
return result;
|
|
@@ -2893,15 +2977,24 @@ class JudgeLine {
|
|
|
2893
2977
|
}
|
|
2894
2978
|
} else {
|
|
2895
2979
|
if (range[0] === undefined) {
|
|
2896
|
-
if (
|
|
2897
|
-
range[0] = thisSpeed !== nextSpeed ? thisTime : computeTime(thisSpeed,
|
|
2898
|
-
} else if (startY <= thisPosY &&
|
|
2980
|
+
if (thisSpeed > 0 && endY >= thisPosY && startY < nextPosY) {
|
|
2981
|
+
range[0] = thisSpeed !== nextSpeed ? thisTime : computeTime(thisSpeed, startY - thisPosY, thisTime);
|
|
2982
|
+
} else if (thisSpeed < 0 && startY <= thisPosY && endY > nextPosY) {
|
|
2983
|
+
range[0] = thisSpeed !== nextSpeed ? thisTime : computeTime(thisSpeed, endY - thisPosY, thisTime);
|
|
2984
|
+
} else if (thisSpeed === 0 && startY <= thisPosY && thisPosY <= endY) {
|
|
2899
2985
|
range[0] = thisTime;
|
|
2900
2986
|
}
|
|
2901
2987
|
}
|
|
2902
2988
|
if (range[0] !== undefined) {
|
|
2903
|
-
if (
|
|
2904
|
-
range[1] = thisSpeed !== nextSpeed ? nextTime : computeTime(thisSpeed,
|
|
2989
|
+
if (thisSpeed > 0 && endY <= nextPosY) {
|
|
2990
|
+
range[1] = thisSpeed !== nextSpeed ? nextTime : computeTime(thisSpeed, endY - thisPosY, thisTime);
|
|
2991
|
+
result.push(range);
|
|
2992
|
+
if (lineMonotonicity !== 2 /* swinging */) {
|
|
2993
|
+
return result;
|
|
2994
|
+
}
|
|
2995
|
+
range = [undefined, undefined];
|
|
2996
|
+
} else if (thisSpeed < 0 && startY >= thisPosY) {
|
|
2997
|
+
range[1] = thisSpeed !== nextSpeed ? nextTime : computeTime(thisSpeed, startY - thisPosY, thisTime);
|
|
2905
2998
|
result.push(range);
|
|
2906
2999
|
if (lineMonotonicity !== 2 /* swinging */) {
|
|
2907
3000
|
return result;
|
|
@@ -2934,6 +3027,18 @@ class JudgeLine {
|
|
|
2934
3027
|
}
|
|
2935
3028
|
return current;
|
|
2936
3029
|
}
|
|
3030
|
+
getStackedValueBySeconds(type, beats, seconds, timeCalculator, usePrev = false) {
|
|
3031
|
+
const length = this.eventLayers.length;
|
|
3032
|
+
let current = 0;
|
|
3033
|
+
for (let index = 0;index < length; index++) {
|
|
3034
|
+
const layer = this.eventLayers[index];
|
|
3035
|
+
if (!layer || !layer[type]) {
|
|
3036
|
+
break;
|
|
3037
|
+
}
|
|
3038
|
+
current += layer[type].getValueAtBySecs(beats, seconds, timeCalculator, usePrev);
|
|
3039
|
+
}
|
|
3040
|
+
return current;
|
|
3041
|
+
}
|
|
2937
3042
|
getNNList(speed, yOffset, isHold, initsJump) {
|
|
2938
3043
|
const lists = isHold ? this.hnLists : this.nnLists;
|
|
2939
3044
|
const medianYOffset = getRangeMedian(yOffset);
|
|
@@ -3190,6 +3295,9 @@ class TimeCalculator {
|
|
|
3190
3295
|
duration;
|
|
3191
3296
|
constructor() {}
|
|
3192
3297
|
initSequence() {
|
|
3298
|
+
if (!this.bpmList || !this.duration) {
|
|
3299
|
+
throw new Error("TimeCalculator: bpmList and duration must be set before initSequence");
|
|
3300
|
+
}
|
|
3193
3301
|
const bpmList = this.bpmList;
|
|
3194
3302
|
this.bpmSequence = new BPMSequence(bpmList, this.duration);
|
|
3195
3303
|
}
|
|
@@ -3211,7 +3319,7 @@ class TimeCalculator {
|
|
|
3211
3319
|
}
|
|
3212
3320
|
}
|
|
3213
3321
|
// src/version.ts
|
|
3214
|
-
var VERSION =
|
|
3322
|
+
var VERSION = 213;
|
|
3215
3323
|
var SCHEMA = "https://cdn.jsdelivr.net/npm/kipphi@2.1.0/chartType2.schema.json";
|
|
3216
3324
|
|
|
3217
3325
|
// src/chart.ts
|
|
@@ -3243,6 +3351,7 @@ class Chart {
|
|
|
3243
3351
|
scoreAttach = null;
|
|
3244
3352
|
nameAttach = null;
|
|
3245
3353
|
levelAttach = null;
|
|
3354
|
+
segmentedTemplates = new Map;
|
|
3246
3355
|
constructor() {}
|
|
3247
3356
|
getEffectiveBeats() {
|
|
3248
3357
|
const effectiveBeats = this.timeCalculator.secondsToBeats(this.duration);
|
|
@@ -3251,7 +3360,7 @@ class Chart {
|
|
|
3251
3360
|
}
|
|
3252
3361
|
static fromRPEJSON(data, duration) {
|
|
3253
3362
|
const chart = new Chart;
|
|
3254
|
-
chart.judgeLineGroups = data.judgeLineGroup.map((group) => new JudgeLineGroup(group));
|
|
3363
|
+
chart.judgeLineGroups = (data.judgeLineGroup || ["Default"]).map((group) => new JudgeLineGroup(group));
|
|
3255
3364
|
chart.name = data.META.name;
|
|
3256
3365
|
chart.level = data.META.level;
|
|
3257
3366
|
chart.offset = data.META.offset;
|
|
@@ -3334,6 +3443,9 @@ class Chart {
|
|
|
3334
3443
|
for (let i = 0;i < len; i++) {
|
|
3335
3444
|
const easingData = templateEasings[i];
|
|
3336
3445
|
const sequence = chart.sequenceMap.get(easingData.content);
|
|
3446
|
+
if (!sequence) {
|
|
3447
|
+
continue;
|
|
3448
|
+
}
|
|
3337
3449
|
if (sequence.type !== 5 /* easing */) {
|
|
3338
3450
|
throw err.CANNOT_IMPLEMENT_TEMEAS_WITH_NON_EASING_ENS(easingData.name);
|
|
3339
3451
|
}
|
|
@@ -3342,7 +3454,15 @@ class Chart {
|
|
|
3342
3454
|
}
|
|
3343
3455
|
chart.templateEasingLib.implement(easingData.name, sequence);
|
|
3344
3456
|
}
|
|
3457
|
+
for (let i = 0;i < len; i++) {
|
|
3458
|
+
const easingData = templateEasings[i];
|
|
3459
|
+
const sequence = chart.sequenceMap.get(easingData.content);
|
|
3460
|
+
if (sequence.hasReferenceTo(sequence)) {
|
|
3461
|
+
throw err.TEMPLATE_EASING_CIRCULAR_REFERENCE(easingData.name);
|
|
3462
|
+
}
|
|
3463
|
+
}
|
|
3345
3464
|
chart.templateEasingLib.check();
|
|
3465
|
+
chart.checkSegmentedTemplates();
|
|
3346
3466
|
for (const lineData of data.orphanLines) {
|
|
3347
3467
|
const line = JudgeLine.fromKPAJSON(data.version, chart, lineData.id, lineData, chart.templateEasingLib, chart.timeCalculator);
|
|
3348
3468
|
chart.orphanLines.push(line);
|
|
@@ -3638,6 +3758,21 @@ class Chart {
|
|
|
3638
3758
|
}
|
|
3639
3759
|
return null;
|
|
3640
3760
|
}
|
|
3761
|
+
checkErrors() {
|
|
3762
|
+
KPAError.flush();
|
|
3763
|
+
for (const [_, seq] of this.sequenceMap) {
|
|
3764
|
+
seq.checkErrors();
|
|
3765
|
+
}
|
|
3766
|
+
}
|
|
3767
|
+
checkSegmentedTemplates() {
|
|
3768
|
+
for (const [easing, [pos, time]] of this.segmentedTemplates) {
|
|
3769
|
+
const inner = easing.easing;
|
|
3770
|
+
if (inner.getValue(easing.left) === inner.getValue(easing.right)) {
|
|
3771
|
+
err.EASING_DELTA_CANNOT_BE_ZERO(pos, time).warn();
|
|
3772
|
+
}
|
|
3773
|
+
}
|
|
3774
|
+
this.segmentedTemplates.clear();
|
|
3775
|
+
}
|
|
3641
3776
|
}
|
|
3642
3777
|
|
|
3643
3778
|
class JudgeLineGroup {
|
|
@@ -4156,6 +4291,13 @@ class EventNodeEvaluatorChangeOperation extends Operation {
|
|
|
4156
4291
|
this.node = node;
|
|
4157
4292
|
this.value = value;
|
|
4158
4293
|
this.originalValue = this.node.evaluator;
|
|
4294
|
+
const seq = node.parentSeq;
|
|
4295
|
+
if (seq.type === 5 /* easing */ && value instanceof EasedEvaluator && value.easing instanceof TemplateEasing) {
|
|
4296
|
+
const circular = TemplateEasing.checkCircularReference(seq, value.easing);
|
|
4297
|
+
if (circular) {
|
|
4298
|
+
throw err.TEMPLATE_EASING_CIRCULAR_REFERENCE(value.easing.name);
|
|
4299
|
+
}
|
|
4300
|
+
}
|
|
4159
4301
|
}
|
|
4160
4302
|
do() {
|
|
4161
4303
|
this.node.evaluator = this.value;
|
|
@@ -5194,14 +5336,34 @@ class RPEChartCompiler {
|
|
|
5194
5336
|
chart;
|
|
5195
5337
|
sequenceMap = new Map;
|
|
5196
5338
|
interpolationStep = [0, 1, 16];
|
|
5339
|
+
deletesEmptyLines = true;
|
|
5197
5340
|
constructor(chart2) {
|
|
5198
5341
|
this.chart = chart2;
|
|
5199
5342
|
}
|
|
5200
5343
|
compileChart() {
|
|
5201
|
-
console.time("compileChart");
|
|
5202
5344
|
const chart2 = this.chart;
|
|
5203
5345
|
const judgeLineGroups = chart2.judgeLineGroups.map((group) => group.name);
|
|
5204
|
-
const
|
|
5346
|
+
const filter = this.deletesEmptyLines ? (line2) => {
|
|
5347
|
+
return line2.nnLists.size > 0 || line2.hnLists.size > 0 || line2.eventLayers.length > 0 || ["moveX", "moveY", "rotate", "alpha"].some((evType) => {
|
|
5348
|
+
const seq = line2.eventLayers[0][evType];
|
|
5349
|
+
let node = seq.head.next;
|
|
5350
|
+
for (let i = 0;i < 2; i++) {
|
|
5351
|
+
const endNode = node.next;
|
|
5352
|
+
if (node.value !== 0) {
|
|
5353
|
+
return true;
|
|
5354
|
+
}
|
|
5355
|
+
if (endNode.type === 1 /* TAIL */) {
|
|
5356
|
+
return false;
|
|
5357
|
+
}
|
|
5358
|
+
if (endNode.value !== 0) {
|
|
5359
|
+
return true;
|
|
5360
|
+
}
|
|
5361
|
+
node = endNode.next;
|
|
5362
|
+
}
|
|
5363
|
+
return true;
|
|
5364
|
+
});
|
|
5365
|
+
} : () => true;
|
|
5366
|
+
const judgeLineList = chart2.judgeLines.filter(filter).map((line2) => this.compileJudgeLine(line2));
|
|
5205
5367
|
const BPMList = chart2.timeCalculator.dump();
|
|
5206
5368
|
const META = {
|
|
5207
5369
|
RPEVersion: 1,
|
|
@@ -5240,7 +5402,6 @@ class RPEChartCompiler {
|
|
|
5240
5402
|
lineData.attachUI = uiName;
|
|
5241
5403
|
}
|
|
5242
5404
|
}
|
|
5243
|
-
console.timeEnd("compileChart");
|
|
5244
5405
|
return {
|
|
5245
5406
|
BPMList,
|
|
5246
5407
|
META,
|
|
@@ -5248,8 +5409,8 @@ class RPEChartCompiler {
|
|
|
5248
5409
|
judgeLineGroup: judgeLineGroups,
|
|
5249
5410
|
multiLineString: "",
|
|
5250
5411
|
multiScale: 1,
|
|
5251
|
-
chartTime: chart2.
|
|
5252
|
-
kpaChartTime: chart2.
|
|
5412
|
+
chartTime: chart2.rpeChartingSeconds,
|
|
5413
|
+
kpaChartTime: chart2.chartingSeconds
|
|
5253
5414
|
};
|
|
5254
5415
|
}
|
|
5255
5416
|
compileJudgeLine(judgeLine) {
|
|
@@ -5296,7 +5457,7 @@ class RPEChartCompiler {
|
|
|
5296
5457
|
bezierPoints: innerEasing instanceof BezierEasing ? [innerEasing.cp1[0], innerEasing.cp1[1], innerEasing.cp2[0], innerEasing.cp2[1]] : [0, 0, 0, 0],
|
|
5297
5458
|
easingLeft: isSegmented ? easing.left : 0,
|
|
5298
5459
|
easingRight: isSegmented ? easing.right : 1,
|
|
5299
|
-
easingType: easing instanceof NormalEasing ? easing.rpeId ?? 1 : null,
|
|
5460
|
+
easingType: isSegmented ? easing.easing instanceof NormalEasing ? easing.easing.rpeId ?? 1 : null : easing instanceof NormalEasing ? easing.rpeId ?? 1 : null,
|
|
5300
5461
|
end,
|
|
5301
5462
|
endTime: endNode.time,
|
|
5302
5463
|
linkgroup: 0,
|