Skip to main content
Created only by Flux.Server. Server-only, so constructing one on a client errors.

Type definition

All listener callbacks receive the sending Player as their first argument, before the event’s own arguments.

Fire()

Sends to one client over the reliable channel.
Player
required
The recipient.
Args...
The payload. Encoded with the event’s schema if one is registered, otherwise with the dynamic encoder.
Returns immediately. The payload is appended to that player’s reliable buffer and flushed on the next Heartbeat, up to about 16 ms later. See Batching.

FireUnreliable()

Sends to one client over the unreliable channel. May be dropped or reordered.
Subject to Roblox’s UnreliableRemoteEvent payload limit. Because Flux batches, the limit applies to the whole accumulated frame rather than to your single call, so many unreliable sends in one frame can collectively exceed it. Keep unreliable traffic to small, self-contained payloads.

FireAll()

Broadcasts to every connected client over the reliable channel, using one FireAllClients rather than a call per player.
Broadcasts use a separate buffer from per-player sends, and are flushed first. A FireAll issued after a Fire(player, ...) in the same frame will reach that player first, so do not interleave the two when order matters.

FireAllUnreliable()

Broadcasts over the unreliable channel. The right tool for continuous world state.

Connect()

Registers a persistent listener for client sends.
(player: Player, Args...) -> ()
required
Invoked once per received message. The sending player is always the first argument.
{ Disconnect: () -> () }
A plain table with a single Disconnect method. Not an RBXScriptConnection, so it has no Connected property and no Destroy.
Listeners are never removed automatically, neither when the creating script is destroyed nor on player leave. Only your Disconnect call removes one. See Connections.
Each callback is dispatched with task.spawn, so listeners run concurrently and an error in one never blocks the others. Listeners are walked from the end of the list backwards, which means the most recently connected runs first. Do not depend on order.
Everything arriving here comes from a client and is untrusted. Generics and schemas constrain your own code, not a tampered client’s packets. Validate types, clamp ranges and verify ownership inside every listener.

Once()

Fires at most once, then removes itself.
Returns nothing. There is no handle, so a Once listener cannot be cancelled before it fires, and if the event never arrives it stays registered for the session. Use Connect with a self-disconnect if you need to be able to back out.

Wait()

Yields the calling thread until the next message on this channel, then returns the sending player followed by the arguments.
(Player, Args...)
The sender, then the payload.
Uses coroutine.running() and coroutine.yield(), so it has to be called from a yieldable thread.It also has no timeout. If the message never arrives, the thread parks forever and both it and its listener entry stay alive. Guard long waits yourself, using the pattern in Connections.

OnInvoke

Assign a function to handle client invocations. It receives the player first, then the client’s arguments, and may return any number of values.
This is a property with an interposed setter, not a method. Flux catches the assignment through __newindex and stores the handler in a module-level table keyed by event name.Three consequences follow: there is exactly one handler per name, assigning twice replaces rather than adds, and every Server object built with that name shares it.
pcall
The handler runs under pcall. Errors are caught, transmitted as a message string, and re-raised on the client by Invoke. Stack traces and error objects do not survive, so return a structured result if the caller needs to branch on failure.
task.spawn
Each request is handled in its own thread, so a yielding handler never blocks other requests. Responses may therefore return out of order.
With no handler registered, incoming requests are silently dropped and the client yields until its 60-second timeout. Register handlers during startup.
There is no Server:Invoke. The server cannot invoke a client. See Invocations.

Shared state

The object itself carries almost nothing. Every operation looks up module-level state through self._id.
string
The channel name. Private.
{ Types.Type }?
The schema passed at construction. Private.
This makes it safe to call Flux.Server("Name") from several modules instead of threading one object through your codebase. It also means an accidental name collision silently merges two systems’ traffic, so namespace your names in a large place, as in "Combat.Hit" or "Shop.Purchase".

Next steps

Client

The other half of the pair.

Events guide

Patterns and pitfalls in prose.