#!/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_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[@]}") } 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_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_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_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_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_iidx31() { # pipewire supported, only tested in LDJ # TDJ still being tested _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[@]}") } 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" --prefix "$_G_root/steamapps/compatdata/$_C_pfxname" --steam-dir "$_G_root") # Remove application of steam runtime } 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[@]}"