Repository navigation
Faster, safer and easier to drive: the whole tool reviewed line by line
0.11.0 is a review of every part of InsideDev: about 92,000 lines of C#, 14,000 lines of Python, the loader and the
native readback plugin. The goal was a tool that costs nothing while you do not use it, records without slowing the game
or drifting from game time, and that people and AI agents can drive without traps.
Existing commands, MCP tools, config keys and file formats keep working. Where a default changed, it is listed under
"Changed defaults" below, with the key that brings the old behaviour back.
Speed
- Nothing runs while nobody uses the tool. With the editor closed and no client connected, 0.10.0 still scanned the
scene, traced sound events, monitored signals and rebuilt overlay text every frame: 1.2 to 2.8 ms per frame and 17 to
23 garbage collections a minute in our test scene. Now every scanner and monitor sleeps until a panel, a command or a
client needs it, and catches up when it wakes: 0.03 ms per frame and no garbage collection in 95 s in the same scene.
background always(orbackground=alwaysineditor.cfg) brings the old always-on behaviour back. - No more hitch every 10 seconds. While an agent or the editor kept the object database awake, it searched every
root of the scene every 10 s (20 to 30 ms in one frame). It now does that only after a level streams in, and once a
minute as a safety net (db.rootRefresh). - Mods only work in their own level. A mod's operations are grouped by level. They are looked up once when their
level loads, only inside that level, retried a few times for late content, and left alone until the next load. With
three mods enabled and two of their levels not loaded, all mods together cost 0.0016 ms per frame; entering a mod's
level applied it in 2.5 ms, and a respawn applied it again. Extension modules can declare their levels
(IInsideDevLevelScoped) and are then only ticked there;LevelGateis part of the core for mod authors.mod list
andextshow each mod's levels and cost, and the log names an extension whose tick is slow. - Screenshots in a fraction of the time. The MCP screenshot no longer writes a full-size PNG to disk and decodes it
again in managed code: the frame is read once, scaled and encoded by Unity itself. 960 px: 2.25 s before, 0.09 s now;
1920 px: 3.9 s before, 0.31 s now. Newformat: "jpeg": a 1600 px shot is 121 KB in 0.12 s. - Faster calls. One main-thread hop per MCP call instead of two or three, a cached tool list, buffered HTTP. observe
33 ms before, 8 ms now; a console command 18 ms before, 8 ms now; geometry 72 ms before, 8 ms now; find_objects 36 ms
before, 13 ms now. - Recording does not hold the game back.
grecwrites frames straight from the readback buffer and a slow encoder
never blocks the render thread; MultiCam's writer has a bounded wait; the scene recorder scans the scene once at start
and samples only what changed; director holds are hard links instead of copies (500 holds in 0.1 s). With srec and
grec recording, the game held 59.8 fps (vSync 60) against 56.5 before; srec starts and stops in under 0.2 s. - Python tools. Seeking back in a take video 9.9 s to 1.0 s, grade statistics 12.6 s to 2.2 s per 600 frames,
ffmpeg does the scaling, one ffmpeg helper that always cleans up its child.
Recording you can trust
- Video length equals game time. 0.10.0 fixed the file rate once and wrote one frame per grab, so a minute of play
came out about 3.5 s short and the sound no longer lined up. Now frames are placed by game time: a 120 s recording
under load gave 120.13 s of video for 120.10 s of game time. A<file>.times.csvnext to the video gives each frame's
game time for exact audio alignment. - Recording while an agent drives. The time an agent's game stands frozen between calls is left out of the video, and
stepped runs are recorded without lost frames (0.10.0 lost most of them). - The game's own picture, also under other windows.
time {op:"record"}andrec startnow record the game's own
frames. Tested with a window covering the game: none of it in the video. Desktop capture is still there as
source:"desktop"/rec start ... desktop. - A failed ffmpeg (no NVENC, odd window size, full disk) is reported at once and capture stops costing frame time.
- ffmpeg can no longer outlive the game: child processes are tied to the game process.
- A take folder that already holds a recording is not overwritten unless you add
overwrite=on. - The scene recorder stops cleanly on a full disk, checks free space before it starts (
record.minFreeMB), and reports
its state insrec status json. - A level load during a replay no longer freezes the game.
Security
- The MCP server refuses requests from web pages. A page in your browser could send commands to the game while it was
open, through anOrigin: nullrequest. Requests with a foreign Origin, a cross-site fetch, a wrong Host (DNS
rebinding) or a non-JSON MCP body are now refused. Local clients (the stdio launcher,inside_ctl.py, scripts) are not
affected. - No MCP call can start a program of its choice any more: ffmpeg is found by the tool itself (
ffmpeg.pathin
editor.cfg,INSIDEDEV_FFMPEG,_mod\ffmpeg, PATH). reflectcalls go through an allow list; calls that write files, start processes or change the registry are refused.- A deeply nested JSON body can no longer crash the game (tested with 200,000 levels).
- The Mono debugger port of the loader is opt-in (
_mod\debugger.flag).
New commands and tools
| Command / tool | What it does |
|---|---|
doctor [json] |
one self-check of every part: loader, modules, versions, ffmpeg and encoders, disk space, minimized window, time scale, background mode |
help <command> |
usage of one command; help lists every command |
cfg [get / set / reset] [json] |
every config key with its value, default and meaning (103 keys), changeable while the game runs |
background [auto / always / off] |
when the background scanners run |
quit |
closes the game cleanly |
labels types <n / all> |
how many component names a world label shows (the rest as "+N"); labels no longer overlap |
state json, where json, perf json, mod list json, srec status json, acap status json, mcam status json, cam status json |
machine-readable status |
GET /status |
server state without waiting for the game's main thread |
POST /cmds |
several commands in one request and one frame |
film (MCP) |
panorama, game-frame recording and the live director camera with structured results |
observe {detail:"delta"} |
only what appeared, disappeared or changed since the last observation |
act {seq:"R1.2 J R0.4+J"} |
the short input grammar of ctl seq in act |
wait_ready_s on act / move_to / interact |
wait for the game to take input instead of being refused |
checkpoint {op:"goto", name} |
load a checkpoint by name |
restore {dry_run:true} |
what a restore would undo, without doing it |
mcam replay ... resume |
skip camera passes that already finished |
srec load <dir> play, srec reload |
fewer steps for the common loops |
inside_ctl.py wait / snapshot / doctor |
wait until the game is ready, read state, self-check from outside |
mcam_compose.py doctor, --resume |
check ffmpeg and encoders before a compose; skip finished outputs |
InsideMuter status / unmute / stop |
the muter can be asked and stopped; it gives back the sound it muted |
Fixed
- A mod file with a JSON error was replaced by an empty file when you ticked its checkbox; now it is left untouched and
the error names the line and column. - After 400 log lines, file-bridge commands answered with empty text and the Console tab stopped updating.
- The audio catalogue lost rows every 10 seconds of normal play.
- After picking an entry in the command palette, the game's keys stopped working until you clicked the game.
- World labels listed every component on one line, ran off the screen and covered each other.
acap statuscould mute the game; acap's volume rule could end up in a recorded mod.- A scale-only change was recorded up to 8 seconds late.
move_totimers ran several times too fast with vSync off, and a goal inside a gap made the body jump it back and
forth until the step limit.- The observation after an action could miss objects that appeared during it.
- Numbers in replies and files used a decimal comma on non-English Windows (for example
camprinted(1,23, 4,56, ...)). - The stdio launcher dropped
inside_statusfrom its tool list once the game was up. mcam_spec_check.pydisagreed with the game in about 20 rules and did not start on Python 3.9 to 3.11.mcam_audio.py fixcould cut a WAV file short without a backup.
Changed defaults
| What | 0.10.0 | 0.11.0 | Old behaviour |
|---|---|---|---|
| Background scanners | always on | only while the tool is used | background=always |
| Recording into a folder that holds a take | overwritten | refused | overwrite=on |
| Mono debugger port 55555 | on | off | _mod\debugger.flag |
Requests with a foreign or null Origin |
accepted | refused | none (use a local client) |
time {op:"record"} / rec start source |
desktop | game frames | source:"desktop" |
| InsideMuter on exit | leaves sessions muted | un-mutes what it muted | --keep-muted |
reflect call |
deny list | allow list | none |
| World labels | every component | 3 names and "+N" | labels types all |
play.vsync_off=1 |
vSync off from game start | off only while an agent works or the clock is held | play.vsync_off=2 |
| Passive hidden-object scanner | always on | off until the Hidden tab or hidden on |
hidden.passive=1 |
A bare file name for grec / pano |
the game's working folder | <game>\_mod\recordings |
a full path |
Example mods in mods\ |
two shipped enabled | all shipped disabled | enable them in the Mods panel |
Install
Everything is in the zip. With the game closed: version.dll next to INSIDE.exe; InsideDev.dll, InsideDev.Mcp.dll and InsideDev.Play.dll in <game>\_mod\ (the lab modules InsideDev.ReplayLab.dll and InsideDev.Det.dll only if you use them); InsideReadback.dll in <game>\INSIDE_Data\Plugins\; tools\mcp\InsideDev.McpStdio.exe if you use the stdio launcher, tools\muter\InsideMuter.exe if you want the game muted. The Steam client must be running, or the game closes itself about two seconds after start. Then type doctor in the console: it checks the install. The README has the full table and the first-run steps.
Tested
In the game, in the same scene and back to back with 0.10.0: idle cost, call latency, screenshots, recording length against game time, recording with another window over the game, recording while an agent drives, mods in loaded and unloaded levels, level loads during recordings and replays, deaths and respawns, swimming, the security refusals, the stdio launcher, and a clean install from this zip. Five independent reviews of the riskiest changes were done before the release and their findings fixed. Not tested: game sound capture together with video (the test machine had no audio output device), and a session of an hour or more.