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/chartTypes.ts CHANGED
@@ -212,7 +212,8 @@ export type EasingDataKPA2 = NormalEasingData | TemplateEasingData | BezierEasin
212
212
 
213
213
  export enum EvaluatorType {
214
214
  eased,
215
- expressionbased
215
+ expressionbased,
216
+ macro
216
217
  }
217
218
 
218
219
  // Eased
@@ -237,14 +238,53 @@ export interface ExpressionEvaluatorDataKPA2 {
237
238
  jsExpr: string;
238
239
  }
239
240
 
241
+ export interface MacroEvaluatorDataKPA2 {
242
+ type: EvaluatorType.macro;
243
+ name: string;
244
+ compiled: string;
245
+ }
246
+
247
+
248
+ export type EvaluatorDataKPA2<T> = EasedEvaluatorDataOfType<T> | ExpressionEvaluatorDataKPA2 | MacroEvaluatorDataKPA2;
249
+
250
+ export type MacroData = [id: string, proto: number] | string;
251
+ export type MacroLink = [macroTypeAndId: `${'value' | 'time'}:${string}`, nodeId: number]
240
252
 
241
- export type EvaluatorDataKPA2<T> = EasedEvaluatorDataOfType<T> | ExpressionEvaluatorDataKPA2;
242
253
  export interface EventDataKPA2<T = number> {
254
+ /** 开始时间 */
243
255
  startTime: TimeT;
256
+ /** 结束时间 */
244
257
  endTime: TimeT;
258
+ /** 起始值 */
245
259
  start: T;
260
+ /** 终值 */
246
261
  end: T;
262
+ /** 求值器 */
247
263
  evaluator: EvaluatorDataKPA2<T>;
264
+ /** 终值绑定的宏的ID */
265
+ macroEnd?: MacroData;
266
+ /** 起始值绑定的宏的ID */
267
+ macroStart?: MacroData;
268
+ /** 起始时间绑定的宏的ID */
269
+ macroStartTime?: MacroData;
270
+ /** 将该事件的起始节点关联到一个宏的某个参数 */
271
+ startLinkedMacro?: MacroLink[];
272
+ endLinkedMacro?: MacroLink[];
273
+ }
274
+
275
+ export interface FinalEventStartNodeDataKPA2<T = number> {
276
+ /** 开始时间 */
277
+ startTime: TimeT;
278
+ /** 起始值 */
279
+ start: T;
280
+ /** 求值器 */
281
+ evaluator: EvaluatorDataKPA2<T>;
282
+ /** 起始值绑定的宏的ID */
283
+ macro?: MacroData;
284
+ /** 起始时间绑定的宏的ID */
285
+ macroTime?: MacroData;
286
+ /** 将该事件的起始节点关联到一个宏的某个参数 */
287
+ linkedMacro?: MacroLink[];
248
288
  }
249
289
 
