#!/usr/bin/env bash # Универсальный запуск .exe в Whisky-bottle. См. docs/games/WINE_APPS_LAUNCH_RUNBOOK.md set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" # shellcheck source=config.sh source "${SCRIPT_DIR}/config.sh" BOTTLE_NAME="${WINE_BOTTLE_NAME:-}" BOTTLE_ID="${WINE_BOTTLE_ID:-}" GOG_BOTTLE_MODE="${GOG_BOTTLE:-0}" PROFILE="plain" BACKGROUND=0 LOG="" EXE_ARG="" usage() { cat <<'EOF' Использование: run-wine-exe.sh [опции] Опции: --bottle NAME Имя bottle в Whisky (напр. HoMM-OldenEra) --bottle-id UUID UUID bottle (приоритет над --bottle) --gog-bottle Bottle из scripts/games/gog/bottle.env --profile PROF plain | steam | gog | game | ja3 (по умолчанию plain) --background nohup, не ждать --log FILE лог при --background -h, --help Примеры: run-wine-exe.sh --profile steam 'C:\Program Files (x86)\Steam\Steam.exe' run-wine-exe.sh --gog-bottle --profile gog ~/Downloads/setup.exe run-wine-exe.sh --bottle HoMM-OldenEra --profile game 'C:\...\game.exe' Документация: docs/games/WINE_APPS_LAUNCH_RUNBOOK.md EOF } resolve_bottle_dir() { if [[ "${GOG_BOTTLE_MODE}" != "1" && -z "${BOTTLE_ID}" && -z "${BOTTLE_NAME}" ]]; then # config.sh: HoMM-OldenEra по умолчанию return 0 fi if [[ "${GOG_BOTTLE_MODE}" == "1" ]]; then local gog_cfg="${SCRIPT_DIR}/gog/bottle.env" if [[ ! -f "${gog_cfg}" ]]; then echo "❌ Нет gog/bottle.env — bash ${SCRIPT_DIR}/gog/use-bottle.sh " exit 1 fi # shellcheck source=/dev/null source "${gog_cfg}" BOTTLE_ID="${BOTTLE_ID:?}" BOTTLE_NAME="${BOTTLE_NAME:-GOG-Install}" fi if [[ -n "${BOTTLE_ID}" ]]; then local _f="${HOME}/Library/Containers/com.franke.Whisky/Bottles/${BOTTLE_ID}" local _i="${HOME}/Library/Containers/com.isaacmarovitz.Whisky/Bottles/${BOTTLE_ID}" if [[ -d "${_f}/drive_c" ]]; then BOTTLE_DIR="${_f}" WHISKY_LIBS="${HOME}/Library/Application Support/com.franke.Whisky" elif [[ -d "${_i}/drive_c" ]]; then BOTTLE_DIR="${_i}" WHISKY_LIBS="${HOME}/Library/Application Support/com.isaacmarovitz.Whisky" else echo "❌ Bottle не найден: ${BOTTLE_ID}" exit 1 fi return 0 fi if [[ -n "${BOTTLE_NAME}" ]]; then local d for d in "${HOME}/Library/Containers/com.franke.Whisky/Bottles"/* \ "${HOME}/Library/Containers/com.isaacmarovitz.Whisky/Bottles"/*; do [[ -d "${d}/drive_c" ]] || continue if [[ "$(basename "${d}")" == "${BOTTLE_NAME}" ]] || \ grep -q "BOTTLE_NAME=${BOTTLE_NAME}" "${d}/Metadata.plist" 2>/dev/null; then BOTTLE_DIR="${d}" if [[ "${d}" == *com.franke* ]]; then WHISKY_LIBS="${HOME}/Library/Application Support/com.franke.Whisky" else WHISKY_LIBS="${HOME}/Library/Application Support/com.isaacmarovitz.Whisky" fi return 0 fi done echo "❌ Bottle по имени не найден: ${BOTTLE_NAME}" exit 1 fi # default: HoMM from config.sh (already sourced) } to_win_path() { local arg="$1" if [[ "${arg}" =~ ^[A-Za-z]:\\ ]]; then echo "${arg}" return 0 fi if [[ ! -f "${arg}" ]]; then echo "❌ Нет файла: ${arg}" >&2 exit 1 fi local base dest base="$(basename "${arg}")" dest="${BOTTLE_DIR}/drive_c/${base}" cp -f "${arg}" "${dest}" echo "C:\\${base}" } apply_profile() { case "${PROFILE}" in plain) export WINEPREFIX="${BOTTLE_DIR}" export WINEMSYNC=1 WINEESYNC=1 export DYLD_LIBRARY_PATH="${WINE_LIB}:${DYLD_LIBRARY_PATH:-}" unset WINEDLLOVERRIDES 2>/dev/null || true ;; steam) export_wine_env_steam ;; gog) if [[ -f "${SCRIPT_DIR}/gog/config.sh" ]]; then # shellcheck source=/dev/null source "${SCRIPT_DIR}/gog/config.sh" export_wine_env_gog else export_wine_env_steam export WINEDLLOVERRIDES="gdiplus=n,b" fi ;; game) export_wine_env_game ;; ja3) if [[ -f "${SCRIPT_DIR}/gog/config.sh" ]]; then # shellcheck source=/dev/null source "${SCRIPT_DIR}/gog/config.sh" export_wine_env_ja3 else export_wine_env_game fi ;; *) echo "❌ Неизвестный профиль: ${PROFILE}" exit 1 ;; esac export WINEDEBUG="${WINEDEBUG:--all}" } while [[ $# -gt 0 ]]; do case "$1" in --bottle) BOTTLE_NAME="$2"; shift 2 ;; --bottle-id) BOTTLE_ID="$2"; shift 2 ;; --gog-bottle) GOG_BOTTLE_MODE=1; shift ;; --profile) PROFILE="$2"; shift 2 ;; --background) BACKGROUND=1; shift ;; --log) LOG="$2"; shift 2 ;; -h|--help) usage; exit 0 ;; -*) echo "Неизвестная опция: $1"; usage; exit 1 ;; *) EXE_ARG="$1"; shift ;; esac done [[ -n "${EXE_ARG}" ]] || { usage; exit 1; } resolve_bottle_dir WINE64="${WHISKY_LIBS}/Libraries/Wine/bin/wine64" WINE_LIB="${WHISKY_LIBS}/Libraries/Wine/lib" [[ -x "${WINE64}" ]] || { echo "❌ Нет Wine: install-whiskywine-manual.sh"; exit 1; } [[ -d "${BOTTLE_DIR}/drive_c" ]] || { echo "❌ Нет drive_c в ${BOTTLE_DIR}"; exit 1; } WIN_EXE="$(to_win_path "${EXE_ARG}")" apply_profile echo "Bottle: ${BOTTLE_DIR##*/}" echo "Профиль: ${PROFILE}" echo "Запуск: ${WIN_EXE}" if [[ "${BACKGROUND}" -eq 1 ]]; then LOG="${LOG:-/tmp/wine-exe-$(basename "${BOTTLE_DIR}").log}" : >"${LOG}" nohup "${WINE64}" "${WIN_EXE}" >>"${LOG}" 2>&1 & echo "Фон (PID $!), лог: ${LOG}" exit 0 fi exec "${WINE64}" "${WIN_EXE}"