Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

12 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Magnet

A generic, zero-allocation UDP game-networking stack in Zig.

Magnet is a game-networking stack that covers both halves of the problem: reliable UDP transport and game-state replication, generated from one comptime Config with fixed capacities and no allocator. Features you do not enable are never compiled in. Its protocol core is sans-IO, so applications retain control of sockets, clocks, scheduling, and memory placement.

One configuration selects the message schema, delivery behavior, congestion controller, security, and resource limits:

const magnet = @import("magnet");

const PlayerInput = struct { tick: u32, move_x: i8, move_y: i8 };
const GameEvent = union(enum) {
    spawned: struct { entity: u32 },
    damaged: struct { entity: u32, amount: u16 },
};

const Channels = magnet.proto.channels(.{
    .input = .{ .mode = .unreliable_sequenced, .Message = PlayerInput },
    .events = .{ .mode = .reliable_ordered, .Message = GameEvent },
    .bulk = .{ .mode = .reliable_unordered, .Message = void },
});

const Cfg = magnet.Config{
    .channels = Channels,
    .protocol_id = 0x4D41474E4554,
    .app_version = 1,
    .security = .{ .mode = .aead, .connection_ids = true },
};
const Endpoint = magnet.Endpoint(Cfg);
comptime magnet.validateProduction(Cfg);

Congestion control, fragmentation, PMTU discovery, and every resource limit are configured the same way. See config for the full surface.

Encryption is off by default. security.mode defaults to .none, which authenticates and encrypts nothing. Set .mode = .aead as above, and assert comptime magnet.validateProduction(Cfg) so the compiler refuses a build that forgets. See security.

From there the application-facing loop stays small. Feed received datagrams in, poll outgoing ones out, and send them through any UDP socket you like:

try client.sendTo(server_addr, .input, input);

while (client.pollTransmit(&datagram, now)) |out| {
    // Send datagram[0..out.len] to out.addr through an IPv4 or IPv6 UDP driver.
}

// Feed each received UDP datagram back into the same endpoint.
client.feedFrom(from_addr, received_datagram, now);

Acknowledgements, loss recovery, retransmission, pacing, congestion control, encryption, and migration all run inside that loop.

Why Magnet

  • Deterministic memory. Connection tables, queues, pools, and transfer state are fixed by the compile-time configuration. magnet.memoryPlan(config) reports exact storage needs.
  • Typed channels. Each channel binds a delivery mode to a message type, with compile-time checking at application boundaries and raw-byte paths when needed.
  • Sans-IO transport. Feed received datagrams into the protocol and poll outgoing datagrams. The same core works in a game loop, a sharded server, or the deterministic simulator.
  • Integrated game replication. Prediction, rollback, interpolation, interest management, authority, lag compensation, and large transfers share one configurable stack.

What's included

The rest of the stack composes around the same endpoint, with no extra dependencies:

Area Included API and behavior
Transport Six reliability modes, typed messages, AEAD, forward secrecy, recovery, congestion control, STUN, ICE, relay, and multipath
Replication magnet.replication and magnet.host.Bridge for prediction, rollback, interpolation, interest, authority, and lag compensation
Streaming magnet.proto.stream for raw bytes, files, live sources, progress, integrity, resume, and flexible storage
Runtime magnet.runtime for IPv4, IPv6, game-loop, sharded, Linux-optimized, simulated, and observable drivers

Continue with Getting started or browse the runnable examples.

Architecture

Each layer is usable independently. Unused declarations are not analyzed or linked:

L5  replication/    snapshots, prediction, rollback, interpolation, interest, lag compensation
L4  wire/           derived serialization, bit packing, quantization, delta coding
L3  proto/channel/  reliability modes, ordering streams, WFQ scheduling, packet packing
L2  proto/delivery/ packet numbers, ACK ranges, RACK, RTT/PTO, congestion, fragmentation
L1  proto/conn/     handshake, tokens, AEAD, replay defense, connection IDs, migration
L0  runtime/        std.Io drivers, poll/reactor/sharded/task loops, network simulation
    core/           sequence buffers, pools, rings, bitsets, fixed-point helpers

The compiler-enforced dependency graph keeps the protocol and replication layers independent of runtime IO. See Layering and Sans-IO for the design constraints.

Install

Requires Zig 0.16:

zig fetch --save=magnet git+https://github.com/zigsel/magnet.git

Then in build.zig:

const dep = b.dependency("magnet", .{
    .target = target,
    .optimize = optimize,
});
exe.root_module.addImport("magnet", dep.module("magnet"));

Documentation

Run zig build docs to generate the API reference in zig-out/docs/.

Status

All six layers described above are implemented and exercised in the repository. Magnet is still a 0.x library, so no API or wire compatibility guarantee is currently offered.

The repository includes deterministic impairment tests, fuzz and soak cases, invariant checks, and real-socket validation. Independent security review and completed, recorded Internet soaks remain external release evidence. A v1 release also requires a frozen wire specification, and an explicit compatibility policy.

Applications remain responsible for account identity, matchmaking, durable game state, deployment orchestration, and abuse response.

Validation

zig build test             # unit, integration, and conformance tests
zig build examples         # build every example
zig build ci               # optimization matrix, examples, and API audit
zig build hardening        # impairments, fuzz/soak, and invariant checks
zig build security-review  # reproducible audit-preparation package
zig build bench            # local ReleaseFast microbenchmarks

Acknowledgements

Magnet is informed by established game-networking systems and Internet transport research:

  • reliable.io, netcode.io, and yojimbo by Glenn Fiedler for fixed-capacity networking structures, acknowledgements, tokens, and serialization ideas.
  • RakNet for reliability modes, ordering streams, path-MTU probing, and fragment management.
  • Valve GameNetworkingSockets for scheduling, pacing, authenticated setup, and key-scheduling ideas.
  • quinn and QUIC for loss recovery, RTT/PTO estimation, migration, anti-amplification, and sans-IO architecture.
  • laminar for module boundaries and injectable transport seams.
  • Bevy lightyear for prediction, rollback, interpolation, interest management, and reconciliation ideas.

The borrowed ideas are theirs; the bugs are ours.