@eva/plugin-renderer-tilemap 2.1.0-beta.5 → 2.1.0-beta.6
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 +94 -1
- package/dist/EVA.plugin.renderer.tilemap.js +1625 -46
- package/dist/EVA.plugin.renderer.tilemap.min.js +1 -1
- package/dist/plugin-renderer-tilemap.cjs.js +2374 -67
- package/dist/plugin-renderer-tilemap.cjs.prod.js +1 -1
- package/dist/plugin-renderer-tilemap.d.ts +1010 -23
- package/dist/plugin-renderer-tilemap.esm.js +2336 -68
- package/package.json +7 -3
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Component } from '@eva/eva.js';
|
|
2
2
|
import { ComponentChanged } from '@eva/eva.js';
|
|
3
|
+
import { Container } from 'pixi.js';
|
|
3
4
|
import { ContainerManager } from '@eva/plugin-renderer';
|
|
4
5
|
import { GameObject } from '@eva/eva.js';
|
|
5
6
|
import { Renderer } from '@eva/plugin-renderer';
|
|
@@ -7,15 +8,633 @@ import { RendererManager } from '@eva/plugin-renderer';
|
|
|
7
8
|
import { RendererSystem } from '@eva/plugin-renderer';
|
|
8
9
|
|
|
9
10
|
/**
|
|
10
|
-
*
|
|
11
|
+
* Adapter:把 host 端 installPerfProbes 的 API 适配到 PerfProbeRegistry。
|
|
11
12
|
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
13
|
+
* ADR-0013 的 installPerfProbes 暴露 `game.perfProbes?.{begin,end,count,gauge}` 等
|
|
14
|
+
* 命名空间。这里只做转发,host 决定具体接入哪个版本。
|
|
15
|
+
*/
|
|
16
|
+
export declare function adaptGamePerfProbes(game: {
|
|
17
|
+
perfProbes?: Partial<PerfProbeRegistry>;
|
|
18
|
+
}): PerfProbeRegistry | null;
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Status flag — true once ADR-0019 lands and this host stop-gap can be removed.
|
|
22
|
+
*
|
|
23
|
+
* Hosts can branch on this to switch from the child-GameObject workaround to a
|
|
24
|
+
* direct registry handshake. Until then, importing this module signals "I am
|
|
25
|
+
* using the pre-ADR-0019 path".
|
|
26
|
+
*/
|
|
27
|
+
export declare const ADR_0019_NATIVE_REGISTRY_AVAILABLE = false;
|
|
28
|
+
|
|
29
|
+
export declare interface AdvanceResult {
|
|
30
|
+
/** key = `${slot},${col},${row}` → 当前帧 atlas (col,row) */
|
|
31
|
+
currentFrames: Map<string, {
|
|
32
|
+
col: number;
|
|
33
|
+
row: number;
|
|
34
|
+
}>;
|
|
35
|
+
/** key set:相比上次 advance() 改变了 currentFrame 的 tiles。 */
|
|
36
|
+
dirtyKeys: Set<string>;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
declare interface AtlasTileRaw {
|
|
40
|
+
atlasCoords: {
|
|
41
|
+
col: number;
|
|
42
|
+
row: number;
|
|
43
|
+
};
|
|
44
|
+
size?: {
|
|
45
|
+
width: number;
|
|
46
|
+
height: number;
|
|
47
|
+
};
|
|
48
|
+
alternatives: Array<{
|
|
49
|
+
altId: number;
|
|
50
|
+
modulate?: string;
|
|
51
|
+
zIndex?: number;
|
|
52
|
+
probability?: number;
|
|
53
|
+
[extra: string]: unknown;
|
|
54
|
+
}>;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export declare interface AutotileCandidate {
|
|
58
|
+
sourceSlot: number;
|
|
59
|
+
col: number;
|
|
60
|
+
row: number;
|
|
61
|
+
altIdx: number;
|
|
62
|
+
probability: number;
|
|
63
|
+
terrain: number;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export declare interface BodyDefinition {
|
|
67
|
+
id: string;
|
|
68
|
+
/** 局部顶点 — Matter.js 会用 fromVertices 构建 polygon body。 */
|
|
69
|
+
vertices: BodyVec2[];
|
|
70
|
+
/** body 中心(world coords)。 */
|
|
71
|
+
centerX: number;
|
|
72
|
+
centerY: number;
|
|
73
|
+
isStatic: boolean;
|
|
74
|
+
friction?: number;
|
|
75
|
+
restitution?: number;
|
|
76
|
+
oneWay?: boolean;
|
|
77
|
+
categoryFilter?: number;
|
|
78
|
+
maskFilter?: number;
|
|
79
|
+
metadata?: Record<string, unknown>;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export declare type BodySourceBuilder = (ctx: BodySourceContext) => BodyDefinition[];
|
|
83
|
+
|
|
84
|
+
export declare interface BodySourceContext {
|
|
85
|
+
worldX: number;
|
|
86
|
+
worldY: number;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
declare class BodySourceRegistryImpl {
|
|
90
|
+
private builders;
|
|
91
|
+
register(name: string, builder: BodySourceBuilder): void;
|
|
92
|
+
unregister(name: string): void;
|
|
93
|
+
has(name: string): boolean;
|
|
94
|
+
build(name: string, ctx: BodySourceContext): BodyDefinition[] | null;
|
|
95
|
+
listRegisteredNames(): string[];
|
|
96
|
+
clear(): void;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Body source registry shim(G1)。
|
|
101
|
+
*
|
|
102
|
+
* 真实 plugin-matterjs `registerBodySource` API 落地需要 ADR-0019 评审 + BREAKING
|
|
103
|
+
* change。这里先 ship 一个完全相同的抽象层,plugin-renderer-tilemap 内部用它建
|
|
104
|
+
* TileMapStaticBody body 集合。host 在初始化时把这个 registry 喂给 plugin-matterjs
|
|
105
|
+
* (或直接消费它建 Matter.Composite)。
|
|
106
|
+
*
|
|
107
|
+
* 当 ADR-0019 落地后,只需要把这里的 import 切到 @eva/plugin-matterjs/lib/body-source。
|
|
108
|
+
*/
|
|
109
|
+
declare interface BodyVec2 {
|
|
110
|
+
x: number;
|
|
111
|
+
y: number;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Build geometry for a chunk。chunkX/Y 是 chunk 在世界坐标的左上(已含 mapOrigin)。
|
|
116
|
+
*/
|
|
117
|
+
export declare function buildChunkGeometry(args: {
|
|
118
|
+
cells: Int32Array;
|
|
119
|
+
chunkWorldX: number;
|
|
120
|
+
chunkWorldY: number;
|
|
121
|
+
cellWidth: number;
|
|
122
|
+
cellHeight: number;
|
|
123
|
+
atlasInfo: ChunkGeometryAtlasInfo;
|
|
124
|
+
}): ChunkGeometryResult;
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* 创建一个 chunk 的 Mesh-path render container。
|
|
128
|
+
*
|
|
129
|
+
* 当前实现:返回 Container stub。Cycle 2 接入真实 PIXI.Mesh + 自定义 shader 时
|
|
130
|
+
* 替换内部实现即可,调用方接口不变(返回 Container,由 ChunkRenderer 加到 stage)。
|
|
131
|
+
*
|
|
132
|
+
* 接口稳定保证:
|
|
133
|
+
* - 返回 Container 必须有 children 数组(Container 默认即有)
|
|
134
|
+
* - 返回的 Container 在 destroy() 时正确释放纹理
|
|
135
|
+
*/
|
|
136
|
+
export declare function buildChunkMesh(_config: ChunkMeshConfig): Container;
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Build BodyDefinition[] for an entire TileMap layer。
|
|
140
|
+
*
|
|
141
|
+
* 每 cell 引用 TileSet 中对应 tile 的 physics polygons:
|
|
142
|
+
* - 在 cache 里查 cached convex parts(load 时已 decompose)
|
|
143
|
+
* - 没缓存就 decomposePolygon stub(当前 polygon=convex 直接返回)
|
|
144
|
+
* - translate 到 cell world 位置
|
|
145
|
+
*/
|
|
146
|
+
export declare function buildTileMapStaticBodies(input: TileMapStaticBodyInput, ctx: BodySourceContext): BodyDefinition[];
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Build BodyDefinition[] for a TileMap entity and group by physics layer.
|
|
150
|
+
*
|
|
151
|
+
* The host is expected to call this after `system.handleAdd` resolves and the
|
|
152
|
+
* record has its `loadedTileset`. The host passes:
|
|
153
|
+
* - chunksByKey from `decodeChunk(layer.cellData.chunks[key])`
|
|
154
|
+
* - physicsByCellKey derived from `loadedTileset.raw.sources[i].tiles[j].alternatives[k].physics`
|
|
155
|
+
*
|
|
156
|
+
* This keeps the runtime plugin agnostic of how the host actually registers bodies
|
|
157
|
+
* with Matter (child GameObject + Physics component vs. direct Matter.Composite.add).
|
|
158
|
+
*/
|
|
159
|
+
export declare function buildTileMapStaticBodyDefinitions(input: TileMapStaticBodyInput, ctx: BodySourceContext,
|
|
160
|
+
/**
|
|
161
|
+
* T-L3 (Phase L):optional probe registry。当 host 注入时,本函数会:
|
|
162
|
+
* - PHYSICS_REBAKE_MS:wrap 整个 buildTileMapStaticBodies 调用计时
|
|
163
|
+
* - BODIES_TOTAL:emit gauge,反映当前生成的 body 总数
|
|
164
|
+
* - BODIES_CREATED:counter+totalBodyCount,统计累计 created
|
|
165
|
+
* 不注入时 silent no-op,保持与现有 caller 行为兼容。
|
|
166
|
+
* BODIES_DESTROYED 暂未 emit(无清晰 destroy point),Cycle 2 再补。
|
|
167
|
+
*/
|
|
168
|
+
probes?: PerfProbeRegistry): TileMapStaticBodyHostBuildResult;
|
|
169
|
+
|
|
170
|
+
export declare interface CachedDecomposition {
|
|
171
|
+
parts: ConvexPart[];
|
|
172
|
+
/** 物理材质参数,Phase 3 时由 plugin-matterjs 消费。 */
|
|
173
|
+
friction?: number;
|
|
174
|
+
restitution?: number;
|
|
175
|
+
oneWay?: boolean;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
export declare function cacheKeyOf(k: DecompositionCacheKey): string;
|
|
179
|
+
|
|
180
|
+
export declare function cacheKeyOfNum(slot: number, col: number, row: number, altIdx: number): number;
|
|
181
|
+
|
|
182
|
+
declare interface CellRecord {
|
|
183
|
+
sourceSlot: number;
|
|
184
|
+
col: number;
|
|
185
|
+
row: number;
|
|
186
|
+
altIdx: number;
|
|
187
|
+
flipH: boolean;
|
|
188
|
+
flipV: boolean;
|
|
189
|
+
transpose: boolean;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* 与 libs/dsl/src/editor/chunk-codec.ts 同形的解码 helper。
|
|
194
|
+
* 在 plugin 内复制一份是为了避免 @eva/* 反向依赖 @ali/eva-dsl 或本仓 libs/dsl。
|
|
195
|
+
*
|
|
196
|
+
* 这里只需要解码 + 拆 cell;编码留给 DSL 编辑层。
|
|
197
|
+
*/
|
|
198
|
+
export declare const CHUNK_SIZE = 16;
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Chunked cell data。与 libs/dsl 的 ChunkedCellData 同形,但为避免反向依赖,
|
|
202
|
+
* 在这里独立声明接口(结构兼容 JSON shape)。
|
|
203
|
+
*
|
|
204
|
+
* Cell encoding (1 int32 per cell):
|
|
205
|
+
* bits 0..7 sourceSlot (1..255,0 = 空)
|
|
206
|
+
* bits 8..15 col
|
|
207
|
+
* bits 16..23 row
|
|
208
|
+
* bits 24..28 altIdx
|
|
209
|
+
* bit 29 flipH
|
|
210
|
+
* bit 30 flipV
|
|
211
|
+
* bit 31 transpose
|
|
212
|
+
*/
|
|
213
|
+
export declare interface ChunkedCellData {
|
|
214
|
+
kind: 'chunked';
|
|
215
|
+
chunkSize: 16;
|
|
216
|
+
stride: 1;
|
|
217
|
+
chunks: Record<string, {
|
|
218
|
+
blob: string;
|
|
219
|
+
nonEmpty: number;
|
|
220
|
+
}>;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* Build packed vertex/index buffers for a chunk mesh(G3)。
|
|
225
|
+
*
|
|
226
|
+
* 输入:Int32Array(256 packed cells)+ atlas region info。
|
|
227
|
+
* 输出:Float32Array (vertex data) + Uint16Array (indices)。
|
|
228
|
+
*
|
|
229
|
+
* 每非空 cell 4 vertices × 8 floats(2 pos + 2 uv + 4 flags) = 32 floats = 128B。
|
|
230
|
+
* 6 indices/quad × 2B = 12B index。
|
|
231
|
+
*/
|
|
232
|
+
export declare interface ChunkGeometryAtlasInfo {
|
|
233
|
+
regionWidth: number;
|
|
234
|
+
regionHeight: number;
|
|
235
|
+
textureWidth: number;
|
|
236
|
+
textureHeight: number;
|
|
237
|
+
margins: {
|
|
238
|
+
x: number;
|
|
239
|
+
y: number;
|
|
240
|
+
};
|
|
241
|
+
separation: {
|
|
242
|
+
x: number;
|
|
243
|
+
y: number;
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
export declare interface ChunkGeometryResult {
|
|
248
|
+
vertexData: Float32Array;
|
|
249
|
+
indices: Uint16Array;
|
|
250
|
+
quadCount: number;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
export declare interface ChunkMeshConfig {
|
|
254
|
+
chunkKey: string;
|
|
255
|
+
chunkX: number;
|
|
256
|
+
chunkY: number;
|
|
257
|
+
cellWidth: number;
|
|
258
|
+
cellHeight: number;
|
|
259
|
+
/** Atlas 纹理 — Mesh shader 通过 uTexture 采样。 */
|
|
260
|
+
atlas: unknown;
|
|
261
|
+
/** Cell record array (256 ints) — 用于 vertex attribute upload。 */
|
|
262
|
+
cells: Int32Array;
|
|
263
|
+
/** Tile region width / height in atlas (regionSize)。 */
|
|
264
|
+
regionWidth: number;
|
|
265
|
+
regionHeight: number;
|
|
266
|
+
/** atlas margins / separation,用于 UV 计算。 */
|
|
267
|
+
margins?: {
|
|
268
|
+
x: number;
|
|
269
|
+
y: number;
|
|
270
|
+
};
|
|
271
|
+
separation?: {
|
|
272
|
+
x: number;
|
|
273
|
+
y: number;
|
|
274
|
+
};
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
export declare interface ChunkRenderStrategyContext {
|
|
278
|
+
nonEmptyCellsInChunk: number;
|
|
279
|
+
atlasesInChunk: number;
|
|
280
|
+
totalChunksVisible: number;
|
|
281
|
+
preference?: ChunkRenderStrategyKind;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
/**
|
|
285
|
+
* Chunk render strategy(Phase 4).
|
|
286
|
+
*
|
|
287
|
+
* 当前 system.ts 直接走 sprite-entity 路径(每非空 cell 一个 PIXI.Sprite),
|
|
288
|
+
* 简单可靠。Phase 4 引入 strategy 接口为后续 Mesh 路径预留位置:
|
|
289
|
+
* - sprite:Phase 1 MVP 路径,适合 < 4096 个 cell / chunk 数 < 30 的场景
|
|
290
|
+
* - mesh: 单 chunk 一次 draw call,适合 200×200 60% 填充等高密度
|
|
291
|
+
* - auto: 按 chunk 内非空 cell 数与 atlas 数动态选择
|
|
292
|
+
*
|
|
293
|
+
* 这里只 ship strategy interface + sprite 实现 + auto-pick 阈值;实际 PIXI.Mesh
|
|
294
|
+
* shader 在下一轮 cycle 落地(见 ADR-0018 §11 未决问题 2)。
|
|
295
|
+
*/
|
|
296
|
+
export declare type ChunkRenderStrategyKind = 'sprite' | 'mesh' | 'auto';
|
|
297
|
+
|
|
298
|
+
export declare interface CompiledTileAnimation {
|
|
299
|
+
sourceSlot: number;
|
|
300
|
+
col: number;
|
|
301
|
+
row: number;
|
|
302
|
+
frames: TileAnimationFrame[];
|
|
303
|
+
totalDurationMs: number;
|
|
304
|
+
phase: 'sync' | 'randomStart';
|
|
305
|
+
phaseOffsetMs: number;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
/**
|
|
309
|
+
* 给定 diff 结果 + 文档 chunks(`chunkKey → Int32Array`),返回需要 rebuild 的 chunk key set。
|
|
310
|
+
*
|
|
311
|
+
* 算法:遍历所有 chunks,对每个非空 cell,如果它引用的 atlas (sourceSlot, col, row) 在 changed
|
|
312
|
+
* /removed/added tile set 里,标记该 chunk dirty。
|
|
313
|
+
*/
|
|
314
|
+
export declare function computeAffectedChunks(chunks: Record<string, Int32Array>, sourceIdBySlot: Map<number, string>, diff: TilesetChunkRebuildDiff): Set<string>;
|
|
315
|
+
|
|
316
|
+
/**
|
|
317
|
+
* DecompositionCache(C1,关联 ADR-0019)。
|
|
318
|
+
*
|
|
319
|
+
* TileSet 上每 alt tile 可能有任意 polygon collision shape。Matter.js 要求 convex,
|
|
320
|
+
* concave 需 poly-decomp。decompose 是 O(n²),不能每 paint stroke 重做。
|
|
321
|
+
*
|
|
322
|
+
* 这里在 TileSet load 时把每 alt tile 的 polygon list 一次性 decompose 成 convex parts,
|
|
323
|
+
* 后续 stroke 只走 translate;decompose 结果按 (sourceSlot, col, row, altIdx, layerId) key 缓存。
|
|
324
|
+
*
|
|
325
|
+
* 当前 cycle:cache 数据结构 + key 生成 + LRU eviction skeleton 实现完毕,真 poly-decomp
|
|
326
|
+
* 在 Phase 3 落地时接入 npm `poly-decomp` 包。
|
|
327
|
+
*/
|
|
328
|
+
export declare interface ConvexPart {
|
|
329
|
+
/** 顶点列表(局部坐标,相对 tile 中心或左上)。 */
|
|
330
|
+
vertices: Array<{
|
|
331
|
+
x: number;
|
|
332
|
+
y: number;
|
|
333
|
+
}>;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
/** 创建一个内存收集器(测试用)。 */
|
|
337
|
+
export declare function createInMemoryProbeRegistry(): PerfProbeRegistry & {
|
|
338
|
+
timings: Map<string, number[]>;
|
|
339
|
+
counts: Map<string, number>;
|
|
340
|
+
gauges: Map<string, number>;
|
|
341
|
+
};
|
|
342
|
+
|
|
343
|
+
export declare function decodeChunk(blob: {
|
|
344
|
+
blob: string;
|
|
345
|
+
nonEmpty: number;
|
|
346
|
+
}): Int32Array;
|
|
347
|
+
|
|
348
|
+
/**
|
|
349
|
+
* 暂时占位的 polygon → convex parts 函数。
|
|
350
|
+
* Phase 3 落地 npm `poly-decomp` 时替换实现;当前假设输入已 convex,
|
|
351
|
+
* 输入 concave polygon(L/T/U/凹槽)会 throw,防止静默产出错误 Matter body。
|
|
352
|
+
*
|
|
353
|
+
* Host 应在 paint 前用 isConvex 做 pre-check,把 concave 提示给用户,避免触发 throw。
|
|
354
|
+
*/
|
|
355
|
+
export declare function decomposePolygon(polygon: Array<{
|
|
356
|
+
x: number;
|
|
357
|
+
y: number;
|
|
358
|
+
}>): ConvexPart[];
|
|
359
|
+
|
|
360
|
+
export declare class DecompositionCache {
|
|
361
|
+
private readonly maxEntries;
|
|
362
|
+
private cache;
|
|
363
|
+
private accessOrder;
|
|
364
|
+
private accessCounter;
|
|
365
|
+
constructor(maxEntries?: number);
|
|
366
|
+
get(key: DecompositionCacheKey): CachedDecomposition | undefined;
|
|
367
|
+
set(key: DecompositionCacheKey, value: CachedDecomposition): void;
|
|
368
|
+
has(key: DecompositionCacheKey): boolean;
|
|
369
|
+
clear(): void;
|
|
370
|
+
get size(): number;
|
|
371
|
+
private evictLRU;
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
export declare interface DecompositionCacheKey {
|
|
375
|
+
sourceSlot: number;
|
|
376
|
+
col: number;
|
|
377
|
+
row: number;
|
|
378
|
+
altIdx: number;
|
|
379
|
+
layerId: string;
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
/**
|
|
383
|
+
* @deprecated Use `diffTilesetForChunkRebuild`. Alias kept for transitional
|
|
384
|
+
* compatibility — the name collided with `@ali/eva-dsl`'s `diffTilesetDocuments`
|
|
385
|
+
* (document-level detailed diff for host UX), which has different semantics.
|
|
386
|
+
*/
|
|
387
|
+
export declare const diffTilesetDocuments: typeof diffTilesetForChunkRebuild;
|
|
388
|
+
|
|
389
|
+
/**
|
|
390
|
+
* 计算两个 TilesetDocumentRaw 之间的 source/tile-level coarse diff,供
|
|
391
|
+
* `computeAffectedChunks` 决定哪些 chunk 要 rebuild。
|
|
392
|
+
*
|
|
393
|
+
* 不要与 `@ali/eva-dsl` 的 `diffTilesetDocuments` 混淆 — 后者是 document-level
|
|
394
|
+
* detailed diff(per alternative / animation / customData / physics / terrain),
|
|
395
|
+
* 用于 host UX 显示,不是 chunk-rebuild 决策。
|
|
396
|
+
*/
|
|
397
|
+
export declare function diffTilesetForChunkRebuild(prev: TilesetDocumentRaw, next: TilesetDocumentRaw): TilesetChunkRebuildDiff;
|
|
398
|
+
|
|
399
|
+
/**
|
|
400
|
+
* 估算单 chunk Mesh path 占用 GPU memory(单位 KB)。
|
|
401
|
+
* 用于 perf probes,Mesh path 上线后 budget 监控参考。
|
|
402
|
+
*/
|
|
403
|
+
export declare function estimateChunkMeshMemoryKB(config: ChunkMeshConfig): number;
|
|
404
|
+
|
|
405
|
+
/**
|
|
406
|
+
* 估算单个 chunk 在 sprite 路径下的额外 PIXI 节点开销(用于 perf-probe)。
|
|
407
|
+
*/
|
|
408
|
+
export declare function estimateSpriteNodes(nonEmptyCellsInChunk: number): number;
|
|
409
|
+
|
|
410
|
+
/**
|
|
411
|
+
* 把 sceneCollection source 展开成 prefab ref 数组。
|
|
412
|
+
*/
|
|
413
|
+
export declare function expandSceneCollectionSource(src: TilesetSourceRaw): SceneCollectionPrefabRef[];
|
|
414
|
+
|
|
415
|
+
/**
|
|
416
|
+
* Extract `physicsByCellKey` Map from a LoadedTileset's raw atlas tile data.
|
|
417
|
+
*
|
|
418
|
+
* Each tile alternative may carry `physics: Array<{ layerId, polygons, oneWay, friction, restitution }>`.
|
|
419
|
+
* The returned Map is keyed by `${slot},${col},${row},${altIdx}` matching the cell-packed
|
|
420
|
+
* id format used by `buildTileMapStaticBodies`.
|
|
421
|
+
*/
|
|
422
|
+
export declare function extractPhysicsByCellKey(tilesetRaw: {
|
|
423
|
+
sources: Array<{
|
|
424
|
+
kind: string;
|
|
425
|
+
tiles?: Array<{
|
|
426
|
+
atlasCoords: {
|
|
427
|
+
col: number;
|
|
428
|
+
row: number;
|
|
429
|
+
};
|
|
430
|
+
alternatives: Array<{
|
|
431
|
+
altId: number;
|
|
432
|
+
physics?: Array<{
|
|
433
|
+
layerId: string;
|
|
434
|
+
polygons: Array<{
|
|
435
|
+
points: Array<{
|
|
436
|
+
x: number;
|
|
437
|
+
y: number;
|
|
438
|
+
}>;
|
|
439
|
+
origin?: "center" | "topLeft";
|
|
440
|
+
}>;
|
|
441
|
+
oneWay?: boolean;
|
|
442
|
+
friction?: number;
|
|
443
|
+
restitution?: number;
|
|
444
|
+
}>;
|
|
445
|
+
}>;
|
|
446
|
+
}>;
|
|
447
|
+
}>;
|
|
448
|
+
}): TileMapStaticBodyInput["physicsByCellKey"];
|
|
449
|
+
|
|
450
|
+
/**
|
|
451
|
+
* Coverage 计算 — Phase B 门禁要求 budgetCoverage ≥ 0.95。
|
|
452
|
+
* 这里返回当前 hot-path 涉及的 probe 名字集合,host 用它对比 installPerfProbes 实际
|
|
453
|
+
* 注册的 probe set。
|
|
454
|
+
*/
|
|
455
|
+
export declare function getRequiredTilemapProbes(): string[];
|
|
456
|
+
|
|
457
|
+
export declare function isEmptyCellValue(packed: number): boolean;
|
|
458
|
+
|
|
459
|
+
/** 返回 true 表示当前环境支持 Mesh path(需要 WebGL2 + Program shader)。 */
|
|
460
|
+
export declare function isMeshPathAvailable(): boolean;
|
|
461
|
+
|
|
462
|
+
/** 运行时解析后的 frozen TileSet。 */
|
|
463
|
+
export declare interface LoadedTileset {
|
|
464
|
+
raw: TilesetDocumentRaw;
|
|
465
|
+
/** sourceSlot 索引(1-based):slot 0 = empty,slot 1 = sources[0]。 */
|
|
466
|
+
sourcesBySlot: TilesetSourceRaw[];
|
|
467
|
+
/** id → slot,patch 寻址用。 */
|
|
468
|
+
slotByIdMap: Map<string, number>;
|
|
469
|
+
tileWidth: number;
|
|
470
|
+
tileHeight: number;
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
export declare function makeLoadedTileset(raw: TilesetDocumentRaw): LoadedTileset;
|
|
474
|
+
|
|
475
|
+
export declare const MAX_TERRAIN_ID = 14;
|
|
476
|
+
|
|
477
|
+
/**
|
|
478
|
+
* Autotile peering-bit index (Phase 2).
|
|
479
|
+
*
|
|
480
|
+
* 在 TileSet load 时构建,把每个 alt tile 的 peering bits 编进 hash key
|
|
481
|
+
* 实现 O(1) 邻居匹配。
|
|
17
482
|
*
|
|
18
|
-
*
|
|
483
|
+
* 数据模型:
|
|
484
|
+
* - 一个 terrainSet 有最多 8 个方向(Godot corners+sides),每个方向上当前
|
|
485
|
+
* 邻居的 terrain id 取值 0..255。
|
|
486
|
+
* - 把 8 个方向打包成一个 BigInt 作 exact-match key:每 byte 一个方向。
|
|
487
|
+
* - 通配 (`undefined` neighbor) 用 0xff 哨兵表示;查询时构造 actual neighborhood
|
|
488
|
+
* 也用 0xff 表示"无邻居 / 空 cell"。
|
|
489
|
+
* - exact 命中优先;否则在 wildcard 桶里按 Hamming 距离打分,取最小者(同分则
|
|
490
|
+
* 按 probability 加权随机 - 注意此处仅返回候选,不做 RNG)。
|
|
491
|
+
*
|
|
492
|
+
* 这里只暴露纯函数 + 数据结构,RNG/decision 留给 AutotileCommand 调用方。
|
|
493
|
+
*/
|
|
494
|
+
export declare const NEIGHBOR_DIRECTIONS: readonly ["topLeft", "top", "topRight", "right", "bottomRight", "bottom", "bottomLeft", "left"];
|
|
495
|
+
|
|
496
|
+
export declare type NeighborDirection = (typeof NEIGHBOR_DIRECTIONS)[number];
|
|
497
|
+
|
|
498
|
+
/**
|
|
499
|
+
* 4-bit-per-direction × 8 directions = 32-bit number 作 hash key。
|
|
500
|
+
* terrain id 范围 0..14;15 (0xf) 作 NO_NEIGHBOR / wildcard 哨兵。
|
|
501
|
+
* v1 限制最多 15 个 terrain per terrain set,足够 Godot 47-tile Wang 集。
|
|
502
|
+
*/
|
|
503
|
+
export declare const NO_NEIGHBOR = 15;
|
|
504
|
+
|
|
505
|
+
/**
|
|
506
|
+
* Build the index from a TileSet's terrainSet candidates.
|
|
507
|
+
*
|
|
508
|
+
* `candidates` is the flat list of all (sourceSlot, col, row, altIdx) belonging
|
|
509
|
+
* to the given terrainSet, each with optional peeringBits + probability.
|
|
510
|
+
*/
|
|
511
|
+
export declare class PeeringBitIndex {
|
|
512
|
+
readonly terrainSetIndex: number;
|
|
513
|
+
private exact;
|
|
514
|
+
private wildcards;
|
|
515
|
+
constructor(terrainSetIndex: number);
|
|
516
|
+
add(candidate: AutotileCandidate, bits: PeeringBitsRecord | undefined): void;
|
|
517
|
+
/**
|
|
518
|
+
* Match an `actual` neighborhood:8 byte values, NO_NEIGHBOR for "empty".
|
|
519
|
+
*
|
|
520
|
+
* Returns the set of best-matching candidates (Hamming distance 0 = exact).
|
|
521
|
+
* If no candidate matches at any distance, returns empty list.
|
|
522
|
+
*/
|
|
523
|
+
match(actual: number[]): PeeringBitMatchResult;
|
|
524
|
+
get exactBucketCount(): number;
|
|
525
|
+
get wildcardCount(): number;
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
export declare interface PeeringBitMatchResult {
|
|
529
|
+
candidates: AutotileCandidate[];
|
|
530
|
+
exactMatch: boolean;
|
|
531
|
+
bestHammingDistance: number;
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
export declare interface PeeringBitsRecord {
|
|
535
|
+
[direction: string]: number;
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
/**
|
|
539
|
+
* Tilemap performance probes(Sprint C B3,关联 ADR-0013)。
|
|
540
|
+
*
|
|
541
|
+
* 提供 11 个 probe(11 计时器 / 计数器),host 可通过 installTilemapPerfProbes(game)
|
|
542
|
+
* 把它们注册到 ADR-0013 的 installPerfProbes 命令式 API 中。
|
|
543
|
+
*
|
|
544
|
+
* 当前不直接依赖 ADR-0013 的 perf 包(避免循环依赖),改为暴露 PerfProbeRegistry
|
|
545
|
+
* 接口,host 注入。这样:
|
|
546
|
+
* - Phase B 门禁:budgetCoverage 通过这 11 个 probe 计入
|
|
547
|
+
* - 测试场景:host 可注入 in-memory 收集器 verify metrics
|
|
548
|
+
*/
|
|
549
|
+
export declare interface PerfProbeRegistry {
|
|
550
|
+
/** 计时 probe — 调 begin → 操作 → end,记录耗时。 */
|
|
551
|
+
beginTiming(name: string): void;
|
|
552
|
+
endTiming(name: string): void;
|
|
553
|
+
/** 计数 probe — 累加。 */
|
|
554
|
+
count(name: string, delta?: number): void;
|
|
555
|
+
/** 距离值 probe — gauge,记录当前瞬时值。 */
|
|
556
|
+
gauge(name: string, value: number): void;
|
|
557
|
+
/** 分布 probe — histogram(可选)。 */
|
|
558
|
+
histogram?(name: string, value: number): void;
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
/**
|
|
562
|
+
* Probability-weighted picker — deterministic when seed is provided.
|
|
563
|
+
*/
|
|
564
|
+
export declare function pickAutotileCandidate(candidates: AutotileCandidate[], rng: () => number): AutotileCandidate | null;
|
|
565
|
+
|
|
566
|
+
/**
|
|
567
|
+
* 给定 packed cell + source 列表,查这个 cell 对应的 prefab name(如果是 scene-collection
|
|
568
|
+
* source);atlas source 返回 null。
|
|
569
|
+
*/
|
|
570
|
+
export declare function resolveCellPrefabName(packed: number, sourcesBySlot: TilesetSourceRaw[]): string | null;
|
|
571
|
+
|
|
572
|
+
/**
|
|
573
|
+
* 决定单个 chunk 走哪条渲染路径。
|
|
574
|
+
*
|
|
575
|
+
* 阈值来源于 ADR-0018 §10 风险登记册(Phase 4 P2-7 改造):
|
|
576
|
+
* - 单 chunk 非空 cell 数 >= 192 (75%) 且单 atlas → mesh
|
|
577
|
+
* - 多 atlas → sprite(等 texture-array 支持后再切 mesh)
|
|
578
|
+
* - 否则 sprite 简单稳定
|
|
579
|
+
*/
|
|
580
|
+
export declare function resolveChunkRenderStrategy(ctx: ChunkRenderStrategyContext): ChunkRenderStrategyKind;
|
|
581
|
+
|
|
582
|
+
export declare interface SceneCollectionPrefabRef {
|
|
583
|
+
sourceId: string;
|
|
584
|
+
prefabName: string;
|
|
585
|
+
/**
|
|
586
|
+
* 在 source 内的索引(等价 atlas 的 atlasCoords;UI 上以 0-based 列出)。
|
|
587
|
+
*/
|
|
588
|
+
index: number;
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
export declare const TILE_FRAG_SHADER = "#version 300 es\nprecision highp float;\n\nin vec2 vTexCoord;\nout vec4 fragColor;\n\nuniform sampler2D uTexture;\nuniform vec4 uModulate;\n\nvoid main() {\n vec4 sampled = texture(uTexture, vTexCoord);\n fragColor = sampled * uModulate;\n if (fragColor.a < 0.01) discard;\n}\n";
|
|
592
|
+
|
|
593
|
+
export declare const TILE_SHADER_SOURCES: TileShaderSources;
|
|
594
|
+
|
|
595
|
+
/**
|
|
596
|
+
* Tile mesh shader 源码(G3)。
|
|
597
|
+
*
|
|
598
|
+
* PIXI v8 用 ProgramSource + Geometry,程序员手工写 GLSL 即可。这里 vert/frag
|
|
599
|
+
* 走 packed vertex attribute,flip/transpose 在 vertex 阶段通过 mat2 完成。
|
|
600
|
+
*
|
|
601
|
+
* Attribute 布局(每 vertex 32 bytes):
|
|
602
|
+
* aPosition vec2 (8B) cell 左上 + 局部偏移
|
|
603
|
+
* aTexCoord vec2 (8B) atlas UV 0..1
|
|
604
|
+
* aFlags vec4 (16B) [flipH, flipV, transpose, animPhase]
|
|
605
|
+
*/
|
|
606
|
+
export declare const TILE_VERT_SHADER = "#version 300 es\nprecision highp float;\n\nin vec2 aPosition;\nin vec2 aTexCoord;\nin vec4 aFlags;\n\nuniform mat3 uProjectionMatrix;\nuniform mat3 uWorldTransformMatrix;\n\nout vec2 vTexCoord;\n\nvoid main() {\n vec3 worldPos = uWorldTransformMatrix * vec3(aPosition, 1.0);\n gl_Position = vec4((uProjectionMatrix * worldPos).xy, 0.0, 1.0);\n\n vec2 uv = aTexCoord;\n if (aFlags.x > 0.5) uv.x = 1.0 - uv.x;\n if (aFlags.y > 0.5) uv.y = 1.0 - uv.y;\n if (aFlags.z > 0.5) { float t = uv.x; uv.x = uv.y; uv.y = t; }\n vTexCoord = uv;\n}\n";
|
|
607
|
+
|
|
608
|
+
export declare class TileAnimationDriver {
|
|
609
|
+
private animations;
|
|
610
|
+
private lastFrameIdxByKey;
|
|
611
|
+
loadFromTileset(raw: TilesetDocumentRaw): void;
|
|
612
|
+
get animationCount(): number;
|
|
613
|
+
/** True when (slot,col,row) is the source tile of an animation in this driver. */
|
|
614
|
+
isAnimatedSource(slot: number, col: number, row: number): boolean;
|
|
615
|
+
advance(nowMs: number): AdvanceResult;
|
|
616
|
+
reset(): void;
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
export declare interface TileAnimationFrame {
|
|
620
|
+
col: number;
|
|
621
|
+
row: number;
|
|
622
|
+
durationMs: number;
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
export declare interface TileAnimationKey {
|
|
626
|
+
sourceSlot: number;
|
|
627
|
+
col: number;
|
|
628
|
+
row: number;
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
/**
|
|
632
|
+
* Tilemap 渲染组件。
|
|
633
|
+
*
|
|
634
|
+
* v1 (Phaser-style, 静态): 通过 `tileset` + `layers[].data[][]` 渲染。
|
|
635
|
+
* v2 (Godot-style, chunked): 通过 `tilemapRef` + `layersV2[].cellData.chunks` 渲染。
|
|
636
|
+
*
|
|
637
|
+
* System 通过有无 `tilemapRef` 判断走哪条路径。两条路径不共存于同一实例。
|
|
19
638
|
*/
|
|
20
639
|
export declare class Tilemap extends Component<TilemapParams> {
|
|
21
640
|
static componentName: string;
|
|
@@ -28,12 +647,93 @@ export declare class Tilemap extends Component<TilemapParams> {
|
|
|
28
647
|
renderTileWidth?: number;
|
|
29
648
|
renderTileHeight?: number;
|
|
30
649
|
layers: TilemapLayer[];
|
|
650
|
+
tilemapRef: string;
|
|
651
|
+
mapOrigin?: {
|
|
652
|
+
x: number;
|
|
653
|
+
y: number;
|
|
654
|
+
};
|
|
655
|
+
cellSize?: {
|
|
656
|
+
width: number;
|
|
657
|
+
height: number;
|
|
658
|
+
};
|
|
659
|
+
layersV2?: TileMapLayerV2[];
|
|
660
|
+
collisionEnabled?: boolean;
|
|
661
|
+
navigationEnabled?: boolean;
|
|
662
|
+
animationEnabled?: boolean;
|
|
663
|
+
renderStrategy?: 'sprite' | 'mesh' | 'auto';
|
|
31
664
|
init(obj?: TilemapParams): void;
|
|
32
665
|
}
|
|
33
666
|
|
|
667
|
+
export declare const TILEMAP_BODY_SOURCE_REGISTRY: BodySourceRegistryImpl;
|
|
668
|
+
|
|
669
|
+
/** Probe 名称常量,与 ADR-0018 §4.6 表对齐。 */
|
|
670
|
+
export declare const TILEMAP_PROBE_NAMES: {
|
|
671
|
+
readonly DIRTY_REBUILD_MS: "tilemap.dirtyRebuild.ms";
|
|
672
|
+
readonly CULL_CHECK_MS: "tilemap.cullCheck.ms";
|
|
673
|
+
readonly ANIM_TICK_MS: "tilemap.animTick.ms";
|
|
674
|
+
readonly DRAWCALLS_COUNT: "tilemap.drawcalls.count";
|
|
675
|
+
readonly DRAWCALLS_BY_ATLAS: "tilemap.drawcalls.byAtlas";
|
|
676
|
+
readonly PHYSICS_REBAKE_MS: "tilemap.physicsRebake.ms";
|
|
677
|
+
readonly GPU_UPLOAD_MS: "tilemap.gpuUpload.ms";
|
|
678
|
+
readonly GPU_UPLOAD_BYTES: "tilemap.gpuUpload.bytes";
|
|
679
|
+
readonly AUTOTILE_MS: "tilemap.autotile.ms";
|
|
680
|
+
readonly PATCH_APPLY_MS: "tilemap.patchApply.ms";
|
|
681
|
+
readonly DIRTY_PENDING: "tilemap.dirty.pending";
|
|
682
|
+
readonly DIRTY_FRAMES_BEHIND: "tilemap.dirty.framesBehind";
|
|
683
|
+
readonly BODIES_TOTAL: "tilemap.bodies.total";
|
|
684
|
+
readonly BODIES_CREATED: "tilemap.bodies.created";
|
|
685
|
+
readonly BODIES_DESTROYED: "tilemap.bodies.destroyed";
|
|
686
|
+
/**
|
|
687
|
+
* ChunkRenderStrategy dispatch counters(P1-3, ADR-0018 §Phase 4).
|
|
688
|
+
* 每构建一个 chunk emit 一次,分别记录 sprite / mesh / mesh-降级-sprite 的次数。
|
|
689
|
+
*/
|
|
690
|
+
readonly STRATEGY_SPRITE_COUNT: "tilemap.strategy.sprite.count";
|
|
691
|
+
readonly STRATEGY_MESH_COUNT: "tilemap.strategy.mesh.count";
|
|
692
|
+
readonly STRATEGY_MESH_FALLBACK_COUNT: "tilemap.strategy.meshFallback.count";
|
|
693
|
+
/**
|
|
694
|
+
* SceneCollection cell skip counter(P1-4, ADR-0018 §H2).
|
|
695
|
+
* 当 TileMap chunk 内含 sceneCollection source 的 cell 时,runtime 暂时跳过(不渲染),
|
|
696
|
+
* 每跳过一次累加 1。配合每条 record 一次性 console.warn,提示需要 prefab placeholder 实现。
|
|
697
|
+
*/
|
|
698
|
+
readonly SCENECOLLECTION_SKIPPED_COUNT: "tilemap.sceneCollection.skipped.count";
|
|
699
|
+
/**
|
|
700
|
+
* Viewport culling hits counter(C-2, ADR-0018 §Phase 4)。
|
|
701
|
+
* 每次 buildChunksForLayer 跳过一个 off-screen chunk 时累加 1。
|
|
702
|
+
* 当前 record-level `cullingBoundsHint` 由 host 注入(可选),未注入时该 probe 永远为 0。
|
|
703
|
+
* 真正的 camera-driven viewport 接入留下 cycle(参考 RendererSystem.application.renderer.view)。
|
|
704
|
+
*/
|
|
705
|
+
readonly CULL_HITS_COUNT: "tilemap.cull.hits";
|
|
706
|
+
/**
|
|
707
|
+
* Mode-switch failure counter(T-L2, Phase L)。
|
|
708
|
+
* 当 handleChange 内部 v1↔v2 mode 切换时,新 mode 的 asset 加载失败导致旧 mode 已 teardown
|
|
709
|
+
* 又 build 不出来的情况:record.mode='unknown',probe 累加 1。host 看到 >0 表示 tilemap 资源
|
|
710
|
+
* 异常,需要诊断 tilemapRef/tileset 引用是否有效。
|
|
711
|
+
*/
|
|
712
|
+
readonly MODE_SWITCH_FAILED_COUNT: "tilemap.modeSwitch.failed";
|
|
713
|
+
/**
|
|
714
|
+
* Animation tick error counter(T-N1, Phase N)。
|
|
715
|
+
*
|
|
716
|
+
* update() 内每帧 advance 每个 animation driver。某个 driver advance / 后续 sprite swap
|
|
717
|
+
* throw 时,本 probe +1 并 console.error 之,但不影响其他 entity 的 tick(try/catch 局部
|
|
718
|
+
* 包裹,外层 try/finally 确保 ANIM_TICK_MS endTiming 一定被调)。host 看到该 probe >0 表示
|
|
719
|
+
* tilemap 有 entity 的 animation pipeline 异常,需要诊断。
|
|
720
|
+
*/
|
|
721
|
+
readonly ANIM_TICK_ERROR_COUNT: "tilemap.animTick.error.count";
|
|
722
|
+
/**
|
|
723
|
+
* WebGL context lost counter(T-N2, Phase N)。
|
|
724
|
+
*
|
|
725
|
+
* Eva runtime 监听 canvas 的 `webglcontextlost`,触发时本 probe +1,并把 record-level
|
|
726
|
+
* `contextLost = true` 暂停 tilemap update tick;`webglcontextrestored` 时清掉该标志。
|
|
727
|
+
* host 看到 >0 即知 WebGL 异常,通常需要在 restored 后 force re-add tilemap component
|
|
728
|
+
* 重新建几何。
|
|
729
|
+
*/
|
|
730
|
+
readonly CONTEXT_LOST_COUNT: "tilemap.context.lost";
|
|
731
|
+
};
|
|
732
|
+
|
|
34
733
|
/**
|
|
35
734
|
* 单个 Tilemap layer 的描述。
|
|
36
735
|
*
|
|
736
|
+
* Phaser-style 静态 tilemap(v1 老路径):
|
|
37
737
|
* - `data` 为二维数组,行优先(row-major):data[row][col]。
|
|
38
738
|
* - tile id `0` 表示空格,不渲染;> 0 的 id 会按 `(id - 1)` 索引到 tileset 的第 N 个 tile。
|
|
39
739
|
* - `offsetX/offsetY` 在 layer 级别整体偏移(等价 Phaser createLayer(... ,x,y))。
|
|
@@ -52,44 +752,331 @@ export declare interface TilemapLayer {
|
|
|
52
752
|
tint?: number;
|
|
53
753
|
}
|
|
54
754
|
|
|
755
|
+
export declare interface TileMapLayerV2 {
|
|
756
|
+
id: string;
|
|
757
|
+
name?: string;
|
|
758
|
+
enabled?: boolean;
|
|
759
|
+
visible?: boolean;
|
|
760
|
+
locked?: boolean;
|
|
761
|
+
modulate?: string;
|
|
762
|
+
opacity?: number;
|
|
763
|
+
zIndex?: number;
|
|
764
|
+
yOrigin?: 'topLeft' | 'center';
|
|
765
|
+
ySort?: boolean;
|
|
766
|
+
ySortOriginPx?: number;
|
|
767
|
+
collisionEnabled?: boolean;
|
|
768
|
+
navigationEnabled?: boolean;
|
|
769
|
+
animationEnabled?: boolean;
|
|
770
|
+
cellData: ChunkedCellData;
|
|
771
|
+
}
|
|
772
|
+
|
|
55
773
|
export declare interface TilemapParams {
|
|
56
774
|
/** Tileset 图像资源 key(对应 DSL assets 中的 image 资源)。 */
|
|
57
|
-
tileset
|
|
775
|
+
tileset?: string;
|
|
58
776
|
/** 单个 tile 在 tileset 中的宽度。 */
|
|
59
|
-
tileWidth
|
|
777
|
+
tileWidth?: number;
|
|
60
778
|
/** 单个 tile 在 tileset 中的高度。 */
|
|
61
|
-
tileHeight
|
|
62
|
-
/**
|
|
63
|
-
* Tileset 横向有几列 tile。Tileset 图像总宽 ≥ tilesetColumns * tileWidth。
|
|
64
|
-
* 如果不传,会使用 tileset 图实际尺寸 / tileWidth 推断。
|
|
65
|
-
*/
|
|
779
|
+
tileHeight?: number;
|
|
66
780
|
tilesetColumns?: number;
|
|
67
|
-
/** Tileset 内部 tile 之间的间距,默认 0。 */
|
|
68
781
|
tilesetSpacing?: number;
|
|
69
|
-
/** Tileset 内部 tile 与图像边缘的 margin,默认 0。 */
|
|
70
782
|
tilesetMargin?: number;
|
|
71
|
-
/** 渲染时的 tile 显示宽度;不传则与 tileWidth 一致(用于切片放大)。 */
|
|
72
783
|
renderTileWidth?: number;
|
|
73
|
-
/** 渲染时的 tile 显示高度。 */
|
|
74
784
|
renderTileHeight?: number;
|
|
75
|
-
|
|
76
|
-
layers
|
|
785
|
+
layers?: TilemapLayer[];
|
|
786
|
+
/** 当存在时,System 走 chunked 路径,忽略 tileset/layers 老字段。 */
|
|
787
|
+
tilemapRef?: string;
|
|
788
|
+
mapOrigin?: {
|
|
789
|
+
x: number;
|
|
790
|
+
y: number;
|
|
791
|
+
};
|
|
792
|
+
/** 单 cell 像素;默认从 tileset 文档的 tileSize 派生。 */
|
|
793
|
+
cellSize?: {
|
|
794
|
+
width: number;
|
|
795
|
+
height: number;
|
|
796
|
+
};
|
|
797
|
+
layersV2?: TileMapLayerV2[];
|
|
798
|
+
collisionEnabled?: boolean;
|
|
799
|
+
navigationEnabled?: boolean;
|
|
800
|
+
animationEnabled?: boolean;
|
|
801
|
+
renderStrategy?: 'sprite' | 'mesh' | 'auto';
|
|
802
|
+
}
|
|
803
|
+
|
|
804
|
+
export declare interface TileMapStaticBodyHostBuildResult {
|
|
805
|
+
bodies: BodyDefinition[];
|
|
806
|
+
/** Per-cell body count summary for diagnostics + perf probe `tilemap.bodies.total` gauge. */
|
|
807
|
+
totalBodyCount: number;
|
|
808
|
+
/** Bodies grouped by layerId (from BodyDefinition.metadata.layerId). */
|
|
809
|
+
bodiesByLayerId: Map<string, BodyDefinition[]>;
|
|
810
|
+
}
|
|
811
|
+
|
|
812
|
+
export declare interface TileMapStaticBodyInput {
|
|
813
|
+
/** 已 hydrate 的 chunked cells:`chunkKey → Int32Array(256)`。 */
|
|
814
|
+
chunksByKey: Record<string, Int32Array>;
|
|
815
|
+
/** TileSet alt tile 的 physics 数据。 */
|
|
816
|
+
physicsByCellKey: Map<string, Array<{
|
|
817
|
+
layerId: string;
|
|
818
|
+
polygons: Array<{
|
|
819
|
+
points: Array<{
|
|
820
|
+
x: number;
|
|
821
|
+
y: number;
|
|
822
|
+
}>;
|
|
823
|
+
origin?: "center" | "topLeft";
|
|
824
|
+
}>;
|
|
825
|
+
oneWay?: boolean;
|
|
826
|
+
friction?: number;
|
|
827
|
+
restitution?: number;
|
|
828
|
+
}>>;
|
|
829
|
+
cellWidth: number;
|
|
830
|
+
cellHeight: number;
|
|
831
|
+
mapOriginX: number;
|
|
832
|
+
mapOriginY: number;
|
|
833
|
+
cache: DecompositionCache;
|
|
77
834
|
}
|
|
78
835
|
|
|
79
836
|
export declare class TilemapSystem extends Renderer {
|
|
80
837
|
static systemName: string;
|
|
81
838
|
name: string;
|
|
82
839
|
private records;
|
|
840
|
+
/** Animation driver per Tilemap entity(只有 v2 路径有 animation,v1 不用)。 */
|
|
841
|
+
private animationDrivers;
|
|
842
|
+
/**
|
|
843
|
+
* Perf probe sink (ADR-0013 + ADR-0018 §4.6).
|
|
844
|
+
* Resolved from `game.perfProbes` in init(); null when host did not install probes —
|
|
845
|
+
* all helper methods become no-ops, no overhead in production builds without perf.
|
|
846
|
+
*/
|
|
847
|
+
private probes;
|
|
848
|
+
/**
|
|
849
|
+
* T-N2 (Phase N):tab visibility / WebGL context loss state。
|
|
850
|
+
* - `isHidden`:document.visibilityState === 'hidden' 时为 true,update() early return
|
|
851
|
+
* - `contextLost`:webglcontextlost 事件触发为 true;webglcontextrestored 清回 false
|
|
852
|
+
* - listener 引用保留以便 destroy 时 detach(避免内存泄漏)
|
|
853
|
+
*/
|
|
854
|
+
private isHidden;
|
|
855
|
+
private contextLost;
|
|
856
|
+
private visibilityListener?;
|
|
857
|
+
private contextLostListener?;
|
|
858
|
+
private contextRestoredListener?;
|
|
859
|
+
/** T-N2:已 install handlers 的 canvas 引用,destroy 时 detach 用。 */
|
|
860
|
+
private canvasWithCtxListeners;
|
|
83
861
|
renderSystem: RendererSystem;
|
|
84
862
|
rendererManager: RendererManager;
|
|
85
863
|
containerManager: ContainerManager;
|
|
86
864
|
init(): void;
|
|
865
|
+
/**
|
|
866
|
+
* T-N2 (Phase N):安装 visibility / WebGL context-loss listener。
|
|
867
|
+
*
|
|
868
|
+
* 安装姿势:
|
|
869
|
+
* - visibility:`document.visibilitychange` → 更新 `isHidden`
|
|
870
|
+
* - context loss:`canvas.webglcontextlost` → 设 `contextLost=true` + probe;
|
|
871
|
+
* `canvas.webglcontextrestored` → 清回 false
|
|
872
|
+
*
|
|
873
|
+
* 失败容忍:任何环境异常(jsdom 不支持某些 listener / renderSystem 还没初始化 application)
|
|
874
|
+
* 都静默 catch,不让 init 因此崩溃。
|
|
875
|
+
*/
|
|
876
|
+
private installVisibilityHandlers;
|
|
877
|
+
/**
|
|
878
|
+
* T-N2:卸载 visibility / context-loss listener,destroy() 调用以避免内存泄漏。
|
|
879
|
+
*/
|
|
880
|
+
private uninstallVisibilityHandlers;
|
|
881
|
+
/** Late probe attach — host can call this after `installPerfProbes` if init order isn't right. */
|
|
882
|
+
attachPerfProbes(probes: PerfProbeRegistry | null): void;
|
|
883
|
+
/**
|
|
884
|
+
* T-L7 (Phase L) public API:host 注入 viewport culling hint。
|
|
885
|
+
*
|
|
886
|
+
* - bounds 非 null:更新 record.cullingBoundsHint,下次 build 时 buildChunksForLayer 会
|
|
887
|
+
* 跳过不相交的 chunk。
|
|
888
|
+
* - null:清除 hint(等价于不剔除任何 chunk)。
|
|
889
|
+
*
|
|
890
|
+
* 本方法只更新字段,不强制重建。host 想立刻生效有两种姿势:
|
|
891
|
+
* 1. 调用后通过 `component.layersV2 = layersV2.slice()` 触发 observer rebuild
|
|
892
|
+
* 2. 调 `invalidateChunks` 标记 dirty 让 rAF flush 时按新 hint rebuild
|
|
893
|
+
* 这样 setHint 是 O(1),呼应性能预算。
|
|
894
|
+
*/
|
|
895
|
+
setCullingBoundsHint(gameObjectId: number, bounds: {
|
|
896
|
+
minX: number;
|
|
897
|
+
minY: number;
|
|
898
|
+
maxX: number;
|
|
899
|
+
maxY: number;
|
|
900
|
+
} | null): void;
|
|
901
|
+
/**
|
|
902
|
+
* T-L4 (Phase L) public API:host 标记若干 chunk dirty,触发 rAF flush 增量重建。
|
|
903
|
+
*
|
|
904
|
+
* 触发场景:layer paint stroke 完成后 host 知道哪些 chunkKey 被改了,调本方法即可。
|
|
905
|
+
* 比 prop=layersV2 整体 reassign 高效得多(整 layer rebuild O(visibleChunks) → O(stroke)).
|
|
906
|
+
*
|
|
907
|
+
* 流程:
|
|
908
|
+
* 1. 把 chunkKeys 累加到 record.dirtyChunkKeys.get(layerId)
|
|
909
|
+
* 2. emit DIRTY_PENDING gauge(总 size)
|
|
910
|
+
* 3. 如果还没 scheduled,启动一次 rAF tick 在下一帧调 flushDirtyChunks
|
|
911
|
+
*
|
|
912
|
+
* 调用方应保证 chunkKey 形态与 cellData.chunks key 一致(如 "0,0")。未知 chunkKey
|
|
913
|
+
* 在 flush 时被静默忽略(已在 cellData.chunks 内会被处理;否则跳过)。
|
|
914
|
+
*/
|
|
915
|
+
invalidateChunks(gameObjectId: number, layerId: string, chunkKeys: string[]): void;
|
|
916
|
+
/**
|
|
917
|
+
* T-L4 (Phase L):rAF callback;只 rebuild record.dirtyChunkKeys 内 chunk,不影响其他 chunk。
|
|
918
|
+
*
|
|
919
|
+
* 本方法是 public 供测试调用,但生产路径只走 invalidateChunks scheduled trigger。
|
|
920
|
+
* 行为:
|
|
921
|
+
* - 找到 component 的 layersV2 layer for layerId
|
|
922
|
+
* - 对每个 dirty chunkKey:destroy 旧 chunkContainer + 重新 populate
|
|
923
|
+
* - emit DIRTY_FRAMES_BEHIND counter+1(本帧 flush 了 N 个 chunk 即"延迟一帧")
|
|
924
|
+
* - 清空 dirtyChunkKeys + 把 DIRTY_PENDING gauge 归零
|
|
925
|
+
*/
|
|
926
|
+
flushDirtyChunks(gameObjectId: number): void;
|
|
927
|
+
private probeBegin;
|
|
928
|
+
private probeEnd;
|
|
929
|
+
private probeCount;
|
|
930
|
+
private probeGauge;
|
|
87
931
|
rendererUpdate(_gameObject: GameObject): void;
|
|
932
|
+
/**
|
|
933
|
+
* Eva.js update 调用(每帧)— 推进 v2 path animation tick。
|
|
934
|
+
* 任何 tile 切到新 frame 时,标记对应 chunk dirty,下一帧重建。
|
|
935
|
+
* v1 路径不参与(没 animation 元数据)。
|
|
936
|
+
*
|
|
937
|
+
* T-N1 (Phase N) hardening:
|
|
938
|
+
* - 每个 driver advance 包在内层 try/catch:一个 entity 的 animation pipeline 抛错
|
|
939
|
+
* 不影响其他 entity 的 tick(continue 到下一个);失败计入 ANIM_TICK_ERROR_COUNT probe
|
|
940
|
+
* 并 console.error 留诊断。
|
|
941
|
+
* - 外层 try/finally 包整段 hot path:保证 probeEnd(ANIM_TICK_MS) 一定 pair probeBegin,
|
|
942
|
+
* 不会因为内层逻辑泄漏 throw 导致 timing 计 inFlight 永远不释放。
|
|
943
|
+
*
|
|
944
|
+
* T-N2 (Phase N) hardening:
|
|
945
|
+
* - tab hidden 或 WebGL context lost 时直接 early return,不浪费 CPU,且避免 context lost
|
|
946
|
+
* 期间渲染调用堆栈抛错。
|
|
947
|
+
*/
|
|
948
|
+
update(_frame: unknown): void;
|
|
88
949
|
componentChanged(changed: ComponentChanged): Promise<void>;
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
950
|
+
private handleAdd;
|
|
951
|
+
/**
|
|
952
|
+
* v1 path:load tileset texture + buildLayersV1。被 handleAdd 与 handleChange(mode upgrade)共用。
|
|
953
|
+
*
|
|
954
|
+
* 调用方负责:
|
|
955
|
+
* - 在调用前设置 record.mode = 'v1'
|
|
956
|
+
* - 在调用前 increaseAsyncId 拿到 asyncId
|
|
957
|
+
* - record 在 records[gameObjectId] 已就位
|
|
958
|
+
*
|
|
959
|
+
* 本方法负责:
|
|
960
|
+
* - resource.getResource(tileset)
|
|
961
|
+
* - asyncId 校验(swap 期间 ref 被替换则中断)
|
|
962
|
+
* - 错误日志
|
|
963
|
+
* - 把 baseTexture 写回 record + buildLayersV1 + requestRedraw
|
|
964
|
+
*/
|
|
965
|
+
private ensureV1Built;
|
|
966
|
+
/**
|
|
967
|
+
* v2 path:load tileset doc + atlas textures + animation driver + buildLayersV2。
|
|
968
|
+
* 被 handleAdd 与 handleChange(mode upgrade / tilemapRef swap)共用。
|
|
969
|
+
*
|
|
970
|
+
* 调用方负责:
|
|
971
|
+
* - 在调用前设置 record.mode = 'v2'
|
|
972
|
+
* - 在调用前 increaseAsyncId 拿到 asyncId
|
|
973
|
+
* - 在调用前已 tearDown 旧 mode 的产物(如果是 mode upgrade)
|
|
974
|
+
*/
|
|
975
|
+
private ensureV2Built;
|
|
976
|
+
/**
|
|
977
|
+
* Editor preview 的 PIXI ticker 在 edit 模式被冻结。Tilemap mount/hot-swap 完成时
|
|
978
|
+
* 主动 trigger 一帧让 chunk 立即可见。preserveDrawingBuffer:true 后单次 render 即可
|
|
979
|
+
* 定格(见 plugin-renderer/lib/System.ts createApplication 注释)。
|
|
980
|
+
*/
|
|
981
|
+
private requestRedraw;
|
|
982
|
+
private handleChange;
|
|
983
|
+
private handleRemove;
|
|
984
|
+
private detectMode;
|
|
985
|
+
private loadV1Texture;
|
|
986
|
+
private tearDownChildrenV1;
|
|
987
|
+
private buildLayersV1;
|
|
988
|
+
private loadV2Tileset;
|
|
989
|
+
private loadAtlasTextures;
|
|
990
|
+
private tearDownChildrenV2;
|
|
991
|
+
private buildLayersV2;
|
|
992
|
+
private buildChunksForLayer;
|
|
993
|
+
/**
|
|
994
|
+
* 尝试用 mesh path 渲染 chunk(P1-3)。
|
|
995
|
+
*
|
|
996
|
+
* 当前实现策略:
|
|
997
|
+
* - 先检查 isMeshPathAvailable():当 false(本 cycle 默认),直接返回 false 让上层降级。
|
|
998
|
+
* - 当 true(后续 cycle 接入真实 shader 时):调 buildChunkMesh,把结果 add 到 chunkContainer。
|
|
999
|
+
*
|
|
1000
|
+
* 出错 / 返回空容器一律视为不可用,返回 false 让 buildChunksForLayer 走 sprite 路径。
|
|
1001
|
+
* 这样 "mesh path is dead code" 的局面变成 "mesh path 已 wired,降级有 probe 记录"。
|
|
1002
|
+
*/
|
|
1003
|
+
private tryBuildMeshChunk;
|
|
1004
|
+
private populateChunkSprites;
|
|
1005
|
+
private getAtlasFrameTexture;
|
|
92
1006
|
destroy(): void;
|
|
93
1007
|
}
|
|
94
1008
|
|
|
1009
|
+
export declare interface TilesetChunkRebuildDiff {
|
|
1010
|
+
addedSources: TilesetSourceRaw[];
|
|
1011
|
+
removedSourceIds: string[];
|
|
1012
|
+
changedSourceIds: string[];
|
|
1013
|
+
addedTilesByKey: Set<string>;
|
|
1014
|
+
removedTilesByKey: Set<string>;
|
|
1015
|
+
changedTilesByKey: Set<string>;
|
|
1016
|
+
}
|
|
1017
|
+
|
|
1018
|
+
/**
|
|
1019
|
+
* @deprecated Use `TilesetChunkRebuildDiff`. Alias kept for transitional
|
|
1020
|
+
* compatibility; will be removed once consumers migrate.
|
|
1021
|
+
*/
|
|
1022
|
+
export declare type TilesetDiff = TilesetChunkRebuildDiff;
|
|
1023
|
+
|
|
1024
|
+
/**
|
|
1025
|
+
* TileSet 外链 .tileset.json 在运行时的 minimal type shape。
|
|
1026
|
+
*
|
|
1027
|
+
* 为避免反向依赖 libs/dsl,这里独立声明;与 libs/dsl/src/types/tileset.ts 的 disk schema 同形。
|
|
1028
|
+
*/
|
|
1029
|
+
export declare interface TilesetDocumentRaw {
|
|
1030
|
+
kind: 'tileset';
|
|
1031
|
+
schemaVersion: 1;
|
|
1032
|
+
name: string;
|
|
1033
|
+
version?: string;
|
|
1034
|
+
tileSize: {
|
|
1035
|
+
width: number;
|
|
1036
|
+
height: number;
|
|
1037
|
+
};
|
|
1038
|
+
gridMode?: 'square' | 'isometric' | 'halfOffsetSquare' | 'hexagon';
|
|
1039
|
+
sources: TilesetSourceRaw[];
|
|
1040
|
+
}
|
|
1041
|
+
|
|
1042
|
+
declare type TilesetSourceRaw = {
|
|
1043
|
+
kind: 'atlas';
|
|
1044
|
+
id: string;
|
|
1045
|
+
textureAsset: string;
|
|
1046
|
+
regionSize: {
|
|
1047
|
+
width: number;
|
|
1048
|
+
height: number;
|
|
1049
|
+
};
|
|
1050
|
+
margins?: {
|
|
1051
|
+
x: number;
|
|
1052
|
+
y: number;
|
|
1053
|
+
};
|
|
1054
|
+
separation?: {
|
|
1055
|
+
x: number;
|
|
1056
|
+
y: number;
|
|
1057
|
+
};
|
|
1058
|
+
usePadding?: boolean;
|
|
1059
|
+
tiles: AtlasTileRaw[];
|
|
1060
|
+
} | {
|
|
1061
|
+
kind: 'sceneCollection';
|
|
1062
|
+
id: string;
|
|
1063
|
+
prefabRefs: string[];
|
|
1064
|
+
};
|
|
1065
|
+
|
|
1066
|
+
/**
|
|
1067
|
+
* 包成 PIXI.GlProgram options 形式 — host 用 `new Program({glProgram: ...})` 创建。
|
|
1068
|
+
*/
|
|
1069
|
+
export declare interface TileShaderSources {
|
|
1070
|
+
vertex: string;
|
|
1071
|
+
fragment: string;
|
|
1072
|
+
}
|
|
1073
|
+
|
|
1074
|
+
/**
|
|
1075
|
+
* 把局部 polygon 平移到目标 cell 的世界坐标。
|
|
1076
|
+
* Phase 3 在 chunk rebuild 时调用,把 cached convex parts 复用到任意 cell 位置。
|
|
1077
|
+
*/
|
|
1078
|
+
export declare function translateConvexParts(parts: ConvexPart[], dx: number, dy: number): ConvexPart[];
|
|
1079
|
+
|
|
1080
|
+
export declare function unpackCell(packed: number): CellRecord;
|
|
1081
|
+
|
|
95
1082
|
export { }
|