commit 570f9247c2791cc3b82fe5839724a89f57d42b5d Author: Scan Date: Wed Aug 28 23:39:19 2024 -0400 Initial re-upload diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..22fbd46 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/monitor_by_id +*.pyc diff --git a/0005731108.py b/0005731108.py new file mode 100644 index 0000000..c07fc34 --- /dev/null +++ b/0005731108.py @@ -0,0 +1,66 @@ +""" Game fix for IIDX (UID:0005731108) +""" +# Protonfix for games supporting Windows 8 prefix +# This protonfix expects prefix shared between multiple titles +# Explicitely set overrides for all dlls fetched here even when not using them +# pylint: disable=C0103 + +import os +from protonfixes import util + + +def main(): + # Generic environment (may be overwritten by subpatch) + util.protontricks("win8") + util.protontricks("sound=alsa") + + # Apply optional patches (without bloating protonfixes) + patches = (os.getenv("PROTON_STYLE_PATCH") or "").strip(":") + try: + for patch in patches.split(":") if len(patches) else []: + globals()[f"iidx_{patch}"]() + except KeyError as err: + print(f"gamefix: no patch available for {err}") + +def iidx_30(): + # probably qpro etc., shader compilation fails for D3DXAssembleShader() - crash with missing callback Direct3DShaderValidatorCreate() + util.protontricks("d3dcompiler_43") + util.protontricks("d3dx9_43") + # this exact override needed for subscreen to be created + util.set_environment("WINEDLLOVERRIDES", "d3dcompiler_43=n,b") + + +def iidx_29(): + # probably qpro etc., shader compilation fails for D3DXAssembleShader() - crash with missing callback Direct3DShaderValidatorCreate() + util.protontricks("d3dcompiler_43") + util.protontricks("d3dx9_43") + # this exact override needed for subscreen to be created + util.set_environment("WINEDLLOVERRIDES", "d3dcompiler_43=n,b") + +def iidx_28(): + # probably qpro etc., shader compilation fails for D3DXAssembleShader() - crash with missing callback Direct3DShaderValidatorCreate() + util.protontricks("d3dcompiler_43") + util.protontricks("d3dx9_43") + # this exact override needed for subscreen to be created + util.set_environment("WINEDLLOVERRIDES", "d3dcompiler_43=n,b") + + +def iidx_27(): + # crash at 0x180176996, shader compilation fails for D3DXAssembleShader() - crash with missing callback Direct3DShaderValidatorCreate() + util.protontricks("d3dcompiler_43") + util.protontricks("d3dx9_43") + # this exact override needed for subscreen to be created + util.set_environment("WINEDLLOVERRIDES", "d3dcompiler_43=n,b") + +def iidx_26(): + # explicit to keep constant behaviour with other games (iidx27) + util.set_environment("WINEDLLOVERRIDES", "d3dcompiler_43,d3dx9_43=b,n") + +def iidx_25(): + # explicit to keep constant behaviour with other games (iidx27) + util.set_environment("WINEDLLOVERRIDES", "d3dcompiler_43,d3dx9_43=b,n") + +def tests(): + # Most dlls that may or may not be required + util.set_environment("WINEDLLOVERRIDES", "quartz,devenum,dmime,dmsynth,dmloader,dmusic,dsound,dsdmo,msdmo,bmsound-wine,d3dx9_41,d3dx9d_41,d3dx9_43,d3dcompiler_43=n,b") + pass diff --git a/README.md b/README.md new file mode 100644 index 0000000..41efdfe --- /dev/null +++ b/README.md @@ -0,0 +1,10 @@ +# Preface + +This repo may seem erratic with no documentation whatsoever. +This is because resources listed here are part of a bigger private repository. + +You don't have to use anything from this repo to get games running as these are just there to make process feel more seamless. + +That being said part of a guide listed at pages may be harder to follow without any system integration whatsoever, therefore this repository exists, providing the minimal wrappers setup that should work with guide provided. + +If it doesn't, create a new issue here, as some wrappers here may be outdated. diff --git a/array_format_to_hex.py b/array_format_to_hex.py new file mode 100755 index 0000000..2dbd14e --- /dev/null +++ b/array_format_to_hex.py @@ -0,0 +1,20 @@ +#!/usr/bin/env python3 +# Transform array visually to display 16 elements per line +import sys +import pyperclip + +if len(sys.argv) < 2: + exit(1) +stin = pyperclip.paste() if sys.argv[1] == "clip" else sys.argv[1] + +asarr = [x.strip() for x in stin.strip().split(",")] + +output = "" +for i in range(0, len(asarr), 16): + output += ", ".join(map(str, asarr[i : i + 16])) + ",\n" +output = output.rstrip("\n").rstrip(",") + +if sys.argv[1] == "clip": + stin = pyperclip.copy(output) +else: + print(output) diff --git a/bytepatch_intern_to_mon.py b/bytepatch_intern_to_mon.py new file mode 100755 index 0000000..b2429e7 --- /dev/null +++ b/bytepatch_intern_to_mon.py @@ -0,0 +1,21 @@ +#!/usr/bin/env python3 +# Translates internal documentation patch notations into js format expected by BemaniPatcher +import sys +import pyperclip + +if len(sys.argv) < 2: + exit(1) +stin = pyperclip.paste() if sys.argv[1] == "clip" else sys.argv[1] + + +[*rest, addr, on] = stin.split(":") +[off, on, *rest] = on.split("->") +off = ", ".join([f"0x{x}" for x in off.strip().split(" ")]) +on = ", ".join([f"0x{x}" for x in on.strip().split(" ")]) +addr = addr.strip() + +output = f"{{ offset: {addr}, off: [{off}], on: [{on}] }}," +if sys.argv[1] == "clip": + stin = pyperclip.copy(output) +else: + print(output) diff --git a/ep_bm2dxnix b/ep_bm2dxnix new file mode 100755 index 0000000..0352c4d --- /dev/null +++ b/ep_bm2dxnix @@ -0,0 +1,361 @@ +#!/bin/bash +# Dump directory expects dir structure like this Beatmania IIDX 26/contents;Beatmania IIDX 26/devel; + +## Constant ## +_C_scriptDir="$(dirname -- "$(realpath -- "$0")")" +_C_scriptName="$(basename -- "$(realpath -- "$0")")" +# These constants are config overridable, but it is not recommended to do so (ex. hooks may not work) +_C_dll_override="bm2dx.dll" +_C_lightning_model="--iidxtdj" +_C_rtname="proton-ge-8.16" +_C_pfxname="u573_bm2dx_w8" +# Audio native ASIO -iidxsounddevice is 27+ only +_C_audio_asio1=(-iidxasio ASIO4ALL -iidxsounddevice asio) +_C_audio_asio2=(-iidxasio FlexASIO -iidxsounddevice asio) +_C_audio_asio3=(-iidxasio WineASIO -iidxsounddevice asio) +# Audio native(dsound,24-)/wasapi(25+) +_C_audio_native=(-audiohookdisable) +_C_audio_wasapi=(-iidxsounddevice wasapi) +# Audio spice dummy routing (25+ only, uses wasapi exclusive internally, which gets routed to specific audiobackend) +_C_audio_dummy_asio=(-iidxsounddevice wasapi -audiodummy -audiobackend asio -asiodriverid 0) +_C_audio_dummy_waveout=(-iidxsounddevice wasapi -audiodummy -audiobackend waveout) +_C_audio_dummy_none=(-iidxsounddevice wasapi -audiodummy -audiobackend none) +_C_audio_dummy_pipewire=(-iidxsounddevice wasapi -audiodummy -audiobackend pipewire) +# Network spice builtin endpoint +_C_net_dummy_maint=(-eamaint 1 -ea) +_C_net_dummy_local=(-ea) + +## Core ## +_G_root="$_C_scriptDir/../.steam/root" +_G_ep=("$_C_scriptDir/ep_protonnix") +_G_exec="" +_G_args=() +_G_style="" +_G_dumps="" +_G_debug=0 + +## Game config ## +_G_video="stable" +_G_display=0 +_G_refresh_rate=0 +_G_fsr=-1 +_G_url="" +_G_pcbid="" +_G_hooks=() +_G_devel=() + + +print_help() { + cat </dev/null || echo {})" + + # Video + _G_video="$(jq -cr ".video.profile // \"$_G_video\"" <<<"$cfgjson")" + _G_display="$(jq -cr ".video.display // \"$_G_display\"" <<<"$cfgjson")" + _G_refresh_rate="$(jq -cr ".video.refresh_rate // \"$_G_refresh_rate\"" <<<"$cfgjson")" + _G_fsr="$(jq -cr ".video.fsr // \"$_G_fsr\"" <<<"$cfgjson")" + + # Network + _G_url="$(jq -cr ".network.url // \"$_G_url\"" <<<"$cfgjson")" + _G_pcbid="$(jq -cr ".network.pcbid // \"$_G_pcbid\"" <<<"$cfgjson")" + + # Extra + while read -r entry; do _G_hooks+=("$entry"); done < <(jq -cr '.extra.hooks // [] | .[]' <<<"$cfgjson") + while read -r entry; do _G_devel+=("$entry"); done < <(jq -cr '.extra.devel // [] | .[]' <<<"$cfgjson") + [ "$(jq -cr ".extra.lightning_support" <<<"$cfgjson")" == "false" ] && _C_lightning_model="" + _C_game_module="$(jq -cr ".extra.dll_override // \"$_C_game_module\"" <<<"$cfgjson")" + _C_rtname="$(jq -cr ".extra.rt_override // \"$_C_rtname\"" <<<"$cfgjson")" + _C_pfxname="$(jq -cr ".extra.pfx_override // \"$_C_pfxname\"" <<<"$cfgjson")" +} + +monitor_by_id() { + if [ ! $(command -v ./monitor_by_id) ]; then + gcc "$_C_scriptDir/monitor_by_id.c" -o "$_C_scriptDir/monitor_by_id" -lX11 -lXrandr || return + fi + "$_C_scriptDir/monitor_by_id" $1 +} + +args_iidx22() { + # dummy audio unsupported, fullscreen working fine + _G_args+=("${_C_audio_native[@]}") + [ "$_G_video" != "stable" ] || _G_args+=(-graphics-force-single-adapter) + [ "$_G_url" != "dummy" ] || _G_args+=("${_C_net_dummy_local[@]}") +} + +args_iidx30() { + # pipewire supported, fullscreen partially? working subscreen + _G_args+=("${_C_audio_dummy_pipewire[@]}" "${_C_lightning_model[@]}" -nolegacy -touchemuforce) + [ "$_G_video" != "stable" ] || _G_args+=(-graphics-force-single-adapter) + [ "$_G_url" != "dummy" ] || _G_args+=("${_C_net_dummy_maint[@]}") +} + +args_iidx29() { + # pipewire supported, fullscreen working subscreen + _G_args+=("${_C_audio_dummy_pipewire[@]}" "${_C_lightning_model[@]}" -nolegacy -touchemuforce) + [ "$_G_video" != "stable" ] || _G_args+=(-graphics-force-single-adapter) + [ "$_G_url" != "dummy" ] || _G_args+=("${_C_net_dummy_maint[@]}") +} + +args_iidx28() { + if ((_G_debug & 8)); then + # Workaround for audio initializing for ALSA driver (not recommended) + #export PULSE_LATENCY_MSEC=10 + export PIPEWIRE_LATENCY=411/44100 + export FIX_RATE=44100 + export FIX_CHANNELS="[ FL FR ]" + export FIX_FORMAT="S16LE" + rate=$(pw-metadata -n settings 0 clock.rate) + rate="${rate#*value:\'}" + rate="${rate%%\'*}" + pw-metadata -n settings 0 clock.force-rate 44100 + #pw-metadata -n settings 0 clock.force-quantum 441 + nohup bash -c "sleep 30; pw-metadata -n settings 0 clock.force-rate $rate; sleep 1; pw-metadata -n settings 0 clock.force-rate --delete;" >/dev/null 2>&1 & + # Results in desync prone audio with alsa, static with pulse + _G_args+=("${_C_audio_wasapi[@]}" "${_C_audio_native[@]}" "${_C_lightning_model[@]}") + else + # pipewire supported, fullscreen working subscreen + _G_args+=("${_C_audio_dummy_pipewire[@]}" "${_C_lightning_model[@]}" -nolegacy -touchemuforce) + [ "$_G_video" != "stable" ] || _G_args+=(-graphics-force-single-adapter) + [ "$_G_url" != "dummy" ] || _G_args+=("${_C_net_dummy_maint[@]}") + fi + +} + +args_iidx27() { + # pipewire supported, fullscreen working subscreen + _G_args+=("${_C_audio_dummy_pipewire[@]}" "${_C_lightning_model[@]}" -nolegacy -touchemuforce) + [ "$_G_video" != "stable" ] || _G_args+=(-graphics-force-single-adapter) + [ "$_G_url" != "dummy" ] || _G_args+=("${_C_net_dummy_maint[@]}") +} + +args_iidx26() { + # pipewire supported, fullscreen breaks on window unfocus + _G_args+=("${_C_audio_dummy_pipewire[@]}") + [ "$_G_video" != "stable" ] || _G_args+=(-w) + [ "$_G_url" != "dummy" ] || _G_args+=("${_C_net_dummy_maint[@]}") +} + +args_iidx25() { + # pipewire supported, fullscreen breaks on window unfocus + _G_args+=("${_C_audio_dummy_pipewire[@]}") + [ "$_G_video" != "stable" ] || _G_args+=(-w) + [ "$_G_url" != "dummy" ] || _G_args+=("${_C_net_dummy_local[@]}") +} + +gen_args() { + # Skip for override (--) mode + [ "${#_G_args[@]}" -eq 0 ] || { + _G_ep+=(--args "${_G_args[*]}") + return 0 + } + + # Basic + _G_args+=(-io -iidx -modules modules "$_C_dll_override") + + # Style + if [[ $(type -t "args_iidx${_G_style}") == function ]]; then + "args_iidx${_G_style}" + else + _G_args+=("${_C_net_dummy[@]}" "${_C_audio_native[@]}") + fi + + # Video + _G_args+=(-monitor $_G_display) + [ "$_G_refresh_rate" -gt 0 ] && _G_args+=(-graphics-force-refresh $_G_refresh_rate) + if [ "$_G_video" = "force_window" ]; then + _G_args+=(-w) + elif [ "$_G_video" = "force_fullscreen" ]; then + _G_args+=(-graphics-force-single-adapter) + fi + + # Network + [ -n "$_G_url" ] && [ "$_G_url" != "dummy" ] && _G_args+=(-url "$_G_url") + [ -n "$_G_pcbid" ] && _G_args+=(-p "$_G_pcbid") + + # Hooks + for hook in "${_G_hooks[@]}"; do _G_args+=(-k "$hook"); done + + # Devel + ((_G_debug & 1)) && _G_args+=(${_G_devel[@]}) + if ((_G_debug & 2)); then + # _REV: could write line directly into db/*.cmdline instead + echo "[INFO] x64dbg session argument recommendation: '${_G_args[*]} -w'" + else + _G_ep+=(--args "${_G_args[*]}") + fi + +} + +gen_base() { + # Core setup + styledir="$_G_dumps/Beatmania IIDX ${_G_style}" + patchid="0005731108" + if [ "$_G_style" -lt "25" ]; then + arch=32 + else + arch=64 + fi + + # Proton setup + [ -n "$LD_LIBRARY_PATH" ] && LD_LIBRARY_PATH="${LD_LIBRARY_PATH}:" + [ -n "$WINEDLLPATH" ] && LD_LIBRARY_PATH="${WINEDLLPATH}:" + LD_LIBRARY_PATH="${LD_LIBRARY_PATH}${styledir}/contents/modules" + WINEDLLPATH="${WINEDLLPATH}${styledir}/contents/modules" + export WINEDLLPATH + export LD_LIBRARY_PATH + if ((_G_debug & 4)); then + : ${PROTON_LOG_DIR:="$styledir/contents"} + : ${PROTON_LOG:=1} + : ${WINEDEBUG:="+loaddll,+module"} + export WINEDEBUG + export PROTON_LOG + export PROTON_LOG_DIR + echo "[INFO] Proton log file: '$PROTON_LOG_DIR/steam-${patchid}.log'" + fi + export PROTON_STYLE_PATCH="$PROTON_STYLE_PATCH:$_G_style" + + # Video fixes (AMD FSR, NVidia VSync) + WINE_FULLSCREEN_FSR=0 + [ -z ${__GL_SYNC_DISPLAY_DEVICE+x} ] && __GL_SYNC_DISPLAY_DEVICE="$(monitor_by_id $_G_display)" + if [ "$_G_fsr" -ge 0 ]; then + WINE_FULLSCREEN_FSR=1 + export WINE_FULLSCREEN_FSR_STRENGTH=$_G_fsr + if [ "$_G_style" -ge "30" ]; then + export WINE_FULLSCREEN_FSR_CUSTOM_MODE=1920x1080 + elif [ "$_G_style" -ge "20" ]; then + export WINE_FULLSCREEN_FSR_CUSTOM_MODE=1280x720 + else + export WINE_FULLSCREEN_FSR_CUSTOM_MODE=640x480 + fi + fi + export WINE_FULLSCREEN_FSR + export __GL_SYNC_DISPLAY_DEVICE + + # Debug/normal environment generation + if ((_G_debug & 2)); then + styledir="$styledir/devel/debug/x64dbg/x${arch}" + [ -n "$_G_exec" ] || _G_exec="x${arch}dbg.exe" + else + styledir="$styledir/contents" + [ -n "$_G_exec" ] || if [ "$arch" -eq "32" ]; then _G_exec="spice.exe"; else _G_exec="spice${arch}.exe"; fi + fi + + # Apply environment + cd "$styledir" || abort "INVALID PATH" + _G_ep+=(--exec "$_G_exec" --uniqueid "$patchid" --runtime "$_G_root/steamapps/common/$_C_rtname" --prefix "$_G_root/steamapps/compatdata/$_C_pfxname" --steam-dir "$_G_root") +} + +sanity_check() { + # IIDX + [ -n "$_G_style" ] || abort "INVALID STYLE" + [ -n "$_G_dumps" ] || _G_dumps="$_G_root/steamapps/common" + [ -d "$_G_dumps" ] || abort "INVALID PATH" + + # Proton + [ -d "$_G_root/steamapps/common" ] || abort "INVALID PATH" + [ -d "$_G_root/steamapps/compatdata" ] || abort "INVALID PATH" + + # Manual features warnings + [ -z ${__GL_SYNC_DISPLAY_DEVICE+x} ] || echo "[WARN] User envar override detected, if game runs at wrong framerates, try unsetting __GL_SYNC_DISPLAY_DEVICE" + + # Test only + echo "_G_display: $_G_display" + echo "_G_refresh_rate: $_G_refresh_rate" + echo "_G_fsr: $_G_fsr" + echo "_G_url: $_G_url" + echo "_G_pcbid: $_G_pcbid" + echo "_G_hooks[${#_G_hooks[@]}]: ${_G_hooks[*]}" + echo "_G_devel[${#_G_devel[@]}]: ${_G_devel[*]}" + +} + +# Set-up environment +arg_parse "${@}" +cfg_parse "${@}" +sanity_check + +# command generation +gen_base +gen_args + +#abort "__GL_SYNC_DISPLAY_DEVICE=$__GL_SYNC_DISPLAY_DEVICE ${_G_ep[*]}" +exec "${_G_ep[@]}" diff --git a/ep_protonnix b/ep_protonnix new file mode 100755 index 0000000..4b7c271 --- /dev/null +++ b/ep_protonnix @@ -0,0 +1,283 @@ +#!/usr/bin/env bash +# Minified version + +_C_scriptName="$(basename -- "$(realpath -- "$0")")" +_C_scriptDir="$(dirname -- "$(realpath -- "$0")")" +_C_rootDir="$(dirname -- "$_C_scriptDir")" +_G_runtime="" +_G_prefix="" +_G_exec="" +_G_args="" +_G_root="" +_G_steamlib=("$HOME/.local/share/Steam") +_G_runmode=() + +print_help() { + cat < APP-ID as used internally by legendary (obtainable through list, App name entry) +eg://by-title/ + MATCH-STRING used to find first matched APP-ID for this title +st:// protocol to trigger steam store simplification wrapper (directly launching games) +EOF +} + +arg_parse() { + #echo $PROTON_NO_D3D11 + echo "$@" + while [ ! -z ${1+x} ]; do + case "$1" in + --help | -h) + shift + print_help + exit 0 + ;; + --runtime) + shift + : ${_G_runtime:="${1%/}"} + shift + ;; + --steam-dir) + shift + _G_steamlib+=("${1%/}") + shift + ;; + --prefix) + shift + : ${_G_prefix:="${1%/}"} + shift + ;; + --exec) + shift + : ${_G_exec:="${1%/}"} + if [[ "${_G_exec}" == "eg://"* ]]; then + _G_exec="${_G_exec:5}" + _G_runmode+=('__exec_eg') + fi + shift + ;; + --args) + shift + : ${_G_args:="${1}"} + shift + ;; + --root) + shift + : ${_G_root:="${1%/}"} + shift + ;; + --uniqueid) + shift + [ -z "${1##*[!0-9]*}" ] || export STEAM_COMPAT_APP_ID="$1" + shift + ;; + --async) + _G_runmode+=('__async') + shift + ;; + --srpt) + _G_runmode+=('__srpt') + shift + shift + ;; + --info-hud) + shift + _G_runmode+=('__mango') + ;; + --local-only) + shift + _G_runmode+=('__local') + ;; + --no-debug) + shift + _G_runmode+=('__silent') + ;; + --dry-run) + shift + _G_runmode+=('__dry') + ;; + "") + shift + ;; + *) + echo "Unknown option: $1" + exit 2 + shift + ;; + esac + done +} + +# Finds path where steamapp has been installed (first occurence) +find_steamapp() { + for el in "${_G_steamlib[@]}"; do + elParse="$el/steamapps/common/$1" + if [ -d "$elParse" ]; then + printf "$elParse" + fi + done +} + +setup_legendary() { + # Adjust exec line to represent Epic Games app name based on protocol extension + if [[ "${_G_exec}" == "by-title/"* ]]; then + _G_exec="${_G_exec:9}" + _G_exec="$(/opt/Heroic/resources/app.asar.unpacked/build/bin/linux/legendary list | grep -m 1 -i -- "${_G_exec}" | grep -Po '^.*?\K(?<=App name: ).*?(?= | Version)')" + fi + + # Adjust execution to use legendary wrappers + prefix="$prefix /opt/Heroic/resources/app.asar.unpacked/build/bin/linux/legendary launch $_G_exec --no-wine --wrapper \"" # add --dry-run before --no-wine to test + _G_exec="" + suffix="\" $suffix" + +} + +setup_srpt() { + routeappid="0" + args=() + while [ ! -z ${1+x} ]; do + case "$1" in + --srpt) + shift + [ -z "${1##*[!0-9]*}" ] || routeappid="$1" + [ "$routeappid" -ne "0" ] || routeappid="1860860" + shift + ;; + *) + args+=("$1") + shift + ;; + esac + done + #echo steam -applaunch "$routeappid" ep_protonnix --cd "$(pwd)" "${args[@]}" + exec steam -applaunch "$routeappid" ep_protonnix --cd "$(pwd)" "${args[@]}" + exit 0 +} + +# Disable network access +setup_network_block() { + # no systemd (gamemode fails dbus connection, since permissions) + if pidof systemd; then + prefix="systemd-run --scope -p IPAddressDeny=any ${prefix}" + else + prefix="unshare -r -n ${prefix}" + fi + #print_log INFO "Disabling network access" +} + +# Setup steam variables +setup_environment() { + # Steam + if [ -n "$STEAM_COMPAT_MOUNTS" ]; then STEAM_COMPAT_MOUNTS="$STEAM_COMPAT_MOUNTS:"; fi # preserve preset additional mounts if any + export STEAM_COMPAT_MOUNTS="${STEAM_COMPAT_MOUNTS}$(find_steamapp "Steamworks Shared"):$_G_runtime:$(find_steamapp "SteamLinuxRuntime_soldier"):$(find_steamapp "Proton EasyAntiCheat Runtime")" + [ -z "${STEAM_COMPAT_APP_ID}" ] && export STEAM_COMPAT_APP_ID="${_G_prefix##*/}" # truncate to string after last occurence of / + [ -z "${STEAM_COMPAT_APP_ID##*[!0-9]*}" ] && export STEAM_COMPAT_APP_ID=0 # set to null if not numeric + export SteamAppId="$STEAM_COMPAT_APP_ID" + export SteamGameId="$STEAM_COMPAT_APP_ID" + export STEAM_COMPAT_INSTALL_PATH="$(realpath -- "$PWD")" + export STEAM_COMPAT_DATA_PATH="$_G_prefix" + export STEAM_COMPAT_SHADER_PATH="${_G_steamlib[${#_G_steamlib[@]} - 1]}/steamapps/shadercache/${_G_prefix##*/}" # ..../steam/steamapps/shadercache/739630 + export STEAM_COMPAT_CLIENT_INSTALL_PATH="$HOME/.local/share/Steam/" + export STEAM_COMPAT_TOOL_PATHS="$_G_runtime:$(find_steamapp "SteamLinuxRuntime_soldier")" #:$(find_steamapp "Proton EasyAntiCheat Runtime")" + + # Proton + : ${DXVK_STATE_CACHE:=1} + export DXVK_STATE_CACHE + : ${DXVK_ASYNC:=1} + unset DXVK_ASYNC # removed as of GE-Proton7-45 (superseeded by in-drivers extension? VK_EXT_graphics_pipeline_library) + #export RADV_PERFTEST=gpl # VK_EXT_graphics_pipeline_library support for AMD(RADV), for NVIDIA enabled in drivers since 515.49.10 without flag + : ${VKD3D_CONFIG:=no_upload_hvv} + export VKD3D_CONFIG + + # Wine (usually preconfigured by proton) + : ${WINEFSYNC:=1} + export WINEFSYNC + + # Epic Games Store + if [[ "${_G_runmode[*]}" =~ "__exec_eg" ]]; then + setup_legendary + fi + +} + +# Set-up environment +arg_parse "${@}" + +# Set-up other +if [ -z "$_G_runtime" ] || [ -z "$_G_prefix" ]; then + print_help + exit 0 +fi +if [[ "${_G_runmode[*]}" =~ "__srpt" ]]; then + setup_srpt "${@}" +fi +if [[ "${_G_runmode[*]}" =~ "__silent" ]]; then + suffix="> /dev/null 2>&1" +fi +if [[ "${_G_runmode[*]}" =~ "__mango" ]]; then + export MANGOHUD=1 +fi +if [[ "${_G_runmode[*]}" =~ "__local" ]]; then + setup_network_block +fi +if [ ! -z "$_G_root" ]; then + cd "$_G_root" # change working dir to game root directory (as expected on windows) +fi + +# Setup environment variables +setup_environment +main_exec="'$_G_runtime/proton'" +if [[ "${_G_runmode[*]}" =~ "__async" ]]; then + main_exec="$main_exec run" +else + main_exec="$main_exec waitforexitandrun" +fi +test -n "$_G_exec" && main_exec="$main_exec '$_G_exec' $_G_args" + +# For test runs +if [[ "${_G_runmode[*]}" =~ "__dry" ]]; then + echo "STEAM_COMPAT_SHADER_PATH $STEAM_COMPAT_SHADER_PATH" + echo "STEAM_COMPAT_MOUNTS $STEAM_COMPAT_MOUNTS" + echo "$prefix $main_exec $suffix : $STEAM_COMPAT_DATA_PATH" + exit 0 +fi + +# Run proton instance (creates prefix if applies) +if [[ ! -e "$_G_prefix" ]] ; then + mkdir "$_G_prefix" || exit 1 + eval "'$_G_runtime/proton' run wineboot --init" +fi +echo "$prefix : $main_exec : $suffix" +echo "Working dir: $PWD" +#read + + +eval "$prefix $main_exec $suffix" + + +[ ! -f "$_C_scriptDir/test_cases.sh" ] || . "$_C_scriptDir/test_cases.sh" +#sleep 600 + + +echo "COMMAND: $prefix $main_exec $suffix" +echo "STEAM_COMPAT_APP_ID: $STEAM_COMPAT_APP_ID" + + diff --git a/helper_steamct b/helper_steamct new file mode 100755 index 0000000..e629cc1 --- /dev/null +++ b/helper_steamct @@ -0,0 +1,47 @@ +#!/bin/bash +# Helper::Steam Compatibility Tools +# Expects below formats (called directly from steam client, supports any ambiguous application through chainloading) +# Launch current game while forcing native support (games steam doesn't list such feature for) +# $this waitforexitandrun /full/path/to/steam/game/binary +# Launch arbitrary EP process while emulating being a steam game in question (chainloading, may enable Remote Play Together etc.) +# $this waitforexitandrun /full/path/to/steam/game/binary "ENTRYPOINTNAME" --cd "ACTUALWORKINGDIR" ..ALLENTRYPOINTARGUMENTS.. +_C_scriptName="$(basename -- "$(realpath -- "$0")")" +_C_scriptDir="$(dirname -- "$(realpath -- "$0")")" + + +# Support for generic native execution (no steam helpers support) +[ "$1" = "waitforexitandrun" ] || exit 0 +args=("${@:2}") + +# Support for routing arbitrary EP through current steam app (expects ep_* next to itself) +argIndex=0 +for arg in "${args[@]}"; do + [[ "$arg" == "ep_"* ]] && break + ((argIndex++)) +done +if [ "${#args[@]}" -ne "$argIndex" ]; then + # Set correct Entry Point + argSwap=("${args[@]}") + args=("$_C_scriptDir/${argSwap[$argIndex]}") + ((argIndex++)) + + # Restore expected working directory (if any) + if [[ "${argSwap[$argIndex]}" == "--cd" ]]; then + ((argIndex++)) + cd "${argSwap[$argIndex]}" + ((argIndex++)) + fi + + # Set corrent args for Entry Point + args+=("${argSwap[@]:$argIndex}") +fi + +# for arg in "${args[@]}"; do +# echo "ARG: $arg" +# done + +# Execute requested command +echo "Command routed as [steam://run/$STEAM_COMPAT_APP_ID]:" +echo "cd $(pwd)" +echo "exec ${args[@]}" +exec "${args[@]}" diff --git a/monitor_by_id.c b/monitor_by_id.c new file mode 100644 index 0000000..8c6261c --- /dev/null +++ b/monitor_by_id.c @@ -0,0 +1,33 @@ +// gcc monitor_by_id.c -o monitor_by_id -lX11 -lXrandr +#include +#include +#include +#include + + +int main(int argc, char *argv[]) +{ + int vmajor = 0; + int vminor = 0; + int moni = -1; + int monc = 0; + if (argc == 2) moni = atoi(argv[1]); + + Display *dpy = XOpenDisplay(NULL); + if (!dpy || moni < 0) return 1; + Window wnd = XDefaultRootWindow(dpy); + + if (XRRQueryExtension(dpy, &vmajor, &vminor)) + { + XRRQueryVersion(dpy, &vmajor, &vminor); + XRRMonitorInfo *info = XRRGetMonitors(dpy, wnd, 0, &monc); + if (moni >= monc) return 1; + + printf("%s\n", XGetAtomName(dpy, info[moni].name)); + + XFree(info); + } + + XCloseDisplay(dpy); + return 0; +} \ No newline at end of file diff --git a/patch_pages b/patch_pages new file mode 100755 index 0000000..a279054 --- /dev/null +++ b/patch_pages @@ -0,0 +1,10 @@ +#!/bin/bash +shopt -s globstar + + +# Patch html +read -p "This action may modify all .html files at '$PWD'" +for html in **/*.html ; do + # Override relative links to open in current tab instead + sed -i 's~href="patcher/" target="_blank"~href="patcher/"~g' "$html" +done diff --git a/proton.patch b/proton.patch new file mode 100644 index 0000000..4e283c9 --- /dev/null +++ b/proton.patch @@ -0,0 +1,11 @@ +--- upstream/proton ++++ mod/proton +@@ -1462,6 +1462,8 @@ + prepend_to_env_str(self.env, ld_path_var, g_proton.lib64_dir + ":" + g_proton.lib_dir, ":") + + self.env["WINEDLLPATH"] = g_proton.lib64_dir + "/wine:" + g_proton.lib_dir + "/wine" ++ if len(os.getenv("WINEDLLPATH") or ""): ++ self.env["WINEDLLPATH"] = os.getenv("WINEDLLPATH").strip(":") + ":" + self.env["WINEDLLPATH"] + + self.env["GST_PLUGIN_SYSTEM_PATH_1_0"] = g_proton.lib64_dir + "gstreamer-1.0" + ":" + g_proton.lib_dir + "gstreamer-1.0" + self.env["WINE_GST_REGISTRY_DIR"] = g_compatdata.path("gstreamer-1.0/") diff --git a/stacktrace.py b/stacktrace.py new file mode 100644 index 0000000..2378469 --- /dev/null +++ b/stacktrace.py @@ -0,0 +1,43 @@ +#!/usr/bin/python +# Translates wine stacktraces to static adresses (so at 18h*Fh^7) +# @1: append to old value (default 0) +# @2: fallback source VA (default 0x0) +# @3: fallback target VA (default 0x180000000) +import sys + +OLDADDRESS = sys.argv[1] == "1" if len(sys.argv) >= 2 else False +VABASE_DEFAULT = int(sys.argv[2].rstrip("h"), 16) if len(sys.argv) >= 3 else 0x0 +VATARGET_DEFAULT = int(sys.argv[3].rstrip("h"), 16) if len(sys.argv) >= 4 else 0x180000000 +VABASE = VABASE_DEFAULT +VATARGET = VATARGET_DEFAULT + +print(f"Fallback source VA: {hex(VABASE)}", file=sys.stderr) +print(f"Fallback target VA: {hex(VATARGET)}", file=sys.stderr) +for line in sys.stdin: + linebase = line + try: + if line.lower().strip().startswith("vabase:"): + # Reconfigure VA for next lines + valindex = line.lower().find("vabase:") + 7 + src, target, *_ = [x.strip() if len(x.strip()) else None for x in line[valindex:].strip().split("->") + [""]] + if src == "SKIP": + VABASE = 0 + VATARGET = 0 + else: + VABASE = int(src.rstrip("h"), 16) if src else VABASE_DEFAULT + VATARGET = int(target.rstrip("h"), 16) if target else VATARGET_DEFAULT + + line = f"{line[:valindex]} {hex(VABASE)} -> {hex(VATARGET)}" + elif VABASE == 0 and VATARGET == 0: + # Lines to be untouched + raise + else: + # Lines to be translated + srcaddrstr = line.strip()[:16] + valindex = line.find(srcaddrstr) + tgtaddr = VATARGET + int(srcaddrstr, 16) - VABASE + tgtaddrstr=f"{hex(tgtaddr)} : {srcaddrstr}" if OLDADDRESS else f"{hex(tgtaddr)}" + line = f"{line[:valindex]}{tgtaddrstr}{line[valindex+16:].rstrip()}" + print(f"{line}") + except: + print(f"{linebase}", end="")