250
290
  export enum EventValueType {
@@ -458,7 +498,7 @@ export interface EventNodeSequenceDataKPA2<VT> {
458
498
  events: EventDataKPA2<VT>[];
459
499
  id: string;
460
500
  type: EventType;
461
- endValue: VT;
501
+ final: FinalEventStartNodeDataKPA2<VT>;
462
502
  }
463
503
 
464
504
  export interface WrapperEasingBodyData {
@@ -468,6 +508,21 @@ export interface WrapperEasingBodyData {
468
508
  id: string;
469
509
  }
470
510
 
511
+ export interface MacroEvaluatorBodyData {
512
+ macro: string;
513
+ id: string;
514
+ }
515
+
516
+ export interface MacroTimeBodyData {
517
+ id: string;
518
+ macro: string;
519
+ parametric?: boolean;
520
+ }
521
+ export interface MacroValueBodyData {
522
+ id: string;
523
+ macro: string;
524
+ parametric?: boolean;
525
+ }
471
526
  export interface ChartDataKPA {
472
527
  version: number;
473
528
  offset: number;
@@ -499,6 +554,7 @@ export interface ChartDataKPA {
499
554
 
500
555
  export interface ChartDataKPA2 {
501
556
  version: number;
557
+ $schema: string;
502
558
  offset: number;
503
559
  duration: number;
504
560
  info: {
@@ -509,16 +565,19 @@ export interface ChartDataKPA2 {
509
565
  composer: string;
510
566
  };
511
567
  ui: {
512
- pause: number;
513
- combonumber: number;
514
- combo: number;
515
- score: number;
516
- bar: number;
517
- name: number;
518
- level: number;
568
+ pause?: number;
569
+ combonumber?: number;
570
+ combo?: number;
571
+ score?: number;
572
+ bar?: number;
573
+ name?: number;
574
+ level?: number;
519
575
  }
520
576
  templateEasings: TemplateEasingBodyData[];
521
- wrapperEasings: WrapperEasingBodyData[]
577
+ wrapperEasings: WrapperEasingBodyData[];
578
+ macroEvaluators: MacroEvaluatorBodyData[];
579
+ timeMacros: MacroTimeBodyData[];
580
+ valueMacros: MacroValueBodyData[];
522
581
  eventNodeSequences: EventNodeSequenceDataKPA2<unknown>[];
523
582
  orphanLines: JudgeLineDataKPA2[];
524
583
  bpmList: BPMSegmentData[];
package/easing.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { type TemplateEasingBodyData, type EasingDataKPA2, EasingType, EventType, type SegmentedEasingData, type NormalEasingData, type BezierEasingData, type TemplateEasingData, WrapperEasingData, WrapperEasingBodyData } from "./chartTypes";
2
2
  import { type EventNodeSequence } from "./event";
3
3
  import { type TupleCoord } from "./util";
4
- import Environment from "./env";
4
+ import Environment, { err } from "./env";
5
5
  import { type ExpressionEvaluator } from "./evaluator";
6
6
 
7
7
 
@@ -93,6 +93,40 @@ const easeInOutElastic = toEaseInOut(easeInElastic, easeOutElastic);
93
93
  const easeInOutBounce = toEaseInOut(easeInBounce, easeOutBounce);
94
94
 
95
95
 
96
+ export const easingFns = {
97
+ linear,
98
+ easeInSine,
99
+ easeOutSine,
100
+ easeInOutSine,
101
+ easeInQuad,
102
+ easeOutQuad,
103
+ easeInOutQuad,
104
+ easeInCubic,
105
+ easeOutCubic,
106
+ easeInOutCubic,
107
+ easeInQuart,
108
+ easeOutQuart,
109
+ easeInOutQuart,
110
+ easeInQuint,
111
+ easeOutQuint,
112
+ easeInOutQuint,
113
+ easeInExpo,
114
+ easeOutExpo,
115
+ easeInOutExpo,
116
+ easeInCirc,
117
+ easeOutCirc,
118
+ easeInOutCirc,
119
+ easeInBack,
120
+ easeOutBack,
121
+ easeInOutBack,
122
+ easeInElastic,
123
+ easeOutElastic,
124
+ easeInOutElastic,
125
+ easeInBounce,
126
+ easeOutBounce,
127
+ easeInOutBounce
128
+ }
129
+
96
130
  type FuncType = "linear" | "sine" | "quad" | "cubic" | "quart" | "quint" | "expo" | "circ" | "back" | "elastic" | "bounce"
97
131
 
98
132
  export const easingFnMap: {
@@ -185,11 +219,6 @@ export class NormalEasing extends Easing {
185
219
  this._getValue = fn;
186
220
  }
187
221
  getValue(t: number): number {
188
- if (t > 1 || t < 0) {
189
- console.warn("缓动超出定义域!")
190
- // debugger;
191
- }
192
- // console.log("t:", t, "rat", this._getValue(t))
193
222
  return this._getValue(t)
194
223
  }
195
224
  private dumpCache: NormalEasingData;
@@ -394,7 +423,7 @@ export class TemplateEasingLib {
394
423
  check() {
395
424
  for (const [name, easing] of this.easings) {
396
425
  if (!easing.eventNodeSequence) {
397
- console.warn(`未实现的缓动:${name}`);
426
+ err.UNIMPLEMENTED_TEMPLATE_EASING(name).warn();
398
427
  }
399
428
  }
400
429
  }
@@ -502,7 +531,7 @@ easingArray.forEach((easing, index) => {
502
531
  })
503
532
 
504
533
  export const rpeEasingArray = [
505
- null,
534
+ fixedEasing,
506
535
  linearEasing, // 1
507
536
  easingMap.sine.out, // 2
508
537
  easingMap.sine.in, // 3
package/env.ts CHANGED
@@ -14,6 +14,7 @@
14
14
 
15
15
  // 就挺神奇的!明明typeof后面跟值,这里却可以写成类型导入
16
16
  import { type TimeT, type EventValueType } from "./chartTypes";
17
+ import { EventNode } from "./event";
17
18
  import { toTimeString } from "./util";
18
19
 
19
20
  // occupied 1
@@ -33,6 +34,7 @@ const
33
34
  EASING = 0xA00,
34
35
  NOTE = 0xB00,
35
36
  TC = 0xC00,
37
+ MACRO = 0xD00,
36
38
  INTERNAL = 0xF00,
37
39
 
38
40
  OCCPIED = 0x10,
@@ -65,19 +67,30 @@ export enum ERROR_IDS {
65
67
  INVALID_EASING_ID = EASING | INVALID_DATA | 0,
66
68
  CANNOT_IMPLEMENT_TEMEAS_WITH_NON_EASING_ENS = EASING | INVALID_DATA | 1,
67
69
  CANNOT_IMPLEMENT_TEMEAS_WITH_NON_NUMERIC_ENS = EASING | INVALID_DATA | 2,
70
+ UNIMPLEMENTED_TEMPLATE_EASING = EASING | INVALID_DATA | 3,
68
71
  MUST_INTERPOLATE_TEMPLATE_EASING = EASING | INVALID_USAGE | 0,
69
72
  NODES_NOT_CONTINUOUS = EASING | INVALID_USAGE | 1,
70
73
  NODES_NOT_BELONG_TO_SAME_SEQUENCE = EASING | INVALID_USAGE | 2,
71
74
  NODES_HAS_ZERO_DELTA = EASING | INVALID_USAGE | 3,
72
75
 
73
76
  CANNOT_DIVIDE_EXPRESSION_EVALUATOR = EVALUATOR | INVALID_USAGE | 0,
77
+ MISSING_MACRO_EVALUATOR_KEY = EVALUATOR | INVALID_DATA | 0,
78
+ MACRO_EVALUATOR_NOT_FOUND = EVALUATOR | INVALID_DATA | 1,
74
79
 
75
80
 
76
81
 
77
82
  INVALID_NOTE_PROP_TYPE = NOTE | INVALID_TYPE | 0,
78
83
 
79
84
 
80
- INVALID_TIME_TUPLE = TC | INVALID_DATA | 0
85
+ INVALID_TIME_TUPLE = TC | INVALID_DATA | 0,
86
+
87
+ TIME_MACRO_NOT_FOUND = MACRO | INVALID_DATA | 0,
88
+ VALUE_MACRO_NOT_FOUND = MACRO | INVALID_DATA | 1,
89
+ UNKNOWN_MACRO_EXPRESSION = MACRO | INVALID_DATA | 2,
90
+ JAVASCRIPT_SYNTAX_ERROR = MACRO | INVALID_DATA | 3,
91
+ PROTO_PRESENT_IN_NONPARAMETRIC = MACRO | INVALID_USAGE | 0,
92
+ PARAMETRIC_MACRO_REQUIRES_PROTO_KEY = MACRO | INVALID_DATA | 4,
93
+ MACRO_NOT_PARAMETRIC = MACRO | INVALID_DATA | 5,
81
94
  }
82
95
 
83
96
  export const ERRORS = {
@@ -140,6 +153,28 @@ export const ERRORS = {
140
153
  CANNOT_DIVIDE_EXPRESSION_EVALUATOR: (id: string) =>
141
154
  `Cannot divide ExpressionEvaluator (Compiling ${id})`,
142
155
 
156
+
157
+ UNIMPLEMENTED_TEMPLATE_EASING: (temEasName: string) =>
158
+ `Unimplemented template easing: '${temEasName}'`,
159
+
160
+ MISSING_MACRO_EVALUATOR_KEY: (pos: string) =>
161
+ `Missing Macro Evaluator key. At ${pos}`,
162
+ MACRO_EVALUATOR_NOT_FOUND: (evaluatorId: string, pos: string) =>
163
+ `Macro Evaluator '${evaluatorId}' not found. At ${pos}`,
164
+ TIME_MACRO_NOT_FOUND: (macroId: string, pos: string) =>
165
+ `Time Macro '${macroId}' not found. At ${pos}`,
166
+ VALUE_MACRO_NOT_FOUND: (macroId: string, pos: string) =>
167
+ `Value Macro '${macroId}' not found. At ${pos}`,
168
+ UNKNOWN_MACRO_EXPRESSION: (expression: string, macroId: string) =>
169
+ `Unknown Macro Expression '${expression}'. At ${macroId}`,
170
+ PROTO_PRESENT_IN_NONPARAMETRIC: (macroId: string) =>
171
+ `'@proto can only be used in parametric Macros. At ${macroId}'`,
172
+ JAVASCRIPT_SYNTAX_ERROR: (error: Error, macroId: string) =>
173
+ `JavaScript Syntax Error: ${error.message}. At ${macroId}`,
174
+ PARAMETRIC_MACRO_REQUIRES_PROTO_KEY: (pos) =>
175
+ `Parametric Macro requires key. At ${pos}`,
176
+ MACRO_NOT_PARAMETRIC: (macroId: string, pos) =>
177
+ `Macro '${macroId}' is not parametric. At ${pos}`,
143
178
  } satisfies Record<keyof typeof ERROR_IDS, (...args: any[]) => string>
144
179
 
145
180
  export class KPAError<ET extends ERROR_IDS> extends Error {
package/evaluator.ts CHANGED
@@ -9,7 +9,10 @@ import {
9
9
  import TC from "./time";
10
10
 
11
11
  import type { EventEndNode, EventStartNode, NonLastStartNode } from "./event";
12
- import { EvaluatorType, InterpreteAs, type ColorEasedEvaluatorKPA2, type EvaluatorDataKPA2, type EventValueESType, type ExpressionEvaluatorDataKPA2, type NumericEasedEvaluatorKPA2, type RGB, type TextEasedEvaluatorKPA2 } from "./chartTypes";
12
+ import { EasingType, EvaluatorType, EventValueType, EventValueTypeOfType, InterpreteAs, MacroEvaluatorBodyData, MacroEvaluatorDataKPA2, type ColorEasedEvaluatorKPA2, type EvaluatorDataKPA2, type EventValueESType, type ExpressionEvaluatorDataKPA2, type NumericEasedEvaluatorKPA2, type RGB, type TextEasedEvaluatorKPA2 } from "./chartTypes";
13
+ import type { JudgeLine } from "./judgeline";
14
+ import { Chart } from "./chart";
15
+ import { EVENT_MACROS } from "./macro";
13
16
 
14
17
 
15
18
  /// #declaration:global
@@ -23,9 +26,9 @@ import { EvaluatorType, InterpreteAs, type ColorEasedEvaluatorKPA2, type Evaluat
23
26
  * @immutable
24
27
  * @since 2.0.0
25
28
  */
26
- export abstract class Evaluator<T> {
27
- abstract eval(event: EventStartNode<T>, beats: number): T;
28
- abstract dump(): EvaluatorDataKPA2<T>;
29
+ export abstract class Evaluator<T extends EventValueESType> {
30
+ abstract eval(event: NonLastStartNode<T>, beats: number): T;
31
+ abstract dumpFor(node: EventStartNode<T>): EvaluatorDataKPA2<T>;
29
32
  }
30
33
 
31
34
 
@@ -54,6 +57,24 @@ export abstract class EasedEvaluator<T extends EventValueESType> extends Evaluat
54
57
  * @returns
55
58
  */
56
59
  abstract deriveWithEasing(easing: Easing): EasedEvaluator<T>;
60
+
61
+ static getEvaluatorFromEasing<T extends EventValueESType>(type: EventValueTypeOfType<T>, easing: Easing, interpretedAs?: InterpreteAs): EasedEvaluatorOfType<T> {
62
+ const easingIsNormal = easing instanceof NormalEasing;
63
+ switch (type) {
64
+ case EventValueType.numeric:
65
+ return easingIsNormal
66
+ ? NumericEasedEvaluator.evaluatorsOfNormalEasing[easing.rpeId] as EasedEvaluatorOfType<T>
67
+ : new NumericEasedEvaluator(easing) as EasedEvaluatorOfType<T>;
68
+ case EventValueType.color:
69
+ return easingIsNormal
70
+ ? ColorEasedEvaluator.evaluatorsOfNormalEasing[easing.rpeId] as EasedEvaluatorOfType<T>
71
+ : new ColorEasedEvaluator(easing) as EasedEvaluatorOfType<T>;
72
+ case EventValueType.text:
73
+ return easingIsNormal
74
+ ? TextEasedEvaluator.evaluatorsOfNoEzAndItpAs[easing.rpeId][interpretedAs ?? InterpreteAs.str] as EasedEvaluatorOfType<T>
75
+ : new TextEasedEvaluator(easing, interpretedAs) as EasedEvaluatorOfType<T>
76
+ }
77
+ }
57
78
  }
58
79
 
59
80
  export type EasedEvaluatorOfType<T extends EventValueESType> = T extends number ? NumericEasedEvaluator : T extends RGB ? ColorEasedEvaluator : TextEasedEvaluator;
@@ -64,7 +85,7 @@ export class NumericEasedEvaluator extends EasedEvaluator<number> {
64
85
  super(easing);
65
86
  }
66
87
  private cache?: NumericEasedEvaluatorKPA2
67
- override dump(): NumericEasedEvaluatorKPA2 {
88
+ override dumpFor(): NumericEasedEvaluatorKPA2 {
68
89
  return this.cache ??= {
69
90
  type: EvaluatorType.eased,
70
91
  easing: this.easing.dump()
@@ -88,7 +109,7 @@ export class ColorEasedEvaluator extends EasedEvaluator<RGB> {
88
109
  constructor(easing: Easing) {
89
110
  super(easing);
90
111
  }
91
- override dump(): ColorEasedEvaluatorKPA2 {
112
+ override dumpFor(): ColorEasedEvaluatorKPA2 {
92
113
  return {
93
114
  type: EvaluatorType.eased,
94
115
  easing: this.easing.dump()
@@ -126,7 +147,7 @@ export class TextEasedEvaluator extends EasedEvaluator<string> {
126
147
  {
127
148
  super(easing);
128
149
  }
129
- override dump(): TextEasedEvaluatorKPA2 {
150
+ override dumpFor(): TextEasedEvaluatorKPA2 {
130
151
  return {
131
152
  type: EvaluatorType.eased,
132
153
  easing: this.easing.dump(),
@@ -174,19 +195,60 @@ export class TextEasedEvaluator extends EasedEvaluator<string> {
174
195
  }
175
196
  }
176
197
 
177
- export class ExpressionEvaluator<T> extends Evaluator<T> {
198
+
199
+
200
+ export class MacroEvaluator<T extends EventValueESType> extends Evaluator<T> {
201
+ readonly consumers: Map<EventStartNode<T>, ExpressionEvaluator<T>> = new Map();
202
+ constructor(public expression: string, public id: string) {
203
+ super();
204
+ }
205
+ compile(node: EventStartNode<T>, chart: Chart): ExpressionEvaluator<T> {
206
+ const jsExpr = this.expression
207
+ .replace(/@([a-z\.]+)/, (k) => {
208
+ return JSON.stringify(EVENT_MACROS[k](node, chart)) + " "
209
+ }).replace(/@\{\{(.+?)\}\}/g, (k) => {
210
+ const replaced = k.replace(new RegExp(Object.keys(EVENT_MACROS).join("|"), "g"), (k) => {
211
+ return JSON.stringify(EVENT_MACROS[k](node, chart)) + " "
212
+ });
213
+ return JSON.stringify(new Function("return " + replaced)()) + " ";
214
+ });
215
+ return new ExpressionEvaluator(jsExpr);
216
+ }
217
+ assignTo(node: EventStartNode<T>, chart: Chart): void {
218
+ node.evaluator = this;
219
+ this.consumers.set(node, this.compile(node, chart));
220
+ }
221
+ eval(event: NonLastStartNode<T>, beats: number): T {
222
+ return this.consumers.get(event)!.eval(event, beats);
223
+ }
224
+ dumpFor(node: EventStartNode<T>): MacroEvaluatorDataKPA2 {
225
+ return {
226
+ type: EvaluatorType.macro,
227
+ name: this.id,
228
+ compiled: this.consumers.get(node)!.jsExpr
229
+ }
230
+ }
231
+ dumpContent(): MacroEvaluatorBodyData {
232
+ return {
233
+ id: this.id,
234
+ macro: this.expression
235
+ }
236
+ }
237
+ }
238
+
239
+ export class ExpressionEvaluator<T extends EventValueESType> extends Evaluator<T> {
178
240
  readonly func: (t: number) => T;
179
241
  constructor(public readonly jsExpr: string) {
180
242
  super();
181
243
  this.func = new Function("t", "return " + jsExpr) as (t: number) => T;
182
244
  }
183
- override eval(startNode: EventStartNode<T> & { next: EventEndNode }, beats: number): T {
245
+ override eval(startNode: NonLastStartNode<T>, beats: number): T {
184
246
  const next = startNode.next;
185
247
  const timeDelta = TC.getDelta(next.time, startNode.time)
186
248
  const current = beats - TC.toBeats(startNode.time)
187
249
  return this.func(current / timeDelta);
188
250
  }
189
- override dump(): ExpressionEvaluatorDataKPA2 {
251
+ override dumpFor(): ExpressionEvaluatorDataKPA2 {
190
252
  return {
191
253
  type: EvaluatorType.expressionbased,
192
254
  jsExpr: this.jsExpr