UNPKG

rock-mod

Version:

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

88 lines (87 loc) 4.7 kB
import { type CCMPEventsManager } from "../../../net/ccmp/events/CCMPEventsManager"; import { type IPlayersManager } from "../../common/player/IPlayersManager"; import { type IWorldObjectsIterator } from "../../common/worldObject/IWorldObjectsIterator"; import { CCMPPlayer } from "./CCMPPlayer"; /** * Реализация `IPlayersManager` под CCMP — single source of truth для * `IPlayer`-инстансов и `rm::playerReady`/`rm::playerConnected`-эмиссий * с настоящими `CCMPPlayer`-инстансами. * * ### Хранилище * * `Map<id, CCMPPlayer>`. For CCMP players only, `id` and `remoteId` still * mean the same server/network id. Non-player CCMP wrappers have a separate * client-local `id` and nullable server `remoteId`. * `findByID`/`findByRemoteID`/`findByRemoteId` map to one lookup for players. * * ### Жизненный цикл local player'а * * `ccmp.players.local` (backed by `op_get_local_player_id`) валиден сразу * после handshake'а — `PlayerManager::set_local_player_id` срабатывает до * того, как scripts загружаются. Мы используем его, чтобы синхронно * выпустить `rm::playerReady` как sticky-event (см. ниже): * * 1. **На конструкторе** — fast-path. Если local op возвращает игрока, * эмитим `rm::playerReady` через `emitInternalSticky` с реальным * `CCMPPlayer`-инстансом. Sticky-кэш гарантирует, что поздние * подписчики из async DI-bootstrap'а геймода тоже получат сигнал * при подписке. * 2. **На `connectionStateChanged`** — fallback / handler реконнекта. * Если на конструкторе local ещё не был валиден (handshake race), * `connected = true` запустит retry fast-path. На `connected = false` * чистим _localPlayer и sticky-кэш, чтобы при следующем connect'е * эмитнуть с актуальным remoteId. * * `CCMPPlayer`-инстанс важен (а не структурный stub) потому что * `RockModStateAdapter` в геймоде хранит `rockModPlayer`-ссылку и через * неё вызывает методы (`setNoCollision`, etc). На структурном stub'е * без методов это падало бы с `TypeError`. * * ### Remote-игроки * * Источники: * - `ccmp.players.all` — prepopulation для уже-существующих на момент * подключения (заполнен Rust'ом в `ClientScriptingService::init`). * - `rm::playerConnected`/`rm::playerDisconnected` internal events * (эмитит `CCMPEventsBridge` из нативных `ccmp.on('playerConnected'/...)`). */ export declare class CCMPPlayersManager implements IPlayersManager { private readonly _players; private readonly _events; private _localPlayer; constructor(events: CCMPEventsManager); findLocalPlayer(): CCMPPlayer | null; getLocalPlayer(): CCMPPlayer; findByRemoteId(remoteId: number): CCMPPlayer | null; getByRemoteId(remoteId: number): CCMPPlayer; findByName(name: string): CCMPPlayer | null; getByName(name: string): CCMPPlayer; syncWithMpPool(): void; registerById(id: number): CCMPPlayer; unregisterById(id: number): CCMPPlayer; findByID(id: number): CCMPPlayer | null; getByID(id: number): CCMPPlayer; findByRemoteID(remoteId: number): CCMPPlayer | null; getByRemoteID(remoteId: number): CCMPPlayer; deleteById(id: number): CCMPPlayer; get iterator(): IWorldObjectsIterator<CCMPPlayer>; private _registerNativePlayerEvents; private _syncRemotePlayersFromRuntime; private _syncLocalPlayerFromRuntime; /** * Идемпотентная точка создания/обновления CCMPPlayer. Все источники * (events, prepopulation, fast-path) проходят сюда. */ private _ensurePlayer; /** * Пытается синхронно достать local player из CCMP, создать CCMPPlayer * и эмитнуть rm::playerReady как sticky-event. Идемпотентна: повторный * вызов после успешной эмиссии — no-op (`_localPlayer !== null`). */ private _tryEmitLocalPlayerReady; private _handleDisconnect; private readonly _iterator; private _iterateDimension; private _iterateRange2D; private _iterateRange3D; }