#!/bin/bash
# Marks Steam's shared redistributables as already run in every Proton prefix.
#
# A game whose depot lists _CommonRedist makes the client run the real installer inside the
# prefix on first launch. Those are x86 bundles, so they run under FEX, and the 2019 one leaves
# a task behind every time: its main thread exits while a helper stays blocked reading a pipe it
# also holds the write end of, so the process never reaps and the client keeps waiting on it.
#
# The client skips a "Run Process" block whose HasRunKey is already set, which is the same escape
# WineUtils.seedVcRedistRegistryIfDllsPresent() takes for the app's own containers. The names and
# versions come out of the install scripts rather than a list kept here, because Valve revises
# them; a prefix already carrying the same set is left alone.
set -u
steam_root=${1:?steam root}

redist="$steam_root/steamapps/common/Steamworks Shared/_CommonRedist"
[ -d "$redist" ] || exit 0

# Every process an install script would run becomes the registry value the client writes once it
# has run it. Names sit one level inside "Run Process", the key they share a level further in.
block=$(find "$redist" -name installscript.vdf -print0 2>/dev/null | sort -z | xargs -0 -r awk -v now="$(date +%s)" '
  function emit(key, name,   path) {
    path = key
    sub(/^HKEY_LOCAL_MACHINE\\\\/, "", path)
    if (path == key)
      return
    printf "\n[%s] %d\n\"%s\"=dword:00000001\n", path, now, name
    # The client writes these from 32-bit steam.exe, so its own copy lands under Wow6432Node;
    # both spellings are seeded because the reader picks by its own word size.
    sub(/^Software\\\\/, "Software\\\\\\\\Wow6432Node\\\\\\\\", path)
    printf "\n[%s] %d\n\"%s\"=dword:00000001\n", path, now, name
  }
  FNR == 1 { depth = 0; name = ""; key = "" }
  /^[[:space:]]*\{/ { depth++; next }
  /^[[:space:]]*\}/ {
    if (depth == 3 && name != "" && key != "")
      emit(key, name)
    depth--
    next
  }
  {
    n = split($0, part, "\"")
    if (n >= 5 && tolower(part[2]) == "hasrunkey") { key = part[4]; next }
    if (n >= 3 && depth == 2) { name = part[2]; key = "" }
  }
')
[ -n "$block" ] || exit 0
stamp=$(printf '%s' "$block" | cksum)

for reg in "$steam_root"/steamapps/compatdata/*/pfx/system.reg \
           /mnt/bannerlator-sd/steamapps/compatdata/*/pfx/system.reg; do
  [ -f "$reg" ] || continue
  seeded=$(dirname "$reg")/.bannerlator-redists
  [ "$(cat "$seeded" 2>/dev/null)" = "$stamp" ] && continue
  printf '%s\n' "$block" >>"$reg" || continue
  printf '%s\n' "$stamp" >"$seeded"
  echo "== seeded redist markers into $reg"
done
