kipphi 2.0.0 → 2.0.1

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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "kipphi",
3
3
  "description": "Parse your Phigros Chart(.rpe.json or .kpa.json) into an editor-friendly format.",
4
- "version": "2.0.0",
4
+ "version": "2.0.1",
5
5
  "author": "Team Zincs (https://github.com/TeamZincs)",
6
6
  "license": "MIT",
7
7
  "repository": {
@@ -1,17 +1,21 @@
1
+
1
2
  import type { Chart, UIName } from "./chart";
2
3
  import { type TimeT, type ChartDataRPE, type MetaData, type JudgeLineDataRPE, type EventLayerDataRPE, type EventDataRPELike, EventType, InterpreteAs, type NoteDataRPE, type EventValueESType, EventValueType } from "./chartTypes";
3
4
  import { SegmentedEasing, BezierEasing, NormalEasing, fixedEasing, TemplateEasing, Easing } from "./easing";
4
- import { EasedEvaluator, ExpressionEvaluator, NumericEasedEvaluator, type EasedEvaluatorConstructorOfType, type EasedEvaluatorOfType } from "./evaluator";
5
+ import { err } from "./env";
6
+ import { EasedEvaluator, Evaluator, ExpressionEvaluator, NumericEasedEvaluator, TextEasedEvaluator, type EasedEvaluatorConstructorOfType, type EasedEvaluatorOfType } from "./evaluator";
5
7
  import { EventEndNode, EventNode, EventNodeSequence, EventStartNode, type EventNodeLike } from "./event";
6
8
  import type { JudgeLine } from "./judgeline";
7
9
  import type { NNList, HNList, NNOrHead } from "./note";
8
- import { TC, TimeCalculator } from "./time";
10
+ import TC from "./time";
9
11
  import { NodeType, numberToRatio } from "./util";
10
12
 
11
13
  /// #declaration:global
12
14
 
13
15
  const getInnerEasing = (easing: Easing) => easing instanceof SegmentedEasing ? easing.easing : easing;
14
16
 
17
+ type EasedStartNode<VT extends EventValueESType> = EventStartNode<VT> & { evaluator: EasedEvaluatorOfType<VT>};
18
+
15
19
  /**
16
20
  * 全生命周期只会编译一次,想多次就再构造一个
17
21
  */
@@ -58,7 +62,9 @@ export class RPEChartCompiler {
58
62
  eventLayers: [],
59
63
  father: target.id,
60
64
  isCover: lineData.isCover,
61
- numOfNotes: 0
65
+ numOfNotes: 0,
66
+ anchor: target.anchor,
67
+ isGif: 0
62
68
  } satisfies Partial<JudgeLineDataRPE> as JudgeLineDataRPE)
