From c86edee1137371e66bea0c12a4d0c0d277699b87 Mon Sep 17 00:00:00 2001 From: Storm Dragon Date: Sun, 22 Feb 2026 06:30:55 -0500 Subject: [PATCH] Fixed speech-dispatcher library in Play Palace. --- .../references/core-map.md | 3 +- .../references/game-extension.md | 23 ++++--- .install/Play Palace.sh | 60 +++++++++---------- .launch/Play Palace.game | 8 +-- 4 files changed, 46 insertions(+), 48 deletions(-) diff --git a/.codex/skills/linux-game-manager-dev/references/core-map.md b/.codex/skills/linux-game-manager-dev/references/core-map.md index 8daf19b..26cab52 100644 --- a/.codex/skills/linux-game-manager-dev/references/core-map.md +++ b/.codex/skills/linux-game-manager-dev/references/core-map.md @@ -71,6 +71,7 @@ python3 .codex/skills/linux-game-manager-dev/scripts/audit_game_catalog.py - Mismatched `.install/.sh` vs `.launch/.game` names create orphaned or invisible entries. - Missing `installPath` reference in launcher prevents full uninstall. +- `game_removal` parses the first `installPath` match in launcher text, so comments containing `installPath` can break removal path detection. - Missing `run_update()` in `.update` scripts breaks update flow. - Bypassing shared download helpers risks cache and validation regressions. -- For `uv`-based Python games that use `accessible-output2`, include a host copy of `libspeechd.so.2` and export `LD_LIBRARY_PATH` from the launcher to avoid distro packaging differences. +- For `uv`-based Python games that need `speechd`, copy host Python `speechd` bindings into a game-local directory and export `PYTHONPATH` from the launcher. diff --git a/.codex/skills/linux-game-manager-dev/references/game-extension.md b/.codex/skills/linux-game-manager-dev/references/game-extension.md index d2d7edb..29eccbc 100644 --- a/.codex/skills/linux-game-manager-dev/references/game-extension.md +++ b/.codex/skills/linux-game-manager-dev/references/game-extension.md @@ -108,27 +108,24 @@ python3 .codex/skills/linux-game-manager-dev/scripts/audit_game_catalog.py - For edited bash scripts, run shellcheck and fix all errors. - If `shellcheck` is not installed, prompt the user to install it first (see `references/tooling-prereqs.md`). -## Pattern: uv + Speech Dispatcher Host Libraries +## Pattern: uv + Host Python speechd Bindings -Use this pattern for Python games installed with `uv` when runtime speech support depends on system `libspeechd`. +Use this pattern for Python games installed with `uv` when runtime speech support depends on `import speechd`. 1. In installer script: -- Check dependencies: `git` and `uv`. +- Check dependencies: `git`, `uv`, and host python binding import (`python-speechd:speechd`). - Clone game repository into `${installPath}/`. - Run `uv sync` in the project directory that contains `pyproject.toml`. -- Locate `libspeechd.so.2` from host system using: - - `ldconfig -p` when available. - - Fallback paths for common distros: - - `/usr/lib/libspeechd.so.2` (Arch-style) - - `/usr/lib/x86_64-linux-gnu/libspeechd.so.2` (Debian/Ubuntu-style) - - `/usr/lib64/libspeechd.so.2` and related `/lib*` fallbacks -- Copy resolved library into a game-local directory such as: - - `${installPath}///.host-libs/libspeechd.so.2` -- Fail with a clear message if library is not found. +- Resolve speechd source path from host Python via: + - `python3 -c 'import pathlib,speechd; print(pathlib.Path(speechd.__file__).resolve())'` +- Copy the module/package into a game-local directory such as: + - `${installPath}///.host-python/` +- Fail with a clear message if import or copy fails. 2. In launcher script: -- Export `LD_LIBRARY_PATH` with the game-local `.host-libs` directory prepended. +- Export `PYTHONPATH` with the game-local `.host-python` directory prepended. - Launch via `uv run ...` from the same directory used for `uv sync`. 3. Removal safety: - Ensure first `installPath` line in launcher points to a path that lets `game_removal` infer the game root correctly. +- Do not put `installPath` in comments above that path line, because removal currently grabs the first matching line. diff --git a/.install/Play Palace.sh b/.install/Play Palace.sh index cad24f5..b310d0d 100644 --- a/.install/Play Palace.sh +++ b/.install/Play Palace.sh @@ -1,17 +1,11 @@ -check_dependencies git uv +check_dependencies git uv python-speechd:speechd -# shellcheck disable=SC2154 # installPath is exported by linux-game-manager.sh +# shellcheck disable=SC2154 # set by linux-game-manager.sh gameRoot="${installPath}/PlayPalace11" desktopPath="${gameRoot}/clients/desktop" -hostLibDir="${desktopPath}/.host-libs" -speechdLibPath="" -libCandidates=( - "/usr/lib/libspeechd.so.2" - "/usr/lib64/libspeechd.so.2" - "/usr/lib/x86_64-linux-gnu/libspeechd.so.2" - "/lib/x86_64-linux-gnu/libspeechd.so.2" - "/lib64/libspeechd.so.2" -) +hostPythonDir="${desktopPath}/.host-python" +speechdFilePath="" +speechdCopySourcePath="" if [[ -e "${gameRoot}" ]]; then ui_msgbox "Game Installer" "Game Installer" "\"${gameRoot}\" already exists. Remove it first or choose a different game." @@ -40,30 +34,36 @@ if ! uv sync; then fi popd > /dev/null || exit 1 -if command -v ldconfig > /dev/null 2>&1; then - speechdLibPath="$(ldconfig -p 2> /dev/null | awk '/libspeechd\.so\.2/{print $NF; exit}')" -fi - -if [[ -z "${speechdLibPath}" ]]; then - for libPath in "${libCandidates[@]}"; do - if [[ -r "${libPath}" ]]; then - speechdLibPath="${libPath}" - break - fi - done -fi - -if [[ -z "${speechdLibPath}" ]]; then - ui_msgbox "Game Installer" "Game Installer" "Could not find libspeechd.so.2.\nInstall speech-dispatcher (Arch) or a libspeechd package (Debian/Ubuntu) and try again." +speechdFilePath="$(python3 -c 'import pathlib,speechd; print(pathlib.Path(speechd.__file__).resolve())' 2> /dev/null)" +if [[ -z "${speechdFilePath}" ]]; then + ui_msgbox "Game Installer" "Game Installer" "Could not import python module speechd from host Python.\nInstall speech-dispatcher python bindings and try again." exit 1 fi -mkdir -p "${hostLibDir}" || { - ui_msgbox "Game Installer" "Game Installer" "Could not create ${hostLibDir}." +if [[ "${speechdFilePath##*/}" == "__init__.py" ]]; then + speechdCopySourcePath="${speechdFilePath%/*}" +elif [[ "${speechdFilePath##*/}" == "speechd.py" ]]; then + speechdCopySourcePath="${speechdFilePath}" +else + speechdCopySourcePath="${speechdFilePath}" +fi + +if ! [[ -r "${speechdCopySourcePath}" ]]; then + ui_msgbox "Game Installer" "Game Installer" "Could not read speechd python binding at ${speechdCopySourcePath}." + exit 1 +fi + +mkdir -p "${hostPythonDir}" || { + ui_msgbox "Game Installer" "Game Installer" "Could not create ${hostPythonDir}." exit 1 } -if ! cp -Lf "${speechdLibPath}" "${hostLibDir}/libspeechd.so.2"; then - ui_msgbox "Game Installer" "Game Installer" "Could not copy ${speechdLibPath} into ${hostLibDir}." +if [[ -d "${speechdCopySourcePath}" ]]; then + if ! cp -a "${speechdCopySourcePath}" "${hostPythonDir}/"; then + ui_msgbox "Game Installer" "Game Installer" "Could not copy speechd package into ${hostPythonDir}." + exit 1 + fi +elif ! cp -a "${speechdCopySourcePath}" "${hostPythonDir}/speechd.py"; then + ui_msgbox "Game Installer" "Game Installer" "Could not copy speechd module into ${hostPythonDir}." exit 1 fi diff --git a/.launch/Play Palace.game b/.launch/Play Palace.game index aaa0757..43bcee9 100644 --- a/.launch/Play Palace.game +++ b/.launch/Play Palace.game @@ -1,17 +1,17 @@ check_dependencies uv -# shellcheck disable=SC2154 # installPath is exported by linux-game-manager.sh +# shellcheck disable=SC2154 # set by linux-game-manager.sh gamePath="${installPath}/PlayPalace11/clients" desktopPath="${gamePath}/desktop" -hostLibDir="${desktopPath}/.host-libs" +hostPythonDir="${desktopPath}/.host-python" if ! [[ -d "${desktopPath}" ]]; then ui_msgbox "Linux Game Manager" "Linux Game Manager" "Play Palace is not installed at ${desktopPath}." exit 1 fi -if [[ -d "${hostLibDir}" ]]; then - export LD_LIBRARY_PATH="${hostLibDir}${LD_LIBRARY_PATH:+:${LD_LIBRARY_PATH}}" +if [[ -d "${hostPythonDir}" ]]; then + export PYTHONPATH="${hostPythonDir}${PYTHONPATH:+:${PYTHONPATH}}" fi pushd "${desktopPath}" || exit 1