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.
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.
Pure Luau vector
local LuauVS = require(path.to.LuauVS)
local Types = LuauVS.Types
local Direction = Types.VectorF16
local bytes = LuauVS.Serialize(Direction, vector.create(0.25, 0.5, 1))
local restored = LuauVS.Deserialize(Direction, bytes)