Skip to content

Snitch

Latest release1.6.1
DownloadGitHub · Thunderstore
RequiresMelonLoader 0.7.3, S1API Forked 3.1.1, Hotline 1.2.0
APIReference

A performance profiler for Schedule I - measure what’s actually slow, then make it fast.

🛟 Need help or found a bug? Get support at support.doodesch.de/snitch.

Snitch measures the cost and state of NPCs, trash, quests, and - through a tiny no-op API built on S1API - any other mod’s systems. Its in-game panel lives in the Hotline overlay (each mod gets its own panel), alongside a combined log timeline and a live web dashboard so you can see frame times, section costs, and entity-state distributions in real time.

  • Frame time distribution + fps + GC pressure - the load-bearing, build-independent truth.
  • Section costs - time named code sections (yours via the API, or vanilla hot paths like NPCMovement.Update).
  • State distributions - NPCs by movement/visibility, trash by physics state, quests by state, and your own.
  • Per-mod panels - any mod that reports data gets its own panel (counters, state, text, action buttons, toggles) in the Hotline overlay and the web dashboard.
  • Log timeline - a combined, chronological view of every mod’s log output, with per-mod filtering.
  • Ablation A/B - toggle a subsystem off and measure the real frame-time delta (the causal “total cost”).
  • Live web dashboard - opens straight to your local game over WebSocket; your telemetry never leaves your PC.
  • Phone remote - scan a QR (in the dashboard or the in-game Snitch panel) to drive the profiler from your phone: live FPS, Start/Stop/Reset, and every mod’s actions and toggles. Works on the same Wi-Fi or across networks, end-to-end encrypted.
  • Honest - every number self-certifies; Snitch even reports its own overhead (Snitch.Self).
  • Modder API - a zero-overhead no-op when Snitch isn’t installed, so you can ship it with no hard dependency.
RequirementVersion / Notes
Schedule IIL2CPP build
MelonLoader0.7.x
S1APIifBars-S1API_Forked
HotlineThe in-game overlay framework Snitch’s panel renders in (auto-installed as a dependency).

Mod manager (Thunderstore / r2modman): install Snitch; the dependencies (MelonLoader, S1API, Hotline) pull in automatically.

Manual: install MelonLoader 0.7.x, S1API and Hotline, then drop Snitch.dll into the game’s Mods/ folder.

Settings live in UserData/MelonPreferences.cfg under Snitch_01_Main (or the in-game Mod Manager UI). The profiler is idle until you run snitch start.

SettingDefaultWhat it does
EnabledtrueMaster switch. OFF = Snitch does nothing.
EnableInMultiplayertrueProfiling runs locally on every peer; state-mutating levers stay host-only.
AutoStartfalseBegin sampling automatically on world load.
PollHz4How often state providers + counters are sampled (frame-time is every frame).
ServerEnabledtrueRun the loopback data server for the web dashboard.
ServerPort6140The loopback port (127.0.0.1 only).
ServerToken(empty)Optional pairing token for the dashboard.
AllowedOriginshttps://snitch.doodesch.deWeb origins allowed to connect from the browser (localhost is always allowed).

The in-game overlay is provided by Hotline - press F6 to open it; Snitch’s panel (Start/Stop/Reset plus live stats) is inside, alongside every other mod’s.

Snitch’s own console:

  • snitch start / snitch stop - arm / disarm sampling (or the Start/Stop buttons on Snitch’s panel in the Hotline overlay).
  • snitch panels - list the per-mod panels (toggle their windows from the Hotline overlay).
  • snitch act <id> / snitch toggle <id> / snitch log [<channel>|all] - run a panel action, flip a toggle, or read the logs.
  • snitch top / snitch sections / snitch states / snitch counters - log the current numbers.
  • snitch vanilla on - attribute CPU cost to vanilla hot paths (e.g. NPCMovement.Update/FixedUpdate).
  • snitch ablate <lever> - measure a subsystem’s causal frame cost (built-in npc lever; snitch levers lists them).
  • snitch report [md|csv|all] - export to Mods/Snitch/runs/.

Or open the web dashboard at snitch.doodesch.de (or the copy bundled offline at http://localhost:6140/) - it auto-connects and shows frame times, section costs, and state distributions live.

Your mod’s per-frame methods (OnUpdate etc.) are auto-timed with zero code - it just appears as <YourMod>.OnUpdate once Snitch is sampling. To go further, drop in Snitch.cs (or reference Snitch.Api.dll) - a zero-overhead no-op when Snitch isn’t installed - and either name a class SnitchProbe with a static Register() (auto-discovered, no wiring). There you can build your own panel - counters, state, free text, action buttons, toggles and a log channel, shown in the Hotline overlay and the web dashboard:

using Snitch.Api; // Profiler, Panel, StateSnapshot
Panel p = Profiler.RegisterPanel("MyMod", "My Mod");
p.Counter("QueueLength", () => _q.Count, "items"); // a numeric gauge
p.State("Jobs", () => new StateSnapshot { Title = "Jobs" }.Add("running", _r)); // a distribution
p.Action("Flush", () => Flush()); // a button (replaces a debug hotkey)
p.Toggle("Verbose", () => _v, x => _v = x); // an on/off control
p.Log(); // show this panel's log channel
using (Profiler.Sample("MyMod.Pathfinding")) { ... } // hand-time a sub-section

See the SnitchExample mod for the full surface, and the Modder API wiki page.

ProfilerRecorder engine counters are inert in Schedule I’s IL2CPP build, so Snitch relies on frame-time + GC as the truth and self-measured section timing (Harmony accumulators) for attribution. The web dashboard (snitch.doodesch.de, source at ScheduleOne-SnitchWeb) is served both from that hosted site and bundled inside the mod for offline use; either way the page connects straight to ws://127.0.0.1:6140 so your data stays on your machine.

Profiling is read-only and safe alongside other mods (it even observes their effects). State-mutating features (the ablation levers) run host-only in multiplayer. The profiler stays idle until you run snitch start.

Built by DooDesch on S1API by ifBars.

MIT - see LICENSE.md.