Recursive AI

The debug overlay

All onegame recipes

Show frame time, tick, entity count, network and audio figures over a running C# game with onegame’s debug overlay, toggle it with F3 or a gamepad chord, capture it in a screenshot test, and keep it out of release builds.

New in 1.5.0. A development build of a game has an on-screen panel in the top-right corner. Press F3, or hold Back and Start on a gamepad, to show or hide it. It reads only what live control already reports: the frame time (current, min, average and max over the last 60 frames, with a small chart), the tick and entity count, the round trip, bytes per second and drift when the game is connected to a server, and the audio device’s backend, underruns, peak and frames written and played. Exports and Release builds don’t contain it.

Show it

Nothing to add to the game. Start any Debug build in a window, here the scaffold from onegame new beacon, and press F3:

Terminal
onegame run

Three environment variables change how it starts:

Terminal
ONEGAME_OVERLAY=on onegame run                                    # shown from the first frame
ONEGAME_OVERLAY_KEY=Backquote onegame run                         # another key; "none" turns the key off
ONEGAME_OVERLAY_CHORD=LeftShoulder+RightShoulder onegame run      # another pad chord; "none" turns it off

The toggle key is swallowed, so the game never sees F3. The window and the keys weren’t run for this page; everything below was.

In a scenario

overlay: on, off or toggle is a scenario step, and a capture includes the panel while it is shown:

scenarios/overlay.yaml

YAML
name: overlay
description: The debug overlay shows in a capture, with machine-dependent figures masked so the picture repeats.
window: 640x360
steps:
  - step: 30
  - overlay: on
expect:
  - capture: { reference: refs/overlay.png, tolerance: 2, max-diff: 0.001 }
Terminal
onegame test --scenario scenarios/overlay.yaml --update-references
onegame test --scenario scenarios/overlay.yaml
Text
PASS overlay (410 ms, tick 30, hash 3864c4c5e102f97d)
created reference /tmp/onegame/beacon/scenarios/refs/overlay.png
1 passed, 0 failed
PASS overlay (330 ms, tick 30, hash 3864c4c5e102f97d)
1 passed, 0 failed

A headless run masks every figure that depends on the machine or the moment, such as frame times, rates and audio counters, as --. That is why the second run matches the reference it made.

From live control

The overlay tool shows or hides the panel and returns its text as lines. With the MCP client from Drive a running game over MCP:

Text
step {"frames": 30} -> {"frame":30,"tick":30,"hash":"3864c4c5e102f97d"}
overlay {"visible": true} -> {"visible":true,"key":"F3","chord":["Back","Start"],"masked":true,"lines":["debug overlay","frame -- ms","tick 30  entities 1"]}
capture_frame {"path": "shots/overlay.png", "size": "720p"} -> {"path":"/tmp/onegame/beacon/artifacts/shots/overlay.png","width":1280,"height":720,"scale":1,"sha256":"94bab70c49443f1fc2d412f5061d7f179067252fda65996f22a30eaea550d669","renderer":"NVIDIA GeForce RTX 4070","tick":30,"hash":"3864c4c5e102f97d"}
overlay {} -> {"visible":true,"key":"F3","chord":["Back","Start"],"masked":true,"lines":["debug overlay","frame -- ms","tick 30  entities 1"]}
quit {} -> {"frame":30,"tick":30,"hash":"3864c4c5e102f97d"}

The capture shows the ship in the middle and a dark panel in the top-right corner with those three lines. A headless game without a server or a sound device has no network or audio lines. masked: false shows the real figures, and key and chord change the bindings while the game runs.

Not in an export

Terminal
onegame export --target linux --json

The report says "devTools":false, and the exported program contains neither the panel’s text nor the live-control assembly. The export checks this itself: if the program mentions the development tools anyway, it fails with dev_tools_present instead of shipping them. Setting <OneGameDev>true</OneGameDev> in the project didn’t trigger it here, because the export still built without the tools ("devTools":false); the check is a backstop.

Good to know

  • The panel needs the default 2D stage, the one Draw2D views use. It is drawn over the finished frame.
  • Its text is rebuilt four times a second, which allocates about 10 KB each time and nothing in between.
  • --live on an exported program exits 5 with no_dev_tools, for the same reason.
  • To watch the network figures, run a client against a server, as in Client/server sync with a dedicated server, and press F3 in the client’s window.

More in Driving a game.