kipphi 2.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.
- package/LICENSE +21 -0
- package/README.md +9 -0
- package/chart.ts +481 -0
- package/chartTypes.ts +512 -0
- package/easing.ts +543 -0
- package/env.ts +7 -0
- package/evaluator.ts +173 -0
- package/event.ts +853 -0
- package/index.ts +11 -0
- package/judgeline.ts +605 -0
- package/jumparray.ts +234 -0
- package/note.ts +731 -0
- package/package.json +20 -0
- package/rpeChartCompiler.ts +425 -0
- package/time.ts +308 -0
- package/tsconfig.json +30 -0
- package/util.ts +26 -0
- package/version.ts +8 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 TeamZincs
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# Parse your chart into an editor-friendly format with Kipphi!
|
|
2
|
+
|
|
3
|
+
This is a Phigros KipphiApparatus/Re:PhiEdit ChartJSON Parser. It is a subproject of [KPA](https://github.com/TeamZincs/KPA).
|
|
4
|
+
|
|
5
|
+
"Kipphi" comes from the Dutch chemist Kipp, who invented Kipp's Apparatus, which was used to produce gas and stop the reaction at any time.
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
## Usage
|
|
9
|
+
|
package/chart.ts
ADDED
|
@@ -0,0 +1,481 @@
|
|
|
1
|
+
|
|
2
|
+
import { VERSION } from "./version";
|
|
3
|
+
|
|
4
|
+
import {
|
|
5
|
+
TimeCalculator,
|
|
6
|
+
BPMSequence
|
|
7
|
+
} from "./time";
|
|
8
|
+
|
|
9
|
+
import {
|
|
10
|
+
BezierEasing,
|
|
11
|
+
Easing,
|
|
12
|
+
rpeEasingArray,
|
|
13
|
+
SegmentedEasing,
|
|
14
|
+
TemplateEasingLib,
|
|
15
|
+
} from "./easing";
|
|
16
|
+
|
|
17
|
+
import {
|
|
18
|
+
EventNodeSequence,
|
|
19
|
+
type AnyEN,
|
|
20
|
+
type ENOrHead,
|
|
21
|
+
type ENOrTail,
|
|
22
|
+
EventNodeLike,
|
|
23
|
+
EventStartNode,
|
|
24
|
+
EventEndNode,
|
|
25
|
+
EventNode,
|
|
26
|
+
} from "./event";
|
|
27
|
+
|
|
28
|
+
import {
|
|
29
|
+
NodeType
|
|
30
|
+
} from "./util"
|
|
31
|
+
|
|
32
|
+
import {
|
|
33
|
+
JudgeLine
|
|
34
|
+
} from "./judgeline";
|
|
35
|
+
|
|
36
|
+
import {
|
|
37
|
+
Note,
|
|
38
|
+
NNList,
|
|
39
|
+
NNNList,
|
|
40
|
+
type NNNOrHead,
|
|
41
|
+
type NNNOrTail,
|
|
42
|
+
NNNode
|
|
43
|
+
} from "./note";
|
|
44
|
+
|
|
45
|
+
import {
|
|
46
|
+
type RGB,
|
|
47
|
+
type TimeT,
|
|
48
|
+
type EventType,
|
|
49
|
+
type EventNodeSequenceDataKPA,
|
|
50
|
+
type ValueTypeOfEventType,
|
|
51
|
+
type BPMSegmentData,
|
|
52
|
+
type ChartDataRPE,
|
|
53
|
+
type ChartDataKPA,
|
|
54
|
+
type JudgeLineDataRPE,
|
|
55
|
+
type EasingDataKPA2,
|
|
56
|
+
EasingType,
|
|
57
|
+
type EvaluatorDataKPA2,
|
|
58
|
+
EvaluatorType,
|
|
59
|
+
type EasedEvaluatorDataOfType,
|
|
60
|
+
EventValueType,
|
|
61
|
+
type EventValueTypeOfType,
|
|
62
|
+
type EventValueESType,
|
|
63
|
+
type ExpressionEvaluatorDataKPA2,
|
|
64
|
+
type TextEasedEvaluatorKPA2,
|
|
65
|
+
type EventNodeSequenceDataKPA2,
|
|
66
|
+
type ChartDataKPA2,
|
|
67
|
+
type EventDataKPA2
|
|
68
|
+
} from "./chartTypes";
|
|
69
|
+
import { ProgramUpdateLevel } from "typescript";
|
|
70
|
+
import { ColorEasedEvaluator, Evaluator, ExpressionEvaluator, NumericEasedEvaluator, TextEasedEvaluator, type EasedEvaluatorOfType } from "./evaluator";
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
/// #declaration:global
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
export type BasicEventName = "moveX" | "moveY" | "rotate" | "alpha" | "speed";
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
type Plain<T> = Record<string, T>;
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* 相当于 Python 推导式
|
|
84
|
+
* @param obj
|
|
85
|
+
* @param expr
|
|
86
|
+
* @param guard
|
|
87
|
+
* @returns
|
|
88
|
+
*/
|
|
89
|
+
function dictForIn<T, RT>(obj: Plain<T>, expr: (v: T) => RT, guard?: (v: T) => boolean): Plain<RT> {
|
|
90
|
+
let ret: Plain<RT> = {}
|
|
91
|
+
for (let key in obj) {
|
|
92
|
+
const each = obj[key]
|
|
93
|
+
if (!guard || guard && guard(each)) {
|
|
94
|
+
ret[key] = expr(each)
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
return ret;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
export type UIName = "combo" | "combonumber" | "score" | "pause" | "bar" | "name" | "level"
|
|
102
|
+
|
|
103
|
+
export class Chart {
|
|
104
|
+
judgeLines: JudgeLine[] = [];
|
|
105
|
+
bpmList: BPMSegmentData[] = [];
|
|
106
|
+
timeCalculator = new TimeCalculator();
|
|
107
|
+
orphanLines: JudgeLine[] = [];
|
|
108
|
+
// comboMapping: ComboMapping;
|
|
109
|
+
name: string = "unknown";
|
|
110
|
+
level: string = "unknown";
|
|
111
|
+
composer: string = "unknown";
|
|
112
|
+
charter: string = "unknown";
|
|
113
|
+
illustrator: string = "unknown";
|
|
114
|
+
offset: number = 0;
|
|
115
|
+
|
|
116
|
+
templateEasingLib = new TemplateEasingLib;
|
|
117
|
+
sequenceMap = new Map<string, EventNodeSequence<any>>();
|
|
118
|
+
|
|
119
|
+
effectiveBeats: number;
|
|
120
|
+
nnnList: NNNList;
|
|
121
|
+
/** */
|
|
122
|
+
judgeLineGroups: JudgeLineGroup[] = [];
|
|
123
|
+
duration: number;
|
|
124
|
+
|
|
125
|
+
// 以分钟计
|
|
126
|
+
chartingTime: number;
|
|
127
|
+
rpeChartingTime: number;
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
modified: boolean = false;
|
|
131
|
+
maxCombo: number = 0;
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
pauseAttach: JudgeLine | null = null;
|
|
135
|
+
combonumberAttach: JudgeLine | null = null;
|
|
136
|
+
comboAttach: JudgeLine | null = null;
|
|
137
|
+
barAttach: JudgeLine | null = null;
|
|
138
|
+
scoreAttach: JudgeLine | null = null;
|
|
139
|
+
nameAttach: JudgeLine | null = null;
|
|
140
|
+
levelAttach: JudgeLine | null = null;
|
|
141
|
+
|
|
142
|
+
constructor() {}
|
|
143
|
+
getEffectiveBeats() {
|
|
144
|
+
const effectiveBeats = this.timeCalculator.secondsToBeats(this.duration)
|
|
145
|
+
console.log(effectiveBeats)
|
|
146
|
+
this.effectiveBeats = effectiveBeats
|
|
147
|
+
return this.effectiveBeats
|
|
148
|
+
}
|
|
149
|
+
static fromRPEJSON(data: ChartDataRPE, duration: number) {
|
|
150
|
+
const chart = new Chart();
|
|
151
|
+
chart.judgeLineGroups = data.judgeLineGroup.map(group => new JudgeLineGroup(group));
|
|
152
|
+
chart.bpmList = data.BPMList;
|
|
153
|
+
chart.name = data.META.name;
|
|
154
|
+
chart.level = data.META.level;
|
|
155
|
+
chart.offset = data.META.offset;
|
|
156
|
+
chart.composer = data.META.composer ?? "unknown";
|
|
157
|
+
chart.charter = data.META.charter ?? "unknown";
|
|
158
|
+
chart.illustrator = data.META.illustration ?? "unknown";
|
|
159
|
+
chart.duration = duration;
|
|
160
|
+
chart.chartingTime = data.kpaChartTime
|
|
161
|
+
chart.rpeChartingTime = data.chartTime ? Math.round(data.chartTime / 60) : 0;
|
|
162
|
+
chart.chartingTime = 0;
|
|
163
|
+
chart.updateCalculator()
|
|
164
|
+
console.log(chart, chart.getEffectiveBeats())
|
|
165
|
+
chart.nnnList = new NNNList(chart.getEffectiveBeats())
|
|
166
|
+
|
|
167
|
+
/*
|
|
168
|
+
if (data.envEasings) {
|
|
169
|
+
chart.templateEasingLib.add(...data.envEasings)
|
|
170
|
+
|
|
171
|
+
}
|
|
172
|
+
*/
|
|
173
|
+
|
|
174
|
+
// let line = data.judgeLineList[0];
|
|
175
|
+
const judgeLineDataList: JudgeLineDataRPE[] = <JudgeLineDataRPE[]>data.judgeLineList;
|
|
176
|
+
const judgeLineList: JudgeLine[] = judgeLineDataList.map(
|
|
177
|
+
(lineData, id) =>
|
|
178
|
+
JudgeLine.fromRPEJSON(chart, id, lineData, chart.templateEasingLib, chart.timeCalculator)
|
|
179
|
+
);
|
|
180
|
+
const length = judgeLineList.length;
|
|
181
|
+
chart.judgeLines = judgeLineList;
|
|
182
|
+
for (let i = 0; i < length; i++) {
|
|
183
|
+
const data = judgeLineDataList[i];
|
|
184
|
+
const line = judgeLineList[i];
|
|
185
|
+
const father = data.father === -1 ? null : judgeLineList[data.father];
|
|
186
|
+
if (father) {
|
|
187
|
+
father.children.add(line);
|
|
188
|
+
} else {
|
|
189
|
+
chart.orphanLines.push(line);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
chart.countMaxCombo();
|
|
193
|
+
return chart
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
static fromKPAJSON(data: ChartDataKPA | ChartDataKPA2) {
|
|
197
|
+
const chart = new Chart();
|
|
198
|
+
|
|
199
|
+
chart.bpmList = data.bpmList;
|
|
200
|
+
chart.duration = data.duration;
|
|
201
|
+
chart.name = data.info.name;
|
|
202
|
+
chart.level = data.info.level;
|
|
203
|
+
chart.illustrator = data.info.illustrator ?? "unknown";
|
|
204
|
+
chart.composer = data.info.composer ?? "unknown";
|
|
205
|
+
chart.charter = data.info.charter ?? "unknown";
|
|
206
|
+
chart.offset = data.offset;
|
|
207
|
+
chart.judgeLineGroups = data.judgeLineGroups.map(group => new JudgeLineGroup(group));
|
|
208
|
+
chart.chartingTime = data.chartTime ?? 0;
|
|
209
|
+
chart.rpeChartingTime = data.rpeChartTime ?? 0;
|
|
210
|
+
chart.updateCalculator()
|
|
211
|
+
chart.nnnList = new NNNList(chart.getEffectiveBeats())
|
|
212
|
+
const envEasings = data.envEasings;
|
|
213
|
+
const len = envEasings.length
|
|
214
|
+
for (let i = 0; i < len; i++) {
|
|
215
|
+
const easingData = envEasings[i];
|
|
216
|
+
chart.templateEasingLib.require(easingData.name);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
if (data.version >= 200) {
|
|
220
|
+
const sequences = (data as ChartDataKPA2).eventNodeSequences;
|
|
221
|
+
const length = sequences.length;
|
|
222
|
+
for (let i = 0; i < length; i++) {
|
|
223
|
+
const seqData = sequences[i];
|
|
224
|
+
const sequence = EventNodeSequence.fromRPEJSON<typeof seqData.type, ValueTypeOfEventType<typeof seqData.type>>(seqData.type, seqData.events, chart, seqData.endValue);
|
|
225
|
+
sequence.id = seqData.id;
|
|
226
|
+
chart.sequenceMap.set(sequence.id, sequence);
|
|
227
|
+
}
|
|
228
|
+
} else {
|
|
229
|
+
|
|
230
|
+
const sequences = (data as ChartDataKPA).eventNodeSequences
|
|
231
|
+
const length = sequences.length
|
|
232
|
+
for (let i = 0; i < length; i++) {
|
|
233
|
+
const seqData = sequences[i];
|
|
234
|
+
const sequence = EventNodeSequence.fromRPEJSON<typeof seqData.type, ValueTypeOfEventType<typeof seqData.type>>(seqData.type, seqData.events, chart, seqData.endValue);
|
|
235
|
+
sequence.id = seqData.id;
|
|
236
|
+
chart.sequenceMap.set(sequence.id, sequence);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
for (let i = 0; i < len; i++) {
|
|
241
|
+
const easingData = envEasings[i];
|
|
242
|
+
chart.templateEasingLib.implement(easingData.name, chart.sequenceMap.get(easingData.content));
|
|
243
|
+
}
|
|
244
|
+
chart.templateEasingLib.check()
|
|
245
|
+
const isOld = !data.version || data.version < 150
|
|
246
|
+
for (let lineData of data.orphanLines) {
|
|
247
|
+
const line: JudgeLine = JudgeLine.fromKPAJSON(isOld, chart, lineData.id, lineData, chart.templateEasingLib, chart.timeCalculator)
|
|
248
|
+
chart.orphanLines.push(line)
|
|
249
|
+
}
|
|
250
|
+
chart.judgeLines.sort((a, b) => a.id - b.id);
|
|
251
|
+
chart.countMaxCombo();
|
|
252
|
+
|
|
253
|
+
const ui = data.ui;
|
|
254
|
+
if (ui) for (const uiname of ["combo", "combonumber", "score", "pause", "bar", "name", "level"] satisfies UIName[]) {
|
|
255
|
+
if (typeof ui[uiname] === "number") { // 踩坑,线号可为0
|
|
256
|
+
const line = chart.judgeLines[ui[uiname]]
|
|
257
|
+
if (!line) {
|
|
258
|
+
continue;
|
|
259
|
+
}
|
|
260
|
+
chart.attachUIToLine(uiname, line);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
return chart;
|
|
264
|
+
}
|
|
265
|
+
updateCalculator() {
|
|
266
|
+
this.timeCalculator.bpmList = this.bpmList;
|
|
267
|
+
this.timeCalculator.duration = this.duration;
|
|
268
|
+
this.timeCalculator.update()
|
|
269
|
+
}
|
|
270
|
+
updateEffectiveBeats(duration: number) {
|
|
271
|
+
const EB = this.timeCalculator.secondsToBeats(duration);
|
|
272
|
+
for (let i = 0; i < this.judgeLines.length; i++) {
|
|
273
|
+
const judgeLine = this.judgeLines[i]
|
|
274
|
+
judgeLine.updateEffectiveBeats(EB);
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
dumpKPA(): Required<ChartDataKPA2> {
|
|
278
|
+
const eventNodeSequenceCollector = new Set<EventNodeSequence>();
|
|
279
|
+
const orphanLines = [];
|
|
280
|
+
for (let line of this.orphanLines) {
|
|
281
|
+
orphanLines.push(line.dumpKPA(eventNodeSequenceCollector, this.judgeLineGroups));
|
|
282
|
+
}
|
|
283
|
+
const envEasings = this.templateEasingLib.dump(eventNodeSequenceCollector);
|
|
284
|
+
const eventNodeSequenceData: EventNodeSequenceDataKPA2<any>[] = [];
|
|
285
|
+
for (let sequence of eventNodeSequenceCollector) {
|
|
286
|
+
eventNodeSequenceData.push(sequence.dump());
|
|
287
|
+
}
|
|
288
|
+
return {
|
|
289
|
+
version: VERSION,
|
|
290
|
+
duration: this.duration,
|
|
291
|
+
bpmList: this.timeCalculator.dump(),
|
|
292
|
+
envEasings: envEasings,
|
|
293
|
+
eventNodeSequences: eventNodeSequenceData,
|
|
294
|
+
info: {
|
|
295
|
+
level: this.level,
|
|
296
|
+
name: this.name,
|
|
297
|
+
charter: this.charter,
|
|
298
|
+
illustrator: this.illustrator,
|
|
299
|
+
composer: this.composer
|
|
300
|
+
},
|
|
301
|
+
ui: {
|
|
302
|
+
combo: this.comboAttach?.id,
|
|
303
|
+
combonumber: this.combonumberAttach?.id,
|
|
304
|
+
score: this.scoreAttach?.id,
|
|
305
|
+
pause: this.pauseAttach?.id,
|
|
306
|
+
bar: this.barAttach?.id,
|
|
307
|
+
name: this.nameAttach?.id,
|
|
308
|
+
level: this.levelAttach?.id
|
|
309
|
+
},
|
|
310
|
+
offset: this.offset,
|
|
311
|
+
orphanLines: orphanLines,
|
|
312
|
+
judgeLineGroups: this.judgeLineGroups.map(g => g.name),
|
|
313
|
+
chartTime: this.chartingTime,
|
|
314
|
+
rpeChartTime: this.rpeChartingTime
|
|
315
|
+
};
|
|
316
|
+
}
|
|
317
|
+
createNNNode(time: TimeT) {
|
|
318
|
+
return new NNNode(time)
|
|
319
|
+
}
|
|
320
|
+
createEventNodeSequence<T extends EventType>(type: T, name: string) {
|
|
321
|
+
if (this.sequenceMap.has(name)) {
|
|
322
|
+
throw new Error(`The name ${name} is occupied.`)
|
|
323
|
+
}
|
|
324
|
+
const seq = EventNodeSequence.newSeq(type, this.getEffectiveBeats());
|
|
325
|
+
seq.id = name;
|
|
326
|
+
this.sequenceMap.set(name, seq);
|
|
327
|
+
return seq;
|
|
328
|
+
}
|
|
329
|
+
countMaxCombo() {
|
|
330
|
+
let combo = 0;
|
|
331
|
+
const nnnlist = this.nnnList;
|
|
332
|
+
for (let node: NNNOrTail = nnnlist.head.next; node.type !== NodeType.TAIL; node = node.next) {
|
|
333
|
+
const nns = node.noteNodes;
|
|
334
|
+
const nnsLength = nns.length;
|
|
335
|
+
for (let i = 0; i < nnsLength; i++) {
|
|
336
|
+
const nn = nns[i];
|
|
337
|
+
combo += nn.notes.reduce((prev, note) => prev + (note.isFake ? 0 : 1), 0);
|
|
338
|
+
}
|
|
339
|
+
const hns = node.holdNodes;
|
|
340
|
+
const hnsLength = hns.length;
|
|
341
|
+
for (let i = 0; i < hnsLength; i++) {
|
|
342
|
+
const hn = hns[i];
|
|
343
|
+
combo += hn.notes.reduce((prev, hold) => prev + (hold.isFake ? 0 : 1), 0);
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
this.maxCombo = combo;
|
|
347
|
+
}
|
|
348
|
+
attachUIToLine(ui: UIName, judgeLine: JudgeLine) {
|
|
349
|
+
const key = `${ui}Attach` satisfies keyof Chart;
|
|
350
|
+
if (this[key]) {
|
|
351
|
+
throw new Error(`UI ${ui} is occupied`);
|
|
352
|
+
}
|
|
353
|
+
this[key] = judgeLine;
|
|
354
|
+
judgeLine.hasAttachUI = true;
|
|
355
|
+
}
|
|
356
|
+
detachUI(ui: UIName) {
|
|
357
|
+
const key = `${ui}Attach` satisfies keyof Chart;
|
|
358
|
+
const judgeLine = this[key];
|
|
359
|
+
if (!judgeLine) {
|
|
360
|
+
return;
|
|
361
|
+
}
|
|
362
|
+
this[key] = null;
|
|
363
|
+
if (![ // 看着好丑
|
|
364
|
+
this.barAttach,
|
|
365
|
+
this.nameAttach,
|
|
366
|
+
this.comboAttach,
|
|
367
|
+
this.scoreAttach,
|
|
368
|
+
this.combonumberAttach,
|
|
369
|
+
this.levelAttach,
|
|
370
|
+
this.pauseAttach
|
|
371
|
+
].includes(judgeLine)) {
|
|
372
|
+
judgeLine.hasAttachUI = false;
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
queryJudgeLineUI(judgeLine: JudgeLine): UIName[] {
|
|
376
|
+
const arr: UIName[] = [];
|
|
377
|
+
for (const ui of ["combo", "combonumber", "score", "pause", "bar", "name", "level"] satisfies UIName[]) {
|
|
378
|
+
if (this[`${ui}Attach` satisfies keyof Chart] === judgeLine) {
|
|
379
|
+
arr.push(ui);
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
return arr;
|
|
383
|
+
}
|
|
384
|
+
scanAllTextures() {
|
|
385
|
+
const textures: Set<string> = new Set;
|
|
386
|
+
for (const line of this.judgeLines) {
|
|
387
|
+
textures.add(line.texture);
|
|
388
|
+
}
|
|
389
|
+
return textures
|
|
390
|
+
}
|
|
391
|
+
createEasingFromData(data: EasingDataKPA2) {
|
|
392
|
+
switch (data.type) {
|
|
393
|
+
case EasingType.bezier:
|
|
394
|
+
return new BezierEasing([data.bezier[0], data.bezier[1]], [data.bezier[2], data.bezier[3]]);
|
|
395
|
+
case EasingType.normal:
|
|
396
|
+
return rpeEasingArray[data.identifier];
|
|
397
|
+
case EasingType.segmented:
|
|
398
|
+
return new SegmentedEasing(this.createEasingFromData(data), data.left, data.right);
|
|
399
|
+
case EasingType.template:
|
|
400
|
+
return this.templateEasingLib.get(data.identifier);
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
createEvaluator<T extends EventValueESType>(data: EvaluatorDataKPA2<T>, type: EventValueTypeOfType<T>): Evaluator<T> {
|
|
404
|
+
switch (data.type) {
|
|
405
|
+
case EvaluatorType.eased:
|
|
406
|
+
return this.createEasedEvaluator(data, type);
|
|
407
|
+
case EvaluatorType.expressionbased:
|
|
408
|
+
return this.createExpressionEvaluator(data) as ExpressionEvaluator<T>;
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
createEasedEvaluator<T extends EventValueESType>(data: EasedEvaluatorDataOfType<T>, type: EventValueTypeOfType<T>): EasedEvaluatorOfType<T> {
|
|
412
|
+
switch (type) {
|
|
413
|
+
case EventValueType.numeric:
|
|
414
|
+
return data.easing.type === EasingType.normal
|
|
415
|
+
? NumericEasedEvaluator.evaluatorsOfNormalEasing[data.easing.identifier] as EasedEvaluatorOfType<T>
|
|
416
|
+
: new NumericEasedEvaluator(this.createEasingFromData(data.easing)) as EasedEvaluatorOfType<T>;
|
|
417
|
+
case EventValueType.color:
|
|
418
|
+
return data.easing.type === EasingType.normal
|
|
419
|
+
? ColorEasedEvaluator.evaluatorsOfNormalEasing[data.easing.identifier] as EasedEvaluatorOfType<T>
|
|
420
|
+
: new ColorEasedEvaluator(this.createEasingFromData(data.easing)) as EasedEvaluatorOfType<T>;
|
|
421
|
+
case EventValueType.text:
|
|
422
|
+
return data.easing.type === EasingType.normal
|
|
423
|
+
? TextEasedEvaluator.evaluatorsOfNoEzAndItpAs[data.easing.identifier][(data as TextEasedEvaluatorKPA2).interpretedAs] as EasedEvaluatorOfType<T>
|
|
424
|
+
: new TextEasedEvaluator(this.createEasingFromData(data.easing), (data as TextEasedEvaluatorKPA2).interpretedAs) as EasedEvaluatorOfType<T>
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
createExpressionEvaluator<T extends EventValueESType>(data: ExpressionEvaluatorDataKPA2) {
|
|
428
|
+
return new ExpressionEvaluator<T>(data.jsExpr);
|
|
429
|
+
}
|
|
430
|
+
/**
|
|
431
|
+
* 使用KPA2JSON创建一对面对面节点
|
|
432
|
+
* @param data
|
|
433
|
+
* @param type
|
|
434
|
+
* @returns
|
|
435
|
+
*/
|
|
436
|
+
createEventFromData<VT extends EventValueESType>(data: EventDataKPA2<VT>, type: EventValueTypeOfType<VT>): [EventStartNode<VT>, EventEndNode<VT>] {
|
|
437
|
+
const start = new EventStartNode(data.startTime, data.start);
|
|
438
|
+
const end = new EventEndNode(data.endTime, data.end);
|
|
439
|
+
start.evaluator = this.createEvaluator(data.evaluator, type);
|
|
440
|
+
EventNode.connect(start, end);
|
|
441
|
+
return [start, end];
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
export class JudgeLineGroup {
|
|
446
|
+
judgeLines: JudgeLine[];
|
|
447
|
+
constructor(public name: string) {
|
|
448
|
+
this.judgeLines = []
|
|
449
|
+
}
|
|
450
|
+
add(judgeLine: JudgeLine) {
|
|
451
|
+
// 加入之前已经按照ID升序排列
|
|
452
|
+
// 加入时将新判定线插入到正确位置
|
|
453
|
+
if (judgeLine.group) {
|
|
454
|
+
judgeLine.group.remove(judgeLine);
|
|
455
|
+
}
|
|
456
|
+
judgeLine.group = this;
|
|
457
|
+
|
|
458
|
+
// 找到正确的位置插入,保持按ID升序排列
|
|
459
|
+
for (let i = 0; i < this.judgeLines.length; i++) {
|
|
460
|
+
if (this.judgeLines[i].id > judgeLine.id) {
|
|
461
|
+
this.judgeLines.splice(i, 0, judgeLine);
|
|
462
|
+
return;
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
// 如果没有找到比它大的ID,则插入到末尾
|
|
466
|
+
this.judgeLines.push(judgeLine);
|
|
467
|
+
|
|
468
|
+
}
|
|
469
|
+
remove(judgeLine: JudgeLine) {
|
|
470
|
+
const index = this.judgeLines.indexOf(judgeLine);
|
|
471
|
+
if (index !== -1) {
|
|
472
|
+
this.judgeLines.splice(index, 1);
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
isDefault() {
|
|
476
|
+
return this.name.toLowerCase() === "default";
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
|
|
481
|
+
/// #enddeclaration
|