kipphi 2.0.1 → 2.1.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/event.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import type { Chart } from "./chart";
2
- import { EventType, type TimeT, type EventDataKPA, type RGB, type EventDataRPELike, InterpreteAs, type ValueTypeOfEventType, type EventNodeSequenceDataKPA, type EventDataKPA2, type EventNodeSequenceDataKPA2, type EventValueESType, EventValueType, EventValueTypeOfType } from "./chartTypes";
2
+ import { EventType, type TimeT, type EventDataKPA, type RGB, type EventDataRPELike, InterpreteAs, type ValueTypeOfEventType, type EventNodeSequenceDataKPA, type EventDataKPA2, type EventNodeSequenceDataKPA2, type EventValueESType, EventValueType, EventValueTypeOfType, FinalEventStartNodeDataKPA2, EvaluatorType, EasingType } from "./chartTypes";
3
3
  import { TemplateEasingLib, BezierEasing, Easing, rpeEasingArray, SegmentedEasing, linearEasing, fixedEasing, TemplateEasing, NormalEasing } from "./easing";
4
4
  import { ColorEasedEvaluator, EasedEvaluator, ExpressionEvaluator, NumericEasedEvaluator, TextEasedEvaluator, type Evaluator } from "./evaluator";
5
5
  import { JumpArray } from "./jumparray";
@@ -10,9 +10,10 @@ import { NodeType } from "./util";
10
10
 
11
11
  import { err, ERROR_IDS, KPAError } from "./env";
12
12
  import { JudgeLine } from "./judgeline";
13
+ import { EventMacro, EventMacroTime, EventMacroValue, Macroable } from "./macro";
13
14
 
14
15
  /// #declaration:global
