Merge pull request #442 from outis1one/claude/wolf-cemu-four-controllers-373xn8
Claude/wolf cemu four controllers 373xn8
This commit is contained in:
+312
-2
@@ -285,6 +285,84 @@ print(pick[0]["browser_download_url"] if pick else "")
|
|||||||
esac
|
esac
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Same job as _wolf_download_emulator_appimage above, but against GitLab's
|
||||||
|
# Releases API instead of GitHub's — needed for any project (ES-DE included)
|
||||||
|
# that's hosted on GitLab rather than GitHub, since GitHub's API obviously
|
||||||
|
# can't answer for a repo it doesn't host. Mirrors the same arch-matching /
|
||||||
|
# post-download ELF-header verification logic so both call sites behave
|
||||||
|
# identically from the caller's point of view.
|
||||||
|
_wolf_download_emulator_appimage_gitlab() {
|
||||||
|
local _display_name="$1" _project_path="$2" _existing_glob="$3" _dir="$4"
|
||||||
|
if ls "$_dir"/$_existing_glob 2>/dev/null | grep -q .; then
|
||||||
|
log_info "$_display_name already present in $_dir/"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
local _get=""
|
||||||
|
echo ""
|
||||||
|
log_info "$_display_name can be auto-downloaded."
|
||||||
|
prompt_yn "Download $_display_name AppImage now? (y/n):" "y" _get
|
||||||
|
[[ "$_get" =~ ^[Yy]$ ]] || return 0
|
||||||
|
|
||||||
|
log_info "Fetching latest $_display_name release from GitLab..."
|
||||||
|
local _encoded_path
|
||||||
|
_encoded_path=$(python3 -c "import urllib.parse,sys; print(urllib.parse.quote(sys.argv[1], safe=''))" "$_project_path")
|
||||||
|
local _url
|
||||||
|
_url=$(curl -fsSL "https://gitlab.com/api/v4/projects/${_encoded_path}/releases" \
|
||||||
|
| HOST_ARCH="$(uname -m)" python3 -c '
|
||||||
|
import sys, json, os
|
||||||
|
host = os.environ.get("HOST_ARCH", "")
|
||||||
|
arch_tags = {
|
||||||
|
"x86_64": ["x86_64", "amd64", "x64"],
|
||||||
|
"aarch64": ["aarch64", "arm64"],
|
||||||
|
"arm64": ["aarch64", "arm64"],
|
||||||
|
}.get(host, [host] if host else [])
|
||||||
|
all_arch_tags = ["x86_64", "amd64", "x64", "aarch64", "arm64", "armv7", "armhf", "i386", "i686"]
|
||||||
|
def has(name, tags):
|
||||||
|
n = name.lower()
|
||||||
|
return any(t in n for t in tags)
|
||||||
|
releases = json.load(sys.stdin)
|
||||||
|
# GitLab does not guarantee list order — sort explicitly instead of
|
||||||
|
# assuming index 0 is the newest (the mistake that would silently pick a
|
||||||
|
# stale/older release on some future API response ordering change).
|
||||||
|
releases = sorted(releases, key=lambda r: r.get("released_at") or "", reverse=True)
|
||||||
|
assets = []
|
||||||
|
for r in releases:
|
||||||
|
for link in r.get("assets", {}).get("links", []):
|
||||||
|
url = link.get("direct_asset_url") or link.get("url") or ""
|
||||||
|
if url.endswith(".AppImage"):
|
||||||
|
assets.append({"name": link.get("name", url), "browser_download_url": url})
|
||||||
|
if assets:
|
||||||
|
break
|
||||||
|
matching = [a for a in assets if arch_tags and has(a["name"], arch_tags)]
|
||||||
|
untagged = [a for a in assets if not has(a["name"], all_arch_tags)]
|
||||||
|
pick = matching or untagged or assets
|
||||||
|
print(pick[0]["browser_download_url"] if pick else "")
|
||||||
|
' 2>/dev/null)
|
||||||
|
if [[ -z "$_url" ]]; then
|
||||||
|
log_warning "Could not resolve download URL — get it manually from https://gitlab.com/${_project_path}/-/releases"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
local _file="$_dir/$(basename "$_url")"
|
||||||
|
curl -fL --progress-bar -o "$_file" "$_url" \
|
||||||
|
&& chmod +x "$_file" \
|
||||||
|
&& chown "$ACTUAL_USER:$ACTUAL_USER" "$_file" \
|
||||||
|
&& log_success "$_display_name downloaded: $_file" \
|
||||||
|
|| { log_warning "Download failed — get it manually from https://gitlab.com/${_project_path}/-/releases"; return 1; }
|
||||||
|
|
||||||
|
local _got_arch
|
||||||
|
_got_arch=$(file -b "$_file" 2>/dev/null)
|
||||||
|
case "$(uname -m)" in
|
||||||
|
x86_64)
|
||||||
|
echo "$_got_arch" | grep -qi 'x86-64\|x86_64' || \
|
||||||
|
log_warning "$_file doesn't look like an x86_64 build ($_got_arch) — it will fail with 'exec format error'. Grab the x86_64 asset by hand from https://gitlab.com/${_project_path}/-/releases"
|
||||||
|
;;
|
||||||
|
aarch64|arm64)
|
||||||
|
echo "$_got_arch" | grep -qi 'aarch64\|arm64' || \
|
||||||
|
log_warning "$_file doesn't look like an aarch64 build ($_got_arch) — it may fail to run. Grab the aarch64 asset by hand from https://gitlab.com/${_project_path}/-/releases"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
install_wolf() {
|
install_wolf() {
|
||||||
require_docker || return 1
|
require_docker || return 1
|
||||||
|
|
||||||
@@ -939,6 +1017,85 @@ UDEV
|
|||||||
log_info "not something this installer can supply. Cemu's own First-Time Setup Wizard covers where"
|
log_info "not something this installer can supply. Cemu's own First-Time Setup Wizard covers where"
|
||||||
log_info "to put it once you have one."
|
log_info "to put it once you have one."
|
||||||
|
|
||||||
|
# ── Optional: ES-DE and RetroArch as standalone AppImages (for Steam) ────
|
||||||
|
# These are ADDITIONAL to the esde/retroarch Wolf catalog containers
|
||||||
|
# above, not a replacement — nothing here removes or changes those. The
|
||||||
|
# only reason to want this: once added as a Steam non-Steam game
|
||||||
|
# (./manage.sh steam-add-nonsteam-game, which the wolf mount fix above
|
||||||
|
# already extended to reach the same roms/saves/bios/retro-home/
|
||||||
|
# retroarch paths the esde/retroarch containers use), Steam Input can
|
||||||
|
# give each of up to 4 identical-model controllers its own distinct
|
||||||
|
# identity by device path — the one thing Wolf's own 3-concrete-pad-type
|
||||||
|
# ceiling can't do for a 4th controller (see manage.sh's own "4
|
||||||
|
# controllers (Cemu / Wii U games)" help text). Skip both prompts below
|
||||||
|
# if you're happy running Wii U/retro systems through the esde app
|
||||||
|
# directly and don't need Steam's per-device controller assignment.
|
||||||
|
#
|
||||||
|
# Both download to a FIXED, predictable filename (ES-DE.AppImage /
|
||||||
|
# RetroArch.AppImage) regardless of the real upstream release asset's
|
||||||
|
# own name — steam-add-nonsteam-game matches by substring against the
|
||||||
|
# actual filename on disk, and bash glob matching is case-sensitive, so
|
||||||
|
# a fixed name (same symlink trick already used for Dolphin above) is
|
||||||
|
# what makes './manage.sh steam-add-nonsteam-game es-de' reliably find
|
||||||
|
# it regardless of how the vendor's own release happens to be named.
|
||||||
|
if [ ! -f "$_EMU_DIR/ES-DE.AppImage" ]; then
|
||||||
|
echo ""
|
||||||
|
# ES-DE is hosted on GitLab, not GitHub (confirmed against its own
|
||||||
|
# project page) — a different Releases API than every other
|
||||||
|
# standalone emulator above, hence the separate _gitlab helper.
|
||||||
|
log_info "ES-DE also ships an official standalone Linux AppImage — separate from the esde Wolf"
|
||||||
|
log_info "app above. Only useful for adding to Steam (see this repo's wolf README); skip this if"
|
||||||
|
log_info "you'll only ever use the esde app directly."
|
||||||
|
local _GET_ESDE_APPIMAGE=""
|
||||||
|
prompt_yn "Download the ES-DE AppImage for use via Steam? (y/n):" "n" _GET_ESDE_APPIMAGE
|
||||||
|
if [[ "$_GET_ESDE_APPIMAGE" =~ ^[Yy]$ ]]; then
|
||||||
|
_wolf_download_emulator_appimage_gitlab \
|
||||||
|
"ES-DE" "es-de/emulationstation-de" "ES-DE.AppImage" "$_EMU_DIR"
|
||||||
|
local _ESDE_REAL
|
||||||
|
_ESDE_REAL=$(ls "$_EMU_DIR"/*.AppImage 2>/dev/null \
|
||||||
|
| grep -iE '/(es-?de|emulationstation)[^/]*\.AppImage$' \
|
||||||
|
| grep -v '/ES-DE\.AppImage$' | head -1)
|
||||||
|
if [[ -n "$_ESDE_REAL" ]]; then
|
||||||
|
ln -sf "$(basename "$_ESDE_REAL")" "$_EMU_DIR/ES-DE.AppImage"
|
||||||
|
chown -h "$ACTUAL_USER:$ACTUAL_USER" "$_EMU_DIR/ES-DE.AppImage" 2>/dev/null || true
|
||||||
|
log_success "Linked $_EMU_DIR/ES-DE.AppImage -> $(basename "$_ESDE_REAL")"
|
||||||
|
log_info "Once Wolf is running, add it to Steam with: cd $WOLF_DIR && ./manage.sh steam-setup-frontends"
|
||||||
|
log_info "(waits for Steam sign-in — QR code via Moonlight — then wires this in automatically)"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ ! -f "$_EMU_DIR/RetroArch.AppImage" ]; then
|
||||||
|
echo ""
|
||||||
|
# Libretro's own buildbot doesn't publish through a GitHub/GitLab
|
||||||
|
# Releases API this installer can automate against — hizzlekizzle/
|
||||||
|
# RetroArch-AppImage is the well-regarded THIRD-PARTY nightly-build
|
||||||
|
# project the AppImage community catalogs (appimage.github.io etc.)
|
||||||
|
# themselves point to, same "flagged, not silently offered as
|
||||||
|
# official" treatment as the Dolphin community build above.
|
||||||
|
log_info "RetroArch also has a standalone Linux AppImage, separate from the retroarch Wolf app"
|
||||||
|
log_info "above — same rationale as ES-DE just above (Steam Input's per-device controller"
|
||||||
|
log_info "assignment). This comes from hizzlekizzle/RetroArch-AppImage, a well-regarded but"
|
||||||
|
log_info "THIRD-PARTY nightly-build project, not an official libretro.org release — grab"
|
||||||
|
log_info "RetroArch's own build by hand instead if you'd rather not run that."
|
||||||
|
local _GET_RA_APPIMAGE=""
|
||||||
|
prompt_yn "Download the RetroArch AppImage for use via Steam? (y/n):" "n" _GET_RA_APPIMAGE
|
||||||
|
if [[ "$_GET_RA_APPIMAGE" =~ ^[Yy]$ ]]; then
|
||||||
|
_wolf_download_emulator_appimage \
|
||||||
|
"RetroArch" "hizzlekizzle/RetroArch-AppImage" "RetroArch.AppImage" "$_EMU_DIR"
|
||||||
|
local _RA_REAL
|
||||||
|
_RA_REAL=$(ls "$_EMU_DIR"/*[Rr]etro[Aa]rch*.AppImage 2>/dev/null \
|
||||||
|
| grep -v '/RetroArch\.AppImage$' | head -1)
|
||||||
|
if [[ -n "$_RA_REAL" ]]; then
|
||||||
|
ln -sf "$(basename "$_RA_REAL")" "$_EMU_DIR/RetroArch.AppImage"
|
||||||
|
chown -h "$ACTUAL_USER:$ACTUAL_USER" "$_EMU_DIR/RetroArch.AppImage" 2>/dev/null || true
|
||||||
|
log_success "Linked $_EMU_DIR/RetroArch.AppImage -> $(basename "$_RA_REAL")"
|
||||||
|
log_info "Once Wolf is running, add it to Steam with: cd $WOLF_DIR && ./manage.sh steam-setup-frontends"
|
||||||
|
log_info "(waits for Steam sign-in — QR code via Moonlight — then wires this in automatically)"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
# ── Optional: TI-99/4A as its own ES-DE system ────────────────────────────
|
# ── Optional: TI-99/4A as its own ES-DE system ────────────────────────────
|
||||||
# TI-99/4A has no libretro core and isn't one of ES-DE's built-in systems,
|
# TI-99/4A has no libretro core and isn't one of ES-DE's built-in systems,
|
||||||
# so getting it real ES-DE treatment (artwork scraping, gameplay-time
|
# so getting it real ES-DE treatment (artwork scraping, gameplay-time
|
||||||
@@ -2166,7 +2323,26 @@ CATALOG = {
|
|||||||
# (see below) — without it, an emulator AppImage (Cemu, etc.)
|
# (see below) — without it, an emulator AppImage (Cemu, etc.)
|
||||||
# added as a non-Steam game (./manage.sh steam-add-nonsteam-game)
|
# added as a non-Steam game (./manage.sh steam-add-nonsteam-game)
|
||||||
# has no file to actually point Exe at from inside this container.
|
# has no file to actually point Exe at from inside this container.
|
||||||
f'{games}/emulators:/home/retro/Applications:rw'],
|
f'{games}/emulators:/home/retro/Applications:rw',
|
||||||
|
# Same roms/saves/bios/retro-home/retroarch mounts as esde/
|
||||||
|
# retroarch below — without these, a standalone ES-DE or
|
||||||
|
# RetroArch AppImage added here as a non-Steam game (same
|
||||||
|
# mechanism as Cemu above) would see none of the ROMs, cores,
|
||||||
|
# save states, BIOS files, or ES-DE's own settings/custom
|
||||||
|
# systems (TI-99, Wii U AntiMicroX command) that the esde/
|
||||||
|
# retroarch containers already have — it'd start from a
|
||||||
|
# completely empty config instead of reusing what's already
|
||||||
|
# set up. Every path here is the exact same host directory
|
||||||
|
# those two containers mount, just also visible from Steam.
|
||||||
|
f'{games}/roms:/ROMs:rw',
|
||||||
|
f'{games}/saves:/mnt/games/saves:rw',
|
||||||
|
f'{games}/media:/media:rw',
|
||||||
|
f'{games}/bios:/home/retro/bioses:rw',
|
||||||
|
f'{games}/retro-home:/home/retro/.config:rw',
|
||||||
|
f'{games}/retro-home-data:/home/retro/.local/share:rw',
|
||||||
|
f'{games}/retroarch:/home/retro/.config/retroarch:rw',
|
||||||
|
f'{games}/esde-custom-systems:/home/retro/ES-DE/custom_systems:rw',
|
||||||
|
f'{games}/esde-settings:/home/retro/ES-DE/settings:rw'],
|
||||||
env=['PROTON_LOG=1', 'RUN_SWAY=true',
|
env=['PROTON_LOG=1', 'RUN_SWAY=true',
|
||||||
'GOW_REQUIRED_DEVICES=/dev/input/* /dev/dri/* /dev/nvidia*'],
|
'GOW_REQUIRED_DEVICES=/dev/input/* /dev/dri/* /dev/nvidia*'],
|
||||||
cap_add=['SYS_ADMIN', 'SYS_NICE', 'SYS_PTRACE', 'NET_RAW', 'MKNOD', 'NET_ADMIN'],
|
cap_add=['SYS_ADMIN', 'SYS_NICE', 'SYS_PTRACE', 'NET_RAW', 'MKNOD', 'NET_ADMIN'],
|
||||||
@@ -3554,7 +3730,7 @@ _manage_wolf_complete() {
|
|||||||
local commands="start stop restart logs status pin controllers update apps cores reorder
|
local commands="start stop restart logs status pin controllers update apps cores reorder
|
||||||
add-web ge-proton games setup-swbf2 fix-ea-game wait-ea-app
|
add-web ge-proton games setup-swbf2 fix-ea-game wait-ea-app
|
||||||
install-ea-app diagnose-ea fix-perms install-completion backup
|
install-ea-app diagnose-ea fix-perms install-completion backup
|
||||||
steam-add-nonsteam-game cemu-clone-controller cemu-sync-controllers"
|
steam-add-nonsteam-game steam-setup-frontends cemu-clone-controller cemu-sync-controllers"
|
||||||
COMPREPLY=( $(compgen -W "$commands" -- "$cur") )
|
COMPREPLY=( $(compgen -W "$commands" -- "$cur") )
|
||||||
}
|
}
|
||||||
# Register for both 'manage.sh' and './manage.sh' invocation styles
|
# Register for both 'manage.sh' and './manage.sh' invocation styles
|
||||||
@@ -4014,6 +4190,75 @@ VDFPY
|
|||||||
echo "'Force the use of a specific Steam Play compatibility tool' is OFF — Cemu and"
|
echo "'Force the use of a specific Steam Play compatibility tool' is OFF — Cemu and"
|
||||||
echo "other native Linux AppImages don't run through Proton."
|
echo "other native Linux AppImages don't run through Proton."
|
||||||
;;
|
;;
|
||||||
|
steam-setup-frontends)
|
||||||
|
# One command covering what the ES-DE/RetroArch AppImage download
|
||||||
|
# step in setup.sh can't finish on its own: that step runs before
|
||||||
|
# Wolf/Steam containers even exist, so it can only download the
|
||||||
|
# AppImages and print instructions. This picks up from there —
|
||||||
|
# start Steam if needed, WAIT for it to be signed in (Steam Guard's
|
||||||
|
# QR-code sign-in itself can't be scripted: it needs a phone
|
||||||
|
# approving a prompt, so this only polls for the result, never
|
||||||
|
# performs the sign-in), then add whichever AppImage(s) already got
|
||||||
|
# downloaded as Steam non-Steam games via the existing
|
||||||
|
# steam-add-nonsteam-game command above (re-invoked, not
|
||||||
|
# reimplemented, so the two never drift apart).
|
||||||
|
if ! docker ps --format '{{.Names}}' | grep -qi WolfSteam; then
|
||||||
|
echo "Starting Wolf (docker compose up -d)..."
|
||||||
|
docker compose up -d
|
||||||
|
sleep 5
|
||||||
|
fi
|
||||||
|
|
||||||
|
_SSF_SIGNED_IN() {
|
||||||
|
local _home
|
||||||
|
_home=$(_steam_home)
|
||||||
|
[ -n "$_home" ] && [ -n "$(sudo ls "$_home/.steam/steam/userdata/" 2>/dev/null)" ]
|
||||||
|
}
|
||||||
|
|
||||||
|
if _SSF_SIGNED_IN; then
|
||||||
|
echo "Steam is already signed in — proceeding."
|
||||||
|
else
|
||||||
|
echo ""
|
||||||
|
echo "Steam isn't signed in yet. In Moonlight:"
|
||||||
|
echo " 1. Connect to the Steam app."
|
||||||
|
echo " 2. On Steam's login screen, choose 'Sign in with QR code'."
|
||||||
|
echo " 3. Scan it with your phone's Steam app and approve the prompt."
|
||||||
|
echo ""
|
||||||
|
echo "Waiting for sign-in (up to 10 minutes, checking every 5s — Ctrl+C to give up"
|
||||||
|
echo "and finish this later by re-running './manage.sh steam-setup-frontends')..."
|
||||||
|
_SSF_WAITED=0
|
||||||
|
until _SSF_SIGNED_IN; do
|
||||||
|
sleep 5
|
||||||
|
_SSF_WAITED=$((_SSF_WAITED + 5))
|
||||||
|
if [ "$_SSF_WAITED" -ge 600 ]; then
|
||||||
|
echo "Still not signed in after 10 minutes — giving up for now."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
echo "Signed in."
|
||||||
|
fi
|
||||||
|
|
||||||
|
GAME_DIR=$(grep '^GAME_STORAGE_DIR=' "$SCRIPT_DIR/.env" 2>/dev/null | cut -d= -f2-)
|
||||||
|
if [ -z "$GAME_DIR" ]; then read -r -p " Game storage path: " GAME_DIR; fi
|
||||||
|
_SSF_EMU_DIR="$GAME_DIR/emulators"
|
||||||
|
_SSF_ADDED_ANY=0
|
||||||
|
if [ -f "$_SSF_EMU_DIR/ES-DE.AppImage" ]; then
|
||||||
|
"$0" steam-add-nonsteam-game es-de "EmulationStation (ES-DE)" && _SSF_ADDED_ANY=1
|
||||||
|
else
|
||||||
|
echo "ES-DE.AppImage not found in $_SSF_EMU_DIR — download it first: sudo ./setup.sh wolf"
|
||||||
|
fi
|
||||||
|
if [ -f "$_SSF_EMU_DIR/RetroArch.AppImage" ]; then
|
||||||
|
"$0" steam-add-nonsteam-game retroarch "RetroArch" && _SSF_ADDED_ANY=1
|
||||||
|
else
|
||||||
|
echo "RetroArch.AppImage not found in $_SSF_EMU_DIR — download it first: sudo ./setup.sh wolf"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$_SSF_ADDED_ANY" = 1 ]; then
|
||||||
|
echo ""
|
||||||
|
echo "Cores/shaders/overlays live in the same retroarch/ directory the esde/retroarch apps"
|
||||||
|
echo "already use (shared mount — nothing new to configure there). If you haven't already:"
|
||||||
|
echo " ./manage.sh cores all (downloads every libretro core + shaders/overlays/database)"
|
||||||
|
fi
|
||||||
|
;;
|
||||||
cemu-clone-controller)
|
cemu-clone-controller)
|
||||||
# Clones a WORKING Cemu controller mapping onto a new device slot,
|
# Clones a WORKING Cemu controller mapping onto a new device slot,
|
||||||
# skipping Cemu's own Input Settings dialog entirely for that slot.
|
# skipping Cemu's own Input Settings dialog entirely for that slot.
|
||||||
@@ -4327,6 +4572,8 @@ SYNCPY
|
|||||||
echo " ./manage.sh install-completion - Enable tab-completion for this script"
|
echo " ./manage.sh install-completion - Enable tab-completion for this script"
|
||||||
echo " ./manage.sh steam-add-nonsteam-game [name] [display name]"
|
echo " ./manage.sh steam-add-nonsteam-game [name] [display name]"
|
||||||
echo " - Add an emulator (emulators/) as a non-Steam game, no GUI needed"
|
echo " - Add an emulator (emulators/) as a non-Steam game, no GUI needed"
|
||||||
|
echo " ./manage.sh steam-setup-frontends - Wait for Steam sign-in (QR code via Moonlight), then add"
|
||||||
|
echo " downloaded ES-DE/RetroArch AppImages to Steam"
|
||||||
echo " ./manage.sh cemu-clone-controller [slot 0-3] [uuid] [display name]"
|
echo " ./manage.sh cemu-clone-controller [slot 0-3] [uuid] [display name]"
|
||||||
echo " - Clone a working Cemu controller mapping onto a new device slot"
|
echo " - Clone a working Cemu controller mapping onto a new device slot"
|
||||||
echo " ./manage.sh cemu-sync-controllers - Auto-detect connected controllers via SDL and clone mappings onto all of them"
|
echo " ./manage.sh cemu-sync-controllers - Auto-detect connected controllers via SDL and clone mappings onto all of them"
|
||||||
@@ -4929,6 +5176,69 @@ container-created virtual controllers specifically (real hardware behaves
|
|||||||
this way; whether Steam Input sees Wolf's virtual joypads the same way is
|
this way; whether Steam Input sees Wolf's virtual joypads the same way is
|
||||||
still to be tested) — worth trying before assuming it works.
|
still to be tested) — worth trying before assuming it works.
|
||||||
|
|
||||||
|
## Running ES-DE and/or RetroArch through Steam instead of their own Wolf apps
|
||||||
|
The same Steam Input reasoning above applies beyond just Cemu: ES-DE and
|
||||||
|
RetroArch both ship their own official standalone Linux AppImages
|
||||||
|
(separate from the \`esde\`/\`retroarch\` Wolf catalog apps this installer
|
||||||
|
already runs), and adding one of those to Steam gets you the same
|
||||||
|
per-device controller assignment for every system it covers, not just
|
||||||
|
Cemu. \`sudo ./setup.sh wolf\` offers to download both (opt-in, default
|
||||||
|
no) right after the Cemu step — ES-DE's from its GitLab releases (it
|
||||||
|
isn't on GitHub), RetroArch's from \`hizzlekizzle/RetroArch-AppImage\` (a
|
||||||
|
well-regarded third-party nightly build — libretro.org's own buildbot
|
||||||
|
doesn't publish through an API this installer can automate against).
|
||||||
|
Both land in \`emulators/\` under a fixed name (\`ES-DE.AppImage\` /
|
||||||
|
\`RetroArch.AppImage\`) regardless of the real release asset's own
|
||||||
|
filename, so Steam's non-Steam-game matching finds them reliably.
|
||||||
|
|
||||||
|
They reuse the exact same \`roms/\`, \`saves/\`, \`bios/\`, \`retro-home\`, and
|
||||||
|
\`retroarch\` (cores/shaders/overlays) directories the \`esde\`/\`retroarch\`
|
||||||
|
containers already use — the \`steam\` Wolf app mounts all of the same
|
||||||
|
paths, so nothing needs re-downloading or re-scraping just because it's
|
||||||
|
now also reachable from Steam. If you haven't already populated cores:
|
||||||
|
\`\`\`bash
|
||||||
|
cd $WOLF_DIR && ./manage.sh cores all
|
||||||
|
\`\`\`
|
||||||
|
|
||||||
|
Finishing the Steam side needs one thing that can't be scripted — Steam
|
||||||
|
Guard's QR-code sign-in requires a phone approving a prompt — so this
|
||||||
|
polls for it instead of trying to script past it:
|
||||||
|
\`\`\`bash
|
||||||
|
cd $WOLF_DIR && ./manage.sh steam-setup-frontends
|
||||||
|
\`\`\`
|
||||||
|
Starts Wolf if it isn't already up, checks whether Steam's already
|
||||||
|
signed in (proceeds immediately if so), otherwise prints the QR-code
|
||||||
|
steps and waits (up to 10 minutes) for sign-in to complete, then adds
|
||||||
|
whichever of ES-DE.AppImage/RetroArch.AppImage was downloaded as a Steam
|
||||||
|
non-Steam game — re-using \`steam-add-nonsteam-game\` above rather than
|
||||||
|
duplicating its shortcuts.vdf-writing logic. Safe to re-run any time
|
||||||
|
(e.g. if it timed out waiting, or you downloaded the second AppImage
|
||||||
|
later) — already-added shortcuts are updated in place, not duplicated.
|
||||||
|
|
||||||
|
**Returning to Steam from ES-DE, without a second instance:** if ES-DE
|
||||||
|
is running as a Steam non-Steam game (via the AppImage above, not the
|
||||||
|
separate \`esde\` Wolf app), Steam is the parent process the whole
|
||||||
|
time — quitting ES-DE drops you back into the same still-running Steam
|
||||||
|
Big Picture session rather than starting a new one. This only works for
|
||||||
|
the AppImage-in-Steam path; the standalone \`esde\` Wolf app is a
|
||||||
|
completely separate container, and Wolf has no supported way to hand off
|
||||||
|
from one running app to another mid-session (switching apps means
|
||||||
|
closing the Moonlight session and reconnecting to the other one).
|
||||||
|
|
||||||
|
**Multiple devices, same Steam account, same controller mappings?**
|
||||||
|
Worth knowing before relying on it: Wolf gives each *paired client* its
|
||||||
|
own separate Steam container/home directory (confirmed against this
|
||||||
|
repo's own \`_steam_home()\` — it searches across multiple
|
||||||
|
\`.../Steam\` directories, not just one), so a second device connecting
|
||||||
|
to Wolf doesn't reuse the first device's Steam install and has to sign
|
||||||
|
in separately the first time. Once it's signed into the *same* Steam
|
||||||
|
account, Valve's own account-level Steam Cloud config sync should
|
||||||
|
replicate your Steam Input controller bindings across those separate
|
||||||
|
local installs (the same mechanism that syncs bindings between a Steam
|
||||||
|
Deck and a gaming PC) — but that's a Steam-account feature, not
|
||||||
|
something Wolf or this installer controls, and hasn't been confirmed
|
||||||
|
live in this specific setup.
|
||||||
|
|
||||||
## Multiple controllers (same game/emulator can't tell them apart)
|
## Multiple controllers (same game/emulator can't tell them apart)
|
||||||
**Symptom:** two or more controllers connected through the same Moonlight
|
**Symptom:** two or more controllers connected through the same Moonlight
|
||||||
session, but the game/emulator only ever sees one — the first controller
|
session, but the game/emulator only ever sees one — the first controller
|
||||||
|
|||||||
Reference in New Issue
Block a user