@needle-tools/engine 5.0.2 → 5.1.0-canary.525aa82
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/CHANGELOG.md +24 -0
- package/README.md +6 -7
- package/SKILL.md +39 -21
- package/components.needle.json +1 -1
- package/dist/needle-engine.bundle-DPag02s9.min.js +1732 -0
- package/dist/needle-engine.bundle-IPMzQpe1.umd.cjs +1732 -0
- package/dist/{needle-engine.bundle-BoTyA-Le.js → needle-engine.bundle-qa_NEunk.js} +8881 -8148
- package/dist/needle-engine.d.ts +633 -61
- package/dist/needle-engine.js +576 -565
- package/dist/needle-engine.min.js +1 -1
- package/dist/needle-engine.umd.cjs +1 -1
- package/dist/{vendor-vHLk8sXu.js → vendor-CAcsI0eU.js} +116 -115
- package/dist/{vendor-CntUvmJu.umd.cjs → vendor-CEM38hLE.umd.cjs} +2 -2
- package/dist/{vendor-DPbfJJ4d.min.js → vendor-HRlxIBga.min.js} +2 -2
- package/lib/engine/api.d.ts +2 -0
- package/lib/engine/api.js +2 -0
- package/lib/engine/api.js.map +1 -1
- package/lib/engine/engine_addressables.js +5 -1
- package/lib/engine/engine_addressables.js.map +1 -1
- package/lib/engine/engine_animation.d.ts +14 -7
- package/lib/engine/engine_animation.js +49 -9
- package/lib/engine/engine_animation.js.map +1 -1
- package/lib/engine/engine_components.js +33 -4
- package/lib/engine/engine_components.js.map +1 -1
- package/lib/engine/engine_context.d.ts +7 -2
- package/lib/engine/engine_context.js +10 -2
- package/lib/engine/engine_context.js.map +1 -1
- package/lib/engine/engine_gameobject.d.ts +4 -0
- package/lib/engine/engine_gameobject.js.map +1 -1
- package/lib/engine/engine_init.js +4 -0
- package/lib/engine/engine_init.js.map +1 -1
- package/lib/engine/engine_input.js +4 -1
- package/lib/engine/engine_input.js.map +1 -1
- package/lib/engine/engine_materialpropertyblock.js +1 -20
- package/lib/engine/engine_materialpropertyblock.js.map +1 -1
- package/lib/engine/engine_networking.d.ts +11 -8
- package/lib/engine/engine_networking.js +43 -26
- package/lib/engine/engine_networking.js.map +1 -1
- package/lib/engine/engine_networking_instantiate.d.ts +100 -5
- package/lib/engine/engine_networking_instantiate.js +150 -16
- package/lib/engine/engine_networking_instantiate.js.map +1 -1
- package/lib/engine/engine_networking_prefabs.d.ts +59 -0
- package/lib/engine/engine_networking_prefabs.js +67 -0
- package/lib/engine/engine_networking_prefabs.js.map +1 -0
- package/lib/engine/engine_physics_rapier.d.ts +3 -0
- package/lib/engine/engine_physics_rapier.js +13 -9
- package/lib/engine/engine_physics_rapier.js.map +1 -1
- package/lib/engine/postprocessing/api.d.ts +2 -0
- package/lib/engine/postprocessing/api.js +2 -0
- package/lib/engine/postprocessing/api.js.map +1 -0
- package/lib/engine/postprocessing/index.d.ts +2 -0
- package/lib/engine/postprocessing/index.js +2 -0
- package/lib/engine/postprocessing/index.js.map +1 -0
- package/lib/engine/postprocessing/postprocessing.d.ts +83 -0
- package/lib/engine/postprocessing/postprocessing.js +280 -0
- package/lib/engine/postprocessing/postprocessing.js.map +1 -0
- package/lib/engine/postprocessing/types.d.ts +39 -0
- package/lib/engine/postprocessing/types.js +2 -0
- package/lib/engine/postprocessing/types.js.map +1 -0
- package/lib/engine/webcomponents/WebXRButtons.js +17 -3
- package/lib/engine/webcomponents/WebXRButtons.js.map +1 -1
- package/lib/engine/webcomponents/icons.js +3 -1
- package/lib/engine/webcomponents/icons.js.map +1 -1
- package/lib/engine/xr/NeedleXRSession.d.ts +1 -0
- package/lib/engine/xr/NeedleXRSession.js +43 -10
- package/lib/engine/xr/NeedleXRSession.js.map +1 -1
- package/lib/engine/xr/init.d.ts +4 -0
- package/lib/engine/xr/init.js +49 -0
- package/lib/engine/xr/init.js.map +1 -0
- package/lib/engine-components/AnimationUtils.d.ts +4 -1
- package/lib/engine-components/AnimationUtils.js +7 -19
- package/lib/engine-components/AnimationUtils.js.map +1 -1
- package/lib/engine-components/AnimatorController.d.ts +135 -2
- package/lib/engine-components/AnimatorController.js +216 -13
- package/lib/engine-components/AnimatorController.js.map +1 -1
- package/lib/engine-components/GroundProjection.d.ts +1 -0
- package/lib/engine-components/GroundProjection.js +184 -48
- package/lib/engine-components/GroundProjection.js.map +1 -1
- package/lib/engine-components/OrbitControls.d.ts +4 -0
- package/lib/engine-components/OrbitControls.js +5 -1
- package/lib/engine-components/OrbitControls.js.map +1 -1
- package/lib/engine-components/SeeThrough.d.ts +0 -2
- package/lib/engine-components/SeeThrough.js +0 -89
- package/lib/engine-components/SeeThrough.js.map +1 -1
- package/lib/engine-components/SyncedRoom.d.ts +4 -0
- package/lib/engine-components/SyncedRoom.js +23 -8
- package/lib/engine-components/SyncedRoom.js.map +1 -1
- package/lib/engine-components/SyncedTransform.js +5 -5
- package/lib/engine-components/SyncedTransform.js.map +1 -1
- package/lib/engine-components/Voip.d.ts +46 -0
- package/lib/engine-components/Voip.js +126 -2
- package/lib/engine-components/Voip.js.map +1 -1
- package/lib/engine-components/api.d.ts +1 -0
- package/lib/engine-components/api.js +1 -0
- package/lib/engine-components/api.js.map +1 -1
- package/lib/engine-components/codegen/components.d.ts +1 -0
- package/lib/engine-components/codegen/components.js +1 -0
- package/lib/engine-components/codegen/components.js.map +1 -1
- package/lib/engine-components/postprocessing/Effects/Tonemapping.d.ts +5 -2
- package/lib/engine-components/postprocessing/Effects/Tonemapping.js +11 -18
- package/lib/engine-components/postprocessing/Effects/Tonemapping.js.map +1 -1
- package/lib/engine-components/postprocessing/PostProcessingEffect.d.ts +3 -4
- package/lib/engine-components/postprocessing/PostProcessingEffect.js +6 -15
- package/lib/engine-components/postprocessing/PostProcessingEffect.js.map +1 -1
- package/lib/engine-components/postprocessing/PostProcessingHandler.d.ts +2 -1
- package/lib/engine-components/postprocessing/PostProcessingHandler.js.map +1 -1
- package/lib/engine-components/postprocessing/Volume.d.ts +18 -11
- package/lib/engine-components/postprocessing/Volume.js +61 -140
- package/lib/engine-components/postprocessing/Volume.js.map +1 -1
- package/lib/engine-components/postprocessing/index.d.ts +1 -0
- package/lib/engine-components/postprocessing/index.js +1 -0
- package/lib/engine-components/postprocessing/index.js.map +1 -1
- package/lib/engine-components/postprocessing/utils.d.ts +2 -0
- package/lib/engine-components/postprocessing/utils.js +2 -0
- package/lib/engine-components/postprocessing/utils.js.map +1 -1
- package/lib/engine-components/ui/Canvas.js +2 -2
- package/lib/engine-components/ui/Canvas.js.map +1 -1
- package/lib/engine-components/ui/Graphic.d.ts +3 -3
- package/lib/engine-components/ui/Graphic.js +6 -2
- package/lib/engine-components/ui/Graphic.js.map +1 -1
- package/lib/engine-components/ui/Text.d.ts +64 -11
- package/lib/engine-components/ui/Text.js +154 -45
- package/lib/engine-components/ui/Text.js.map +1 -1
- package/lib/engine-components/ui/index.d.ts +1 -0
- package/lib/engine-components/ui/index.js +1 -0
- package/lib/engine-components/ui/index.js.map +1 -1
- package/lib/engine-components-experimental/networking/PlayerSync.d.ts +25 -3
- package/lib/engine-components-experimental/networking/PlayerSync.js +60 -11
- package/lib/engine-components-experimental/networking/PlayerSync.js.map +1 -1
- package/package.json +6 -5
- package/plugins/vite/ai.d.ts +11 -10
- package/plugins/vite/ai.js +305 -31
- package/src/engine/api.ts +3 -0
- package/src/engine/engine_addressables.ts +4 -1
- package/src/engine/engine_animation.ts +47 -9
- package/src/engine/engine_components.ts +36 -7
- package/src/engine/engine_context.ts +11 -2
- package/src/engine/engine_gameobject.ts +5 -0
- package/src/engine/engine_init.ts +4 -0
- package/src/engine/engine_input.ts +2 -1
- package/src/engine/engine_materialpropertyblock.ts +1 -20
- package/src/engine/engine_networking.ts +46 -23
- package/src/engine/engine_networking_instantiate.ts +160 -18
- package/src/engine/engine_networking_prefabs.ts +80 -0
- package/src/engine/engine_physics_rapier.ts +14 -9
- package/src/engine/postprocessing/api.ts +2 -0
- package/src/engine/postprocessing/index.ts +2 -0
- package/src/engine/postprocessing/postprocessing.ts +322 -0
- package/src/engine/postprocessing/types.ts +43 -0
- package/src/engine/webcomponents/WebXRButtons.ts +21 -4
- package/src/engine/webcomponents/icons.ts +5 -3
- package/src/engine/xr/NeedleXRSession.ts +50 -15
- package/src/engine/xr/init.ts +56 -0
- package/src/engine-components/AnimationUtils.ts +7 -17
- package/src/engine-components/AnimatorController.ts +288 -18
- package/src/engine-components/GroundProjection.ts +226 -52
- package/src/engine-components/OrbitControls.ts +5 -1
- package/src/engine-components/SeeThrough.ts +0 -116
- package/src/engine-components/SyncedRoom.ts +28 -9
- package/src/engine-components/SyncedTransform.ts +5 -5
- package/src/engine-components/Voip.ts +129 -2
- package/src/engine-components/api.ts +1 -0
- package/src/engine-components/codegen/components.ts +1 -0
- package/src/engine-components/postprocessing/Effects/Tonemapping.ts +16 -24
- package/src/engine-components/postprocessing/PostProcessingEffect.ts +9 -16
- package/src/engine-components/postprocessing/PostProcessingHandler.ts +2 -1
- package/src/engine-components/postprocessing/Volume.ts +72 -163
- package/src/engine-components/postprocessing/index.ts +1 -0
- package/src/engine-components/postprocessing/utils.ts +2 -0
- package/src/engine-components/ui/Canvas.ts +2 -2
- package/src/engine-components/ui/Graphic.ts +7 -3
- package/src/engine-components/ui/Text.ts +170 -52
- package/src/engine-components/ui/index.ts +2 -1
- package/src/engine-components-experimental/networking/PlayerSync.ts +64 -11
- package/dist/needle-engine.bundle-B3ywqx5o.min.js +0 -1654
- package/dist/needle-engine.bundle-CzOPcOui.umd.cjs +0 -1654
|
@@ -11,7 +11,7 @@ import type { INetworkConnection } from "./engine_networking_types.js";
|
|
|
11
11
|
import type { IModel } from "./engine_networking_types.js";
|
|
12
12
|
import { SendQueue } from "./engine_networking_types.js";
|
|
13
13
|
import { Context } from "./engine_setup.js"
|
|
14
|
-
import type { IComponent as Component, IGameObject as GameObject } from "./engine_types.js"
|
|
14
|
+
import type { IComponent as Component, IContext,IGameObject as GameObject } from "./engine_types.js"
|
|
15
15
|
import type { UIDProvider } from "./engine_types.js";
|
|
16
16
|
import * as utils from "./engine_utils.js"
|
|
17
17
|
|
|
@@ -154,13 +154,46 @@ export function sendDestroyed(guid: string, con: INetworkConnection, opts?: Sync
|
|
|
154
154
|
con.send(InstantiateEvent.InstanceDestroyed, model, SendQueue.Queued);
|
|
155
155
|
}
|
|
156
156
|
|
|
157
|
+
declare type SyncDestroyCallback = (guid: string, object: Object3D) => void;
|
|
158
|
+
const _onSyncDestroyCallbacks: SyncDestroyCallback[] = [];
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Register a callback that fires when a remote `syncDestroy` event is received.
|
|
162
|
+
* The callback receives the guid and the resolved Object3D (or null if not found in the scene).
|
|
163
|
+
* The callback fires **before** the object is destroyed, so you can still access its state.
|
|
164
|
+
* @param callback Called with the guid and the Object3D about to be destroyed
|
|
165
|
+
* @returns An unsubscribe function
|
|
166
|
+
* @category Networking
|
|
167
|
+
* @example
|
|
168
|
+
* ```ts
|
|
169
|
+
* const unsub = onSyncDestroy((guid, obj) => {
|
|
170
|
+
* console.log("Remote object destroyed:", guid, obj?.name);
|
|
171
|
+
* });
|
|
172
|
+
* // later: unsub();
|
|
173
|
+
* ```
|
|
174
|
+
*/
|
|
175
|
+
export function onSyncDestroy(callback: SyncDestroyCallback): () => void {
|
|
176
|
+
_onSyncDestroyCallbacks.push(callback);
|
|
177
|
+
return () => {
|
|
178
|
+
const idx = _onSyncDestroyCallbacks.indexOf(callback);
|
|
179
|
+
if (idx >= 0) _onSyncDestroyCallbacks.splice(idx, 1);
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
|
|
157
183
|
export function beginListenDestroy(context: Context) {
|
|
158
184
|
context.connection.beginListen(InstantiateEvent.InstanceDestroyed, (data: DestroyInstanceModel) => {
|
|
159
185
|
if (debug)
|
|
160
186
|
console.log("[Remote] Destroyed", context.scene, data);
|
|
161
187
|
// TODO: create global lookup table for guids
|
|
162
188
|
const obj = findByGuid(data.guid, context.scene);
|
|
163
|
-
if (obj)
|
|
189
|
+
if (obj) {
|
|
190
|
+
// Notify listeners before destroying
|
|
191
|
+
for (const cb of _onSyncDestroyCallbacks) {
|
|
192
|
+
try { cb(data.guid, obj as Object3D); }
|
|
193
|
+
catch (err) { console.error("Error in onSyncDestroy callback", err); }
|
|
194
|
+
}
|
|
195
|
+
destroy(obj);
|
|
196
|
+
}
|
|
164
197
|
});
|
|
165
198
|
}
|
|
166
199
|
|
|
@@ -215,27 +248,125 @@ export class NewInstanceModel implements IModel {
|
|
|
215
248
|
|
|
216
249
|
/**
|
|
217
250
|
* Instantiation options for {@link syncInstantiate}
|
|
251
|
+
* @category Networking
|
|
252
|
+
* @see {@link syncInstantiate} - Instantiate objects across the network
|
|
218
253
|
*/
|
|
219
254
|
export type SyncInstantiateOptions = IInstantiateOptions & Pick<IModel, "deleteOnDisconnect">;
|
|
220
255
|
|
|
221
256
|
// #region Sync Instantiate
|
|
257
|
+
|
|
258
|
+
/**
|
|
259
|
+
* Callback type for {@link onSyncInstantiate}
|
|
260
|
+
* @param instance The instantiated object
|
|
261
|
+
* @param model The network model data sent with the instantiate event
|
|
262
|
+
* @param context The network context in which the instantiate event was received
|
|
263
|
+
* @category Networking
|
|
264
|
+
*/
|
|
265
|
+
declare type SyncInstantiateCallback = (instance: GameObject, model: NewInstanceModel, context: IContext) => void;
|
|
266
|
+
/** Registered callbacks for remote instantiation events */
|
|
267
|
+
const _onSyncInstantiateCallbacks: SyncInstantiateCallback[] = [];
|
|
268
|
+
|
|
222
269
|
/**
|
|
223
|
-
*
|
|
270
|
+
* Register a callback that fires when a remote `syncInstantiate` object is created on this client.
|
|
271
|
+
* Use this to get references to objects spawned by other users.
|
|
272
|
+
* @param callback Called with the instantiated Object3D, the network model data, and the Needle Engine context in which the instantiate event was received
|
|
273
|
+
* @returns An unsubscribe function
|
|
224
274
|
* @category Networking
|
|
275
|
+
* @example
|
|
276
|
+
* ```ts
|
|
277
|
+
* const unsub = onSyncInstantiate((instance, model, context) => {
|
|
278
|
+
* console.log("Remote object created:", instance.name, model.originalGuid, context);
|
|
279
|
+
* });
|
|
280
|
+
* // later: unsub();
|
|
281
|
+
* ```
|
|
282
|
+
* @see {@link syncInstantiate} - Instantiate objects across the network
|
|
283
|
+
* @see {@link syncDestroy} - Destroy objects across the network
|
|
284
|
+
*/
|
|
285
|
+
export function onSyncInstantiate(callback: SyncInstantiateCallback): () => void {
|
|
286
|
+
_onSyncInstantiateCallbacks.push(callback);
|
|
287
|
+
return () => {
|
|
288
|
+
const idx = _onSyncInstantiateCallbacks.indexOf(callback);
|
|
289
|
+
if (idx >= 0) _onSyncInstantiateCallbacks.splice(idx, 1);
|
|
290
|
+
};
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
/**
|
|
294
|
+
* Instantiate an object across the network. The object is cloned locally and a network message
|
|
295
|
+
* is sent so all connected clients create the same clone. Late joiners receive the message
|
|
296
|
+
* via room state replay (unless `deleteOnDisconnect` is set or `save` is false).
|
|
297
|
+
*
|
|
298
|
+
* ## How it works internally
|
|
299
|
+
* 1. The prefab is cloned locally using a seeded {@link InstantiateIdProvider}
|
|
300
|
+
* 2. The seed ensures all clients generate **identical deterministic guids** for the clone
|
|
301
|
+
* and all its children — no need to send individual guids over the network
|
|
302
|
+
* 3. A {@link NewInstanceModel} message is sent containing the prefab's `originalGuid`,
|
|
303
|
+
* the clone's `guid`, the `seed`, and transform data
|
|
304
|
+
* 4. On receiving clients, the prefab is resolved via {@link registerPrefabProvider} or
|
|
305
|
+
* by searching the scene for an object with matching guid, then cloned with the same seed
|
|
306
|
+
*
|
|
307
|
+
* ## Runtime-created prefabs (no GLB)
|
|
308
|
+
* If the object has a `guid` but no prefab provider is registered for it, `syncInstantiate`
|
|
309
|
+
* will **auto-register** the object as a prefab provider. This means for code-only prefabs
|
|
310
|
+
* you just need to set a `guid` — no manual `registerPrefabProvider` call needed, as long as
|
|
311
|
+
* all clients run the same setup code that creates the same prefab with the same guid.
|
|
312
|
+
*
|
|
313
|
+
* @param object The object to instantiate. Must have a `guid` property (set one for runtime objects).
|
|
314
|
+
* @param opts Options for the instantiation, including the network context to send the instantiate event to
|
|
315
|
+
* @param hostData Optional data about a file to download when this object is instantiated (e.g. when instantiated via file drop)
|
|
316
|
+
* @param save When false, the state of this instance will not be saved in the networking backend. Default is true.
|
|
317
|
+
* @returns The instantiated object, or null if instantiation failed (e.g. missing guid or network context)
|
|
318
|
+
* @see {@link syncDestroy} - Destroy objects across the network
|
|
319
|
+
* @see {@link onSyncInstantiate} - Register a callback to get references to remotely instantiated objects
|
|
320
|
+
* @see {@link registerPrefabProvider} - Manually register a prefab provider (auto-registered by syncInstantiate)
|
|
321
|
+
* @see {@link unregisterPrefabProvider} - Remove a registered prefab provider
|
|
322
|
+
* @category Networking
|
|
323
|
+
*
|
|
324
|
+
* @example Basic usage with a runtime-created prefab
|
|
325
|
+
* ```ts
|
|
326
|
+
* const cookie = ObjectUtils.createPrimitive("Cube", { color: 0xff8c00 });
|
|
327
|
+
* cookie.guid = "cookie-prefab";
|
|
328
|
+
* // No need to call registerPrefabProvider — syncInstantiate auto-registers it
|
|
329
|
+
* syncInstantiate(cookie, { parent: ctx.scene, deleteOnDisconnect: false });
|
|
330
|
+
* ```
|
|
331
|
+
*
|
|
332
|
+
* @example With deterministic seed (advanced)
|
|
333
|
+
* ```ts
|
|
334
|
+
* const idProvider = new InstantiateIdProvider("my-seed");
|
|
335
|
+
* const instance = syncInstantiate(prefab, { context, idProvider });
|
|
336
|
+
* ```
|
|
337
|
+
* The seed generates deterministic guids via UUID v5, so all clients produce identical
|
|
338
|
+
* identifiers for the clone and its children without sending them over the network.
|
|
225
339
|
*/
|
|
226
340
|
export function syncInstantiate(object: GameObject | Object3D, opts: SyncInstantiateOptions, hostData?: HostData, save?: boolean): GameObject | null {
|
|
227
341
|
|
|
228
342
|
const obj: GameObject = object as GameObject;
|
|
229
343
|
|
|
230
344
|
if (!obj.guid) {
|
|
231
|
-
|
|
232
|
-
|
|
345
|
+
// Auto-assign guid from object name if available.
|
|
346
|
+
// The name must be the same on all clients (which it is when both run the same setup code).
|
|
347
|
+
if (obj.name) {
|
|
348
|
+
obj.guid = obj.name;
|
|
349
|
+
}
|
|
350
|
+
else {
|
|
351
|
+
console.error("[syncInstantiate] Can not instantiate: a 'guid' is required. For runtime-created objects, either set a name (`obj.name = 'my-prefab'`) or a guid (`obj.guid = 'my-prefab-id'`). The identifier must be the same on all clients.", obj);
|
|
352
|
+
return null;
|
|
353
|
+
}
|
|
233
354
|
}
|
|
234
355
|
|
|
235
|
-
if
|
|
356
|
+
// Auto-register the prefab provider if none exists for this guid.
|
|
357
|
+
// This allows runtime-created objects to work with syncInstantiate without
|
|
358
|
+
// manual Prefabs.register calls, as long as all clients create the
|
|
359
|
+
// same prefab with the same guid in their setup code.
|
|
360
|
+
if (!Prefabs.has(obj.guid)) {
|
|
361
|
+
Prefabs.register(obj.guid, async () => obj);
|
|
362
|
+
}
|
|
236
363
|
|
|
237
364
|
if (!opts.context) {
|
|
238
|
-
|
|
365
|
+
opts.context = Context.Current;
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
if (!opts.context) {
|
|
369
|
+
console.error("[syncInstantiate] Missing network instantiate options / reference to network connection in sync instantiate. Please pass in the Needle Engine context.");
|
|
239
370
|
return null;
|
|
240
371
|
}
|
|
241
372
|
|
|
@@ -318,7 +449,6 @@ const syncedInstantiated = new Array<WeakRef<Object3D>>();
|
|
|
318
449
|
|
|
319
450
|
export function beginListenInstantiate(context: Context) {
|
|
320
451
|
|
|
321
|
-
|
|
322
452
|
const cb1 = context.connection.beginListen(InstantiateEvent.NewInstanceCreated, async (model: NewInstanceModel) => {
|
|
323
453
|
const obj: GameObject | null = await tryResolvePrefab(model.originalGuid, context.scene) as GameObject;
|
|
324
454
|
if (model.preventCreation === true) {
|
|
@@ -350,6 +480,11 @@ export function beginListenInstantiate(context: Context) {
|
|
|
350
480
|
context.scene.add(inst);
|
|
351
481
|
if (debug)
|
|
352
482
|
console.log("[Remote] new instance", "gameobject:", inst?.guid, obj);
|
|
483
|
+
// Notify listeners about the remote instantiation
|
|
484
|
+
for (const cb of _onSyncInstantiateCallbacks) {
|
|
485
|
+
try { cb(inst, model, context); }
|
|
486
|
+
catch (err) { console.error("Error in onSyncInstantiate callback", err); }
|
|
487
|
+
}
|
|
353
488
|
}
|
|
354
489
|
});
|
|
355
490
|
const cb2 = context.connection.beginListen("left-room", () => {
|
|
@@ -377,21 +512,28 @@ function instantiateSeeded(obj: GameObject, opts: IInstantiateOptions | null): {
|
|
|
377
512
|
return { seed: seed, instance: instance };
|
|
378
513
|
}
|
|
379
514
|
|
|
380
|
-
export
|
|
515
|
+
export { type PrefabProviderCallback,Prefabs } from "./engine_networking_prefabs.js";
|
|
516
|
+
import { Prefabs } from "./engine_networking_prefabs.js";
|
|
381
517
|
|
|
382
|
-
|
|
518
|
+
/**
|
|
519
|
+
* Register a prefab provider. Forwards to {@link Prefabs.register}.
|
|
520
|
+
* @category Networking
|
|
521
|
+
*/
|
|
522
|
+
export function registerPrefabProvider(key: string, fn: (guid: string) => Promise<Object3D | null>) {
|
|
523
|
+
Prefabs.register(key, fn);
|
|
524
|
+
}
|
|
383
525
|
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
526
|
+
/**
|
|
527
|
+
* Unregister a prefab provider. Forwards to {@link Prefabs.unregister}.
|
|
528
|
+
* @category Networking
|
|
529
|
+
*/
|
|
530
|
+
export function unregisterPrefabProvider(key: string) {
|
|
531
|
+
Prefabs.unregister(key);
|
|
387
532
|
}
|
|
388
533
|
|
|
389
534
|
async function tryResolvePrefab(guid: string, obj: Object3D): Promise<Object3D | null> {
|
|
390
|
-
const
|
|
391
|
-
if (
|
|
392
|
-
const res = await prov(guid);
|
|
393
|
-
if (res) return res;
|
|
394
|
-
}
|
|
535
|
+
const res = await Prefabs.resolve(guid);
|
|
536
|
+
if (res) return res;
|
|
395
537
|
return tryFindObjectByGuid(guid, obj) as Object3D;
|
|
396
538
|
}
|
|
397
539
|
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { Object3D } from "three";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Callback type for prefab providers.
|
|
5
|
+
* @param guid The guid of the prefab to resolve
|
|
6
|
+
* @returns The prefab Object3D, or null if not found
|
|
7
|
+
*/
|
|
8
|
+
export declare type PrefabProviderCallback = (guid: string) => Promise<Object3D | null>;
|
|
9
|
+
|
|
10
|
+
const registeredProviders: { [key: string]: PrefabProviderCallback } = {};
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Prefab registry for networked instantiation.
|
|
14
|
+
*
|
|
15
|
+
* When a remote {@link syncInstantiate} event is received, the engine looks up the prefab
|
|
16
|
+
* by its guid using this registry. Both GLB-loaded objects and runtime-created objects
|
|
17
|
+
* can be registered here.
|
|
18
|
+
*
|
|
19
|
+
* Note: {@link syncInstantiate} auto-registers prefabs if no provider exists for their guid,
|
|
20
|
+
* so manual registration is only needed for custom resolution logic.
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* ```ts
|
|
24
|
+
* import { Prefabs, ObjectUtils } from "@needle-tools/engine";
|
|
25
|
+
*
|
|
26
|
+
* const cookie = ObjectUtils.createPrimitive("Cube", { color: 0xff8c00 });
|
|
27
|
+
* cookie.guid = "cookie-prefab";
|
|
28
|
+
* Prefabs.register("cookie-prefab", async () => cookie);
|
|
29
|
+
*
|
|
30
|
+
* console.log(Prefabs.list()); // ["cookie-prefab"]
|
|
31
|
+
* Prefabs.unregister("cookie-prefab");
|
|
32
|
+
* ```
|
|
33
|
+
*
|
|
34
|
+
* @category Networking
|
|
35
|
+
*/
|
|
36
|
+
export const Prefabs = {
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Register a prefab provider that resolves objects by guid for networked instantiation.
|
|
40
|
+
* When a remote `syncInstantiate` event is received, the engine uses this to find the prefab
|
|
41
|
+
* to clone on the receiving client.
|
|
42
|
+
*
|
|
43
|
+
* @param key The guid to register the provider for
|
|
44
|
+
* @param fn Callback that returns the prefab Object3D for the given guid
|
|
45
|
+
*/
|
|
46
|
+
register(key: string, fn: PrefabProviderCallback) {
|
|
47
|
+
registeredProviders[key] = fn;
|
|
48
|
+
},
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Unregister a previously registered prefab provider.
|
|
52
|
+
* @param key The guid to unregister
|
|
53
|
+
*/
|
|
54
|
+
unregister(key: string) {
|
|
55
|
+
delete registeredProviders[key];
|
|
56
|
+
},
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Returns a list of all registered prefab provider keys (guids).
|
|
60
|
+
* Useful for debugging to see which prefabs are available for networked instantiation.
|
|
61
|
+
*/
|
|
62
|
+
list(): string[] {
|
|
63
|
+
return Object.keys(registeredProviders);
|
|
64
|
+
},
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Check if a prefab provider is registered for the given guid.
|
|
68
|
+
* @param key The guid to check
|
|
69
|
+
*/
|
|
70
|
+
has(key: string): boolean {
|
|
71
|
+
return key in registeredProviders;
|
|
72
|
+
},
|
|
73
|
+
|
|
74
|
+
/** @internal Resolve a prefab by guid. Used by the networking system. */
|
|
75
|
+
async resolve(guid: string): Promise<Object3D | null> {
|
|
76
|
+
const prov = registeredProviders[guid];
|
|
77
|
+
if (prov) return prov(guid);
|
|
78
|
+
return null;
|
|
79
|
+
},
|
|
80
|
+
} as const;
|
|
@@ -46,16 +46,21 @@ const $colliderRigidbody = Symbol("rigidbody");
|
|
|
46
46
|
|
|
47
47
|
declare const NEEDLE_USE_RAPIER: boolean;
|
|
48
48
|
globalThis["NEEDLE_USE_RAPIER"] = globalThis["NEEDLE_USE_RAPIER"] !== undefined ? globalThis["NEEDLE_USE_RAPIER"] : true;
|
|
49
|
-
if (debugPhysics)
|
|
50
|
-
console.log("Use Rapier", NEEDLE_USE_RAPIER, globalThis["NEEDLE_USE_RAPIER"])
|
|
51
49
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
50
|
+
/** Register the Rapier physics backend. Called from {@link initEngine}
|
|
51
|
+
* to ensure it runs regardless of tree-shaking. */
|
|
52
|
+
export function initPhysics() {
|
|
53
|
+
if (debugPhysics)
|
|
54
|
+
console.log("Use Rapier", NEEDLE_USE_RAPIER, globalThis["NEEDLE_USE_RAPIER"])
|
|
55
|
+
|
|
56
|
+
if (NEEDLE_USE_RAPIER) {
|
|
57
|
+
ContextRegistry.registerCallback(ContextEvent.ContextCreationStart, evt => {
|
|
58
|
+
if (debugPhysics)
|
|
59
|
+
console.log("Register rapier physics backend")
|
|
60
|
+
evt.context.physics.engine = new RapierPhysics(evt.context);
|
|
61
|
+
// We do not initialize physics immediately to avoid loading the physics engine if it is not needed
|
|
62
|
+
});
|
|
63
|
+
}
|
|
59
64
|
}
|
|
60
65
|
|
|
61
66
|
|