63
69
  } else {
64
70
  lineData.attachUI = uiName;
@@ -89,18 +95,18 @@ export class RPEChartCompiler {
89
95
  Name: judgeLine.name,
90
96
  Texture: judgeLine.texture,
91
97
  bpmfactor: 1.0,
92
- eventLayers: judgeLine.eventLayers.map((layer): EventLayerDataRPE => ({
93
- moveXEvents: layer.moveX ? this.dumpEventNodeSequence(layer.moveX) : null,
94
- moveYEvents: layer.moveY ? this.dumpEventNodeSequence(layer.moveY) : null,
95
- rotateEvents: layer.rotate ? this.dumpEventNodeSequence(layer.rotate) : null,
96
- alphaEvents: layer.alpha ? this.dumpEventNodeSequence(layer.alpha) : null,
97
- speedEvents: layer.speed ? this.dumpEventNodeSequence(layer.speed) : null
98
+ eventLayers: judgeLine.eventLayers.map((layer, index): EventLayerDataRPE => ({
99
+ moveXEvents: layer.moveX ? this.dumpEventNodeSequence(layer.moveX) : undefined,
100
+ moveYEvents: layer.moveY ? this.dumpEventNodeSequence(layer.moveY) : undefined,
101
+ rotateEvents: layer.rotate ? this.dumpEventNodeSequence(layer.rotate) : undefined,
102
+ alphaEvents: layer.alpha ? this.dumpEventNodeSequence(layer.alpha) : undefined,
103
+ speedEvents: index === 0 ? this.dumpEventNodeSequence(judgeLine.speedSequence) : undefined
98
104
  })),
99
105
  extended: {
100
- scaleXEvents: judgeLine.extendedLayer.scaleX ? this.dumpEventNodeSequence(judgeLine.extendedLayer.scaleX) : null,
101
- scaleYEvents: judgeLine.extendedLayer.scaleY ? this.dumpEventNodeSequence(judgeLine.extendedLayer.scaleY) : null,
102
- textEvents: judgeLine.extendedLayer.text ? this.dumpEventNodeSequence(judgeLine.extendedLayer.text) : null,
103
- colorEvents: judgeLine.extendedLayer.color ? this.dumpEventNodeSequence(judgeLine.extendedLayer.color) : null
106
+ scaleXEvents: judgeLine.extendedLayer.scaleX ? this.dumpEventNodeSequence(judgeLine.extendedLayer.scaleX) : undefined,
107
+ scaleYEvents: judgeLine.extendedLayer.scaleY ? this.dumpEventNodeSequence(judgeLine.extendedLayer.scaleY) : undefined,
108
+ textEvents: judgeLine.extendedLayer.text ? this.dumpEventNodeSequence(judgeLine.extendedLayer.text) : undefined,
109
+ colorEvents: judgeLine.extendedLayer.color ? this.dumpEventNodeSequence(judgeLine.extendedLayer.color) : undefined
104
110
  },
105
111
  father: judgeLine.father?.id ?? -1,
106
112
  isCover: judgeLine.cover ? 1 : 0,
@@ -121,7 +127,11 @@ export class RPEChartCompiler {
121
127
  const easing = evaluator.easing;
122
128
  const isSegmented = easing instanceof SegmentedEasing;
123
129
  const innerEasing = isSegmented ? easing.easing : easing;
124
-
130
+ const start = getValue(snode);
131
+ const end = getValue(easing === fixedEasing ? snode : endNode)
132
+ // if (isNaN(start) || isNaN(end)) {
133
+ // console.log("????")
134
+ // }
125
135
  return {
126
136
  bezier: innerEasing instanceof BezierEasing ? 1 : 0,
127
137
  bezierPoints: innerEasing instanceof BezierEasing ?
@@ -129,29 +139,29 @@ export class RPEChartCompiler {
129
139
  [0, 0, 0, 0],
130
140
  easingLeft: isSegmented ? easing.left : 0.0,
131
141
  easingRight: isSegmented ? easing.right : 1.0,
142
+ // @ts-expect-error 缓动为贝塞尔型时可以为null
132
143
  easingType: easing instanceof NormalEasing ?
133
144
  easing.rpeId ?? 1 :
134
145
  null,
135
- end: getValue(easing === fixedEasing ? snode : endNode),
146
+ end,
136
147
  endTime: endNode.time,
137
148
  linkgroup: 0, // 假设默认值为 0
138
- start: getValue(snode),
149
+ start,
139
150
  startTime: snode.time
140
151
  }
141
152
  }
142
153
 
143
- dumpEventNodeSequence<VT>(sequence: EventNodeSequence<VT>): EventDataRPELike<VT>[] {
154
+ dumpEventNodeSequence<VT extends EventValueESType>(sequence: EventNodeSequence<VT>): EventDataRPELike<VT>[] {
144
155
  const nodes: EventDataRPELike<VT>[] = [];
145
156
  const interpolationStep = this.interpolationStep;
146
- if (!(sequence.type === EventType.color || sequence.type === EventType.text)) {
147
- // @ts-ignore 烦死了烦死了烦死了
148
- sequence = this.substitute(sequence);
149
- }
150
- let node = sequence.head.next;
157
+ sequence = this.substitute(sequence);
158
+
159
+ let node = sequence.head.next!;
151
160
  // 唯一真史
152
161
  const getValue = (sequence.type === EventType.text
153
162
  ? (node: EventStartNode<string> | EventEndNode<string>) => {
154
- const interpretedAs = node instanceof EventStartNode ? node.interpretedAs : node.previous.interpretedAs;
163
+ const evaluator = (node instanceof EventStartNode ? node.evaluator : node.previous.evaluator) as TextEasedEvaluator;
164
+ const interpretedAs = evaluator.interpretedAs;
155
165
  return interpretedAs === InterpreteAs.str ? node.value : "%P%" + node.value;
156
166
  }
157
167
  : (node: EventStartNode<number> | EventEndNode<number>) => node.value) as unknown as (node: EventStartNode<VT> | EventEndNode<VT>) => VT;
@@ -159,6 +169,7 @@ export class RPEChartCompiler {
159
169
  const end = node.next;
160
170
  if (end.type === NodeType.TAIL) break;
161
171
  if (node.evaluator instanceof ExpressionEvaluator) {
172
+ // 插值
162
173
  let cur = node.time;
163
174
  const endTime = end.time;
164
175
  let value = getValue(node);
@@ -195,11 +206,17 @@ export class RPEChartCompiler {
195
206
  })
196
207
 
197
208
  } else {
198
- nodes.push(this.compileEvent(node, getValue));
209
+ nodes.push(this.compileEasedEvent(node as EasedStartNode<VT>, getValue));
199
210
  }
200
211
  node = end.next;
201
212
  }
202
- nodes.push(node.dumpAsLast());
213
+ // 刻意造一个事件,并给它加一个结束节点,距离一拍长(用于处理endValue)
214
+ const newStart = node!.clone();
215
+ // 只是占位而已,并不重要,我们这里期望最后一个事件的缓动为1号,特别注意不要写成0了
216
+ newStart.evaluator = NumericEasedEvaluator.evaluatorsOfNormalEasing[1] as unknown as EasedEvaluator<VT>;
217
+ const newEnd = new EventEndNode(TC.vadd(newStart.time, [1, 0, 1]), newStart.value);
218
+ EventNode.connect(newStart, newEnd);
219
+ nodes.push(this.compileEasedEvent(newStart as EasedStartNode<VT>, getValue));
203
220
 
204
221
  return nodes
205
222
  }
@@ -213,16 +230,17 @@ export class RPEChartCompiler {
213
230
  if (lists.length === 0) return;
214
231
  // 先按最早的时间排序
215
232
  lists.sort((a, b) => {
216
- return TimeCalculator.gt(time(a), time(b)) ? 1 : -1;
233
+ return TC.gt(time(a), time(b)) ? 1 : -1;
217
234
  });
218
235
  // 每次从lists中第一个list pop一个data加入到结果,然后冒泡调整这个list的位置
219
236
  while (lists[0].length > 0) {
220
237
  const list = lists[0];
221
238
  // 只需要pop就可以了,pop复杂度O(1),这是倒序的原因
222
239
  const node = list.pop();
223
- ret.push(node);
240
+ // !: 上面保证了list一定还有至少一个元素,否则的话不满足循环条件
241
+ ret.push(node!);
224
242
  let i = 0;
225
- while (i + 1 < lists.length && TimeCalculator.gt(time(lists[i]), time(lists[i + 1]))) {
243
+ while (i + 1 < lists.length && TC.gt(time(lists[i]), time(lists[i + 1]))) {
226
244
  const temp = lists[i];
227
245
  lists[i] = lists[i + 1];
228
246
  lists[i + 1] = temp;
@@ -242,12 +260,15 @@ export class RPEChartCompiler {
242
260
  */
243
261
  nnListToArray(nnList: NNList) {
244
262
  const notes: NoteDataRPE[] = [];
245
- let node: NNOrHead = nnList.tail.previous;
263
+ // 这个地方正常来讲不会为null或undefined
264
+ let node: NNOrHead = nnList.tail.previous!;
265
+ // 从最尾往前遍历
246
266
  while (node.type !== NodeType.HEAD) {
247
- for (let each of node.notes) {
267
+ for (const each of node.notes) {
248
268
  notes.push(each.dumpRPE(this.chart.timeCalculator));
249
269
  }
250
- node = node.previous;
270
+ // 同上,正常来讲不会为null或undefined
271
+ node = node.previous!;
251
272
  }
252
273
  return notes;
253
274
  }
@@ -256,27 +277,32 @@ export class RPEChartCompiler {
256
277
  * 将当前序列中所有通过模板缓动引用了其他序列的事件直接展开为被引用的序列内容
257
278
  * transform all events that reference other sequences by template easing
258
279
  * into the content of the referenced sequence
259
- * 有点类似于MediaWiki的{{subst:templateName}}
260
- * @param map 由TemplateEasingLib提供
280
+ *
281
+ * 有点类似于MediaWiki的`{{subst:templateName}}`
261
282
  * @returns
262
283
  */
263
284
  substitute<VT extends EventValueESType>(seq: EventNodeSequence<VT>): EventNodeSequence<VT> {
264
285
  const map = this.sequenceMap;
265
286
  if (map.has(seq)) {
266
- return map.get(seq);
287
+ // 都has了还担心啥undefined,TSC也是个人机
288
+ return map.get(seq)!;
267
289
  }
268
- let currentNode: EventStartNode<VT> = seq.head.next;
290
+ // 一般不会为null
291
+ let currentNode: EventStartNode<VT> = seq.head.next!;
269
292
  const newSeq = new EventNodeSequence<VT>(seq.type, seq.effectiveBeats);
270
293
  const valueType = seq.type === EventType.color
271
294
  ? EventValueType.color : seq.type === EventType.text
272
295
  ? EventValueType.text : EventValueType.numeric;
296
+ // 加入哈希表缓存,避免重复计算
273
297
  map.set(seq, newSeq);
274
298
  let currentPos: EventNodeLike<NodeType.HEAD, VT> | EventEndNode<VT> = newSeq.head;
275
299
  while (true) {
276
300
  if (!currentNode || (currentNode.next.type === NodeType.TAIL)) {
277
301
  break;
278
302
  }
303
+ /** 原序列当前结束节点 */
279
304
  const endNode = currentNode.next;
305
+ /** 原序列当前节点的求值器 */
280
306
  const evaluator = currentNode.evaluator;
281
307
  let innerEasing: Easing;
282
308
  if ( evaluator
@@ -293,15 +319,15 @@ export class RPEChartCompiler {
293
319
  const timeDelta = TC.sub(currentNode.next.time, startTime);
294
320
 
295
321
 
296
- let srcStart: number, srcEnd: number, leftDividedNodeSrc: EventStartNode, rightDividedNode: EventStartNode,
322
+ let srcStart: number, srcEnd: number, leftDividedNodeSrc: EventStartNode, rightDividedNodeSrc: EventStartNode,
297
323
  srcStartTime: TimeT, srcTimeDelta: TimeT, toStopAt: EventStartNode;
298
324
  if (isSegmented) {
299
- const totalDuration = TC.sub(srcSeq.tail.previous.time, srcSeq.head.next.time);
325
+ const totalDuration = TC.sub(srcSeq.tail.previous!.time, srcSeq.head.next!.time);
300
326
  srcStart = srcSeq.getValueAt(easing.left * srcSeq.effectiveBeats)
301
327
  srcEnd = srcSeq.getValueAt(easing.right * srcSeq.effectiveBeats, true);
302
328
  leftDividedNodeSrc = srcSeq.getNodeAt(easing.left * srcSeq.effectiveBeats);
303
- rightDividedNode = srcSeq.getNodeAt(easing.right * srcSeq.effectiveBeats, true);
304
- toStopAt = rightDividedNode.next.next;
329
+ rightDividedNodeSrc = srcSeq.getNodeAt(easing.right * srcSeq.effectiveBeats, true);
330
+ toStopAt = rightDividedNodeSrc.next.next!;
305
331
  srcStartTime = TC.mul(totalDuration, numberToRatio(easing.left));
306
332
  const srcEndTime = TC.mul(totalDuration, numberToRatio(easing.right));
307
333
  TC.validateIp(srcStartTime);
@@ -309,13 +335,13 @@ export class RPEChartCompiler {
309
335
  srcTimeDelta = TC.sub(srcEndTime, srcStartTime);
310
336
  TC.validateIp(srcTimeDelta);
311
337
  } else {
312
- srcStart = srcSeq.head.next.value;
313
- srcEnd = srcSeq.tail.previous.value;
314
- leftDividedNodeSrc = srcSeq.head.next;
315
- rightDividedNode = srcSeq.tail.previous;
316
- toStopAt = rightDividedNode;
317
- srcStartTime = srcSeq.head.next.time;
318
- srcTimeDelta = TC.sub(srcSeq.tail.previous.time, srcStartTime);
338
+ srcStart = srcSeq.head.next!.value;
339
+ srcEnd = srcSeq.tail.previous!.value;
340
+ leftDividedNodeSrc = srcSeq.head.next!;
341
+ rightDividedNodeSrc = srcSeq.tail.previous!;
342
+ toStopAt = rightDividedNodeSrc;
343
+ srcStartTime = srcSeq.head.next!.time;
344
+ srcTimeDelta = TC.sub(srcSeq.tail.previous!.time, srcStartTime);
319
345
  }
320
346
 
321
347
  const srcDelta = srcEnd - srcStart;
@@ -327,84 +353,93 @@ export class RPEChartCompiler {
327
353
  const convertTime: (t: TimeT) => TimeT
328
354
  = (time: TimeT) => TC.validateIp(TC.add(startTime, TC.mul(TC.sub(time, srcStartTime), ratio)));
329
355
 
356
+ /** 目标序列中某次参与替换操作的第一个节点 */
330
357
  const first = currentNode.clone();
331
358
  EventNode.connect(currentPos, first)
332
359
  // 处理第一个节点的截段
333
- if (isSegmented) {
334
- const left = easing.left * srcSeq.effectiveBeats
335
- if (left - TC.toBeats(leftDividedNodeSrc.time) > 1e-6) {
336
- // 断言:这里left不会大于有效拍数
337
- const newLeft = left / (TC.toBeats((leftDividedNodeSrc.next as EventEndNode).time) - TC.toBeats(leftDividedNodeSrc.time))
338
- // 如果切到的这个位置是表达式求值器,这是没办法保留缓动的,只能运用表达式求值器
339
- if (leftDividedNodeSrc.evaluator instanceof ExpressionEvaluator) {
340
- const exprEvaluator = leftDividedNodeSrc.evaluator as ExpressionEvaluator<number>;
341
- first.evaluator = new ExpressionEvaluator("t");
342
- // 强行修改
343
- // @ts-ignore
344
- first.evaluator.func = (t: number) => {
345
- const value = exprEvaluator.func(
346
- t * (TC.getDelta((first.next as EventEndNode).time, first.time) * (1 - left)) / srcSeq.effectiveBeats
347
- ); // 脑细胞杀器
348
- return convert(value);
349
- }
350
- } else {
351
- // 否则就是带缓动求值器
352
- first.evaluator = new EvaluatorConstructor(
353
- new SegmentedEasing((leftDividedNodeSrc.evaluator as NumericEasedEvaluator).easing, newLeft, 1.0)
354
- );
355
-
356
- }
360
+ if (
361
+ isSegmented
362
+ && (
363
+ easing.left * srcSeq.effectiveBeats - TC.toBeats(leftDividedNodeSrc.time) > 1e-6
364
+ )
365
+ ) {
366
+ const left = easing.left * srcSeq.effectiveBeats;
367
+ // 断言:这里left不会大于有效拍数
368
+ const newLeft = left / (TC.toBeats((leftDividedNodeSrc.next as EventEndNode).time) - TC.toBeats(leftDividedNodeSrc.time))
369
+ // 如果切到的这个位置是表达式求值器,这是没办法保留缓动的,只能运用表达式求值器
370
+ if (leftDividedNodeSrc.evaluator instanceof ExpressionEvaluator) {
371
+ throw err.CANNOT_DIVIDE_EXPRESSION_EVALUATOR(seq.id);
357
372
  } else {
358
- if (leftDividedNodeSrc.evaluator instanceof ExpressionEvaluator) {
359
- first.evaluator = new ExpressionEvaluator("t");
360
- // 也不知道对不对
361
- // @ts-ignore
362
- first.evaluator.func = (t: number) => {
363
- return convert(leftDividedNodeSrc.evaluator.eval(leftDividedNodeSrc, t))
364
- }
365
- } else {
366
- first.evaluator = new EvaluatorConstructor((leftDividedNodeSrc.evaluator as NumericEasedEvaluator).easing, evaluator.interpretedAs);
367
- }
373
+ // 否则就是带缓动求值器
374
+ first.evaluator = evaluator.deriveWithEasing(
375
+ new SegmentedEasing((leftDividedNodeSrc.evaluator as NumericEasedEvaluator).easing, newLeft, 1.0)
376
+ ) as unknown as Evaluator<VT>;
377
+ // TypeScript Compiler我*你娘啊
378
+
368
379
  }
369
380
  } else {
370
381
  if (leftDividedNodeSrc.evaluator instanceof ExpressionEvaluator) {
371
- first.evaluator = new ExpressionEvaluator("t");
372
- // 也不知道对不对
373
- // @ts-ignore
374
- first.evaluator.func = (t: number) => {
375
- return convert(leftDividedNodeSrc.evaluator.eval(leftDividedNodeSrc, t))
376
- }
382
+ throw err.CANNOT_DIVIDE_EXPRESSION_EVALUATOR(seq.id);
377
383
  } else {
378
- first.evaluator = new EvaluatorConstructor((leftDividedNodeSrc.evaluator as NumericEasedEvaluator).easing, evaluator.interpretedAs);
384
+ first.evaluator = evaluator.deriveWithEasing(
385
+ (leftDividedNodeSrc.evaluator as NumericEasedEvaluator).easing
386
+ ) as unknown as Evaluator<VT>;
379
387
  }
380
388
  }
381
389
  let prev = first
382
390
  // 这里在到toStopAt之前一直都是非尾的
383
- for (let n: EventEndNode<number> = leftDividedNodeSrc.next as EventEndNode<number>; n.next !== toStopAt; n = n.next.next) {
391
+ for (let n: EventEndNode<number> = leftDividedNodeSrc.next as EventEndNode<number>; n.next !== toStopAt; ) {
384
392
  const endNode = n;
385
393
  const startNode = n.next;
394
+ // 断言:TSC不理解序列结构,这里截止得可能还早些,一定不是尾结点
395
+ n = startNode.next as EventEndNode<number>;
386
396
  const newEnd = new EventEndNode(convertTime(endNode.time), convert(endNode.value));
387
397
  const newStart = new EventStartNode(convertTime(startNode.time), convert(startNode.value));
388
- newStart.evaluator = new EvaluatorConstructor(startNode.evaluator.easing);
398
+ if (startNode.evaluator instanceof ExpressionEvaluator) {
399
+ throw err.CANNOT_DIVIDE_EXPRESSION_EVALUATOR(seq.id);
400
+ } else {
401
+ newStart.evaluator = evaluator.deriveWithEasing(
402
+ (startNode.evaluator as NumericEasedEvaluator).easing,
403
+ ) as unknown as Evaluator<VT>;
404
+ }
389
405
  EventNode.connect(prev, newEnd)
390
406
  EventNode.connect(newEnd, newStart);
391
407
  prev = newStart;
392
408
  }
393
409
  // 处理最后一个节点的截段
394
- if (isSegmented) {
410
+ if (
411
+ isSegmented
412
+ && (
413
+ TC.toBeats((rightDividedNodeSrc.next as EventEndNode).time) - easing.right * srcSeq.effectiveBeats > 1e-6
414
+ )
415
+ ) {
395
416
  const right = easing.right * srcSeq.effectiveBeats
396
- if (TC.toBeats((rightDividedNode.next as EventEndNode).time) - right > 1e-6) {
397
- // 断言:这里right不会大于有效拍数
398
- const newRight = right / (TC.toBeats((rightDividedNode.next as EventEndNode).time) - TC.toBeats(rightDividedNode.time))
399
- // 这时候prev是最后一个subst的node
400
- prev.easing = new SegmentedEasing(rightDividedNode.easing, 0.0, newRight)
401
- }
417
+ // 断言:这里left不会大于有效拍数
418
+ const newRight = right / (TC.toBeats((rightDividedNodeSrc.next as EventEndNode).time) - TC.toBeats(rightDividedNodeSrc.time))
419
+ // 如果切到的这个位置是表达式求值器,这是没办法保留缓动的,只能运用表达式求值器
420
+ if (rightDividedNodeSrc.evaluator instanceof ExpressionEvaluator) {
421
+ throw err.CANNOT_DIVIDE_EXPRESSION_EVALUATOR(seq.id);
422
+ } else {
423
+ // 否则就是带缓动求值器
424
+ first.evaluator = evaluator.deriveWithEasing(
425
+ new SegmentedEasing((rightDividedNodeSrc.evaluator as NumericEasedEvaluator).easing, 0.0, newRight)
426
+ ) as unknown as Evaluator<VT>;
427
+ // TypeScript Compiler我*你娘啊
402
428
 
429
+ }
430
+ } else {
431
+ if (rightDividedNodeSrc.evaluator instanceof ExpressionEvaluator) {
432
+ throw err.CANNOT_DIVIDE_EXPRESSION_EVALUATOR(seq.id);
433
+ } else {
434
+ first.evaluator = evaluator.deriveWithEasing(
435
+ (rightDividedNodeSrc.evaluator as NumericEasedEvaluator).easing
436
+ ) as unknown as Evaluator<VT>;
437
+ }
403
438
  }
404
439
  const endNode = currentNode.next.clone();
405
440
  EventNode.connect(prev, endNode);
406
441
  currentPos = endNode;
407
- endNode.value = isSegmented ? endNode.value : convert((srcSeq.tail.previous.previous as EventEndNode).value);
442
+ endNode.value = isSegmented ? endNode.value : convert((srcSeq.tail.previous!.previous as EventEndNode).value);
408
443
  } else {
409
444
  const newStartNode = currentNode.clone();
410
445
  const newEndNode = endNode.clone();
@@ -420,6 +455,6 @@ export class RPEChartCompiler {
420
455
  return newSeq;
421
456
  }
422
457
  }
423
-
458
+ // 现在是2025年10月18日,杨哲思已经改掉了此项目最史山的代码之一,但是还是一坨
424
459
 
425
460
  /// #enddeclaration