Start typing to search packages!
roblox-devtools
By @hurreman
Roblox
Mirrored from Wallyroblox-devtools
Diagnostics for hurreman's Roblox games:
- Slime Nebula's replication profiler and leak counters;
- a Studio-only command hook for MCP-driven tests, generalized from Magic Neighborhood's
TOTD_Debugand Steal an Egg'sHAUNT_Debug.
# wally.toml (a normal dependency: LeakHunter's counters and the hook are called from game code)
[dependencies]
DevTools = "hurreman/roblox-devtools@0.1.0"
ReplicationProfiler
This ranks what eats network bandwidth over a window, because Roblox gives no per-system breakdown of replication. It counts:
- scripted property writes on replicated instances, grouped by instance and by top-level container;
- attribute writes;
- instances created and removed;
- RemoteEvent traffic, with payload size estimates;
- on the server, a census of unanchored physics assemblies: who owns them and which are moving.
Run it from the Studio command bar in Play mode, once on the server and once on the client:
require(game.ReplicatedStorage.Packages.DevTools).ReplicationProfiler.Run({ window = 15, ignoreNames = { "MyLocalVfx" } })
A row that appears in both reports is server-driven replication. A row that appears only on the client is a local effect. Stats.DataReceiveKbps reads 0 in single-process Studio play, so this is how to attribute traffic without a Local Server.
The command bar has its own module cache, so the profiler only listens to signals and never touches the game's module state. Slime Nebula's own client-only folder names moved from the defaults to ignoreNames.
LeakHunter
local LeakHunter = DevTools.LeakHunter
LeakHunter.SetCategory("Client/UI/Inventory") -- memory category, safe outside the microprofiler
LeakHunter.CountInc("connections") -- and CountDec in cleanup
LeakHunter.LogTop(10) -- at the same checkpoints as two LuauHeap snapshots
Compare LuauHeap snapshots with the counters:
- If the heap rises but the counters don't, look at untracked allocations.
- If both rise, follow the owner of that key.
DebugHook
local hook = DevTools.DebugHook.new({
name = "TOTD_Debug", -- ServerStorage.TOTD_Debug
context = function()
local player = Players:GetPlayers()[1]
local save = player and profiles:Data(player)
return save and { player = player, save = save, S = services }
end,
fallback = function(ctx) return HttpService:JSONEncode(ctx.save) end, -- the answer when a command returns nothing
commands = {
give = function(ctx, amount) ctx.save.cash += amount end,
},
})
hook:Install() -- Studio only (anywhere = true to override)
-- command bar / MCP: game.ServerStorage.TOTD_Debug:Invoke("give", 1e6)
How it answers:
- Unknown commands answer with the fallback.
helplists the commands.- A command that errors answers
"error: ...", so test scripts read failures like any other answer.
Moving the games over
- Slime Nebula:
Utils/ReplicationProfiler.luaandSharedModules/Memory/LeakHunter.luabecome one-line re-exports. The profiler keeps SN's four*_Local/ VFX names throughignoreNames.- Update the
CLAUDE.mdcommand-bar line to the package path.
- Magic Neighborhood:
server/DebugCommands.luaukeeps its command table, andinstallbecomesDebugHook.new({ name = "TOTD_Debug", ... }):Install(). - Steal an Egg: the
HAUNT_Debugblock ininit.server.luaubecomes a DebugHook.
Developing
lune run tests/run
Checks so far:
- Lune: the hook's commands, fallback, errors, help and Studio gate, and LeakHunter's counters.
- Studio: Install, Invoke round trips and reinstalling over an old hook, through a real BindableFunction.
- No separate run: ReplicationProfiler and LeakHunter are Slime Nebula's files apart from the header, the usage path and the default ignore list, as a diff against the originals shows.
Package Details
Install command (Click to copy)
Version
0.1.0
License
MIT
Safe for commercial use
Automated license review — not legal advice.
