Skip to content
dream-net

Library active

dream-net

DreamWeave's networking substrate: secure UDP between authenticated peers, with reliable-ordered and unreliable event channels and a schema handshake.

cargo add dream-net
Stable
1.1.0 2026-09-29
Package
Rust crate
License
MIT OR Apache-2.0

Overview

A multiplayer engine needs two kinds of traffic. A chat line, a spell cast or an inventory change must arrive exactly once and in order, however many packets the network loses. An actor’s position is stale the moment the next one exists, and resending it is worse than useless. Both kinds have to share one encrypted connection, reach only peers that proved who they are, and never let a hostile peer grow the server’s memory or crash it.

dream-net is that transport for the DreamWeave engine. It moves opaque event payloads between authenticated peers and stops there: it knows event ids, channels, peers and bytes, and never what an event means. Who may send what, and where it goes next, is decided above it.

One event, from send to poll

The host hands dream-net an event id and bytes. They cross in a packet that many events share, inside an encrypted netcode datagram, and come out of the other host's poll with the sender attached.

  1. source

    send

    Checks the event and its size against the schema, and copies the bytes into its channel's queue before returning.

  2. tool

    flush

    Packs events from every channel into packets sized to one datagram. reliable numbers and acknowledges them; netcode encrypts them and sends them over UDP.

  3. result

    poll

    On the other host, after its update: lifecycle records and events in arrival order, with the authenticated sender.

input

Schema

Channels and events, frozen before networking starts. Both ends compare its fingerprint before any event is accepted.

input

TransportConfig

Packet sizes, timers, and the byte budgets that bound every queue.

How the pieces relate
  • send flush
  • flush poll
  • Schema ids and sizes send
  • TransportConfig bounds flush

It is built on the Más Bandwidth crates, pinned exactly: netcode for connect tokens, encryption, replay protection and client slots; reliable for packet acknowledgement, fragmentation and link statistics; and serialize for bit-packing. dream-net adds the part they leave out: channels of events, packed many to a datagram.

  • Events are the protocol unit. A schema names every channel and event before networking starts. Event ids come from the sorted names, never the order they were declared in, and both ends compare a fingerprint of the whole schema before a single event is accepted. A mismatch is reported on both ends, with both fingerprints.
  • Polled, never called back. A host runs one network phase per frame: update, poll, send, flush. Nothing calls into the host from inside the transport.
  • The sender is transport metadata. A PeerId comes from the authenticated netcode slot and carries a generation, so a handle to a peer that left never reaches the next one in its slot.
  • Bounded memory. Every queue has a limit, and what a peer can make a connection hold on receive has a fixed ceiling. Malformed input is refused, counted and disconnected, never a panic.
use dream_net::{ChannelConfig, Schema, Server, ServerConfig, ServerEvent, TransportConfig};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let mut schema = Schema::builder(1);
    let reliable = schema.channel(ChannelConfig::reliable_ordered("reliable"))?;
    let state = schema.channel(ChannelConfig::unreliable_unordered("state"))?;
    schema.event("Chat", reliable, 256)?;
    schema.event("ActorPosition", state, 28)?;
    let schema = schema.build()?;
    let chat = schema.event_id("Chat").expect("declared above");

    let config = ServerConfig {
        public_address: "127.0.0.1:0".parse()?,
        protocol_id: 0x4452_4541_4d00_0001,
        max_clients: 16,
        transport: TransportConfig::default(),
    };
    let mut server = Server::new(config, &dream_net::generate_key(), schema, 0.0)?;
    let mut buffer = [0u8; 256];

    // once per frame, in one network phase
    server.update(1.0 / 60.0);
    while let Some(event) = server.poll_into(&mut buffer)? {
        match event {
            ServerEvent::Connected { peer, .. } => server.send(peer, chat, b"welcome")?,
            ServerEvent::Message { peer, event, payload, .. } => {
                println!("{peer} sent {event}: {:?}", &buffer[..payload]);
            }
            ServerEvent::Disconnected { .. } | ServerEvent::Rejected { .. } => {}
        }
    }
    server.flush();
    Ok(())
}

