Recursive AI

Ship a game for Steam and the Steam Deck

All onegame recipes

Export a C# game for Steam on Linux and Windows with the Steamworks library beside it, and build a Linux program that starts on the Steam Deck’s runtime.

Export with Steam

--steam copies Valve’s Steamworks library next to the program. The library is never downloaded and isn’t in the engine’s repository: you supply it from your copy of the Steamworks SDK. Without it the export stops before building:

Terminal
onegame export --target linux --steam
Text
error: --steam needs libsteam_api.so from your Steamworks SDK. Pass --steam-redist <folder>, or set ONEGAME_STEAM_REDIST (folder with linux-x64/libsteam_api.so) or ONEGAME_STEAM_SDK (the SDK folder).

The command exits 4 (with --json, the code is steam_redist_missing). Point it at the SDK:

Terminal
ONEGAME_STEAM_SDK=~/steamworks/sdk onegame export --target linux --steam --json
ONEGAME_STEAM_SDK=~/steamworks/sdk onegame export --target win --steam --json

ONEGAME_STEAM_SDK is the unpacked Steamworks SDK (it reads redistributable_bin/linux64 and redistributable_bin/win64). --steam-redist <dir> or ONEGAME_STEAM_REDIST instead names a folder holding linux-x64/libsteam_api.so and win-x64/steam_api64.dll. The Linux folder gets libsteam_api.so, the Windows one steam_api64.dll. These two commands weren’t run for this page, because the Steamworks SDK is Valve’s and needs your own account; the error above was.

  • The game itself must use OneGame.Steam for the library to be loaded. That package has the Steamworks bindings, Steam Input, and achievements, stats, cloud saves and presence behind store-neutral services.
  • steam_appid.txt is never shipped: the export deletes it from the output. With it present Steam’s relaunch check always passes, so the game would run outside the Steam client. To try an exported build by hand, put steam_appid.txt in the current directory with the Steam client signed in.
  • In the depot, set the Linux launch option to run.sh and the Windows one to <game>.exe. Uploading depots isn’t part of the export.
  • --steam isn’t available for macOS.

The Steam Deck and the Steam Linux runtime

Steam runs Linux games in its Steam Linux Runtime 3 (“sniper”), which has glibc 2.31. A program linked on a newer system won’t start there: version 'GLIBC_2.38' not found. The export reads the program and warns when it needs more:

Text
  warning glibc_too_new: Orchard needs glibc 2.38, newer than 2.31 in Steam's Linux runtime (and so on the Steam Deck). Build on an older system, or inside the Steam Linux Runtime SDK: see docs/exporting.md.

That warning is from a build on a current Linux system. For a build that runs on the Deck, export on a system with glibc 2.31 or older, or inside Valve’s Steam Linux Runtime SDK image.

The engine repository has a script for the second way, tools/steamrt.sh, which runs the export and a headless check inside Valve’s public runtime images with bubblewrap (no Steam account needed). It is a repository tool, not part of the NuGet packages, and it mounts an engine checkout as /engine, so it needs a checkout at 1.1.2 and a game built against it. Its run step is the check: the exported folder read-only in the same image, and a passing run prints the same state hash as onegame run --headless --frames 60 --json on the development machine. It doesn’t replace a run on the device for the controller, display and graphics driver.

Good to know

  • On the Deck, a game is played with the gamepad: give every screen a starting focus and make every action reachable with the d-pad and confirm. See Controller and keyboard navigation.
  • onegame capture --size deck draws a frame at the Deck’s 1280×800.
  • The repository’s tools/devices/deck.sh runs a build on a Deck over ssh and checks it; see Checking on devices.
  • Exports for Windows made on Linux aren’t NativeAOT: see Export for Linux, Windows and macOS.

Every Steam detail is in Exporting.