Add UMU Proton backend for Shadow Line
This commit is contained in:
@@ -1,3 +1,5 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
declare -a errorList
|
||||
declare -a packageList
|
||||
if [[ $# -eq 0 ]]; then
|
||||
@@ -10,6 +12,12 @@ else
|
||||
errorList+=("Critical: Wine is not installed. You will not be able to play any games.")
|
||||
fi
|
||||
packageList+=("wine")
|
||||
if command -v umu-run &> /dev/null ; then
|
||||
[[ $# -eq 0 ]] && echo "umu-launcher is installed."
|
||||
else
|
||||
errorList+=("Warning: umu-launcher is not installed. Games that require Proton/UMU will not install or launch.")
|
||||
fi
|
||||
packageList+=("umu-launcher")
|
||||
if command -v curl &> /dev/null ; then
|
||||
[[ $# -eq 0 ]] && echo "Curl is installed."
|
||||
else
|
||||
|
||||
+28
-2
@@ -1,3 +1,6 @@
|
||||
#!/usr/bin/env bash
|
||||
# shellcheck disable=SC2154 # Sourced by audiogame-manager with shared globals.
|
||||
|
||||
documentation() {
|
||||
if [[ "$2" == "Become a Patron" ]]; then
|
||||
return
|
||||
@@ -8,13 +11,36 @@ documentation() {
|
||||
|
||||
# Extract architecture from first parameter (format: "win64|path")
|
||||
local wineArch="${1%%|*}"
|
||||
get_bottle "$wineArch"
|
||||
if [[ "$wineArch" == "umu" ]]; then
|
||||
local launcherLine=""
|
||||
local docFlag=""
|
||||
local umuGameId=""
|
||||
local -a documentationGame=()
|
||||
launcherLine="$(grep -F -m1 "${1}|" "$configFile" 2> /dev/null || true)"
|
||||
IFS='|' read -ra documentationGame <<< "$launcherLine"
|
||||
for docFlag in "${documentationGame[@]:3}" ; do
|
||||
if [[ "$docFlag" =~ ^export\ [a-zA-Z_][a-zA-Z0-9_]*=\'?.*\'?$ ]]; then
|
||||
eval "$docFlag"
|
||||
fi
|
||||
done
|
||||
if [[ -z "$umuGameId" ]]; then
|
||||
echo "Unable to find UMU game id for documentation lookup."
|
||||
return
|
||||
fi
|
||||
get_umu_bottle "$umuGameId"
|
||||
else
|
||||
get_bottle "$wineArch"
|
||||
fi
|
||||
|
||||
echo "Loading documentation, please wait..."
|
||||
|
||||
# Try to find documentation based on common naming conventions.
|
||||
local gamePath
|
||||
gamePath="$(winepath -u "$2" 2> /dev/null)"
|
||||
if [[ "$wineArch" == "umu" ]]; then
|
||||
gamePath="$(umu_windows_path_to_unix "$2")"
|
||||
else
|
||||
gamePath="$(winepath -u "$2" 2> /dev/null)"
|
||||
fi
|
||||
gamePath="${gamePath%/*}"
|
||||
local gameDoc=""
|
||||
local isUrl="false"
|
||||
|
||||
@@ -0,0 +1,112 @@
|
||||
#!/usr/bin/env bash
|
||||
# shellcheck disable=SC2034,SC2154 # Sourced by audiogame-manager and installers with shared globals.
|
||||
|
||||
require_umu() {
|
||||
if command -v umu-run &> /dev/null; then
|
||||
return 0
|
||||
fi
|
||||
local message="This game requires umu-launcher. Please install umu-launcher and try again."
|
||||
if declare -F agm_msgbox &> /dev/null; then
|
||||
agm_msgbox "Audio Game Manager" "Audio Game Manager" "$message"
|
||||
else
|
||||
echo "$message" >&2
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
|
||||
get_umu_bottle() {
|
||||
local gameId="$1"
|
||||
if [[ -z "$gameId" ]]; then
|
||||
echo "get_umu_bottle requires a game id." >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
export umuGameId="$gameId"
|
||||
export WINEPREFIX="${XDG_DATA_HOME:-$HOME/.local/share}/audiogame-manager/protonBottles/${gameId}"
|
||||
export GAMEID="$gameId"
|
||||
export STORE="${umuStore:-none}"
|
||||
export DISPLAY="${DISPLAY:-:0}"
|
||||
mkdir -p "$WINEPREFIX"
|
||||
}
|
||||
|
||||
install_proton_bottle() {
|
||||
local gameId="$1"
|
||||
shift || true
|
||||
require_umu || return 1
|
||||
get_umu_bottle "$gameId" || return 1
|
||||
|
||||
if [[ ! -f "${WINEPREFIX}/system.reg" ]]; then
|
||||
umu-run ""
|
||||
fi
|
||||
|
||||
if [[ $# -gt 0 ]]; then
|
||||
umu-run winetricks "$@"
|
||||
fi
|
||||
}
|
||||
|
||||
umu_windows_path_to_unix() {
|
||||
local windowsPath="$1"
|
||||
local relativePath=""
|
||||
if [[ "$windowsPath" =~ ^[cC]:\\ ]]; then
|
||||
relativePath="${windowsPath:3}"
|
||||
relativePath="${relativePath//\\//}"
|
||||
printf '%s/drive_c/%s\n' "$WINEPREFIX" "$relativePath"
|
||||
return 0
|
||||
fi
|
||||
winepath -u "$windowsPath"
|
||||
}
|
||||
|
||||
run_umu_game() {
|
||||
local windowsPath="$1"
|
||||
local exePath=""
|
||||
require_umu || return 1
|
||||
if [[ -z "${umuGameId:-}" ]]; then
|
||||
echo "UMU game id is not set for ${game[2]:-selected game}." >&2
|
||||
return 1
|
||||
fi
|
||||
get_umu_bottle "$umuGameId" || return 1
|
||||
exePath="$(umu_windows_path_to_unix "$windowsPath")"
|
||||
if [[ ! -f "$exePath" ]]; then
|
||||
echo "UMU executable not found: $exePath" >&2
|
||||
return 1
|
||||
fi
|
||||
pushd "${exePath%/*}" > /dev/null || return 1
|
||||
umu-run "$exePath"
|
||||
popd > /dev/null || return 1
|
||||
}
|
||||
|
||||
add_umu_launcher() {
|
||||
local gameId="$1"
|
||||
local windowsPath="$2"
|
||||
shift 2
|
||||
local launchSettings="umu|${windowsPath}|${game}|export umuGameId=${gameId}"
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
launchSettings+="|$1"
|
||||
shift
|
||||
done
|
||||
|
||||
if ! grep -F -q -x "$launchSettings" "$configFile" 2> /dev/null; then
|
||||
echo "$launchSettings" >> "$configFile"
|
||||
sort -t '|' -k3,3f -o "$configFile" "$configFile"
|
||||
fi
|
||||
}
|
||||
|
||||
set_umu_reg_value() {
|
||||
local key="$1"
|
||||
local valueName="$2"
|
||||
local valueData="$3"
|
||||
wine reg add "$key" /v "$valueName" /t REG_SZ /d "$valueData" /f
|
||||
}
|
||||
|
||||
set_umu_app_winver() {
|
||||
local exeName="$1"
|
||||
local winVersion="$2"
|
||||
set_umu_reg_value "HKCU\\Software\\Wine\\AppDefaults\\${exeName}" "Version" "$winVersion"
|
||||
}
|
||||
|
||||
stop_umu_bottle() {
|
||||
if command -v wineserver &> /dev/null; then
|
||||
wineserver -k 2> /dev/null || true
|
||||
fi
|
||||
}
|
||||
+35
-20
@@ -1,23 +1,38 @@
|
||||
# shellcheck shell=bash disable=SC2154 # cache and WINEPREFIX are set by audiogame-manager
|
||||
#//Disable since it's not working
|
||||
download "https://www.mm-galabo.com/sr/Download_files_srfv/shadowrine_fullvoice3.171.exe" "https://raw.githubusercontent.com/LordLuceus/sr-english-localization/master/language_en.dat"
|
||||
export WINEARCH="win64" # Migrated to wine64 with WINETRICKS_FORCE=1
|
||||
export winVer="win8"
|
||||
install_wine_bottle fakejapanese
|
||||
# Add bcrypt DLL override required for Shadow Line to run
|
||||
cat > /tmp/bcrypt_override.reg << 'EOF'
|
||||
[HKEY_CURRENT_USER\Software\Wine\DllOverrides]
|
||||
"bcryptprimitives"="native,builtin"
|
||||
EOF
|
||||
wine regedit /tmp/bcrypt_override.reg
|
||||
rm /tmp/bcrypt_override.reg
|
||||
# shellcheck shell=bash disable=SC2154 # cache, game, and helper functions are set by audiogame-manager.
|
||||
|
||||
export game="Shadow Line"
|
||||
shadowLineGameId="shadow-line"
|
||||
shadowLinePath='c:\Program Files (x86)\GalaxyLaboratory\ShadowRine_FullVoice\play_sr.exe'
|
||||
|
||||
download "https://www.mm-galabo.com/sr/Download_files_srfv/shadowrine_fullvoice3.171.exe" \
|
||||
"https://raw.githubusercontent.com/LordLuceus/sr-english-localization/master/language_en.dat" \
|
||||
"${nvdaControllerClient32Dll}" \
|
||||
"${nvdaControllerClient64Dll}"
|
||||
|
||||
install_proton_bottle "$shadowLineGameId" fakejapanese
|
||||
shadowLineInstallDir="${WINEPREFIX}/drive_c/Program Files (x86)/GalaxyLaboratory/ShadowRine_FullVoice"
|
||||
|
||||
set_umu_reg_value "HKCU\\Software\\Wine\\DllOverrides" "bcryptprimitives" "native,builtin"
|
||||
set_umu_app_winver "play_sr.exe" "win8"
|
||||
|
||||
{
|
||||
echo "# Installing Shadow Line..."
|
||||
timeout 300 wine "${cache}/shadowrine_fullvoice3.171.exe" /sp- /VERYSILENT /SUPPRESSMSGBOXES 2>&1 || true
|
||||
timeout 300 umu-run "${cache}/shadowrine_fullvoice3.171.exe" /sp- /VERYSILENT /SUPPRESSMSGBOXES 2>&1 || true
|
||||
echo "# Installation complete"
|
||||
} | agm_progressbox "Installing Game" "Installing Shadow Line (this may take a few minutes)..."
|
||||
# Kill any auto-launched game processes (installer lacks skipifsilent flag)
|
||||
wineserver -k 2>/dev/null || true
|
||||
mv -v "${cache}/language_en.dat" "${WINEPREFIX}/drive_c/Program Files (x86)/GalaxyLaboratory/ShadowRine_FullVoice/SystemData/language_en.dat"
|
||||
add_launcher "c:\Program Files (x86)\GalaxyLaboratory\ShadowRine_FullVoice\play_sr.exe"
|
||||
alert "Please set the language to English when the game opens.\nGo to options and press enter.\nPress down arrow 5 times and press enter.\nPress down arrow 1 time and press enter.\nPress up arrow 2 times and press enter.\nIf everything worked as expected you should be back on the game menu and speech should work."
|
||||
} | agm_progressbox "Installing Game" "Installing Shadow Line with UMU/Proton (this may take a few minutes)..."
|
||||
|
||||
stop_umu_bottle
|
||||
|
||||
if [[ ! -f "${shadowLineInstallDir}/play_sr.exe" ]]; then
|
||||
agm_msgbox "Shadow Line" "Shadow Line" "Shadow Line did not install to the expected location: ${shadowLineInstallDir}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
install -m 0644 "${cache}/language_en.dat" "${shadowLineInstallDir}/SystemData/language_en.dat"
|
||||
|
||||
find "$shadowLineInstallDir" -type f -iname 'nvdaControllerClient32.dll' -exec cp -v "${cache}/nvdaControllerClient32.dll" "{}" \;
|
||||
find "$shadowLineInstallDir" -type f -iname 'nvdaControllerClient64.dll' -exec cp -v "${cache}/nvdaControllerClient64.dll" "{}" \;
|
||||
find "$shadowLineInstallDir" -type f -iname 'nvdaControllerClient.dll' -exec cp -v "${cache}/nvdaControllerClient32.dll" "{}" \;
|
||||
|
||||
add_umu_launcher "$shadowLineGameId" "$shadowLinePath"
|
||||
alert "Shadow Line" "Shadow Line" "Please set the language to English when the game opens.\nGo to options and press enter.\nPress down arrow 5 times and press enter.\nPress down arrow 1 time and press enter.\nPress up arrow 2 times and press enter.\nIf everything worked as expected you should be back on the game menu and speech should work."
|
||||
|
||||
+42
-14
@@ -469,23 +469,36 @@ game_removal() {
|
||||
# With shared bottles, always remove only the game files, never the entire bottle
|
||||
create_game_array "$selectedGame"
|
||||
if [[ ${#game[@]} -gt 0 ]]; then
|
||||
# Set up wine environment for this game
|
||||
# shellcheck source=.includes/bottle.sh
|
||||
source "${scriptDir}/.includes/bottle.sh"
|
||||
get_bottle "${game[0]}"
|
||||
process_launcher_flags
|
||||
if [[ "${game[0]}" == "umu" ]]; then
|
||||
get_umu_bottle "$umuGameId"
|
||||
else
|
||||
# Set up wine environment for this game
|
||||
# shellcheck source=.includes/bottle.sh
|
||||
source "${scriptDir}/.includes/bottle.sh"
|
||||
get_bottle "${game[0]}"
|
||||
fi
|
||||
|
||||
if ! agm_yesno "Confirm Removal" "Audio Game Removal" "Are you sure you want to remove \"${game[2]}\"?"; then
|
||||
agm_msgbox "Audio Game Removal" "" "Removal cancelled."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# kill any previous existing wineservers for this prefix in case they didn't shut down properly.
|
||||
wineserver -k
|
||||
# kill any previous existing servers for this prefix in case they didn't shut down properly.
|
||||
if [[ "${game[0]}" == "umu" ]]; then
|
||||
stop_umu_bottle
|
||||
else
|
||||
wineserver -k
|
||||
fi
|
||||
|
||||
# Remove only the game's installation directory
|
||||
if [[ -n "$winePath" ]]; then
|
||||
local gameDir
|
||||
gameDir="$(winepath "$winePath")"
|
||||
if [[ "${game[0]}" == "umu" ]]; then
|
||||
gameDir="$(umu_windows_path_to_unix "$winePath")"
|
||||
else
|
||||
gameDir="$(winepath "$winePath")"
|
||||
fi
|
||||
if [[ -d "$gameDir" ]]; then
|
||||
rm -rfv "$gameDir" | agm_progressbox "Removing Game" "Removing \"${game[2]}\" files..."
|
||||
else
|
||||
@@ -534,9 +547,16 @@ kill_game() {
|
||||
local wineExec="${game#*|}"
|
||||
wineExec="${wineExec%|*}"
|
||||
wineExec="${wineExec##*\\}"
|
||||
# kill the wine server.
|
||||
get_bottle "${game%|*}"
|
||||
wineserver -k
|
||||
create_game_array "$game"
|
||||
if [[ "${game[0]}" == "umu" ]]; then
|
||||
process_launcher_flags
|
||||
get_umu_bottle "$umuGameId"
|
||||
stop_umu_bottle
|
||||
else
|
||||
# kill the wine server.
|
||||
get_bottle "${game[0]}"
|
||||
wineserver -k
|
||||
fi
|
||||
agm_msgbox "Audio Game Killer" "" "The selected game has been stopped."
|
||||
fi
|
||||
exit 0
|
||||
@@ -790,14 +810,21 @@ game_launcher() {
|
||||
open_url "https://2mb.games/product/2mb-patron/"
|
||||
exit 0
|
||||
fi
|
||||
# Set default path/exec for custom launch handlers.
|
||||
winePath="${game[1]%\\*.exe}"
|
||||
wineExec="${game[1]##*\\}"
|
||||
process_launcher_flags
|
||||
if [[ "${game[0]}" == "umu" ]]; then
|
||||
echo "launching with umu"
|
||||
start_nvda2speechd
|
||||
run_umu_game "${game[1]}"
|
||||
exit 0
|
||||
fi
|
||||
get_bottle "${game[0]}"
|
||||
echo -n "launching "
|
||||
wine --version
|
||||
# kill any previous existing wineservers for this prefix in case they didn't shut down properly.
|
||||
wineserver -k
|
||||
# Set default path/exec for custom launch handlers.
|
||||
winePath="${game[1]%\\*.exe}"
|
||||
wineExec="${game[1]##*\\}"
|
||||
# launch the game
|
||||
if command -v qjoypad &> /dev/null ; then
|
||||
mkdir -p ~/.qjoypad3
|
||||
@@ -812,7 +839,6 @@ game_launcher() {
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
process_launcher_flags
|
||||
apply_executioners_rage_focus_workaround
|
||||
customLaunchHandled="false"
|
||||
custom_launch_parameters
|
||||
@@ -901,6 +927,8 @@ export ipfsGateway="${ipfsGateway:-https://ipfs.stormux.org}"
|
||||
# Source helper functions
|
||||
# shellcheck source=.includes/bottle.sh
|
||||
source "${scriptDir}/.includes/bottle.sh" # Also sourced in functions that need it
|
||||
# shellcheck source=.includes/proton.sh
|
||||
source "${scriptDir}/.includes/proton.sh"
|
||||
# shellcheck source=.includes/desktop.sh
|
||||
source "${scriptDir}/.includes/desktop.sh"
|
||||
# dialog-interface.sh already sourced earlier
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
repoRoot="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
testRoot="$(mktemp -d)"
|
||||
trap 'rm -rf "$testRoot"' EXIT
|
||||
|
||||
export HOME="${testRoot}/home"
|
||||
export XDG_DATA_HOME="${HOME}/.local/share"
|
||||
export XDG_CONFIG_HOME="${HOME}/.config"
|
||||
export XDG_CACHE_HOME="${HOME}/.cache"
|
||||
export DISPLAY=""
|
||||
export cache="${XDG_CACHE_HOME}/audiogame-manager"
|
||||
export configFile="${XDG_CONFIG_HOME}/storm-games/audiogame-manager/games.conf"
|
||||
export game="Shadow Line"
|
||||
export scriptDir="$repoRoot"
|
||||
mkdir -p "$cache" "${configFile%/*}" "${testRoot}/bin"
|
||||
touch "$configFile"
|
||||
|
||||
cat > "${testRoot}/bin/umu-run" <<'STUB'
|
||||
#!/usr/bin/env bash
|
||||
printf '%s|%s|%s|%s\n' "$WINEPREFIX" "$GAMEID" "${STORE:-}" "$*" >> "$UMU_STUB_LOG"
|
||||
if [[ "${1:-}" == "" ]]; then
|
||||
mkdir -p "$WINEPREFIX/drive_c"
|
||||
fi
|
||||
STUB
|
||||
chmod +x "${testRoot}/bin/umu-run"
|
||||
|
||||
cat > "${testRoot}/bin/wine" <<'STUB'
|
||||
#!/usr/bin/env bash
|
||||
if [[ "${1:-}" == "winepath" || "${1:-}" == "winepath.exe" ]]; then
|
||||
shift
|
||||
fi
|
||||
if [[ "${1:-}" == "-u" ]]; then
|
||||
input="$2"
|
||||
path="${input#c:\\}"
|
||||
path="${path//\\//}"
|
||||
printf '%s/drive_c/%s\n' "$WINEPREFIX" "$path"
|
||||
exit 0
|
||||
fi
|
||||
printf 'wine %s\n' "$*" >> "$WINE_STUB_LOG"
|
||||
STUB
|
||||
chmod +x "${testRoot}/bin/wine"
|
||||
|
||||
cat > "${testRoot}/bin/wineserver" <<'STUB'
|
||||
#!/usr/bin/env bash
|
||||
printf 'wineserver %s\n' "$*" >> "$WINE_STUB_LOG"
|
||||
STUB
|
||||
chmod +x "${testRoot}/bin/wineserver"
|
||||
|
||||
export PATH="${testRoot}/bin:$PATH"
|
||||
export UMU_STUB_LOG="${testRoot}/umu.log"
|
||||
export WINE_STUB_LOG="${testRoot}/wine.log"
|
||||
|
||||
# shellcheck source=.includes/proton.sh
|
||||
source "${repoRoot}/.includes/proton.sh"
|
||||
|
||||
assert_equals() {
|
||||
local expected="$1"
|
||||
local actual="$2"
|
||||
local message="$3"
|
||||
if [[ "$expected" != "$actual" ]]; then
|
||||
printf 'FAIL: %s\nexpected: %s\nactual: %s\n' "$message" "$expected" "$actual" >&2
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
assert_file_contains() {
|
||||
local file="$1"
|
||||
local pattern="$2"
|
||||
local message="$3"
|
||||
if ! grep -Fq "$pattern" "$file"; then
|
||||
printf 'FAIL: %s\nmissing pattern: %s\nfile contents:\n' "$message" "$pattern" >&2
|
||||
cat "$file" >&2
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
test_get_umu_bottle_sets_environment() {
|
||||
get_umu_bottle "shadow-line"
|
||||
assert_equals "${XDG_DATA_HOME}/audiogame-manager/protonBottles/shadow-line" "$WINEPREFIX" "WINEPREFIX points at AGM proton bottle"
|
||||
assert_equals "shadow-line" "$GAMEID" "GAMEID is exported"
|
||||
assert_equals "none" "$STORE" "STORE defaults to none"
|
||||
assert_equals ":0" "$DISPLAY" "DISPLAY defaults to :0"
|
||||
}
|
||||
|
||||
test_add_umu_launcher_records_backend_and_game_id() {
|
||||
get_umu_bottle "shadow-line"
|
||||
add_umu_launcher "shadow-line" 'c:\Program Files (x86)\GalaxyLaboratory\ShadowRine_FullVoice\play_sr.exe'
|
||||
assert_file_contains "$configFile" 'umu|c:\Program Files (x86)\GalaxyLaboratory\ShadowRine_FullVoice\play_sr.exe|Shadow Line|export umuGameId=shadow-line' "UMU launcher entry is recorded"
|
||||
}
|
||||
|
||||
test_run_umu_game_uses_converted_path() {
|
||||
get_umu_bottle "shadow-line"
|
||||
mkdir -p "${WINEPREFIX}/drive_c/Program Files (x86)/GalaxyLaboratory/ShadowRine_FullVoice"
|
||||
touch "${WINEPREFIX}/drive_c/Program Files (x86)/GalaxyLaboratory/ShadowRine_FullVoice/play_sr.exe"
|
||||
run_umu_game 'c:\Program Files (x86)\GalaxyLaboratory\ShadowRine_FullVoice\play_sr.exe'
|
||||
assert_file_contains "$UMU_STUB_LOG" "${WINEPREFIX}|shadow-line|none|${WINEPREFIX}/drive_c/Program Files (x86)/GalaxyLaboratory/ShadowRine_FullVoice/play_sr.exe" "UMU launches converted exe path"
|
||||
}
|
||||
|
||||
test_get_umu_bottle_sets_environment
|
||||
test_add_umu_launcher_records_backend_and_game_id
|
||||
test_run_umu_game_uses_converted_path
|
||||
printf 'UMU backend tests passed\n'
|
||||
Reference in New Issue
Block a user