rock-mod
Version:
Rock-Mod is a powerful framework designed for creating and managing mods for Grand Theft Auto (GTA) games.
75 lines (74 loc) • 4.71 kB
TypeScript
import { type INativeCallerManager } from "../../common/native/INativeCallerManager";
/**
* Реализация `INativeCallerManager` под CCMP — полноценный generic dispatch
* GTA V-нативов по hex-хэшу.
*
* ### Архитектура
*
* **Таблица hash→method** генерируется на build-time скриптом
* `scripts/generate-native-dispatch.mjs` из alloc8or-format nativedb
* (`scripts/data/natives.json`, ~6649 натов). Output:
* `_generated/nativeDispatch.ts`. Каждая запись — `{ns: "<ccmp-namespace>",
* methods: ["<camelMethod1>", "<camelMethod2-fallback>"]}`, где `methods[]`
* содержит канонический имя натива + все `old_names` алиасы (нужно потому
* что CCMP-биндинги могут использовать либо новое каноническое, либо
* легаси-имя в зависимости от момента генерации `@classic-mp/types`).
*
* **Runtime resolve**: при первом вызове `callNative(hash, ...args)`:
* 1. Lookup в `NATIVE_DISPATCH[hash.toLowerCase()]` → `{ns, methods[]}`.
* 2. `ccmp.natives[ns]` — берём namespace-объект.
* 3. Перебираем `methods[]` в порядке: для первой существующей функции —
* биндим `[nsObj, fn]` в `_resolved` кэш.
* 4. Зовём с args через `fn.apply(nsObj, args)`.
* 5. Адаптируем return-shape (см. ниже).
*
* Lookup-кэш `_resolved` — Map с hash-ключом, чтобы не дёргать
* `NATIVE_DISPATCH[]` + `_resolve()` на каждый вызов (multiple natives
* вызываются на каждый render-tick).
*
* ### Адаптация return-shape (CCMP → RageMP-конвенция)
*
* CCMP-нативы для multi-return значений возвращают **объект** с именованными
* полями (например, `getGameplayCamCoord()` → `{x, y, z}`). Геймод (написанный
* под RageMP-конвенцию) ожидает **массив-кортеж** (`[x, y, z]`).
*
* Generic `_adaptResult`:
* - `boolean` (top-level) → `0` или `1` (RageMP'шный native-bool протокол:
* `mp.game.invoke(boolNative)` возвращает число).
* - Object с string-keys → `Object.values(obj)` (порядок гарантирован ES2015
* insertion-order для non-integer keys; CCMP-типы декларируют поля в
* каноническом порядке).
* - Nested object внутри tuple → рекурсивно тоже `Object.values()`
* (для нативов вроде `getShapeTestResult` с nested `endcoords: {x,y,z}`).
* - Bool **внутри** объекта/tuple → не конвертим (нужен для tuple-полей
* типа `[bool, x, y]` где геймод-тип честно ожидает boolean).
* - Primitives / arrays / null → passthrough.
*
* ### Hot path
*
* `callNative` вызывается из render-tick consumer'ов: `HudController`
* (drawBlip), `CameraIdleController.onInterval`, `VehicleIndicatorService`,
* `PolygonZoneRenderer`, `ScriptedMarker`, `ConeDebugRenderer`. После прогрева
* `_resolved`-кэша — один Map.get + `fn.apply` + adapt-проход. Адапт — линейный
* по числу полей возврата (обычно ≤ 5), стоимость незначительная.
*
* ### Ошибки
*
* - **Hash не в DB**: натив отсутствует в nativedb. Throws с подсказкой
* "обновите scripts/data/natives.json" — обычно случается для свежих
* build-specific натов, не вошедших в last-snapshot базы.
* - **Namespace не в `ccmp.natives`**: CCMP-runtime версия не имеет такого
* namespace'а. Throws с указанием ns.
* - **Все method-кандидаты отсутствуют в namespace'е**: CCMP-биндинг не
* экспонирует ни одного из known-имён. Throws с перечислением кандидатов.
*/
export declare class CCMPNativeCallerManager implements INativeCallerManager {
private readonly _resolved;
callNative(hash: string, ...args: unknown[]): unknown;
private _resolve;
/**
* Конвертация CCMP object-return → RageMP tuple-return.
* См. block-комментарий класса (Адаптация return-shape).
*/
private static _adaptResult;
}