Files

135 lines
6.1 KiB
Bash

#!/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"
}