murow 0.0.72 → 0.1.1
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 +15 -1
- package/dist/cjs/core/binary-codec/binary-codec.js +1 -1
- package/dist/cjs/core/driver/driver.js +1 -1
- package/dist/cjs/core/driver/drivers/immediate.js +1 -1
- package/dist/cjs/core/driver/drivers/raf.js +1 -1
- package/dist/cjs/core/driver/drivers/timeout.js +1 -1
- package/dist/cjs/core/input/index.js +1 -1
- package/dist/cjs/core/input/mouse-look/index.js +1 -0
- package/dist/cjs/core/input/mouse-look/mouse-look.js +1 -0
- package/dist/cjs/core/input/scroll-zoom/index.js +1 -0
- package/dist/cjs/core/input/scroll-zoom/scroll-zoom.js +1 -0
- package/dist/cjs/core/sparse-batcher/sparse-batcher.js +1 -1
- package/dist/cjs/ecs/component.js +1 -1
- package/dist/cjs/ecs/system-builder.js +1 -1
- package/dist/cjs/ecs/world.js +1 -1
- package/dist/cjs/game/loop/loop.js +1 -1
- package/dist/cjs/net/adapters/bun-websocket.js +1 -1
- package/dist/cjs/renderer/base/renderer-3d.js +1 -1
- package/dist/cjs/renderer/prefab-bucket/concrete.js +1 -1
- package/dist/cjs/renderer/prefab-bucket/index.js +1 -1
- package/dist/cjs/renderer/prefab-bucket/parsers.js +1 -1
- package/dist/cjs/renderer/prefab-bucket/specs.js +1 -1
- package/dist/esm/core/binary-codec/binary-codec.js +1 -1
- package/dist/esm/core/driver/drivers/immediate.js +1 -1
- package/dist/esm/core/driver/drivers/raf.js +1 -1
- package/dist/esm/core/driver/drivers/timeout.js +1 -1
- package/dist/esm/core/input/index.js +1 -1
- package/dist/esm/core/input/mouse-look/index.js +1 -0
- package/dist/esm/core/input/mouse-look/mouse-look.js +1 -0
- package/dist/esm/core/input/scroll-zoom/index.js +1 -0
- package/dist/esm/core/input/scroll-zoom/scroll-zoom.js +1 -0
- package/dist/esm/core/sparse-batcher/sparse-batcher.js +1 -1
- package/dist/esm/ecs/component.js +1 -1
- package/dist/esm/ecs/system-builder.js +1 -1
- package/dist/esm/ecs/world.js +1 -1
- package/dist/esm/game/loop/loop.js +1 -1
- package/dist/esm/net/adapters/bun-websocket.js +1 -1
- package/dist/esm/renderer/base/renderer-3d.js +1 -1
- package/dist/esm/renderer/prefab-bucket/concrete.js +1 -1
- package/dist/esm/renderer/prefab-bucket/index.js +1 -1
- package/dist/esm/renderer/prefab-bucket/parsers.js +1 -1
- package/dist/netcode/cjs/index.js +1552 -0
- package/dist/netcode/esm/index.js +1530 -0
- package/dist/netcode/types/client/game-client.d.ts +125 -0
- package/dist/netcode/types/client/index.d.ts +1 -0
- package/dist/netcode/types/client/interpolation-buffer.d.ts +37 -0
- package/dist/netcode/types/client/interpolation-buffer.test.d.ts +1 -0
- package/dist/netcode/types/codec/delta-codec.d.ts +17 -0
- package/dist/netcode/types/codec/delta-codec.test.d.ts +1 -0
- package/dist/netcode/types/codec/index.d.ts +1 -0
- package/dist/netcode/types/components/index.d.ts +1 -0
- package/dist/netcode/types/components/sync-spec.d.ts +43 -0
- package/dist/netcode/types/components/sync-spec.test.d.ts +1 -0
- package/dist/netcode/types/ctx.d.ts +105 -0
- package/dist/netcode/types/ctx.test.d.ts +1 -0
- package/dist/netcode/types/handlers/define-handlers.d.ts +47 -0
- package/dist/netcode/types/handlers/index.d.ts +1 -0
- package/dist/netcode/types/index.d.ts +11 -0
- package/dist/netcode/types/integration.test.d.ts +1 -0
- package/dist/netcode/types/intents/define-intents.d.ts +53 -0
- package/dist/netcode/types/intents/define-intents.test.d.ts +1 -0
- package/dist/netcode/types/intents/index.d.ts +1 -0
- package/dist/netcode/types/network/base.d.ts +120 -0
- package/dist/netcode/types/network/index.d.ts +2 -0
- package/dist/netcode/types/network/transport.d.ts +1 -0
- package/dist/netcode/types/packets/convergence.test.d.ts +1 -0
- package/dist/netcode/types/packets/harness.d.ts +103 -0
- package/dist/netcode/types/packets/index.d.ts +2 -0
- package/dist/netcode/types/packets/intermittent-intents.test.d.ts +1 -0
- package/dist/netcode/types/packets/pathological.test.d.ts +1 -0
- package/dist/netcode/types/packets/peer-interpolation.test.d.ts +1 -0
- package/dist/netcode/types/packets/reordering.test.d.ts +1 -0
- package/dist/netcode/types/packets/virtual-network.d.ts +65 -0
- package/dist/netcode/types/predictions/define-predictions.d.ts +45 -0
- package/dist/netcode/types/predictions/define-predictions.test.d.ts +1 -0
- package/dist/netcode/types/predictions/index.d.ts +1 -0
- package/dist/netcode/types/reconciliation.test.d.ts +1 -0
- package/dist/netcode/types/rpcs/define-rpcs.d.ts +44 -0
- package/dist/netcode/types/rpcs/define-rpcs.test.d.ts +1 -0
- package/dist/netcode/types/rpcs/index.d.ts +1 -0
- package/dist/netcode/types/server/game-server.d.ts +77 -0
- package/dist/netcode/types/server/index.d.ts +2 -0
- package/dist/netcode/types/server/plugins/aoi-grid.d.ts +34 -0
- package/dist/netcode/types/server/plugins/index.d.ts +3 -0
- package/dist/netcode/types/server/plugins/lag-compensation.d.ts +34 -0
- package/dist/netcode/types/server/plugins/plugin.d.ts +24 -0
- package/dist/netcode/types/tick-rate.test.d.ts +1 -0
- package/dist/netcode/types/transports/index.d.ts +1 -0
- package/dist/netcode/types/transports/memory-transport.d.ts +51 -0
- package/dist/netcode/types/types.test.d.ts +1 -0
- package/dist/types/core/binary-codec/binary-codec.d.ts +89 -31
- package/dist/types/core/driver/driver.d.ts +8 -8
- package/dist/types/core/driver/drivers/immediate.d.ts +4 -4
- package/dist/types/core/driver/drivers/raf.d.ts +17 -6
- package/dist/types/core/driver/drivers/timeout.d.ts +4 -4
- package/dist/types/core/input/index.d.ts +2 -0
- package/dist/types/core/input/mouse-look/index.d.ts +1 -0
- package/dist/types/core/input/mouse-look/mouse-look.d.ts +139 -0
- package/dist/types/core/input/scroll-zoom/index.d.ts +1 -0
- package/dist/types/core/input/scroll-zoom/scroll-zoom.d.ts +38 -0
- package/dist/types/ecs/component.d.ts +67 -11
- package/dist/types/ecs/entity-handle.d.ts +5 -5
- package/dist/types/ecs/system-builder.d.ts +13 -0
- package/dist/types/ecs/world.d.ts +72 -4
- package/dist/types/game/loop/loop.d.ts +21 -2
- package/dist/types/net/adapters/bun-websocket.d.ts +19 -3
- package/dist/types/renderer/base/renderer-3d.d.ts +1 -1
- package/dist/types/renderer/prefab-bucket/concrete.d.ts +42 -2
- package/dist/types/renderer/prefab-bucket/index.d.ts +12 -2
- package/dist/types/renderer/prefab-bucket/specs.d.ts +46 -3
- package/dist/types/renderer/types.d.ts +5 -3
- package/dist/webgpu/cjs/index.js +591 -40
- package/dist/webgpu/esm/index.js +591 -40
- package/dist/webgpu/types/3d/renderer.d.ts +111 -5
- package/package.json +6 -1
|
@@ -96,7 +96,7 @@ export declare class EntityHandle {
|
|
|
96
96
|
* const velocityVx = entity.field(Velocity, 'vx');
|
|
97
97
|
*
|
|
98
98
|
* // Direct array access - same as RAW API!
|
|
99
|
-
* transformX[entity.id] += velocityVx[entity.id] *
|
|
99
|
+
* transformX[entity.id] += velocityVx[entity.id] * deltaTime;
|
|
100
100
|
* ```
|
|
101
101
|
*/
|
|
102
102
|
field<T extends object, K extends keyof T>(component: Component<T>, field: K): Float32Array | Int32Array | Uint32Array | Uint16Array | Uint8Array;
|
|
@@ -149,8 +149,8 @@ export declare class EntityHandle {
|
|
|
149
149
|
* const velocity = entity.get(Velocity); // Uses cached data
|
|
150
150
|
*
|
|
151
151
|
* entity
|
|
152
|
-
* .setField(Transform, 'x', transform.x + velocity.vx *
|
|
153
|
-
* .setField(Transform, 'y', transform.y + velocity.vy *
|
|
152
|
+
* .setField(Transform, 'x', transform.x + velocity.vx * deltaTime)
|
|
153
|
+
* .setField(Transform, 'y', transform.y + velocity.vy * deltaTime)
|
|
154
154
|
* .flush();
|
|
155
155
|
* ```
|
|
156
156
|
*/
|
|
@@ -189,8 +189,8 @@ export declare class EntityHandle {
|
|
|
189
189
|
* ```typescript
|
|
190
190
|
* // Mutate fields directly
|
|
191
191
|
* entity.setFields(Transform, function (t) {
|
|
192
|
-
* t.x += velocity.vx *
|
|
193
|
-
* t.y += velocity.vy *
|
|
192
|
+
* t.x += velocity.vx * deltaTime;
|
|
193
|
+
* t.y += velocity.vy * deltaTime;
|
|
194
194
|
* });
|
|
195
195
|
*
|
|
196
196
|
* // Conditional mutation
|
|
@@ -120,10 +120,23 @@ export declare class ExecutableSystem {
|
|
|
120
120
|
private queryMask;
|
|
121
121
|
private conditionPredicate?;
|
|
122
122
|
private proxyEntity;
|
|
123
|
+
/**
|
|
124
|
+
* Indices of queried components that have `__sync` metadata. Cached at
|
|
125
|
+
* construction so `execute()` can flip dirty bits without re-checking
|
|
126
|
+
* each tick. Empty for systems whose query touches no synced components,
|
|
127
|
+
* which keeps the hot path zero-overhead.
|
|
128
|
+
*/
|
|
129
|
+
private syncedComponentIndices;
|
|
123
130
|
constructor(world: World, components: Component<any>[], userCallback: (entity: any, deltaTime: number, world: World) => void, fieldDescs: FieldDesc[], queryMaskKey: string, queryMask: number[], conditionPredicate?: (entity: any) => boolean);
|
|
124
131
|
/**
|
|
125
132
|
* Execute the system for all matching entities.
|
|
126
133
|
*
|
|
134
|
+
* If the system's query includes any synced components, every entity
|
|
135
|
+
* touched by the system is marked dirty for those components after the
|
|
136
|
+
* callback runs (coarse strategy. the network layer assumes any
|
|
137
|
+
* entity that flowed through a system whose query included its synced
|
|
138
|
+
* component may have changed).
|
|
139
|
+
*
|
|
127
140
|
* @param deltaTime - Time delta to pass to system callback
|
|
128
141
|
*/
|
|
129
142
|
execute(deltaTime: number): void;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { ArrayFromField, Schema } from "../core/binary-codec";
|
|
1
2
|
import { Component } from "./component";
|
|
2
3
|
import { ComponentStore } from "./component-store";
|
|
3
4
|
import { EntityHandle } from "./entity-handle";
|
|
@@ -70,6 +71,21 @@ export declare class World extends WorldSystems {
|
|
|
70
71
|
private queryMaskCache;
|
|
71
72
|
private despawnedBuffer;
|
|
72
73
|
private despawnedCount;
|
|
74
|
+
/**
|
|
75
|
+
* Per-component dirty bitmask, indexed by [componentIndex][entity>>>5].
|
|
76
|
+
* `null` for components without `__sync` metadata: no overhead when
|
|
77
|
+
* networking isn't in play. Higher-level packages might read these
|
|
78
|
+
* to build per-peer snapshot deltas.
|
|
79
|
+
*/
|
|
80
|
+
private dirtyBitsByComponent;
|
|
81
|
+
/**
|
|
82
|
+
* Per-component field bundle: a frozen object whose keys are the
|
|
83
|
+
* component's field names and whose values are the same typed-array
|
|
84
|
+
* references returned by `getFieldArray`. Built once at registration,
|
|
85
|
+
* shared forever — `world.fields(C)` returns the same object on every
|
|
86
|
+
* call (zero garbage). Indexed by `component.__worldIndex`.
|
|
87
|
+
*/
|
|
88
|
+
private fieldsByComponent;
|
|
73
89
|
private worldId;
|
|
74
90
|
constructor(config: WorldConfig);
|
|
75
91
|
/**
|
|
@@ -150,6 +166,34 @@ export declare class World extends WorldSystems {
|
|
|
150
166
|
* Invalidate all query caches (called on archetype changes).
|
|
151
167
|
*/
|
|
152
168
|
private invalidateQueryCache;
|
|
169
|
+
/**
|
|
170
|
+
* Mark an entity dirty for a given component index. No-op for
|
|
171
|
+
* components without `__sync` metadata. Called internally by every
|
|
172
|
+
* write path (`add`, `set`, `update`, `system-builder` field setters).
|
|
173
|
+
*/
|
|
174
|
+
markDirty(entity: Entity, componentIndex: number): void;
|
|
175
|
+
/**
|
|
176
|
+
* Test whether an entity is currently marked dirty for a component.
|
|
177
|
+
* Used by snapshot builders.
|
|
178
|
+
*/
|
|
179
|
+
isDirty(entity: Entity, component: Component<any>): boolean;
|
|
180
|
+
/**
|
|
181
|
+
* Clear the dirty bit for an entity/component pair. Called by the
|
|
182
|
+
* snapshot builder after a delta for the entity has been acknowledged
|
|
183
|
+
* by all peers.
|
|
184
|
+
*/
|
|
185
|
+
clearDirty(entity: Entity, component: Component<any>): void;
|
|
186
|
+
/**
|
|
187
|
+
* Iterate dirty entities for a synced component. Calls `cb` for each
|
|
188
|
+
* entity whose dirty bit is set. Returns immediately for unsynced
|
|
189
|
+
* components.
|
|
190
|
+
*/
|
|
191
|
+
forEachDirty(component: Component<any>, cb: (entity: Entity) => void): void;
|
|
192
|
+
/**
|
|
193
|
+
* Clear all dirty bits across all components. Usually the snapshot
|
|
194
|
+
* pipeline clears bits per-entity as it processes them.
|
|
195
|
+
*/
|
|
196
|
+
clearAllDirty(): void;
|
|
153
197
|
/**
|
|
154
198
|
* Add a component to an entity with initial data.
|
|
155
199
|
*/
|
|
@@ -223,8 +267,8 @@ export declare class World extends WorldSystems {
|
|
|
223
267
|
* const t = world.get(entity, Transform);
|
|
224
268
|
* const v = world.get(entity, Velocity);
|
|
225
269
|
* world.update(entity, Transform, {
|
|
226
|
-
* x: t.x + v.vx *
|
|
227
|
-
* y: t.y + v.vy *
|
|
270
|
+
* x: t.x + v.vx * deltaTime,
|
|
271
|
+
* y: t.y + v.vy * deltaTime
|
|
228
272
|
* });
|
|
229
273
|
* }
|
|
230
274
|
* ```
|
|
@@ -289,12 +333,36 @@ export declare class World extends WorldSystems {
|
|
|
289
333
|
* const velocityVy = world.getFieldArray(Velocity, 'vy');
|
|
290
334
|
*
|
|
291
335
|
* for (const entity of world.query(Transform, Velocity)) {
|
|
292
|
-
* transformX[entity] += velocityVx[entity] *
|
|
293
|
-
* transformY[entity] += velocityVy[entity] *
|
|
336
|
+
* transformX[entity] += velocityVx[entity] * deltaTime;
|
|
337
|
+
* transformY[entity] += velocityVy[entity] * deltaTime;
|
|
294
338
|
* }
|
|
295
339
|
* ```
|
|
296
340
|
*/
|
|
297
341
|
getFieldArray<T extends object>(component: Component<T>, fieldName: keyof T): Float32Array | Int32Array | Uint32Array | Uint16Array | Uint8Array;
|
|
342
|
+
/**
|
|
343
|
+
* Get a typed-array bundle for every field of a component.
|
|
344
|
+
*
|
|
345
|
+
* Returns the same frozen object on every call - built once at component
|
|
346
|
+
* registration and shared forever. Each field name maps to its underlying
|
|
347
|
+
* typed array, with the EXACT element type inferred from the schema:
|
|
348
|
+
* `f32 -> Float32Array`, `u8 -> Uint8Array`, `u16 -> Uint16Array`, etc.
|
|
349
|
+
* No casts needed in caller code.
|
|
350
|
+
*
|
|
351
|
+
* Use this when you want RAW-speed per-entity reads/writes without the
|
|
352
|
+
* `world.update({...})` allocation + `for...in` overhead. Bypasses dirty
|
|
353
|
+
* tracking: for networked components, see `ctx.fields()` in `murow/netcode`
|
|
354
|
+
* which auto-marks dirty, or call `world.markDirty(entity, index)` yourself.
|
|
355
|
+
*
|
|
356
|
+
* @example
|
|
357
|
+
* ```ts
|
|
358
|
+
* const pos = world.fields(Position); // pos.x, pos.z typed as Float32Array
|
|
359
|
+
* pos.x[entity] += velocity.x * dt;
|
|
360
|
+
* pos.z[entity] += velocity.z * dt;
|
|
361
|
+
* ```
|
|
362
|
+
*/
|
|
363
|
+
fields<T extends object, S extends Schema<T>>(component: Component<T, S>): Readonly<{
|
|
364
|
+
[K in keyof S]: ArrayFromField<S[K]>;
|
|
365
|
+
}>;
|
|
298
366
|
/**
|
|
299
367
|
* Create an EntityHandle wrapper for fluent API usage.
|
|
300
368
|
*
|
|
@@ -51,8 +51,8 @@ export declare class GameLoop<T extends GameLoopType = DriverType> {
|
|
|
51
51
|
interface GameLoopOptions<T extends GameLoopType> {
|
|
52
52
|
tickRate: number;
|
|
53
53
|
type: T;
|
|
54
|
-
onTick?: (
|
|
55
|
-
onRender?: (
|
|
54
|
+
onTick?: (deltaTime: number, tick: number, input: ReturnType<InputManager["snapshot"]>) => void;
|
|
55
|
+
onRender?: (deltaTime: number, alpha: number, input: ReturnType<InputManager["peek"]>) => void;
|
|
56
56
|
}
|
|
57
57
|
type BaseEvents = [
|
|
58
58
|
[
|
|
@@ -64,6 +64,25 @@ type BaseEvents = [
|
|
|
64
64
|
startedAt: number;
|
|
65
65
|
}
|
|
66
66
|
],
|
|
67
|
+
[
|
|
68
|
+
"sync",
|
|
69
|
+
{
|
|
70
|
+
/**
|
|
71
|
+
* Current tick number.
|
|
72
|
+
*/
|
|
73
|
+
tick: number;
|
|
74
|
+
/**
|
|
75
|
+
* Delta time since the last tick.
|
|
76
|
+
*/
|
|
77
|
+
deltaTime: number;
|
|
78
|
+
/**
|
|
79
|
+
* Input snapshot at the start of the tick.
|
|
80
|
+
*
|
|
81
|
+
* **Only available in client loops.**
|
|
82
|
+
*/
|
|
83
|
+
input: ReturnType<InputManager["snapshot"]>;
|
|
84
|
+
}
|
|
85
|
+
],
|
|
67
86
|
[
|
|
68
87
|
"pre-tick",
|
|
69
88
|
{
|
|
@@ -63,7 +63,10 @@ export declare class BunWebSocketServerTransport implements ServerTransportAdapt
|
|
|
63
63
|
getPeerIds(): string[];
|
|
64
64
|
close(): void;
|
|
65
65
|
/**
|
|
66
|
-
* Internal: Register a new peer
|
|
66
|
+
* Internal: Register a new peer. Records the peer in the internal map
|
|
67
|
+
* but does NOT fire connection handlers: that's `_handlePeerConnection`'s
|
|
68
|
+
* job, called separately by the `open` callback. Splitting registration
|
|
69
|
+
* from notification keeps the handler count to exactly one per connect.
|
|
67
70
|
*/
|
|
68
71
|
_registerPeer(socket: ServerWebSocket<unknown>): string;
|
|
69
72
|
/**
|
|
@@ -76,7 +79,20 @@ export declare class BunWebSocketServerTransport implements ServerTransportAdapt
|
|
|
76
79
|
_handlePeerDisconnection(peerId: string): void;
|
|
77
80
|
_handlePeerConnection(peerId: string): void;
|
|
78
81
|
/**
|
|
79
|
-
* Static factory method to create a Bun WebSocket server
|
|
82
|
+
* Static factory method to create a Bun WebSocket server.
|
|
83
|
+
*
|
|
84
|
+
* @param port - Port to listen on.
|
|
85
|
+
* @param opts - Optional configuration:
|
|
86
|
+
* - `path`: If set, only requests to this URL pathname are upgraded
|
|
87
|
+
* (e.g., `/ws`). Other paths fall through to `fetch`. Defaults to
|
|
88
|
+
* accepting any path.
|
|
89
|
+
* - `fetch`: Handler for non-upgrade HTTP requests on the same port.
|
|
90
|
+
* Useful for serving a static bundle alongside the WS endpoint so
|
|
91
|
+
* the whole app runs on one port. If omitted, non-upgrade requests
|
|
92
|
+
* get a 400 response (matches the previous WS-only behavior).
|
|
80
93
|
*/
|
|
81
|
-
static create(port: number
|
|
94
|
+
static create(port: number, opts?: {
|
|
95
|
+
path?: string;
|
|
96
|
+
fetch?: (req: Request, server: Server<unknown>) => Response | Promise<Response>;
|
|
97
|
+
}): BunWebSocketServerTransport;
|
|
82
98
|
}
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
import { BaseRenderer } from "./renderer";
|
|
5
5
|
import type { Camera3DState, Renderer3DOptions } from "../types";
|
|
6
6
|
export declare abstract class Base3DRenderer extends BaseRenderer<Renderer3DOptions> {
|
|
7
|
-
readonly
|
|
7
|
+
readonly maxInstances: number;
|
|
8
8
|
abstract readonly camera: Camera3DState;
|
|
9
9
|
constructor(canvas: HTMLCanvasElement, options: Renderer3DOptions);
|
|
10
10
|
}
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
* ```
|
|
18
18
|
*/
|
|
19
19
|
import { BasePrefabBucket, type StringOr } from './index';
|
|
20
|
-
import type { Prefab2D, Prefab2DSpec, Prefab3D, Prefab3DSpec, PrefabFor } from './specs';
|
|
20
|
+
import type { CompositePrefab, PartOffset, Prefab2D, Prefab2DSpec, Prefab3D, Prefab3DSpec, PrefabFor } from './specs';
|
|
21
21
|
type SpecForMode<M> = M extends '3d' ? Prefab3DSpec : Prefab2DSpec;
|
|
22
22
|
type PrefabUnionForMode<M> = M extends '3d' ? Prefab3D : Prefab2D;
|
|
23
23
|
/**
|
|
@@ -48,8 +48,48 @@ export declare class PrefabBucket<M extends '2d' | '3d' = '3d', Specs extends Re
|
|
|
48
48
|
* Accepts any string at runtime but autocompletes known ids.
|
|
49
49
|
*/
|
|
50
50
|
get<K extends keyof Specs & string, R = PrefabFor<Specs[K]>>(id: StringOr<K>): R;
|
|
51
|
+
/**
|
|
52
|
+
* Register a named group of part specs. Each part is added as a top-level
|
|
53
|
+
* prefab with id `<groupName>.<partId>` (or `<groupName>.<auto-hex>` when
|
|
54
|
+
* the part omitted `id`). A `composite` prefab is also created at id
|
|
55
|
+
* `groupName`, with the parts wired up via their `offset` for spawning.
|
|
56
|
+
*
|
|
57
|
+
* ```ts
|
|
58
|
+
* bucket.addGroup('campfire', [
|
|
59
|
+
* { type: 'gltf', id: 'logs', src: '/logs.glb' },
|
|
60
|
+
* { type: 'cube', id: 'flame', size: 0.3, offset: { position: [0, 0.3, 0] } },
|
|
61
|
+
* { type: 'cube', size: 0.5, offset: { position: [0, 0.8, 0] } }, // auto id
|
|
62
|
+
* ]);
|
|
63
|
+
*
|
|
64
|
+
* await bucket.load();
|
|
65
|
+
*
|
|
66
|
+
* bucket.get('campfire'); // composite (spawnable as one)
|
|
67
|
+
* bucket.get('campfire.logs'); // the part directly
|
|
68
|
+
* bucket.getGroup('campfire').prefabs; // both parts
|
|
69
|
+
* ```
|
|
70
|
+
*/
|
|
71
|
+
addGroup(name: string, parts: readonly GroupPartInput<M>[]): this;
|
|
72
|
+
/**
|
|
73
|
+
* Look up a group registered via `addGroup`. Returns the parts in order
|
|
74
|
+
* and an `asComposite()` helper that returns the composite prefab created
|
|
75
|
+
* for the group (equivalent to `bucket.get(groupName)`).
|
|
76
|
+
*/
|
|
77
|
+
getGroup(name: string): {
|
|
78
|
+
prefabs: Prefab3D[];
|
|
79
|
+
asComposite(): CompositePrefab;
|
|
80
|
+
};
|
|
51
81
|
}
|
|
82
|
+
/**
|
|
83
|
+
* Part spec accepted by `addGroup`: a regular 3D spec with `id` optional
|
|
84
|
+
* (auto-generated when absent) and a new `offset` field.
|
|
85
|
+
*/
|
|
86
|
+
type GroupPartInput<M extends '2d' | '3d'> = M extends '3d' ? {
|
|
87
|
+
[K in Prefab3DSpec as K['type']]: Omit<K, 'id'> & {
|
|
88
|
+
id?: string;
|
|
89
|
+
offset?: PartOffset;
|
|
90
|
+
};
|
|
91
|
+
}[Prefab3DSpec['type']] : never;
|
|
52
92
|
/** Convenience aliases for explicit mode typing (e.g. function params). */
|
|
53
93
|
export type PrefabBucket2D<Specs extends Record<string, Prefab2DSpec> = {}> = PrefabBucket<'2d', Specs>;
|
|
54
94
|
export type PrefabBucket3D<Specs extends Record<string, Prefab3DSpec> = {}> = PrefabBucket<'3d', Specs>;
|
|
55
|
-
export type { GltfPrefab, GltfSpec, GridPrefab, GridSpec, Prefab2D, Prefab2DSpec, Prefab3D, Prefab3DSpec, PrefabFor, SpritesheetPrefab, SpritesheetSpec, } from './specs';
|
|
95
|
+
export type { CompositePrefab, CompositeSpec, CubePrefab, CubeSpec, GltfPrefab, GltfSpec, GridPrefab, GridSpec, PartOffset, Prefab2D, Prefab2DSpec, Prefab3D, Prefab3DSpec, PrefabFor, SpritesheetPrefab, SpritesheetSpec, } from './specs';
|
|
@@ -58,17 +58,27 @@ export type PrefabParser<Spec extends PrefabSpecBase = PrefabSpecBase, Prefab ex
|
|
|
58
58
|
export type PrefabParserMap<Spec extends PrefabSpecBase, Prefab extends PrefabBase> = Record<string, PrefabParser<Spec, Prefab>>;
|
|
59
59
|
export declare class BasePrefabBucket<M extends PrefabMode = PrefabMode, Spec extends PrefabSpecBase = PrefabSpecBase, Prefab extends PrefabBase = PrefabBase, Specs extends Record<string, Spec> = {}> {
|
|
60
60
|
readonly mode: M;
|
|
61
|
-
/** Shared notification channel
|
|
61
|
+
/** Shared notification channel - see `PrefabBucketEvents`. */
|
|
62
62
|
readonly events: EventSystem<PrefabBucketEvents>;
|
|
63
63
|
private parsers;
|
|
64
64
|
private pending;
|
|
65
65
|
private pendingIds;
|
|
66
66
|
private prefabs;
|
|
67
|
+
/** `groupName -> ordered list of final part ids`. Populated by `addGroup` on subclasses. */
|
|
68
|
+
protected groups: Map<string, string[]>;
|
|
67
69
|
constructor(mode: M, parsers?: PrefabParserMap<Spec, Prefab>);
|
|
68
|
-
/** Add a single spec. Throws if id is a duplicate or if the bucket is already loaded. */
|
|
70
|
+
/** Add a single spec. Throws if id is a duplicate, contains '.', or if the bucket is already loaded. */
|
|
69
71
|
add<const S extends Spec>(spec: S): BasePrefabBucket<M, Spec, Prefab, Specs & {
|
|
70
72
|
[K in S['id']]: S;
|
|
71
73
|
}>;
|
|
74
|
+
/**
|
|
75
|
+
* Internal add that skips the '.' validation. Used by `addGroup` on
|
|
76
|
+
* subclasses to register parts under group-path ids (e.g. `'campfire.logs'`)
|
|
77
|
+
* after the group itself has validated user input.
|
|
78
|
+
*/
|
|
79
|
+
protected addUnchecked<const S extends Spec>(spec: S): BasePrefabBucket<M, Spec, Prefab, Specs & {
|
|
80
|
+
[K in S['id']]: S;
|
|
81
|
+
}>;
|
|
72
82
|
/**
|
|
73
83
|
* Add multiple specs. Validates the whole batch (ids unique, not loaded) before
|
|
74
84
|
* committing, so the bucket never lands in a half-applied state.
|
|
@@ -53,7 +53,35 @@ export interface GridSpec {
|
|
|
53
53
|
/** Optional user-defined sidecar data (scale, speed, gameplay hints, etc). */
|
|
54
54
|
readonly metadata?: Record<string, unknown>;
|
|
55
55
|
}
|
|
56
|
-
|
|
56
|
+
/** Unit cube prefab centered at origin. Use the instance's `scale` to size it. */
|
|
57
|
+
export interface CubeSpec {
|
|
58
|
+
readonly type: 'cube';
|
|
59
|
+
readonly id: string;
|
|
60
|
+
/** Edge length. Defaults to 1. */
|
|
61
|
+
readonly size?: number;
|
|
62
|
+
readonly metadata?: Record<string, unknown>;
|
|
63
|
+
}
|
|
64
|
+
/** Local transform offset applied to a part inside a composite/group at spawn time. */
|
|
65
|
+
export interface PartOffset {
|
|
66
|
+
readonly position?: readonly [number, number, number];
|
|
67
|
+
readonly rotation?: readonly [number, number, number];
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* A prefab that spawns several other prefabs at fixed local offsets. Created
|
|
71
|
+
* by `bucket.addGroup(...)`; not typically written by hand. Spawning a
|
|
72
|
+
* composite instance spawns one child per part, with each part's offset
|
|
73
|
+
* composed onto the instance's position/rotation.
|
|
74
|
+
*/
|
|
75
|
+
export interface CompositeSpec {
|
|
76
|
+
readonly type: 'composite';
|
|
77
|
+
readonly id: string;
|
|
78
|
+
readonly parts: readonly {
|
|
79
|
+
readonly partId: string;
|
|
80
|
+
readonly offset?: PartOffset;
|
|
81
|
+
}[];
|
|
82
|
+
readonly metadata?: Record<string, unknown>;
|
|
83
|
+
}
|
|
84
|
+
export type Prefab3DSpec = GltfSpec | GridSpec | CubeSpec | CompositeSpec;
|
|
57
85
|
/**
|
|
58
86
|
* Map a spec's `animations` tuple to a record-keyed-by-name. Used to type
|
|
59
87
|
* `GltfPrefab.animations` so `prefab.animations.Run` is a string literal
|
|
@@ -134,7 +162,22 @@ export interface GridPrefab<S extends GridSpec = GridSpec> {
|
|
|
134
162
|
readonly lineWidth: number;
|
|
135
163
|
readonly metadata: MetadataOf<S>;
|
|
136
164
|
}
|
|
137
|
-
export
|
|
165
|
+
export interface CubePrefab<S extends CubeSpec = CubeSpec> {
|
|
166
|
+
readonly type: 'cube';
|
|
167
|
+
readonly id: S['id'];
|
|
168
|
+
readonly size: number;
|
|
169
|
+
readonly metadata: MetadataOf<S>;
|
|
170
|
+
}
|
|
171
|
+
export interface CompositePrefab<S extends CompositeSpec = CompositeSpec> {
|
|
172
|
+
readonly type: 'composite';
|
|
173
|
+
readonly id: S['id'];
|
|
174
|
+
readonly parts: readonly {
|
|
175
|
+
readonly partId: string;
|
|
176
|
+
readonly offset?: PartOffset;
|
|
177
|
+
}[];
|
|
178
|
+
readonly metadata: MetadataOf<S>;
|
|
179
|
+
}
|
|
180
|
+
export type Prefab3D = GltfPrefab | GridPrefab | CubePrefab | CompositePrefab;
|
|
138
181
|
export interface SpritesheetSpec {
|
|
139
182
|
readonly type: 'spritesheet';
|
|
140
183
|
readonly id: string;
|
|
@@ -162,5 +205,5 @@ export type Prefab2D = SpritesheetPrefab;
|
|
|
162
205
|
* bucket's `get()` so `bucket.get('minion')` returns `GltfPrefab` directly,
|
|
163
206
|
* not the discriminated union.
|
|
164
207
|
*/
|
|
165
|
-
export type PrefabFor<S> = S extends GltfSpec ? GltfPrefab<S> : S extends GridSpec ? GridPrefab<S> : S extends SpritesheetSpec ? SpritesheetPrefab<S> : never;
|
|
208
|
+
export type PrefabFor<S> = S extends GltfSpec ? GltfPrefab<S> : S extends GridSpec ? GridPrefab<S> : S extends CubeSpec ? CubePrefab<S> : S extends CompositeSpec ? CompositePrefab<S> : S extends SpritesheetSpec ? SpritesheetPrefab<S> : never;
|
|
166
209
|
export {};
|
|
@@ -14,10 +14,12 @@ export interface Renderer2DOptions extends RendererOptions {
|
|
|
14
14
|
}
|
|
15
15
|
export interface Renderer3DOptions extends RendererOptions {
|
|
16
16
|
/**
|
|
17
|
-
*
|
|
18
|
-
*
|
|
17
|
+
* How many instances you intend to spawn at once. Sizes both the
|
|
18
|
+
* non-skinned instance pool directly and seeds the default for the
|
|
19
|
+
* skinned-instance budget. Optional when a prefab bucket is provided -
|
|
20
|
+
* the renderer derives a sensible default from the bucket.
|
|
19
21
|
*/
|
|
20
|
-
|
|
22
|
+
maxInstances?: number;
|
|
21
23
|
enableLighting?: boolean;
|
|
22
24
|
}
|
|
23
25
|
export interface Camera2DState {
|