15
- export class EventNodeLike<T extends NodeType, VT = number> {
16
+ export class EventNodeLike<T extends NodeType, VT extends EventValueESType = number> {
16
17
  type: T;
17
18
  /** 后一个事件节点 */
18
19
  next: [EventStartNode<VT>, null, ENOrTail<VT>][T] | null = null;
@@ -23,10 +24,10 @@ export class EventNodeLike<T extends NodeType, VT = number> {
23
24
  this.type = type;
24
25
  }
25
26
  }
26
- export type ENOrTail<VT = number> = EventNode<VT> | EventNodeLike<NodeType.TAIL, VT>;
27
- export type ENOrHead<VT = number> = EventNode<VT> | EventNodeLike<NodeType.HEAD, VT>;
28
- export type AnyEN<VT = number> = EventNode<VT> | EventNodeLike<NodeType.HEAD, VT> | EventNodeLike<NodeType.TAIL, VT>;
29
- export type EvSoE<VT = number> = EventEndNode<VT> | EventStartNode<VT>;
27
+ export type ENOrTail<VT extends EventValueESType = number> = EventNode<VT> | EventNodeLike<NodeType.TAIL, VT>;
28
+ export type ENOrHead<VT extends EventValueESType = number> = EventNode<VT> | EventNodeLike<NodeType.HEAD, VT>;
29
+ export type AnyEN<VT extends EventValueESType = number> = EventNode<VT> | EventNodeLike<NodeType.HEAD, VT> | EventNodeLike<NodeType.TAIL, VT>;
30
+ export type EvSoE<VT extends EventValueESType = number> = EventEndNode<VT> | EventStartNode<VT>;
30
31
 
31
32
  /**
32
33
  * 事件节点基类
@@ -43,10 +44,12 @@ export type EvSoE<VT = number> = EventEndNode<VT> | EventStartNode<VT>;
43
44
  * 与RPE不同的是,KPA使用两个节点来表示一个事件,而不是一个对象。
44
45
  * Different from that in RPE, KPA uses two nodes rather than one object to represent an event.
45
46
  */
46
- export abstract class EventNode<VT = number> extends EventNodeLike<NodeType.MIDDLE, VT> {
47
+ export abstract class EventNode<VT extends EventValueESType = number> extends EventNodeLike<NodeType.MIDDLE, VT> {
47
48
  time: TimeT;
48
49
  value: VT;
49
50
  evaluator: Evaluator<VT>;
51
+ macroValue: EventMacroValue;
52
+ linkedMacros: Set<EventMacro<Macroable>> = new Set();
50
53
  constructor(time: TimeT, value: VT) {
51
54
  super(NodeType.MIDDLE);
52
55
  this.time = TC.validateIp([...time]);
@@ -106,12 +109,11 @@ export abstract class EventNode<VT = number> extends EventNodeLike<NodeType.MIDD
106
109
  const right = data.easingRight;
107
110
  const wrap = (easing: Easing): EasedEvaluator<VT> => {
108
111
  if (typeof data.start === "number") {
109
- return new NumericEasedEvaluator(easing) as EasedEvaluator<VT>;
112
+ return new NumericEasedEvaluator(easing) as unknown as EasedEvaluator<VT>;
110
113
  } else if (typeof data.start === "string") {
111
- // @ts-expect-error
112
- return new TextEasedEvaluator(easing, interpreteAs);
114
+ return new TextEasedEvaluator(easing, interpreteAs) as unknown as EasedEvaluator<VT>;
113
115
  } else {
114
- return new ColorEasedEvaluator(easing) as EasedEvaluator<VT>;
116
+ return new ColorEasedEvaluator(easing) as unknown as EasedEvaluator<VT>;
115
117
  }
116
118
  };
117
119
  if ((left && right) && (left !== 0.0 || right !== 1.0)) {
@@ -173,9 +175,9 @@ export abstract class EventNode<VT = number> extends EventNodeLike<NodeType.MIDD
173
175
  EventNode.connect(start, end)
174
176
  return [start, end]
175
177
  }
176
- static connect<VT>(node1: EventStartNode<VT>, node2: EventEndNode<VT> | EventNodeLike<NodeType.TAIL, VT>): void
177
- static connect<VT>(node1: EventEndNode<VT> | EventNodeLike<NodeType.HEAD, VT>, node2: EventStartNode<VT>): void
178
- static connect<VT>(node1: ENOrHead<VT>, node2: ENOrTail<VT>): void {
178
+ static connect<VT extends EventValueESType>(node1: EventStartNode<VT>, node2: EventEndNode<VT> | EventNodeLike<NodeType.TAIL, VT>): void
179
+ static connect<VT extends EventValueESType>(node1: EventEndNode<VT> | EventNodeLike<NodeType.HEAD, VT>, node2: EventStartNode<VT>): void
180
+ static connect<VT extends EventValueESType>(node1: ENOrHead<VT>, node2: ENOrTail<VT>): void {
179
181
  node1.next = node2;
180
182
  node2.previous = node1;
181
183
  if (node1 && node2) {
@@ -188,7 +190,7 @@ export abstract class EventNode<VT = number> extends EventNodeLike<NodeType.MIDD
188
190
  * @param startNode
189
191
  * @returns 应该在何范围内更新跳数组
190
192
  */
191
- static removeNodePair<VT>(endNode: EventEndNode<VT>, startNode: EventStartNode<VT>): [EventStartNode<VT> | EventNodeLike<NodeType.HEAD, VT>, EventStartNode<VT> | EventNodeLike<NodeType.TAIL,VT>] {
193
+ static removeNodePair<VT extends EventValueESType>(endNode: EventEndNode<VT>, startNode: EventStartNode<VT>): [EventStartNode<VT> | EventNodeLike<NodeType.HEAD, VT>, EventStartNode<VT> | EventNodeLike<NodeType.TAIL,VT>] {
192
194
  const prev = endNode.previous;
193
195
  const next = startNode.next;
194
196
  prev.next = next;
@@ -199,7 +201,7 @@ export abstract class EventNode<VT = number> extends EventNodeLike<NodeType.MIDD
199
201
  startNode.parentSeq = null; // 每亩的东西(
200
202
  return [this.previousStartOfStart(prev), this.nextStartOfEnd(next)]
201
203
  }
202
- static insert<VT>(node: EventStartNode<VT>, tarPrev: EventStartNode<VT>): [EventNodeLike<NodeType.HEAD, VT> | EventStartNode<VT>, EventStartNode<VT> | EventNodeLike<NodeType.TAIL, VT>] {
204
+ static insert<VT extends EventValueESType>(node: EventStartNode<VT>, tarPrev: EventStartNode<VT>): [EventNodeLike<NodeType.HEAD, VT> | EventStartNode<VT>, EventStartNode<VT> | EventNodeLike<NodeType.TAIL, VT>] {
203
205
  const tarNext = tarPrev.next;
204
206
  if (node.previous.type === NodeType.HEAD) {
205
207
  throw err.CANNOT_INSERT_BEFORE_HEAD();
@@ -214,7 +216,7 @@ export abstract class EventNode<VT = number> extends EventNodeLike<NodeType.MIDD
214
216
  * @param node
215
217
  * @returns the next node if it is a tailer, otherwise the next start node
216
218
  */
217
- static nextStartOfStart<VT>(node: EventStartNode<VT>) {
219
+ static nextStartOfStart<VT extends EventValueESType>(node: EventStartNode<VT>) {
218
220
  return node.next.type === NodeType.TAIL ? node.next : node.next.next
219
221
  }
220
222
  /**
@@ -222,10 +224,10 @@ export abstract class EventNode<VT = number> extends EventNodeLike<NodeType.MIDD
222
224
  * @param node
223
225
  * @returns itself if node is a tailer, otherwise the next start node
224
226
  */
225
- static nextStartOfEnd<VT>(node: EventEndNode<VT> | EventNodeLike<NodeType.TAIL, VT>) {
227
+ static nextStartOfEnd<VT extends EventValueESType>(node: EventEndNode<VT> | EventNodeLike<NodeType.TAIL, VT>) {
226
228
  return node.type === NodeType.TAIL ? node : node.next
227
229
  }
228
- static previousStartOfStart<VT>(node: EventStartNode<VT>): EventStartNode<VT> | EventNodeLike<NodeType.HEAD, VT> {
230
+ static previousStartOfStart<VT extends EventValueESType>(node: EventStartNode<VT>): EventStartNode<VT> | EventNodeLike<NodeType.HEAD, VT> {
229
231
  return node.previous.type === NodeType.HEAD ? node.previous : node.previous.previous;
230
232
  }
231
233
  /**
@@ -233,10 +235,10 @@ export abstract class EventNode<VT = number> extends EventNodeLike<NodeType.MIDD
233
235
  * @param node
234
236
  * @returns
235
237
  */
236
- static secondPreviousStartOfEnd<VT>(node: EventEndNode<VT>): EventStartNode<VT> | EventNodeLike<NodeType.HEAD, VT> {
238
+ static secondPreviousStartOfEnd<VT extends EventValueESType>(node: EventEndNode<VT>): EventStartNode<VT> | EventNodeLike<NodeType.HEAD, VT> {
237
239
  return this.previousStartOfStart(node.previous);
238
240
  }
239
- static nextStartInJumpArray<VT>(node: EventStartNode<VT>): EventStartNode<VT> | EventNodeLike<NodeType.TAIL, VT> {
241
+ static nextStartInJumpArray<VT extends EventValueESType>(node: EventStartNode<VT>): EventStartNode<VT> | EventNodeLike<NodeType.TAIL, VT> {
240
242
  if ((node.next as EventEndNode<VT>).next.isLastStart()) {
241
243
  return node.next.next.next as EventNodeLike<NodeType.TAIL, VT>;
242
244
  } else {
@@ -248,7 +250,7 @@ export abstract class EventNode<VT = number> extends EventNodeLike<NodeType.MIDD
248
250
  * @param node
249
251
  * @returns
250
252
  */
251
- static getEndStart<VT>(node: EventStartNode<VT> | EventEndNode<VT>): [EventEndNode<VT>, EventStartNode<VT>] {
253
+ static getEndStart<VT extends EventValueESType>(node: EventStartNode<VT> | EventEndNode<VT>): [EventEndNode<VT>, EventStartNode<VT>] {
252
254
  if (node instanceof EventStartNode) {
253
255
  if (node.isFirstStart()) {
254
256
  throw new Error("Cannot get previous start node of the first start node");
@@ -258,7 +260,7 @@ export abstract class EventNode<VT = number> extends EventNodeLike<NodeType.MIDD
258
260
  return [node, node.next]
259
261
  }
260
262
  }
261
- static getStartEnd<VT>(node: EventStartNode<VT> | EventEndNode<VT>): [EventStartNode<VT>, EventEndNode<VT>] {
263
+ static getStartEnd<VT extends EventValueESType>(node: EventStartNode<VT> | EventEndNode<VT>): [EventStartNode<VT>, EventEndNode<VT>] {
262
264
  if (node instanceof EventStartNode) {
263
265
  return [node, <EventEndNode<VT>>node.next]
264
266
  } else if (node instanceof EventEndNode) {
@@ -267,7 +269,7 @@ export abstract class EventNode<VT = number> extends EventNodeLike<NodeType.MIDD
267
269
  throw new Error("unreachable");
268
270
  }
269
271
  }
270
- static setToNewOrderedArray<VT>(dest: TimeT, set: Set<EventStartNode<VT>>): [EventStartNode<VT>[], EventStartNode<VT>[]] {
272
+ static setToNewOrderedArray<VT extends EventValueESType>(dest: TimeT, set: Set<EventStartNode<VT>>): [EventStartNode<VT>[], EventStartNode<VT>[]] {
271
273
  const nodes = [...set]
272
274
  nodes.sort((a, b) => TC.gt(a.time, b.time) ? 1 : -1);
273
275
  const offset = TC.sub(dest, nodes[0].time)
@@ -302,9 +304,10 @@ export abstract class EventNode<VT = number> extends EventNodeLike<NodeType.MIDD
302
304
  // #endregion
303
305
  }
304
306
 
305
- export class EventStartNode<VT = number> extends EventNode<VT> {
307
+ export class EventStartNode<VT extends EventValueESType = number> extends EventNode<VT> {
306
308
  override next: EventEndNode<VT> | EventNodeLike<NodeType.TAIL, VT>;
307
309
  override previous: EventEndNode<VT> | EventNodeLike<NodeType.HEAD, VT>;
310
+ macroTime: EventMacroTime | null = null;
308
311
  /**
309
312
  * 对于速度事件,从0时刻到此节点的总积分
310
313
  */
@@ -325,16 +328,32 @@ export class EventStartNode<VT = number> extends EventNode<VT> {
325
328
  end: endNode.value,
326
329
  startTime: this.time,
327
330
  endTime: endNode.time,
328
- evaluator: this.evaluator.dump(),
331
+ evaluator: this.evaluator.dumpFor(this),
332
+ macroStart: this.macroValue?.dumpForNode(this),
333
+ macroEnd: this.macroValue?.dumpForNode(endNode),
334
+ macroStartTime: this.macroTime?.dumpForNode(this),
335
+ // 没有macroEndTime
336
+ startLinkedMacro: [...this.linkedMacros].map(macro => macro.dumpLinkForNode(this)),
337
+ endLinkedMacro: [...endNode.linkedMacros].map(macro => macro.dumpLinkForNode(endNode))
329
338
  }
330
339
  }
340
+ dumpAsFinal(): FinalEventStartNodeDataKPA2<VT> {
341
+ return {
342
+ start: this.value,
343
+ startTime: this.time,
344
+ evaluator: this.evaluator.dumpFor(this),
345
+ macro: this.macroValue?.dumpForNode(this),
346
+ macroTime: this.macroTime?.dumpForNode(this),
347
+ linkedMacro: [...this.linkedMacros].map(macro => macro.dumpLinkForNode(this)),
348
+ }
349
+ }
331
350
  getValueAt(beats: number): VT {
332
351
  // 除了尾部的开始节点,其他都有下个节点
333
352
  // 钩定型缓动也有
334
353
  if (this.next.type === NodeType.TAIL) {
335
354
  return this.value;
336
355
  }
337
- return this.evaluator.eval(this, beats);
356
+ return this.evaluator.eval(this as NonLastStartNode<VT>, beats);
338
357
  }
339
358
  getSpeedValueAt(this: EventStartNode<number>, beats: number) {
340
359
  if (this.next.type === NodeType.TAIL) {
@@ -384,7 +403,7 @@ export class EventStartNode<VT = number> extends EventNode<VT> {
384
403
 
385
404
  export type NonLastStartNode<VT extends EventValueESType> = EventStartNode<VT> & {next: EventEndNode<VT>}
386
405
 
387
- export class EventEndNode<VT = number> extends EventNode<VT> {
406
+ export class EventEndNode<VT extends EventValueESType = number> extends EventNode<VT> {
388
407
  override next!: EventStartNode<VT>;
389
408
  override previous!: EventStartNode<VT>;
390
409
 
@@ -435,7 +454,7 @@ export enum Monotonicity {
435
454
  * 插入或删除节点时,需要更新跳数组。
436
455
  * Remember to update the jump array when inserting or deleting nodes.
437
456
  */
438
- export class EventNodeSequence<VT = number> { // 泛型的传染性这一块
457
+ export class EventNodeSequence<VT extends EventValueESType = number> { // 泛型的传染性这一块
439
458
  /**
440
459
  * @deprecated 谱面属性未实装,以后有必要的时候会添加为其赋值的逻辑
441
460
  */
@@ -489,7 +508,18 @@ export class EventNodeSequence<VT = number> { // 泛型的传染性这一块
489
508
  type === EventType.color ? [0, 0, 0] :
490
509
  0
491
510
  }
492
- static fromRPEJSON<T extends EventType, VT = number>(type: T, data: EventDataRPELike<VT>[], chart: Chart, pos: string, endValue?: number) {
511
+ /**
512
+ * 从RPEJSON数据创建一个事件序列。
513
+ *
514
+ * KPAJSON 1.x也会使用此接口
515
+ * @param type 事件类型(不是数值类型,也不是数值ECMAScript类型)
516
+ * @param data 事件数据的数组
517
+ * @param chart
518
+ * @param pos 当前事件序列应当具有什么ID(用于报错和警告,外部调用可以写空字符串)
519
+ * @param endValue 结束值(RPEJSON没有)
520
+ * @returns
521
+ */
522
+ static fromRPEJSON<T extends EventType, VT extends EventValueESType = number>(type: T, data: EventDataRPELike<VT>[], chart: Chart, pos: string, endValue?: number) {
493
523
  const {templateEasingLib: templates} = chart
494
524
  const length = data.length;
495
525
  // const isSpeed = type === EventType.Speed;
@@ -507,6 +537,7 @@ export class EventNodeSequence<VT = number> { // 泛型的传染性这一块
507
537
  lastEnd = end;
508
538
  }
509
539
 
540
+ // 当前仅用于检查时间递增
510
541
  let lastEndTime: TimeT = [0, 0, 1];
511
542
 
512
543
  // 读取事件列表
@@ -551,7 +582,7 @@ export class EventNodeSequence<VT = number> { // 泛型的传染性这一块
551
582
  const last = lastEnd;
552
583
  const tail = new EventStartNode(
553
584
  last.type === NodeType.HEAD ? [0, 0, 1] : last.time,
554
- endValue ?? last.value
585
+ endValue ?? (last as EventEndNode<VT>).value
555
586
  );
556
587
  EventNode.connect(last, tail);
557
588
  // last can be a header, in which case easing is undefined.
@@ -565,12 +596,21 @@ export class EventNodeSequence<VT = number> { // 泛型的传染性这一块
565
596
  }
566
597
  return seq;
567
598
  }
599
+ /**
600
+ * 从KPAJSON 2.x数据创建一个事件序列。
601
+ * @param type 事件类型(不是数值类型,也不是数值ECMAScript类型)
602
+ * @param data 事件数据的数组
603
+ * @param chart
604
+ * @param pos 当前事件序列应当具有什么ID(用于报错和警告)
605
+ * @param finalNodeData 最终节点数据
606
+ * @returns
607
+ */
568
608
  static fromKPA2JSON<T extends EventType, VT extends EventValueESType = number>(
569
609
  type: T,
570
610
  data: EventDataKPA2<VT>[],
571
611
  chart: Chart,
572
612
  pos: string,
573
- endValue?: VT
613
+ finalNodeData: FinalEventStartNodeDataKPA2<VT>
574
614
  )
575
615
  {
576
616
  const length = data.length;
@@ -602,7 +642,7 @@ export class EventNodeSequence<VT = number> { // 泛型的传染性这一块
602
642
  let lastEndTime: TimeT = [0, 0, 1];
603
643
  for (let index = 0; index < length; index++) {
604
644
  const event = data[index];
605
- const [start, end] = chart.createEventFromData<VT>(event, valueType);
645
+ const [start, end] = chart.createEventFromData<VT>(event, valueType, `${pos}.events[${index}]`);
606
646
  // 从前面复制了,复用性减一
607
647
  // KPA2没有更改RPE的按事件存储的机制。
608
648
  if (TC.lt(event.startTime, lastEndTime)) { // event.startTime < lastEndTime
@@ -638,15 +678,25 @@ export class EventNodeSequence<VT = number> { // 泛型的传染性这一块
638
678
  lastEnd = end;
639
679
  }
640
680
  const last = lastEnd;
641
- const tail = new EventStartNode(
642
- last.type === NodeType.HEAD ? [0, 0, 1] : last.time,
643
- last.type === NodeType.HEAD ? endValue : last.value
681
+ const final = chart.createFinalEventStartNodeFromData(
682
+ finalNodeData || {
683
+ // @ts-expect-error 简化写法
684
+ start: last.value ?? this.getDefaultValueFromEventType(type),
685
+ // @ts-expect-error 极其边缘情况,finalNodeData只有在内测的谱面里面才可能为null,且last一般都有值
686
+ startTime: last.time,
687
+ evaluator: {
688
+ type: EvaluatorType.eased,
689
+ easing: {
690
+ type: EasingType.normal,
691
+ identifier: linearEasing.rpeId
692
+ }
693
+ }
694
+ } satisfies FinalEventStartNodeDataKPA2<any>,
695
+ valueType,
696
+ pos + ".finalNode"
644
697
  );
645
- EventNode.connect(last, tail);
646
- // last can be a header, in which case easing is undefined.
647
- // then we use the easing that initialized in the EventStartNode constructor.
648
- tail.evaluator = last.previous?.evaluator ?? tail.evaluator;
649
- EventNode.connect(tail, seq.tail)
698
+ EventNode.connect(last, final);
699
+ EventNode.connect(final, seq.tail)
650
700
  seq.listLength = listLength;
651
701
  seq.initJump();
652
702
  if (type === EventType.speed) {
@@ -711,7 +761,7 @@ export class EventNodeSequence<VT = number> { // 泛型的传染性这一块
711
761
  (node: EventStartNode<VT>, beats: number) => {
712
762
  return TC.toBeats((node.next as EventEndNode<VT>).time) > beats ? false : EventNode.nextStartInJumpArray(node)
713
763
  },
714
- (node: EventStartNode) => {
764
+ (node: AnyEN<VT>) => {
715
765
  return node.next && node.next.type === NodeType.TAIL ? node.next : node;
716
766
  }
717
767
  /*(node: EventStartNode) => {
@@ -767,6 +817,10 @@ export class EventNodeSequence<VT = number> { // 泛型的传染性这一块
767
817
  * @param this
768
818
  * @param node
769
819
  * @param tc
820
+ *
821
+ * @example
822
+ * node.value += 1;
823
+ * (node.parentSequence as SpeedENS).updateFloorPositionAfter(node, tc);
770
824
  */
771
825
  updateFloorPositionAfter(this: SpeedENS, node: EventStartNode, tc: TimeCalculator): void {
772
826
  let currentFP: number;
@@ -802,7 +856,7 @@ export class EventNodeSequence<VT = number> { // 泛型的传染性这一块
802
856
  type: this.type,
803
857
  events: nodes,
804
858
  id: this.id,
805
- endValue: currentNode.value
859
+ final: currentNode.dumpAsFinal()
806
860
  };
807
861
  }
808
862