Merge pull request #439 from outis1one/claude/wolf-pair-port-conflict-7nz8qg
Claude/wolf pair port conflict 7nz8qg
This commit is contained in:
+159
-1
@@ -3554,7 +3554,7 @@ _manage_wolf_complete() {
|
||||
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
|
||||
install-ea-app diagnose-ea fix-perms install-completion backup
|
||||
steam-add-nonsteam-game"
|
||||
steam-add-nonsteam-game cemu-clone-controller"
|
||||
COMPREPLY=( $(compgen -W "$commands" -- "$cur") )
|
||||
}
|
||||
# Register for both 'manage.sh' and './manage.sh' invocation styles
|
||||
@@ -4014,6 +4014,115 @@ VDFPY
|
||||
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."
|
||||
;;
|
||||
cemu-clone-controller)
|
||||
# Clones a WORKING Cemu controller mapping onto a new device slot,
|
||||
# skipping Cemu's own Input Settings dialog entirely for that slot.
|
||||
#
|
||||
# Why this is safe, not just convenient: confirmed against two real,
|
||||
# separately-hand-mapped profiles captured live (Nintendo Switch Pro
|
||||
# on controller0.xml, Xbox One S on controller1.xml) — both contain
|
||||
# the exact same 24 <mapping>/<button> pairs, just listed in a
|
||||
# different order. That's real proof (not the README's word for
|
||||
# it) that Cemu's <mappings> block uses universal
|
||||
# SDL_CONTROLLER_BUTTON_* semantics, not per-device raw indices, and
|
||||
# that Cemu doesn't care about entry order — so a proven-working
|
||||
# block can be dropped into a new device's file wholesale.
|
||||
#
|
||||
# This still needs ONE real, Cemu-written <uuid> per new device
|
||||
# type first — that value isn't something this script can compute
|
||||
# (it depends on the CRC16-of-device-name half of the SDL GUID,
|
||||
# which SDL derives from the exact joystick name string the device
|
||||
# reports at runtime — guessing it risks writing a uuid Cemu will
|
||||
# never actually match against the live device). Get it the
|
||||
# cheapest possible way: in Cemu's Input Settings for the new
|
||||
# controller slot, click + and select the device — even mapping
|
||||
# ONE button and hitting Save is enough, since only the <uuid> and
|
||||
# <display_name> this writes are kept; the whole <mappings> block
|
||||
# gets replaced by this command anyway.
|
||||
if [ -z "${3:-}" ]; then
|
||||
echo "Usage: ./manage.sh cemu-clone-controller <target-slot 0-3> <uuid> [display name]"
|
||||
echo ""
|
||||
echo " <target-slot> Which controllerN.xml to write (0-indexed, same as"
|
||||
echo " Cemu's own file naming and Wolf's own controller"
|
||||
echo " numbering — controller0.xml is Cemu's Controller 1)."
|
||||
echo " <uuid> The REAL uuid Cemu wrote for the new device — get this"
|
||||
echo " by adding it in Cemu's Input Settings once (map just one"
|
||||
echo " button, Save), then:"
|
||||
echo " cat controllerProfiles/controllerN.xml | grep uuid"
|
||||
echo " [display name] Cosmetic only. Defaults to the source profile's own name."
|
||||
exit 1
|
||||
fi
|
||||
_CCC_SLOT="${2:-}"
|
||||
_CCC_UUID="${3:-}"
|
||||
_CCC_NAME="${4:-}"
|
||||
|
||||
case "$_CCC_SLOT" in
|
||||
0|1|2|3) ;;
|
||||
*) echo "Target slot must be 0, 1, 2, or 3 (Cemu's own Controller 1-4, 0-indexed)."; exit 1 ;;
|
||||
esac
|
||||
case "$_CCC_UUID" in
|
||||
0_????????????????????????????????) ;;
|
||||
*) echo "That doesn't look like a real Cemu uuid (expected '0_' + 32 hex chars)."
|
||||
echo "Got: $_CCC_UUID"
|
||||
exit 1 ;;
|
||||
esac
|
||||
|
||||
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
|
||||
if [ -z "$GAME_DIR" ]; then echo "No game storage path."; exit 1; fi
|
||||
_CCC_DIR="$GAME_DIR/retro-home/Cemu/controllerProfiles"
|
||||
if [ ! -d "$_CCC_DIR" ]; then
|
||||
echo "No controllerProfiles/ yet at $_CCC_DIR — set up at least one controller"
|
||||
echo "in Cemu's own Input Settings first (Controller 1), so there's a real,"
|
||||
echo "working profile to clone the mapping from."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Pick any existing, non-empty controllerN.xml as the mapping source —
|
||||
# prefer controller0.xml (Cemu's own Controller 1), since that's the
|
||||
# slot people set up first, but fall back to whichever one actually
|
||||
# exists so this isn't hard-wired to slot 0 specifically.
|
||||
_CCC_SRC=""
|
||||
for _n in 0 1 2 3; do
|
||||
_cand="$_CCC_DIR/controller${_n}.xml"
|
||||
if [ -s "$_cand" ] && [ "$_n" != "$_CCC_SLOT" ]; then
|
||||
_CCC_SRC="$_cand"
|
||||
break
|
||||
fi
|
||||
done
|
||||
if [ -z "$_CCC_SRC" ]; then
|
||||
echo "No other working controllerN.xml found in $_CCC_DIR to clone from."
|
||||
echo "Set up at least one controller fully in Cemu's own Input Settings first."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
_CCC_TARGET="$_CCC_DIR/controller${_CCC_SLOT}.xml"
|
||||
[ -f "$_CCC_TARGET" ] && cp "$_CCC_TARGET" "$_CCC_TARGET.bak.$(date +%s)"
|
||||
|
||||
if [ -z "$_CCC_NAME" ]; then
|
||||
_CCC_NAME=$(grep -o '<display_name>[^<]*</display_name>' "$_CCC_SRC" | head -1 | sed -E 's#</?display_name>##g')
|
||||
fi
|
||||
|
||||
python3 - "$_CCC_SRC" "$_CCC_TARGET" "$_CCC_UUID" "$_CCC_NAME" << 'CLONEPY'
|
||||
import re, sys
|
||||
src_path, out_path, uuid, display_name = sys.argv[1:5]
|
||||
with open(src_path) as f:
|
||||
template = f.read()
|
||||
new = re.sub(r'<uuid>[^<]*</uuid>', f'<uuid>{uuid}</uuid>', template, count=1)
|
||||
new = re.sub(r'<display_name>[^<]*</display_name>', f'<display_name>{display_name}</display_name>', new, count=1)
|
||||
with open(out_path, 'w') as f:
|
||||
f.write(new)
|
||||
print(f"Wrote {out_path}")
|
||||
print(f" uuid: {uuid}")
|
||||
print(f" display_name: {display_name}")
|
||||
CLONEPY
|
||||
chown 1000:1000 "$_CCC_TARGET"
|
||||
|
||||
echo ""
|
||||
echo "Cloned the mapping from $(basename "$_CCC_SRC") onto controller${_CCC_SLOT}.xml."
|
||||
echo "Close Cemu COMPLETELY and relaunch for this to take effect — a hand-edited"
|
||||
echo "profile file isn't picked up by an already-running Cemu."
|
||||
;;
|
||||
pin)
|
||||
# Wolf logs: "Insert pin at http://SOMEIP:47989/pin/#HEXHASH"
|
||||
# Extract just the hash fragment and build URLs for every interface
|
||||
@@ -4068,6 +4177,8 @@ VDFPY
|
||||
echo " ./manage.sh install-completion - Enable tab-completion for this script"
|
||||
echo " ./manage.sh steam-add-nonsteam-game [name] [display name]"
|
||||
echo " - Add an emulator (emulators/) as a non-Steam game, no GUI needed"
|
||||
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 " ./manage.sh backup - How to set up backups"
|
||||
;;
|
||||
esac
|
||||
@@ -4628,6 +4739,7 @@ cd $WOLF_DIR
|
||||
./manage.sh diagnose-ea # check link2ea:// state when game returns to Play
|
||||
./manage.sh install-completion # enable tab-completion for manage.sh
|
||||
./manage.sh steam-add-nonsteam-game # add an emulator as a non-Steam game, no GUI needed
|
||||
./manage.sh cemu-clone-controller # clone a working Cemu controller mapping onto a new device slot
|
||||
\`\`\`
|
||||
|
||||
### Tab completion
|
||||
@@ -5065,6 +5177,33 @@ time Cemu launches from ES-DE too.
|
||||
repo, not just reconnecting) reliably cleared it in testing, giving a
|
||||
fresh PulseAudio session to work with. Reconnect to a fresh Desktop
|
||||
session afterward and try again.
|
||||
|
||||
**If the TV device stays stuck on "Disabled" and won't take a real
|
||||
device at all** (not just a one-time hang), this narrows down whether
|
||||
it's PulseAudio itself with nothing to offer inside the container, or
|
||||
Cemu choking on a device it can actually see:
|
||||
\`\`\`bash
|
||||
# Has this been a full Wolf restart, not just a reconnect, since it broke?
|
||||
sudo ./setup.sh wolf
|
||||
|
||||
# Does PulseAudio inside the Desktop container see any output devices at all?
|
||||
CONTAINER=\$(docker ps --format '{{.Names}}' | grep -i WolfDesktop | head -1)
|
||||
docker exec "\$CONTAINER" pactl list short sinks
|
||||
docker exec "\$CONTAINER" pactl info | grep -i "default sink"
|
||||
|
||||
# Cemu's own log — it logs audio device init/errors directly
|
||||
GAME_DIR=\$(grep '^GAME_STORAGE_DIR=' $WOLF_DIR/.env | cut -d= -f2-)
|
||||
find "\$GAME_DIR/retro-home/Cemu" -iname "log.txt" -exec cat {} \\;
|
||||
|
||||
# What settings.xml currently has for Audio (even while stuck "disabled")
|
||||
cat "\$GAME_DIR/retro-home/Cemu/settings.xml" 2>/dev/null | grep -A5 -i "<Audio"
|
||||
\`\`\`
|
||||
An empty \`pactl list short sinks\` means there's no real fix on Cemu's
|
||||
side to chase — the container itself has no audio sink for anything to
|
||||
attach to. A populated sink list with Cemu still stuck points at Cemu's
|
||||
own device-switch path instead, and \`log.txt\` / the \`<Audio>\` block
|
||||
above are what to paste back for that to get root-caused rather than
|
||||
guessed at.
|
||||
6. **Adding a second controller and the first one ends up driving both
|
||||
characters?** That's not a Cemu-specific bug — see
|
||||
"Multiple controllers" above (\`./manage.sh controllers\`).
|
||||
@@ -5107,6 +5246,25 @@ ambiguity about which one Cemu picks. Back up the file first
|
||||
\`sudo\` needed, these files are written world-writable by Cemu itself.
|
||||
Close Cemu completely and relaunch for a hand-edited profile to take effect.
|
||||
|
||||
**\`./manage.sh cemu-clone-controller\` does this copy for you.** Once
|
||||
you've got 4 distinct controller *types* set up via \`./manage.sh controllers\`
|
||||
(so Cemu can tell the devices apart at all) and one slot fully mapped by
|
||||
hand, adding the rest doesn't need full manual button-mapping — Cemu's own
|
||||
\`<mappings>\` format is universal SDL_CONTROLLER_BUTTON_* semantics, not
|
||||
per-device raw indices, so the same mapping works for every device. All
|
||||
each new slot needs is its own real \`<uuid>\` — get that the cheap way (in
|
||||
Cemu's Input Settings, click **+** on the new controller, select the
|
||||
device, map ONE button, Save; the mapping itself is thrown away), then:
|
||||
\`\`\`bash
|
||||
cd $WOLF_DIR
|
||||
grep uuid "\$(grep '^GAME_STORAGE_DIR=' .env | cut -d= -f2-)/retro-home/Cemu/controllerProfiles/controller2.xml"
|
||||
./manage.sh cemu-clone-controller 2 0_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
\`\`\`
|
||||
Clones a fully-configured slot's mapping onto slot 2 with that device's own
|
||||
uuid — no per-button rebinding, no fighting the cut-off Save button for
|
||||
every single controller. Backs up any existing \`controllerN.xml\` first,
|
||||
and needs Cemu closed and relaunched afterward like any other hand-edit.
|
||||
|
||||
ROMs are mounted at \`/ROMs\` inside Desktop too, so Cemu's own File → Load
|
||||
can browse straight to \`/ROMs/wiiu/\` without needing ES-DE at all.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user