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.
- package/.babelrc +5 -0
- package/index.ts +12 -0
- package/package.json +31 -0
- package/src/effectProcessor.ts +82 -0
- package/src/format.ts +69 -0
- package/src/parser/BufferParser.ts +102 -0
- package/src/parser/StringParser.ts +168 -0
- package/src/parser.ts +4 -0
- package/src/pathdata.ts +20 -0
- package/src/presets.ts +85 -0
- package/src/structure/Level.ts +351 -0
- package/src/structure/interfaces.ts +38 -0
- package/src/structure.ts +6 -0
- package/src/structure.ts.bak +412 -0
- package/test/editor.html +501 -0
- package/test/index.html +26 -0
- package/tsconfig.json +17 -0
- package/webpack.config.mjs +35 -0
|
@@ -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;
|