Skip to main content

Examples

Round trip a struct​

local VoidSentryUltimate = require(path.to.VoidSentryUltimate)
local Types = VoidSentryUltimate.Types

local Profile = Types.Struct {
Coins = Types.U32,
DisplayName = Types.String8,
EquippedItem = Types.Optional(Types.U16),
}

local original = {
Coins = 12_500,
DisplayName = "Elentium",
EquippedItem = 17,
}

local bytes = VoidSentryUltimate.Serialize(Profile, original)
local restored = VoidSentryUltimate.Deserialize(Profile, bytes)

print(restored.DisplayName, restored.Coins, restored.EquippedItem)

Encode a compact inventory​

When item identifiers fit from 0 through 255, an array of U8 values keeps both the element representation and count compact:

local Inventory = Types.Array8(Types.U8)
local bytes = VoidSentryUltimate.Serialize(Inventory, { 4, 9, 23, 71 })
local itemIds = VoidSentryUltimate.Deserialize(Inventory, bytes)

Array8 adds a one-byte element count, and every U8 item adds one byte. Use a wider count or item node if either limit can be exceeded.

Send a RemoteEvent payload​

Define the schema in a shared module so the server and client cannot accidentally drift.

local VoidSentryUltimate = require(path.to.VoidSentryUltimate)
local Types = VoidSentryUltimate.Types

local DamageMessage = Types.Struct {
Amount = Types.U16,
Critical = Types.Bool,
Origin = Types.VectorF24,
Target = Types.Instance,
}

return DamageMessage

Serialize on the server:

local bytes = VoidSentryUltimate.Serialize(DamageMessage, {
Amount = 25,
Critical = false,
Origin = Vector3.new(10, 2, -4),
Target = targetPart,
})

DamageEvent:FireClient(player, bytes)

Deserialize on the client with the same schema:

DamageEvent.OnClientEvent:Connect(function(bytes: buffer)
local message = VoidSentryUltimate.Deserialize(DamageMessage, bytes)
print(message.Target, message.Amount)
end)

Types.Instance depends on the Roblox module's _VSID maps. Use Types.SerInstance instead only when the receiver should create a new instance from serialized properties.

Serialize an instance by value​

local SerializablePart = Types.SerInstance("Part", {
Anchored = Types.Bool,
Color = Types.Color3,
Name = Types.String8,
Position = Types.Vector,
Size = Types.Vector,
})

local bytes = VoidSentryUltimate.Serialize(SerializablePart, workspace.SourcePart)
local copiedPart = VoidSentryUltimate.Deserialize(SerializablePart, bytes)
copiedPart.Parent = workspace

Deserialization creates a new Part and assigns the listed properties. Parent is not included unless it is explicitly part of the schema.

Pack eight flags​

local flags = {
true,
true,
false,
false,
true,
false,
false,
true,
}

local oneByte = VoidSentryUltimate.Serialize(Types.BoolPacked, flags)
local restoredFlags = VoidSentryUltimate.Deserialize(Types.BoolPacked, oneByte)

BoolPacked always represents exactly eight booleans.

Choose F24 or F32 deliberately​

For three-dimensional positions, VectorF24 uses 9 bytes while Vector uses 12 bytes:

local CompactPosition = Types.VectorF24
local ExactF32Position = Types.Vector

local compact = VoidSentryUltimate.Serialize(CompactPosition, position)
local regular = VoidSentryUltimate.Serialize(ExactF32Position, position)

VectorF24 is lossy and has less range and precision. Round-trip values from your actual game and compare them against your accepted positional tolerance before choosing it. Use Vector when normal F32 behavior is required.

Quantize UI scales and compact CFrames​

UDim2Quant stores only scale, mapped into 16-bit values over a chosen range. CFrameQuantF16 and CFrameQuant8F16 store F16 position plus quantized Euler angles:

local Scale = Types.UDim2Quant(0, 1)
local CompactCFrame = Types.CFrameQuantF16
local SmallerCFrame = Types.CFrameQuant8F16

local scaleBytes = VoidSentryUltimate.Serialize(Scale, UDim2.fromScale(0.5, 0.25))
local cframeBytes = VoidSentryUltimate.Serialize(CompactCFrame, cframe)

Decoded UDim2Quant offsets are zero. CFrameQuant8F16 is smaller (9 bytes) than CFrameQuantF16 (12 bytes) and coarser in orientation.

Use a fixed-size record​

local DigestRecord = Types.Struct {
Digest = Types.BufferFixed(16),
Label = Types.StringFixed(8),
Samples = Types.ArrayFixed(Types.I16, 4),
}

local bytes = VoidSentryUltimate.Serialize(DigestRecord, {
Digest = digestBuffer,
Label = "SENSOR01",
Samples = { -2, 4, 8, 16 },
})

Digest must be exactly 16 bytes, Label exactly 8 bytes, and Samples exactly four elements. No lengths are written or validated.

Preserve an application header​

local Payload = Types.Struct {
Id = Types.U32,
Message = Types.String8,
}

local bytes = VoidSentryUltimate.SerializeWithOffset(Payload, {
Id = 7,
Message = "ready",
}, 2)

buffer.writeu8(bytes, 0, 1)
buffer.writeu8(bytes, 1, 9)

local decoded = VoidSentryUltimate.DeserializeWithOffset(Payload, bytes, 2)

The first two bytes are initially zero because SerializeWithOffset allocates a new zero-filled buffer of offset + payload length.