Releases / v0.88.0
v0.88.0 Hold The Line
2026-09-10 Engine
A host whose connection blips for a moment no longer ends everybody's match, and a lobby code can now survive a server restart. Plus a way to see where your bandwidth is actually going.
Your match survives a moment of bad connection
Two players fought over a relay for ten minutes. Three times, the host's connection dropped for a few seconds — and each time the lobby was destroyed and the other player was quietly cut off. For them, everything in the world vanished except the sky and the HUD, and nothing said why.
A lobby now outlives its host's connection by twenty seconds. The players stay in it, and a host that comes back is put straight back into the match it was already in, with the same people. A rebinding router or a Wi-Fi hiccup costs a stutter instead of the game.
If the host really is gone, the lobby still ends and everybody is told what happened — with a sentence that names it rather than a bare disconnect.
If you host a relay yourself, its log now names lobbies and says why each one ended, instead of printing a count. That count was the reason the problem above went unnoticed for so long: it could not say which lobby died, or what killed it.
A lobby code can outlive the server behind it
floptle serve --lobby-code ABCDEF asks to reclaim a code rather than be handed a
new one. Managed servers get this automatically. It means a server that restarts,
or reconnects to a relay that restarted, comes back on the same six characters
your players already wrote down.
A relay only honours the request when the code genuinely belongs to that game, so asking for somebody else's does nothing but get you an ordinary code.
Joining a server that is still starting up
net.joinState() gained "starting" in the last release. It is now wired
through: a join to a server that is still coming up waits instead of failing, the
engine keeps trying on its own, and the second return carries something you can
put on screen.
local state, why = net.joinState()
if state == "starting" then
find("Status").text = why -- "about 30 seconds"
end
Give up sooner if you want to: net.join(addr, {timeout = 30}). The default is
90 seconds, after which it becomes a normal refusal. This only ever applies to a
server that is waking — an ordinary join is answered immediately, as before.
See where your bandwidth goes
for _, r in ipairs(net.traffic()) do
log(r.kind .. ": " .. r.count .. " msgs, " .. r.bytes .. " bytes")
end
net.traffic() breaks down what your game has sent by message kind, biggest
first, and resets each time you read it — so calling it once a second shows you
the last second.
It is worth a look if you have a fast-paced multiplayer game. A rollback match
should be almost all Input, at a few bytes per player per frame. A large
Snapshot row means full state is going out where inputs would do, which is the
single biggest thing you can fix about a game's bandwidth.
Measuring a relay you run
New alongside the relay: floptle-relay-bench, which drives synthetic players
through a relay and reports what one player costs, where packet loss starts, and
the round-trip time your players would feel. See
relay-bench.md.
Also
floptle servedocuments--lobby-codealongside the flags added last release.- A dedicated server now reports the player cap it is enforcing, so a hosting dashboard can show the real number rather than the one it asked for.
Upgrading
Nothing to do. If you run a region box, take the new fleet agent and relay — the match-survival fix is in the relay.
Floptle Hub
Engine
The binaries are not signed yet. On macOS, right-click the app and pick Open the first time. On Windows, if SmartScreen appears, pick More info then Run anyway.