Yucom/proton

682 lines
24 KiB
Text
Raw Normal View History

2018-10-05 17:51:21 +02:00
#!/usr/bin/env python3
2018-01-18 21:00:48 +01:00
#script to launch Wine with the correct environment
from __future__ import print_function
import fcntl
import array
import filecmp
2018-01-18 21:00:48 +01:00
import json
import os
import shutil
import errno
import struct
2018-01-18 21:00:48 +01:00
import subprocess
import sys
import tarfile
2018-01-18 21:00:48 +01:00
2018-10-24 21:22:22 +02:00
from filelock import FileLock
#To enable debug logging, copy "user_settings.sample.py" to "user_settings.py"
#and edit it if needed.
2019-06-19 16:31:09 +02:00
CURRENT_PREFIX_VERSION="4.11-1"
2018-01-18 21:00:48 +01:00
PFX="Proton: "
2018-10-11 15:50:23 +02:00
ld_path_var = "LD_LIBRARY_PATH"
2018-03-06 19:13:24 +01:00
def nonzero(s):
return len(s) > 0 and s != "0"
2018-01-18 21:00:48 +01:00
def log(msg):
sys.stderr.write(PFX + msg + os.linesep)
sys.stderr.flush()
def remove_tracked_files(prefix):
if not os.path.exists(prefix + "/tracked_files"):
log("Prefix has no tracked_files??")
return
with open(prefix + "/tracked_files", "r") as tracked_files:
dirs = []
for f in tracked_files:
path = prefix + "/pfx/" + f.strip()
if os.path.exists(path):
if os.path.isfile(path) or os.path.islink(path):
os.remove(path)
else:
dirs.append(path)
for d in dirs:
try:
os.rmdir(d)
except OSError:
#not empty
pass
os.remove(prefix + "/tracked_files")
os.remove(prefix + "/version")
def file_is_wine_fake_dll(path):
if not os.path.exists(path):
return False
try:
sfile = open(path, "rb")
sfile.seek(0x40)
tag = sfile.read(20)
return tag == b"Wine placeholder DLL"
except IOError:
return False
def upgrade_pfx(old_ver):
if old_ver == CURRENT_PREFIX_VERSION:
return
2018-04-20 17:11:19 +02:00
log("Upgrading prefix from " + str(old_ver) + " to " + CURRENT_PREFIX_VERSION + " (" + os.environ["STEAM_COMPAT_DATA_PATH"] + ")")
2018-08-23 16:42:18 +02:00
2018-10-24 21:22:22 +02:00
if old_ver is None:
2018-08-23 16:42:18 +02:00
return
if not '-' in old_ver:
#How can this happen??
log("Prefix has an invalid version?! You may want to back up user files and delete this prefix.")
#If it does, just let the Wine upgrade happen and hope it works...
return
try:
old_proton_ver, old_prefix_ver = old_ver.split('-')
old_proton_maj, old_proton_min = old_proton_ver.split('.')
new_proton_ver, new_prefix_ver = CURRENT_PREFIX_VERSION.split('-')
new_proton_maj, new_proton_min = new_proton_ver.split('.')
if int(new_proton_maj) < int(old_proton_maj) or \
(int(new_proton_maj) == int(old_proton_maj) and \
int(new_proton_min) < int(old_proton_min)):
log("Removing newer prefix")
if old_proton_ver == "3.7" and not os.path.exists(os.environ["STEAM_COMPAT_DATA_PATH"] + "/tracked_files"):
#proton 3.7 did not generate tracked_files, so copy it into place first
2019-07-29 17:49:26 +02:00
try_copy(g_proton.path("proton_3.7_tracked_files"), os.environ["STEAM_COMPAT_DATA_PATH"] + "/tracked_files")
remove_tracked_files(os.environ["STEAM_COMPAT_DATA_PATH"])
return
2018-01-18 21:00:48 +01:00
if old_proton_ver == "3.7" and old_prefix_ver == "1":
if not os.path.exists(prefix + "/drive_c/windows/syswow64/kernel32.dll"):
#shipped a busted 64-bit-only installation on 20180822. detect and wipe clean
log("Detected broken 64-bit-only installation, re-creating prefix.")
shutil.rmtree(prefix)
return
#replace broken .NET installations with wine-mono support
if os.path.exists(prefix + "/drive_c/windows/Microsoft.NET/NETFXRepair.exe") and \
file_is_wine_fake_dll(prefix + "/drive_c/windows/system32/mscoree.dll"):
log("Broken .NET installation detected, switching to wine-mono.")
#deleting this directory allows wine-mono to work
shutil.rmtree(prefix + "/drive_c/windows/Microsoft.NET")
except ValueError:
log("Prefix has an invalid version?! You may want to back up user files and delete this prefix.")
#Just let the Wine upgrade happen and hope it works...
return
def run_wine(args):
subprocess.call(args, env=env, stderr=lfile, stdout=lfile)
def makedirs(path):
try:
os.makedirs(path)
2018-10-11 15:50:23 +02:00
except OSError:
#already exists
pass
def try_copy(src, dst):
try:
if os.path.isdir(dst):
dstfile = dst + "/" + os.path.basename(src)
if os.path.lexists(dstfile):
os.remove(dstfile)
elif os.path.lexists(dst):
os.remove(dst)
shutil.copy(src, dst)
except PermissionError as e:
if e.errno == errno.EPERM:
#be forgiving about permissions errors; if it's a real problem, things will explode later anyway
log('Error while copying to \"' + dst + '\": ' + e.strerror)
else:
raise
def real_copy(src, dst):
if os.path.islink(src):
os.symlink(os.readlink(src), dst)
else:
try_copy(src, dst)
def mergedirs(src, dst, tracked_files):
for src_dir, dirs, files in os.walk(src):
rel_dir = src_dir.replace(src, "", 1).lstrip('/')
if len(rel_dir) > 0:
rel_dir = rel_dir + "/"
dst_dir = src_dir.replace(src, dst, 1)
if not os.path.exists(dst_dir):
os.makedirs(dst_dir)
tracked_files.write(rel_dir + "\n")
for dir_ in dirs:
src_file = os.path.join(src_dir, dir_)
dst_file = os.path.join(dst_dir, dir_)
if os.path.islink(src_file) and not os.path.exists(dst_file):
real_copy(src_file, dst_file)
for file_ in files:
src_file = os.path.join(src_dir, file_)
dst_file = os.path.join(dst_dir, file_)
if not os.path.exists(dst_file):
real_copy(src_file, dst_file)
tracked_files.write(rel_dir + file_ + "\n")
2019-07-29 17:49:26 +02:00
class Proton:
def __init__(self, base_dir):
self.base_dir = base_dir + "/"
self.dist_dir = self.path("dist/")
self.bin_dir = self.path("dist/bin/")
self.lib_dir = self.path("dist/lib/")
self.lib64_dir = self.path("dist/lib64/")
self.fonts_dir = self.path("dist/share/fonts/")
self.version_file = self.path("version")
self.default_pfx_dir = self.path("dist/share/default_pfx/")
self.user_settings_file = self.path("user_settings.py")
self.wine_bin = self.bin_dir + "wine"
self.wineserver_bin = self.bin_dir + "wineserver"
self.dist_lock = FileLock(self.path("dist.lock"), timeout=-1)
def path(self, d):
return self.base_dir + d
2018-10-24 21:22:22 +02:00
if not "STEAM_COMPAT_DATA_PATH" in os.environ:
2018-01-18 21:00:48 +01:00
log("No compat data path?")
sys.exit(1)
2019-07-29 17:49:26 +02:00
g_proton = Proton(os.path.dirname(sys.argv[0]))
2018-01-18 21:00:48 +01:00
#extract if needed
2019-07-29 17:49:26 +02:00
with g_proton.dist_lock:
if not os.path.exists(g_proton.dist_dir) or \
not os.path.exists(g_proton.path("dist/version")) or \
not filecmp.cmp(g_proton.version_file, g_proton.path("dist/version")):
if os.path.exists(g_proton.dist_dir):
shutil.rmtree(g_proton.dist_dir)
tar = tarfile.open(g_proton.path("proton_dist.tar.gz"), mode="r:gz")
tar.extractall(path=g_proton.dist_dir)
tar.close()
2019-07-29 17:49:26 +02:00
try_copy(g_proton.version_file, g_proton.dist_dir)
2018-01-18 21:00:48 +01:00
env = dict(os.environ)
dlloverrides = {
"steam.exe": "b", #always use our special built-in steam.exe
"mfplay": "n" #disable built-in mfplay
}
2018-01-18 21:00:48 +01:00
if "HOST_LC_ALL" in env and len(env["HOST_LC_ALL"]) > 0:
#steam sets LC_ALL=C to help some games, but Wine requires the real value
#in order to do path conversion between win32 and host. steam sets
#HOST_LC_ALL to allow us to use the real value.
env["LC_ALL"] = env["HOST_LC_ALL"]
else:
env.pop("LC_ALL", "")
#for performance, logging is disabled by default; override with user_settings.py
env["DXVK_LOG_LEVEL"] = "none"
env["WINEDEBUG"] = "-all"
2018-08-22 17:11:30 +02:00
env.pop("WINEARCH", "")
2018-03-06 19:13:24 +01:00
if ld_path_var in os.environ:
2019-07-29 17:49:26 +02:00
env[ld_path_var] = g_proton.lib64_dir + ":" + g_proton.lib_dir + ":" + os.environ[ld_path_var]
2018-01-18 21:00:48 +01:00
else:
2019-07-29 17:49:26 +02:00
env[ld_path_var] = g_proton.lib64_dir + ":" + g_proton.lib_dir
2018-02-14 20:59:35 +01:00
2019-07-29 17:49:26 +02:00
env["WINEDLLPATH"] = g_proton.lib64_dir + "/wine:" + g_proton.lib_dir + "/wine"
2018-02-14 20:59:35 +01:00
if "PATH" in os.environ:
2019-07-29 17:49:26 +02:00
env["PATH"] = g_proton.bin_dir + ":" + os.environ["PATH"]
2018-02-14 20:59:35 +01:00
else:
2019-07-29 17:49:26 +02:00
env["PATH"] = g_proton.bin_dir
2018-01-18 21:00:48 +01:00
2019-07-29 17:49:26 +02:00
with g_proton.dist_lock:
if not os.path.isdir(g_proton.default_pfx_dir):
#make default prefix
2019-07-29 17:49:26 +02:00
env["WINEPREFIX"] = g_proton.default_pfx_dir
run_wine([g_proton.wine_bin, "wineboot"])
run_wine([g_proton.wineserver_bin, "-w"])
prefix = os.environ["STEAM_COMPAT_DATA_PATH"] + "/pfx/"
env["WINEPREFIX"] = prefix
2018-01-18 21:00:48 +01:00
if "PROTON_LOG" in env and nonzero(env["PROTON_LOG"]):
env["WINEDEBUG"] = "+timestamp,+pid,+tid,+seh,+debugstr,+loaddll,+mscoree"
2019-04-09 15:51:22 +02:00
env["DXVK_LOG_LEVEL"] = "info"
env["WINE_MONO_TRACE"] = "E:System.NotImplementedException"
2019-04-05 22:43:25 +02:00
#default wine-mono override for FNA games
env["WINE_MONO_OVERRIDES"] = "Microsoft.Xna.Framework.*,Gac=n"
#load environment overrides
2019-07-29 17:49:26 +02:00
if os.path.exists(g_proton.user_settings_file):
try:
import user_settings
env.update(user_settings.user_settings)
2018-10-24 21:22:22 +02:00
except:
log("************************************************")
log("THERE IS AN ERROR IN YOUR user_settings.py FILE:")
log("%s" % sys.exc_info()[1])
log("************************************************")
def check_environment(env_name, config_name):
if not env_name in env:
2018-10-15 18:40:33 +02:00
return False
if nonzero(env[env_name]):
config_opts.add(config_name)
else:
config_opts.discard(config_name)
2018-10-15 18:40:33 +02:00
return True
if "STEAM_COMPAT_CONFIG" in os.environ:
config_opts = set(os.environ["STEAM_COMPAT_CONFIG"].split(","))
else:
config_opts = set()
2018-10-15 18:40:33 +02:00
if "wined3d11" in config_opts:
config_opts.add("wined3d")
if not check_environment("PROTON_USE_WINED3D", "wined3d"):
check_environment("PROTON_USE_WINED3D11", "wined3d")
2019-06-18 17:01:06 +02:00
check_environment("PROTON_USE_D9VK", "d9vk")
check_environment("PROTON_NO_D3D11", "nod3d11")
2018-12-19 00:49:36 +01:00
check_environment("PROTON_NO_D3D10", "nod3d10")
check_environment("PROTON_NO_ESYNC", "noesync")
check_environment("PROTON_NO_FSYNC", "nofsync")
check_environment("PROTON_FORCE_LARGE_ADDRESS_AWARE", "forcelgadd")
check_environment("PROTON_OLD_GL_STRING", "oldglstr")
if not "noesync" in config_opts:
env["WINEESYNC"] = "1"
if not "nofsync" in config_opts:
env["WINEFSYNC"] = "1"
if "oldglstr" in config_opts:
#mesa override
env["MESA_EXTENSION_MAX_YEAR"] = "2003"
#nvidia override
env["__GL_ExtensionStringVersion"] = "17700"
if "forcelgadd" in config_opts:
#forcelgadd should be used just for testing whether a game is helped by
#setting LARGE_ADDRESS_AWARE. If it does, then add an AppDefault in the
#registry, so that it doesn't impact every executable in the prefix.
env["WINE_LARGE_ADDRESS_AWARE"] = "1"
lfile = None
if "SteamGameId" in env:
if env["WINEDEBUG"] != "-all":
lfile_path = os.environ["HOME"] + "/steam-" + os.environ["SteamGameId"] + ".log"
if os.path.exists(lfile_path):
os.remove(lfile_path)
lfile = open(lfile_path, "w+")
lfile.write("======================\n")
2019-07-29 17:49:26 +02:00
with open(g_proton.version_file, "r") as f:
lfile.write("Proton: " + f.readline().strip() + "\n")
lfile.write("SteamGameId: " + env["SteamGameId"] + "\n")
lfile.write("Command: " + str(sys.argv[2:]) + "\n")
lfile.write("Options: " + str(config_opts) + "\n")
lfile.write("======================\n")
lfile.flush()
else:
env["WINEDEBUG"] = "-all"
2018-10-12 13:20:49 +02:00
def create_fonts_symlinks(prefix_path):
fontsmap = [
( "LiberationSans-Regular.ttf", "arial.ttf" ),
( "LiberationSans-Bold.ttf", "arialbd.ttf" ),
( "LiberationSerif-Regular.ttf", "times.ttf" ),
( "LiberationMono-Regular.ttf", "cour.ttf" ),
]
windowsfonts = prefix_path + "/drive_c/windows/Fonts"
makedirs(windowsfonts)
2018-10-12 13:20:49 +02:00
for p in fontsmap:
lname = os.path.join(windowsfonts, p[1])
2019-07-29 17:49:26 +02:00
fname = os.path.join(g_proton.fonts_dir, p[0])
2018-10-12 13:20:49 +02:00
if os.path.lexists(lname):
if os.path.islink(lname):
os.remove(lname)
os.symlink(fname, lname)
else:
os.symlink(fname, lname)
EXT2_IOC_GETFLAGS = 0x80086601
EXT2_IOC_SETFLAGS = 0x40086602
EXT4_CASEFOLD_FL = 0x40000000
def set_dir_casefold_bit(dir_path):
dr = os.open(dir_path, 0o644)
if dr < 0:
return
try:
dat = array.array('I', [0])
if fcntl.ioctl(dr, EXT2_IOC_GETFLAGS, dat, True) >= 0:
dat[0] = dat[0] | EXT4_CASEFOLD_FL
fcntl.ioctl(dr, EXT2_IOC_SETFLAGS, dat, False)
except OSError:
#no problem
pass
os.close(dr)
2018-03-16 16:39:04 +01:00
prefix_lock = FileLock(os.environ["STEAM_COMPAT_DATA_PATH"] + "/pfx.lock", timeout=-1)
with prefix_lock:
version_file = os.environ["STEAM_COMPAT_DATA_PATH"] + "/version"
if os.path.exists(version_file):
with open(version_file, "r") as f:
upgrade_pfx(f.readline().strip())
else:
upgrade_pfx(None)
if not os.path.exists(prefix):
makedirs(prefix + "/drive_c")
set_dir_casefold_bit(prefix + "/drive_c")
if not os.path.exists(prefix + "/user.reg"):
#copy default prefix into place
2018-10-11 15:50:23 +02:00
with open(os.environ["STEAM_COMPAT_DATA_PATH"] + "/tracked_files", "w") as tfiles:
2019-07-29 17:49:26 +02:00
mergedirs(g_proton.default_pfx_dir, prefix, tfiles)
2018-03-16 16:39:04 +01:00
with open(version_file, "w") as f:
f.write(CURRENT_PREFIX_VERSION + "\n")
2018-10-12 13:20:49 +02:00
#create font files symlinks
create_fonts_symlinks(prefix)
2018-03-16 16:39:04 +01:00
#copy steam files into place
if "STEAM_COMPAT_CLIENT_INSTALL_PATH" in os.environ:
#modern steam client sets this
steamdir = os.environ["STEAM_COMPAT_CLIENT_INSTALL_PATH"]
else:
#linux-only fallback, really shouldn't get here
steamdir = os.environ["HOME"] + ".steam/root/"
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 + "/legacycompat/" + f):
dstfile = dst + "Steam/" + f
if os.path.isfile(dstfile):
os.remove(dstfile)
try_copy(steamdir + "/legacycompat/" + f, dstfile)
2018-03-16 16:39:04 +01:00
#copy openvr files into place
dst = prefix + "/drive_c/vrclient/bin/"
makedirs(dst)
2019-07-29 17:49:26 +02:00
try_copy(g_proton.lib_dir + "wine/fakedlls/vrclient.dll", dst)
try_copy(g_proton.lib64_dir + "wine/fakedlls/vrclient_x64.dll", dst)
2018-03-16 16:39:04 +01:00
2019-07-29 17:49:26 +02:00
try_copy(g_proton.lib_dir + "wine/dxvk/openvr_api_dxvk.dll", prefix + "/drive_c/windows/syswow64/")
try_copy(g_proton.lib64_dir + "wine/dxvk/openvr_api_dxvk.dll", prefix + "/drive_c/windows/system32/")
2018-03-16 16:39:04 +01:00
#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:
2018-10-15 16:51:29 +02:00
path = os.environ.get("XDG_CONFIG_HOME", os.environ["HOME"] + "/.config")
2018-03-16 16:39:04 +01:00
path = path + "/openvr/openvrpaths.vrpath"
2018-10-11 15:50:23 +02:00
with open(path, "r") as jfile:
j = json.load(jfile)
2018-03-16 16:39:04 +01:00
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 (TypeError, ValueError, OSError):
log("Missing or invalid openvrpaths.vrpath file! " + str(sys.exc_info()[1]))
2018-03-16 16:39:04 +01:00
makedirs(prefix + "/drive_c/users/steamuser/Local Settings/Application Data/openvr")
2018-03-16 16:39:04 +01:00
#remove existing file
vrpaths_name = prefix + "/drive_c/users/steamuser/Local Settings/Application Data/openvr/openvrpaths.vrpath"
2018-03-16 16:39:04 +01:00
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:
2019-07-29 17:49:26 +02:00
win_vr_config = subprocess.check_output([g_proton.wine_bin, "winepath", "-w", vr_config], env=env, stderr=lfile).decode("utf-8")
2018-03-16 16:39:04 +01:00
j["config"] = [ win_vr_config.strip() ]
if not vr_log is None:
2019-07-29 17:49:26 +02:00
win_vr_log = subprocess.check_output([g_proton.wine_bin, "winepath", "-w", vr_log], env=env, stderr=lfile).decode("utf-8")
2018-03-16 16:39:04 +01:00
j["log"] = [ win_vr_log.strip() ]
j["version"] = 1
j["jsonid"] = "vrpathreg"
2018-10-11 15:50:23 +02:00
with open(vrpaths_name, "w") as vfile:
json.dump(j, vfile, indent=2)
except (ValueError, OSError):
log("Unable to write VR config! " + str(sys.exc_info()[1]))
2018-03-16 16:39:04 +01:00
2018-10-15 18:40:33 +02:00
if "wined3d" in config_opts:
dxvkfiles = []
wined3dfiles = ["d3d11", "d3d10", "d3d10core", "d3d10_1", "dxgi", "d3d9"]
else:
dxvkfiles = ["d3d11", "d3d10", "d3d10core", "d3d10_1", "dxgi"]
wined3dfiles = []
if "d9vk" in config_opts:
dxvkfiles.append("d3d9")
else:
wined3dfiles.append("d3d9")
for f in wined3dfiles:
2019-07-29 17:49:26 +02:00
try_copy(g_proton.default_pfx_dir + "drive_c/windows/system32/" + f + ".dll",
prefix + "drive_c/windows/system32/" + f + ".dll")
2019-07-29 17:49:26 +02:00
try_copy(g_proton.default_pfx_dir + "drive_c/windows/syswow64/" + f + ".dll",
prefix + "drive_c/windows/syswow64/" + f + ".dll")
for f in dxvkfiles:
2019-07-29 17:49:26 +02:00
try_copy(g_proton.lib64_dir + "wine/dxvk/" + f + ".dll",
prefix + "drive_c/windows/system32/" + f + ".dll")
2019-07-29 17:49:26 +02:00
try_copy(g_proton.lib_dir + "wine/dxvk/" + f + ".dll",
prefix + "drive_c/windows/syswow64/" + f + ".dll")
dlloverrides[f] = "n"
2018-03-28 17:27:56 +02:00
if "nod3d11" in config_opts:
dlloverrides["d3d11"] = ""
if "dxgi" in dlloverrides:
del dlloverrides["dxgi"]
2018-12-19 00:49:36 +01:00
if "nod3d10" in config_opts:
dlloverrides["d3d10_1"] = ""
dlloverrides["d3d10"] = ""
dlloverrides["dxgi"] = ""
2018-03-28 17:27:56 +02:00
s = ""
for dll in dlloverrides:
setting = dlloverrides[dll]
2018-03-28 17:27:56 +02:00
if len(s) > 0:
s = s + ";" + dll + "=" + setting
else:
s = dll + "=" + setting
if "WINEDLLOVERRIDES" in os.environ:
env["WINEDLLOVERRIDES"] = os.environ["WINEDLLOVERRIDES"] + ";" + s
else:
env["WINEDLLOVERRIDES"] = s
2018-03-28 17:27:56 +02:00
2018-03-14 19:58:11 +01:00
def dump_dbg_env(f):
f.write("PATH=\"" + env["PATH"] + "\" \\\n")
2018-03-14 19:58:11 +01:00
f.write("\tTERM=\"xterm\" \\\n") #XXX
f.write("\tWINEDEBUG=\"-all\" \\\n")
f.write("\tWINEDLLPATH=\"" + env["WINEDLLPATH"] + "\" \\\n")
2018-03-06 19:13:24 +01:00
f.write("\t" + ld_path_var + "=\"" + env[ld_path_var] + "\" \\\n")
f.write("\tWINEPREFIX=\"" + env["WINEPREFIX"] + "\" \\\n")
if "WINEESYNC" in env:
f.write("\tWINEESYNC=\"" + env["WINEESYNC"] + "\" \\\n")
if "SteamGameId" in env:
f.write("\tSteamGameId=\"" + env["SteamGameId"] + "\" \\\n")
if "SteamAppId" in env:
f.write("\tSteamAppId=\"" + env["SteamAppId"] + "\" \\\n")
if "PROTON_VR_RUNTIME" in env:
f.write("\tPROTON_VR_RUNTIME=\"" + env["PROTON_VR_RUNTIME"] + "\" \\\n")
if "WINEDLLOVERRIDES" in env:
f.write("\tWINEDLLOVERRIDES=\"" + env["WINEDLLOVERRIDES"] + "\" \\\n")
if "STEAM_COMPAT_CLIENT_INSTALL_PATH" in env:
f.write("\tSTEAM_COMPAT_CLIENT_INSTALL_PATH=\"" + env["STEAM_COMPAT_CLIENT_INSTALL_PATH"] + "\" \\\n")
if "WINE_LARGE_ADDRESS_AWARE" in env:
f.write("\tWINE_LARGE_ADDRESS_AWARE=\"" + env["WINE_LARGE_ADDRESS_AWARE"] + "\" \\\n")
2018-03-14 19:58:11 +01:00
def dump_dbg_scripts():
exe_name = os.path.basename(sys.argv[2])
2018-10-24 21:22:22 +02:00
tmpdir = env.get("PROTON_DEBUG_DIR", "/tmp") + "/proton_" + os.environ["USER"] + "/"
makedirs(tmpdir)
2018-10-24 21:22:22 +02:00
with open(tmpdir + "winedbg", "w") as f:
2018-03-14 19:58:11 +01:00
f.write("#!/bin/bash\n")
f.write("#Run winedbg with args\n\n")
f.write("cd \"" + os.getcwd() + "\"\n")
dump_dbg_env(f)
2019-07-29 17:49:26 +02:00
f.write("\t\"" + g_proton.wine_bin + "\" winedbg \"$@\"\n")
2018-10-24 21:22:22 +02:00
os.chmod(tmpdir + "winedbg", 0o755)
2018-03-14 19:58:11 +01:00
2018-10-24 21:22:22 +02:00
with open(tmpdir + "winedbg_run", "w") as f:
2018-03-14 19:58:11 +01:00
f.write("#!/bin/bash\n")
f.write("#Run winedbg and prepare to run game or given program\n\n")
f.write("cd \"" + os.getcwd() + "\"\n")
f.write("DEF_CMD=(")
first = True
for arg in sys.argv[2:]:
if first:
f.write("\"" + arg + "\"")
first = False
else:
f.write(" \"" + arg + "\"")
f.write(")\n")
dump_dbg_env(f)
2019-07-29 17:49:26 +02:00
f.write("\t\"" + g_proton.wine_bin + "\" winedbg \"${@:-${DEF_CMD[@]}}\"\n")
2018-10-24 21:22:22 +02:00
os.chmod(tmpdir + "winedbg_run", 0o755)
2018-03-14 19:58:11 +01:00
2018-10-24 21:22:22 +02:00
with open(tmpdir + "gdb_attach", "w") as f:
2018-03-14 19:58:11 +01:00
f.write("#!/bin/bash\n")
f.write("#Run winedbg in gdb mode and auto-attach to already-running program\n\n")
f.write("cd \"" + os.getcwd() + "\"\n")
f.write("EXE_NAME=${1:-\"" + exe_name + "\"}\n")
2018-10-24 21:22:22 +02:00
f.write("WPID_HEX=$(\"" + tmpdir + "winedbg\" --command 'info process' | grep -i \"$EXE_NAME\" | cut -f2 -d' ' | tr -d '0')\n")
2018-03-14 19:58:11 +01:00
f.write("if [ -z \"$WPID_HEX\" ]; then \n")
f.write(" echo \"Program does not appear to be running: \\\"$EXE_NAME\\\"\"\n")
f.write(" exit 1\n")
f.write("fi\n")
f.write("WPID_DEC=$(printf %d 0x$WPID_HEX)\n")
dump_dbg_env(f)
2019-07-29 17:49:26 +02:00
f.write("\t\"" + g_proton.wine_bin + "\" winedbg --gdb $WPID_DEC\n")
2018-10-24 21:22:22 +02:00
os.chmod(tmpdir + "gdb_attach", 0o755)
2018-03-14 19:58:11 +01:00
2018-10-24 21:22:22 +02:00
with open(tmpdir + "gdb_run", "w") as f:
2018-03-14 19:58:11 +01:00
f.write("#!/bin/bash\n")
f.write("#Run winedbg in gdb mode and prepare to run game or given program\n\n")
f.write("cd \"" + os.getcwd() + "\"\n")
f.write("DEF_CMD=(")
first = True
for arg in sys.argv[2:]:
if first:
f.write("\"" + arg + "\"")
first = False
else:
f.write(" \"" + arg + "\"")
f.write(")\n")
dump_dbg_env(f)
2019-07-29 17:49:26 +02:00
f.write("\t\"" + g_proton.wine_bin + "\" winedbg --gdb \"${@:-${DEF_CMD[@]}}\"\n")
2018-10-24 21:22:22 +02:00
os.chmod(tmpdir + "gdb_run", 0o755)
2018-03-14 19:58:11 +01:00
2018-10-24 21:22:22 +02:00
with open(tmpdir + "run", "w") as f:
2018-03-14 19:58:11 +01:00
f.write("#!/bin/bash\n")
f.write("#Run game or given command in environment\n\n")
f.write("cd \"" + os.getcwd() + "\"\n")
f.write("DEF_CMD=(")
first = True
for arg in sys.argv[2:]:
if first:
f.write("\"" + arg + "\"")
first = False
else:
f.write(" \"" + arg + "\"")
f.write(")\n")
dump_dbg_env(f)
2019-07-29 17:49:26 +02:00
f.write("\t\"" + g_proton.wine_bin + "\" steam.exe \"${@:-${DEF_CMD[@]}}\"\n")
2018-10-24 21:22:22 +02:00
os.chmod(tmpdir + "run", 0o755)
def run():
if "PROTON_DUMP_DEBUG_COMMANDS" in env and nonzero(env["PROTON_DUMP_DEBUG_COMMANDS"]):
try:
dump_dbg_scripts()
2018-10-11 15:50:23 +02:00
except OSError:
log("Unable to write debug scripts! " + str(sys.exc_info()[1]))
2019-07-29 17:49:26 +02:00
run_wine([g_proton.wine_bin, "steam"] + sys.argv[2:])
if sys.version_info[0] == 2:
binary_stdout = sys.stdout
elif sys.version_info[0] == 3:
binary_stdout = sys.stdout.buffer
else:
2018-08-26 22:52:05 +02:00
raise Exception("Unsupported python version")
#determine mode
if sys.argv[1] == "run":
#start target app
run()
elif sys.argv[1] == "waitforexitandrun":
#wait for wineserver to shut down
2019-07-29 17:49:26 +02:00
run_wine([g_proton.wineserver_bin, "-w"])
#then run
run()
2018-02-20 14:41:39 +01:00
elif sys.argv[1] == "getcompatpath":
#linux -> windows path
2019-07-29 17:49:26 +02:00
path = subprocess.check_output([g_proton.wine_bin, "winepath", "-w", sys.argv[2]], env=env, stderr=lfile)
binary_stdout.write(path)
2018-02-20 14:41:39 +01:00
elif sys.argv[1] == "getnativepath":
#windows -> linux path
2019-07-29 17:49:26 +02:00
path = subprocess.check_output([g_proton.wine_bin, "winepath", sys.argv[2]], env=env, stderr=lfile)
binary_stdout.write(path)
2018-02-02 21:21:35 +01:00
else:
2018-02-15 20:06:32 +01:00
log("Need a verb.")
2018-02-02 21:21:35 +01:00
sys.exit(1)
2018-01-18 21:00:48 +01:00
sys.exit(0)
# vim: set syntax=python: