What's new in 1.1
A release for games that are somewhere else. The generated modules do not change, so there is nothing to do on upgrading.
--fromconverts another library’s definitions into a draft schema.blinkblox net.zap --from zapreads a zap config;--from bytenet,packet,quicknetandwarprun a Luau definitions file against a stand-in for the library that records what it defines. See the command line.- The draft does not guess. What the other library has no way to say – how often a client may
fire, how long an array may be, which side sends a packet – is a
TODO(convert)comment where the answer goes, and is listed when the command finishes. What has no equivalent is named, with its line. The draft is compiled before it is handed over. - A guide for each: plain remotes, zap, ByteNet, Packet, QuickNet and Warp. Each has a short wrapper that gives the generated modules the other library’s call names, so a game can move its definitions first and its call sites after, one event at a time.
A release built from other libraries’ bug reports: about two hundred, from the DevForum threads and issue trackers of upstream Blink, zap, ByteNet, Packet, Warp and QuickNet, each checked against this fork. The wire does not change, so a module built by 1.0.0 talks to one built by 0.40.0 or later.
- A missing Instance costs one event, not the packet. Under StreamingEnabled an Instance the sender had is often not there on arrival. That event alone is refused and reported, and the rest of the packet is still read, at no cost to decoding when everything arrives.
- Mistakes that were silent are named. A second copy of a module in an
Actor errors at require; a
send made with
:says so; a function’s second.Onwarns; a client left waiting for a server explains why after five seconds; a file of events imported twice warns (W3036). The client’s queues stop at 256, as the server’s do. - New types:
Vector2,UDim,UDim2,NumberRange,ColorSequence,TweenInfo, andEnum(Name)for a Roblox enum’s items, sent byValue. RemotesFolderkeeps the remotes in a folder.- Types survive the new type solver however many events a schema has.
- The Studio plugin keeps up with typing on long schemas, and saving, deleting and generating are undo steps.
The compiler is on Wally as a library, for code that compiles schemas inside Roblox. The generated modules are exactly 1.0.0’s, so nothing needs regenerating.
0.42.0
Section titled “0.42.0”A release about speed, measured against every library this fork is compared with – QuickNet and Warp joined the benchmarks – and against 0.41.2 in one harness. The wire does not change: modules from 0.40.0 on still talk to these, so either side can be updated first.
- A packet decodes without allocating. A channel’s decoder is a function of the module, and a Single Sync listener is called without a pcall of its own: when it throws, the packet’s pcall sees the listener was running, reports it as before, and decoding goes on with the next event. A hundred events carrying a part decode in 0.011 ms, from 0.021, where Blink’s take 0.013.
- The client refills the last frame’s packet when the next is the same size: a thousand booleans flush in 0.005 ms, from 0.042.
- A
boolean[]is read the faster way where the module runs, measured as it loads: bits natively, rows of eight interpreted, about 30% faster there.PackedBooleanReaderfixes the choice.
0.42.1
Section titled “0.42.1”A toolchain release: the compiler emits exactly what 0.42.0 did, so nothing needs regenerating.
- The toolchain runs on LuneBlox 0.10.10, on the same Luau and flags as before.
- CI, the release workflow and the docs build run on Node.js 24.
0.41.0
Section titled “0.41.0”0.41.0 is a release about bytes and speed again, and every part of it but one waits for your schema to ask for it. The wire format does not change: a schema that compiled under 0.40.0 sends the same bytes.
0.41.2
Section titled “0.41.2”A toolchain release: the compiler emits exactly what 0.41.1 did, so nothing needs regenerating.
- The toolchain runs on LuneBlox 0.10.8, on the same Luau and flags as before.
- The Studio benchmark prints how many events the server heard after each tool, and warns when it is fewer than were sent. Its Loss column is exact: only a full count reads 0%.
0.41.1
Section titled “0.41.1”A toolchain release: the compiler emits exactly what 0.41.0 did, byte for byte, so nothing needs regenerating.
- The native executables are built on LuneBlox, Lune on the Luau version Roblox runs with Roblox’s fast flags, and the compiler inside them is 14 to 25% faster.
- Run through pesde, the compiler hands itself over to
lunebloxwhen it is installed, and otherwise runs on the Lune pesde started, as before.BLINKBLOX_NO_LUNEBLOX=1keeps it there. - The benchmarks are measured on LuneBlox, so their figures are what Roblox runs.
Upgrading
Section titled “Upgrading”- Update the compiler to 0.41.0 (the rokit pin, the release binary or the Studio plugin).
- Regenerate the server and the client module from the same schema, and ship them together.
- Nothing in the game’s code changes: every member and every handler keeps its name and signature.
A 0.41.0 module talks to a 0.40.0 one, since WIRE_VERSION is still 3, but a quantized float or a new
option is part of the schema signature, and a fix applies only on the side built by the release that
has it. Ship both sides from one build.
Quantized floats
Section titled “Quantized floats”A float with a step and a closed range is sent as whole steps above its minimum, in the narrowest integer that holds them. You say how precise a value is and where it can be; BlinkBlox picks the bytes.
type Aim = f32<0.01>(-1..1)type Height = f32<0.25>(100..200)Aim is one byte where the float took four, and Height two. A step on a float was refused before,
so nothing that compiled changes. See quantized floats.
An outbound budget
Section titled “An outbound budget”option OutboundBytesPerSecond
gives each player a byte budget for what the server sends, and
Priority: Low marks the unreliable events and streams that may
wait. Every send is charged; only a low one is ever left out, while its player’s budget is spent. A
low stream held per player sends the state it holds once the budget refills.
option OutboundBytesPerSecond = 20000
event Footstep { From: Server, Type: Unreliable, Call: SingleSync, Priority: Low, Data: vector}Without the option the module carries no budget at all, byte for byte what 0.40.0 generated.
A client sends at most 60 times a second
Section titled “A client sends at most 60 times a second”Measured in Studio, every remote call costs about 11 bytes beside its payload, and the server’s inbound
budget charges each packet at least 128 bytes – so a client at 500 frames a second that sent every
frame spent the whole default budget on those floors. A client now sends at most
ClientFlushRate times a second, 60 unless the schema
says. A StepReplication your code calls still sends at once. The same session sent up to 480 calls a
second and met no cap of Roblox’s own. See the cost of a remote
call.
Faster
Section titled “Faster”- Dispatch by halving. The event an index names is found by halving the range rather than one comparison after another: 100 events a frame over 128 declarations decode in 0.053 ms interpreted, from 0.086. A channel of up to eight declarations compiles exactly as it did.
- No checks a read already makes. A received length is not checked below its minimum, nor above 65535 when its varint refuses that itself, and an integer skips a bound its type already meets.
- Checks on a local. A ranged number decoded into a struct field is checked before it is stored, rather than read back out of the table for each bound: 30% off a struct of three ranged numbers.
Every figure is in Benchmarks, and the full list in the changelog.
