Skip to content

Flare

Flare is Cluaupp’s network kernel: Zap-tight packing, batched reliable/unreliable remotes, and query RPC. You do not hand-wire remotes — write src/ReplicatedStorage/Shared/Net/Net.flare, run cluaupp build, and use the generated Net.clh / Net.luau API (Net.Hit.FireServer, Net.GetCoins.Invoke(), …). This header exposes the low-level Flare.write* / Flare.read* helpers and Flare.open used by generated code.

Header: #include <clpp/libs/flare.clh> (kernel). Gameplay includes the generated Net.clh. Runtime: CluauppLibs.Flare.

  • Schema-first networking with typed packets and queries instead of ad-hoc Net tables.
  • Binary buffers on the hot path (QuickNet-style cursors, instance sidecar arrays).
  • Inbound client packets are gated by Ward — size cap, token bucket, and from Client direction. Forged server-origin ids are struck, not dispatched.
  • Kernel only in games — gameplay calls generated Net.*; custom codecs in advanced pipelines call Flare.write* / read*.

When not to use: trivial one-off remotes (Net), or declaring packets in CL++ without a .flare file (generation owns the game API). Keep’s own data handshake (NotifyReady) is separate — do not replace it with a Flare packet.

src/ReplicatedStorage/Shared/Net/Net.flare (build generates Net.clh + Net.luau):

opt name = Net
packet Hit(Player target, i32 damage) from Client
packet Announce(string text) from Server
packet Spark(Vector3 pos) from Server unreliable
query GetCoins() -> i32
KindGenerated API
from ClientFireServer(...) on the client; Connect on the server (first arg is Player)
from ServerFire(recipient, …fields) / FireAll(…fields) on the server; Connect on the client (fields only — no recipient)
queryInvoke(...) on the client; On on the server (first arg is Player, return the result)
#pragma strict
#include <clpp/roblox.clh>
#include "Net.clh"
[[server]]
void init() {
Net.Hit~>Connect(func (Player player, Player target, int damage) {
if (damage < 1 || damage > 25) {
return;
}
post(player.Name);
});
Net.GetCoins.On(func (Player player) {
return 100;
});
}
[[client]]
void attack(Player target) {
Net.Hit.FireServer(target, 25);
}
[[client]]
void showCoins() {
int coins = Net.GetCoins.Invoke();
}

Full join handshake: Connection.

Client says it is ready; server replies with session identity. Place the schema next to gameplay remotes:

opt name = Net
packet Ready() from Client
packet Welcome(i32 userId, f64 clock) from Server
query Session() -> i32
#pragma strict
#include <clpp/roblox.clh>
#include "Net.clh"
#include <clpp/libs/keep.clh>
#include <clpp/libs/ward.clh>
[[server]]
void init() {
Net.Ready~>Connect(func (Player player) {
Ward.Grace(player, 2);
Keep.Server.WaitFor(player);
Net.Welcome.Fire(player, player.UserId, tick()); // recipient, then schema: i32, f64
});
Net.Session.On(func (Player player) {
return player.UserId;
});
}
[[client]]
void init() {
Keep.Client.Init();
Net.Welcome~>Connect(func (int userId, double clock) {
post(userId);
});
Net.Ready.FireServer();
int me = Net.Session.Invoke();
}

After a legitimate server teleport, call Ward.Grace so movement checks do not look like a speed hack. Keep still owns persisted data; this channel is gameplay only.

Manual cursor (kernel):

#include <clpp/libs/flare.clh>
void pack() {
FlareCursor c = Flare.cursor();
Flare.writeu16(c, 42);
int n = Flare.readu16(c); // must use a fresh cursor on encoded buf in real code
}

Returns: FlareCursor — empty write buffer (default capacity 64).

When: Building a payload byte-by-byte in generated or custom codecs.

Example

FlareCursor c = Flare.cursor();

Returns: FlareCursor — buffer with initial capacity size.

When: Known payload size to reduce reallocations.

Example

FlareCursor c = Flare.cursor(256);

Returns: FlareSession — registers packets/queries against remotes under host.

When: Generated Net.luau startup (not typical game CL++).

Example

FlareSession session = Flare.open(netModule);

Returns: auto — packet API object (generated spec: id, reliability, write/read fns).

When: Registering a fire-and-forget packet definition.

Example

session.packet(spec); // spec built by codegen

Returns: auto — query API object (Invoke client-side, On server-side).

When: Registering request/response RPC.

Example

session.query(spec);

Returns: Luau nil. Writes unsigned 8-bit integer at cursor offset (grows buffer as needed).

When: Packed enums or small counters.

Example

Flare.writeu8(c, 255);

Returns: Luau nil. Writes unsigned 16-bit integer (little-endian).

When: Length prefixes, ids.

Example

Flare.writeu16(c, 1000);

Returns: Luau nil. Writes unsigned 32-bit integer.

When: Timestamps, large ids.

Example

Flare.writeu32(c, 1);

Returns: Luau nil. Writes signed 8-bit integer.

When: Small signed deltas.

Example

Flare.writei8(c, -1);

Returns: Luau nil. Writes signed 16-bit integer.

When: Coordinates or scores in ±32k range.

Example

Flare.writei16(c, -500);

Returns: Luau nil. Writes signed 32-bit integer.

When: .flare i32 fields.

Example

Flare.writei32(c, 25); // damage in Hit packet

Returns: Luau nil. Writes IEEE float32.

When: Compact vectors and normals.

Example

Flare.writef32(c, 3.14);

Returns: Luau nil. Writes IEEE float64.

When: Full-precision numbers in custom payloads.

Example

Flare.writef64(c, 1.0);

Returns: Luau nil. Writes boolean as a single byte.

When: Flags in binary protocols.

Example

Flare.writebool(c, true);

Returns: Luau nil. Writes length-prefixed string (u16 length + bytes).

When: Names, chat, ids.

Example

Flare.writestring(c, "hi");

Returns: Luau nil. Writes three float32 components.

When: Positions and directions in packets.

Example

Flare.writeVector3(c, Vector3.new(0, 10, 0));

Returns: Luau nil. Writes two float32 components.

When: UI or 2D math on the wire.

Example

Flare.writeVector2(c, Vector2.new(1, 0));

Returns: Luau nil. Writes CFrame as 12 float32 components (runtime layout).

When: Replication of full transforms.

Example

Flare.writeCFrame(c, part.CFrame);

Returns: Luau nil. Writes Color3 in packed form used by Flare.

When: Tint or team color fields.

Example

Flare.writeColor3(c, Color3.new(1, 0, 0));

Returns: Luau nil. Writes scale + offset for UDim.

When: UI schema fields.

Example

Flare.writeUDim(c, UDim.new(0.5, 0));

Returns: Luau nil. Writes two UDim components.

When: UI size/position in .flare.

Example

Flare.writeUDim2(c, UDim2.new(1, 0, 1, 0));

Returns: Luau nil. Writes BrickColor id.

When: Legacy color fields.

Example

Flare.writeBrickColor(c, BrickColor.Red());

Returns: Luau nil. Writes nested buffer with length prefix.

When: Opaque blobs alongside structured fields.

Example

Flare.writebuffer(c, myBuf);

Returns: Luau nil. Appends instance to cursor sidecar and writes reference index.

When: Passing parts, tools, or characters (instances ride parallel to the buffer).

Example

Flare.writeInstance(c, part);

Returns: int — unsigned byte at cursor (advances offset).

When: Decoding generated packet bodies.

Example

int b = Flare.readu8(c); // 255 if that was written

Returns: int — unsigned 16-bit value.

When: Reading length or id fields.

Example

int n = Flare.readu16(c); // 1000

Returns: int — unsigned 32-bit value.

When: Large counters.

Example

int n = Flare.readu32(c);

Returns: int — signed 8-bit value.

When: Small signed fields.

Example

int n = Flare.readi8(c); // -1

Returns: int — signed 16-bit value.

When: .flare i16 fields.

Example

int n = Flare.readi16(c);

Returns: int — signed 32-bit value.

When: .flare i32 fields such as coin counts.

Example

int coins = Flare.readi32(c); // 100

Returns: double — float32 decoded to Luau number.

When: Vector components.

Example

double x = Flare.readf32(c);

Returns: double — float64 value.

When: High-precision custom data.

Example

double v = Flare.readf64(c); // 1.0

Returns: bool — boolean from one byte.

When: Flag decoding.

Example

bool ok = Flare.readbool(c); // true

Returns: string — length-prefixed string.

When: Text fields in packets.

Example

string s = Flare.readstring(c); // "hi"

Returns: Vector3.

When: World-space replication.

Example

Vector3 p = Flare.readVector3(c);

Returns: Vector2.

When: 2D data.

Example

Vector2 v = Flare.readVector2(c);

Returns: CFrame.

When: Transform replication.

Example

CFrame cf = Flare.readCFrame(c);

Returns: Color3.

When: Color fields.

Example

Color3 col = Flare.readColor3(c);

Returns: UDim.

When: UI decoding.

Example

UDim d = Flare.readUDim(c);

Returns: UDim2.

When: UI size/position decode.

Example

UDim2 d2 = Flare.readUDim2(c);

Returns: BrickColor.

When: Legacy color decode.

Example

BrickColor bc = Flare.readBrickColor(c);

Returns: buffer — nested buffer slice.

When: Opaque attachment fields.

Example

buffer b = Flare.readbuffer(c);

Returns: Instance — next instance from the cursor sidecar (may be nil if absent).

When: Resolving written instance references.

Example

Instance inst = Flare.readInstance(c); // same part that was written