import Clock from '@colyseus/timer';
import { EventEmitter } from 'events';
import { Presence } from './presence/Presence.js';
import { Serializer } from './serializer/Serializer.js';
import { Deferred } from './utils/Utils.js';
import { RoomCache } from './matchmaker/driver/api.js';
import { AuthContext, Client, ClientPrivate, ClientArray, ISendOptions } from './Transport.js';
import { RoomException } from './errors/RoomExceptions.js';
export declare const DEFAULT_SEAT_RESERVATION_TIME: number;
export type SimulationCallback = (deltaTime: number) => void;
export interface IBroadcastOptions extends ISendOptions {
    except?: Client | Client[];
}
export declare enum RoomInternalState {
    CREATING = 0,
    CREATED = 1,
    DISPOSING = 2
}
export type ExtractUserData<T> = T extends ClientArray<infer U> ? U : never;
export type ExtractAuthData<T> = T extends ClientArray<infer _, infer U> ? U : never;
/**
 * A Room class is meant to implement a game session, and/or serve as the communication channel
 * between a group of clients.
 *
 * - Rooms are created on demand during matchmaking by default
 * - Room classes must be exposed using `.define()`
 */
export declare abstract class Room<State extends object = any, Metadata = any, UserData = any, AuthData = any> {
    #private;
    /**
     * This property will change on these situations:
     * - The maximum number of allowed clients has been reached (`maxClients`)
     * - You manually locked, or unlocked the room using lock() or `unlock()`.
     *
     * @readonly
     */
    get locked(): boolean;
    get metadata(): Metadata;
    listing: RoomCache<Metadata>;
    /**
     * Timing events tied to the room instance.
     * Intervals and timeouts are cleared when the room is disposed.
     */
    clock: Clock;
    /**
     * Maximum number of clients allowed to connect into the room. When room reaches this limit,
     * it is locked automatically. Unless the room was explicitly locked by you via `lock()` method,
     * the room will be unlocked as soon as a client disconnects from it.
     */
    maxClients: number;
    /**
     * Automatically dispose the room when last client disconnects.
     *
     * @default true
     */
    autoDispose: boolean;
    /**
     * Frequency to send the room state to connected clients, in milliseconds.
     *
     * @default 50ms (20fps)
     */
    patchRate: number;
    /**
     * The state instance you provided to `setState()`.
     */
    state: State;
    /**
     * The presence instance. Check Presence API for more details.
     *
     * @see {@link https://docs.colyseus.io/colyseus/server/presence/|Presence API}
     */
    presence: Presence;
    /**
     * The array of connected clients.
     *
     * @see {@link https://docs.colyseus.io/colyseus/server/room/#client|Client instance}
     */
    clients: ClientArray<UserData, AuthData>;
    /** @internal */
    _events: EventEmitter<[never]>;
    protected seatReservationTime: number;
    protected reservedSeats: {
        [sessionId: string]: [any, any, boolean?, boolean?];
    };
    protected reservedSeatTimeouts: {
        [sessionId: string]: NodeJS.Timeout;
    };
    protected _reconnections: {
        [reconnectionToken: string]: [string, Deferred];
    };
    private _reconnectingSessionId;
    private onMessageHandlers;
    private _serializer;
    private _afterNextPatchQueue;
    private _simulationInterval;
    private _internalState;
    private _lockedExplicitly;
    private _autoDisposeTimeout;
    constructor();
    /**
     * This method is called by the MatchMaker before onCreate()
     * @internal
     */
    protected __init(): void;
    /**
     * The name of the room you provided as first argument for `gameServer.define()`.
     *
     * @returns roomName string
     */
    get roomName(): string;
    /**
     * Setting the name of the room. Overwriting this property is restricted.
     *
     * @param roomName
     */
    set roomName(roomName: string);
    /**
     * A unique, auto-generated, 9-character-long id of the room.
     * You may replace `this.roomId` during `onCreate()`.
     *
     * @returns roomId string
     */
    get roomId(): string;
    /**
     * Setting the roomId, is restricted in room lifetime except upon room creation.
     *
     * @param roomId
     * @returns roomId string
     */
    set roomId(roomId: string);
    onBeforePatch?(state: State): void | Promise<any>;
    onCreate?(options: any): void | Promise<any>;
    onJoin?(client: Client<UserData, AuthData>, options?: any, auth?: AuthData): void | Promise<any>;
    onLeave?(client: Client<UserData, AuthData>, consented?: boolean): void | Promise<any>;
    onDispose?(): void | Promise<any>;
    /**
     * Define a custom exception handler.
     * If defined, all lifecycle hooks will be wrapped by try/catch, and the exception will be forwarded to this method.
     *
     * These methods will be wrapped by try/catch:
     * - `onMessage`
     * - `onAuth` / `onJoin` / `onLeave` / `onCreate` / `onDispose`
     * - `clock.setTimeout` / `clock.setInterval`
     * - `setSimulationInterval`
     *
     * (Experimental: this feature is subject to change in the future - we're currently getting feedback to improve it)
     */
    onUncaughtException?(error: RoomException<this>, methodName: 'onCreate' | 'onAuth' | 'onJoin' | 'onLeave' | 'onDispose' | 'onMessage' | 'setSimulationInterval' | 'setInterval' | 'setTimeout'): void;
    onAuth(client: Client<UserData, AuthData>, options: any, context: AuthContext): any | Promise<any>;
    static onAuth(token: string, options: any, context: AuthContext): Promise<unknown>;
    /**
     * This method is called during graceful shutdown of the server process
     * You may override this method to dispose the room in your own way.
     *
     * Once process reaches room count of 0, the room process will be terminated.
     */
    onBeforeShutdown(): void;
    /**
     * devMode: When `devMode` is enabled, `onCacheRoom` method is called during
     * graceful shutdown.
     *
     * Implement this method to return custom data to be cached. `onRestoreRoom`
     * will be called with the data returned by `onCacheRoom`
     */
    onCacheRoom?(): any;
    /**
     * devMode: When `devMode` is enabled, `onRestoreRoom` method is called during
     * process startup, with the data returned by the `onCacheRoom` method.
     */
    onRestoreRoom?(cached?: any): void;
    /**
     * Returns whether the sum of connected clients and reserved seats exceeds maximum number of clients.
     *
     * @returns boolean
     */
    hasReachedMaxClients(): boolean;
    /**
     * Set the number of seconds a room can wait for a client to effectively join the room.
     * You should consider how long your `onAuth()` will have to wait for setting a different seat reservation time.
     * The default value is 15 seconds. You may set the `COLYSEUS_SEAT_RESERVATION_TIME`
     * environment variable if you'd like to change the seat reservation time globally.
     *
     * @default 15 seconds
     *
     * @param seconds - number of seconds.
     * @returns The modified Room object.
     */
    setSeatReservationTime(seconds: number): this;
    hasReservedSeat(sessionId: string, reconnectionToken?: string): boolean;
    checkReconnectionToken(reconnectionToken: string): string;
    /**
     * (Optional) Set a simulation interval that can change the state of the game.
     * The simulation interval is your game loop.
     *
     * @default 16.6ms (60fps)
     *
     * @param onTickCallback - You can implement your physics or world updates here!
     *  This is a good place to update the room state.
     * @param delay - Interval delay on executing `onTickCallback` in milliseconds.
     */
    setSimulationInterval(onTickCallback?: SimulationCallback, delay?: number): void;
    /**
     * @deprecated Use `.patchRate=` instead.
     */
    setPatchRate(milliseconds: number | null): void;
    /**
     * @deprecated Use `.state =` instead.
     */
    setState(newState: State): void;
    setSerializer(serializer: Serializer<State>): void;
    setMetadata(meta: Partial<Metadata>): Promise<void>;
    setPrivate(bool?: boolean): Promise<void>;
    /**
     * Locking the room will remove it from the pool of available rooms for new clients to connect to.
     */
    lock(): Promise<void>;
    /**
     * Unlocking the room returns it to the pool of available rooms for new clients to connect to.
     */
    unlock(): Promise<void>;
    send(client: Client, type: string | number, message: any, options?: ISendOptions): void;
    broadcast(type: string | number, message?: any, options?: IBroadcastOptions): void;
    /**
     * Broadcast bytes (UInt8Arrays) to a particular room
     */
    broadcastBytes(type: string | number, message: Uint8Array, options: IBroadcastOptions): void;
    /**
     * Checks whether mutations have occurred in the state, and broadcast them to all connected clients.
     */
    broadcastPatch(): boolean;
    onMessage<T = any>(messageType: '*', callback: (client: Client<UserData, AuthData>, type: string | number, message: T) => void): any;
    onMessage<T = any>(messageType: string | number, callback: (client: Client<UserData, AuthData>, message: T) => void, validate?: (message: unknown) => T): any;
    /**
     * Disconnect all connected clients, and then dispose the room.
     *
     * @param closeCode WebSocket close code (default = 4000, which is a "consented leave")
     * @returns Promise<void>
     */
    disconnect(closeCode?: number): Promise<any>;
    ['_onJoin'](client: Client & ClientPrivate, authContext: AuthContext): Promise<void>;
    /**
     * Allow the specified client to reconnect into the room. Must be used inside `onLeave()` method.
     * If seconds is provided, the reconnection is going to be cancelled after the provided amount of seconds.
     *
     * @param previousClient - The client which is to be waiting until re-connection happens.
     * @param seconds - Timeout period on re-connection in seconds.
     *
     * @returns Deferred<Client> - The differed is a promise like type.
     *  This type can forcibly reject the promise by calling `.reject()`.
     */
    allowReconnection(previousClient: Client, seconds: number | "manual"): Deferred<Client>;
    protected resetAutoDisposeTimeout(timeoutInSeconds?: number): void;
    private broadcastMessageType;
    protected sendFullState(client: Client): void;
    protected _dequeueAfterPatchMessages(): void;
    protected _reserveSeat(sessionId: string, joinOptions?: any, authData?: any, seconds?: number, allowReconnection?: boolean, devModeReconnection?: boolean): Promise<boolean>;
    protected _disposeIfEmpty(): boolean;
    protected _dispose(): Promise<any>;
    protected _onMessage(client: Client & ClientPrivate, buffer: Buffer): void;
    protected _forciblyCloseClient(client: Client & ClientPrivate, closeCode: number): void;
    protected _onLeave(client: Client, code?: number): Promise<any>;
    protected _onAfterLeave(client: Client): Promise<void>;
    protected _incrementClientCount(): Promise<void>;
    protected _decrementClientCount(): Promise<boolean>;
}
