Forest Logo
search
package_2

roblox-devtools

By @hurreman

Roblox

Mirrored from Wally

roblox-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_Debug and Steal an Egg's HAUNT_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.
  • help lists 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.lua and SharedModules/Memory/LeakHunter.lua become one-line re-exports. The profiler keeps SN's four *_Local / VFX names through ignoreNames.
    • Update the CLAUDE.md command-bar line to the package path.
  • Magic Neighborhood: server/DebugCommands.luau keeps its command table, and install becomes DebugHook.new({ name = "TOTD_Debug", ... }):Install().
  • Steal an Egg: the HAUNT_Debug block in init.server.luau becomes 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

check_circle

Safe for commercial use

Automated license review — not legal advice.