#!/usr/bin/env bash # Run setup in this shell so WINEDLLPATH remains available to the launcher. prepare_prism_speech() { local title="$1" shift local logDir="${XDG_CACHE_HOME:-$HOME/.cache}/audiogame-manager/prism-wine" local logFile details if ! mkdir -p "$logDir" || ! logFile="$(mktemp "${logDir}/setup.XXXXXX.log")"; then agm_msgbox "$title" "$title" "Could not prepare Prism Wine speech support: unable to create a diagnostic log in ${logDir}. Check directory permissions and free disk space." return 1 fi if "$@" > "$logFile" 2>&1; then cat "$logFile" rm -f "$logFile" return 0 fi cat "$logFile" >&2 details="$(tail -n 15 "$logFile")" agm_msgbox "$title" "$title" "Could not prepare Prism Wine speech support. ${details} Full diagnostic log: ${logFile}" return 1 } # Build the host bridge from the same release as the application's Prism DLL. # Wine does not implement RpcMgmtInqIfIds, which Prism uses to detect NVDA. build_prism_speech_bridge() ( local prismVersion="$1" local bridgeDir="$2" local buildRoot sourceRoot tool local -a missingTools=() for tool in curl tar cmake make winegcc wineg++ winebuild pkg-config; do command -v "$tool" >/dev/null || missingTools+=("$tool") done if [[ ${#missingTools[@]} -gt 0 ]]; then echo "Missing Prism Wine speech build tools: ${missingTools[*]}. Install these tools using your distribution's package manager, then launch the game again." >&2 return 1 fi if ! pkg-config --exists speech-dispatcher; then echo "Missing Speech Dispatcher development files (libspeechd). Install your distribution's Speech Dispatcher development package, then launch the game again." >&2 return 1 fi if ! mkdir -p "${bridgeDir%/*}" || ! buildRoot="$(mktemp -d "${bridgeDir%/*}/.build.XXXXXX")"; then echo "Could not create the Prism build directory. Check cache directory permissions and free disk space." >&2 return 1 fi trap 'rm -rf "$buildRoot"' EXIT echo "Preparing Prism ${prismVersion} Wine speech support..." if ! curl -fsSL --retry 3 "https://codeload.github.com/ethindp/prism/tar.gz/refs/tags/v${prismVersion}" -o "${buildRoot}/source.tar.gz"; then echo "Could not download Prism ${prismVersion}. Check your internet connection and whether this Prism release is available, then try again." >&2 return 1 fi if ! tar -xzf "${buildRoot}/source.tar.gz" -C "$buildRoot"; then echo "Could not extract Prism ${prismVersion}. Check free disk space and the archive error above." >&2 return 1 fi sourceRoot="${buildRoot}/prism-${prismVersion}" if ! cmake -S "${sourceRoot}/winelibs" -B "${buildRoot}/build" \ -DCMAKE_TOOLCHAIN_FILE="${sourceRoot}/cmake/winelib-toolchain.cmake" \ -DCMAKE_BUILD_TYPE=Release; then echo "Could not configure Prism ${prismVersion} Wine speech support. See the CMake error above." >&2 return 1 fi if ! cmake --build "${buildRoot}/build" --target \ prism_speech_dispatcher_bridge prism_speech_dispatcher_bridge_placeholder -j2; then echo "Could not compile Prism ${prismVersion} Wine speech support. See the compiler error above." >&2 return 1 fi if ! mkdir -p "$bridgeDir" || ! cp "${buildRoot}/build/speechd/prism_speech_dispatcher_bridge.dll.so" \ "${buildRoot}/build/speechd/placeholder/prism_speech_dispatcher_bridge.dll" \ "$bridgeDir/"; then echo "Could not save the Prism speech bridge to the cache. Check directory permissions and free disk space." >&2 return 1 fi ) prepare_arcadelux_prism_bridge() { local gameDir="$1" local prismVersion local -a metadataFiles=("${gameDir}"/_internal/prismatoid-*.dist-info/METADATA) if [[ ${#metadataFiles[@]} -ne 1 || ! -f "${metadataFiles[0]}" ]]; then echo "Could not identify Arcadelux's bundled Prism version: expected one _internal/prismatoid-*.dist-info/METADATA file. Update or reinstall Arcadelux, then try again." >&2 return 1 fi prismVersion="$(sed -n 's/^Version: //p' "${metadataFiles[0]}" | tr -d '\r')" if [[ ! "$prismVersion" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then echo "Unsupported Prism version: ${prismVersion}" >&2 return 1 fi prepare_prism_bridge "$gameDir" "$prismVersion" "Arcadelux.exe" } # App wrappers identify their bundled Prism release before sharing bridge setup. prepare_prism_bridge() { local gameDir="$1" local prismVersion="$2" local gameExecutable="$3" local bridgeDir if [[ ! "$prismVersion" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then echo "Unsupported Prism version: ${prismVersion}" >&2 return 1 fi if [[ "$(uname -m)" != "x86_64" ]] || ! file -b "${gameDir}/${gameExecutable}" | grep -q 'PE32+'; then echo "Prism Wine speech requires an x86_64 host and 64-bit game." >&2 return 1 fi bridgeDir="${XDG_CACHE_HOME:-$HOME/.cache}/audiogame-manager/prism-wine/${prismVersion}-x86_64" if [[ ! -f "${bridgeDir}/prism_speech_dispatcher_bridge.dll" || ! -f "${bridgeDir}/prism_speech_dispatcher_bridge.dll.so" ]]; then build_prism_speech_bridge "$prismVersion" "$bridgeDir" || return 1 fi # Updates replace the game directory, so restore the placeholder each launch. if ! cp "${bridgeDir}/prism_speech_dispatcher_bridge.dll" "$gameDir/"; then echo "Could not copy the Prism speech bridge into the game directory. Check directory permissions and free disk space." >&2 return 1 fi export WINEDLLPATH="${bridgeDir}${WINEDLLPATH:+:$WINEDLLPATH}" } prepare_tekken3_prism_bridge() { local gameDir="$1" local prismHash # Only this Prism 0.18.3 DLL is supported by the Tekken integration. prismHash="$(sha256sum "${gameDir}/T3Access/prism.dll")" || return 1 if [[ "${prismHash%% *}" != "7c7d09c8c7306e8e1a0c46d603ccb2a391c194c77843400c11b746e7dd56a467" ]]; then echo "Tekken 3 Access has an unrecognized Prism DLL; update its AGM integration before launching." >&2 return 1 fi prepare_prism_bridge "$gameDir" "0.18.3" "Tekken3.exe" }