UNPKG

@needle-tools/engine

Version:

Needle Engine is a web-based runtime for 3D apps. It runs on your machine for development with great integrations into editors like Unity or Blender - and can be deployed onto any device! It is flexible, extensible and networking and XR are built-in.

196 lines (195 loc) 9.17 kB
import { Object3D } from "three"; import { type IInstantiateOptions } from "./engine_gameobject.js"; import type { INetworkConnection } from "./engine_networking_types.js"; import type { IModel } from "./engine_networking_types.js"; import { Context } from "./engine_setup.js"; import type { IComponent as Component, IContext, IGameObject as GameObject } from "./engine_types.js"; import type { UIDProvider } from "./engine_types.js"; export declare class InstantiateIdProvider implements UIDProvider { get seed(): number; set seed(val: number); private _originalSeed; private _seed; constructor(seed: string | number); reset(): void; generateUUID(str?: string): string; initialize(strOrNumber: string | number): void; static createFromString(str: string): InstantiateIdProvider; private static hash; } export declare enum InstantiateEvent { NewInstanceCreated = "new-instance-created", InstanceDestroyed = "instance-destroyed" } export interface IBeforeNetworkedDestroy { onBeforeNetworkedDestroy(networkIds: string[]): void; } declare type SyncDestroyOptions = { /** When true the state will be saved in the networking backend */ saveInRoom?: boolean; }; /** * Destroy an object across the network. See also {@link syncInstantiate}. * @param obj The object or component to be destroyed * @param con The network connection to send the destroy event to * @param recursive If true, all children will be destroyed as well. Default is true * @param opts Options for the destroy operation * @category Networking */ export declare function syncDestroy(obj: GameObject | Component, con: INetworkConnection, recursive?: boolean, opts?: SyncDestroyOptions): void; export declare function sendDestroyed(guid: string, con: INetworkConnection, opts?: SyncDestroyOptions): void; declare type SyncDestroyCallback = (guid: string, object: Object3D) => void; /** * Register a callback that fires when a remote `syncDestroy` event is received. * The callback receives the guid and the resolved Object3D (or null if not found in the scene). * The callback fires **before** the object is destroyed, so you can still access its state. * @param callback Called with the guid and the Object3D about to be destroyed * @returns An unsubscribe function * @category Networking * @example * ```ts * const unsub = onSyncDestroy((guid, obj) => { * console.log("Remote object destroyed:", guid, obj?.name); * }); * // later: unsub(); * ``` */ export declare function onSyncDestroy(callback: SyncDestroyCallback): () => void; export declare function beginListenDestroy(context: Context): void; /** * When a file is instantiated via some server (e.g. via file drop) we also want to send the info where the file can be downloaded. * @internal */ export declare class HostData { /** File to download */ filename: string; /** Checksum to verify its the correct file */ hash: string; /** Expected size of the referenced file and its dependencies */ size: number; constructor(filename: string, hash: string, size: number); } export declare class NewInstanceModel implements IModel { guid: string; originalGuid: string; seed: number | undefined; visible: boolean | undefined; hostData: HostData | undefined; dontSave?: boolean | undefined; parent: string | undefined; position: { x: number; y: number; z: number; } | undefined; rotation: { x: number; y: number; z: number; w: number; } | undefined; scale: { x: number; y: number; z: number; } | undefined; /** Set to true to prevent this model from being instantiated */ preventCreation?: boolean; /** * When set this will delete the server state when the user disconnects */ deleteStateOnDisconnect?: boolean | undefined; constructor(originalGuid: string, newGuid: string); } /** * Instantiation options for {@link syncInstantiate} * @category Networking * @see {@link syncInstantiate} - Instantiate objects across the network */ export type SyncInstantiateOptions = IInstantiateOptions & Pick<IModel, "deleteOnDisconnect">; /** * Callback type for {@link onSyncInstantiate} * @param instance The instantiated object * @param model The network model data sent with the instantiate event * @param context The network context in which the instantiate event was received * @category Networking */ declare type SyncInstantiateCallback = (instance: GameObject, model: NewInstanceModel, context: IContext) => void; /** * Register a callback that fires when a remote `syncInstantiate` object is created on this client. * Use this to get references to objects spawned by other users. * @param callback Called with the instantiated Object3D, the network model data, and the Needle Engine context in which the instantiate event was received * @returns An unsubscribe function * @category Networking * @example * ```ts * const unsub = onSyncInstantiate((instance, model, context) => { * console.log("Remote object created:", instance.name, model.originalGuid, context); * }); * // later: unsub(); * ``` * @see {@link syncInstantiate} - Instantiate objects across the network * @see {@link syncDestroy} - Destroy objects across the network */ export declare function onSyncInstantiate(callback: SyncInstantiateCallback): () => void; /** * Instantiate an object across the network. The object is cloned locally and a network message * is sent so all connected clients create the same clone. Late joiners receive the message * via room state replay (unless `deleteOnDisconnect` is set or `save` is false). * * ## How it works internally * 1. The prefab is cloned locally using a seeded {@link InstantiateIdProvider} * 2. The seed ensures all clients generate **identical deterministic guids** for the clone * and all its children — no need to send individual guids over the network * 3. A {@link NewInstanceModel} message is sent containing the prefab's `originalGuid`, * the clone's `guid`, the `seed`, and transform data * 4. On receiving clients, the prefab is resolved via {@link registerPrefabProvider} or * by searching the scene for an object with matching guid, then cloned with the same seed * * ## Runtime-created prefabs (no GLB) * If the object has a `guid` but no prefab provider is registered for it, `syncInstantiate` * will **auto-register** the object as a prefab provider. This means for code-only prefabs * you just need to set a `guid` — no manual `registerPrefabProvider` call needed, as long as * all clients run the same setup code that creates the same prefab with the same guid. * * @param object The object to instantiate. Must have a `guid` property (set one for runtime objects). * @param opts Options for the instantiation, including the network context to send the instantiate event to * @param hostData Optional data about a file to download when this object is instantiated (e.g. when instantiated via file drop) * @param save When false, the state of this instance will not be saved in the networking backend. Default is true. * @returns The instantiated object, or null if instantiation failed (e.g. missing guid or network context) * @see {@link syncDestroy} - Destroy objects across the network * @see {@link onSyncInstantiate} - Register a callback to get references to remotely instantiated objects * @see {@link registerPrefabProvider} - Manually register a prefab provider (auto-registered by syncInstantiate) * @see {@link unregisterPrefabProvider} - Remove a registered prefab provider * @category Networking * * @example Basic usage with a runtime-created prefab * ```ts * const cookie = ObjectUtils.createPrimitive("Cube", { color: 0xff8c00 }); * cookie.guid = "cookie-prefab"; * // No need to call registerPrefabProvider — syncInstantiate auto-registers it * syncInstantiate(cookie, { parent: ctx.scene, deleteOnDisconnect: false }); * ``` * * @example With deterministic seed (advanced) * ```ts * const idProvider = new InstantiateIdProvider("my-seed"); * const instance = syncInstantiate(prefab, { context, idProvider }); * ``` * The seed generates deterministic guids via UUID v5, so all clients produce identical * identifiers for the clone and its children without sending them over the network. */ export declare function syncInstantiate(object: GameObject | Object3D, opts: SyncInstantiateOptions, hostData?: HostData, save?: boolean): GameObject | null; export declare function generateSeed(): number; export declare function beginListenInstantiate(context: Context): () => void; export { type PrefabProviderCallback, Prefabs } from "./engine_networking_prefabs.js"; /** * Register a prefab provider. Forwards to {@link Prefabs.register}. * @category Networking */ export declare function registerPrefabProvider(key: string, fn: (guid: string) => Promise<Object3D | null>): void; /** * Unregister a prefab provider. Forwards to {@link Prefabs.unregister}. * @category Networking */ export declare function unregisterPrefabProvider(key: string): void;