# GOG-only Wine/Whisky — без Steam, HoMM, export_wine_env_steam. GOG_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" GAMES_DIR="$(cd "${GOG_DIR}/.." && pwd)" GAMES_CACHE_DIR="${GAMES_DIR}/cache" _env_file="${GOG_DIR}/bottle.env" if [[ -f "${_env_file}" ]]; then # shellcheck source=/dev/null source "${_env_file}" elif [[ -n "${GOG_BOTTLE_ID:-}" ]]; then BOTTLE_ID="${GOG_BOTTLE_ID}" BOTTLE_NAME="${GOG_BOTTLE_NAME:-GOG-Install}" else echo "❌ Нет bottle для GOG." echo " 1) Whisky → New Bottle (Windows 10 64-bit), имя GOG-Install" echo " 2) bash ${GOG_DIR}/list-bottles.sh" echo " 3) bash ${GOG_DIR}/use-bottle.sh " echo "" echo " Не используйте bottle HoMM-OldenEra — там Steam, дампы и winedbg." exit 1 fi unset _env_file _FRANKE="${HOME}/Library/Containers/com.franke.Whisky/Bottles/${BOTTLE_ID}" _ISAAC="${HOME}/Library/Containers/com.isaacmarovitz.Whisky/Bottles/${BOTTLE_ID}" if [[ -d "${_FRANKE}/drive_c" ]]; then BOTTLE_DIR="${_FRANKE}" WHISKY_LIBS="${HOME}/Library/Application Support/com.franke.Whisky" elif [[ -d "${_ISAAC}/drive_c" ]]; then BOTTLE_DIR="${_ISAAC}" WHISKY_LIBS="${HOME}/Library/Application Support/com.isaacmarovitz.Whisky" else echo "❌ Bottle не найден: ${BOTTLE_NAME} (${BOTTLE_ID})" echo " Проверьте UUID: bash ${GOG_DIR}/list-bottles.sh" exit 1 fi unset _FRANKE _ISAAC WINE64="${WHISKY_LIBS}/Libraries/Wine/bin/wine64" WINE_LIB="${WHISKY_LIBS}/Libraries/Wine/lib" WINEPATH_BIN="${WHISKY_LIBS}/Libraries/Wine/bin/winepath" gog_data_volume_path() { if [[ -d /System/Volumes/Data ]]; then echo /System/Volumes/Data else echo "${HOME}" fi } gog_disk_free_kb() { df -k "$(gog_data_volume_path)" | awk 'NR==2 {print $4}' } gog_disk_guard() { local min_gb="${1:-5}" local min_kb free_kb min_kb=$((min_gb * 1024 * 1024)) free_kb="$(gog_disk_free_kb)" if [[ "${free_kb}" -lt "${min_kb}" ]]; then echo "❌ Мало места (<${min_gb} GB на Data)." return 1 fi return 0 } gog_swap_used_mb() { local used used="$(sysctl vm.swapusage 2>/dev/null | sed -n 's/.*used = \([0-9.]*\)M.*/\1/p')" [[ -n "${used}" ]] || return 1 printf '%.0f' "${used}" } gog_swap_guard() { local max_mb="${1:-400}" local used used="$(gog_swap_used_mb)" || return 0 if awk -v u="${used}" -v m="${max_mb}" 'BEGIN{exit !(u>=m)}'; then echo "❌ Swap уже ~${used}MB (лимит ${max_mb}MB) — запуск GOG/Wine запрещён." echo " bash ${GOG_DIR}/emergency-stop.sh" echo " затем перезагрузка Mac (swap macOS отдаёт медленно)" return 1 fi return 0 } # JA3/Whisky: жёсткий стоп только если swap высокий И Wine/JA3 ещё живы. # «Залипший» swap после закрытия (macOS не отдал) — предупреждение, запуск разрешён. gog_wine_or_ja3_active() { pgrep -f 'JA3\.exe' >/dev/null 2>&1 } gog_swap_guard_ja3_launch() { local soft_mb="${1:-1200}" local hard_mb="${2:-4096}" local used used="$(gog_swap_used_mb)" || return 0 if [[ "${JA3_IGNORE_SWAP:-0}" == "1" ]]; then echo "⚠️ JA3_IGNORE_SWAP=1 — swap ~${used}MB" return 0 fi if gog_wine_or_ja3_active; then if awk -v u="${used}" -v m="${soft_mb}" 'BEGIN{exit !(u>=m)}'; then echo "❌ Swap ~${used}MB и Wine/JA3 ещё работают (лимит ${soft_mb}MB)." echo " bash ${GOG_DIR}/reset-ja3-whisky.sh" echo " затем reboot Mac. Или: JA3_IGNORE_SWAP=1 bash ${GOG_DIR}/run-ja3.sh" return 1 fi return 0 fi if awk -v u="${used}" -v m="${hard_mb}" 'BEGIN{exit !(u>=m)}'; then echo "❌ Swap ~${used}MB (лимит ${hard_mb}MB) — reboot Mac." echo " Или: JA3_IGNORE_SWAP=1 bash ${GOG_DIR}/run-ja3.sh" return 1 fi if awk -v u="${used}" -v m="${soft_mb}" 'BEGIN{exit !(u>=m)}'; then echo "⚠️ Swap ~${used}MB — залип после прошлых сессий (Wine не запущен). Запуск JA3…" echo " (reboot снизит swap; JA3_IGNORE_SWAP=1 — принудительный игнор)" fi return 0 } # Виртуальный стол Wine — окно CEF часто «есть в логах», но не видно на macOS без /desktop. GOG_VDESKTOP="${GOG_VDESKTOP:-1280x800}" # 0 = прямой GalaxyClient (рекомендуется; vdesktop — в Whisky Metadata или launch-galaxy-ui.sh). GOG_USE_WINEVDESKTOP="${GOG_USE_WINEVDESKTOP:-0}" # GOG_LAUNCH_FG=1 — exec в текущем терминале (лучше для видимости окна, блокирует shell). GOG_LAUNCH_FG="${GOG_LAUNCH_FG:-0}" # GOG_CEF_PROFILE=steam — добавить -cef-in-process-gpu (A/B если login пустой). # /deelevated — обязательно в Wine (иначе DeelevateStrategy + exit -31, см. WineHQ #41584). GOG_GALAXY_BASE_ARGS="${GOG_GALAXY_BASE_ARGS:-/runWithoutUpdating /deelevated}" GOG_GALAXY_CEF_ARGS="${GOG_GALAXY_CEF_ARGS:--allosarches -cef-force-32bit -no-cef-sandbox -cef-disable-gpu}" gog_galaxy_cef_args_array() { local -a a=(${GOG_GALAXY_BASE_ARGS} ${GOG_GALAXY_CEF_ARGS}) if [[ "${GOG_CEF_PROFILE:-}" == "steam" ]]; then a+=(-cef-in-process-gpu) fi printf '%s\n' "${a[@]}" } export_wine_env_gog() { export WINEPREFIX="${BOTTLE_DIR}" export WINEMSYNC=1 unset WINEESYNC 2>/dev/null || true local _wine_ext="${WHISKY_LIBS}/Libraries/Wine/lib/external" if [[ -d "${_wine_ext}/D3DMetal.framework" ]]; then export DYLD_FRAMEWORK_PATH="${_wine_ext}:${DYLD_FRAMEWORK_PATH:-}" export DYLD_LIBRARY_PATH="${_wine_ext}:${WINE_LIB}:${DYLD_LIBRARY_PATH:-}" else export DYLD_LIBRARY_PATH="${WINE_LIB}:${DYLD_LIBRARY_PATH:-}" fi unset _wine_ext export WINEDLLOVERRIDES="gdiplus=n,b" unset DXVK_ASYNC DXVK_HUD 2>/dev/null || true export WINEDEBUG=-all export MVK_CONFIG_LOG_LEVEL=0 } ja3_gptk_available() { [[ -d "${WHISKY_LIBS}/Libraries/Wine/lib/external/D3DMetal.framework" ]] && return 0 [[ -f "${WHISKY_LIBS}/Libraries/.gptk_installed" ]] && return 0 [[ -d "${WHISKY_LIBS}/D3DMetal" ]] && return 0 [[ -d "${WHISKY_LIBS}/GPTK" ]] && return 0 return 1 } ja3_bottle_uses_d3dmetal() { local meta="${BOTTLE_DIR}/Metadata.plist" [[ -f "${meta}" ]] || return 1 plutil -extract graphicsConfig.backend raw -o - "${meta}" 2>/dev/null | grep -q d3dMetal } ja3_dxmt_installed() { [[ -f "${BOTTLE_DIR}/.ja3_dxmt_installed" ]] } # JA3 = D3D12 (Porting Kit / GPTK). Без GPTK — best-effort D3D11+DXVK (d3d12=d). export_wine_env_ja3() { export_wine_env_gog if ja3_gptk_available || ja3_bottle_uses_d3dmetal; then export WINED3DMETAL=1 unset DXVK_ASYNC DXVK_HUD DXVK_CONFIG_FILE 2>/dev/null || true # builtin d3d12/dxgi + libd3dshared.so; без n,b на GPTK PE export WINEDLLOVERRIDES="libxess,xess,dxcompiler,dxil,nvngx_dlss,XeFX,XeFX_Loader=d;gdiplus=n,b" return 0 fi if ja3_dxmt_installed; then # DXMT builtin: не ставить dxgi/d3d11=n,b (ломает загрузку, c000007b). export WINEDLLOVERRIDES="d3d12=d;libxess,xess,dxcompiler,dxil,nvngx_dlss,XeFX,XeFX_Loader=d;gdiplus=n,b" else export WINEDLLOVERRIDES="d3d11,d3d10core=n,b;d3d12=d;libxess,xess,dxcompiler,dxil,nvngx_dlss,XeFX,XeFX_Loader=d;gdiplus=n,b" fi unset DXVK_ASYNC DXVK_HUD DXVK_CONFIG_FILE 2>/dev/null || true export SDL_VIDEO_MAC_FULLSCREEN_SPACES="${SDL_VIDEO_MAC_FULLSCREEN_SPACES:-0}" export MVK_CONFIG_RESUME_LOST_DEVICE=1 } export_wine_env_ja3_d3dmetal() { export_wine_env_gog export WINED3DMETAL=1 export WINEDLLOVERRIDES="libxess,xess,dxcompiler,dxil,nvngx_dlss,XeFX,XeFX_Loader=d;gdiplus=n,b" unset DXVK_ASYNC DXVK_HUD 2>/dev/null || true } # Whisky GOG-Install: D3D11 + DXVK-macOS (D3D12 через GPTK/D3DMetal при наличии). export_wine_env_ja3_whisky() { export_wine_env_gog unset WINED3DMETAL 2>/dev/null || true export WINEDLLOVERRIDES="d3d11,d3d10core,dxgi=n,b;d3d12=d;libxess,xess,dxcompiler,dxil,nvngx_dlss,XeFX,XeFX_Loader=d;gdiplus=n,b" local _dxvk_conf="${BOTTLE_DIR}/drive_c/GOG Games/Jagged Alliance 3/dxvk.conf" if [[ -f "${_dxvk_conf}" ]]; then export DXVK_CONFIG_FILE="${_dxvk_conf}" fi unset DXVK_ASYNC DXVK_HUD 2>/dev/null || true export SDL_VIDEO_MAC_FULLSCREEN_SPACES="${SDL_VIDEO_MAC_FULLSCREEN_SPACES:-0}" export MVK_CONFIG_RESUME_LOST_DEVICE=1 } gog_steam_client_in_bottle() { local f [[ -d "${BOTTLE_DIR}/drive_c/Program Files (x86)/Steam" ]] && return 0 [[ -f "${BOTTLE_DIR}/drive_c/Program Files (x86)/Steam/steam.exe" ]] && return 0 f="$(find "${BOTTLE_DIR}/drive_c" -maxdepth 4 -iname 'steam.exe' -print -quit 2>/dev/null || true)" [[ -n "${f}" ]] } gog_assert_no_steam_client() { if gog_steam_client_in_bottle; then echo "❌ В bottle ${BOTTLE_NAME} найден Steam client — контур GOG/JA3 без Steam." echo " bash ${GOG_DIR}/purge-steam-from-bottle.sh" return 1 fi if [[ "${BOTTLE_ID}" == "38412122-AAE1-4831-9F2E-6A0EB364B3F9" ]]; then echo "❌ Это bottle HoMM-OldenEra (Steam). JA3 только в GOG-Install:" echo " bash ${GOG_DIR}/use-bottle.sh " return 1 fi return 0 } gog_wine_check() { if [[ ! -x "${WINE64}" ]]; then echo "Нет Wine: bash ${GAMES_DIR}/install-whiskywine-manual.sh" exit 1 fi if [[ ! -d "${BOTTLE_DIR}/drive_c" ]]; then echo "❌ Нет drive_c в ${BOTTLE_DIR}" echo " Откройте bottle «${BOTTLE_NAME}» в Whisky один раз." exit 1 fi }