- 201
- 263
Привет. Задумывались ли вы когда-то о возможности передавать информацию между игроками на любом расстоянии, вне зоны стрима и без сторонних серверов? Если да, то это то, что нужно.
broadcaster - это библиотека, реализующая протокол передачи данных по всему серверу. Импортируем её, вызываем одну функцию - сообщение отправлено. Определяем callback функцию, регистрируем - готово, теперь ваш скрипт может принимать сообщения. Просто? Очень.
Использование
broadcaster распределяет сообщения между т.н. хендлерами (обработчиками). Хендлер - это и есть ваша callback функция. Вы указываете название хендлера при отправке сообщения, а также при регистрации callback функции. Это позволяет сразу нескольким скриптам использовать библиотеку.
[!] Обратите внимание [!] для импортирования библиотеки используется не стандартное выражение
Кроме того, для корректной передачи сообщений с русскими символами понадобится модуль encoding:
Перейдем к регистрации хендлера. Для начала определим функцию:
Если вы хотите, чтобы регистрация проходила автоматически, это следует сделать в функции main с некоторой задержкой:
Рассмотрим этот момент подробнее. Первым аргументом является уникальное название хендлера. Вы должны сделать его действительно уникальным, иначе если два скрипта попробуют зарегистрировать два хендлера с одинаковыми названиями, библиотека выдаст ошибку и ни один из скриптов работать не будет. Если вы собираетесь публиковать скрипт, который использует эту библиотеку - не поленитесь оставить в комментариях название хендлера, чтобы избежать конфузов. Ограничений на длину практически нет (256 символов), но имейте ввиду - каждый символ стоит отдельного пакета, поэтому будьте экономными. Вторым аргументом передается сама callback функция.
Также перед завершением работы скрипта нужно удалить хендлеры, которые он зарегистрировал, это требуется для корректной перезагрузки скрипта:
Отправляются сообщения проще:
Но если вы разработчик, то есть шанс что пользователь введёт какой-нибудь необычный символ и работа завершиться ошибкой. В силу ограниченной пропускной способности я был вынужден реализовать собственную кодировку, которая состоит из букв английского и русского алфавита, цифр, а также спец. символов. Надеюсь этого хватит. Но всё же, чтобы вышеописанная ситация не произошла, следует ловить ошибки при отправке следующим образом:
Детали реализации
broadcaster работает поверх битстрима. Он превращает двухбайтовый битстрим в список битов и обратно. У протокола есть 4 типа пакетов: 1 - пакет сигнала начала передачи данных, 2 - пакет сигнала завершения передачи данных, 3 - пакет данных, 4 - пакет названия хендлера. Идентификатор пакета записывается 3 первыми битами внутри каждого пакета. Опознав пакет, broadcaster распаковывает его и проводит манипуляции в зависимости от типа пакета.
Структуры пакетов
Пакет сигнала начала передачи данных
Пакет сигнала завершения передачи данных
Пакет данных
Пакет названия хендлера
Бит чётности - это разновидность проверки данных на наличие повреждений. Если число единиц в двоичном числе непарное, то бит чётности будет 1, если парное - 0.
Сессии
Интересным аспектом являются сессии, которые предотвращают смешывание данных, если два пользователя отправят данные одновременно. Концепт следующий: при отправке сообщения создается новая сессия, ей присвается случайный 4-битный номер. Отправляющиеся пакеты включают в себя номер сессии. Когда получателю поступает пакет сигнала начала передачи данных у него создается новая сессия. При получении последующих пакетов данных или пакетов названия хендлера, библиотека ищет подходящую сессию, если такая есть - добавляет туда полученные данные. Когда приходит пакет завершения передачи данных, broadcaster также ищет сессию, но теперь он удаляет её из списка и передает в обработчик сессий, где извлекается название хендлера и если такой зарегистрирован, данные передаются ему.
Присутствует механизм очистки старых сессий - если последнее обращение к незавершенной сессии было более 30 секунд назад, она будет удалена при получении следующего пакета.
Тип передаваемых данных
По-умолчанию, пользуясь теми методами, что я описал выше, для передачи доступны только строки. Но я специально вынес прикладной интерфейс в broadcaster.lua, поэтому вы можете спуститься чуть ниже - broadcaster/proto.lua. Там вам понадобится функция
Функция вернёт список списков - в каждом вложенном списке 16 бит в виде
Для того, чтобы данные приходили вам в "сыром" виде (тоже в виде таблицы, как вы их отправляли, а не строки), нужно при регистрации хендлера указать третий параметр - rawData, установить его на true.
Возможно вы заметите то огромное количество логов, которое производит библиотека. Но, к сожалению, это необходимость на стадии бета-тестирования. В случае, если обнаружите логи типа WARN, ERROR или FATAL - скидывайте moonloader.log в комментарии. broadcaster совсем не работает на samp-rp и плохо работает на advance-rp. Оставляйте отзывы о работе на других серверах.
Честно говоря уже устал писать, ниже библиотека со всеми зависимостями, а также чатик на её основе. Для более углубленной информации изучайте исходники, там везде комментарии. Спасибо @EvgeN 1137 за идею и @randazzo за тестирование.
Git репозиторий: https://github.com/r4nx/broadcaster
Распространяется под лицензией MIT (кратко: единственное требование - указание копирайтов)
broadcaster - это библиотека, реализующая протокол передачи данных по всему серверу. Импортируем её, вызываем одну функцию - сообщение отправлено. Определяем callback функцию, регистрируем - готово, теперь ваш скрипт может принимать сообщения. Просто? Очень.
Использование
broadcaster распределяет сообщения между т.н. хендлерами (обработчиками). Хендлер - это и есть ваша callback функция. Вы указываете название хендлера при отправке сообщения, а также при регистрации callback функции. Это позволяет сразу нескольким скриптам использовать библиотеку.
[!] Обратите внимание [!] для импортирования библиотеки используется не стандартное выражение
require
, а функция import
из moonloader. В ней нужно указывать не просто название библиотеки, а путь к ней - если ваш скрипт находится в папке moonloader, то вам необходимо делать это так:
Lua:
local broadcaster = import('lib/broadcaster.lua')
Lua:
local encoding = require 'encoding'
encoding.default = 'CP1251'
u8 = encoding.UTF8
Перейдем к регистрации хендлера. Для начала определим функцию:
Lua:
function myHandler(message)
sampAddChatMessage('New message: ' .. u8:decode(message), 0xAAAAAA)
end
Lua:
wait(100)
broadcaster.registerHandler('myhndl', myHandler)
Также перед завершением работы скрипта нужно удалить хендлеры, которые он зарегистрировал, это требуется для корректной перезагрузки скрипта:
Lua:
function onScriptTerminate(scr)
if scr == thisScript() then
broadcaster.unregisterHandler('myhndl')
end
end
Lua:
broadcaster.sendMessage(u8('hello world'), 'myhndl')
Lua:
local result, returned = pcall(broadcaster.sendMessage, u8('hello world'), 'myhndl')
if not result then
print('error occured while sending msg:\n' .. returned)
end
Детали реализации
broadcaster работает поверх битстрима. Он превращает двухбайтовый битстрим в список битов и обратно. У протокола есть 4 типа пакетов: 1 - пакет сигнала начала передачи данных, 2 - пакет сигнала завершения передачи данных, 3 - пакет данных, 4 - пакет названия хендлера. Идентификатор пакета записывается 3 первыми битами внутри каждого пакета. Опознав пакет, broadcaster распаковывает его и проводит манипуляции в зависимости от типа пакета.
Структуры пакетов
Пакет сигнала начала передачи данных
Позиция (в битах) | Описание |
---|---|
1-3 | Идентификатор пакета (1) |
4-7 | Идентификатор сессии |
Пакет сигнала завершения передачи данных
1-3 | Идентификатор пакета (2) |
4-7 | Идентификатор сессии |
Пакет данных
1-3 | Идентификатор пакета (3) |
4-7 | Идентификатор сессии |
8 | Бит чётности |
9-16 | Данные |
Пакет названия хендлера
1-3 | Идентификатор пакета (4) |
4-7 | Идентификатор сессии |
8 | Бит чётности |
9-16 | Название хендлера |
Бит чётности - это разновидность проверки данных на наличие повреждений. Если число единиц в двоичном числе непарное, то бит чётности будет 1, если парное - 0.
Сессии
Интересным аспектом являются сессии, которые предотвращают смешывание данных, если два пользователя отправят данные одновременно. Концепт следующий: при отправке сообщения создается новая сессия, ей присвается случайный 4-битный номер. Отправляющиеся пакеты включают в себя номер сессии. Когда получателю поступает пакет сигнала начала передачи данных у него создается новая сессия. При получении последующих пакетов данных или пакетов названия хендлера, библиотека ищет подходящую сессию, если такая есть - добавляет туда полученные данные. Когда приходит пакет завершения передачи данных, broadcaster также ищет сессию, но теперь он удаляет её из списка и передает в обработчик сессий, где извлекается название хендлера и если такой зарегистрирован, данные передаются ему.
Присутствует механизм очистки старых сессий - если последнее обращение к незавершенной сессии было более 30 секунд назад, она будет удалена при получении следующего пакета.
Тип передаваемых данных
По-умолчанию, пользуясь теми методами, что я описал выше, для передачи доступны только строки. Но я специально вынес прикладной интерфейс в broadcaster.lua, поэтому вы можете спуститься чуть ниже - broadcaster/proto.lua. Там вам понадобится функция
proto.sendData()
, которая принимает на вход массив из 1-байтовых чисел (до 255) в качестве данных, а также такой же массив (из чисел) в качестве названия хендлера. Но как так - название-то - текст, как из него сделать числа? На помощь приходит broadcaster/encoder.lua. С помощью следующего нехитрого кода можно закодировать текст кодировкой, которую использует broadcaster:
Lua:
local encoder = require 'broadcaster.encoder'
local charset = require 'broadcaster.charset'
local encodedHandlerId = encoder.encode('myhndl', charset.MESSAGE_ENCODE)
{0, 0, 1, 0, 1, 1, 1, ...}
. Один вложенный список - 1 битстрим. Чтобы записать бит, используйте raknetBitStreamWriteBool
; после записи всех битов установите оффсет записи на 16 бит с помощью raknetBitStreamSetWriteOffset
.Для того, чтобы данные приходили вам в "сыром" виде (тоже в виде таблицы, как вы их отправляли, а не строки), нужно при регистрации хендлера указать третий параметр - rawData, установить его на true.
Возможно вы заметите то огромное количество логов, которое производит библиотека. Но, к сожалению, это необходимость на стадии бета-тестирования. В случае, если обнаружите логи типа WARN, ERROR или FATAL - скидывайте moonloader.log в комментарии. broadcaster совсем не работает на samp-rp и плохо работает на advance-rp. Оставляйте отзывы о работе на других серверах.
Честно говоря уже устал писать, ниже библиотека со всеми зависимостями, а также чатик на её основе. Для более углубленной информации изучайте исходники, там везде комментарии. Спасибо @EvgeN 1137 за идею и @randazzo за тестирование.
Git репозиторий: https://github.com/r4nx/broadcaster
Распространяется под лицензией MIT (кратко: единственное требование - указание копирайтов)
Вложения
Последнее редактирование: