Start typing to search packages!
sequenaplus
By @qscythee
Roblox
MirroredSequena+
Sequena+ is the client-facing name for this redesigned networking library.
The installed Wally package and Luau module are qscythee/sequenaplus and
Sequena respectively.
Generated by Rojo 7.7.0.
Getting Started
To build the place from scratch, use:
rojo build -o "SequenaPlus.rbxlx"
Next, open SequenaPlus.rbxlx in Roblox Studio and start the Rojo server:
rojo serve
Wally & pesde Support,
wally add qscythee/sequenaplus@0.2.0
(same for pesde)
For more help, check out the Rojo documentation.
Usage Example
local Data = Sequena.Data
local MyEvent = Sequena.Define(
{
Name = "Action",
Reliable = true,
UseDelta = true,
},
Data.U8,
Data.Vector3,
Data.String
)
Packets must have non-empty names. Names use deterministic IDs, so adding or reordering definitions does not change the wire ID. Names must be unique and stable between the server and client; packet names are part of the network protocol.
For more help, join this Discord Server Link
Documentation site
The VitePress documentation site lives in docs/. To develop or preview it:
cd docs
npm install
npm run dev
Build it with npm run build. The main branch deploys the generated site to
GitHub Pages through .github/workflows/docs.yml.
Functional library tests
The repository includes a client/server functional test harness in
tests/functional/ and
integration.project.json. Sync it with Rojo:
rojo serve integration.project.json
Open a place in Studio, connect the Rojo plugin, and press Play. The server
and client runners report assertions through the Roblox TestService output.
The harness covers primitive values, Roblox values, tables, structs,
composites, dynamic values, delta packets, runtime validation, and
request/response packets. Performance benchmarking lives separately under
benchmarks/networking/.
Networking benchmark
benchmarks/networking/ is an isolated benchmark project. It has its
own Rojo project and Wally manifest, and reports engine-observed send/receive
Kbps median and peak, message tension, RTT, loss, and sampled CPU time. See
its README for setup and the transport list.
Configuration
Configuration can be overridden after requiring the Sequena module and before defining packets. Unknown sections/options are rejected.
Sequena.Configure({
Security = {
MaxStringSize = 4096,
MaxArraySize = 500,
},
Network = {
MaxBatchSize = 32768,
},
})
Configuration is locked after the first packet is defined so all packet serializers use the same limits.
Incoming payloads are bounds-checked before reads, compressed/decompressed payload sizes are limited, oversized strings/buffers/tables are rejected, unknown packet/type IDs are rejected, and server inbound traffic is rate limited per player.
Data Types
Use Sequena.Data for primitive schema values instead of writing type-name
strings directly:
local Data = Sequena.Data
local Packet = Sequena.Define({
Name = "Inventory/Updated",
}, Data.U8, Data.Vector3F16, Data.String)
Composite types such as Data.Array, Data.Optional, Data.Literal,
Data.Or, Data.And, Data.Map, Data.Struct, Data.Enum, and Data.Bitfield are
also available.
The public table is assembled internally from focused datatype modules under
src/Datatypes: Numbers, Primitives, Roblox, RobloxSerializers,
Dynamic, DynamicSerializers, Checks, Resolver, and Composites.
Datatype modules register their serializers/deserializers against the active buffer context; composite builders use the same context for
schema resolution and bounds enforcement.
Typed packet APIs
Sequena+'s public schema fields carry their Luau value type. The config-first vararg form provides precise positional inference for every packet field:
local Data = Sequena.Data
local Request = Sequena.Define({
Name = "Inventory/Get",
}, Data.U32, Data.String)
Request.OnServerEvent:Connect(function(Player, UserId, ItemName)
-- Player: Player, UserId: number, ItemName: string
end)
Request:Fire(42, "Potion")
Packet direction is enforced at runtime. Clients use Fire and
OnClientEvent; servers use FireClient, the broadcast/collection fire
methods, and OnServerEvent. Calling an API from the wrong context throws.
Request/response packets are client-to-server only. The server binds one
handler and the client invokes it with Fire:
local GetItem = Sequena.Define({ Name = "Inventory/GetItem" }, Data.U32)
:SetRequestResponse(Data.String)
-- Server
GetItem:BindServerInvoke(function(Player, ItemId)
return "Potion"
end)
-- Client
local ItemName = GetItem:Fire(42)
TypedPacket is also exported when an explicit packet contract annotation is
useful:
local Packet: Sequena.TypedPacket<(number, string)> = Sequena.Define({
Name = "Inventory/Updated",
}, Data.U32, Data.String)
Struct accepts a keyed schema and infers the complete payload table:
local Item = Data.Struct({
Id = Data.U32,
Name = Data.String,
})
Keyed struct fields are serialized in sorted key order. Use OrderedStruct
when the wire order must be explicit; Data.Field retains each literal field
name so the complete payload table is still inferred:
local OrderedItem = Data.OrderedStruct({
Data.Field("Id", Data.U32),
Data.Field("Name", Data.String),
})
Or accepts between 2 and 25 schema options and infers their Luau union.
Sequena+ writes a one-byte option tag followed by the matching payload:
local StringOrNumber = Data.Or(Data.String, Data.F32)
-- Descriptor<string | number>
And combines between 2 and 25 Struct or OrderedStruct schemas with
distinct field names and infers their Luau intersection:
local Item = Data.And(
Data.Struct({ Id = Data.U32 }),
Data.Struct({ Name = Data.String })
)
-- Descriptor<{ Id: number } & { Name: string }>
Define carries all positional schema fields through a generic type pack, so
there is no builder-specific inference or arity limit. Runtime schemas remain
unchanged; the generic typing improves editor and type-checker feedback.
Package Details
Install command (Click to copy)
Version
0.2.0
License
MIT
Safe for commercial use
Automated license review — not legal advice.
