BitStream (Russian)
Как правильно работать с данными и передавать их по средствам 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
- кол-во символов равно кол-ву символов в строке