mirror of
https://github.com/Droid-Deck/DroidDeck.git
synced 2026-11-11 02:51:10 +00:00
Restart the client once for a title mapped while it runs
The client reads config.vdf once, as it starts. A title installed during a session got its per-app ARM64 Proton entry from the compat beat, but the running client kept its own pick: native for a Linux build, which then sat on "Downloading content (0%)" waiting for Steam Linux Runtime 2.0 and FEX it can never run here (Left 4 Dead 2), or proton-stable for a Windows one. The beat now runs the compat pass with --live, which notes titles it maps while the client runs. Once each has finished installing and no game is running, the session restarts the client through the existing restart-once marker. Once per title and three times per session at most. The mapping is re-applied before the client starts again, since it writes config.vdf back from memory as it exits.
This commit is contained in:
1 parent
9a6558d8b3
commit
c9fb19b0cd
2 files changed
+56
-4
No files matched your search
@@ -498,6 +498,31 @@ case $mode in
|
||||
done
|
||||
return 1
|
||||
}
|
||||
# A title the compat pass maps while the client runs only takes that mapping at the client's
|
||||
# next start (see bannerlator-steam-compat): until then the client launches it its own way -
|
||||
# a Linux build stuck on "Downloading content (0%)" for a Steam Linux Runtime and FEX that
|
||||
# cannot run here (Left 4 Dead 2, 2026-10-02). So restart the client once for it, through the
|
||||
# same marker and -shutdown as the ARM64 Proton's restart: only when every new title has
|
||||
# finished installing (StateFlags 4) and no game is running; another download just resumes.
|
||||
# Once per title and three times per session at most, so a client that rewrites config.vdf
|
||||
# can never loop it.
|
||||
compat_pending=$HOME/.bl-compat-pending
|
||||
compat_restarted=$HOME/.bl-compat-restarted
|
||||
rm -f "$compat_pending"
|
||||
: > "$compat_restarted"
|
||||
compat_restarts=0
|
||||
compat_settled() {
|
||||
local app m flags
|
||||
while read -r app; do
|
||||
[ -n "$app" ] || continue
|
||||
m="$steam_root/steamapps/appmanifest_$app.acf"
|
||||
[ -f "$m" ] || m="/mnt/droiddeck-sd/steamapps/appmanifest_$app.acf"
|
||||
[ -f "$m" ] || return 1
|
||||
flags=$(sed -n 's/^[[:space:]]*"StateFlags"[[:space:]]*"\([0-9]*\)".*/\1/p' "$m" | head -n 1)
|
||||
[ "$flags" = 4 ] || return 1
|
||||
done < "$compat_pending"
|
||||
! pgrep -f 'reaper SteamLaunch' >/dev/null 2>&1
|
||||
}
|
||||
for ((_i = 0; _i < 720; _i++)); do
|
||||
nap 5
|
||||
beat=$((beat + 1))
|
||||
@@ -505,7 +530,17 @@ case $mode in
|
||||
bannerlator-seed-redists "$steam_root" >/dev/null 2>&1 || true
|
||||
if compat_due; then
|
||||
: > "$compat_stamp"
|
||||
bannerlator-steam-compat "$steam_root" >/dev/null 2>&1 || true
|
||||
bannerlator-steam-compat "$steam_root" --live >/dev/null 2>&1 || true
|
||||
fi
|
||||
if [ -s "$compat_pending" ] && compat_settled; then
|
||||
_bl_new=$(sort -u "$compat_pending" | grep -vxF -f "$compat_restarted" || true)
|
||||
rm -f "$compat_pending"
|
||||
[ -n "$_bl_new" ] && [ "$compat_restarts" -lt 3 ] || continue
|
||||
compat_restarts=$((compat_restarts + 1))
|
||||
printf '%s\n' $_bl_new >> "$compat_restarted"
|
||||
step "newly installed title(s) $(echo $_bl_new) set to the ARM64 Proton: restarting the Steam client once so it takes effect"
|
||||
: > "$HOME/.bl-restart-once"
|
||||
"$steam_root/steamrtarm64/steam" -shutdown >/dev/null 2>&1 || true
|
||||
fi
|
||||
done
|
||||
) &
|
||||
@@ -719,6 +754,9 @@ BUSCONF
|
||||
# arguments, which were acted on. Not counted against the update cap.
|
||||
if [ -f "$HOME/.bl-restart-once" ]; then
|
||||
echo "== steam: restarting once so the new compatibility layer is in the client's lists"
|
||||
# The client wrote config.vdf back from its own memory as it exited, which can drop the
|
||||
# per-title entries written while it ran - the very ones this restart is for.
|
||||
bannerlator-steam-compat "$steam_root" >/dev/null 2>&1 || true
|
||||
set --
|
||||
continue
|
||||
fi
|
||||
|
||||
@@ -579,7 +579,8 @@ def installed_apps(steam_root):
|
||||
|
||||
|
||||
def register_default(config_path, apps=(), name=None, protect=()):
|
||||
"""Writes the mapping. `name` defaults to our own tool; the first-run seed passes Valve's."""
|
||||
"""Writes the mapping. `name` defaults to our own tool; the first-run seed passes Valve's.
|
||||
Returns the app ids given a per-app entry by this call."""
|
||||
tool = name or TOOL
|
||||
# Tool names the user may deliberately have chosen (see adopt_extras); never repointed.
|
||||
keep = {n.lower() for n in protect}
|
||||
@@ -588,7 +589,8 @@ def register_default(config_path, apps=(), name=None, protect=()):
|
||||
tokens = tokenize(original)
|
||||
steam = find_block(tokens, ["InstallConfigStore", "Software", "Valve", "Steam"])
|
||||
if steam is None:
|
||||
return
|
||||
return []
|
||||
added = []
|
||||
mapping = find_block(tokens[steam + 1:], ["CompatToolMapping"])
|
||||
entry = ['"0"', "{", '"name"', '"%s"' % tool, '"config"', '""', '"priority"', '"75"', "}"]
|
||||
if mapping is None:
|
||||
@@ -612,10 +614,12 @@ def register_default(config_path, apps=(), name=None, protect=()):
|
||||
continue
|
||||
tokens[mapping + 1:mapping + 1] = [
|
||||
'"%s"' % app, "{", '"name"', '"%s"' % tool, '"config"', '""', '"priority"', '"250"', "}"]
|
||||
added.append(app)
|
||||
# Nothing to change is the usual case on the session's beat: the client's own file is left alone.
|
||||
text = serialize(tokens)
|
||||
if text != serialize(tokenize(original)):
|
||||
write_changed(config_path, text)
|
||||
return added
|
||||
|
||||
|
||||
def depot_build(depot):
|
||||
@@ -666,8 +670,18 @@ def main():
|
||||
config = os.path.join(steam_root, "config", "config.vdf")
|
||||
if os.path.isfile(config):
|
||||
apps = installed_apps(steam_root)
|
||||
register_default(config, apps, protect=extras)
|
||||
added = register_default(config, apps, protect=extras)
|
||||
print("bannerlator-steam-compat: default and %d installed title(s) set to %s" % (len(apps), TOOL))
|
||||
# The client reads config.vdf once, as it starts, and keeps its own decisions in memory for
|
||||
# the rest of its run: a title installed while it runs gets the client's own pick (native
|
||||
# for a Linux build, which then waits for Steam Linux Runtime + FEX it can never run here;
|
||||
# proton-stable for a Windows one), and the entry written here only counts from the next
|
||||
# start. Run from the session's beat (--live), the new entries are noted for the session,
|
||||
# which restarts the client once the install has settled (bannerlator-session).
|
||||
if added and "--live" in sys.argv[2:]:
|
||||
with open(os.path.join(os.path.expanduser("~"), ".bl-compat-pending"), "a") as f:
|
||||
f.write("".join("%s\n" % a for a in added))
|
||||
print("bannerlator-steam-compat: mapped while the client runs: %s" % " ".join(added))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
Reference in new issue
Block a user