{"id":"hurreman/roblox-devtools","name":"roblox-devtools","scope":"hurreman","platform":"roblox","description":"Diagnostics for hurreman's Roblox games: a replication profiler that ranks network traffic by source, memory counters for leak hunts, and a Studio-only command hook for MCP-driven tests","version":"0.1.0","latest":"0.1.0","versions":["0.1.0"],"license":"MIT","licenseRating":"safe","licenseCaveats":[],"licenseVerified":true,"dependencies":{},"integrity":"374cee82506e241b2b5b7d0059c1936a5fdba6f6c9ca58a8d68d19cbdcaeab7c","likes":0,"downloads":0,"install":"forest install hurreman/roblox-devtools","url":"https://forest.dev/p/roblox/hurreman/roblox-devtools","files":"https://api.forest.dev/ai/package/roblox/hurreman/roblox-devtools/files","readme":"# roblox-devtools\n\nDiagnostics for hurreman's Roblox games:\n- Slime Nebula's replication profiler and leak counters;\n- a Studio-only command hook for MCP-driven tests, generalized from Magic Neighborhood's `TOTD_Debug` and Steal an Egg's `HAUNT_Debug`.\n\n```toml\n# wally.toml (a normal dependency: LeakHunter's counters and the hook are called from game code)\n[dependencies]\nDevTools = \"hurreman/roblox-devtools@0.1.0\"\n```\n\n## ReplicationProfiler\n\nThis ranks what eats network bandwidth over a window, because Roblox gives no per-system breakdown of replication. It counts:\n- scripted property writes on replicated instances, grouped by instance and by top-level container;\n- attribute writes;\n- instances created and removed;\n- RemoteEvent traffic, with payload size estimates;\n- on the server, a census of unanchored physics assemblies: who owns them and which are moving.\n\nRun it from the Studio command bar in Play mode, once on the server and once on the client:\n\n```lua\nrequire(game.ReplicatedStorage.Packages.DevTools).ReplicationProfiler.Run({ window = 15, ignoreNames = { \"MyLocalVfx\" } })\n```\n\nA 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.\n\nThe 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`.\n\n## LeakHunter\n\n```lua\nlocal LeakHunter = DevTools.LeakHunter\nLeakHunter.SetCategory(\"Client/UI/Inventory\") -- memory category, safe outside the microprofiler\nLeakHunter.CountInc(\"connections\")            -- and CountDec in cleanup\nLeakHunter.LogTop(10)                          -- at the same checkpoints as two LuauHeap snapshots\n```\n\nCompare LuauHeap snapshots with the counters:\n- If the heap rises but the counters don't, look at untracked allocations.\n- If both rise, follow the owner of that key.\n\n## DebugHook\n\n```lua\nlocal hook = DevTools.DebugHook.new({\n\tname = \"TOTD_Debug\",                                   -- ServerStorage.TOTD_Debug\n\tcontext = function()\n\t\tlocal player = Players:GetPlayers()[1]\n\t\tlocal save = player and profiles:Data(player)\n\t\treturn save and { player = player, save = save, S = services }\n\tend,\n\tfallback = function(ctx) return HttpService:JSONEncode(ctx.save) end, -- the answer when a command returns nothing\n\tcommands = {\n\t\tgive = function(ctx, amount) ctx.save.cash += amount end,\n\t},\n})\nhook:Install() -- Studio only (anywhere = true to override)\n-- command bar / MCP: game.ServerStorage.TOTD_Debug:Invoke(\"give\", 1e6)\n```\n\nHow it answers:\n- Unknown commands answer with the fallback.\n- `help` lists the commands.\n- A command that errors answers `\"error: ...\"`, so test scripts read failures like any other answer.\n\n## Moving the games over\n\n- **Slime Nebula:**\n  - `Utils/ReplicationProfiler.lua` and `SharedModules/Memory/LeakHunter.lua` become one-line re-exports. The profiler keeps SN's four `*_Local` / VFX names through `ignoreNames`.\n  - Update the `CLAUDE.md` command-bar line to the package path.\n- **Magic Neighborhood:** `server/DebugCommands.luau` keeps its command table, and `install` becomes `DebugHook.new({ name = \"TOTD_Debug\", ... }):Install()`.\n- **Steal an Egg:** the `HAUNT_Debug` block in `init.server.luau` becomes a DebugHook.\n\n## Developing\n\n```bash\nlune run tests/run\n```\n\nChecks so far:\n- **Lune:** the hook's commands, fallback, errors, help and Studio gate, and LeakHunter's counters.\n- **Studio:** Install, Invoke round trips and reinstalling over an old hook, through a real BindableFunction.\n- **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.\n","readmeTruncated":false}