Skip to content

A tool to losslessly encode / decode roblox data types to buffers.

License

Notifications You must be signed in to change notification settings

EgoMoose/rbx-bufferize

Repository files navigation

rbx-bufferize

Get it on Github Get it on Wally

A tool to losslessly encode / decode roblox data types to buffers.

local mail = {
	email = "john.doe@email.com",
	street = "321 Road City Country",
	unit = 123,
}

local tbl = {
	name = "John Doe",
	age = 603,
	contact = mail,
	mail = mail,
}

local b: buffer = Bufferize.encode("Hello world!", 123, true, tbl)
print(Bufferize.decode(b)) -- "Hello world!", 123, true, tbl

Instances

Since instances can be converted to roblox data types it's possible for Bufferize to encode and decode them. To help with this Bufferize contains two functions to help with this process.

local b = Bufferize.encode(Bufferize.serializeInstance(workspace.Baseplate))
local baseplateCopy = Bufferize.deserializeInstance(Bufferize.decode(b))

Sometimes properties are references to other instances (i.e. ObjectValue.Value). In order for a reference to be maintained it must be pointing to an instance that is also in the instance tree being serialized.

local objV = Instance.new("ObjectValue")
local folder = Instance.new("Folder")
folder.Parent = objV

objV.Value = folder
local b = Bufferize.encode(Bufferize.serializeInstance(folder))
local objVCopy = Bufferize.deserializeInstance(Bufferize.decode(b))
-- valid: objVCopy.Value == folderCopy

objV.Value = workspace.Terrain
local b = Bufferize.encode(Bufferize.serializeInstance(folder))
local objVCopy = Bufferize.deserializeInstance(Bufferize.decode(b))
-- not valid: objVCopy.Value == nil

Custom Encoding

Bufferize attempts to store all data types losslessly by default. This is helpful if precision is important for you, but depending on your project it may not be needed. In order to remain flexible in this regard Bufferize supports the ability to define custom encodings for any specific data type (except tables).

local inHouseEncoder = Bufferize.custom()

-- CFrame override that stores rotation euler angles XYZ rounded to nearest degree
-- this is not lossless, but depending on your use case it may be good enough and it results
-- in a smaller buffer size
inHouseEncoder:override("CFrame", {
	read = function(b: buffer)
		local stream = Bufferize.stream(b)
		local x, y, z = stream:readf32(), stream:readf32(), stream:readf32()
		local rx, ry, rz = math.rad(stream:readi16()), math.rad(stream:readi16()), math.rad(stream:readi16())
		return CFrame.new(x, y, z) * CFrame.fromEulerAngles(rx, ry, rz, Enum.RotationOrder.XYZ)
	end,
	write = function(cf: CFrame)
		local stream = Bufferize.stream(buffer.create(0))
		local rx, ry, rz = cf:ToEulerAngles(Enum.RotationOrder.XYZ)
		stream:writef32(cf.X)
		stream:writef32(cf.Y)
		stream:writef32(cf.Z)
		stream:writei16(math.round(math.deg(rx)))
		stream:writei16(math.round(math.deg(ry)))
		stream:writei16(math.round(math.deg(rz)))
		return stream.b
	end,
})

local complexRotation = CFrame.new(0, 0, 0, 1, 2, 3, 4)
local lengthA = buffer.len(Bufferize.encode(complexRotation))
local lengthB = buffer.len(inHouseEncoder:encode(complexRotation))
print(lengthA > lengthB) -- true

Versioning

Bufferize strictly adheres to semantic versioning.

When a buffer is encoded the current version of bufferize is included. That way when a buffer is decoded it's possible to ensure we're not attempting to decode with an incompatible version of bufferize.

For example, say you used bufferize v1.0.0 to store data in a datastore and then v2.0.0 is released. If you tried to read the v1.0.0 data with v2.0.0 bufferize then you'd get an error.

This means in practice that when a major version of bufferize releases old data will not be compatible. When the minor or patch version changes you can decode your old data with the new version of bufferize, but you can't decode your new data with the old version.

Supported DataTypes

Data Type Supported Overridable
boolean
buffer
nil
number
string
table
Axes
BrickColor
CatalogSearchParams
CFrame
Color3
ColorSequence
ColorSequenceKeypoint
Content
DockWidgetPluginGuiInfo
Enum
EnumItem
Enums
Faces
FloatCurveKey
Font
Instance
NumberRange
NumberSequence
NumberSequenceKeypoint
OverlapParams
Path2DControlPoint
PathWaypoint
PhysicalProperties
Random
Ray
RaycastParams
RaycastResult
RBXScriptConnection
RBXScriptSignal
Rect
Region3
Region3int16
RotationCurveKey
Secret
SharedTable
TweenInfo
UDim
UDim2
ValueCurveKey
vector
Vector2
Vector2int16
Vector3
Vector3int16

✔ Implemented | ❌ Unimplemented | ⛔ Never

About

A tool to losslessly encode / decode roblox data types to buffers.

Resources

License

Stars

Watchers

Forks

Languages