@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
TypeScript
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;