UNPKG

rock-mod

Version:

Rock-Mod is a powerful framework designed for creating and managing mods for Grand Theft Auto (GTA) games.

73 lines (72 loc) 5.64 kB
import { type IEventsManager } from "../../common/events/IEventsManager"; import { type IClientInternalEvents } from "../../common/events/types"; import { type IClientToServerEvents, type IServerToClientEvents } from "../../../../shared/net/common/events/types"; /** * Реализация `IEventsManager` поверх нативного CCMP клиента. * * Важные особенности CCMP, продиктовавшие дизайн: * * 1. У `ccmp.on(name, cb)` **нет** парного `ccmp.off`. Поэтому unsubscribe * реализован через собственный реестр: на каждое имя регистрируется ровно * один диспетчер в `ccmp`, который проходит по нашему `Set` подписчиков. * `off` лишь удаляет колбэк из `Set`, диспетчер на стороне CCMP остаётся * висеть (становится no-op). * * 2. `ccmp.emitServer(event, data)` принимает **одно** значение `data`. Наш * контракт `emitServer(name, ...args)` — variadic. Чтобы не терять * позиционные аргументы, всегда отправляем `args` массивом, а на приёме * разворачиваем обратно. Это совпадает с тем, как сервер уже шлёт клиенту * (`ccmpPlayer.emit(name, args)` в `CCMPEventsManager` на сервере). * * 3. Локальной in-process шины событий (аналог `mp.events.call`) у CCMP нет — * под `emitInternal` подкладываем `CCMPInProcessEmitter`. Однако `onInternal` * дополнительно подписывает handler ещё и на нативный `ccmp.on(name, ...)`, * потому что геймод использует `events.onInternal` как канал для UI-ingress * (см. `rock-mod-event-emitter.adapter.ts:61-66` в геймоде: `registerUI()` * делегирует в `events.onInternal`). Под RageMP такого дубля не нужно, * потому что `mp.events.add` естественно ловит и `mp.events.call`, и * CEF-выпуски `mp.trigger`. Побочный эффект: server/system события с тем * же именем тоже долетят до internal-handler'а — на практике конфликтов * нет, потому что namespace'ы геймода различаются (`rm::*` server, * `api:*` UI, `player:*`/`vehicle:*`/etc. internal). * * 4. `IClientEvents` (для `onRaw`/`offRaw`) — RageMP-specific глобальный * тип. Под CCMP осмысленно регистрировать `ccmp.on('playerConnected', ...)` * и другие билтины, но строго типизировать их через `IClientEvents` нельзя * — используем `@ts-expect-error` по аналогии с серверным `CCMPEventsManager`. */ export declare class CCMPEventsManager implements IEventsManager { /** Реестр всех серверных/raw/generic подписчиков. */ private readonly _externalListeners; /** Имена, для которых уже зарегистрирован диспетчер в нативном `ccmp`. */ private readonly _dispatched; /** Локальная in-process шина — питает `onInternal`/`emitInternal`. */ private readonly _internalEmitter; onRaw(events: Partial<IClientEvents>): void; offRaw<K extends keyof IClientEvents>(eventName: K, listener?: IClientEvents[K]): void; onInternal(events: Partial<IClientInternalEvents>): void; offInternal<K extends keyof IClientInternalEvents>(eventName: K, listener?: IClientInternalEvents[K]): void; emitInternal<K extends keyof IClientInternalEvents>(eventName: K, ...args: Parameters<IClientInternalEvents[K]>): void; /** * Sticky-вариант `emitInternal`. Кэширует последнее значение, чтобы поздние * подписчики (`onInternal`) получили его сразу при подписке. Использовать * для one-shot lifecycle-событий (`rm::playerReady` и т.п.), где гонка между * "событие случилось" и "подписчик зарегистрирован" критична. * * См. `CCMPInProcessEmitter.emitSticky` для подробностей семантики. */ emitInternalSticky<K extends keyof IClientInternalEvents>(eventName: K, ...args: Parameters<IClientInternalEvents[K]>): void; /** * Очищает sticky-кэш для конкретного internal-события. Использовать на * disconnect/reset чтобы новые подписчики не получали устаревший local- * player-stub после реконнекта. */ clearInternalSticky<K extends keyof IClientInternalEvents>(eventName: K): void; onServer(events: Partial<IServerToClientEvents>): void; offServer<K extends keyof IServerToClientEvents>(eventName: K, listener?: IServerToClientEvents[K]): void; emitServer<K extends keyof IClientToServerEvents>(eventName: K, ...args: Parameters<IClientToServerEvents[K]>): void; register(event: string, listener: (...args: unknown[]) => void): void; unregister(event: string): void; private _registerExternal; private _unregisterExternal; }