@yali-engine/world 0.0.0-stage → 0.12.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.
@@ -0,0 +1,159 @@
1
+ import type { BlobCache } from './cache.ts';
2
+ /** "YCEL", little-endian. */
3
+ export declare const CELL_MAGIC = 1279607641;
4
+ export declare const CELL_VERSION = 2;
5
+ /** A mesh as the archive stores it (the render plugin's `MeshData` without LODs or skins). */
6
+ export interface ArchiveMesh {
7
+ readonly positions: Float32Array;
8
+ readonly normals: Float32Array;
9
+ readonly uvs?: Float32Array | null;
10
+ readonly indices: Uint32Array;
11
+ }
12
+ /** A material by value (the standard PBR knobs). */
13
+ export interface ArchiveMaterial {
14
+ readonly baseColor: readonly [number, number, number, number];
15
+ readonly roughness: number;
16
+ readonly metalness?: number;
17
+ }
18
+ /** An entity: a mesh and a material at a world transform (f64 position). */
19
+ export interface ArchiveInstance {
20
+ readonly mesh: number;
21
+ readonly material: number;
22
+ readonly t: readonly [number, number, number];
23
+ readonly r?: readonly [number, number, number, number];
24
+ readonly s?: number;
25
+ }
26
+ /** A light in the world (ADR-0207): what `render.Light` takes, at a world transform (f64 position). */
27
+ export interface ArchiveLight {
28
+ readonly kind: 'point' | 'spot';
29
+ /** Linear RGB, 0–1. */
30
+ readonly color: readonly [number, number, number];
31
+ readonly intensity: number;
32
+ /** Metres. */
33
+ readonly range: number;
34
+ /** A spot's cone, radians (inner, outer half-angles). */
35
+ readonly inner?: number;
36
+ readonly outer?: number;
37
+ readonly t: readonly [number, number, number];
38
+ /** A spot shines along its −Z, rotated by this quaternion. */
39
+ readonly r?: readonly [number, number, number, number];
40
+ }
41
+ /** What `writeCellArchive` cuts into cells. */
42
+ export interface WorldInput {
43
+ /** Cell size, metres (default 128, DESIGN §15). */
44
+ readonly cell?: number;
45
+ /** The world's origin (f64; default the origin): cell (0, 0)'s corner. */
46
+ readonly origin?: readonly [number, number, number];
47
+ readonly meshes: readonly ArchiveMesh[];
48
+ readonly materials: readonly ArchiveMaterial[];
49
+ readonly instances: readonly ArchiveInstance[];
50
+ /** Lights, cut into cells by position like entities (ADR-0207). */
51
+ readonly lights?: readonly ArchiveLight[];
52
+ }
53
+ /** A blob's entry in the table of contents. */
54
+ export interface BlobEntry {
55
+ /** SHA-256 of its bytes, the first 16 bytes in hex: the same content, the same id, stored once. */
56
+ readonly id: string;
57
+ readonly offset: number;
58
+ readonly length: number;
59
+ /** `records`: a cell's entities and lights (v2, ADR-0211), Float32 rows. */
60
+ readonly kind: 'mesh' | 'records';
61
+ }
62
+ /** A cell's entry: its index, the blobs its entities use, and the entities (position relative to the cell's corner). */
63
+ export interface CellEntry {
64
+ readonly x: number;
65
+ readonly z: number;
66
+ readonly blobs: readonly number[];
67
+ /** v2 (ADR-0211): the blob holding the cell's rows (entities then lights), and how many of each. */
68
+ readonly records?: number;
69
+ readonly instanceCount?: number;
70
+ readonly lightCount?: number;
71
+ /** v1 only: per entity: blob, material, tx, ty, tz (from the corner), rx, ry, rz, rw, s. */
72
+ readonly instances?: readonly (readonly number[])[];
73
+ /** The cell's bounds relative to its corner (min xyz, max xyz): what streaming and culling test. */
74
+ readonly bounds: readonly number[];
75
+ /** Per light (absent in archives without lights): kind (0 point, 1 spot), r, g, b, intensity, range, inner, outer,
76
+ * tx, ty, tz (from the corner), rx, ry, rz, rw. */
77
+ readonly lights?: readonly (readonly number[])[];
78
+ }
79
+ export interface CellToc {
80
+ readonly version: number;
81
+ readonly cell: number;
82
+ readonly origin: readonly [number, number, number];
83
+ readonly materials: readonly ArchiveMaterial[];
84
+ readonly blobs: readonly BlobEntry[];
85
+ readonly cells: readonly CellEntry[];
86
+ }
87
+ /** A mesh's blob: magic, vertex and index counts, whether it has UVs, then positions, normals, (UVs), indices. */
88
+ export declare function encodeMesh(m: ArchiveMesh): Uint8Array<ArrayBuffer>;
89
+ /** `encodeMesh`'s blob back to arrays (views on a copy aligned for them). */
90
+ export declare function decodeMesh(bytes: Uint8Array): ArchiveMesh;
91
+ /**
92
+ * Cuts `world` into cells by each entity's position and writes the archive. Meshes are stored once each (by content), only
93
+ * those some cell uses.
94
+ */
95
+ export declare function writeCellArchive(world: WorldInput): Promise<Uint8Array<ArrayBuffer>>;
96
+ /** Reads bytes [start, end) of the archive (an HTTP `Range` request, a file, a test buffer). */
97
+ export type RangeRead = (start: number, end: number) => Promise<Uint8Array>;
98
+ /** `RangeRead` over HTTP: `Range: bytes=start-(end−1)`; a server that ignores Range (200, whole file) is refused by name. */
99
+ export declare function httpRange(url: string, init?: RequestInit): RangeRead;
100
+ /** What `loadCell` returns: the cell's meshes (by blob index), its entities with world positions, its corner. */
101
+ export interface LoadedCell {
102
+ readonly x: number;
103
+ readonly z: number;
104
+ /** The cell's corner (f64, world). */
105
+ readonly corner: readonly [number, number, number];
106
+ readonly meshes: ReadonlyMap<number, ArchiveMesh>;
107
+ /** Per entity: its blob (mesh), material, world position (f64), rotation, scale. */
108
+ readonly instances: readonly {
109
+ blob: number;
110
+ material: number;
111
+ t: [number, number, number];
112
+ r: [number, number, number, number];
113
+ s: number;
114
+ }[];
115
+ /** The cell's lights at world positions (ADR-0207; empty for an archive without lights). */
116
+ readonly lights: readonly {
117
+ kind: 'point' | 'spot';
118
+ color: [number, number, number];
119
+ intensity: number;
120
+ range: number;
121
+ inner: number;
122
+ outer: number;
123
+ t: [number, number, number];
124
+ r: [number, number, number, number];
125
+ }[];
126
+ }
127
+ /** How `CellArchive.open` reads. */
128
+ export interface ArchiveOptions {
129
+ /** Blobs read before, by content id (`opfsCache()`, `memoryCache()`; ADR-0207): checked before the network. */
130
+ readonly cache?: BlobCache;
131
+ }
132
+ /**
133
+ * An archive opened by its header and table of contents (two reads); cells load on demand, their missing blobs fetched in
134
+ * coalesced ranges and kept (`dropCell` releases a cell's own).
135
+ *
136
+ * @example
137
+ * const world = await CellArchive.open(httpRange('/worlds/coast.cells'));
138
+ * const cell = await world.loadCell(0, -1);
139
+ */
140
+ export declare class CellArchive {
141
+ #private;
142
+ readonly toc: CellToc;
143
+ /** Ranges read so far, and their bytes (for budgets and tests). */
144
+ reads: number;
145
+ bytesRead: number;
146
+ /** Blobs found in the cache, and their bytes (ADR-0207). */
147
+ cacheHits: number;
148
+ cacheBytes: number;
149
+ private constructor();
150
+ static open(read: RangeRead, options?: ArchiveOptions): Promise<CellArchive>;
151
+ /** The cell holding a world point, as [x, z] (whether or not the archive has it). */
152
+ cellAt(x: number, z: number): [number, number];
153
+ /** Whether the archive holds cell (x, z). */
154
+ has(x: number, z: number): boolean;
155
+ /** Cell (x, z): its blobs not yet held are read in as few ranges as gaps under 64 KB allow. */
156
+ loadCell(x: number, z: number): Promise<LoadedCell>;
157
+ /** Releases the meshes only cell (x, z) used among the cells still `kept` (a set of "x,z" keys). */
158
+ dropCell(x: number, z: number, kept: ReadonlySet<string>): void;
159
+ }
@@ -0,0 +1,393 @@
1
+ // The cell archive (M3 increment 1, ADR-0201; DESIGN §15): a world cut into square cells (128 m by default), stored as
2
+ // one file read by HTTP `Range`, never whole.
3
+ //
4
+ // header (64 bytes) magic "YCEL", version, cell size, the world's origin (f64), where the table of contents is
5
+ // table of contents JSON: materials, blobs (a content id, offset, length, kind) and per cell its blobs and entities
6
+ // blobs content-addressed: a mesh a thousand rocks share is stored once
7
+ //
8
+ // A cell's entities carry their position relative to the cell's corner (f32 is exact there, ADR-0008); the cell's corner
9
+ // is the origin plus its index × the cell size, in f64. The table of contents maps onto a 3D Tiles 1.1 tileset (a tile
10
+ // per cell, its content the cell's blobs) for interchange; that exporter is a later step (the user's decision, M3.md).
11
+ /** "YCEL", little-endian. */
12
+ export const CELL_MAGIC = 0x4c454359;
13
+ export const CELL_VERSION = 2;
14
+ /** Floats an entity takes in a records blob (blob, material, t xyz from the corner, r xyzw, s), and a light. */
15
+ const INSTANCE_FLOATS = 10;
16
+ const LIGHT_FLOATS = 15;
17
+ const HEADER_BYTES = 64;
18
+ /** "YMSH": a mesh blob. */
19
+ const MESH_MAGIC = 0x48534d59;
20
+ function archiveError(code, message, path) {
21
+ return Object.assign(new Error(`${code}: ${message}`), { code, path });
22
+ }
23
+ async function sha256Id(bytes) {
24
+ const digest = new Uint8Array(await crypto.subtle.digest('SHA-256', bytes));
25
+ let hex = '';
26
+ for (const b of digest.subarray(0, 16))
27
+ hex += b.toString(16).padStart(2, '0');
28
+ return hex;
29
+ }
30
+ /** A mesh's blob: magic, vertex and index counts, whether it has UVs, then positions, normals, (UVs), indices. */
31
+ export function encodeMesh(m) {
32
+ const v = m.positions.length / 3;
33
+ const uv = m.uvs && m.uvs.length === v * 2 ? m.uvs : null;
34
+ const bytes = 16 + v * 12 * 2 + (uv ? v * 8 : 0) + m.indices.length * 4;
35
+ const out = new Uint8Array(bytes);
36
+ const u = new Uint32Array(out.buffer, 0, 4);
37
+ u.set([MESH_MAGIC, v, m.indices.length, uv ? 1 : 0]);
38
+ let o = 16;
39
+ for (const a of uv ? [m.positions, m.normals, uv] : [m.positions, m.normals]) {
40
+ out.set(new Uint8Array(a.buffer, a.byteOffset, a.byteLength), o);
41
+ o += a.byteLength;
42
+ }
43
+ out.set(new Uint8Array(m.indices.buffer, m.indices.byteOffset, m.indices.byteLength), o);
44
+ return out;
45
+ }
46
+ /** `encodeMesh`'s blob back to arrays (views on a copy aligned for them). */
47
+ export function decodeMesh(bytes) {
48
+ const b = bytes.byteOffset % 4 === 0 ? bytes : bytes.slice();
49
+ const u = new Uint32Array(b.buffer, b.byteOffset, 4);
50
+ if (u[0] !== MESH_MAGIC)
51
+ throw archiveError('CELL_FORMAT', 'a mesh blob without its YMSH magic', 'blob');
52
+ const [, v, n, hasUv] = u;
53
+ let o = b.byteOffset + 16;
54
+ const take = (count) => {
55
+ const a = new Float32Array(b.buffer, o, count);
56
+ o += count * 4;
57
+ return a;
58
+ };
59
+ const positions = take(v * 3);
60
+ const normals = take(v * 3);
61
+ const uvs = hasUv ? take(v * 2) : null;
62
+ if (o + n * 4 > b.byteOffset + b.byteLength)
63
+ throw archiveError('CELL_FORMAT', `a mesh blob cut off (${v} vertices, ${n} indices)`, 'blob');
64
+ return { positions, normals, uvs, indices: new Uint32Array(b.buffer, o, n) };
65
+ }
66
+ /** A mesh's bounds (min xyz, max xyz) under a uniform scale and rotation: its rotated box's, conservatively a sphere. */
67
+ function meshRadius(m) {
68
+ let r = 0;
69
+ for (let i = 0; i < m.positions.length; i += 3)
70
+ r = Math.max(r, Math.hypot(m.positions[i], m.positions[i + 1], m.positions[i + 2]));
71
+ return r;
72
+ }
73
+ /**
74
+ * Cuts `world` into cells by each entity's position and writes the archive. Meshes are stored once each (by content), only
75
+ * those some cell uses.
76
+ */
77
+ export async function writeCellArchive(world) {
78
+ const cell = world.cell ?? 128;
79
+ if (!(cell > 0))
80
+ throw archiveError('CELL_SIZE', `a cell of ${cell} m`, 'cell');
81
+ const origin = world.origin ?? [0, 0, 0];
82
+ // Blobs by content: identical meshes share one.
83
+ const blobs = [];
84
+ const blobOfMesh = [];
85
+ const byId = new Map();
86
+ const radius = [];
87
+ for (let m = 0; m < world.meshes.length; m++) {
88
+ const bytes = encodeMesh(world.meshes[m]);
89
+ const id = await sha256Id(bytes);
90
+ let b = byId.get(id);
91
+ if (b === undefined) {
92
+ b = blobs.length;
93
+ byId.set(id, b);
94
+ blobs.push({ id, bytes });
95
+ }
96
+ blobOfMesh.push(b);
97
+ radius.push(meshRadius(world.meshes[m]));
98
+ }
99
+ // Entities into cells (x, z) by their position.
100
+ const cells = new Map();
101
+ const cellOf = (x, z) => {
102
+ const key = `${x},${z}`;
103
+ let c = cells.get(key);
104
+ if (!c) {
105
+ c = { x, z, instances: [], lights: [], blobs: new Set(), lo: [Infinity, Infinity, Infinity], hi: [-Infinity, -Infinity, -Infinity] };
106
+ cells.set(key, c);
107
+ }
108
+ return c;
109
+ };
110
+ world.instances.forEach((e, i) => {
111
+ if (!(e.mesh >= 0 && e.mesh < world.meshes.length))
112
+ throw archiveError('CELL_INSTANCE', `entity ${i} names mesh ${e.mesh} of ${world.meshes.length}`, `instances.${i}.mesh`);
113
+ if (!(e.material >= 0 && e.material < world.materials.length))
114
+ throw archiveError('CELL_INSTANCE', `entity ${i} names material ${e.material} of ${world.materials.length}`, `instances.${i}.material`);
115
+ const x = Math.floor((e.t[0] - origin[0]) / cell);
116
+ const z = Math.floor((e.t[2] - origin[2]) / cell);
117
+ const c = cellOf(x, z);
118
+ const corner = [origin[0] + x * cell, origin[1], origin[2] + z * cell];
119
+ const local = [e.t[0] - corner[0], e.t[1] - corner[1], e.t[2] - corner[2]];
120
+ const s = e.s ?? 1;
121
+ const r = e.r ?? [0, 0, 0, 1];
122
+ const blob = blobOfMesh[e.mesh];
123
+ c.blobs.add(blob);
124
+ c.instances.push([blob, e.material, ...local, ...r, s]);
125
+ const reach = radius[e.mesh] * s;
126
+ for (let k = 0; k < 3; k++) {
127
+ c.lo[k] = Math.min(c.lo[k], local[k] - reach);
128
+ c.hi[k] = Math.max(c.hi[k], local[k] + reach);
129
+ }
130
+ });
131
+ (world.lights ?? []).forEach((l, i) => {
132
+ if (!(l.range > 0) || !(l.intensity >= 0))
133
+ throw archiveError('CELL_LIGHT', `light ${i} has range ${l.range} and intensity ${l.intensity}`, `lights.${i}`);
134
+ const x = Math.floor((l.t[0] - origin[0]) / cell);
135
+ const z = Math.floor((l.t[2] - origin[2]) / cell);
136
+ const c = cellOf(x, z);
137
+ const local = [l.t[0] - (origin[0] + x * cell), l.t[1] - origin[1], l.t[2] - (origin[2] + z * cell)];
138
+ c.lights.push([l.kind === 'spot' ? 1 : 0, ...l.color, l.intensity, l.range, l.inner ?? 0, l.outer ?? 0, ...local, ...(l.r ?? [0, 0, 0, 1])]);
139
+ // A light reaches its range: the cell's bounds hold it (streaming loads a cell whose light reaches the camera).
140
+ for (let k = 0; k < 3; k++) {
141
+ c.lo[k] = Math.min(c.lo[k], local[k] - l.range);
142
+ c.hi[k] = Math.max(c.hi[k], local[k] + l.range);
143
+ }
144
+ });
145
+ // Lay the blobs out in the order cells first use them (a cell's blobs sit together: fewer, larger ranges); each cell's
146
+ // records blob (v2, ADR-0211) first, so it comes in the same range as its meshes. Its bytes are written once every
147
+ // blob's final place is known (the rows name meshes by it).
148
+ const order = [];
149
+ const placed = new Set();
150
+ const cellList = [...cells.values()].sort((a, b) => a.z - b.z || a.x - b.x);
151
+ const kinds = blobs.map(() => 'mesh');
152
+ const recordsOf = [];
153
+ for (const c of cellList) {
154
+ recordsOf.push(blobs.length);
155
+ order.push(blobs.length);
156
+ blobs.push({ id: '', bytes: new Uint8Array(0) });
157
+ kinds.push('records');
158
+ for (const b of [...c.blobs].sort((p, q) => p - q)) {
159
+ if (!placed.has(b)) {
160
+ placed.add(b);
161
+ order.push(b);
162
+ }
163
+ }
164
+ }
165
+ const newIndex = new Map(order.map((b, i) => [b, i]));
166
+ for (const [k, c] of cellList.entries()) {
167
+ const rows = new Float32Array(c.instances.length * INSTANCE_FLOATS + c.lights.length * LIGHT_FLOATS);
168
+ c.instances.forEach((r, i) => rows.set([newIndex.get(r[0]), ...r.slice(1)], i * INSTANCE_FLOATS));
169
+ c.lights.forEach((l, i) => rows.set(l, c.instances.length * INSTANCE_FLOATS + i * LIGHT_FLOATS));
170
+ const bytes = new Uint8Array(rows.buffer);
171
+ blobs[recordsOf[k]] = { id: await sha256Id(bytes), bytes };
172
+ }
173
+ let offset = 0;
174
+ const entries = order.map((b) => {
175
+ // 16-byte alignment: a decoded mesh's arrays are views on the fetched bytes.
176
+ const e = { id: blobs[b].id, offset, length: blobs[b].bytes.byteLength, kind: kinds[b] };
177
+ offset += Math.ceil(blobs[b].bytes.byteLength / 16) * 16;
178
+ return e;
179
+ });
180
+ const toc = {
181
+ version: CELL_VERSION,
182
+ cell,
183
+ origin: [origin[0], origin[1], origin[2]],
184
+ materials: world.materials,
185
+ blobs: entries,
186
+ cells: cellList.map((c) => ({
187
+ x: c.x,
188
+ z: c.z,
189
+ blobs: [...c.blobs].map((b) => newIndex.get(b)).sort((p, q) => p - q),
190
+ records: newIndex.get(recordsOf[cellList.indexOf(c)]),
191
+ instanceCount: c.instances.length,
192
+ lightCount: c.lights.length,
193
+ bounds: [...c.lo, ...c.hi],
194
+ })),
195
+ };
196
+ const tocBytes = new TextEncoder().encode(JSON.stringify(toc));
197
+ const blobStart = Math.ceil((HEADER_BYTES + tocBytes.byteLength) / 16) * 16;
198
+ const out = new Uint8Array(blobStart + offset);
199
+ const view = new DataView(out.buffer);
200
+ view.setUint32(0, CELL_MAGIC, true);
201
+ view.setUint32(4, CELL_VERSION, true);
202
+ view.setFloat32(8, cell, true);
203
+ view.setUint32(12, cells.size, true);
204
+ for (let k = 0; k < 3; k++)
205
+ view.setFloat64(16 + k * 8, origin[k], true);
206
+ view.setUint32(40, HEADER_BYTES, true);
207
+ view.setUint32(44, tocBytes.byteLength, true);
208
+ view.setUint32(48, blobStart, true);
209
+ out.set(tocBytes, HEADER_BYTES);
210
+ for (const [i, b] of order.entries())
211
+ out.set(blobs[b].bytes, blobStart + entries[i].offset);
212
+ return out;
213
+ }
214
+ /** `RangeRead` over HTTP: `Range: bytes=start-(end−1)`; a server that ignores Range (200, whole file) is refused by name. */
215
+ export function httpRange(url, init) {
216
+ return async (start, end) => {
217
+ const res = await fetch(url, { ...init, headers: { ...init?.headers, Range: `bytes=${start}-${end - 1}` } });
218
+ if (res.status !== 206)
219
+ throw archiveError('CELL_RANGE', `${url} answered ${res.status} to a Range request (206 expected): the server must serve byte ranges`, 'url');
220
+ return new Uint8Array(await res.arrayBuffer());
221
+ };
222
+ }
223
+ /** Requests closer than this many bytes are merged into one range (the bytes between are read and dropped). */
224
+ const COALESCE_GAP = 64 * 1024;
225
+ /**
226
+ * An archive opened by its header and table of contents (two reads); cells load on demand, their missing blobs fetched in
227
+ * coalesced ranges and kept (`dropCell` releases a cell's own).
228
+ *
229
+ * @example
230
+ * const world = await CellArchive.open(httpRange('/worlds/coast.cells'));
231
+ * const cell = await world.loadCell(0, -1);
232
+ */
233
+ export class CellArchive {
234
+ toc;
235
+ #read;
236
+ #blobStart;
237
+ #cells = new Map();
238
+ #meshes = new Map();
239
+ /** Held cells' rows by records blob (v2), released with the cell. */
240
+ #records = new Map();
241
+ /** Ranges read so far, and their bytes (for budgets and tests). */
242
+ reads = 0;
243
+ bytesRead = 0;
244
+ /** Blobs found in the cache, and their bytes (ADR-0207). */
245
+ cacheHits = 0;
246
+ cacheBytes = 0;
247
+ #cache;
248
+ constructor(read, toc, blobStart, cache) {
249
+ this.#read = read;
250
+ this.#cache = cache;
251
+ this.toc = toc;
252
+ this.#blobStart = blobStart;
253
+ for (const c of toc.cells)
254
+ this.#cells.set(`${c.x},${c.z}`, c);
255
+ }
256
+ static async open(read, options = {}) {
257
+ const head = await read(0, HEADER_BYTES);
258
+ if (head.byteLength < HEADER_BYTES)
259
+ throw archiveError('CELL_FORMAT', `a ${head.byteLength}-byte header (64 expected)`, 'header');
260
+ const view = new DataView(head.buffer, head.byteOffset, head.byteLength);
261
+ if (view.getUint32(0, true) !== CELL_MAGIC)
262
+ throw archiveError('CELL_FORMAT', 'not a cell archive (no YCEL magic)', 'header');
263
+ const version = view.getUint32(4, true);
264
+ if (version !== CELL_VERSION && version !== 1)
265
+ throw archiveError('CELL_FORMAT', `version ${version}, this reader knows 1 and ${CELL_VERSION}`, 'header.version');
266
+ const tocAt = view.getUint32(40, true);
267
+ const tocLength = view.getUint32(44, true);
268
+ const blobStart = view.getUint32(48, true);
269
+ const tocBytes = await read(tocAt, tocAt + tocLength);
270
+ const toc = JSON.parse(new TextDecoder().decode(tocBytes));
271
+ const a = new CellArchive(read, toc, blobStart, options.cache ?? null);
272
+ a.reads = 2;
273
+ a.bytesRead = HEADER_BYTES + tocLength;
274
+ return a;
275
+ }
276
+ /** The cell holding a world point, as [x, z] (whether or not the archive has it). */
277
+ cellAt(x, z) {
278
+ return [Math.floor((x - this.toc.origin[0]) / this.toc.cell), Math.floor((z - this.toc.origin[2]) / this.toc.cell)];
279
+ }
280
+ /** Whether the archive holds cell (x, z). */
281
+ has(x, z) {
282
+ return this.#cells.has(`${x},${z}`);
283
+ }
284
+ /** Cell (x, z): its blobs not yet held are read in as few ranges as gaps under 64 KB allow. */
285
+ async loadCell(x, z) {
286
+ const c = this.#cells.get(`${x},${z}`);
287
+ if (!c)
288
+ throw archiveError('CELL_MISSING', `the archive has no cell (${x}, ${z})`, 'cell');
289
+ // The cell's rows (v2): read with its meshes, kept only for this load.
290
+ let rows = null;
291
+ const want = c.records === undefined ? c.blobs : [...c.blobs, c.records];
292
+ const rows0 = c.records === undefined ? undefined : this.#records.get(c.records);
293
+ let missing = want.filter((b) => (b === c.records ? !rows0 : !this.#meshes.has(b))).sort((p, q) => this.toc.blobs[p].offset - this.toc.blobs[q].offset);
294
+ const take = (b, bytes) => {
295
+ if (b === c.records) {
296
+ const al = bytes.byteOffset % 4 === 0 ? bytes : bytes.slice();
297
+ rows = new Float32Array(al.buffer, al.byteOffset, al.byteLength / 4);
298
+ this.#records.set(b, rows);
299
+ }
300
+ else
301
+ this.#meshes.set(b, decodeMesh(bytes));
302
+ };
303
+ // The cache first: a blob is valid wherever its content id matches (and its length, against a torn write).
304
+ const cache = this.#cache;
305
+ if (cache && missing.length) {
306
+ const found = await Promise.all(missing.map((b) => cache.get(this.toc.blobs[b].id)));
307
+ missing = missing.filter((b, i) => {
308
+ const bytes = found[i];
309
+ if (!bytes || bytes.byteLength !== this.toc.blobs[b].length)
310
+ return true;
311
+ take(b, bytes);
312
+ this.cacheHits++;
313
+ this.cacheBytes += bytes.byteLength;
314
+ return false;
315
+ });
316
+ }
317
+ // Coalesce: runs of blobs whose gaps are small become one read.
318
+ let i = 0;
319
+ while (i < missing.length) {
320
+ let j = i;
321
+ const start = this.toc.blobs[missing[i]].offset;
322
+ let end = start + this.toc.blobs[missing[i]].length;
323
+ while (j + 1 < missing.length && this.toc.blobs[missing[j + 1]].offset - end < COALESCE_GAP) {
324
+ j++;
325
+ end = this.toc.blobs[missing[j]].offset + this.toc.blobs[missing[j]].length;
326
+ }
327
+ const bytes = await this.#read(this.#blobStart + start, this.#blobStart + end);
328
+ this.reads++;
329
+ this.bytesRead += bytes.byteLength;
330
+ for (let k = i; k <= j; k++) {
331
+ const b = this.toc.blobs[missing[k]];
332
+ const blob = bytes.subarray(b.offset - start, b.offset - start + b.length);
333
+ take(missing[k], blob);
334
+ if (cache)
335
+ void cache.put(b.id, blob);
336
+ }
337
+ i = j + 1;
338
+ }
339
+ rows ??= rows0 ?? null;
340
+ const corner = [this.toc.origin[0] + x * this.toc.cell, this.toc.origin[1], this.toc.origin[2] + z * this.toc.cell];
341
+ return {
342
+ x,
343
+ z,
344
+ corner,
345
+ meshes: new Map(c.blobs.map((b) => [b, this.#meshes.get(b)])),
346
+ instances: this.#rows(c, rows, 'instances').map((r) => ({
347
+ blob: r[0],
348
+ material: r[1],
349
+ t: [corner[0] + r[2], corner[1] + r[3], corner[2] + r[4]],
350
+ r: [r[5], r[6], r[7], r[8]],
351
+ s: r[9],
352
+ })),
353
+ lights: this.#rows(c, rows, 'lights').map((l) => ({
354
+ kind: l[0] === 1 ? 'spot' : 'point',
355
+ color: [l[1], l[2], l[3]],
356
+ intensity: l[4],
357
+ range: l[5],
358
+ inner: l[6],
359
+ outer: l[7],
360
+ t: [corner[0] + l[8], corner[1] + l[9], corner[2] + l[10]],
361
+ r: [l[11], l[12], l[13], l[14]],
362
+ })),
363
+ };
364
+ }
365
+ /** A cell's entity or light rows: from its records blob (v2) or the table of contents (v1). */
366
+ #rows(c, rows, which) {
367
+ if (c.records === undefined)
368
+ return [...((which === 'instances' ? c.instances : c.lights) ?? [])];
369
+ if (!rows)
370
+ throw archiveError('CELL_FORMAT', `cell (${c.x}, ${c.z})'s records were not read`, 'records');
371
+ const r = rows;
372
+ const n = which === 'instances' ? (c.instanceCount ?? 0) : (c.lightCount ?? 0);
373
+ const w = which === 'instances' ? INSTANCE_FLOATS : LIGHT_FLOATS;
374
+ const at = which === 'instances' ? 0 : (c.instanceCount ?? 0) * INSTANCE_FLOATS;
375
+ return Array.from({ length: n }, (_, i) => Array.from(r.subarray(at + i * w, at + (i + 1) * w)));
376
+ }
377
+ /** Releases the meshes only cell (x, z) used among the cells still `kept` (a set of "x,z" keys). */
378
+ dropCell(x, z, kept) {
379
+ const c = this.#cells.get(`${x},${z}`);
380
+ if (!c)
381
+ return;
382
+ if (c.records !== undefined)
383
+ this.#records.delete(c.records);
384
+ const still = new Set();
385
+ for (const k of kept)
386
+ for (const b of this.#cells.get(k)?.blobs ?? [])
387
+ still.add(b);
388
+ for (const b of c.blobs)
389
+ if (!still.has(b))
390
+ this.#meshes.delete(b);
391
+ }
392
+ }
393
+ //# sourceMappingURL=archive.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"archive.js","sourceRoot":"","sources":["../src/archive.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ /** Where blobs read before are kept, by content id. */
2
+ export interface BlobCache {
3
+ /** The blob's bytes, or null when it is not held (or cannot be read). */
4
+ get(id: string): Promise<Uint8Array | null>;
5
+ /** Keeps a blob; failures (quota, a private window) are swallowed: the cache is an optimisation. */
6
+ put(id: string, bytes: Uint8Array): Promise<void>;
7
+ }
8
+ /**
9
+ * Blobs in memory (tests, or a page that streams the same world twice in one visit).
10
+ *
11
+ * @example
12
+ * const archive = await CellArchive.open(httpRange(url), { cache: memoryCache() });
13
+ */
14
+ export declare function memoryCache(): BlobCache & {
15
+ readonly size: number;
16
+ };
17
+ /**
18
+ * Blobs in the Origin Private File System, under `dir` (default `yali-cells`), one file per content id. Where OPFS is
19
+ * missing (no `navigator.storage.getDirectory`, some private windows) every `get` misses and `put` does nothing.
20
+ *
21
+ * @example
22
+ * const archive = await CellArchive.open(httpRange('/worlds/coast.cells'), { cache: opfsCache() });
23
+ */
24
+ export declare function opfsCache(dir?: string): BlobCache;
package/dist/cache.js ADDED
@@ -0,0 +1,68 @@
1
+ // The cell archive's blob cache (M3 increment 4, ADR-0207): blobs are content-addressed (ADR-0201), so a blob read once
2
+ // is valid for every archive that holds the same id, and a second visit reads it from the device instead of the network.
3
+ // `opfsCache()` keeps them in the Origin Private File System, one file per id; `memoryCache()` is the same in memory.
4
+ /**
5
+ * Blobs in memory (tests, or a page that streams the same world twice in one visit).
6
+ *
7
+ * @example
8
+ * const archive = await CellArchive.open(httpRange(url), { cache: memoryCache() });
9
+ */
10
+ export function memoryCache() {
11
+ const held = new Map();
12
+ return {
13
+ get size() {
14
+ return held.size;
15
+ },
16
+ get: async (id) => held.get(id) ?? null,
17
+ put: async (id, bytes) => {
18
+ held.set(id, bytes.slice());
19
+ },
20
+ };
21
+ }
22
+ /**
23
+ * Blobs in the Origin Private File System, under `dir` (default `yali-cells`), one file per content id. Where OPFS is
24
+ * missing (no `navigator.storage.getDirectory`, some private windows) every `get` misses and `put` does nothing.
25
+ *
26
+ * @example
27
+ * const archive = await CellArchive.open(httpRange('/worlds/coast.cells'), { cache: opfsCache() });
28
+ */
29
+ export function opfsCache(dir = 'yali-cells') {
30
+ let root = null;
31
+ const folder = () => (root ??= (async () => {
32
+ try {
33
+ const top = await navigator.storage.getDirectory();
34
+ return await top.getDirectoryHandle(dir, { create: true });
35
+ }
36
+ catch {
37
+ return null;
38
+ }
39
+ })());
40
+ return {
41
+ get: async (id) => {
42
+ const d = await folder();
43
+ if (!d)
44
+ return null;
45
+ try {
46
+ const f = await (await d.getFileHandle(id)).getFile();
47
+ return new Uint8Array(await f.arrayBuffer());
48
+ }
49
+ catch {
50
+ return null;
51
+ }
52
+ },
53
+ put: async (id, bytes) => {
54
+ const d = await folder();
55
+ if (!d)
56
+ return;
57
+ try {
58
+ const w = await (await d.getFileHandle(id, { create: true })).createWritable();
59
+ await w.write(bytes);
60
+ await w.close();
61
+ }
62
+ catch {
63
+ // Quota or a locked file: the next visit reads the network again.
64
+ }
65
+ },
66
+ };
67
+ }
68
+ //# sourceMappingURL=cache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cache.js","sourceRoot":"","sources":["../src/cache.ts"],"names":[],"mappings":"AAAA,wHAAwH;AACxH,yHAAyH;AACzH,sHAAsH;AAUtH;;;;;GAKG;AACH,MAAM,UAAU,WAAW;IACzB,MAAM,IAAI,GAAG,IAAI,GAAG,EAAsB,CAAC;IAC3C,OAAO;QACL,IAAI,IAAI;YACN,OAAO,IAAI,CAAC,IAAI,CAAC;QACnB,CAAC;QACD,GAAG,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,IAAI;QACvC,GAAG,EAAE,KAAK,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE;YACvB,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC;QAC9B,CAAC;KACF,CAAC;AACJ,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,SAAS,CAAC,GAAG,GAAG,YAAY;IAC1C,IAAI,IAAI,GAAqD,IAAI,CAAC;IAClE,MAAM,MAAM,GAAG,GAAG,EAAE,CAClB,CAAC,IAAI,KAAK,CAAC,KAAK,IAAI,EAAE;QACpB,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,MAAM,SAAS,CAAC,OAAO,CAAC,YAAY,EAAE,CAAC;YACnD,OAAO,MAAM,GAAG,CAAC,kBAAkB,CAAC,GAAG,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;QAC7D,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC,CAAC,EAAE,CAAC,CAAC;IACR,OAAO;QACL,GAAG,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE;YAChB,MAAM,CAAC,GAAG,MAAM,MAAM,EAAE,CAAC;YACzB,IAAI,CAAC,CAAC;gBAAE,OAAO,IAAI,CAAC;YACpB,IAAI,CAAC;gBACH,MAAM,CAAC,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,aAAa,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC;gBACtD,OAAO,IAAI,UAAU,CAAC,MAAM,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC;YAC/C,CAAC;YAAC,MAAM,CAAC;gBACP,OAAO,IAAI,CAAC;YACd,CAAC;QACH,CAAC;QACD,GAAG,EAAE,KAAK,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE;YACvB,MAAM,CAAC,GAAG,MAAM,MAAM,EAAE,CAAC;YACzB,IAAI,CAAC,CAAC;gBAAE,OAAO;YACf,IAAI,CAAC;gBACH,MAAM,CAAC,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,aAAa,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,cAAc,EAAE,CAAC;gBAC/E,MAAM,CAAC,CAAC,KAAK,CAAC,KAAgC,CAAC,CAAC;gBAChD,MAAM,CAAC,CAAC,KAAK,EAAE,CAAC;YAClB,CAAC;YAAC,MAAM,CAAC;gBACP,kEAAkE;YACpE,CAAC;QACH,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,4 @@
1
+ export { type BlobCache, memoryCache, opfsCache } from './cache.ts';
2
+ export { type ArchiveInstance, type ArchiveLight, type ArchiveMaterial, type ArchiveOptions, type ArchiveMesh, type BlobEntry, CELL_MAGIC, CELL_VERSION, CellArchive, type CellEntry, type CellToc, decodeMesh, encodeMesh, httpRange, type LoadedCell, type RangeRead, type WorldInput, writeCellArchive } from './archive.ts';
3
+ export { CellStreamer, type StreamerOptions, type StreamStep } from './streamer.ts';
4
+ export { type WorkBudget, WorkQueue, type WorkRun, type WorkTask } from './work-queue.ts';
package/dist/index.js ADDED
@@ -0,0 +1,6 @@
1
+ // `@yali-engine/world` (M3, ADR-0201): worlds larger than memory, in cells read by HTTP Range.
2
+ export { memoryCache, opfsCache } from "./cache.js";
3
+ export { CELL_MAGIC, CELL_VERSION, CellArchive, decodeMesh, encodeMesh, httpRange, writeCellArchive } from "./archive.js";
4
+ export { CellStreamer } from "./streamer.js";
5
+ export { WorkQueue } from "./work-queue.js";
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,+FAA+F;AAC/F,OAAO,EAAkB,WAAW,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AACpE,OAAO,EAAwH,UAAU,EAAE,YAAY,EAAE,WAAW,EAAgC,UAAU,EAAE,UAAU,EAAE,SAAS,EAAoD,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAChU,OAAO,EAAE,YAAY,EAAyC,MAAM,eAAe,CAAC;AACpF,OAAO,EAAmB,SAAS,EAA+B,MAAM,iBAAiB,CAAC"}
@@ -0,0 +1,74 @@
1
+ import type { CellArchive, CellEntry, LoadedCell } from './archive.ts';
2
+ export interface StreamerOptions {
3
+ /** Cells whose square is this close to the camera (now or predicted) are loaded, metres (default 600). */
4
+ readonly loadRadius?: number;
5
+ /** Cells are let go only this far past the load radius (default one cell): no flicker at the edge. */
6
+ readonly unloadMargin?: number;
7
+ /** Reads in flight at once (default 2). */
8
+ readonly maxInFlight?: number;
9
+ /** Resident blob bytes at most (default 256 MiB): a load that would pass it waits until cells are let go. */
10
+ readonly budgetBytes?: number;
11
+ /** Longest look ahead, seconds (default 3): a slow read never sends the prediction kilometres off. */
12
+ readonly maxLookahead?: number;
13
+ /** How much a cell matters (default 1): its priority is its distance divided by this. */
14
+ readonly importance?: (cell: CellEntry) => number;
15
+ /** Called when the anchor cell changes, with the shift of its corner in metres (f64) and the new anchor. */
16
+ readonly onRebase?: (shift: readonly [number, number, number], anchor: readonly [number, number]) => void;
17
+ /** The clock `update`'s `now` comes from, ms (default `performance.now`): a read's latency is measured on it. */
18
+ readonly clock?: () => number;
19
+ }
20
+ /** What one `update` did (for HUDs and tests; the same object every call). */
21
+ export interface StreamStep {
22
+ /** Reads started by this update. */
23
+ started: number;
24
+ /** Cells added to `unload` by this update. */
25
+ released: number;
26
+ /** A wanted cell waited on the byte budget this update. */
27
+ overBudget: boolean;
28
+ }
29
+ export declare class CellStreamer {
30
+ #private;
31
+ readonly archive: CellArchive;
32
+ readonly loadRadius: number;
33
+ readonly unloadMargin: number;
34
+ readonly maxInFlight: number;
35
+ readonly budgetBytes: number;
36
+ readonly maxLookahead: number;
37
+ /** Loaded cells waiting to be spawned, nearest-first in the order they landed. */
38
+ readonly ready: LoadedCell[];
39
+ /** Cells to despawn, as "x,z" keys; the archive has already let their blobs go. */
40
+ readonly unload: string[];
41
+ /** Cells loaded (spawned or waiting in `ready`), by "x,z". */
42
+ readonly resident: Set<string>;
43
+ /** Smoothed time a cell read takes, ms (measured; starts at 100). */
44
+ latencyMs: number;
45
+ /** Extra look ahead the app adds for its spawn queue's delay, ms (it sets this from its queue's length). */
46
+ spawnDelayMs: number;
47
+ /** The camera's smoothed ground velocity, m/s (x, z). */
48
+ readonly velocity: [number, number];
49
+ /** Where the camera is predicted to be when a read started now lands (x, z). */
50
+ readonly predicted: [number, number];
51
+ /** The cell the camera stands in (moved with hysteresis). */
52
+ readonly anchor: [number, number];
53
+ /** Resident blob bytes (each blob once however many resident cells use it). */
54
+ residentBytes: number;
55
+ readonly step: StreamStep;
56
+ /**
57
+ * @example
58
+ * const streamer = new CellStreamer(await CellArchive.open(httpRange('/worlds/coast.cells')), { loadRadius: 600 });
59
+ * // each frame:
60
+ * streamer.update(camera.target[0], camera.target[2], performance.now());
61
+ * for (const cell of streamer.ready.splice(0)) queue.push(spawnCell(cell));
62
+ */
63
+ constructor(archive: CellArchive, options?: StreamerOptions);
64
+ /** Reads in flight. */
65
+ get inFlight(): number;
66
+ /** The look ahead now, seconds: read latency plus the spawn delay, capped. */
67
+ get lookahead(): number;
68
+ /** The distance from (x, z) to cell c's square (0 inside it), metres. */
69
+ distance(c: CellEntry, x: number, z: number): number;
70
+ /** The blob bytes cell c would add to what is resident. */
71
+ bytesToLoad(c: CellEntry): number;
72
+ /** One scheduling step for the camera's ground point (x, z) at `now` (ms): starts reads, lists cells to let go. */
73
+ update(x: number, z: number, now: number): StreamStep;
74
+ }
@@ -0,0 +1,281 @@
1
+ const LATENCY_START_MS = 100;
2
+ const SMOOTH = 0.2;
3
+ export class CellStreamer {
4
+ archive;
5
+ loadRadius;
6
+ unloadMargin;
7
+ maxInFlight;
8
+ budgetBytes;
9
+ maxLookahead;
10
+ /** Loaded cells waiting to be spawned, nearest-first in the order they landed. */
11
+ ready = [];
12
+ /** Cells to despawn, as "x,z" keys; the archive has already let their blobs go. */
13
+ unload = [];
14
+ /** Cells loaded (spawned or waiting in `ready`), by "x,z". */
15
+ resident = new Set();
16
+ /** Smoothed time a cell read takes, ms (measured; starts at 100). */
17
+ latencyMs = LATENCY_START_MS;
18
+ /** Extra look ahead the app adds for its spawn queue's delay, ms (it sets this from its queue's length). */
19
+ spawnDelayMs = 0;
20
+ /** The camera's smoothed ground velocity, m/s (x, z). */
21
+ velocity = [0, 0];
22
+ /** Where the camera is predicted to be when a read started now lands (x, z). */
23
+ predicted = [0, 0];
24
+ /** The cell the camera stands in (moved with hysteresis). */
25
+ anchor = [0, 0];
26
+ /** Resident blob bytes (each blob once however many resident cells use it). */
27
+ residentBytes = 0;
28
+ step = { started: 0, released: 0, overBudget: false };
29
+ #onRebase;
30
+ #clock;
31
+ #pending = new Set();
32
+ #blobRefs = new Map();
33
+ #byKey = new Map();
34
+ #keys = [];
35
+ #index = new Map();
36
+ /** Per cell (toc order): its square's lowest corner (x, z), its importance, and 0 = out, 1 = being read, 2 = resident. */
37
+ #corner;
38
+ #weight;
39
+ #state;
40
+ /** The best candidates of an update (cell index, priority), at most maxInFlight. */
41
+ #bestCell;
42
+ #bestP;
43
+ #last = null;
44
+ #anchored = false;
45
+ /**
46
+ * @example
47
+ * const streamer = new CellStreamer(await CellArchive.open(httpRange('/worlds/coast.cells')), { loadRadius: 600 });
48
+ * // each frame:
49
+ * streamer.update(camera.target[0], camera.target[2], performance.now());
50
+ * for (const cell of streamer.ready.splice(0)) queue.push(spawnCell(cell));
51
+ */
52
+ constructor(archive, options = {}) {
53
+ this.archive = archive;
54
+ this.loadRadius = options.loadRadius ?? 600;
55
+ this.unloadMargin = options.unloadMargin ?? archive.toc.cell;
56
+ this.maxInFlight = options.maxInFlight ?? 2;
57
+ this.budgetBytes = options.budgetBytes ?? 256 * 1024 * 1024;
58
+ this.maxLookahead = options.maxLookahead ?? 3;
59
+ this.#onRebase = options.onRebase;
60
+ this.#clock = options.clock ?? (() => performance.now());
61
+ if (!(this.loadRadius > 0))
62
+ throw Object.assign(new Error(`STREAM_RADIUS: a load radius of ${this.loadRadius} m; give a positive radius`), { code: 'STREAM_RADIUS', path: 'loadRadius' });
63
+ if (!(this.maxInFlight >= 1))
64
+ throw Object.assign(new Error(`STREAM_IN_FLIGHT: maxInFlight ${this.maxInFlight}; at least 1 read must be allowed`), { code: 'STREAM_IN_FLIGHT', path: 'maxInFlight' });
65
+ const cells = archive.toc.cells;
66
+ this.#corner = new Float64Array(cells.length * 2);
67
+ this.#weight = new Float64Array(cells.length);
68
+ this.#state = new Uint8Array(cells.length);
69
+ this.#bestCell = new Int32Array(this.maxInFlight);
70
+ this.#bestP = new Float64Array(this.maxInFlight);
71
+ const importance = options.importance ?? (() => 1);
72
+ cells.forEach((c, i) => {
73
+ const k = `${c.x},${c.z}`;
74
+ this.#byKey.set(k, c);
75
+ this.#index.set(k, i);
76
+ this.#keys.push(k);
77
+ this.#corner[i * 2] = archive.toc.origin[0] + c.x * archive.toc.cell;
78
+ this.#corner[i * 2 + 1] = archive.toc.origin[2] + c.z * archive.toc.cell;
79
+ this.#weight[i] = Math.max(1e-6, importance(c));
80
+ });
81
+ }
82
+ /** Cell i's squared distance from (x, z), m². */
83
+ #d2(i, x, z) {
84
+ const size = this.archive.toc.cell;
85
+ const cx = this.#corner[i * 2];
86
+ const cz = this.#corner[i * 2 + 1];
87
+ const dx = Math.max(cx - x, 0, x - cx - size);
88
+ const dz = Math.max(cz - z, 0, z - cz - size);
89
+ return dx * dx + dz * dz;
90
+ }
91
+ /** Reads in flight. */
92
+ get inFlight() {
93
+ return this.#pending.size;
94
+ }
95
+ /** The look ahead now, seconds: read latency plus the spawn delay, capped. */
96
+ get lookahead() {
97
+ return Math.min(this.maxLookahead, (this.latencyMs + this.spawnDelayMs) / 1000);
98
+ }
99
+ /** The distance from (x, z) to cell c's square (0 inside it), metres. */
100
+ distance(c, x, z) {
101
+ const size = this.archive.toc.cell;
102
+ const cx = this.archive.toc.origin[0] + c.x * size;
103
+ const cz = this.archive.toc.origin[2] + c.z * size;
104
+ const dx = Math.max(cx - x, 0, x - cx - size);
105
+ const dz = Math.max(cz - z, 0, z - cz - size);
106
+ return Math.hypot(dx, dz);
107
+ }
108
+ /** The blob bytes cell c would add to what is resident. */
109
+ bytesToLoad(c) {
110
+ let n = 0;
111
+ for (const b of c.blobs)
112
+ if (!this.#blobRefs.has(b))
113
+ n += this.archive.toc.blobs[b].length;
114
+ return n;
115
+ }
116
+ /** One scheduling step for the camera's ground point (x, z) at `now` (ms): starts reads, lists cells to let go. */
117
+ update(x, z, now) {
118
+ const step = this.step;
119
+ step.started = 0;
120
+ step.released = 0;
121
+ step.overBudget = false;
122
+ this.#track(x, z, now);
123
+ const px = this.predicted[0];
124
+ const pz = this.predicted[1];
125
+ const keep2 = (this.loadRadius + this.unloadMargin) ** 2;
126
+ const load2 = this.loadRadius * this.loadRadius;
127
+ // One pass: let go of resident cells past the margin (now and predicted); keep the most urgent wanted cells.
128
+ const slots = this.maxInFlight - this.#pending.size;
129
+ let found = 0;
130
+ const n = this.#state.length;
131
+ for (let i = 0; i < n; i++) {
132
+ const st = this.#state[i];
133
+ if (st === 1)
134
+ continue;
135
+ const d2 = Math.min(this.#d2(i, x, z), this.#d2(i, px, pz));
136
+ if (st === 2) {
137
+ if (d2 > keep2)
138
+ this.#release(this.#keys[i]);
139
+ continue;
140
+ }
141
+ if (slots <= 0 || d2 > load2)
142
+ continue;
143
+ // Insertion into the few best by priority (distance / importance).
144
+ const pr = Math.sqrt(d2) / this.#weight[i];
145
+ if (found === slots && pr >= this.#bestP[found - 1])
146
+ continue;
147
+ let at = found < slots ? found++ : found - 1;
148
+ while (at > 0 && this.#bestP[at - 1] > pr) {
149
+ this.#bestP[at] = this.#bestP[at - 1];
150
+ this.#bestCell[at] = this.#bestCell[at - 1];
151
+ at--;
152
+ }
153
+ this.#bestP[at] = pr;
154
+ this.#bestCell[at] = i;
155
+ }
156
+ // Start them in order while the byte budget allows.
157
+ for (let k = 0; k < found; k++) {
158
+ const c = this.archive.toc.cells[this.#bestCell[k]];
159
+ if (this.residentBytes + this.bytesToLoad(c) > this.budgetBytes) {
160
+ step.overBudget = true;
161
+ break;
162
+ }
163
+ this.#start(c, this.#keys[this.#bestCell[k]], now);
164
+ step.started++;
165
+ }
166
+ return step;
167
+ }
168
+ #track(x, z, now) {
169
+ const last = this.#last;
170
+ if (last) {
171
+ const dt = (now - last[2]) / 1000;
172
+ if (dt > 0) {
173
+ const vx = (x - last[0]) / dt;
174
+ const vz = (z - last[1]) / dt;
175
+ // A jump (a teleport, a long stall) resets the velocity instead of predicting from it.
176
+ if (Math.hypot(x - last[0], z - last[1]) > this.archive.toc.cell * 4 || dt > 1) {
177
+ this.velocity[0] = 0;
178
+ this.velocity[1] = 0;
179
+ }
180
+ else {
181
+ this.velocity[0] += (vx - this.velocity[0]) * SMOOTH;
182
+ this.velocity[1] += (vz - this.velocity[1]) * SMOOTH;
183
+ }
184
+ }
185
+ last[0] = x;
186
+ last[1] = z;
187
+ last[2] = now;
188
+ }
189
+ else
190
+ this.#last = [x, z, now];
191
+ const t = this.lookahead;
192
+ this.predicted[0] = x + this.velocity[0] * t;
193
+ this.predicted[1] = z + this.velocity[1] * t;
194
+ // The anchor: the cell under the camera, moved once the camera is a quarter cell past its edge.
195
+ const size = this.archive.toc.cell;
196
+ const o = this.archive.toc.origin;
197
+ const ax = Math.floor((x - o[0]) / size);
198
+ const az = Math.floor((z - o[2]) / size);
199
+ if (!this.#anchored) {
200
+ this.anchor[0] = ax;
201
+ this.anchor[1] = az;
202
+ this.#anchored = true;
203
+ return;
204
+ }
205
+ const fx = (x - o[0]) / size - this.anchor[0];
206
+ const fz = (z - o[2]) / size - this.anchor[1];
207
+ if (fx < -0.25 || fx > 1.25 || fz < -0.25 || fz > 1.25) {
208
+ const shift = [(ax - this.anchor[0]) * size, 0, (az - this.anchor[1]) * size];
209
+ this.anchor[0] = ax;
210
+ this.anchor[1] = az;
211
+ this.#onRebase?.(shift, this.anchor);
212
+ }
213
+ }
214
+ #start(c, key, now) {
215
+ this.#pending.add(key);
216
+ this.#state[this.#index.get(key)] = 1;
217
+ // Its blobs count against the budget from the moment the read starts.
218
+ this.#hold(c, 1);
219
+ this.archive
220
+ .loadCell(c.x, c.z)
221
+ .then((cell) => {
222
+ const took = this.#clock() - now;
223
+ this.latencyMs += (took - this.latencyMs) * SMOOTH;
224
+ this.#pending.delete(key);
225
+ this.#state[this.#index.get(key)] = 0;
226
+ // Still wanted? A cell the camera left while it was read is let go at once.
227
+ const keep = this.loadRadius + this.unloadMargin;
228
+ const last = this.#last;
229
+ if (this.distance(c, last[0], last[1]) > keep && this.distance(c, this.predicted[0], this.predicted[1]) > keep) {
230
+ this.#hold(c, -1);
231
+ this.archive.dropCell(c.x, c.z, this.#kept());
232
+ return;
233
+ }
234
+ this.resident.add(key);
235
+ this.#state[this.#index.get(key)] = 2;
236
+ this.ready.push(cell);
237
+ })
238
+ .catch((e) => {
239
+ this.#pending.delete(key);
240
+ this.#state[this.#index.get(key)] = 0;
241
+ this.#hold(c, -1);
242
+ console.error(e);
243
+ });
244
+ }
245
+ #release(key) {
246
+ const c = this.#byKey.get(key);
247
+ this.resident.delete(key);
248
+ this.#state[this.#index.get(key)] = 0;
249
+ this.#hold(c, -1);
250
+ this.archive.dropCell(c.x, c.z, this.#kept());
251
+ // A cell still waiting to be spawned is simply never spawned.
252
+ const i = this.ready.findIndex((r) => r.x === c.x && r.z === c.z);
253
+ if (i >= 0)
254
+ this.ready.splice(i, 1);
255
+ else
256
+ this.unload.push(key);
257
+ this.step.released++;
258
+ }
259
+ /** The cells whose blobs must stay: resident ones and those being read (a read in flight may already count on them). */
260
+ #kept() {
261
+ const k = new Set(this.resident);
262
+ for (const p of this.#pending)
263
+ k.add(p);
264
+ return k;
265
+ }
266
+ #hold(c, by) {
267
+ for (const b of c.blobs) {
268
+ const n = (this.#blobRefs.get(b) ?? 0) + by;
269
+ if (n === 0) {
270
+ this.#blobRefs.delete(b);
271
+ this.residentBytes -= this.archive.toc.blobs[b].length;
272
+ }
273
+ else {
274
+ if (by === 1 && n === 1)
275
+ this.residentBytes += this.archive.toc.blobs[b].length;
276
+ this.#blobRefs.set(b, n);
277
+ }
278
+ }
279
+ }
280
+ }
281
+ //# sourceMappingURL=streamer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"streamer.js","sourceRoot":"","sources":["../src/streamer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,38 @@
1
+ /** A task: each `next()` does one small step and yields the bytes that step uploads. */
2
+ export type WorkTask = Iterator<number, unknown, undefined>;
3
+ export interface WorkBudget {
4
+ /** Main-thread time per frame, ms (default 1, ADR-0026's upload budget). */
5
+ readonly ms?: number;
6
+ /** Bytes handed to the GPU per frame (default 512 KiB: ~0.3 ms of `writeBuffer` under 4 MiB, ADR-0026). */
7
+ readonly bytes?: number;
8
+ }
9
+ /** What the last `run` did (the same object every call). */
10
+ export interface WorkRun {
11
+ ms: number;
12
+ bytes: number;
13
+ steps: number;
14
+ }
15
+ /**
16
+ * Runs queued tasks a step at a time inside a per-frame budget; the step that crosses it is the last of the frame (a
17
+ * step overshoots by at most itself, so keep steps small). At least one step runs per frame, so work always advances.
18
+ *
19
+ * @example
20
+ * const queue = new WorkQueue({ ms: 1 });
21
+ * queue.push(spawnCell(cell)); // a generator: yield after each mesh and each 64 entities
22
+ * // each frame:
23
+ * queue.run();
24
+ */
25
+ export declare class WorkQueue {
26
+ #private;
27
+ readonly ms: number;
28
+ readonly bytes: number;
29
+ readonly last: WorkRun;
30
+ /** The longest `run`, ms (for budget checks). */
31
+ worstMs: number;
32
+ constructor(budget?: WorkBudget, now?: () => number);
33
+ /** Tasks not yet finished. */
34
+ get length(): number;
35
+ push(task: WorkTask): void;
36
+ /** Runs steps until this frame's time or byte budget is spent or the queue is empty. */
37
+ run(): WorkRun;
38
+ }
@@ -0,0 +1,68 @@
1
+ // Work inside a frame budget (M3 increment 3, ADR-0202): a cell's spawn is cut into small steps (a mesh, a batch of
2
+ // entities) and each frame runs steps until its time or byte budget is spent, so a cell never lands as one long frame.
3
+ // A step is one `next()` of an iterator; the value it yields is the bytes it handed the GPU (0 when none): mesh uploads
4
+ // are paid the frame after they are added (`render.upload`), so they are budgeted by bytes, not by the time `next()` took.
5
+ /**
6
+ * Runs queued tasks a step at a time inside a per-frame budget; the step that crosses it is the last of the frame (a
7
+ * step overshoots by at most itself, so keep steps small). At least one step runs per frame, so work always advances.
8
+ *
9
+ * @example
10
+ * const queue = new WorkQueue({ ms: 1 });
11
+ * queue.push(spawnCell(cell)); // a generator: yield after each mesh and each 64 entities
12
+ * // each frame:
13
+ * queue.run();
14
+ */
15
+ export class WorkQueue {
16
+ ms;
17
+ bytes;
18
+ last = { ms: 0, bytes: 0, steps: 0 };
19
+ /** The longest `run`, ms (for budget checks). */
20
+ worstMs = 0;
21
+ #tasks = [];
22
+ #head = 0;
23
+ #now;
24
+ constructor(budget = {}, now = () => performance.now()) {
25
+ this.ms = budget.ms ?? 1;
26
+ this.bytes = budget.bytes ?? 512 * 1024;
27
+ this.#now = now;
28
+ }
29
+ /** Tasks not yet finished. */
30
+ get length() {
31
+ return this.#tasks.length - this.#head;
32
+ }
33
+ push(task) {
34
+ this.#tasks.push(task);
35
+ }
36
+ /** Runs steps until this frame's time or byte budget is spent or the queue is empty. */
37
+ run() {
38
+ const t0 = this.#now();
39
+ const r = this.last;
40
+ r.bytes = 0;
41
+ r.steps = 0;
42
+ while (this.#head < this.#tasks.length) {
43
+ const step = this.#tasks[this.#head].next();
44
+ r.steps++;
45
+ if (step.done) {
46
+ this.#head++;
47
+ }
48
+ else
49
+ r.bytes += step.value;
50
+ if (this.#now() - t0 >= this.ms || r.bytes >= this.bytes)
51
+ break;
52
+ }
53
+ // Compact once the finished prefix is long (no per-frame allocation).
54
+ if (this.#head > 32 && this.#head * 2 > this.#tasks.length) {
55
+ this.#tasks.splice(0, this.#head);
56
+ this.#head = 0;
57
+ }
58
+ else if (this.#head === this.#tasks.length && this.#head > 0) {
59
+ this.#tasks.length = 0;
60
+ this.#head = 0;
61
+ }
62
+ r.ms = this.#now() - t0;
63
+ if (r.ms > this.worstMs)
64
+ this.worstMs = r.ms;
65
+ return r;
66
+ }
67
+ }
68
+ //# sourceMappingURL=work-queue.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"work-queue.js","sourceRoot":"","sources":["../src/work-queue.ts"],"names":[],"mappings":"AAAA,oHAAoH;AACpH,uHAAuH;AACvH,wHAAwH;AACxH,2HAA2H;AAmB3H;;;;;;;;;GASG;AACH,MAAM,OAAO,SAAS;IACX,EAAE,CAAS;IACX,KAAK,CAAS;IACd,IAAI,GAAY,EAAE,EAAE,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC;IACvD,iDAAiD;IACjD,OAAO,GAAG,CAAC,CAAC;IACH,MAAM,GAAe,EAAE,CAAC;IACjC,KAAK,GAAG,CAAC,CAAC;IACD,IAAI,CAAe;IAE5B,YAAY,SAAqB,EAAE,EAAE,MAAoB,GAAG,EAAE,CAAC,WAAW,CAAC,GAAG,EAAE;QAC9E,IAAI,CAAC,EAAE,GAAG,MAAM,CAAC,EAAE,IAAI,CAAC,CAAC;QACzB,IAAI,CAAC,KAAK,GAAG,MAAM,CAAC,KAAK,IAAI,GAAG,GAAG,IAAI,CAAC;QACxC,IAAI,CAAC,IAAI,GAAG,GAAG,CAAC;IAClB,CAAC;IAED,8BAA8B;IAC9B,IAAI,MAAM;QACR,OAAO,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC;IACzC,CAAC;IAED,IAAI,CAAC,IAAc;QACjB,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACzB,CAAC;IAED,wFAAwF;IACxF,GAAG;QACD,MAAM,EAAE,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;QACvB,MAAM,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC;QACpB,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC;QACZ,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC;QACZ,OAAO,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC;YACvC,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,CAAC;YAC5C,CAAC,CAAC,KAAK,EAAE,CAAC;YACV,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;gBACd,IAAI,CAAC,KAAK,EAAE,CAAC;YACf,CAAC;;gBAAM,CAAC,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC;YAC7B,IAAI,IAAI,CAAC,IAAI,EAAE,GAAG,EAAE,IAAI,IAAI,CAAC,EAAE,IAAI,CAAC,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK;gBAAE,MAAM;QAClE,CAAC;QACD,sEAAsE;QACtE,IAAI,IAAI,CAAC,KAAK,GAAG,EAAE,IAAI,IAAI,CAAC,KAAK,GAAG,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC;YAC3D,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;YAClC,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC;QACjB,CAAC;aAAM,IAAI,IAAI,CAAC,KAAK,KAAK,IAAI,CAAC,MAAM,CAAC,MAAM,IAAI,IAAI,CAAC,KAAK,GAAG,CAAC,EAAE,CAAC;YAC/D,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC;YACvB,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC;QACjB,CAAC;QACD,CAAC,CAAC,EAAE,GAAG,IAAI,CAAC,IAAI,EAAE,GAAG,EAAE,CAAC;QACxB,IAAI,CAAC,CAAC,EAAE,GAAG,IAAI,CAAC,OAAO;YAAE,IAAI,CAAC,OAAO,GAAG,CAAC,CAAC,EAAE,CAAC;QAC7C,OAAO,CAAC,CAAC;IACX,CAAC;CACF"}
package/package.json CHANGED
@@ -1,6 +1,25 @@
1
1
  {
2
2
  "name": "@yali-engine/world",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
3
+ "version": "0.12.0",
4
+ "description": "Yali worlds: the cell archive (header, table of contents, content-addressed blobs) read by HTTP Range (M3, ADR-0201).",
5
+ "license": "MIT OR Apache-2.0",
6
+ "type": "module",
7
+ "sideEffects": false,
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "default": "./dist/index.js"
12
+ }
13
+ },
14
+ "publishConfig": {
15
+ "access": "public"
16
+ },
17
+ "files": [
18
+ "dist"
19
+ ],
20
+ "dependencies": {},
21
+ "scripts": {
22
+ "typecheck": "tsc -p tsconfig.json",
23
+ "test": "node --experimental-strip-types --no-warnings --test \"test/*.test.ts\""
24
+ }
6
25
  }
package/README.md DELETED
@@ -1,3 +0,0 @@
1
- # Temporary Holding Version
2
-
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.