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;
