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.modedefaults to.none, which authenticates and encrypts nothing. Set.mode = .aeadas above, and assertcomptime 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.
- 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.
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.
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.
Requires Zig 0.16:
zig fetch --save=magnet git+https://github.com/zigsel/magnet.gitThen in build.zig:
const dep = b.dependency("magnet", .{
.target = target,
.optimize = optimize,
});
exe.root_module.addImport("magnet", dep.module("magnet"));Run zig build docs to generate the API reference in zig-out/docs/.
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.
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 microbenchmarksMagnet 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.