Skip to content

BitStream (Russian)

Pavel Akulichev edited this page Sep 24, 2020 · 2 revisions

SL:NET BitStream

Как правильно работать с данными и передавать их по средствам SL:NET
Существует множество способов передачи данных по средствам UDP, но один из самых компактных и быстрых, но не самых удобных - BitStream. В общем и целом, суть работы этого способа заключается в сжатии данных по средствам перевода не типизированных Lua-переменных в типизированный формат, тем самым экономя на размере отправляемого и получаемого пакета. У SL:NET BitStream имеется два основных метода: BitStream:write и BitStream:read. Как не сложно догадаться, эти методы позволяют записывать и читать данные. Также одним из главных методов является BitStream:new - он позволяет создать BitStream для дальнейшего заполнения. Давайте же разберем на примере как записывать данные: представим, что у нас есть данные игрока, которые нам нужно упаковать.

Представим, что у нас есть PlayerID, максимальное значение которого - 255 символов, три координаты, имеющих тип Float, а также PlayerName в формате строки.

local bitStream = BitStream:new() -- для начала создадим новый BitStream
bitStream:write(UINT8, PlayerID) -- UINT8 имеет диапазон значений от 0 до 255, то что надо
bitStream:write(FLOAT, coordX):write(FLOAT, coordY):write(FLOAT, coordZ) 
-- необязательно каждый раз начинать с переменной, в которой хранится BitStream, достаточно продолжать заполнять данные методом `write`
bitStream:write(UINT8, #PlayerName):write(STRING, PlayerName) -- запишем размер строки, чтобы её потом можно было прочитать

Теперь представим, что мы получили такой пакет и теперь нам нужно его разобрать, чтобы использовать эти данные в дальнейшем.

local PlayerID = bitStream:read(UINT8) -- да, вот так вот просто, теперь PlayerID заполнен
local coord = { 0, 0, 0 }
for i = 1, 3 do
  coord[i] = bitStream:read(FLOAT) -- данные, идущие друг за другом, можно читать в цикле
end
local PlayerName = bitStream:read(STRING, bitStream:read(UINT8)) -- а вот так хитро можно прочитать строку

Стоит сказать, что BitStream SL:NET защищен от невалидных значений, поэтому даже если значений, которые вы пытаетесь извлечь, нет, вам вернется значение правильного типа, но оно вероятнее всего будет равно нулю, либо символу 0x0, если возвращаемый результат символьный.

Импорт и экспорт байтов из BitStream
Байты из заполненных BitStream'ов можно экспортировать, а в незаполненные (можно и в заполненные, но я не рекомендую) можно импортировать. Это очень удобно, если нужно передать BitStream на обработку дальше, а в вашей системе используются какие-либо служебные данные в пакете. Например, в начале. Представим, что в каждом пакете передается значение типа BOOL, которое показывает какие-либо параметры, а потом от него нужно избавиться.

local myBool = bitStream:read(BOOL) -- прочитали значение, сохранили в переменную
local exportData = bitStream:export() -- экспортируем байты, теперь это строковая переменная
bitStream = BitStream:new() -- пересоздаем BitStream, чтобы отчистить его от старых данных
bitStream:import(exportData:sub(2, #exportData)) -- импортируем с поправкой на один символ, ибо BOOL - это 1 CHAR
bitStream:setWritePointer(1):setReadPointer(1) -- сбрасываем позиции чтения и записи до единицы (необязательно)

Если вы знаете, что первым действием будет импорт, то можно создать BitStream с начальным набором байтов (стартовый импорт).

local myBool = bitStream:read(BOOL) -- прочитали значение, сохранили в переменную
local exportData = bitStream:export() -- экспортируем байты, теперь это строковая переменная
bitStream = BitStream:new(exportData:sub(2, #exportData)) -- пересоздаем BitStream и сразу импортируем данные
bitStream:setWritePointer(1):setReadPointer(1) -- сбрасываем позиции чтения и записи до единицы (необязательно)

Типы данных, их размер в символах и диапазон значений

  • UINT8 - 1 символ, число от 0 до 255
  • UINT16 - 2 символа, число от 0 до 65,535
  • UINT32 - 4 символа, число от 0 до 4,294,967,295
  • INT8 - 1 символ, число от -128 до 127
  • INT16 - 2 символа, число от -32,768 до 32,767
  • INT32 - 4 символа, число от -2,147,483,648 до 2,147,483,647
  • BOOL - 1 символ, TRUE / FALSE
  • FLOAT - 4 символа, от -3.4E+38 до +3.4E+38
  • STRING - кол-во символов равно кол-ву символов в строке
Clone this wiki locally