The final echo summary still advertised a removed `apps` command and left out
everything added since (cores, backup, controllers, steam-add-nonsteam-game,
steam-setup-frontends, cemu-clone-controller, cemu-sync-controllers,
install-completion, etc.). Also add a short pointer to the Steam-as-4-controller-hub
workflow (documented in depth further down in README.md) right in the install
summary, since it's currently only discoverable by reading the generated README.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V99t5754SyXdnMTpVe2ba5
The steam-setup-frontends command and the ES-DE/RetroArch AppImage
download step had no matching section in the ~/docker/wolf/README.md
content this file generates, unlike every other manage.sh command. Adds
one, alongside the existing Cemu-in-Steam section: why you'd want it,
how the mounts/cores are already shared, and the two honest caveats
(returning to Steam from ES-DE only works via this path, and whether
controller mappings sync across separately-paired Wolf clients is
expected but unconfirmed).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015Z4nqULUEipWNgBsPoSuAb
Steam Guard's QR-code sign-in can't be scripted (needs a phone approving
a prompt), so this polls for it instead: starts Wolf if needed, waits
for Steam's userdata/ to appear (or proceeds immediately if already
signed in), then re-invokes the existing steam-add-nonsteam-game command
for whichever of ES-DE.AppImage/RetroArch.AppImage was downloaded during
install. Points to ./manage.sh cores all for the shared cores/shaders/
overlays directory rather than duplicating that download logic.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015Z4nqULUEipWNgBsPoSuAb
Both projects ship official standalone Linux AppImages separate from
the esde/retroarch Wolf catalog containers this repo already runs.
Adding either one to Steam as a non-Steam game (steam-add-nonsteam-game,
now reaching the same roms/saves/bios/retro-home/retroarch mounts as
the esde/retroarch containers) lets Steam Input assign a 4th controller
its own identity by device path, past Wolf's 3-concrete-pad-type ceiling.
ES-DE is hosted on GitLab rather than GitHub, so this adds a GitLab
Releases API counterpart to the existing GitHub-based download helper.
RetroArch's own buildbot doesn't publish through either API, so this
uses hizzlekizzle/RetroArch-AppImage, the community nightly-build
project the AppImage catalogs themselves point to (flagged as
third-party, same treatment this file already gives the Dolphin
community build). Both downloads are opt-in (default no) and symlink
to a fixed filename so steam-add-nonsteam-game's case-sensitive
substring match finds them regardless of the vendor's own asset name.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015Z4nqULUEipWNgBsPoSuAb
Lets a manually-downloaded ES-DE or RetroArch AppImage, added via
./manage.sh steam-add-nonsteam-game, see the same library, cores, and
ES-DE settings/custom systems (TI-99, Wii U) the esde/retroarch
containers already have, instead of starting from an empty config.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015Z4nqULUEipWNgBsPoSuAb
docker exec needs an explicit -i flag to forward stdin into the
container process; without it, the heredoc piped into `python3 -`
never reached the containerized script, which ran empty and printed
nothing. cemu-sync-controllers then misread that empty output as
"SDL reported zero joysticks" — a false negative with a working set of
4 controllers already confirmed live in ES-DE, not an actual SDL or
GUID problem. Root-caused against the user's own live output: the
exact same probe script, run directly (not via the manage.sh command),
found real device nodes (js0-js4) present in the same container at the
same time cemu-sync-controllers reported zero.
Audited every other docker exec call in this file for the same
stdin-via-heredoc pattern; this was the only one missing -i.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VLX1yYKJExGSXmgUhxKQG6
cemu-clone-controller still needed one manual Cemu GUI step per new
device (click +, select it, map one button, Save) just to learn its
real uuid. This eliminates that too: instead of getting the uuid from
Cemu, it asks SDL directly (SDL_JoystickGetDeviceGUID/GetGUIDString via
ctypes against libSDL2 — the exact library Cemu itself links against)
for the live GUID of every controller connected to the active session,
then clones the proven-working mapping onto each one automatically.
Confirmed live end-to-end on the user's real box: querying SDL this
way inside a running ES-DE session reproduced the exact uuids Cemu had
already written by hand for two different controllers (Nintendo Switch
Pro and Xbox One S) — byte-for-byte identical to their real
controllerProfiles/controllerN.xml. This is what makes trusting SDL as
the uuid source safe, after an earlier attempt to reverse-engineer the
GUID's CRC16 portion by hand (tried 7 different CRC16 variants) failed
to match either device.
Also improved cemu-clone-controller's sibling: the synced profile's
display_name now comes from SDL's own live device name (when the probe
reports one) rather than always inheriting the mapping template's name,
which was a real but purely cosmetic issue caught while re-testing.
Verified end-to-end in an isolated harness against the real captured
controller0.xml/controller1.xml: idempotent skip on already-synced
slots (no needless backups, existing files left byte-identical), a new
slot correctly cloned with the live name and same 24-pair mapping set,
and valid XML output.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VLX1yYKJExGSXmgUhxKQG6
Cemu's own Wolf-facing controller slots (up to 4) still each need a
separate manual bind through Cemu's Input Settings even after
./manage.sh controllers makes them distinct SDL devices — that dialog's
Save button is documented elsewhere in this README as getting cut off
the viewport, making binding all 4 slots by hand painful.
Validated the underlying assumption against two real, separately
hand-mapped profiles pulled live from a working install (Nintendo
Switch Pro on controller0.xml, Xbox One S on controller1.xml): both
contain the exact same 24 <mapping>/<button> pairs, just in a different
order — real proof Cemu's mapping format is device-agnostic and
order-independent, not just the README's prior unverified claim.
New command clones a proven-working <mappings> block onto a new
device's controllerN.xml, needing only that device's own real <uuid>
(which still has to come from Cemu itself — a hand-computed SDL GUID
risks not matching what SDL actually reports for the live device, so
this never guesses one). Getting that uuid only needs a single-button
minimal bind in Cemu's UI, not full mapping, since only the uuid gets
kept from it.
Verified end-to-end against the real captured controller0.xml/
controller1.xml content: cloning controller0's mappings onto
controller1's real uuid reproduces the exact same 24-pair set Cemu
itself wrote, and the output validates as well-formed XML.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VLX1yYKJExGSXmgUhxKQG6
Copyable follow-up for the existing Cubeb/PulseAudio hang note: checks
whether a full Wolf restart has actually happened, whether PulseAudio
inside the Desktop container has any sinks at all, and pulls Cemu's own
log.txt plus its current <Audio> settings.xml block — narrows "stuck on
Disabled" down to a container-level audio problem vs. Cemu's own
device-switch path before guessing at a fix.
Verified the heredoc escaping by rendering the write_readme block through
a real bash heredoc and confirming $WOLF_DIR interpolates while every
other $ stays literal in the output.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VLX1yYKJExGSXmgUhxKQG6
Root-caused against the user's own live output: the settings file had
<string name="ROMDirectory" value="" /> — the key was present, just
empty. The self-healing check only tested whether the string
"ROMDirectory" appeared anywhere in the file, so a key that exists with
a blank value (ES-DE can write this itself if its own first-run "select
ROM directory" step goes unanswered in a headless Moonlight session,
saving an empty path back over GOW's template) looked "already
populated" and got skipped — leaving ROM discovery broken even after
the fix had run.
Now ROMDirectory is independently forced to /ROMs whenever its value is
blank, on top of (not instead of) the existing RunInBackground patch —
no longer gated on the key's mere presence. Verified against the exact
reported bug (ROMDirectory present but blank) plus the existing missing-
file, already-correct, and idempotent-rerun scenarios in isolated /tmp
harnesses before touching the real script.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VLX1yYKJExGSXmgUhxKQG6
Adding an emulator (Cemu, etc.) to Steam as a non-Steam game previously
needed Steam's own Big Picture file-browser flow through Moonlight. This
writes the shortcut directly into Steam's binary shortcuts.vdf instead,
matching this repo's existing no-manual-wizard pattern (ge-proton,
install-ea-app). Motivated by wanting to test whether Steam Input's
per-device controller tracking (distinct device paths, not SDL GUIDs)
can hand Cemu 4 explicitly-assigned controllers where ES-DE/Cemu's own
SDL-based handling can't tell identical controllers apart.
- New generic binary VDF (KeyValues) parser/serializer: round-trips any
existing shortcuts.vdf entries byte-for-byte and only inserts/replaces
the one entry matching the given Exe path, so it's safe against a file
that already has real, hand-configured shortcuts. Verified in isolated
/tmp harnesses: fresh file, idempotent re-add, a second distinct entry,
and preserving a synthetic pre-existing GUI-set entry (icon,
LaunchOptions, tags) untouched.
- Steam's own CATALOG entry had no mount for emulators/ at all (unlike
esde/retroarch) — added emulators:/home/retro/Applications so an
AppImage is actually reachable from inside the Steam container. Like
the ES-DE settings mount, this only takes effect on a freshly created
WolfSteam container (Wolf reuses existing ones) — noted in the README.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VLX1yYKJExGSXmgUhxKQG6
2026-09-03 18:52:31 +00:00
1 changed files with 928 additions and 19 deletions
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.