5.7 KiB
Steam game imports
Second Library still registers the selected Steam library. It now also scans Windows
executables in its immediate game subfolders and steamapps/common, using the same
importer as Added Games. Existing Steam manifests are preserved.
droiddeck-steam-games watch runs beside the client. It identifies a game by an
existing manifest's install directory, a steam_appid.txt beside the game or selected
executable, or a unique normalized title from Steam's store search with an explicit
country. A steam_appid.txt naming 480 (Spacewar, the Steamworks SDK sample that Steam
emulators and multiplayer fixes use in place of the game) identifies nothing; the
launcher's artwork matching ignores it too. Matching also accepts the terminal Windows Edition and INTERGRADE suffixes;
multiple matches still remain unresolved. Artwork's fuzzy matching is deliberately not
used for identity. Ambiguous or unresolved titles remain non-Steam games.
Ownership comes from the running native ARM64 client's BIsSubscribedApp, through
versioned SteamClient020 / SteamUser021 / STEAMAPPS_INTERFACE_VERSION008 interfaces. The
helper gets the account from that connection, not from a public profile. No API key,
password, profile visibility change, or CEF debugging port is needed. Each probe runs in
a bounded subprocess so library failures cannot crash the importer or client.
The resulting snapshot is stored under that account's userdata/<id>/config and
refreshed every 30 seconds while logged in. Title lookups retry every five minutes and
when the source changes, so an early network failure does not end the watcher. Changed
status and probe failures are written to the session log. Startup and post-exit import
use the last successful snapshot for the selected account. The client reads manifests
and shortcuts only at start, so when a snapshot confirms owned titles that are not yet
imported, the watcher restarts the client once (not while a game runs or a download is in
progress) and the importer runs between the exit and the next start. An unavailable client or offline first launch falls back to shortcuts; existing
snapshots remain usable offline. Steam still enforces the current license at launch.
For a confirmed game without a manifest, the importer links the source folder into the
internal Steam library and writes an installed manifest with Universe=1 and
StateFlags=4. Steam ignores manifests without the universe field. A manifest without
installed depots makes Steam verify every file, so the importer carries the build another
client recorded: WinNative's .winnative-steam/steamapps manifest beside the game folder,
or a completed download's depot manifest IDs from .DepotDownloader/depot.config or, when
that file is gone, the <depot>_<gid>.manifest names in .DepotDownloader/completed. Steam then
only downloads what changed since that build. Bare manifests from earlier imports are
upgraded while Steam has not touched them. Without either record Steam still verifies.
WinNative's manifest also identifies the folder without a store lookup. Steam updates and uninstall
operate on the linked game files, so imported folders must be writable. Existing Steam
manifests and directories are preserved. Only the exact minimal manifests generated by
the earlier importer are migrated, with the matching source symlink still present. If
registration fails, the game remains a shortcut. Once Steam takes over an install,
manage it in Steam; forgetting an Added Games folder only removes its shortcuts.
An import is undone (its symlink and manifest, never the folder) when the folder was imported as Spacewar, or when a snapshot of the folder's current files names another app. The folder is then imported as that app if the account owns it, else it is a shortcut again. A failed title lookup undoes nothing. The launcher likewise drops artwork it fetched for the app the files named before and fetches it again; pictures the user chose are kept.
The account's .droiddeck-routes.json maps shortcut IDs to real Steam app IDs so the
Android launcher uses the same title and Proton prefix as Steam. Other accounts do not
inherit those routes. Managed shortcuts are replaced; user-created shortcuts and
unreadable shortcut files are preserved. Both routes use the existing ARM64 Proton
registration.
Launcher artwork
The installed Steam game scan lists each game's appcache/librarycache/<appid>
directory once for its cover, background, icon and logo. Filename preference is
checked before directory preference: the app folder, then hash folders sorted by
name. Hash-named fallback icons are still taken only from the app folder in its
listing order. The directory snapshot is not kept between scans, so the next
scan sees new artwork folders.
Validation
Run python3 -m unittest discover -s tools/tests -p 'test_*.py' and Android unit tests.
Tests cover identity and edition matching, network recovery, account isolation,
owned/unowned/unknown routing, legacy manifest migration, manifest preservation,
filesystem collisions, shortcut preservation, and the versioned IPC call/cleanup
contract. On 2026-09-28, the ARM64 Steam client (1790545198) confirmed ownership and
installed status through ISteamApps for Final Fantasy VII Rebirth (2909400), Final
Fantasy VII Remake Intergrade (1462040), and Final Fantasy XV (637650), with all three
install paths resolving to the original second-library folders. The old managed
shortcuts were removed. This verifies library registration, not complete game launches.
Unowned fallback and account isolation are covered by automated tests.
References: Steam Apps API, [Valve's versioned interfaces](https://github.com/ValveSoftware/Proton/tree/proton_11.0/lsteamcli ent/steamworks_sdk_154).