Codecs¶
A codec defines how a value is validated, encoded and decoded. Sending a value outside the codec's bounds throws. Receiving one drops it.
Numbers¶
| Codec | Type | |
|---|---|---|
int(min, max) |
number |
Whole, bounded. |
quant(min, max, step) |
number |
Rounded onto a grid of step. |
angle(degrees) |
number |
Cyclic, wraps at a whole turn, at that precision. |
f32() |
number |
Roughly 7 digits. |
f64() |
number |
Roughly 15 digits. |
vlq() |
number |
Unsigned integer, exact to 2^53. |
vli() |
number |
Signed integer, exact to 2^53. |
bool() |
boolean |
One bit. |
empty() |
nil |
No payload. |
The wire size of some examples.
| Codec | Bits |
|---|---|
int(0, 100) |
7 |
quant(-512, 512, 0.1) |
14 |
angle(1) |
9 |
f32() |
32 |
Text¶
| Codec | Type | |
|---|---|---|
str(min, max) |
string |
Byte length bounded. |
str.alphabet(symbols, min, max) |
string |
Only the given characters are allowed. A smaller set takes fewer bits per character. |
buffer(min, max) |
buffer |
Opaque bytes, length bounded. |
A 32 character hex string. Each character takes 4 bits, so the whole string takes 16 bytes.
Roblox¶
| Codec | Type | |
|---|---|---|
vec2(component?) |
Vector2 |
f32 per component, or one codec for every component. |
vec3(component?) |
Vector3 |
The same. |
vec3.unit(degrees) |
Vector3 |
A direction at the given precision. Any nonzero vector is normalized when encoded. |
cframe(position, rotation) |
CFrame |
A position codec paired with a rotation codec. |
rotation.none() |
CFrame |
No rotation at all. |
rotation.quat(degrees) |
CFrame |
Any rotation, at that precision. |
color3() |
Color3 |
Three floats. |
color3.rgb565() |
Color3 |
One 16 bit word. |
inst(class?) |
Instance? |
Always optional. If the instance is not replicated to the receiver, it receives nil. |
A CFrame with the position quantised to 0.1 and the rotation to half a degree, and a reference to a part.
Other Roblox types such as UDim2, Region3 and Ray can be sent through :as, described below.
Composites¶
| Codec | Type | |
|---|---|---|
struct({ name = codec }) |
{ name: T } |
Named fields. A field that is not declared throws when encoded. |
array(codec, min, max) |
{ T } |
Count bounded. |
map(key, value, min, max) |
{ [K]: V } |
Count bounded. |
optional(codec) |
T? |
May be absent. |
tagged(field, { name = struct }) |
union | One struct per variant. The variant's name is stored in field. |
enum({ "a", "b" }) |
"a" \| "b" |
One of a fixed set. |
bitfield({ "a", "b" }) |
{ a: boolean, b: boolean } |
One bit per flag. |
A tagged union, and a value that matches its hit variant.
Outcome = Lync.tagged("kind", {
hit = Lync.struct({ target = Lync.int(0, 255) }),
miss = Lync.struct({ at = Lync.vec3() }),
}),
Modifiers¶
A modifier returns a new codec. The codec it was called on is not changed.
| Modifier | Scope | |
|---|---|---|
:validate(fn) |
any | Adds a check. fn(value, context) returns nil to accept or a string to reject. See Validation. |
:as(lift, lower) |
any | Converts between the wire type and a type of your own. |
:newest(hz?) |
set fields | Only the latest value is delivered. hz limits the send rate. |
:as takes two functions. The first converts a decoded wire value to your type. The second
converts your type back to the wire value.
Fraction = Lync.int(0, 255):as(
function(byte)
return byte / 255
end,
function(fraction)
return math.round(fraction * 255)
end
),
UDim = Lync.struct({ scale = Lync.f32(), offset = Lync.int(-4096, 4096) }):as(
function(wire)
return UDim.new(wire.scale, wire.offset)
end,
function(udim)
return { scale = udim.Scale, offset = udim.Offset }
end
),
Using a set only modifier such as :newest inside a packet or query throws at start.