import { Object3D } from "three";
import { type GLTF } from "three/examples/jsm/loaders/GLTFLoader.js";
import { Context } from "./engine_setup.js";
import type { Constructor, ConstructorConcrete, SourceIdentifier } from "./engine_types.js";
export declare type NodeToObjectMap = {
    [nodeId: string]: Object3D;
};
export declare type ObjectToNodeMap = {
    [uuid: string]: number;
};
declare class SerializationHelper {
    register(type: Constructor<any>, ser: ITypeSerializer): void;
    /** type > serializer map */
    private readonly typeMap;
    private getSerializer;
    getSerializerForConstructor(type: any, level?: number): ITypeSerializer | undefined;
}
export declare const helper: SerializationHelper;
export interface ITypeSerializer {
    readonly name?: string;
    onSerialize(data: any, context: SerializationContext): any;
    onDeserialize(data: any, context: SerializationContext): any;
}
/**
 * implement and call super(<type string or array>) with the type names this serializer can handle
 * for example:
 * class ColorSerializer extends TypeSerializer {
 *  constructor() {
 *      super("Color")
 *  }
 * }
*/
export declare abstract class TypeSerializer implements ITypeSerializer {
    readonly name?: string;
    constructor(type: Constructor<any> | Constructor<any>[], name?: string);
    abstract onSerialize(data: any, context: SerializationContext): any | void;
    abstract onDeserialize(data: any, context: SerializationContext): any | void;
}
export interface ITypeInformation {
    type?: ConstructorConcrete<any>;
}
/** holds information if a field was undefined before serialization. This gives us info if we might want to warn the user about missing attributes */
export declare class ImplementationInformation {
    private isDevMode;
    private cache;
    /** only call when assigning values for the very first time */
    registerDefinedKeys(typeName: string, type: object): void;
    getDefinedKey(typeName: string, key: string): boolean;
}
export declare class SerializationContext {
    root: Object3D;
    gltf?: GLTF;
    /** the url of the glb that is currently being loaded */
    gltfId?: SourceIdentifier;
    object: Object3D;
    target?: object;
    nodeId?: number;
    nodeToObject?: NodeToObjectMap;
    objectToNode?: ObjectToNodeMap;
    context?: Context;
    path?: string;
    type?: ConstructorConcrete<any>;
    /** the serializable attribute for this field (target.path) */
    serializable?: any;
    /** holds information if a field was undefined before serialization. This gives us info if we might want to warn the user about missing attributes */
    implementationInformation?: ImplementationInformation;
    constructor(root: Object3D);
}
export interface ISerializable {
    $serializedTypes?: {
        [key: string]: ConstructorConcrete<any> | ITypeInformation | null;
    };
    onBeforeDeserialize?(data: any, context: SerializationContext): void | undefined | boolean;
    onBeforeDeserializeMember?(key: string, data: any, context: SerializationContext): void | undefined | boolean;
    onAfterDeserializeMember?(key: string, data: any, context: SerializationContext): void;
    onAfterDeserialize?(data: any, context: SerializationContext): void;
}
export declare function serializeObject(obj: ISerializable, context: SerializationContext): object | null;
export declare function deserializeObject(obj: ISerializable, serializedData: object, context: SerializationContext): boolean;
/** set to true while assigning properties during instantiation.
 * Used for validate decorator to not invoke callbacks on components that are currently in the process of being built */
export declare const $isAssigningProperties: unique symbol;
/**
 * Callback that is called when a property is assigned.
 * @param source the source object that is being assigned from
 * @param key the key that is being assigned
 * @param value the value that is being assigned
 */
type AssignedCallback = (source: object, key: string, oldValue: any, newValue: any) => any;
/** Object.assign behaviour but check if property is writeable (e.g. getter only properties are skipped) */
export declare function assign(target: any, source: any, info?: ImplementationInformation, opts?: {
    onAssigned?: AssignedCallback;
}): void;
export {};