Luau scripts reach it through l3i, which binds dream-net as the @dream/net module. The host still creates servers in Rust: the private key never reaches a script.

Documentation#

  • Start here: a server and a client in one program, exchanging their first events.
  • Guide: how it fits together, schemas, channels, hosting, memory limits, captures and the simulator.
  • Rust API: every public type and function.
  • Compatibility and performance: the Rust version, the license, what is tested, and what a frame costs.

Install

Rust crate · 1.1.0

Add it with Cargofrom crates.io, 1.1.0 today

From your project's directory:

cargo add dream-net

Or by hand, in Cargo.toml:

[dependencies]
dream-net = "1.1.0"

Cargo reads a bare version as "this or any compatible newer release" and records the exact one in Cargo.lock.

From the repositorythe default branch, ahead of the latest release
[dependencies]
dream-net = { git = "https://github.com/DreamWeave-MP/dream-net" }

Cargo pins the commit it fetched in Cargo.lock; cargo update -p dream-net moves it forward.

  1. 1.1.0 stable 2026-09-29

    A peer is announced before its first event, captures without payloads keep their lengths, and the codec’s decode errors are standard Rust errors.

    Added

    • wire::DecodeError and wire::Malformed implement std::error::Error, and DecodeError implements Display, like the crate’s other errors: a malformed packet prints its reason, which is also its source(), and a mismatch prints the foreign hello.

    Fixed

    • Server and Client queued Connected after the events of the packet that completed the handshake, so a host could poll a peer’s Message before its Connected. Connected now comes first.
    • CaptureWriter without payloads wrote each event’s length from its payload, so a capture read back and written again recorded every event as zero bytes. It now writes the record’s len.
    dream-net 1.1.0 100.18 kB · crates.io
    View on crates.io
    Verify · sha256 2df0cb5ee602…4ba4d51d
    File
    dream-net-1.1.0.crate
    Size
    102580 bytes
    SHA-256
    2df0cb5ee602184918adad25df359efd364166568947e03e73c747144ba4d51d

    The same digest as the crates.io index's checksum, which Cargo checks on every download.

  2. 1.0.0 stable 2026-09-27

    First release: secure UDP between authenticated peers, reliable-ordered and unreliable event channels, and a schema handshake, over the Más Bandwidth netcode, reliable and serialize crates.

    Added

    • A frozen Schema of channels and events: event ids from sorted names, never registration order, and a 128-bit fingerprint (truncated SHA-256) peers compare before any event is accepted.
    • Reliable-ordered channels, delivered exactly once in send order and resent until acknowledged, and unreliable-unordered channels with a choice of overflow policy.
    • Many events aggregated into each packet, and events larger than a datagram fragmented by reliable.
    • Server and Client over netcode: connect tokens, encryption, generation-checked PeerId handles, and polled lifecycle events, including schema and protocol mismatches reported with both fingerprints on both ends.
    • Bounded memory on every queue: pending, parked and pooled bytes, with at most max_pending_bytes + 2 * max_parked_bytes held per connection on receive.
    • Protocol captures at the host boundary, in a versioned binary format that carries the schema’s names.
    • Connection independent of sockets, and a deterministic link simulator for tests and benchmarks.
    • Wire format 2, pinned by golden bytes; warm send and receive paths that allocate nothing; fuzz harnesses, a soak test and Criterion benchmarks.
    dream-net 1.0.0 98.02 kB · crates.io
    View on crates.io
    Verify · sha256 fe667f5bd125…5fd03c87
    File
    dream-net-1.0.0.crate
    Size
    100369 bytes
    SHA-256
    fe667f5bd1256bcebe4fef2143ad2a09e84ed73301405437856ea17e5fd03c87

    The same digest as the crates.io index's checksum, which Cargo checks on every download.

Credits