Namespace
The Namespace is the object returned by KravasNet.createNamespace. It accumulates pending channel definitions and only registers them with ByteNet once, at build time.
type Namespace = {
_name : string,
add : (self: Namespace, name: string, schema: {[string]: any}, options: ChannelOptions?) -> Namespace,
build : (self: Namespace) -> Namespace,
[string]: Channel,
}Properties
| Property | Type | Description |
|---|---|---|
_name | string | The name passed to createNamespace. Also the ByteNet namespace name. |
[channelName] | Channel | Reading any channel key triggers :build() if it hasn't run yet, then returns the live Channel. |
Namespace:add
Namespace:add(name: string, schema: {[string]: any}, options: ChannelOptions?): NamespaceQueues a new pending channel. Returns the namespace itself for chaining.
| Parameter | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Non-empty channel name, unique within this namespace. |
schema | {[string]: any} | Yes | Field-to-type map for this channel's packet. |
options | ChannelOptions | No | Reliability and middleware. See Middleware & Reliability. |
Errors:
| Condition | Message |
|---|---|
name is empty or not a string | "Channel name must be a non-empty string" |
| A channel with that name is already pending | Channel "{name}" already exists in namespace "{namespace}" |
| The namespace was already built | A descriptive error explaining that ByteNet requires every packet in one defineNamespace call, and this channel can't be added post-hoc |
local CombatNet = KravasNet.createNamespace("Combat")
:add("Damage", { amount = KravasNet.float32 })
:add("Heal", { amount = KravasNet.float32 })Once a namespace is built, :add() throws instead of failing silently or
crashing deep inside ByteNet. If you hit this error, the fix is almost
always to move the :add() call earlier, before anything reads a
channel off this namespace (including on the other side of the
client/server boundary, and including calling :build()).
Building the namespace
Namespace:build(): NamespaceRegisters every pending channel with ByteNet in a single ByteNet.defineNamespace() call, then replaces each pending entry with a live Channel. Idempotent — calling it again after the namespace is already built is a no-op.
This happens in one of two ways:
- Automatically, the first time any channel key is read off the namespace (e.g.
CombatNet.Damage). - Explicitly, if you call
Namespace:build()yourself.
Prefer calling :build() explicitly, right after your :add() calls,
in the same module. If you rely on automatic building, the exact moment
a namespace becomes "live" depends on which script happens to touch a
channel first — and if the server and client touch it at very different
times, the client can read the replicated namespace data before the
server has written it (or vice versa), leading to dropped packets or
runtime errors deep inside ByteNet's buffer reader. See
Best Practices for the
full explanation and a concrete example of this failure mode.
local CombatNet = KravasNet.createNamespace("Combat")
:add("Damage", { amount = KravasNet.float32 })
:add("Position", { pos = KravasNet.vec3 }, { reliability = "unreliable" })
CombatNet:build()
return CombatNetImmediate channels via createNamespace
The second argument to createNamespace accepts a table where each value is either:
- A plain schema table → queued with default options (
reliable, no middleware). - A
PacketDefproduced byKravasNet.packet(schema, options)→ queued with the specified options.
local CombatNet = KravasNet.createNamespace("Combat", {
Damage = { amount = KravasNet.float32 },
Position = KravasNet.packet({ pos = KravasNet.vec3 }, { reliability = "unreliable" }),
})Both forms are just queued as pending — nothing is registered with ByteNet until :build() runs.