Назначение
tera-network-proxy передает TCP-трафик между клиентом TERA и игровым сервером, позволяя читать, изменять, блокировать и создавать пакеты. Для автора обычного модуля публичный вход — mod.hook и mod.send. Классы ниже предназначены для интеграции самой сетевой части.
Путь пакета
Сервер → TCP → расшифровка → сборка полного пакета → Dispatch
↓ хуки
Клиент ← TCP ← шифрование ← пакет после обработки ←─────┘
Обратный поток проходит от RealClient через расшифровку и буфер к Dispatch.handle(data, false), затем к серверу. TCP передает поток байтов: один data сокета не обязан совпадать с одним игровым пакетом. PacketBuffer собирает полные сообщения по длине заголовка. Рукопожатие и обмен ключами предшествуют обработке обычных пакетов; модули работают с расшифрованными сообщениями.
У каждого соединения собственные Dispatch, карта opcode, определения протокола и состояние шифрования. Медленный синхронный обработчик задерживает дальнейшую обработку трафика в цикле событий. Не выполняйте в нем длительные вычисления и файловый ввод-вывод.
Dispatch
Dispatch объединяет хуки конкретного opcode и '*' по order, проверяет фильтры, затем разбирает сообщение по нужной версии определения. Изменение очищает кеш разобранного события. Если пакет остался заблокирован, handle возвращает false; иначе — итоговый Buffer.
| API текущей реализации | Назначение |
|---|---|
hook(moduleName, name, version, options, callback) |
Низкоуровневая регистрация с явным именем модуля |
unhook(handle), unhookModule(name) |
Удаление хука или хуков модуля |
write(outgoing, buffer) |
Отправка готового пакета |
write(outgoing, name, version, data) |
Сериализация и отправка объекта |
handle(data, incoming, fake = false) |
Выполнение цепочки хуков |
fromRaw(name, version, data) |
Разбор Buffer по определению |
toRaw(name, version, data) |
Сериализация объекта |
resolve(name, version = '*') |
Разрешение определения |
destructor() |
Очистка хуков |
У write параметр outgoing: true означает сервер, а у handle incoming: true означает клиент. Сгенерированные пакеты тоже проходят handle, но с fake: true. Перед raw-отправкой буфер копируется, поскольку шифрование меняет байты на месте.
Connection
const { Connection, RealClient, FakeClient } = require('tera-network-proxy');
Текущая сигнатура — new Connection(metadata, clientInterfaceConnection, noIntegrity = false). В metadata нужны согласованные данные клиента: protocolVersion, majorPatchVersion, minorPatchVersion, platform, maps.protocol, maps.sysmsg, dataFolder. Их обычно подготавливает Toolbox. Это не автономный пример подключения: произвольные пустые метаданные не создадут рабочий протокол.
connection.connect(client, options) передает параметры в net.connect и возвращает сокет сервера. На серверном сокете включается setNoDelay(true). connection.dispatch содержит обработчик пакетов. close() закрывает обе стороны, уничтожает Dispatch и освобождает состояние соединения. Шифрование и проверка целостности пакетов выполняются инфраструктурой с учетом версии клиента.
RealClient
new RealClient(connection, socket) подключает настоящий игровой TCP-клиент. У него собственный буфер и состояние обработки трафика в сторону сервера. Для принятого сокета используйте socket.setNoDelay(true), как делает интеграция Toolbox. Управление этим клиентом выполняет Connection; обычному модулю создавать его не требуется.
FakeClient
new FakeClient(connection, keys) представляет соединение без входящего сокета игрового клиента. Необязательный keys — массив двух буферов по 128 байт; без него они генерируются случайно. Класс наследует EventEmitter.
| Событие | Значение |
|---|---|
connect |
Завершено первоначальное рукопожатие и обмен ключами |
timeout |
Событие сокета сервера |
error |
Ошибка сокета сервера |
close |
Закрытие FakeClient |
FakeClient сам не реализует вход в учетную запись или игровую логику. Успешное TCP/криптографическое соединение не означает авторизацию в игре.
Отличия от исторического README
В поставляемом README приведен API старого TERA Proxy. В этой сборке менеджер модулей находится в bin/mod-manager.js/bin/mod.js: у Dispatch нет описанных там load() и reset(). Пример с new Connection() без метаданных также устарел. Используйте точные имена S_LOGIN, а не полагайтесь на старое обещание преобразования sLogin. Raw-хук получает копию буфера: измененный Buffer нужно вернуть.
Источники: node_modules/tera-network-proxy/README.md, lib/connection/{index,dispatch}.js, lib/clients/{RealClient,FakeClient}.js, lib/packetBuffer.js.