mirror of
https://github.com/spoopyghosty0/frameport.git
synced 2026-10-06 07:00:40 +02:00
Steam library fallback (agent v56, GitHub #41): Play re-registers a devkit entry Steam forgot after a restart, the console-log appid comes from the current Steam session only, and art updates also reach the devkit entry
This commit is contained in:
1 parent
9b57c4753f
commit
bad59bfb5b
3 files changed
+58
-10
No files matched your search
@@ -514,7 +514,7 @@ lacks (ActivityNotFoundException) → imported by hand: libmain.so + game.json
|
||||
DATA/ → external files/WiiCompiledOpenXRVR/DATA, MOD/ → .../RetroRewind6 (decompiled with jadx). Lepton has no
|
||||
picker at all: a FramePort fix would be an injected picker activity. Generated cover/banner art used to suppress the
|
||||
Steam placeholder set (no Steam art at all) → fixed in artwork/steam.py.
|
||||
**Steam library failures (GitHub #21/#30):** on some Frames Steam never loads FramePort's shortcuts.vdf entries (same SteamOS build and arm64 beta client as the dev Frame; IDs correct; file written before Steam starts): Play → console_log `GameAction [AppID <id>] … RequestingLicense → UpdatingAppInfo → LaunchApp failed with AppError_9` (= "Game configuration unavailable", Steam treats the id as a store app). Cause unknown; agent v42/43 diagnostics: `launch` returns `steam` (started / error + code / silent from console_log), `collect_diag` adds `steam_library` (real Steam dir, beta, Steam start vs vdf write time, entries per account, devkit games) + `steam-console.txt` (incl. Steam's `logs/shortcuts.previous.txt` if present; steamclient.so has "LoadShortcuts: rejecting attempt to load shortcuts: invalid account ID"). **Fallback (agent v43):** when Play gets AppError_9 the agent registers the game through Steam's devkit interface (what Valve's Devkit Management Tool does, MIT: `devkit-1 steam://devkit-1/<~/.steam/steam.token>/create-shortcut?response=<file>&gameid=<id>&directory=~/devkit-game` written to ~/.steam/steam.pipe; answer file / `.error`; `~/devkit-game/<id>/launch.sh` = link to the game's launch.sh, `<id>-argv.json` ["launch.sh"] (relative to the folder), `<id>-settings.json` {steam_play 0, compat_tool ""}). Steam adds it live (no restart), picks its own appid (read back from shortcuts.vdf by DevkitGameID), shows it as a normal non-Steam game named "Devkit Game: <id>" (OpenVR 0, but VR works: owner-verified 2026-10-04), art copied to grid/<appid>*. Ids: letter first, then letters/digits/_ only (spaces, '-', leading digit → "missing/invalid arguments"). Later Plays use the devkit entry; uninstall (`devkit_unregister`, `delete-shortcut` live) and purge remove it. Verified on the dev Frame: register/launch/unregister; the AppError_9 trigger itself only in unit tests. GitHub #42 (two Steam accounts, neither MostRecent): Steam rewrote the active account's shortcuts.vdf without FramePort's entries right after starting, and added the devkit entry live without saving it, so `devkit_appid` (vdf only) failed ("Steam added the devkit entry but didn't save it"); agent v55 `devkit_appid_from_log` reads Steam's `sanitize shortcut app id "~/devkit-game/<id>/launch.sh": replacing 0 with N` console line.
|
||||
**Steam library failures (GitHub #21/#30):** on some Frames Steam never loads FramePort's shortcuts.vdf entries (same SteamOS build and arm64 beta client as the dev Frame; IDs correct; file written before Steam starts): Play → console_log `GameAction [AppID <id>] … RequestingLicense → UpdatingAppInfo → LaunchApp failed with AppError_9` (= "Game configuration unavailable", Steam treats the id as a store app). Cause unknown; agent v42/43 diagnostics: `launch` returns `steam` (started / error + code / silent from console_log), `collect_diag` adds `steam_library` (real Steam dir, beta, Steam start vs vdf write time, entries per account, devkit games) + `steam-console.txt` (incl. Steam's `logs/shortcuts.previous.txt` if present; steamclient.so has "LoadShortcuts: rejecting attempt to load shortcuts: invalid account ID"). **Fallback (agent v43):** when Play gets AppError_9 the agent registers the game through Steam's devkit interface (what Valve's Devkit Management Tool does, MIT: `devkit-1 steam://devkit-1/<~/.steam/steam.token>/create-shortcut?response=<file>&gameid=<id>&directory=~/devkit-game` written to ~/.steam/steam.pipe; answer file / `.error`; `~/devkit-game/<id>/launch.sh` = link to the game's launch.sh, `<id>-argv.json` ["launch.sh"] (relative to the folder), `<id>-settings.json` {steam_play 0, compat_tool ""}). Steam adds it live (no restart), picks its own appid (read back from shortcuts.vdf by DevkitGameID), shows it as a normal non-Steam game named "Devkit Game: <id>" (OpenVR 0, but VR works: owner-verified 2026-10-04), art copied to grid/<appid>*. Ids: letter first, then letters/digits/_ only (spaces, '-', leading digit → "missing/invalid arguments"). Later Plays use the devkit entry; uninstall (`devkit_unregister`, `delete-shortcut` live) and purge remove it. Verified on the dev Frame: register/launch/unregister; the AppError_9 trigger itself only in unit tests. GitHub #42 (two Steam accounts, neither MostRecent): Steam rewrote the active account's shortcuts.vdf without FramePort's entries right after starting, and added the devkit entry live without saving it, so `devkit_appid` (vdf only) failed ("Steam added the devkit entry but didn't save it"); agent v55 `devkit_appid_from_log` reads Steam's `sanitize shortcut app id "~/devkit-game/<id>/launch.sh": replacing 0 with N` console line. GitHub #41 (one account): same Steam behaviour, and every install restarts Steam, which forgets the never-saved devkit entry. Agent v56: the log fallback reads only the current session's console_log.txt; Play re-registers a devkit entry that gets AppError_9; art updates also write the devkit entry's grid art (`copy_grid_art`). Open: why some Frames' Steam never loads or saves shortcuts.vdf (single account too).
|
||||
**Exit game (GitHub #36, 2026-10-04):** `Apps.TerminateApp` (what Exit game calls; reachable for tests through Steam's CEF devtools on 127.0.0.1:8080, SharedJSContext, `Runtime.evaluate` — a stdlib websocket client is enough) closed both a normal shortcut and a devkit entry on the dev Frame within 1-3 s. SIGTERM to Steam's `reaper` alone left launch.sh + Lepton (setsid) + the container running (an earlier headset launch ran on for 87 min); SIGTERM to launch.sh cleans up in ~4 s. Agent v44: launch.sh's 2 s loop ends the game when its parent (the reaper) is gone; `upgrade_launchers` (from ensure_host_fixes) adds that to existing launchers in place. Which in-headset exit path fails is still unknown. Screenshots on the Frame: all under SteamVR's appid 250820 (`760/remote/250820/screenshots`, screenshots.vdf has creation time, no game).
|
||||
**SteamVR dashboard at game start (2026-10-04):** the dashboard (Resume game / controller / VR options) was open whenever a FramePort game started (also over Lepton's 2D launcher). Steam's UI exposes `SteamClient.OpenVR.VROverlay.{IsDashboardVisible,HideDashboard,ShowDashboard}` (CEF devtools, `steam_js` in the agent). Agent v44: launch.sh starts `_dashboard_worker` (waits for FrameBridge's first `pacing:` line in launch.log, then hides a visible dashboard for 25 s, at most 3 times; log `<base>/dashboard.log`; opt out with env FRAMEPORT_KEEP_DASHBOARD=1). Verified on the dev Frame (dashboard shown → 4XVR launched via Steam → hidden ~5 s after the first frames); not yet seen in the headset. **Headset (ITR2, 2026-10-05): too late** — Steam shows its frame menu (`valve.steam.gamepadui.frame.menu`, vrwebhelper_systemui.txt `[PooledPopups] Showing`) ~0.3 s after the game's first submitted frame (FrameBridge `new layer:`), but the first `pacing:` summary comes ~8 s later; the owner had pressed Resume (`[HideDashboard] return_to_game`) before the worker looked. Agent v52: watches from the first `new layer:` line (incremental log reads, 0.5 s polls, 30 s window). Agent v53: stops for good once the player opens the dashboard with the controller (`toggle_dashboard_action` in vrwebhelper_systemui.txt since the worker started): v52 closed it 60 ms after each press, and the game, paused for it, stayed paused.
|
||||
**Space warp / ITR2 (2026-10-04):** Into The Radius 2 (UE5, `libUnreal.so` + OVRPlugin, Vulkan) uses Application SpaceWarp (extra swapchains `376x376 format=97` motion vectors + `format=129` depth); #35 reports flickering textures. OVRPort's `patch_disable_space_warp` has no effect on UE5, and hiding XR_FB_space_warp in FrameBridge's enumerate doesn't reach the game either: **OVRPort's dispatcher offers/enables XR_FB_space_warp itself**. FrameBridge `hide_space_warp` (per game, off) hides it and strips `XrCompositionLayerSpaceWarpInfoFB` (1000171000) from the projection views (log `hide_space_warp: removed space warp info`); the game still renders its MV swapchains. Test build installed on the dev Frame; flicker not yet checked in a headset. Heuristic: UE5 + OVRPlugin shows it as an option (off). `equirect_emul` is suggested for Unreal games whose graphics API isn't detected ("GLES or unknown"); on Vulkan it switches itself off (Myst/Riven/ITR2): harmless, but Unreal Vulkan detection is a known gap.
|
||||
|
||||
@@ -36,7 +36,7 @@ import time
|
||||
import zlib
|
||||
from types import SimpleNamespace
|
||||
|
||||
AGENT_VERSION = 55
|
||||
AGENT_VERSION = 56
|
||||
HOME = os.path.expanduser("~")
|
||||
STEAM = os.path.join(HOME, ".local/share/Steam")
|
||||
ANCHORS = os.path.join(HOME, "Applications/quest-frame")
|
||||
@@ -1135,7 +1135,16 @@ def remove_from_library(user, remove, result):
|
||||
|
||||
def update_library(user, packages, result, shortcuts=True):
|
||||
"""Add/update installed games' shortcuts + grid art in one Steam account (Steam is closed; shortcuts=False: only
|
||||
the grid art of shortcuts that are already right, while Steam runs)."""
|
||||
the grid art of shortcuts that are already right, while Steam runs). A game's devkit entry (the Play fallback)
|
||||
gets the same art: on Frames where Steam ignores shortcuts.vdf it is the one in the library (GitHub #41)."""
|
||||
for pkg in packages:
|
||||
gameid = devkit_gameid(pkg)
|
||||
appid = devkit_appid(gameid) if gameid else None
|
||||
if appid:
|
||||
try:
|
||||
copy_grid_art(pkg, appid, [user])
|
||||
except OSError as exc:
|
||||
result.setdefault("errors", []).append(f"{pkg}: devkit art: {exc}")
|
||||
vdf = os.path.join(STEAM, "userdata", user, "config/shortcuts.vdf")
|
||||
grid = os.path.join(os.path.dirname(vdf), "grid")
|
||||
os.makedirs(grid, exist_ok=True)
|
||||
@@ -1283,12 +1292,13 @@ def devkit_appid(gameid):
|
||||
|
||||
def devkit_appid_from_log(gameid):
|
||||
"""The appid Steam picked for a devkit game, from its console log ('sanitize shortcut app id "<dir>/<id>/launch.sh":
|
||||
replacing 0 with N'). Steam adds the entry live but may save shortcuts.vdf only later (GitHub #42: a Frame with two
|
||||
Steam accounts never had it on disk), so the log is the fallback. The newest line wins."""
|
||||
replacing 0 with N'). Steam adds the entry live but may never save it (GitHub #41/#42), so the log of the running
|
||||
Steam session is the fallback (console_log.previous.txt is the session before, whose live entries are gone). The
|
||||
newest line wins."""
|
||||
exe = os.path.join(DEVKIT_GAMES, gameid, "launch.sh")
|
||||
pat = re.compile(r'sanitize shortcut app id "' + re.escape(exe) + r'": replacing \d+ with (\d+)')
|
||||
found = None
|
||||
for name in ("console_log.previous.txt", "console_log.txt"):
|
||||
for name in ("console_log.txt",): # this Steam session only: entries added live are gone after a restart
|
||||
try:
|
||||
with open(os.path.join(STEAM, "logs", name), errors="replace") as f:
|
||||
for line in f:
|
||||
@@ -1340,8 +1350,14 @@ def devkit_register(pkg):
|
||||
time.sleep(0.5)
|
||||
if not appid:
|
||||
raise AgentError("Steam added the devkit entry but didn't save it")
|
||||
copy_grid_art(pkg, appid)
|
||||
return appid
|
||||
|
||||
|
||||
def copy_grid_art(pkg, appid, users=None):
|
||||
"""The game's Steam art (portrait, landscape, hero, logo) as grid/<appid>* in every (or the given) account."""
|
||||
anchor = os.path.join(ANCHORS, pkg)
|
||||
for user in steam_users():
|
||||
for user in users if users is not None else steam_users():
|
||||
grid = os.path.join(STEAM, "userdata", user, "config/grid")
|
||||
os.makedirs(grid, exist_ok=True)
|
||||
for kind, suffix in (("portrait", "p"), ("landscape", ""), ("hero", "_hero"), ("logo", "_logo")):
|
||||
@@ -1351,7 +1367,6 @@ def devkit_register(pkg):
|
||||
if re.match(rf"^{appid}{re.escape(suffix)}\.", os.path.basename(old)):
|
||||
os.remove(old)
|
||||
shutil.copy(img, os.path.join(grid, f"{appid}{suffix}{os.path.splitext(img)[1]}"))
|
||||
return appid
|
||||
|
||||
|
||||
def devkit_unregister(pkg, steam_running=True):
|
||||
@@ -1403,8 +1418,9 @@ def cmd_launch(args):
|
||||
raise AgentError(f"{NOT_IN_LIBRARY}: {dep.get('title') or pkg}")
|
||||
steam = steam_launch(appid, args.get("wait", 10))
|
||||
out = {"package": pkg, "gameid": steam_gameid(appid), "title": dep.get("title"), "via": via, "steam": steam}
|
||||
if via == "shortcut" and steam["result"] == "error" and steam.get("code") == 9 and args.get("fallback", True):
|
||||
# Steam doesn't know the shortcut at all (it tried to license a store app with that id): devkit entry
|
||||
if steam["result"] == "error" and steam.get("code") == 9 and args.get("fallback", True):
|
||||
# Steam doesn't know the shortcut at all (it tried to license a store app with that id): devkit entry. A devkit
|
||||
# entry Steam never saved is gone after a Steam restart (every install restarts it, GitHub #41): add it again
|
||||
try:
|
||||
appid = devkit_register(pkg)
|
||||
except AgentError as exc:
|
||||
|
||||
@@ -1329,3 +1329,35 @@ def test_devkit_appid_from_steams_console_log(monkeypatch, tmp_path):
|
||||
f'[2026-10-05 15:29:14] sanitize shortcut app id "{exe}": replacing 0 with 3849978642, reason: k_unAppIdInvalid\n')
|
||||
assert a.devkit_appid("I_Am_Cat") == 3849978642 # nothing in shortcuts.vdf: the newest log line
|
||||
assert a.devkit_appid("Missing") is None
|
||||
|
||||
|
||||
def test_devkit_appid_ignores_the_previous_steam_session(monkeypatch, tmp_path):
|
||||
"""Live devkit entries die with Steam (GitHub #41): an appid from console_log.previous.txt is stale."""
|
||||
a = load_agent(monkeypatch, tmp_path)
|
||||
logs = Path(a.STEAM) / "logs"
|
||||
logs.mkdir(parents=True, exist_ok=True)
|
||||
exe = f"{a.DEVKIT_GAMES}/Batman/launch.sh"
|
||||
(logs / "console_log.previous.txt").write_text(f'sanitize shortcut app id "{exe}": replacing 0 with 77, x\n')
|
||||
(logs / "console_log.txt").write_text("Steam started\n")
|
||||
assert a.devkit_appid("Batman") is None
|
||||
|
||||
|
||||
def test_launch_registers_a_lost_devkit_entry_again(monkeypatch, tmp_path):
|
||||
"""After a Steam restart Steam forgot the (never saved) devkit entry: Play gets AppError_9 and registers it again."""
|
||||
a = load_agent(monkeypatch, tmp_path)
|
||||
monkeypatch.setattr(a, "check_pkg", lambda p: p)
|
||||
monkeypatch.setattr(a, "deployment", lambda p: {"appid": 111, "title": "Batman"})
|
||||
monkeypatch.setattr(a, "run", lambda *x, **k: subprocess.CompletedProcess([], 0, "", ""))
|
||||
monkeypatch.setattr(a, "devkit_gameid", lambda p: "Batman")
|
||||
monkeypatch.setattr(a, "devkit_appid", lambda g: 222) # the stale entry from before the restart
|
||||
registered = []
|
||||
monkeypatch.setattr(a, "devkit_register", lambda p: registered.append(p) or 333)
|
||||
launches = []
|
||||
|
||||
def launch(appid, wait=10):
|
||||
launches.append(appid)
|
||||
return {"result": "error", "code": 9} if appid == 222 else {"result": "started"}
|
||||
monkeypatch.setattr(a, "steam_launch", launch)
|
||||
out = a.cmd_launch({"package": "com.camouflaj.manta"})
|
||||
assert registered == ["com.camouflaj.manta"] and launches == [222, 333]
|
||||
assert out["via"] == "devkit" and out["steam"]["result"] == "started"
|
||||
Reference in new issue
Block a user