#!/usr/bin/python2.7 #script to launch Wine with the correct environment import filecmp import json import os import shutil import subprocess import sys import tarfile PFX="Proton: " def log(msg): sys.stdout.write(PFX + msg + os.linesep) def run_wine(args): if lfile == None: subprocess.call(args, env=env) else: subprocess.call(args, env=env, stdout=lfile, stderr=subprocess.STDOUT) def makedirs(path): try: os.makedirs(path) except: #already exists pass if not ("STEAM_COMPAT_DATA_PATH" in os.environ): log("No compat data path?") sys.exit(1) if "STEAM_COMPAT_CONFIG" in os.environ: config_opts = os.environ["STEAM_COMPAT_CONFIG"].split(",") else: config_opts = [] if "PROTON_USE_DXVK" in os.environ: config_opts.append("dxvk") basedir = os.path.dirname(sys.argv[0]) bindir = basedir + "/dist/bin/" libdir = basedir + "/dist/lib" lib64dir = basedir + "/dist/lib64" wine_path = bindir + "/wine64" #extract if needed if not os.path.exists(basedir + "/dist") or \ not os.path.exists(basedir + "/dist/version") or \ not filecmp.cmp(basedir + "/version", basedir + "/dist/version"): if os.path.exists(basedir + "/dist"): shutil.rmtree(basedir + "/dist") tar = tarfile.open(basedir + "/proton_dist.tar.gz", mode="r:gz") tar.extractall(path=basedir + "/dist") tar.close() shutil.copy(basedir + "/version", basedir + "/dist/") env = dict(os.environ) env["WINEDEBUG"] = "-all" lfile_path = None #env["WINEDEBUG"] = "+timestamp,+tid,+seh" #lfile_path = env["HOME"] + "/steam-" + env["SteamGameId"] + ".log" if lfile_path is None: lfile = open("/dev/null", "w") else: if os.path.exists(lfile_path): os.remove(lfile_path) lfile = open(lfile_path, "w") if "LD_LIBRARY_PATH" in os.environ: env["LD_LIBRARY_PATH"] = lib64dir + ":" + libdir + ":" + env["LD_LIBRARY_PATH"] else: env["LD_LIBRARY_PATH"] = lib64dir + ":" + libdir env["WINEDLLPATH"] = lib64dir + "/wine:" + libdir + "/wine" if "PATH" in os.environ: env["PATH"] = bindir + ":" + env["PATH"] else: env["PATH"] = bindir if not os.path.isdir(basedir + "/dist/share/default_pfx"): #make default prefix env["WINEPREFIX"] = basedir + "/dist/share/default_pfx" run_wine([wine_path, "wineboot"]) run_wine([bindir + "/wineserver", "-w"]) prefix = os.environ["STEAM_COMPAT_DATA_PATH"] + "/pfx/" env["WINEPREFIX"] = prefix if not os.path.isdir(prefix): #copy default prefix into place shutil.copytree(basedir + "/dist/share/default_pfx", prefix, symlinks=True) #copy steam files into place steamdir = env["HOME"] + "/.steam/steam/legacycompat/" dst = prefix + "/drive_c/Program Files (x86)/" makedirs(dst + "Steam") filestocopy = ["steamclient.dll", "steamclient64.dll", "Steam.dll"] for f in filestocopy: if os.path.isfile(steamdir + f): shutil.copy(steamdir + f, dst + "Steam/" + f) #copy openvr files into place dst = prefix + "/drive_c/vrclient/bin/" makedirs(dst) shutil.copy(basedir + "/dist/lib/wine/fakedlls/vrclient.dll", dst) shutil.copy(basedir + "/dist/lib64/wine/fakedlls/vrclient_x64.dll", dst) #parse linux openvr config and present it in win32 format to the app. #logic from openvr's CVRPathRegistry_Public::GetPaths #check environment for overrides vr_runtime = None if "VR_OVERRIDE" in env: vr_runtime = env["VR_OVERRIDE"] env.pop("VR_OVERRIDE") vr_config = None if "VR_CONFIG_PATH" in env: vr_config = env["VR_CONFIG_PATH"] env.pop("VR_CONFIG_PATH") vr_log = None if "VR_LOG_PATH" in env: vr_log = env["VR_LOG_PATH"] env.pop("VR_LOG_PATH") #load from json if needed if vr_runtime is None or \ vr_config is None or \ vr_log is None: try: if "XDG_CONFIG_HOME" in env: path = env["XDG_CONFIG_HOME"] else: path = env["HOME"] + "/.config" path = path + "/openvr/openvrpaths.vrpath" j = json.load(open(path, "r")) if vr_runtime is None: vr_runtime = j["runtime"][0] if vr_config is None: vr_config = j["config"][0] if vr_log is None: vr_log = j["log"][0] except: pass makedirs(prefix + "/drive_c/users/steamuser/Local Settings/Application Data/openvr") #remove existing file vrpaths_name = prefix + "/drive_c/users/steamuser/Local Settings/Application Data/openvr/openvrpaths.vrpath" if os.path.exists(vrpaths_name): os.remove(vrpaths_name) #dump new file if not vr_runtime is None: try: env["PROTON_VR_RUNTIME"] = vr_runtime j = { "runtime": [ "C:\\vrclient\\", "C:\\vrclient" ] } if not vr_config is None: win_vr_config = subprocess.check_output([wine_path, "winepath", "-w", vr_config], env=env, stderr=open("/dev/null", "w")) j["config"] = [ win_vr_config.strip() ] if not vr_log is None: win_vr_log = subprocess.check_output([wine_path, "winepath", "-w", vr_log], env=env, stderr=open("/dev/null", "w")) j["log"] = [ win_vr_log.strip() ] j["version"] = 1 j["jsonid"] = "vrpathreg" json.dump(j, open(vrpaths_name, "w"), indent=2) except: pass def make_dxvk_links(dll_dir, link_dir): if os.path.lexists(link_dir + "/d3d11.dll"): os.remove(link_dir + "/d3d11.dll") if os.path.lexists(link_dir + "/dxgi.dll"): os.remove(link_dir + "/dxgi.dll") os.symlink(dll_dir + "/d3d11.dll", link_dir + "/d3d11.dll") os.symlink(dll_dir + "/dxgi.dll", link_dir + "/dxgi.dll") if "dxvk" in config_opts: make_dxvk_links(basedir + "/dist/lib64/wine/dxvk/", prefix + "drive_c/windows/system32") make_dxvk_links(basedir + "/dist/lib/wine/dxvk/", prefix + "drive_c/windows/syswow64") env["WINEDLLOVERRIDES"] = "dxgi,d3d11=n" else: make_dxvk_links(basedir + "/dist/lib64/wine/", prefix + "drive_c/windows/system32") make_dxvk_links(basedir + "/dist/lib/wine/", prefix + "drive_c/windows/syswow64") #determine mode if sys.argv[1] == "run": #start target app run_wine([wine_path] + sys.argv[2:]) elif sys.argv[1] == "translatepath": #get windows path equivalent path = subprocess.check_output([wine_path, "winepath", "-w", sys.argv[2]], env=env, stderr=open("/dev/null", "w")) stdout.write(path) else: stdout.write("Need a verb.") sys.exit(1) sys.exit(0)