adofai 2.9.7

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.
@@ -0,0 +1,412 @@
1
+ interface AdofaiEvent {
2
+ eventType: string;
3
+ [key: string]: any;
4
+ }
5
+
6
+ interface LevelOptions {
7
+ pathData: string;
8
+ angleData: number[];
9
+ actions: AdofaiEvent[];
10
+ settings: Record<string, any>;
11
+ decorations: AdofaiEvent[];
12
+ [key: string]: any;
13
+ }
14
+
15
+ interface EventCallback {
16
+ guid: string;
17
+ callback: Function;
18
+ }
19
+
20
+ interface GuidCallback {
21
+ eventName: string;
22
+ callback: Function;
23
+ }
24
+
25
+ interface Tile {
26
+ direction?: number;
27
+ angle?: number;
28
+ actions: AdofaiEvent[];
29
+ addDecorations?: AdofaiEvent[];
30
+ _lastdir?: number;
31
+ twirl?: number;
32
+ position?: number[];
33
+ extraProps?: Record<string, any>;
34
+ }
35
+
36
+ interface ParseProvider {
37
+ parse(t: string): LevelOptions;
38
+ }
39
+ class Level {
40
+ private _events: Map<string, EventCallback[]>;
41
+ private guidCallbacks: Map<string, GuidCallback>;
42
+ private guidCounter: number;
43
+ private _options: string | LevelOptions;
44
+ private _provider?: ParseProvider;
45
+ public angleData!: number[];
46
+ public actions!: AdofaiEvent[];
47
+ public settings!: Record<string, any>;
48
+ public __decorations!: AdofaiEvent[];
49
+ public tiles!: Tile[];
50
+ private _angleDir!: number;
51
+ private _twirlCount!: number;
52
+
53
+ constructor(opt: string | LevelOptions, provider?: ParseProvider) {
54
+ this._events = new Map();
55
+ this.guidCallbacks = new Map();
56
+ this.guidCounter = 0;
57
+
58
+ this._options = opt;
59
+ this._provider = provider;
60
+ }
61
+
62
+ generateGUID(): string {
63
+ return `event_${Date.now()}_${this.guidCounter++}_${Math.floor(Math.random() * 1000)}`;
64
+ }
65
+
66
+ load(): Promise<boolean> {
67
+ return new Promise((resolve, reject) => {
68
+ let opt = this._options;
69
+ let options: LevelOptions;
70
+
71
+ switch (typeof opt) {
72
+ case 'string':
73
+ try {
74
+ options = Parser.parseAsObject(opt, this._provider)
75
+ } catch (e) {
76
+ reject(e);
77
+ return;
78
+ }
79
+ break;
80
+ case 'object':
81
+ options = Object.assign({}, opt);
82
+ break;
83
+ default:
84
+ reject("Options must be String or Object");
85
+ return;
86
+ }
87
+ if ('pathData' in options) {
88
+ this.angleData = pathData.parseToangleData(options['pathData']!);
89
+ } else {
90
+ if ('angleData' in options) {
91
+ this.angleData = options['angleData']!;
92
+ } else {
93
+ reject("There is not any angle datas.");
94
+ return;
95
+ }
96
+ }
97
+ if ('actions' in options) {
98
+ this.actions = options['actions']!;
99
+ } else {
100
+ this.actions = [];
101
+ }
102
+ if ('settings' in options) {
103
+ this.settings = options['settings']!;
104
+ } else {
105
+ reject("There is no ADOFAI settings.");
106
+ return;
107
+ }
108
+ if ('decorations' in options) {
109
+ this.__decorations = options['decorations']!;
110
+ } else {
111
+ this.__decorations = [];
112
+ }
113
+ this.tiles = [];
114
+ this._angleDir = -180;
115
+ this._twirlCount = 0;
116
+ this._createArray(this.angleData.length, { angleData: this.angleData, actions: this.actions, decorations: this.__decorations })
117
+ .then(e => {
118
+ this.tiles = e;
119
+ this.trigger('load', this);
120
+ resolve(true);
121
+ }).catch(e => {
122
+ reject(e);
123
+ });
124
+
125
+ });
126
+
127
+ }
128
+
129
+ /**
130
+ * @param {string} eventName EventName
131
+ * @param {function} callback Callback
132
+ * @returns {string} only GUID
133
+ */
134
+ on(eventName: string, callback: Function): string {
135
+ if (!this._events.has(eventName)) {
136
+ this._events.set(eventName, []);
137
+ }
138
+
139
+ const guid = this.generateGUID();
140
+ const eventCallbacks = this._events.get(eventName)!;
141
+
142
+ eventCallbacks.push({ guid, callback });
143
+ this.guidCallbacks.set(guid, { eventName, callback });
144
+
145
+ return guid;
146
+ }
147
+
148
+ /**
149
+ * @param {string} eventName EventName
150
+ * @param {any} data Data
151
+ */
152
+ trigger(eventName: string, data: any): void {
153
+ if (!this._events.has(eventName)) return;
154
+
155
+ const callbacks = this._events.get(eventName)!;
156
+ callbacks.forEach(({ callback }) => callback(data));
157
+ }
158
+
159
+ /**
160
+ * @param {string} guid GUID
161
+ */
162
+ off(guid: string): void {
163
+ if (!this.guidCallbacks.has(guid)) return;
164
+
165
+ const { eventName } = this.guidCallbacks.get(guid)!;
166
+ this.guidCallbacks.delete(guid);
167
+
168
+ if (!this._events.has(eventName)) return;
169
+
170
+ const callbacks = this._events.get(eventName)!;
171
+ const index = callbacks.findIndex(cb => cb.guid === guid);
172
+
173
+ if (index !== -1) {
174
+ callbacks.splice(index, 1);
175
+ }
176
+ }
177
+
178
+ // Placeholder for other methods that would be in the Level class
179
+ private _filterByFloor(arr: AdofaiEvent[], i: number): AdofaiEvent[] {
180
+ let actionT = arr.filter(item => item.floor === i);
181
+ this._twirlCount += actionT.filter(t => t.eventType === 'Twirl').length;
182
+ return actionT.map(({ floor, ...rest }) => rest);
183
+ }
184
+
185
+ private _filterByFloorwithDeco(arr: AdofaiEvent[], i: number): AdofaiEvent[] {
186
+ let actionT = arr.filter(item => item.floor === i);
187
+ return actionT.map(({ floor, ...rest }) => rest);
188
+ }
189
+
190
+ private async _createArray(xLength: number, opt: { angleData: number[], actions: AdofaiEvent[], decorations: AdofaiEvent[] }): Promise<Tile[]> {
191
+ let m = Array.from({ length: xLength }, (_, i) => ({
192
+ direction: opt.angleData[i],
193
+ _lastdir: opt.angleData[i - 1] || 0,
194
+ actions: this._filterByFloor(opt.actions, i),
195
+ angle: this._parseAngle(opt.angleData, i, this._twirlCount % 2),
196
+ addDecorations: this._filterByFloorwithDeco(opt.decorations, i),
197
+ twirl: this._twirlCount,
198
+ extraProps: {}
199
+ }));
200
+ return m;
201
+ }
202
+
203
+ private _changeAngle(): Tile[] {
204
+ let y = 0;
205
+ let m = this.tiles.map(t => {
206
+ y++;
207
+ t.angle = this._parsechangedAngle(t.direction!, y, t.twirl!, t._lastdir!);
208
+ return t;
209
+ });
210
+ return m;
211
+ }
212
+
213
+ private _parsechangedAngle(agd: number, i: number, isTwirl: number, lstagd: number): number {
214
+ let prev = 0;
215
+ if (i === 0) { this._angleDir = 180; }
216
+ if (agd === 999) {
217
+ this._angleDir = lstagd;
218
+ if (isNaN(this._angleDir)) {
219
+ this._angleDir = 0;
220
+ }
221
+ prev = 0;
222
+ } else {
223
+ if (isTwirl === 0) {
224
+ prev = (this._angleDir - agd) % 360;
225
+ } else {
226
+ prev = 360 - (this._angleDir - agd) % 360;
227
+ }
228
+ if (prev === 0) {
229
+ prev = 360;
230
+ }
231
+ this._angleDir = agd + 180;
232
+ }
233
+ return prev;
234
+ }
235
+
236
+ private _parseAngle(agd: number[], i: number, isTwirl: number): number {
237
+ let prev = 0;
238
+ if (i === 0) { this._angleDir = 180; }
239
+ if (agd[i] === 999) {
240
+ this._angleDir = agd[i - 1];
241
+ if (isNaN(this._angleDir)) {
242
+ this._angleDir = 0;
243
+ }
244
+ prev = 0;
245
+ } else {
246
+ if (isTwirl === 0) {
247
+ prev = (this._angleDir - agd[i]) % 360;
248
+ } else {
249
+ prev = 360 - (this._angleDir - agd[i]) % 360;
250
+ }
251
+ if (prev === 0) {
252
+ prev = 360;
253
+ }
254
+ this._angleDir = agd[i] + 180;
255
+ }
256
+ return prev;
257
+ }
258
+
259
+ private _flattenActionsWithFloor(arr: Tile[]): AdofaiEvent[] {
260
+ return arr.flatMap((item, index) =>
261
+ (item.actions || []).map(action => ({
262
+ floor: index,
263
+ ...action,
264
+ }))
265
+ );
266
+ }
267
+
268
+ private _flattenAngleDatas(arr: Tile[]): number[] {
269
+ return arr.map(item => item.direction!);
270
+ }
271
+
272
+ private _flattenDecorationsWithFloor(arr: Tile[]): AdofaiEvent[] {
273
+ return arr.flatMap((item, index) =>
274
+ (item.addDecorations || []).map(addDecorations => ({
275
+ floor: index,
276
+ ...addDecorations,
277
+ }))
278
+ );
279
+ }
280
+
281
+ public filterActionsByEventType(en: string): { index: number, action: AdofaiEvent }[] {
282
+ return Object.entries(this.tiles)
283
+ .flatMap(([index, a]) =>
284
+ (a.actions || []).map(b => ({ b, index }))
285
+ )
286
+ .filter(({ b }) => b.eventType === en)
287
+ .map(({ b, index }) => ({
288
+ index: Number(index),
289
+ action: b
290
+ }));
291
+ }
292
+
293
+ public calculateTileCoordinates(): void {
294
+ let angles = this.angleData;
295
+ let floats: number[] = [];
296
+ let startPos = [0, 0];
297
+
298
+ for (let i = 0; i < this.tiles.length; i++) {
299
+ let value = angles[i];
300
+ if (value === 999) {
301
+ value = angles[i - 1] + 180;
302
+ }
303
+ floats.push(value);
304
+ }
305
+
306
+ for (let i = 0; i <= floats.length; i++) {
307
+ let angle1 = Number((i === floats.length) ? floats[i - 1] : floats[i]) || 0;
308
+ let angle2 = Number((i === 0) ? 0 : floats[i - 1]) || 0;
309
+ let currentTile = this.tiles[i];
310
+ if (this.getActionsByIndex('PositionTrack', i).count > 0) {
311
+ let pevent = this.getActionsByIndex('PositionTrack', i).actions[0];
312
+ if ('positionOffset' in pevent) {
313
+ if (pevent['editorOnly'] !== true && pevent['editorOnly'] !== 'Enabled') {
314
+ startPos[0] += pevent['positionOffset'][0];
315
+ startPos[1] += pevent['positionOffset'][1];
316
+ }
317
+ }
318
+ }
319
+ startPos[0] += Math.cos(angle1 * Math.PI / 180);
320
+ startPos[1] += Math.sin(angle1 * Math.PI / 180);
321
+ if (typeof currentTile !== 'undefined') {
322
+ currentTile.position = [
323
+ Number(startPos[0].toFixed(8)),
324
+ Number(startPos[1].toFixed(8))
325
+ ];
326
+ currentTile.extraProps!.angle1 = angle1;
327
+ currentTile.extraProps!.angle2 = angle2 - 180;
328
+ currentTile.extraProps!.cangle = i === floats.length ? floats[i - 1] + 180 : floats[i];
329
+ }
330
+ }
331
+ }
332
+
333
+ public getActionsByIndex(en: string, index: number): { count: number, actions: AdofaiEvent[] } {
334
+ const filtered = this.filterActionsByEventType(en);
335
+ const matches = filtered.filter(item => item.index === index);
336
+
337
+ return {
338
+ count: matches.length,
339
+ actions: matches.map(item => item.action)
340
+ };
341
+ }
342
+
343
+ public floorOperation(info: { type: 'append' | 'insert' | 'delete', direction: number, id?: number } = { type: 'append', direction: 0 }): void {
344
+ switch (info.type) {
345
+ case 'append':
346
+ this.appendFloor(info);
347
+ break;
348
+ case 'insert':
349
+ if (typeof info.id === 'number') {
350
+ this.tiles.splice(info.id, 0, {
351
+ direction: info.direction || 0,
352
+ angle: 0,
353
+ actions: [],
354
+ addDecorations: [],
355
+ _lastdir: this.tiles[info.id - 1].direction,
356
+ twirl: this.tiles[info.id - 1].twirl
357
+ });
358
+ }
359
+ break;
360
+ case 'delete':
361
+ if (typeof info.id === 'number') {
362
+ this.tiles.splice(info.id, 1);
363
+ }
364
+ break;
365
+ }
366
+ this._changeAngle();
367
+ }
368
+
369
+ public appendFloor(args: { direction: number }): void {
370
+ this.tiles.push({
371
+ direction: args.direction,
372
+ angle: 0,
373
+ actions: [],
374
+ addDecorations: [],
375
+ _lastdir: this.tiles[this.tiles.length - 1].direction,
376
+ twirl: this.tiles[this.tiles.length - 1].twirl
377
+ });
378
+ this._changeAngle();
379
+ }
380
+
381
+ public clearDeco(): boolean {
382
+ this.tiles = effectProcessor.clearDecorations(this.tiles) as Tile[];
383
+ return true;
384
+ }
385
+
386
+ public clearEffect(presetName: string): void {
387
+ this.clearEvent(presets[presetName as keyof typeof presets]);
388
+ }
389
+
390
+ public clearEvent(preset: { type: string, events: string[] }): void {
391
+ switch (preset.type) {
392
+ case 'include':
393
+ this.tiles = effectProcessor.keepEvents(preset.events, this.tiles) as Tile[];
394
+ break;
395
+ case 'exclude':
396
+ this.tiles = effectProcessor.clearEvents(preset.events, this.tiles) as Tile[];
397
+ break;
398
+ }
399
+ }
400
+
401
+ public export(type: 'string' | 'object', indent?: number, useAdofaiStyle: boolean = true): string | Record<string, any> {
402
+ const ADOFAI = {
403
+ angleData: this._flattenAngleDatas(this.tiles),
404
+ settings: this.settings,
405
+ actions: this._flattenActionsWithFloor(this.tiles),
406
+ decorations: this._flattenDecorationsWithFloor(this.tiles)
407
+ };
408
+ return type === 'object' ? ADOFAI : customFormatJSON(ADOFAI, indent, useAdofaiStyle);
409
+ }
410
+ }
411
+
412
+ export default Level;