adofai 3.2.0 → 3.3.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/README.md +423 -51
- package/dist/src/pathdata/index.d.ts +1 -4
- package/dist/src/pathdata/index.js +45 -2
- package/dist/src/structure/Level.d.ts +0 -65
- package/dist/src/structure/Level.js +23 -395
- package/dist/src/structure/levelAngle.d.ts +40 -0
- package/dist/src/structure/levelAngle.js +316 -0
- package/dist/umd/index.js +1 -1
- package/package.json +1 -1
|
@@ -10,8 +10,6 @@ export declare class Level {
|
|
|
10
10
|
settings: Record<string, any>;
|
|
11
11
|
__decorations: AdofaiEvent[];
|
|
12
12
|
tiles: Tile[];
|
|
13
|
-
private _angleDir;
|
|
14
|
-
private _twirlCount;
|
|
15
13
|
/** 预计算的事件缓存 */
|
|
16
14
|
private _precomputedEvents;
|
|
17
15
|
/** 是否启用预计算模式 */
|
|
@@ -20,68 +18,21 @@ export declare class Level {
|
|
|
20
18
|
private _lightweightData;
|
|
21
19
|
constructor(opt: string | LevelOptions, provider?: ParseProvider);
|
|
22
20
|
generateGUID(): string;
|
|
23
|
-
/**
|
|
24
|
-
* 触发进度事件
|
|
25
|
-
*/
|
|
26
21
|
private _emitProgress;
|
|
27
|
-
/**
|
|
28
|
-
* 启用预计算模式 - 在 load() 和 calculateTilePosition() 过程中不触发事件,
|
|
29
|
-
* 而是将所有事件缓存起来,之后可以通过 getPrecomputedEvents() 获取
|
|
30
|
-
*/
|
|
31
22
|
enablePrecomputeMode(): void;
|
|
32
|
-
/**
|
|
33
|
-
* 禁用预计算模式
|
|
34
|
-
*/
|
|
35
23
|
disablePrecomputeMode(): void;
|
|
36
|
-
/**
|
|
37
|
-
* 获取预计算的事件缓存
|
|
38
|
-
* 返回所有缓存的进度事件,可以用于渲染器按帧播放
|
|
39
|
-
*/
|
|
40
24
|
getPrecomputedEvents(): PrecomputedProgressEvents | null;
|
|
41
|
-
/**
|
|
42
|
-
* 清除预计算的事件缓存
|
|
43
|
-
*/
|
|
44
25
|
clearPrecomputedEvents(): void;
|
|
45
|
-
/**
|
|
46
|
-
* 按进度百分比获取事件(用于渲染器按帧渲染)
|
|
47
|
-
* @param percent 0-100 的百分比
|
|
48
|
-
* @param stage 可选,指定阶段
|
|
49
|
-
*/
|
|
50
26
|
getEventsAtPercent(percent: number, stage?: ParseProgressEvent['stage']): ParseProgressEvent[];
|
|
51
|
-
/**
|
|
52
|
-
* 获取指定阶段的总事件数
|
|
53
|
-
*/
|
|
54
27
|
getPrecomputedEventCount(stage?: ParseProgressEvent['stage']): number;
|
|
55
|
-
/**
|
|
56
|
-
* 获取轻量级预计算数据
|
|
57
|
-
* 只包含渲染必需的数据:angles, positions, twirlFlags
|
|
58
|
-
* 内存占用极低,适合大物量谱面
|
|
59
|
-
*/
|
|
60
28
|
getLightweightData(): LightweightPrecomputedData | null;
|
|
61
|
-
/**
|
|
62
|
-
* 轻量级预计算 - 只计算渲染必需的数据
|
|
63
|
-
* 不存储完整的 tile 对象,极大减少内存占用
|
|
64
|
-
*
|
|
65
|
-
* @param skipPositionCalculation 是否跳过坐标计算(如果只需要角度数据)
|
|
66
|
-
*/
|
|
67
29
|
precomputeLightweight(skipPositionCalculation?: boolean): LightweightPrecomputedData;
|
|
68
|
-
/**
|
|
69
|
-
* 获取指定范围内的轻量级渲染数据(分片获取,避免一次性加载全部)
|
|
70
|
-
* @param startIndex 起始索引
|
|
71
|
-
* @param count 数量
|
|
72
|
-
*/
|
|
73
30
|
getLightweightDataRange(startIndex: number, count: number): {
|
|
74
31
|
angles: number[];
|
|
75
32
|
positions: [number, number][];
|
|
76
33
|
twirlFlags: boolean[];
|
|
77
34
|
} | null;
|
|
78
|
-
/**
|
|
79
|
-
* 清除轻量级预计算数据
|
|
80
|
-
*/
|
|
81
35
|
clearLightweightData(): void;
|
|
82
|
-
/**
|
|
83
|
-
* 获取单个 tile 的渲染数据(按需获取,不预加载全部)
|
|
84
|
-
*/
|
|
85
36
|
getTileRenderData(index: number): {
|
|
86
37
|
angle: number;
|
|
87
38
|
position: [number, number] | null;
|
|
@@ -91,16 +42,6 @@ export declare class Level {
|
|
|
91
42
|
on(eventName: string, callback: Function): string;
|
|
92
43
|
trigger(eventName: string, data: any): void;
|
|
93
44
|
off(guid: string): void;
|
|
94
|
-
private _createArray;
|
|
95
|
-
private _changeAngle;
|
|
96
|
-
private _normalizeAngle;
|
|
97
|
-
private _parsechangedAngle;
|
|
98
|
-
private _filterByFloor;
|
|
99
|
-
private _flattenAngleDatas;
|
|
100
|
-
private _flattenActionsWithFloor;
|
|
101
|
-
private _filterByFloorwithDeco;
|
|
102
|
-
private _flattenDecorationsWithFloor;
|
|
103
|
-
private _parseAngle;
|
|
104
45
|
filterActionsByEventType(en: string): {
|
|
105
46
|
index: number;
|
|
106
47
|
action: ActionData;
|
|
@@ -110,12 +51,6 @@ export declare class Level {
|
|
|
110
51
|
actions: ActionData[];
|
|
111
52
|
};
|
|
112
53
|
calculateTileCoordinates(): void;
|
|
113
|
-
/**
|
|
114
|
-
* 计算所有 Tile 的坐标位置
|
|
115
|
-
* 触发 parse:tilePosition 和 parse:progress 事件报告进度
|
|
116
|
-
*
|
|
117
|
-
* 性能优化:预先构建 PositionTrack 索引,避免循环内重复遍历
|
|
118
|
-
*/
|
|
119
54
|
calculateTilePosition(): number[][];
|
|
120
55
|
floorOperation(info?: {
|
|
121
56
|
type: 'append' | 'insert' | 'delete';
|
|
@@ -1,27 +1,9 @@
|
|
|
1
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
-
});
|
|
9
|
-
};
|
|
10
|
-
var __rest = (this && this.__rest) || function (s, e) {
|
|
11
|
-
var t = {};
|
|
12
|
-
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
13
|
-
t[p] = s[p];
|
|
14
|
-
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
|
15
|
-
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
16
|
-
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
|
17
|
-
t[p[i]] = s[p[i]];
|
|
18
|
-
}
|
|
19
|
-
return t;
|
|
20
|
-
};
|
|
21
1
|
import pathData from '../pathdata';
|
|
22
2
|
import exportAsADOFAI from './format';
|
|
23
3
|
import effectProcessor from '../filter/effectProcessor';
|
|
24
4
|
import { EffectCleanerType } from '../filter/effectProcessor';
|
|
5
|
+
import * as presets from '../filter/presets';
|
|
6
|
+
import { createTiles, changeAngles, filterActionsByEventType as filterActions, getActionsByIndex as getActions, calculateTilePositions, precomputePositions, flattenAngleDatas, flattenActionsWithFloor, flattenDecorationsWithFloor } from './levelAngle';
|
|
25
7
|
function uuid() {
|
|
26
8
|
var _a;
|
|
27
9
|
const r = new Uint8Array(16);
|
|
@@ -42,7 +24,6 @@ function uuid() {
|
|
|
42
24
|
+ h(r[8]) + h(r[9]) + '-'
|
|
43
25
|
+ h(r[10]) + h(r[11]) + h(r[12]) + h(r[13]) + h(r[14]) + h(r[15]);
|
|
44
26
|
}
|
|
45
|
-
import * as presets from '../filter/presets';
|
|
46
27
|
export class Level {
|
|
47
28
|
constructor(opt, provider) {
|
|
48
29
|
/** 预计算的事件缓存 */
|
|
@@ -59,9 +40,6 @@ export class Level {
|
|
|
59
40
|
generateGUID() {
|
|
60
41
|
return `event_${uuid()}`;
|
|
61
42
|
}
|
|
62
|
-
/**
|
|
63
|
-
* 触发进度事件
|
|
64
|
-
*/
|
|
65
43
|
_emitProgress(stage, current, total, data) {
|
|
66
44
|
const progressEvent = {
|
|
67
45
|
stage,
|
|
@@ -70,7 +48,6 @@ export class Level {
|
|
|
70
48
|
percent: total > 0 ? Math.round((current / total) * 100) : 0,
|
|
71
49
|
data
|
|
72
50
|
};
|
|
73
|
-
// 如果是预计算模式,存储事件而不是触发
|
|
74
51
|
if (this._precomputeMode && this._precomputedEvents) {
|
|
75
52
|
this._precomputedEvents[stage].push(progressEvent);
|
|
76
53
|
}
|
|
@@ -79,10 +56,6 @@ export class Level {
|
|
|
79
56
|
this.trigger(`parse:${stage}`, progressEvent);
|
|
80
57
|
}
|
|
81
58
|
}
|
|
82
|
-
/**
|
|
83
|
-
* 启用预计算模式 - 在 load() 和 calculateTilePosition() 过程中不触发事件,
|
|
84
|
-
* 而是将所有事件缓存起来,之后可以通过 getPrecomputedEvents() 获取
|
|
85
|
-
*/
|
|
86
59
|
enablePrecomputeMode() {
|
|
87
60
|
this._precomputeMode = true;
|
|
88
61
|
this._precomputedEvents = {
|
|
@@ -94,30 +67,15 @@ export class Level {
|
|
|
94
67
|
complete: []
|
|
95
68
|
};
|
|
96
69
|
}
|
|
97
|
-
/**
|
|
98
|
-
* 禁用预计算模式
|
|
99
|
-
*/
|
|
100
70
|
disablePrecomputeMode() {
|
|
101
71
|
this._precomputeMode = false;
|
|
102
72
|
}
|
|
103
|
-
/**
|
|
104
|
-
* 获取预计算的事件缓存
|
|
105
|
-
* 返回所有缓存的进度事件,可以用于渲染器按帧播放
|
|
106
|
-
*/
|
|
107
73
|
getPrecomputedEvents() {
|
|
108
74
|
return this._precomputedEvents;
|
|
109
75
|
}
|
|
110
|
-
/**
|
|
111
|
-
* 清除预计算的事件缓存
|
|
112
|
-
*/
|
|
113
76
|
clearPrecomputedEvents() {
|
|
114
77
|
this._precomputedEvents = null;
|
|
115
78
|
}
|
|
116
|
-
/**
|
|
117
|
-
* 按进度百分比获取事件(用于渲染器按帧渲染)
|
|
118
|
-
* @param percent 0-100 的百分比
|
|
119
|
-
* @param stage 可选,指定阶段
|
|
120
|
-
*/
|
|
121
79
|
getEventsAtPercent(percent, stage) {
|
|
122
80
|
if (!this._precomputedEvents)
|
|
123
81
|
return [];
|
|
@@ -127,9 +85,7 @@ export class Level {
|
|
|
127
85
|
const events = this._precomputedEvents[s];
|
|
128
86
|
for (const event of events) {
|
|
129
87
|
if (event.percent <= percent) {
|
|
130
|
-
// 获取不超过目标百分比的最后一个事件
|
|
131
88
|
if (result.length === 0 || result[result.length - 1].percent <= event.percent) {
|
|
132
|
-
// 避免重复添加相同百分比的事件
|
|
133
89
|
const lastEvent = result[result.length - 1];
|
|
134
90
|
if (!lastEvent || lastEvent.stage !== event.stage || lastEvent.current !== event.current) {
|
|
135
91
|
result.push(event);
|
|
@@ -140,81 +96,31 @@ export class Level {
|
|
|
140
96
|
}
|
|
141
97
|
return result;
|
|
142
98
|
}
|
|
143
|
-
/**
|
|
144
|
-
* 获取指定阶段的总事件数
|
|
145
|
-
*/
|
|
146
99
|
getPrecomputedEventCount(stage) {
|
|
147
100
|
if (!this._precomputedEvents)
|
|
148
101
|
return 0;
|
|
149
|
-
if (stage)
|
|
102
|
+
if (stage)
|
|
150
103
|
return this._precomputedEvents[stage].length;
|
|
151
|
-
}
|
|
152
104
|
return Object.values(this._precomputedEvents).reduce((sum, arr) => sum + arr.length, 0);
|
|
153
105
|
}
|
|
154
|
-
/**
|
|
155
|
-
* 获取轻量级预计算数据
|
|
156
|
-
* 只包含渲染必需的数据:angles, positions, twirlFlags
|
|
157
|
-
* 内存占用极低,适合大物量谱面
|
|
158
|
-
*/
|
|
159
106
|
getLightweightData() {
|
|
160
107
|
return this._lightweightData;
|
|
161
108
|
}
|
|
162
|
-
/**
|
|
163
|
-
* 轻量级预计算 - 只计算渲染必需的数据
|
|
164
|
-
* 不存储完整的 tile 对象,极大减少内存占用
|
|
165
|
-
*
|
|
166
|
-
* @param skipPositionCalculation 是否跳过坐标计算(如果只需要角度数据)
|
|
167
|
-
*/
|
|
168
109
|
precomputeLightweight(skipPositionCalculation = false) {
|
|
169
110
|
var _a, _b;
|
|
170
111
|
const totalTiles = this.tiles.length;
|
|
171
|
-
// 预分配数组
|
|
172
112
|
const angles = new Array(totalTiles);
|
|
173
113
|
const positions = skipPositionCalculation ? [] : new Array(totalTiles);
|
|
174
114
|
const twirlFlags = new Array(totalTiles);
|
|
175
|
-
// 提取角度和 twirl 标记
|
|
176
115
|
for (let i = 0; i < totalTiles; i++) {
|
|
177
116
|
const tile = this.tiles[i];
|
|
178
117
|
angles[i] = (_a = tile.angle) !== null && _a !== void 0 ? _a : 0;
|
|
179
118
|
twirlFlags[i] = ((_b = tile.twirl) !== null && _b !== void 0 ? _b : 0) % 2 === 1;
|
|
180
119
|
}
|
|
181
|
-
// 计算坐标(如果需要)
|
|
182
120
|
if (!skipPositionCalculation) {
|
|
183
|
-
const
|
|
184
|
-
const angleData = this.angleData;
|
|
185
|
-
// 预构建 PositionTrack 索引
|
|
186
|
-
const positionTrackMap = new Map();
|
|
187
|
-
for (const action of this.actions) {
|
|
188
|
-
if (action.eventType === 'PositionTrack' && action.positionOffset) {
|
|
189
|
-
if (action.editorOnly !== true && action.editorOnly !== 'Enabled') {
|
|
190
|
-
positionTrackMap.set(action.floor, action);
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
}
|
|
121
|
+
const result = precomputePositions(this.angleData, totalTiles, this.actions);
|
|
194
122
|
for (let i = 0; i < totalTiles; i++) {
|
|
195
|
-
|
|
196
|
-
const posTrack = positionTrackMap.get(i);
|
|
197
|
-
if (posTrack === null || posTrack === void 0 ? void 0 : posTrack.positionOffset) {
|
|
198
|
-
startPos[0] += posTrack.positionOffset[0];
|
|
199
|
-
startPos[1] += posTrack.positionOffset[1];
|
|
200
|
-
}
|
|
201
|
-
positions[i] = [startPos[0], startPos[1]];
|
|
202
|
-
// 计算下一个位置(向前回溯连续999)
|
|
203
|
-
let angle;
|
|
204
|
-
if (angleData[i] === 999) {
|
|
205
|
-
let minus = 1;
|
|
206
|
-
while (i - minus >= 0 && angleData[i - minus] === 999) {
|
|
207
|
-
minus++;
|
|
208
|
-
}
|
|
209
|
-
const realAngle = i - minus >= 0 ? angleData[i - minus] : 0;
|
|
210
|
-
angle = realAngle + (minus - 1) * 180;
|
|
211
|
-
}
|
|
212
|
-
else {
|
|
213
|
-
angle = angleData[i];
|
|
214
|
-
}
|
|
215
|
-
const rad = angle * Math.PI / 180;
|
|
216
|
-
startPos[0] += Math.cos(rad);
|
|
217
|
-
startPos[1] += Math.sin(rad);
|
|
123
|
+
positions[i] = result.positions[i];
|
|
218
124
|
}
|
|
219
125
|
}
|
|
220
126
|
this._lightweightData = {
|
|
@@ -226,11 +132,6 @@ export class Level {
|
|
|
226
132
|
};
|
|
227
133
|
return this._lightweightData;
|
|
228
134
|
}
|
|
229
|
-
/**
|
|
230
|
-
* 获取指定范围内的轻量级渲染数据(分片获取,避免一次性加载全部)
|
|
231
|
-
* @param startIndex 起始索引
|
|
232
|
-
* @param count 数量
|
|
233
|
-
*/
|
|
234
135
|
getLightweightDataRange(startIndex, count) {
|
|
235
136
|
if (!this._lightweightData)
|
|
236
137
|
return null;
|
|
@@ -241,15 +142,9 @@ export class Level {
|
|
|
241
142
|
twirlFlags: this._lightweightData.twirlFlags.slice(startIndex, end)
|
|
242
143
|
};
|
|
243
144
|
}
|
|
244
|
-
/**
|
|
245
|
-
* 清除轻量级预计算数据
|
|
246
|
-
*/
|
|
247
145
|
clearLightweightData() {
|
|
248
146
|
this._lightweightData = null;
|
|
249
147
|
}
|
|
250
|
-
/**
|
|
251
|
-
* 获取单个 tile 的渲染数据(按需获取,不预加载全部)
|
|
252
|
-
*/
|
|
253
148
|
getTileRenderData(index) {
|
|
254
149
|
var _a, _b;
|
|
255
150
|
if (index < 0 || index >= this.tiles.length)
|
|
@@ -273,7 +168,6 @@ export class Level {
|
|
|
273
168
|
if (typeof opt === 'string' || isArrayBuffer || isUint8Array || isBuffer) {
|
|
274
169
|
try {
|
|
275
170
|
let input = isArrayBuffer ? new Uint8Array(opt) : opt;
|
|
276
|
-
// 确保此时 input 是 string, Uint8Array 或 Buffer
|
|
277
171
|
options = (_a = this._provider) === null || _a === void 0 ? void 0 : _a.parse(input);
|
|
278
172
|
}
|
|
279
173
|
catch (e) {
|
|
@@ -288,15 +182,12 @@ export class Level {
|
|
|
288
182
|
reject("Options must be String, Buffer, ArrayBuffer or Object");
|
|
289
183
|
return;
|
|
290
184
|
}
|
|
291
|
-
// 阶段2: 处理 pathData 或 angleData
|
|
292
185
|
const hasPathData = options && typeof options === 'object' && options !== null && typeof options.pathData !== 'undefined';
|
|
293
186
|
const hasAngleData = options && typeof options === 'object' && options !== null && typeof options.angleData !== 'undefined';
|
|
294
187
|
if (hasPathData) {
|
|
295
188
|
const pathDataStr = options['pathData'];
|
|
296
|
-
// 开始转换 pathData
|
|
297
189
|
this._emitProgress('pathData', 0, pathDataStr.length, { source: pathDataStr });
|
|
298
190
|
this.angleData = pathData.parseToangleData(pathDataStr);
|
|
299
|
-
// 转换完成,返回结果
|
|
300
191
|
this._emitProgress('pathData', pathDataStr.length, pathDataStr.length, {
|
|
301
192
|
source: pathDataStr,
|
|
302
193
|
processed: this.angleData
|
|
@@ -312,7 +203,6 @@ export class Level {
|
|
|
312
203
|
reject("There is not any angle datas.");
|
|
313
204
|
return;
|
|
314
205
|
}
|
|
315
|
-
// 阶段3: 提取其他数据
|
|
316
206
|
if (options && typeof options === 'object' && options !== null && Array.isArray(options.actions)) {
|
|
317
207
|
this.actions = options['actions'];
|
|
318
208
|
}
|
|
@@ -333,11 +223,16 @@ export class Level {
|
|
|
333
223
|
this.__decorations = [];
|
|
334
224
|
}
|
|
335
225
|
this.tiles = [];
|
|
336
|
-
|
|
337
|
-
this.
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
.
|
|
226
|
+
let twirlCount = 0;
|
|
227
|
+
createTiles(this.angleData.length, {
|
|
228
|
+
angleData: this.angleData,
|
|
229
|
+
actions: this.actions,
|
|
230
|
+
decorations: this.__decorations
|
|
231
|
+
}, {
|
|
232
|
+
onProgress: (stage, current, total, data) => this._emitProgress(stage, current, total, data),
|
|
233
|
+
onTwirl: (count) => { twirlCount = count; },
|
|
234
|
+
getTwirl: () => twirlCount,
|
|
235
|
+
}).then(e => {
|
|
341
236
|
this.tiles = e;
|
|
342
237
|
this._emitProgress('complete', this.angleData.length, this.angleData.length);
|
|
343
238
|
this.trigger('load', this);
|
|
@@ -376,284 +271,17 @@ export class Level {
|
|
|
376
271
|
callbacks.splice(index, 1);
|
|
377
272
|
}
|
|
378
273
|
}
|
|
379
|
-
_createArray(xLength, opt) {
|
|
380
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
381
|
-
const tiles = new Array(xLength);
|
|
382
|
-
const batchSize = Math.max(100, Math.floor(xLength / 100)); // 每批处理的数量,提高最小批量
|
|
383
|
-
// 性能优化:预先按 floor 分组 actions 和 decorations
|
|
384
|
-
const actionsByFloor = new Map();
|
|
385
|
-
if (Array.isArray(opt.actions)) {
|
|
386
|
-
for (const action of opt.actions) {
|
|
387
|
-
if (!actionsByFloor.has(action.floor)) {
|
|
388
|
-
actionsByFloor.set(action.floor, []);
|
|
389
|
-
}
|
|
390
|
-
actionsByFloor.get(action.floor).push(action);
|
|
391
|
-
}
|
|
392
|
-
}
|
|
393
|
-
const decorationsByFloor = new Map();
|
|
394
|
-
if (Array.isArray(opt.decorations)) {
|
|
395
|
-
for (const deco of opt.decorations) {
|
|
396
|
-
if (!decorationsByFloor.has(deco.floor)) {
|
|
397
|
-
decorationsByFloor.set(deco.floor, []);
|
|
398
|
-
}
|
|
399
|
-
decorationsByFloor.get(deco.floor).push(deco);
|
|
400
|
-
}
|
|
401
|
-
}
|
|
402
|
-
for (let i = 0; i < xLength; i++) {
|
|
403
|
-
// 从 Map 中直接获取当前 floor 的 actions
|
|
404
|
-
const floorActions = actionsByFloor.get(i) || [];
|
|
405
|
-
const floorDecos = decorationsByFloor.get(i) || [];
|
|
406
|
-
// 更新 _twirlCount
|
|
407
|
-
for (const action of floorActions) {
|
|
408
|
-
if (action.eventType === 'Twirl') {
|
|
409
|
-
this._twirlCount++;
|
|
410
|
-
}
|
|
411
|
-
}
|
|
412
|
-
// 计算相对角度
|
|
413
|
-
const angle = this._parseAngle(opt.angleData, i, this._twirlCount % 2);
|
|
414
|
-
// 移除 floor 属性并创建 tile
|
|
415
|
-
const tileActions = floorActions.map((_a) => {
|
|
416
|
-
var { floor } = _a, rest = __rest(_a, ["floor"]);
|
|
417
|
-
return rest;
|
|
418
|
-
});
|
|
419
|
-
const tileDecos = floorDecos.map((_a) => {
|
|
420
|
-
var { floor } = _a, rest = __rest(_a, ["floor"]);
|
|
421
|
-
return rest;
|
|
422
|
-
});
|
|
423
|
-
tiles[i] = {
|
|
424
|
-
direction: opt.angleData[i],
|
|
425
|
-
_lastdir: opt.angleData[i - 1] || 0,
|
|
426
|
-
actions: tileActions,
|
|
427
|
-
angle: angle,
|
|
428
|
-
addDecorations: tileDecos,
|
|
429
|
-
twirl: this._twirlCount,
|
|
430
|
-
extraProps: {}
|
|
431
|
-
};
|
|
432
|
-
// 降低进度汇报和让出循环的频率
|
|
433
|
-
if (i % batchSize === 0 || i === xLength - 1) {
|
|
434
|
-
this._emitProgress('relativeAngle', i + 1, xLength, {
|
|
435
|
-
tileIndex: i,
|
|
436
|
-
angle: opt.angleData[i],
|
|
437
|
-
relativeAngle: angle
|
|
438
|
-
});
|
|
439
|
-
// 每 10% 让出一次,或者对于超大谱面增加频率
|
|
440
|
-
if (i % (batchSize * 10) === 0) {
|
|
441
|
-
yield new Promise(r => setTimeout(r, 0));
|
|
442
|
-
}
|
|
443
|
-
}
|
|
444
|
-
}
|
|
445
|
-
return tiles;
|
|
446
|
-
});
|
|
447
|
-
}
|
|
448
|
-
_changeAngle() {
|
|
449
|
-
let y = 0;
|
|
450
|
-
let m = this.tiles.map(t => {
|
|
451
|
-
y++;
|
|
452
|
-
t.angle = this._parsechangedAngle(t.direction, y, t.twirl, t._lastdir);
|
|
453
|
-
return t;
|
|
454
|
-
});
|
|
455
|
-
return m;
|
|
456
|
-
}
|
|
457
|
-
_normalizeAngle(v) {
|
|
458
|
-
return ((v % 360) + 360) % 360;
|
|
459
|
-
}
|
|
460
|
-
_parsechangedAngle(agd, i, isTwirl, lstagd) {
|
|
461
|
-
var _a;
|
|
462
|
-
let prev = 0;
|
|
463
|
-
if (i === 0) {
|
|
464
|
-
this._angleDir = 180;
|
|
465
|
-
}
|
|
466
|
-
if (agd === 999) {
|
|
467
|
-
// 向前回溯(1-based i → tiles 0-based index: i-1 是当前tile)
|
|
468
|
-
let minus = 1;
|
|
469
|
-
while (i - minus - 1 >= 0 && ((_a = this.tiles[i - minus - 1]) === null || _a === void 0 ? void 0 : _a.direction) === 999) {
|
|
470
|
-
minus++;
|
|
471
|
-
}
|
|
472
|
-
const realAngle = i - minus - 1 >= 0 ? this.tiles[i - minus - 1].direction : 0;
|
|
473
|
-
this._angleDir = this._normalizeAngle(realAngle + (minus - 1) * 180);
|
|
474
|
-
if (isNaN(this._angleDir)) {
|
|
475
|
-
this._angleDir = 0;
|
|
476
|
-
}
|
|
477
|
-
prev = 0;
|
|
478
|
-
}
|
|
479
|
-
else {
|
|
480
|
-
const delta = this._normalizeAngle(this._angleDir - agd);
|
|
481
|
-
if (isTwirl === 0) {
|
|
482
|
-
prev = delta;
|
|
483
|
-
}
|
|
484
|
-
else {
|
|
485
|
-
prev = this._normalizeAngle(360 - delta);
|
|
486
|
-
}
|
|
487
|
-
if (prev === 0) {
|
|
488
|
-
prev = 360;
|
|
489
|
-
}
|
|
490
|
-
this._angleDir = this._normalizeAngle(agd + 180);
|
|
491
|
-
}
|
|
492
|
-
return prev;
|
|
493
|
-
}
|
|
494
|
-
_filterByFloor(arr, i) {
|
|
495
|
-
if (!Array.isArray(arr))
|
|
496
|
-
return [];
|
|
497
|
-
let actionT = arr.filter(item => item.floor === i);
|
|
498
|
-
this._twirlCount += actionT.filter(t => t.eventType === 'Twirl').length;
|
|
499
|
-
return actionT.map((_a) => {
|
|
500
|
-
var { floor } = _a, rest = __rest(_a, ["floor"]);
|
|
501
|
-
return rest;
|
|
502
|
-
});
|
|
503
|
-
}
|
|
504
|
-
_flattenAngleDatas(arr) {
|
|
505
|
-
return arr.map(item => item.direction);
|
|
506
|
-
}
|
|
507
|
-
_flattenActionsWithFloor(arr) {
|
|
508
|
-
return arr.flatMap((tile, index) => (Array.isArray(tile === null || tile === void 0 ? void 0 : tile.actions) ? tile.actions : []).map((_a) => {
|
|
509
|
-
var { floor } = _a, rest = __rest(_a, ["floor"]);
|
|
510
|
-
return (Object.assign({ floor: index }, rest));
|
|
511
|
-
}));
|
|
512
|
-
}
|
|
513
|
-
_filterByFloorwithDeco(arr, i) {
|
|
514
|
-
if (!Array.isArray(arr))
|
|
515
|
-
return [];
|
|
516
|
-
let actionT = arr.filter(item => item.floor === i);
|
|
517
|
-
return actionT.map((_a) => {
|
|
518
|
-
var { floor } = _a, rest = __rest(_a, ["floor"]);
|
|
519
|
-
return rest;
|
|
520
|
-
});
|
|
521
|
-
}
|
|
522
|
-
_flattenDecorationsWithFloor(arr) {
|
|
523
|
-
return arr.flatMap((tile, index) => (Array.isArray(tile === null || tile === void 0 ? void 0 : tile.addDecorations) ? tile.addDecorations : []).map((_a) => {
|
|
524
|
-
var { floor } = _a, rest = __rest(_a, ["floor"]);
|
|
525
|
-
return (Object.assign({ floor: index }, rest));
|
|
526
|
-
}));
|
|
527
|
-
}
|
|
528
|
-
_parseAngle(agd, i, isTwirl) {
|
|
529
|
-
let prev = 0;
|
|
530
|
-
if (i === 0) {
|
|
531
|
-
this._angleDir = 180;
|
|
532
|
-
}
|
|
533
|
-
if (agd[i] === 999) {
|
|
534
|
-
// 向前回溯,找到第一个非999的真实角度
|
|
535
|
-
let minus = 1;
|
|
536
|
-
while (i - minus >= 0 && agd[i - minus] === 999) {
|
|
537
|
-
minus++;
|
|
538
|
-
}
|
|
539
|
-
const realAngle = i - minus >= 0 ? agd[i - minus] : 0;
|
|
540
|
-
this._angleDir = this._normalizeAngle(realAngle + (minus - 1) * 180);
|
|
541
|
-
if (isNaN(this._angleDir)) {
|
|
542
|
-
this._angleDir = 0;
|
|
543
|
-
}
|
|
544
|
-
prev = 0;
|
|
545
|
-
}
|
|
546
|
-
else {
|
|
547
|
-
const delta = this._normalizeAngle(this._angleDir - agd[i]);
|
|
548
|
-
if (isTwirl === 0) {
|
|
549
|
-
prev = delta;
|
|
550
|
-
}
|
|
551
|
-
else {
|
|
552
|
-
prev = this._normalizeAngle(360 - delta);
|
|
553
|
-
}
|
|
554
|
-
if (prev === 0) {
|
|
555
|
-
prev = 360;
|
|
556
|
-
}
|
|
557
|
-
this._angleDir = this._normalizeAngle(agd[i] + 180);
|
|
558
|
-
}
|
|
559
|
-
return prev;
|
|
560
|
-
}
|
|
561
274
|
filterActionsByEventType(en) {
|
|
562
|
-
return
|
|
563
|
-
.flatMap(([index, a]) => (Array.isArray(a.actions) ? a.actions : []).map(b => ({ b, index })))
|
|
564
|
-
.filter(({ b }) => b.eventType === en)
|
|
565
|
-
.map(({ b, index }) => ({
|
|
566
|
-
index: Number(index),
|
|
567
|
-
action: b
|
|
568
|
-
}));
|
|
275
|
+
return filterActions(this.tiles, en);
|
|
569
276
|
}
|
|
570
277
|
getActionsByIndex(en, index) {
|
|
571
|
-
|
|
572
|
-
const matches = filtered.filter(item => item.index === index);
|
|
573
|
-
return {
|
|
574
|
-
count: matches.length,
|
|
575
|
-
actions: matches.map(item => item.action)
|
|
576
|
-
};
|
|
278
|
+
return getActions(this.tiles, en, index);
|
|
577
279
|
}
|
|
578
280
|
calculateTileCoordinates() {
|
|
579
281
|
console.warn("calculateTileCoordinates is deprecated. Use calculateTilePosition instead.");
|
|
580
282
|
}
|
|
581
|
-
/**
|
|
582
|
-
* 计算所有 Tile 的坐标位置
|
|
583
|
-
* 触发 parse:tilePosition 和 parse:progress 事件报告进度
|
|
584
|
-
*
|
|
585
|
-
* 性能优化:预先构建 PositionTrack 索引,避免循环内重复遍历
|
|
586
|
-
*/
|
|
587
283
|
calculateTilePosition() {
|
|
588
|
-
|
|
589
|
-
const totalTiles = this.tiles.length;
|
|
590
|
-
const positions = [];
|
|
591
|
-
const startPos = [0, 0];
|
|
592
|
-
// 性能优化:预先构建 PositionTrack 索引 Map,O(n) 预处理
|
|
593
|
-
const positionTrackMap = new Map();
|
|
594
|
-
for (const action of this.actions) {
|
|
595
|
-
if (action.eventType === 'PositionTrack' && action.positionOffset) {
|
|
596
|
-
if (action.editorOnly !== true && action.editorOnly !== 'Enabled') {
|
|
597
|
-
positionTrackMap.set(action.floor, action);
|
|
598
|
-
}
|
|
599
|
-
}
|
|
600
|
-
}
|
|
601
|
-
// 触发开始事件
|
|
602
|
-
this._emitProgress('tilePosition', 0, totalTiles);
|
|
603
|
-
// 预处理 floats 数组(向前回溯连续999)
|
|
604
|
-
const floats = new Array(totalTiles);
|
|
605
|
-
for (let i = 0; i < totalTiles; i++) {
|
|
606
|
-
if (angles[i] === 999) {
|
|
607
|
-
let minus = 1;
|
|
608
|
-
while (i - minus >= 0 && angles[i - minus] === 999) {
|
|
609
|
-
minus++;
|
|
610
|
-
}
|
|
611
|
-
const realAngle = i - minus >= 0 ? angles[i - minus] : 0;
|
|
612
|
-
floats[i] = realAngle + (minus - 1) * 180;
|
|
613
|
-
}
|
|
614
|
-
else {
|
|
615
|
-
floats[i] = angles[i];
|
|
616
|
-
}
|
|
617
|
-
}
|
|
618
|
-
// 进度事件触发频率:每 1% 或最少每 100 个 tile 触发一次
|
|
619
|
-
const progressInterval = Math.max(100, Math.floor(totalTiles / 100));
|
|
620
|
-
for (let i = 0; i <= totalTiles; i++) {
|
|
621
|
-
const isLastTile = i === totalTiles;
|
|
622
|
-
const angle1 = isLastTile ? (floats[i - 1] || 0) : floats[i];
|
|
623
|
-
const angle2 = i === 0 ? 0 : (floats[i - 1] || 0);
|
|
624
|
-
const currentTile = this.tiles[i];
|
|
625
|
-
// 使用索引 Map 直接查询,O(1) 复杂度
|
|
626
|
-
const posTrack = positionTrackMap.get(i);
|
|
627
|
-
if (posTrack === null || posTrack === void 0 ? void 0 : posTrack.positionOffset) {
|
|
628
|
-
startPos[0] += posTrack.positionOffset[0];
|
|
629
|
-
startPos[1] += posTrack.positionOffset[1];
|
|
630
|
-
}
|
|
631
|
-
const tempPos = [startPos[0], startPos[1]];
|
|
632
|
-
positions.push(tempPos);
|
|
633
|
-
if (currentTile) {
|
|
634
|
-
currentTile.position = tempPos;
|
|
635
|
-
currentTile.extraProps.angle1 = angle1;
|
|
636
|
-
currentTile.extraProps.angle2 = angle2 - 180;
|
|
637
|
-
currentTile.extraProps.cangle = isLastTile ? floats[i - 1] + 180 : floats[i];
|
|
638
|
-
}
|
|
639
|
-
// 更新位置
|
|
640
|
-
const rad = angle1 * Math.PI / 180;
|
|
641
|
-
startPos[0] += Math.cos(rad);
|
|
642
|
-
startPos[1] += Math.sin(rad);
|
|
643
|
-
// 触发进度事件(降低频率,轻量级数据)
|
|
644
|
-
if (i % progressInterval === 0 || isLastTile) {
|
|
645
|
-
this._emitProgress('tilePosition', i, totalTiles, {
|
|
646
|
-
tileIndex: i,
|
|
647
|
-
position: [tempPos[0], tempPos[1]],
|
|
648
|
-
angle: angle1
|
|
649
|
-
});
|
|
650
|
-
}
|
|
651
|
-
}
|
|
652
|
-
// 触发完成事件
|
|
653
|
-
this._emitProgress('tilePosition', totalTiles, totalTiles, {
|
|
654
|
-
processed: positions.flat()
|
|
655
|
-
});
|
|
656
|
-
return positions;
|
|
284
|
+
return calculateTilePositions(this.angleData, this.tiles, this.actions, (stage, current, total, data) => this._emitProgress(stage, current, total, data));
|
|
657
285
|
}
|
|
658
286
|
floorOperation(info = { type: 'append', direction: 0 }) {
|
|
659
287
|
switch (info.type) {
|
|
@@ -678,7 +306,7 @@ export class Level {
|
|
|
678
306
|
}
|
|
679
307
|
break;
|
|
680
308
|
}
|
|
681
|
-
this.
|
|
309
|
+
changeAngles(this.tiles);
|
|
682
310
|
}
|
|
683
311
|
appendFloor(args) {
|
|
684
312
|
this.tiles.push({
|
|
@@ -690,7 +318,7 @@ export class Level {
|
|
|
690
318
|
twirl: this.tiles[this.tiles.length - 1].twirl,
|
|
691
319
|
extraProps: {}
|
|
692
320
|
});
|
|
693
|
-
this.
|
|
321
|
+
changeAngles(this.tiles);
|
|
694
322
|
}
|
|
695
323
|
clearDeco() {
|
|
696
324
|
this.tiles = effectProcessor.clearDecorations(this.tiles);
|
|
@@ -709,10 +337,10 @@ export class Level {
|
|
|
709
337
|
}
|
|
710
338
|
export(type, indent, useAdofaiStyle = true, indentChar, indentStep) {
|
|
711
339
|
const ADOFAI = {
|
|
712
|
-
angleData:
|
|
340
|
+
angleData: flattenAngleDatas(this.tiles),
|
|
713
341
|
settings: this.settings,
|
|
714
|
-
actions:
|
|
715
|
-
decorations:
|
|
342
|
+
actions: flattenActionsWithFloor(this.tiles),
|
|
343
|
+
decorations: flattenDecorationsWithFloor(this.tiles)
|
|
716
344
|
};
|
|
717
345
|
return type === 'object' ? ADOFAI : exportAsADOFAI(ADOFAI, indent, useAdofaiStyle, indentChar, indentStep);
|
|
718
346
|
}
|