rock-mod
Version:
Rock-Mod is a powerful framework designed for creating and managing mods for Grand Theft Auto (GTA) games.
108 lines (107 loc) • 4.46 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.CCMPNetManager = void 0;
const CCMPEventsManager_1 = require("./events/CCMPEventsManager");
const CCMPRPCManager_1 = require("./rpc/CCMPRPCManager");
/**
* Имя cooperation-события для синтеза `rm::playerReady` на клиенте.
*
* Клиент шлёт это сразу после `connectionStateChanged.connected = true`;
* сервер отвечает тому же игроку этим же именем с `{ remoteId }`. Клиентский
* `CCMPEventsBridge` ловит ответ и эмитит `rm::playerReady`.
*/
const CLIENT_READY_EVENT = "rm::clientReady";
/**
* Имя приватного события для зеркалирования клиентских `console.*` вызовов
* в серверный stdout. Реализация клиента — `CCMPConsoleForwarder`.
*/
const CLIENT_LOG_EVENT = "rm::clientLog";
function isSerializedError(value) {
return typeof value === "object" && value !== null && value.__error === true;
}
function isSerializedToString(value) {
return (typeof value === "object" && value !== null && typeof value.__toString === "string");
}
function rehydrateArg(value) {
if (isSerializedError(value)) {
// Приоритет: stack -> name+message -> toString-репрезентация.
if (value.stack) {
return value.stack;
}
if (value.name && value.message) {
return `${value.name}: ${value.message}`;
}
if (value.message) {
return value.message;
}
if (value.toString) {
return value.toString;
}
return "<unknown error>";
}
if (isSerializedToString(value)) {
return value.__toString;
}
return value;
}
function pickConsoleSink(level) {
switch (level) {
case "error":
return console.error.bind(console);
case "warn":
return console.warn.bind(console);
case "info":
return console.info ? console.info.bind(console) : console.log.bind(console);
case "debug":
return console.debug ? console.debug.bind(console) : console.log.bind(console);
case "log":
default:
return console.log.bind(console);
}
}
class CCMPNetManager {
_eventsManager;
_rpcManager;
get events() {
return this._eventsManager;
}
get rpc() {
return this._rpcManager;
}
constructor() {
this._eventsManager = new CCMPEventsManager_1.CCMPEventsManager();
this._rpcManager = new CCMPRPCManager_1.CCMPRPCManager();
this._registerClientReadyCooperation();
this._registerClientLogForwarder();
}
_registerClientReadyCooperation() {
// Регистрируем напрямую через `ccmp.on` (а не через events.onClient),
// потому что событие не входит в `IClientToServerEvents` — это
// приватный rock-mod протокол.
ccmp.on(CLIENT_READY_EVENT, (player) => {
const ccmpPlayer = ccmp.players.getById(player.id);
if (!ccmpPlayer) {
return;
}
// Зеркалит контракт client-side `CCMPEventsManager`: payload всегда
// массивом, на клиенте развернётся обратно в позиционные аргументы.
ccmpPlayer.emit(CLIENT_READY_EVENT, [{ remoteId: player.id }]);
});
}
/**
* Принимает зеркалированные клиентские `console.*` вызовы и печатает в
* серверный stdout. Необходимо для отладки CCMP-клиента: иначе ошибки
* boot'а уходят в игровую консоль (F8), не видны разработчику.
*
* Парный клиент — `CCMPConsoleForwarder`.
*/
_registerClientLogForwarder() {
ccmp.on(CLIENT_LOG_EVENT, (player, payload) => {
const level = payload?.level ?? "log";
const args = Array.isArray(payload?.args) ? payload.args : [];
const sink = pickConsoleSink(level);
sink(`[client:${player.id}]`, ...args.map(rehydrateArg));
});
}
}
exports.CCMPNetManager = CCMPNetManager;