Hooks
raknet.add_send_hook(callback: (packet: RakNetPacket) -> ())
Register an outgoing packet callback. Multiple send hooks stack — every registered callback fires in registration order. Packets originated by
raknet.send can be modified with :SetData or dropped with :Block; native Roblox packets arrive as async snapshots.
lua
local function log(p) print(p.Direction, p.PacketId, p.Size) end raknet.add_send_hook(log)
raknet.remove_send_hook(callback: (packet: RakNetPacket) -> ())
Remove the first registration matching this function value.
lua
raknet.remove_send_hook(log)
raknet.add_receive_hook(callback: (packet: RakNetPacket) -> ())
Set the single incoming packet callback. Calling again REPLACES the previous callback (unlike send hooks, only one receive slot exists). Incoming packets are always snapshot-only.
lua
raknet.add_receive_hook(function(p) print("in id=0x" .. string.format("%02X", p.PacketId), p.Size) end)
raknet.remove_receive_hook()
Clear the incoming callback slot. Takes no arguments.
lua
raknet.remove_receive_hook()
Sending & state
raknet.send(data: buffer | string | {number}, priority: number?, reliability: number?, ordering_channel: number?)
Send a custom packet. Defaults:
priority = 1 (High), reliability = 3 (Reliable ordered), ordering_channel = 0. Empty payloads and payloads over 1 MiB are rejected. Byte-array entries must be integers 0–255.
lua
local payload = { 0x01, 0x02, 0x03, 0x04 } raknet.send(payload, 1, 3, 0)
raknet.hooked() → boolean
Return whether both RakPeer & ClientReplicator hooks are active. If they aren't, an attempt is made to install them first, and the resulting state is returned.
lua
assert(raknet.hooked(), "RakNet hooks are inactive")
raknet.is_enabled() → boolean
Alias of
hooked() without the auto-install side effect. Kept for Volt-style compatibility.
lua
if raknet.is_enabled() then print("ready") end
raknet.stats() → table
Snapshot of transport, capture, rule, and blocking counters. Fields:
ready, hooked, send, receive, send_hooked, receive_hooked, desync, status, captured, dispatched, duplicates, dropped, blocked_packets, mutated_packets, queued, capacity, maximum_capture_size, send_callback_count, receive_callback, rule_count, blocked_count, rules ({{id,value,start,stop,enabled}}), blocked ({id,…}).
lua
local s = raknet.stats() print("captured:", s.captured, "blocked:", s.blocked_packets)
raknet.clear()
Wipe every patch rule, blocked id, desync flag, and the mutated/blocked/dropped counters. Callbacks stay registered.
lua
raknet.clear()
raknet.desync(enabled: boolean) → boolean
Toggle outgoing physics-replication suppression (drops
ID_PHYSICS / ID_PHYSICS_TOUCHES). Returns the resulting state. Always restore after a bounded test.
lua
raknet.desync(true) task.delay(5, function() raknet.desync(false) end)
Patching rules
raknet.set(packetId: number, value: number, start: number?, stop: number?)
Create or replace a byte-patching rule for packets whose first byte matches
packetId. Every slot in the zero-based, stop-exclusive range [start, stop) AFTER the id byte is set to value. Defaults: start = 0, stop = 5. Applies to native outbound AND raknet.send payloads.
lua
-- overwrite bytes 1..5 (after the id) with 0xAA raknet.set(0xFE, 0xAA, 0, 5)
raknet.toggle(packetId: number, enabled: boolean)
Disable / re-enable an existing rule without removing it. No-op if no rule exists for that id.
lua
raknet.toggle(0xFE, false) -- pause raknet.toggle(0xFE, true) -- resume
raknet.remove(packetId: number)
Delete the rule for this packet id.
lua
raknet.remove(0xFE)
Blocking packet IDs
raknet.block(packetId: number, enabled: boolean?) → boolean
Block or unblock all outgoing packets with this leading byte.
enabled defaults to true. Returns the requested state.
lua
raknet.block(0xA1) -- start blocking raknet.block(0xA1, false) -- stop
raknet.unblock(packetId: number)
Stop blocking this packet id — shorthand for
raknet.block(id, false).
lua
task.delay(3, function() raknet.unblock(0xA1) end)
RakNetPacket userdata
packet:SetData(data: buffer | string | {number})
Replace the outbound payload. Only affects packets originated by
raknet.send — native Roblox packets are snapshots.
lua
raknet.add_send_hook(function(p) if p.PacketId == 0x83 then p:SetData(p.AsString .. "\x00") end end)
packet:Block()
Drop this packet before it is transmitted. Native packets are already in Roblox's outbound pipeline — use
raknet.block / raknet.desync to affect those synchronously.
lua
raknet.add_send_hook(function(p) if p.Size > 1024 then p:Block() end end)
packet.Direction — string
"Outgoing" or "Incoming".
lua
if packet.Direction == "Incoming" then ... end
packet.PacketId — number
First payload byte — the RakNet MessageID (e.g.
0x83 = ID_DATA).
lua
if packet.PacketId == 0x83 then print("ID_DATA") end
packet.ItemId — number
Second payload byte, or
0 when absent. NOT guaranteed to be an item type for every packet format — just the raw byte.
lua
print(string.format("id=%02X item=%02X", packet.PacketId, packet.ItemId))
packet.Priority — number
RakNet send priority: 0 Immediate, 1 High, 2 Medium, 3 Low.
lua
print("pri:", packet.Priority)
packet.Reliability — number
RakNet reliability mode (0–7). 0 Unreliable, 3 Reliable ordered, etc.
lua
print("rel:", packet.Reliability)
packet.OrderingChannel — number
Ordering channel (0–31).
lua
print("chan:", packet.OrderingChannel)
packet.Size — number
Original payload length in bytes (before any snapshot truncation).
lua
print(packet.Size, "bytes on wire")
packet.CapturedSize — number
Number of payload bytes stored in the snapshot (≤ 4096).
lua
print(packet.CapturedSize, "bytes visible")
packet.Truncated — boolean
true when the snapshot is shorter than the on-wire payload (Size > CapturedSize).
lua
if packet.Truncated then warn("payload > 4 KiB") end
packet.Sequence — number
Monotonic capture id assigned per snapshot — useful for ordering across hooks.
lua
print("#", packet.Sequence)
packet.Timestamp — number
Capture time in milliseconds (from
GetTickCount64).
lua
print("age:", tick() * 1000 - packet.Timestamp)
packet.Data — string
Alias of
AsString — captured payload bytes as a binary string.
lua
print(#packet.Data)
packet.AsString — string
Captured payload bytes as a binary-safe string.
lua
writefile("packet.bin", packet.AsString)
packet.AsBuffer — buffer
Captured payload bytes as a Luau
buffer.
lua
print(buffer.len(packet.AsBuffer))
packet.AsArray — {number}
Captured payload as an array of unsigned bytes (0–255, 1-indexed).
lua
local b = packet.AsArray for i = 1, math.min(#b, 8) do io.write(string.format("%02X ", b[i])) end
packet.Modified — boolean
true if :SetData was called on this packet object.
lua
if not packet.Modified then packet:SetData("...") end
packet.Blocked — boolean
true if :Block was called on this packet object.
lua
print("dropped:", packet.Blocked)
lua
-- End-to-end: observe both directions, patch a specific id, -- and block anything huge. raknet.add_send_hook(function(p) print(p.Direction, string.format("id=%02X", p.PacketId), p.Size) if p.Size > 4096 then p:Block() end end) raknet.add_receive_hook(function(p) print("in", string.format("%02X.%02X", p.PacketId, p.ItemId), p.Size) end) raknet.set(0xFE, 0xAA, 0, 5) -- patch bytes 1..5 of id 0xFE raknet.block(0xA1) -- drop everything with id 0xA1 raknet.send({ 0x01, 0x02, 0x03 }, 1, 3, 0) print(raknet.stats().captured, "packets seen")