@ -1,3 +1,49 @@ | |||||
# steamproton-systemwine | |||||
# Steam games with system Wine, DXVK & D9VK | |||||
Use system-wide Wine, DXVK & D9VK for Steam Play/Proton (Windows) games, directly from Steam client. | |||||
Use system-wide Wine, DXVK & D9VK for Steam Play/Proton (Windows) games, directly from Steam client. | |||||
## Contents | |||||
- [files_wine](files_wine) = Necessary source code patches for Wine to make it Steam-compatible | |||||
- [files_archlinux](files_archlinux) = Necessary packages & installation scripts for system-wide, Steam-compatible Wine + DXVK + D9VK installation. NOTE: Wine files are provided in [files_wine](files_wine). | |||||
- [files_proton](files_proton) = Modified Python 3 launch script for Steam Play. The script is modified to use system-wide Wine + DXVK + D9VK + OpenVR libraries & executables instead of Steam-provided, bundled ones. | |||||
## Usage | |||||
**1)** Install Steam Client unless you haven't done so yet. | |||||
**2)** On Steam Client, install `Proton 4.2` (or any version above): `Steam Client -> LIBRARY -> Tools -> Proton 4.2 -> Install Game...` (skip this step if done already) | |||||
**3)** Compile & install Wine using patch files in [files_wine](files_wine). See [files_wine/README](files_wine/README.md) for additional information. | |||||
**4)** Compile & install all packages in [files_archlinux](files_archlinux). If provided, see `README.md` file of each package for additional information. | |||||
**5.A)** Apply modified [files_proton](files_proton/proton) Steam Play launch script. Put this file into `$HOME/.local/share/Steam/steamapps/common/Proton <version>/` where `<version>` is `4.2` or higher (depending on your configuration). | |||||
**5.B)** Select this specific Proton version in Steam client configuration menu (`Steam Client -> Settings -> Steam Play`). _This means system-wide Wine, DXVK & D9VK are used for your Steam Play games._ **Only selected version works** | |||||
Wine using patch files in [files_wine](files_wine). See [files_wine/README](files_wine/README.md) for additional information. | |||||
## Recommendations & Notes | |||||
- **Backup _proton_ script**. It is known that Steam client likes to apply automatic patches. Have a backup of your _proton_ script file in case the client decides to overwrite it. | |||||
- **Games may not work**. Games which work on Steam-bundled Proton may not work on this modified Wine/DXVK/D9VK configuration. In this case, either A) choose different Proton version for non-working game titles or B) revert _proton_ script changes. Original _proton_ script version `4.2` can be downloaded from [ValveSoftware/Proton - proton](https://github.com/ValveSoftware/Proton/blob/proton_4.2/proton). This script file restores original Steam Proton original functionality for the selected Proton version. | |||||
## LICENSE | |||||
This repository uses various licenses. | |||||
- [License (files_wine): ValveSoftware/Wine](https://github.com/ValveSoftware/wine/blob/proton_4.2/LICENSE) | |||||
- License (files_proton): | |||||
- [ValveSoftware/Proton/LICENSE](https://github.com/ValveSoftware/Proton/blob/proton_4.2/LICENSE) | |||||
- [ValveSoftware/Proton/LICENSE.proton](https://github.com/ValveSoftware/Proton/blob/proton_4.2/LICENSE.proton) | |||||
- License (files_archlinux): | |||||
- Subdirectories here provide only `PKGBUILD` compilation scripts for various packages. Licenses for these packages are listed in their respective `PKGBUILD` files. |
@ -0,0 +1,88 @@ | |||||
# Maintainer: Pekka Helenius <fincer89 [at] hotmail [dot] com> | |||||
# Contributor: Adrià Cereto i Massagué <ssorgatem at gmail.com> | |||||
pkgname=d9vk-git | |||||
pkgver=m0.12.r0.g6b125834 | |||||
pkgrel=1 | |||||
pkgdesc="A Vulkan-based compatibility layer for Direct3D 9 which allows running 3D applications on Linux using Wine" | |||||
url="https://github.com/Joshua-Ashton/d9vk" | |||||
license=('custom:zlib/libpng') | |||||
arch=('x86_64') | |||||
conflicts=( | |||||
'd9vk-bin' | |||||
'd9vk-mingw' | |||||
'd9vk-winelib' | |||||
'd9vk-mingw-git' | |||||
'd9vk-winelib-git' | |||||
) | |||||
depends=('wine' 'vulkan-icd-loader' 'lib32-vulkan-icd-loader') | |||||
makedepends=( | |||||
'ninja' | |||||
'meson>=0.43' | |||||
'glslang' | |||||
'git' | |||||
'wine' | |||||
) | |||||
provides=('d9vk') | |||||
source=(${pkgname}::"git+https://github.com/Joshua-Ashton/d9vk.git") | |||||
sha256sums=('SKIP' | |||||
'SKIP' | |||||
'b67f3a88115b1d048fb373ff6df2140c3027fe9edecccf58c1a88efce01fb738') | |||||
############################## | |||||
# Copy custom patches to correct location | |||||
p=0 | |||||
for patch in $(find . -mindepth 1 -maxdepth 1 -regex ".*\.\(patch\|diff\)$"); do | |||||
patches[$p]="$(basename ${patch})" | |||||
let p++ | |||||
done | |||||
unset p | |||||
source+=(${source[@]} ${patches[@]}) | |||||
# Reset git tree and apply custom patches | |||||
prepare() { | |||||
cd "${srcdir}/${pkgname}" | |||||
# Apply patches, if present | |||||
if [[ $(ls "${srcdir}"/*.{patch,diff} 2>/dev/null | wc -w) -ne 0 ]]; then | |||||
# Apply all custom patches | |||||
msg2 "Applying custom patches..." | |||||
for i in "${srcdir}"/*.{patch,diff}; do | |||||
if [[ -f ${i} ]]; then | |||||
patch -Np1 < ${i} | |||||
fi | |||||
done | |||||
fi | |||||
} | |||||
############################## | |||||
pkgver() { | |||||
cd "$srcdir/${pkgname}" | |||||
git describe --long --tags --always | sed 's/\([^-]*-g\)/r\1/;s/-/./g;s/v//g' | |||||
} | |||||
build() { | |||||
cd "$srcdir/${pkgname}" | |||||
./package-release.sh ${pkgver} build --no-package | |||||
} | |||||
package() { | |||||
mkdir -p "$pkgdir"/usr/share/dxvk/{x32,x64} | |||||
cd "$srcdir/${pkgname}" | |||||
install -m0644 build/dxvk-${pkgver}/x32/d3d9.dll "$pkgdir"/usr/share/dxvk/x32/d3d9.dll | |||||
install -m0644 build/dxvk-${pkgver}/x64/d3d9.dll "$pkgdir"/usr/share/dxvk/x64/d3d9.dll | |||||
install -m0755 build/dxvk-${pkgver}/setup_dxvk.sh "$pkgdir"/usr/share/dxvk/setup_d9vk.sh | |||||
mkdir "$pkgdir"/usr/bin | |||||
cd "$pkgdir"/usr/bin | |||||
ln -s /usr/share/dxvk/setup_d9vk.sh setup_d9vk | |||||
} |
@ -0,0 +1,10 @@ | |||||
--- a/setup_dxvk.sh | |||||
+++ b/setup_dxvk.sh | |||||
@@ -173,7 +173,3 @@ | |||||
fi | |||||
$action d3d9 | |||||
-$action d3d10 | |||||
-$action d3d10_1 | |||||
-$action d3d10core | |||||
-$action d3d11 |
@ -0,0 +1,87 @@ | |||||
# Maintainer: Pekka Helenius (~Fincer) <fincer89 at hotmail dot com> | |||||
# Contributor: Adrià Cereto i Massagué <ssorgatem at gmail.com> | |||||
pkgname=dxvk-git | |||||
_pkgname=dxvk | |||||
pkgver=1.2.1.4 | |||||
pkgrel=1 | |||||
pkgdesc="A Vulkan-based compatibility layer for Direct3D 10/11 which allows running 3D applications on Linux using Wine." | |||||
url="https://github.com/doitsujin/dxvk" | |||||
license=('custom:zlib/libpng') | |||||
arch=('x86_64') | |||||
conflicts=( | |||||
'dxvk-bin' | |||||
'dxvk-winelib-git' | |||||
'dxvk-legacy-git' | |||||
'dxvk-mingw-git' | |||||
) | |||||
depends=('wine' 'vulkan-icd-loader' 'lib32-vulkan-icd-loader') | |||||
makedepends=( | |||||
'ninja' | |||||
'meson>=0.43' | |||||
'glslang' | |||||
'mingw-w64-gcc' | |||||
'git' | |||||
'wine' | |||||
) | |||||
provides=('dxvk') | |||||
options=(!strip !buildflags staticlibs) | |||||
source=(${pkgname}::"git+https://github.com/doitsujin/dxvk.git") | |||||
sha256sums=('SKIP' | |||||
'SKIP') | |||||
############################## | |||||
p=0 | |||||
for patch in $(find . -mindepth 1 -maxdepth 1 -regex ".*\.\(patch\|diff\)$"); do | |||||
patches[$p]="$(basename ${patch})" | |||||
let p++ | |||||
done | |||||
unset p | |||||
source+=(${source[@]} ${patches[@]}) | |||||
# Reset git tree and apply custom patches | |||||
prepare() { | |||||
cd "${srcdir}/${pkgname}" | |||||
# Apply patches, if present | |||||
if [[ $(ls "${srcdir}"/*.{patch,diff} 2>/dev/null | wc -w) -ne 0 ]]; then | |||||
# Apply all custom patches | |||||
msg2 "Applying custom patches..." | |||||
for i in "${srcdir}"/*.{patch,diff}; do | |||||
if [[ -f ${i} ]]; then | |||||
patch -Np1 < ${i} | |||||
fi | |||||
done | |||||
fi | |||||
} | |||||
############################## | |||||
# Retrieve DXVK version tag | |||||
pkgver() { | |||||
cd "${pkgname}" | |||||
printf '%s' $(git describe --long --always | sed 's/\-[a-z].*//; s/\-/\./; s/[a-z]//g') | |||||
} | |||||
# Launch DXVK build script | |||||
build() { | |||||
"${srcdir}/${pkgname}"/package-release.sh ${pkgver} "${srcdir}"/build --no-package | |||||
} | |||||
# Bundle the compiled files | |||||
package() { | |||||
mkdir -p "${pkgdir}"/usr/{bin,share/dxvk} | |||||
cp -r "${srcdir}"/build/${_pkgname}-${pkgver}/* "${pkgdir}/usr/share/dxvk/" | |||||
echo -e "#!/bin/sh\n/usr/share/dxvk/setup_dxvk.sh" \ | |||||
> "${pkgdir}/usr/bin/setup_dxvk" | |||||
chmod +x "${pkgdir}/usr/bin/setup_dxvk" | |||||
} |
@ -0,0 +1,22 @@ | |||||
# Maintainer: Pekka Helenius <fincer89 [at] hotmail [dot] com> | |||||
pkgname=lib32-steamlibs | |||||
pkgver=4.2 | |||||
pkgrel=1 | |||||
pkgdesc='Proprietary Valve Steam client libraries for Wine (Proton)' | |||||
arch=('x86_64') | |||||
url='https://steampowered.com/' | |||||
license=('custom') | |||||
depends=('wine' 'steam') | |||||
source=( | |||||
'libsteam_api.so' | |||||
'steam.exe.so' | |||||
) | |||||
md5sums=('2b8113a13ad8409c916492b8b7cb061c' | |||||
'7c269269b9e3de1f780d7be81f910ba7') | |||||
package() { | |||||
mkdir -p "${pkgdir}/usr/lib32/wine" | |||||
install -Dm 644 -t "$pkgdir/usr/lib32/" libsteam_api.so | |||||
install -Dm 755 -t "$pkgdir/usr/lib32/wine/" steam.exe.so | |||||
} |
@ -0,0 +1,31 @@ | |||||
# Additional PKGBUILD files | |||||
The following files are required for this package. Due to legal reasons, these files are not provided here. Obtain these files from provided hyperlinks or existing Steam Proton file locations defined below. You can also extract these files directly from `proton_dist.tar.gz` archive. | |||||
The easiest way to install Proton is to use Steam client application. On the client, go to: | |||||
``` | |||||
LIBRARY -> TOOLS -> Proton <version> -> Install Game... | |||||
``` | |||||
Proton 4.2 or higher is required. | |||||
## libsteam_api.so | |||||
**Alternative A)** | |||||
Link: [GitHub - ValveSoftware/Proton - libsteam_api.so](https://github.com/ValveSoftware/Proton/raw/proton_4.2/steam_helper/libsteam_api.so) | |||||
**Alternative B)** | |||||
``` | |||||
$HOME/.local/share/Steam/steamapps/common/Proton <version>/dist/lib/libsteam_api.so | |||||
``` | |||||
## steam.exe.so | |||||
``` | |||||
$HOME/.local/share/Steam/steamapps/common/Proton <version>/dist/lib/wine/steam.exe.so | |||||
``` | |||||
ut these files in the same directory along provided lib32-steamlibs `PKGBUILD` file, after which you can build & install the package with `updpkgsums && makepkg -fi` command. |
@ -0,0 +1,39 @@ | |||||
From 1fd28b735d8abcc3fde9a4f5493407b5c0fcb91e Mon Sep 17 00:00:00 2001 | |||||
From: Christoph Haag <christoph.haag@collabora.com> | |||||
Date: Wed, 8 Aug 2018 01:06:29 +0200 | |||||
Subject: [PATCH] also add pragma pack around VRControllerState_t | |||||
See https://github.com/ValveSoftware/SteamVR-for-Linux/issues/35 | |||||
--- | |||||
headers/openvr_capi.h | 8 ++++++++ | |||||
1 file changed, 8 insertions(+) | |||||
diff --git a/headers/openvr_capi.h b/headers/openvr_capi.h | |||||
index 66da364..97906eb 100644 | |||||
--- a/headers/openvr_capi.h | |||||
+++ b/headers/openvr_capi.h | |||||
@@ -1206,6 +1206,11 @@ typedef struct VRControllerAxis_t | |||||
float y; | |||||
} VRControllerAxis_t; | |||||
+#if defined(__linux__) || defined(__APPLE__) | |||||
+// This structure was originally defined mis-packed on Linux, preserved for | |||||
+// compatibility. | |||||
+#pragma pack( push, 4 ) | |||||
+#endif | |||||
typedef struct VRControllerState_t | |||||
{ | |||||
uint32_t unPacketNum; | |||||
@@ -1213,6 +1218,9 @@ typedef struct VRControllerState_t | |||||
uint64_t ulButtonTouched; | |||||
struct VRControllerAxis_t rAxis[5]; //struct vr::VRControllerAxis_t[5] | |||||
} VRControllerState_t; | |||||
+#if defined(__linux__) || defined(__APPLE__) | |||||
+#pragma pack( pop ) | |||||
+#endif | |||||
typedef struct Compositor_OverlaySettings | |||||
{ | |||||
-- | |||||
2.18.0 | |||||
@ -0,0 +1,23 @@ | |||||
From 0fa21ba17748efcca1816536e27bdca70141b074 Mon Sep 17 00:00:00 2001 | |||||
From: Christoph Haag <haagch@frickel.club> | |||||
Date: Tue, 25 Jul 2017 02:07:09 +0200 | |||||
Subject: [PATCH] Use correct definition for vsprintf_s | |||||
defining it to sprintf actually segfaults in a release build. | |||||
--- | |||||
samples/shared/compat.h | 2 +- | |||||
1 file changed, 1 insertion(+), 1 deletion(-) | |||||
diff --git a/samples/shared/compat.h b/samples/shared/compat.h | |||||
index 154f8b0..28002d9 100644 | |||||
--- a/samples/shared/compat.h | |||||
+++ b/samples/shared/compat.h | |||||
@@ -12,7 +12,7 @@ | |||||
#include <unistd.h> | |||||
#define sprintf_s snprintf | |||||
-#define vsprintf_s sprintf | |||||
+#define vsprintf_s vsprintf | |||||
#define _stricmp strcmp | |||||
#define stricmp strcmp | |||||
#define strnicmp strncasecmp |
@ -0,0 +1,86 @@ | |||||
pkgname=openvr-git | |||||
pkgver=1.4.18.r0.g02bc73b | |||||
pkgrel=1 | |||||
pkgdesc="API and runtime that allows access to VR hardware from multiple vendors. Contains API and samples. The runtime is under SteamVR in Tools on Steam." | |||||
arch=('x86_64') | |||||
url="https://github.com/ValveSoftware/openvr" | |||||
license=('custom') | |||||
depends=('libgl' 'sdl2' 'glew') | |||||
optdepends=('oculus-udev: Udev rule to make the rift sensors usable to the "plugdev" group' | |||||
'steam: For SteamVR (Duh)' | |||||
'vive-udev: Udev rule to make the Vive sensors usable to the "plugdev" group') | |||||
makedepends=('git' 'cmake' 'qt5-base') #qt5 for the overlayexample | |||||
provides=("openvr") | |||||
options=('!strip' 'staticlibs') | |||||
source=("git+https://github.com/ValveSoftware/openvr.git" | |||||
'https://github.com/ValveSoftware/openvr/commit/0fa21ba17748efcca1816536e27bdca70141b074.patch' | |||||
'0001-also-add-pragma-pack-around-VRControllerState_t.patch') | |||||
md5sums=('SKIP' | |||||
'7350517830b1a0038d30c6ad33b4bb39' | |||||
'8a9379f8cdf9a38f21942f46378714a5') | |||||
pkgver() { | |||||
cd "$srcdir/openvr" | |||||
#echo $(git rev-list --count HEAD).$(git rev-parse --short HEAD) | |||||
git describe --long | sed 's/^v//;s/\([^-]*-g\)/r\1/;s/-/./g' | |||||
} | |||||
prepare() { | |||||
cd "$srcdir/openvr" | |||||
git apply ../0fa21ba17748efcca1816536e27bdca70141b074.patch #https://github.com/ValveSoftware/openvr/pull/594 | |||||
git apply ../0001-also-add-pragma-pack-around-VRControllerState_t.patch | |||||
} | |||||
build() { | |||||
#export CXX=clang++ | |||||
#export CC=clang | |||||
cd openvr | |||||
cmake -DBUILD_SHARED=0 -DCMAKE_INSTALL_PREFIX=/usr/ -DCMAKE_BUILD_TYPE=Release . | |||||
make | |||||
# Valve's build of libopenvr_api.so contains symbols that have no source code available | |||||
# See: https://github.com/ValveSoftware/openvr/issues/425 | |||||
#cmake -DBUILD_SHARED=1 -DCMAKE_INSTALL_PREFIX=/usr/ -DCMAKE_BUILD_TYPE=Release . | |||||
#make | |||||
cd samples | |||||
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr/ -Wno-dev . | |||||
make | |||||
} | |||||
package() { | |||||
#make install DESTDIR="$pkgdir" | |||||
#make install DESTDIR="$pkgdir" | |||||
install -d "$pkgdir"/usr/lib | |||||
install -m 555 openvr/bin/linux64/libopenvr_api.so "$pkgdir/usr/lib" | |||||
install -m 555 openvr/bin/linux64/libopenvr_api.a "$pkgdir/usr/lib" | |||||
#make install DESTDIR="$pkgdir" #There is no installer for the samples | |||||
install -d "$pkgdir/usr/bin" | |||||
install -d "$pkgdir/usr/shaders" | |||||
install -m 755 "$srcdir/openvr/samples/bin/linux64/hellovr_vulkan" "$pkgdir/usr/bin" | |||||
for shader in "$srcdir/openvr/samples/bin/shaders/"*.spv | |||||
do | |||||
install -m 755 "$shader" "$pkgdir/usr/shaders" | |||||
done | |||||
install -m 755 "$srcdir/openvr/samples/bin/linux64/hellovr_opengl" "$pkgdir/usr/bin" | |||||
install -m 755 "$srcdir/openvr/samples/bin/hellovr_actions.json" "$pkgdir/usr/" | |||||
install -m 755 "$srcdir/openvr/samples/bin/cube_texture.png" "$pkgdir/usr/" #TODO: fix source code to look in proper place | |||||
install -m 755 "$srcdir/openvr/samples/bin/linux64/helloworldoverlay" "$pkgdir/usr/bin" | |||||
install -m 755 "$srcdir/openvr/samples/bin/linux64/tracked_camera_openvr_sample" "$pkgdir/usr/bin" | |||||
#install -m 755 "$srcdir/build/samples/hellovr_opengl/run_hellovr.sh" "$pkgdir/usr/bin/run_hellovr.sh" | |||||
install -d "$pkgdir/usr/include/" | |||||
cp -ra "$srcdir/openvr/headers"/* "$pkgdir/usr/include/" | |||||
#install "$srcdir/openvr/headers"/* "$pkgdir/usr/include/" | |||||
} | |||||
# vim:set ts=2 sw=2 et: |
@ -0,0 +1,14 @@ | |||||
# Additional files | |||||
You should create file `` with the following contents: | |||||
``` | |||||
{ | |||||
"config" : [ "/home/<username>/.local/share/Steam/config/" ], | |||||
"external_drivers" : null, | |||||
"log" : [ "/home/<username>/.local/share/Steam/logs/" ], | |||||
"runtime" : [ "/home/<username>/.local/share/Steam/SteamApps/common/SteamVR" ] | |||||
} | |||||
``` | |||||
where `<username>` is user name of the Unix user which uses Steam client. |
@ -0,0 +1,17 @@ | |||||
diff --git a/samples/hellovr_opengl/hellovr_opengl_main.cpp b/samples/hellovr_opengl/hellovr_opengl_main.cpp | |||||
index 64d1d47..dac2e9f 100644 | |||||
--- a/samples/hellovr_opengl/hellovr_opengl_main.cpp | |||||
+++ b/samples/hellovr_opengl/hellovr_opengl_main.cpp | |||||
@@ -1276,6 +1276,12 @@ bool CMainApplication::SetupStereoRenderTargets() | |||||
return true; | |||||
} | |||||
+//http://www.g-truc.net/post-0708.html | |||||
+template <typename T, std::size_t N> | |||||
+constexpr std::size_t _countof(T const (&)[N]) noexcept | |||||
+{ | |||||
+return N; | |||||
+} | |||||
//----------------------------------------------------------------------------- | |||||
// Purpose: |
@ -0,0 +1,40 @@ | |||||
# Maintainer: Pekka Helenius <fincer89 [at] hotmail [dot] com> | |||||
pkgname=openvr-proton | |||||
pkgver=4.2 | |||||
pkgrel=1 | |||||
pkgdesc='DLL libraries for Valve Steam Proton & OpenVR platforms' | |||||
arch=('x86_64') | |||||
url='https://steampowered.com/' | |||||
license=('custom') | |||||
depends=('wine' 'steam' 'openvr-git' 'dxvk-git') | |||||
source=( | |||||
"32_vrclient.dll"::"file:///${startdir}/lib32/vrclient.dll" | |||||
"32_openvr_api_dxvk.dll"::"file:///${startdir}/lib32/openvr_api_dxvk.dll" | |||||
"64_vrclient_x64.dll"::"file:///${startdir}/lib64/vrclient_x64.dll" | |||||
"64_openvr_api_dxvk.dll"::"file:///${startdir}/lib64/openvr_api_dxvk.dll" | |||||
) | |||||
md5sums=('8c15e73e9963e600845c27f840380e92' | |||||
'14b755f2c6a58873a5f0410a2d8396c0' | |||||
'0b2025db24e3570d2a2732b035bb499a' | |||||
'8df23226245195205047694fc6aec654') | |||||
package() { | |||||
mkdir -p "${pkgdir}"/usr/{lib{32,64}/wine/fakedlls,/share/dxvk/x{32,64}} | |||||
cd "${srcdir}" | |||||
for dll in ./*.dll; do | |||||
for i in 32 64; do | |||||
dll_newname=$(echo $(basename "${dll}" | sed "s/^${i}\_//")) | |||||
if [[ $(echo $(basename "${dll}")) =~ ^${i} ]]; then | |||||
if [[ $(echo $(basename "${dll}")) =~ dxvk ]]; then | |||||
install -Dm644 "${dll}" "${pkgdir}/usr/share/dxvk/x${i}/${dll_newname}" | |||||
else | |||||
install -Dm644 "${dll}" "${pkgdir}/usr/lib${i}/wine/fakedlls/${dll_newname}" | |||||
fi | |||||
fi | |||||
done | |||||
done | |||||
} | |||||
@ -0,0 +1,36 @@ | |||||
# Additional PKGBUILD files | |||||
The following files are required for this package. Due to legal reasons, these files are not provided here. Obtain these files from existing Steam Proton file locations defined below or from other sources. You can also extract these files directly from `proton_dist.tar.gz` archive. | |||||
**1)** From `proton_dist.tar.gz` archive, obtain the files listed in `DLL file` column: | |||||
| DLL file | Target location | | |||||
|--------------------------------------|---------------------------| | |||||
| lib/wine/fakedlls/vrclient.dll | lib32/vrclient.dll | | |||||
| lib/wine/dxvk/openvr_api_dxvk.dll | lib32/openvr_api_dxvk.dll | | |||||
| lib64/wine/fakedlls/vrclient_x64.dll | lib64/vrclient_x64.dll | | |||||
| lib64/wine/dxvk/openvr_api_dxvk.dll | lib64/openvr_api_dxvk.dll | | |||||
**2)** Create two new subdirectories: `lib32`, `lib64`. Insert copied DLL files into respective locations defined in `Target location` column above. | |||||
**3)** Put these directories in the same location with your `openvr-proton` PKGBUILD. | |||||
**4)** Run `updpkgsums && makepkg -fi` | |||||
---------- | |||||
# Configuration files | |||||
You should create file `` with the following contents: | |||||
``` | |||||
{ | |||||
"config" : [ "/home/<username>/.local/share/Steam/config/" ], | |||||
"external_drivers" : null, | |||||
"log" : [ "/home/<username>/.local/share/Steam/logs/" ], | |||||
"runtime" : [ "/home/<username>/.local/share/Steam/SteamApps/common/SteamVR" ] | |||||
} | |||||
``` | |||||
where `<username>` is user name of the Unix user which uses Steam client. |
@ -0,0 +1,86 @@ | |||||
# Maintainer: Yurii Kolesnykov <root@yurikoles.com> | |||||
# Contributor: Sean Anderson <seanga2@gamil.com> | |||||
pkgname=proton-git | |||||
_pkgname=proton | |||||
pkgver=8.0 | |||||
pkgrel=1 | |||||
pkgdesc="Compatibility tool for Steam Play based on Wine and additional components" | |||||
arch=('x86_64') | |||||
url="https://github.com/ValveSoftware/Proton/" | |||||
license=('BSD') | |||||
depends=('python2' | |||||
'wine') | |||||
optdepends=() | |||||
provides=("${_pkgname}") | |||||
conflicts=("${_pkgname}") | |||||
source=("${pkgname}::git+https://github.com/ValveSoftware/Proton.git") | |||||
sha512sums=('SKIP') | |||||
pkgver() { | |||||
local version count | |||||
cd "${pkgname}" | |||||
version="$(git describe --abbrev=0 --tags)" | |||||
count="$(git rev-list --count ${version}..)" | |||||
printf '%s.%s' "${version#proton-*-}" "${count}" | |||||
} | |||||
prepare() { | |||||
cd "${pkgname}" | |||||
sed -i 's/openvr_v0.9.16//g' vrclient_x64/vrclient_x64/* | |||||
} | |||||
build() { | |||||
cd "${pkgname}" | |||||
export CXXFLAGS="$CXXFLAGS -Wno-attributes" | |||||
export WINEMAKEFLAGS="--nosource-fix --nolower-include --nodlls --nomsvcrt --dll" | |||||
export WINEMAKEFLAGS32="$WINEMAKEFLAGS --wine32" | |||||
# The build script provided has so much cruft that it's easier to make everything manually | |||||
mkdir -p build/lsteamclient.win32 | |||||
cp -a lsteamclient/* build/lsteamclient.win32 | |||||
cd build/lsteamclient.win32 | |||||
winemaker $WINEMAKEFLAGS32 -DSTEAM_API_EXPORTS . | |||||
make | |||||
cd ../.. | |||||
mkdir -p build/lsteamclient.win64 | |||||
cp -a lsteamclient/* build/lsteamclient.win64 | |||||
cd build/lsteamclient.win64 | |||||
winemaker $WINEMAKEFLAGS -DSTEAM_API_EXPORTS . | |||||
make | |||||
cd ../.. | |||||
# Currently depends on the custom bundled wine | |||||
# Will be re-enabled after I can make a package for it | |||||
#mkdir -p build/vrclient.win32 | |||||
#cp -a vrclient_x64/* build/vrclient.win32 | |||||
#cd build/vrclient.win32/vrclient_x64 | |||||
#winemaker $WINEMAKEFLAGS32 . | |||||
#CXXFLAGS="$CXXFLAGS --std=c++0x" make | |||||
#winebuild --dll --fake-module -E vrclient_64.spec -o vrclient.dll.fake | |||||
} | |||||
package() { | |||||
cd "${pkgname}" | |||||
install -d -m755 $pkgdir/usr/share/licenses/$pkgname | |||||
install -m644 LICENSE $pkgdir/usr/share/licenses/$pkgname/LICENSE | |||||
install -m644 LICENSE.proton $pkgdir/usr/share/licenses/$pkgname/LICENSE.proton | |||||
install -m644 dist.LICENSE $pkgdir/usr/share/licenses/$pkgname/dist.LICENSE | |||||
install -d -m755 $pkgdir/usr/share/doc/$pkgname | |||||
install -m644 README.md $pkgdir/usr/share/doc/$pkgname/README.md | |||||
install -d -m755 $pkgdir/usr/lib32/wine | |||||
install -m755 build/lsteamclient.win32/lsteamclient.dll.so $pkgdir/usr/lib32/wine/ | |||||
#install build/vrclient.win32/vrclient.dll.so $pkgdir/usr/lib32/wine/ | |||||
#install -d $pkgdir/usr/lib32/wine/fakedlls | |||||
#install build/vrclient.win32/vrclient.dll.fake $pkgdir/lib/wine/fakedlls/vrclient.dll | |||||
install -d -m755 $pkgdir/usr/lib/wine | |||||
install -m755 build/lsteamclient.win64/lsteamclient.dll.so $pkgdir/usr/lib/wine/ | |||||
} |
@ -0,0 +1,95 @@ | |||||
# Maintainer: Pekka Helenius <fincer89 [at] hotmail [dot] com> | |||||
# Contributor: Levente Polyak <anthraxx[at]archlinux[dot]org> | |||||
# Contributor: Daniel Wallace <danielwallace at gtmanfred dot com> | |||||
# Contributor: K900 <k0009000@gmail.com> | |||||
pkgname=steam | |||||
pkgver=1.0.0.61 | |||||
pkgrel=2 | |||||
pkgdesc="Valve's digital software delivery system" | |||||
url='http://steampowered.com/' | |||||
arch=('x86_64') | |||||
license=('custom') | |||||
depends=( | |||||
'bash' | |||||
'desktop-file-utils' | |||||
'hicolor-icon-theme' | |||||
'curl' | |||||
'dbus' | |||||
'freetype2' | |||||
'ttf-font' | |||||
'ttf-liberation' | |||||
'wine' | |||||
'proton-git' | |||||
'openvr-git' | |||||
'openvr-proton' | |||||
'lib32-steamlibs' | |||||
'dxvk-git' | |||||
'd9vk-git' | |||||
) | |||||
depends_x86_64=( | |||||
'lib32-libgl' | |||||
'lib32-gcc-libs' | |||||
'lib32-libx11' | |||||
'lib32-libxss' | |||||
'lib32-alsa-plugins' | |||||
'lib32-gtk2' | |||||
'lib32-gdk-pixbuf2' | |||||
'lib32-libvdpau' | |||||
'lib32-libva1' | |||||
) | |||||
optdepends=('steam-native-runtime: steam native runtime support') | |||||
#source=(http://repo.steampowered.com/${pkgname}/pool/${pkgname}/s/${pkgname}/${pkgname}_${pkgver}.tar.gz | |||||
source=(${pkgname}_${pkgver}.tar.gz | |||||
steam-runtime.sh | |||||
steam-native.sh | |||||
alsa_sdl_audiodriver.patch) | |||||
sha512sums=('14b4e2d10953dea7e062205f986d95ea46f0791a964c0dcfac905b707da55b25142cb2bc056c5488e0309f7ef4521b44f1540ce14617deb5f1df57a8fd1f723e' | |||||
'da40f8e814f547f6a14901d753a2ffed1a4cf83df9200ee86e83a470b57b3103c3fbfb7cc77166ff1db646cbb306d6a41e79450cc1ea113d68a2defc55168ee2' | |||||
'32a12cb011eff4d9d4caf54a5c04f622b6301977258e86597be9c4622f87b0ea329bb31e963ecb56ce738ccc2e4d1068fb2b65bdd5ac1758bcd25296d4dab6d6' | |||||
'5c6117d86cb95071246434851bae3bf7d1c2174b0c8744e33e9c98ccc22efae0c956e1d7e3969c572aa96259b1b8164992d265541bce49a24daa12555d825fd5') | |||||
prepare() { | |||||
cd ${pkgname} | |||||
patch -Np1 < "${srcdir}/alsa_sdl_audiodriver.patch" | |||||
# apply roundups for udev rules | |||||
# sed -r 's|("0666")|"0660", TAG+="uaccess"|g' -i lib/udev/rules.d/99-steam-controller-perms.rules | |||||
# sed -r 's|("misc")|\1, OPTIONS+="static_node=uinput"|g' -i lib/udev/rules.d/99-steam-controller-perms.rules | |||||
# sed -r 's|(, TAG\+="uaccess")|, MODE="0660"\1|g' -i lib/udev/rules.d/60-steam-vr.rules | |||||
# separated runtime/native desktop files | |||||
cp steam{,-native}.desktop | |||||
sed -r 's|(Name=Steam)|\1 (Runtime)|' -i steam.desktop | |||||
sed -r 's|(/usr/bin/steam)|\1-runtime|' -i steam.desktop | |||||
sed -r 's|(Name=Steam)|\1 (Native)|' -i steam-native.desktop | |||||
sed -r 's|(/usr/bin/steam)|\1-native|' -i steam-native.desktop | |||||
} | |||||
package() { | |||||
cd ${pkgname} | |||||
make DESTDIR="${pkgdir}" install | |||||
install -Dm 755 "${srcdir}/steam-runtime.sh" "${pkgdir}/usr/bin/steam-runtime" | |||||
install -Dm 755 "${srcdir}/steam-native.sh" "${pkgdir}/usr/bin/steam-native" | |||||
install -d "${pkgdir}/usr/lib/steam" | |||||
mv "${pkgdir}/usr/bin/steam" "${pkgdir}/usr/lib/steam/steam" | |||||
ln -sf /usr/bin/steam-runtime "${pkgdir}/usr/bin/steam" | |||||
install -Dm 644 steam-native.desktop -t "${pkgdir}/usr/share/applications" | |||||
# install -Dm 644 "${pkgdir}/usr/share/doc/steam/steam_install_agreement.txt" \ | |||||
# "${pkgdir}/usr/share/licenses/steam/LICENSE" | |||||
install -Dm 644 debian/changelog -t "${pkgdir}/usr/share/doc/${pkgname}" | |||||
# blank steamdeps because apt-get | |||||
ln -sf /usr/bin/true "${pkgdir}/usr/bin/steamdeps" | |||||
install -Dm 644 lib/udev/rules.d/60-steam-input.rules \ | |||||
"${pkgdir}/usr/lib/udev/rules.d/60-steam-input.rules" | |||||
install -Dm 644 lib/udev/rules.d/60-steam-vr.rules \ | |||||
"${pkgdir}/usr/lib/udev/rules.d/70-steam-vr.rules" | |||||
} | |||||
# vim: ts=2 sw=2 et: |
@ -0,0 +1,14 @@ | |||||
--- a/steam 2013-02-15 14:43:40.000000000 -0500 | |||||
+++ b/steam 2013-02-17 23:26:31.951179106 -0500 | |||||
@@ -17,6 +17,11 @@ | |||||
# Set up domain for script localization | |||||
export TEXTDOMAIN=steam | |||||
+# check if pulseaudio is installed and if it isn't, use alsa for SDL_AUDIODRIVER | |||||
+if ! pulseaudio --check &>/dev/null; then | |||||
+ export SDL_AUDIODRIVER=alsa | |||||
+fi | |||||
+ | |||||
function show_message() | |||||
{ | |||||
style=$1 |
@ -0,0 +1,8 @@ | |||||
#!/bin/sh | |||||
export STEAM_RUNTIME=0 | |||||
# Workaround for dbus fatal termination related coredumps (SIGABRT) | |||||
# https://github.com/ValveSoftware/steam-for-linux/issues/4464 | |||||
export DBUS_FATAL_WARNINGS=0 | |||||
# Override some libraries as these are what games linked against. | |||||
export LD_LIBRARY_PATH="/usr/lib/steam:/usr/lib32/steam${LD_LIBRARY_PATH:+:}$LD_LIBRARY_PATH" | |||||
exec /usr/lib/steam/steam "$@" |
@ -0,0 +1,4 @@ | |||||
#!/bin/sh | |||||
# Override some libraries to avoid incompatibillity | |||||
export LD_PRELOAD='/usr/$LIB/libstdc++.so.6 /usr/$LIB/libgcc_s.so.1 /usr/$LIB/libxcb.so.1 /usr/$LIB/libgpg-error.so' | |||||
exec /usr/lib/steam/steam "$@" |
@ -0,0 +1,12 @@ | |||||
Copyright (c) 2018, Valve Corporation | |||||
All rights reserved. | |||||
Redistribution and use of Proton in source and binary forms is governed | |||||
by a variety of licenses. | |||||
Refer to the contents of LICENCE.proton for the license for the top | |||||
level contents of the Proton project. | |||||
Proton uses a variety of other software, each of which is governed | |||||
by its own license. Those licenses are contained in a file named | |||||
LICENSE or COPYING in each directory. |
@ -0,0 +1,27 @@ | |||||
Copyright (c) 2018, Valve Corporation | |||||
All rights reserved. | |||||
Redistribution and use in source and binary forms, with or without modification, | |||||
are permitted provided that the following conditions are met: | |||||
1. Redistributions of source code must retain the above copyright notice, this | |||||
list of conditions and the following disclaimer. | |||||
2. Redistributions in binary form must reproduce the above copyright notice, | |||||
this list of conditions and the following disclaimer in the documentation and/or | |||||
other materials provided with the distribution. | |||||
3. Neither the name of the copyright holder nor the names of its contributors | |||||
may be used to endorse or promote products derived from this software without | |||||
specific prior written permission. | |||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND | |||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | |||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR | |||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON | |||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
@ -0,0 +1,648 @@ | |||||
#!/usr/bin/env python3 | |||||
#script to launch Wine with the correct environment | |||||
#################### | |||||
# System-wide Wine for Steam client (Proton/Steam Play) games with system-wide DXVK & D9VK support | |||||
# | |||||
# Put this file into | |||||
# $HOME/.local/share/Steam/steamapps/common/Proton <version>/ | |||||
# | |||||
# Select this specific Proton version in Steam client configuration menu | |||||
# (Steam Client -> Settings -> Steam Play). | |||||
# This means system-wide Wine, DXVK & D9VK are used for your Steam Play games. | |||||
#################### | |||||
# LICENSE | |||||
# https://github.com/ValveSoftware/Proton/blob/proton_4.2/LICENSE | |||||
# https://github.com/ValveSoftware/Proton/blob/proton_4.2/LICENSE.proton | |||||
# | |||||
#################### | |||||
# ORIGINAL SOURCE CODE | |||||
# https://github.com/ValveSoftware/Proton/blob/proton_4.2/proton | |||||
# | |||||
from __future__ import print_function | |||||
import filecmp | |||||
import json | |||||
import os | |||||
import shutil | |||||
import errno | |||||
import struct | |||||
import subprocess | |||||
import sys | |||||
import tarfile | |||||
from filelock import FileLock | |||||
#To enable debug logging, copy "user_settings.sample.py" to "user_settings.py" | |||||
#and edit it if needed. | |||||
CURRENT_PREFIX_VERSION="4.2-5" | |||||
PFX="Proton: " | |||||
ld_path_var = "LD_LIBRARY_PATH" | |||||
def nonzero(s): | |||||
return len(s) > 0 and s != "0" | |||||
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 | |||||
log("Upgrading prefix from " + str(old_ver) + " to " + CURRENT_PREFIX_VERSION + " (" + os.environ["STEAM_COMPAT_DATA_PATH"] + ")") | |||||
if old_ver is None: | |||||
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 | |||||
try_copy(proton_basedir + "/proton_3.7_tracked_files", os.environ["STEAM_COMPAT_DATA_PATH"] + "/tracked_files") | |||||
remove_tracked_files(os.environ["STEAM_COMPAT_DATA_PATH"]) | |||||
return | |||||
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 | |||||
lfile = None | |||||
def run_wine(args): | |||||
subprocess.call(args, env=env, stderr=lfile, stdout=lfile) | |||||
def makedirs(path): | |||||
try: | |||||
os.makedirs(path) | |||||
except OSError: | |||||
#already exists | |||||
pass | |||||
def try_copy(src, dst): | |||||
try: | |||||
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") | |||||
if not "STEAM_COMPAT_DATA_PATH" in os.environ: | |||||
log("No compat data path?") | |||||
sys.exit(1) | |||||
basedir = "/" | |||||
bindir = "/usr/bin" | |||||
libdir = "/usr/lib32" | |||||
lib64dir = "/usr/lib" | |||||
fontsdir = "/usr/share/fonts/TTF" | |||||
wine_path = bindir + "/wine" | |||||
proton_basedir = os.path.dirname(sys.argv[0]) | |||||
default_prefixdir = proton_basedir + "/default_pfx" | |||||
dxvkdir = "/usr/share/dxvk/x32" | |||||
dxvk64dir = "/usr/share/dxvk/x64" | |||||
env = dict(os.environ) | |||||
dlloverrides = {"steam.exe": "b"} #always use our special built-in steam.exe | |||||
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" | |||||
env.pop("WINEARCH", "") | |||||
if ld_path_var in os.environ: | |||||
env[ld_path_var] = lib64dir + ":" + libdir + ":" + os.environ[ld_path_var] | |||||
else: | |||||
env[ld_path_var] = lib64dir + ":" + libdir | |||||
env["WINEDLLPATH"] = lib64dir + "/wine:" + libdir + "/wine" | |||||
if "PATH" in os.environ: | |||||
env["PATH"] = bindir + ":" + os.environ["PATH"] | |||||
else: | |||||
env["PATH"] = bindir | |||||
if not os.path.isdir(default_prefixdir): | |||||
#make default prefix | |||||
env["WINEPREFIX"] = default_prefixdir | |||||
run_wine([wine_path, "wineboot"]) | |||||
run_wine([bindir + "/wineserver", "-w"]) | |||||
prefix = os.environ["STEAM_COMPAT_DATA_PATH"] + "/pfx/" | |||||
env["WINEPREFIX"] = prefix | |||||
if "PROTON_LOG" in env and nonzero(env["PROTON_LOG"]): | |||||
env["WINEDEBUG"] = "+timestamp,+pid,+tid,+seh,+debugstr,+loaddll,+mscoree" | |||||
env["DXVK_LOG_LEVEL"] = "info" | |||||
env["WINE_MONO_TRACE"] = "E:System.NotImplementedException" | |||||
#default wine-mono override for FNA games | |||||
env["WINE_MONO_OVERRIDES"] = "Microsoft.Xna.Framework.*,Gac=n" | |||||
#load environment overrides | |||||
if os.path.exists(proton_basedir + "/user_settings.py"): | |||||
try: | |||||
import user_settings | |||||
env.update(user_settings.user_settings) | |||||
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: | |||||
return False | |||||
if nonzero(env[env_name]): | |||||
config_opts.add(config_name) | |||||
else: | |||||
config_opts.discard(config_name) | |||||
return True | |||||
if "STEAM_COMPAT_CONFIG" in os.environ: | |||||
config_opts = set(os.environ["STEAM_COMPAT_CONFIG"].split(",")) | |||||
else: | |||||
config_opts = set() | |||||
if "wined3d11" in config_opts: | |||||
config_opts.add("wined3d") | |||||
if not check_environment("PROTON_USE_WINED3D", "wined3d"): | |||||
check_environment("PROTON_USE_WINED3D11", "wined3d") | |||||
check_environment("PROTON_NO_D3D11", "nod3d11") | |||||
check_environment("PROTON_NO_D3D10", "nod3d10") | |||||
check_environment("PROTON_NO_D3D9", "nod3d9") | |||||
check_environment("PROTON_NO_ESYNC", "noesync") | |||||
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 "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" | |||||
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") | |||||
with open(basedir + "/version", "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("======================\n") | |||||
lfile.flush() | |||||
else: | |||||
env["WINEDEBUG"] = "-all" | |||||
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) | |||||
for p in fontsmap: | |||||
lname = os.path.join(windowsfonts, p[1]) | |||||
fname = os.path.join(fontsdir, p[0]) | |||||
if os.path.lexists(lname): | |||||
if os.path.islink(lname): | |||||
os.remove(lname) | |||||
os.symlink(fname, lname) | |||||
else: | |||||
os.symlink(fname, lname) | |||||
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 + "/user.reg"): | |||||
#copy default prefix into place | |||||
with open(os.environ["STEAM_COMPAT_DATA_PATH"] + "/tracked_files", "w") as tfiles: | |||||
mergedirs(default_prefixdir, prefix, tfiles) | |||||
with open(version_file, "w") as f: | |||||
f.write(CURRENT_PREFIX_VERSION + "\n") | |||||
#create font files symlinks | |||||
create_fonts_symlinks(prefix) | |||||
#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) | |||||
#copy openvr files into place | |||||
dst = prefix + "/drive_c/vrclient/bin/" | |||||
makedirs(dst) | |||||
try_copy(libdir + "/wine/fakedlls/vrclient.dll", dst) | |||||
try_copy(lib64dir + "/wine/fakedlls/vrclient_x64.dll", dst) | |||||
try_copy(dxvkdir + "/openvr_api_dxvk.dll", prefix + "/drive_c/windows/syswow64/") | |||||
try_copy(dxvk64dir + "/openvr_api_dxvk.dll", prefix + "/drive_c/windows/system32/") | |||||
#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: | |||||
path = os.environ.get("XDG_CONFIG_HOME", os.environ["HOME"] + "/.config") | |||||
path = path + "/openvr/openvrpaths.vrpath" | |||||
with open(path, "r") as jfile: | |||||
j = json.load(jfile) | |||||
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])) | |||||
makedirs(prefix + "/drive_c/users/" + os.environ["USER"] + "/Local Settings/Application Data/openvr") | |||||
#remove existing file | |||||
vrpaths_name = prefix + "/drive_c/users/" + os.environ["USER"] + "/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=lfile).decode("utf-8") | |||||
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=lfile).decode("utf-8") | |||||
j["log"] = [ win_vr_log.strip() ] | |||||
j["version"] = 1 | |||||
j["jsonid"] = "vrpathreg" | |||||
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])) | |||||
dxvkfiles = ("d3d11", "d3d10", "d3d10core", "d3d10_1", "dxgi", "d3d9") | |||||
def make_dxvk_links(dll_dir, link_dir): | |||||
for f in dxvkfiles: | |||||
dst = link_dir + "/" + f + ".dll" | |||||
src = dll_dir + "/" + f + ".dll" | |||||
if os.path.lexists(dst): | |||||
os.remove(dst) | |||||
os.symlink(src, dst) | |||||
if "wined3d" in config_opts: | |||||
#use gl-based wined3d for d3d11, d3d10 and d3d9 | |||||
make_dxvk_links(lib64dir + "/wine/fakedlls/", | |||||
prefix + "drive_c/windows/system32") | |||||
make_dxvk_links(libdir + "/wine/fakedlls/", | |||||
prefix + "drive_c/windows/syswow64") | |||||
else: | |||||
#use vulkan-based dxvk for d3d11, d3d10 and d3d9 | |||||
make_dxvk_links(dxvk64dir, | |||||
prefix + "drive_c/windows/system32") | |||||
make_dxvk_links(dxvkdir, | |||||
prefix + "drive_c/windows/syswow64") | |||||
for f in dxvkfiles: | |||||
dlloverrides[f] = "n" | |||||
if "nod3d11" in config_opts: | |||||
dlloverrides["d3d11"] = "" | |||||
if "dxgi" in dlloverrides: | |||||
del dlloverrides["dxgi"] | |||||
if "nod3d10" in config_opts: | |||||
dlloverrides["d3d10_1"] = "" | |||||
dlloverrides["d3d10"] = "" | |||||
dlloverrides["dxgi"] = "" | |||||
if "nod3d9" in config_opts: | |||||
dlloverrides["d3d9"] = "" | |||||
s = "" | |||||
for dll in dlloverrides: | |||||
setting = dlloverrides[dll] | |||||
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 | |||||
def dump_dbg_env(f): | |||||
f.write("PATH=\"" + env["PATH"] + "\" \\\n") | |||||
f.write("\tTERM=\"xterm\" \\\n") #XXX | |||||
f.write("\tWINEDEBUG=\"-all\" \\\n") | |||||
f.write("\tWINEDLLPATH=\"" + env["WINEDLLPATH"] + "\" \\\n") | |||||
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") | |||||
def dump_dbg_scripts(): | |||||
exe_name = os.path.basename(sys.argv[2]) | |||||
tmpdir = env.get("PROTON_DEBUG_DIR", "/tmp") + "/proton_" + os.environ["USER"] + "/" | |||||
makedirs(tmpdir) | |||||
with open(tmpdir + "winedbg", "w") as f: | |||||
f.write("#!/bin/bash\n") | |||||
f.write("#Run winedbg with args\n\n") | |||||
f.write("cd \"" + os.getcwd() + "\"\n") | |||||
dump_dbg_env(f) | |||||
f.write("\t\"" + wine_path + "\" winedbg \"$@\"\n") | |||||
os.chmod(tmpdir + "winedbg", 0o755) | |||||
with open(tmpdir + "winedbg_run", "w") as f: | |||||
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) | |||||
f.write("\t\"" + wine_path + "\" winedbg \"${@:-${DEF_CMD[@]}}\"\n") | |||||
os.chmod(tmpdir + "winedbg_run", 0o755) | |||||
with open(tmpdir + "gdb_attach", "w") as f: | |||||
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") | |||||
f.write("WPID_HEX=$(\"" + tmpdir + "winedbg\" --command 'info process' | grep -i \"$EXE_NAME\" | cut -f2 -d' ' | tr -d '0')\n") | |||||
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) | |||||
f.write("\t\"" + wine_path + "\" winedbg --gdb $WPID_DEC\n") | |||||
os.chmod(tmpdir + "gdb_attach", 0o755) | |||||
with open(tmpdir + "gdb_run", "w") as f: | |||||
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) | |||||
f.write("\t\"" + wine_path + "\" winedbg --gdb \"${@:-${DEF_CMD[@]}}\"\n") | |||||
os.chmod(tmpdir + "gdb_run", 0o755) | |||||
with open(tmpdir + "run", "w") as f: | |||||
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) | |||||
f.write("\t\"" + wine_path + "\" steam.exe \"${@:-${DEF_CMD[@]}}\"\n") | |||||
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() | |||||
except OSError: | |||||
log("Unable to write debug scripts! " + str(sys.exc_info()[1])) | |||||
run_wine([wine_path, "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: | |||||
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 | |||||
run_wine([bindir + "/wineserver", "-w"]) | |||||
#then run | |||||
run() | |||||
elif sys.argv[1] == "getcompatpath": | |||||
#linux -> windows path | |||||
path = subprocess.check_output([wine_path, "winepath", "-w", sys.argv[2]], env=env, stderr=lfile) | |||||
binary_stdout.write(path) | |||||
elif sys.argv[1] == "getnativepath": | |||||
#windows -> linux path | |||||
path = subprocess.check_output([wine_path, "winepath", sys.argv[2]], env=env, stderr=lfile) | |||||
binary_stdout.write(path) | |||||
else: | |||||
log("Need a verb.") | |||||
sys.exit(1) | |||||
sys.exit(0) | |||||
# vim: set syntax=python: |
@ -0,0 +1,28 @@ | |||||
# Steam Proton patches for system Wine | |||||
The included patch files hook necessary Steam libraries into Wine process, allowing Steam games to detect Steam client presence. Without these patches, it is impossible/difficult to run Steam client with system Wine. | |||||
Original patch code by Valve Corporation. Respective source code links are provided in headers of the provided patch files. | |||||
Patch name syntax: | |||||
``` | |||||
patch_steamproton_<number>_<dll-component>_wine<wine-version>_<staging|nostaging>.patch | |||||
``` | |||||
For instance: | |||||
| Patch file | Description | | |||||
|-------------------------------------------------------|----------------------------------------------------------------------------------------| | |||||
| patch_steamproton_01_kernel32_wine4.9_staging.patch | Patch file targeted to DLL component `kernel32`, Wine version 4.9, vanilla/non-staging | | |||||
| patch_steamproton_01_kernel32_wine4.9_nostaging.patch | Patch file targeted to DLL component `kernel32`, Wine version 4.9, staging | | |||||
## How-to | |||||
Apply the provided patches directly to Wine source code, and compile + install Wine. | |||||
On Arch Linux, you can use helper scripts such as [Fincer/dxvk-wine-autobuilder](https://github.com/Fincer/dxvk-wine-autobuilder) or add patches manually to your Wine `PKGBUILD` file. | |||||
## LICENSE | |||||
Please see license [here (ValveSoftware/Wine - Proton 4.2)](https://github.com/ValveSoftware/wine/blob/proton_4.2/LICENSE) |
@ -0,0 +1,209 @@ | |||||
Original patch code by Valve Corporation | |||||
Original commits: | |||||
https://github.com/ValveSoftware/wine/commit/45a30e45c6ba6f0a28e2df4107d2e73203e97c64 | |||||
https://github.com/ValveSoftware/wine/commit/46759f772e5e82e1c063c93d743fafa018f406b2 | |||||
https://github.com/ValveSoftware/wine/commit/667994216734d72e2b9a4df268aae87bd8189d43 | |||||
https://github.com/ValveSoftware/wine/commit/050f036aa031322e4f32ffd9b4a90edb24b78609 | |||||
https://github.com/ValveSoftware/wine/commit/647086c049ac7e05750bf01c1cdb5a37f436a558 | |||||
https://github.com/ValveSoftware/wine/commit/6a02230c44b7a26422fdb6d4edbb8bcbc2f3d035 | |||||
LICENSE: See https://github.com/ValveSoftware/wine | |||||
Target Wine version of this patch file: | |||||
Wine 4.9 (Vanilla/Non-staging) | |||||
--- a/dlls/kernel32/module.c | |||||
+++ b/dlls/kernel32/module.c | |||||
@@ -77,6 +77,32 @@ static CRITICAL_SECTION_DEBUG critsect_d | |||||
}; | |||||
static CRITICAL_SECTION dlldir_section = { &critsect_debug, -1, 0, 0, 0, 0 }; | |||||
+#if defined(__x86_64__) | |||||
+static const WCHAR steamclientW[] = {'s','t','e','a','m','c','l','i','e','n','t','6','4',0}; | |||||
+static const WCHAR steamclient_pathW[] = {'C',':','\\','P','r','o','g','r','a','m',' ','F','i','l','e','s',' ','(','x','8','6',')','\\','S','t','e','a','m','\\','s','t','e','a','m','c','l','i','e','n','t','6','4','.','d','l','l',0}; | |||||
+#else | |||||
+static const WCHAR steamclientW[] = {'s','t','e','a','m','c','l','i','e','n','t',0}; | |||||
+static const WCHAR steamclient_pathW[] = {'C',':','\\','P','r','o','g','r','a','m',' ','F','i','l','e','s',' ','(','x','8','6',')','\\','S','t','e','a','m','\\','s','t','e','a','m','c','l','i','e','n','t','.','d','l','l',0}; | |||||
+#endif | |||||
+static const WCHAR steamProgramPathW[] = {'C',':','\\','P','r','o','g','r','a','m',' ','F','i','l','e','s',' ','(','x','8','6',')','\\','S','t','e','a','m',0}; | |||||
+static const DWORD steamProgramPathW_len = 28; | |||||
+static const WCHAR steamdllW[] = {'S','t','e','a','m','.','d','l','l',0}; | |||||
+static const DWORD steamdllW_len = 9; | |||||
+static HMODULE steamclient_hmod = NULL; | |||||
+static HMODULE lsteamclient_hmod = NULL; | |||||
+ | |||||
+static WCHAR *strcasestrW( const WCHAR *str, const WCHAR *sub ) | |||||
+{ | |||||
+ while (*str) | |||||
+ { | |||||
+ const WCHAR *p1 = str, *p2 = sub; | |||||
+ while (*p1 && *p2 && tolowerW(*p1) == tolowerW(*p2)) { p1++; p2++; } | |||||
+ if (!*p2) return (WCHAR *)str; | |||||
+ str++; | |||||
+ } | |||||
+ return NULL; | |||||
+} | |||||
+ | |||||
/**************************************************************************** | |||||
* GetDllDirectoryA (KERNEL32.@) | |||||
*/ | |||||
@@ -445,10 +471,16 @@ BOOL WINAPI GetModuleHandleExW( DWORD fl | |||||
{ | |||||
void *dummy; | |||||
if (!(ret = RtlPcToFileHeader( (void *)name, &dummy ))) status = STATUS_DLL_NOT_FOUND; | |||||
+ if(steamclient_hmod != NULL && ret == lsteamclient_hmod) | |||||
+ ret = steamclient_hmod; | |||||
} | |||||
else | |||||
{ | |||||
UNICODE_STRING wstr; | |||||
+ if(steamclient_hmod != NULL && strcasestrW(name, steamclientW)){ | |||||
+ *module = steamclient_hmod; | |||||
+ return TRUE; | |||||
+ } | |||||
RtlInitUnicodeString( &wstr, name ); | |||||
status = LdrGetDllHandle( NULL, 0, &wstr, &ret ); | |||||
} | |||||
@@ -557,6 +589,11 @@ DWORD WINAPI GetModuleFileNameW( HMODULE | |||||
NTSTATUS nts; | |||||
WIN16_SUBSYSTEM_TIB *win16_tib; | |||||
+ if(steamclient_hmod != NULL && hModule == steamclient_hmod){ | |||||
+ memcpy(lpFileName, steamclient_pathW, sizeof(steamclient_pathW)); | |||||
+ return sizeof(steamclient_pathW)/sizeof(WCHAR); | |||||
+ } | |||||
+ | |||||
if (!hModule && ((win16_tib = NtCurrentTeb()->Tib.SubSystemTib)) && win16_tib->exe_name) | |||||
{ | |||||
len = min(size, win16_tib->exe_name->Length / sizeof(WCHAR)); | |||||
@@ -600,11 +637,15 @@ static const WCHAR *get_dll_system_path( | |||||
if (!cached_path) | |||||
{ | |||||
WCHAR *p, *path; | |||||
- int len = 1; | |||||
+ int len = 2; | |||||
+ len += steamProgramPathW_len; | |||||
len += 2 * GetSystemDirectoryW( NULL, 0 ); | |||||
len += GetWindowsDirectoryW( NULL, 0 ); | |||||
p = path = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ); | |||||
+ strcpyW(p, steamProgramPathW); | |||||
+ p += steamProgramPathW_len; | |||||
+ *p++ = ';'; | |||||
GetSystemDirectoryW( p, path + len - p); | |||||
p += strlenW(p); | |||||
/* if system directory ends in "32" add 16-bit version too */ | |||||
@@ -933,6 +974,7 @@ static HMODULE load_library( const UNICO | |||||
NTSTATUS nts; | |||||
HMODULE hModule; | |||||
WCHAR *load_path; | |||||
+ const WCHAR *p; | |||||
const DWORD load_library_search_flags = (LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR | | |||||
LOAD_LIBRARY_SEARCH_APPLICATION_DIR | | |||||
LOAD_LIBRARY_SEARCH_USER_DIRS | | |||||
@@ -946,6 +988,36 @@ static HMODULE load_library( const UNICO | |||||
if( flags & unsupported_flags) | |||||
FIXME("unsupported flag(s) used (flags: 0x%08x)\n", flags); | |||||
+ if((p = strcasestrW(libname->Buffer, steamclientW)) && | |||||
+ (p == libname->Buffer || | |||||
+ *(p - 1) != 'l')){ | |||||
+ | |||||
+ if(!lsteamclient_hmod) | |||||
+ lsteamclient_hmod = LoadLibraryA("lsteamclient.dll"); | |||||
+ | |||||
+ if(!steamclient_hmod){ | |||||
+ HANDLE f = CreateFileW(steamclient_pathW, | |||||
+ GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, | |||||
+ NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); | |||||
+ if(f != INVALID_HANDLE_VALUE){ | |||||
+ DWORD sz, readed; | |||||
+ | |||||
+ sz = GetFileSize(f, NULL); | |||||
+ | |||||
+ steamclient_hmod = HeapAlloc(GetProcessHeap(), 0, sz); | |||||
+ ReadFile(f, steamclient_hmod, sz, &readed, NULL); | |||||
+ | |||||
+ CloseHandle(f); | |||||
+ }else{ | |||||
+ /* this will fail DRM checks, but otherwise should work */ | |||||
+ ERR("somehow failed to load steamclient\n"); | |||||
+ steamclient_hmod = lsteamclient_hmod; | |||||
+ } | |||||
+ } | |||||
+ | |||||
+ return steamclient_hmod; | |||||
+ } | |||||
+ | |||||
if (flags & load_library_search_flags) | |||||
load_path = get_dll_load_path_search_flags( libname->Buffer, flags ); | |||||
else | |||||
@@ -1101,6 +1173,9 @@ BOOL WINAPI DECLSPEC_HOTPATCH FreeLibrar | |||||
return FALSE; | |||||
} | |||||
+ if(steamclient_hmod != NULL && hLibModule == steamclient_hmod) | |||||
+ return TRUE; | |||||
+ | |||||
if ((ULONG_PTR)hLibModule & 3) /* this is a datafile module */ | |||||
{ | |||||
void *ptr = (void *)((ULONG_PTR)hLibModule & ~3); | |||||
@@ -1155,6 +1230,9 @@ FARPROC get_proc_address( HMODULE hModul | |||||
if (!hModule) hModule = NtCurrentTeb()->Peb->ImageBaseAddress; | |||||
+ if(steamclient_hmod != NULL && hModule == steamclient_hmod) | |||||
+ hModule = lsteamclient_hmod; | |||||
+ | |||||
if ((ULONG_PTR)function >> 16) | |||||
{ | |||||
ANSI_STRING str; | |||||
--- a/dlls/kernel32/process.c | |||||
+++ b/dlls/kernel32/process.c | |||||
@@ -3384,6 +3384,22 @@ HANDLE WINAPI OpenProcess( DWORD access, | |||||
OBJECT_ATTRIBUTES attr; | |||||
CLIENT_ID cid; | |||||
+ if(id == 0xfffe) | |||||
+ /* STEAMOS HACK: | |||||
+ * On Windows, the Steam client puts its process ID into the registry | |||||
+ * at: | |||||
+ * | |||||
+ * [HKCU\Software\Valve\Steam\ActiveProcess] | |||||
+ * PID=dword:00000008 | |||||
+ * | |||||
+ * Games get that pid from the registry and then query it with | |||||
+ * OpenProcess to ensure Steam is running. Since we aren't running the | |||||
+ * Windows Steam in Wine, instead we hack this magic number into the | |||||
+ * registry and then substitute the game's process itself in its place | |||||
+ * so it can query a valid process. | |||||
+ */ | |||||
+ id = GetCurrentProcessId(); | |||||
+ | |||||
cid.UniqueProcess = ULongToHandle(id); | |||||
cid.UniqueThread = 0; /* FIXME ? */ | |||||
--- a/loader/wine.inf.in | |||||
+++ b/loader/wine.inf.in | |||||
@@ -178,6 +181,7 @@ | |||||
CurrentVersionNT="Software\Microsoft\Windows NT\CurrentVersion" | |||||
FontSubStr="Software\Microsoft\Windows NT\CurrentVersion\FontSubstitutes" | |||||
Control="System\CurrentControlSet\Control" | |||||
+FontsNT="Software\Microsoft\Windows NT\CurrentVersion\Fonts" | |||||
[Classes] | |||||
HKCR,.chm,,2,"chm.file" | |||||
@@ -610,6 +614,11 @@ | |||||
HKLM,%FontSubStr%,"Times New Roman Greek,161",,"Times New Roman,161" | |||||
HKLM,%FontSubStr%,"Times New Roman TUR,162",,"Times New Roman,162" | |||||
HKLM,System\CurrentControlSet\Hardware Profiles\Current\Software\Fonts,"LogPixels",0x10003,0x00000060 | |||||
+HKLM,%FontsNT%,"Arial (TrueType)",,"arial.ttf" | |||||
+HKLM,%FontsNT%,"Arial Bold (TrueType)",,"arialbd.ttf" | |||||
+HKLM,%FontsNT%,"Times New Roman (TrueType)",,"times.ttf" | |||||
+HKLM,%FontsNT%,"Courier New (TrueType)",,"cour.ttf" | |||||
+HKCU,Software\Wine\Fonts\Replacements,"Palatino Linotype",,"Times New Roman" | |||||
[MCI] | |||||
HKLM,%Mci32Str%,"AVIVideo",,"mciavi32.dll" |
@ -0,0 +1,210 @@ | |||||
Original patch code by Valve Corporation | |||||
Original commits: | |||||
https://github.com/ValveSoftware/wine/commit/45a30e45c6ba6f0a28e2df4107d2e73203e97c64 | |||||
https://github.com/ValveSoftware/wine/commit/46759f772e5e82e1c063c93d743fafa018f406b2 | |||||
https://github.com/ValveSoftware/wine/commit/667994216734d72e2b9a4df268aae87bd8189d43 | |||||
https://github.com/ValveSoftware/wine/commit/050f036aa031322e4f32ffd9b4a90edb24b78609 | |||||
https://github.com/ValveSoftware/wine/commit/647086c049ac7e05750bf01c1cdb5a37f436a558 | |||||
https://github.com/ValveSoftware/wine/commit/6a02230c44b7a26422fdb6d4edbb8bcbc2f3d035 | |||||
LICENSE: See https://github.com/ValveSoftware/wine | |||||
Target Wine version of this patch file: | |||||
Wine 4.9 (Staging) | |||||
--- a/dlls/kernel32/module.c | |||||
+++ b/dlls/kernel32/module.c | |||||
@@ -77,6 +77,32 @@ static CRITICAL_SECTION_DEBUG critsect_d | |||||
}; | |||||
static CRITICAL_SECTION dlldir_section = { &critsect_debug, -1, 0, 0, 0, 0 }; | |||||
+#if defined(__x86_64__) | |||||
+static const WCHAR steamclientW[] = {'s','t','e','a','m','c','l','i','e','n','t','6','4',0}; | |||||
+static const WCHAR steamclient_pathW[] = {'C',':','\\','P','r','o','g','r','a','m',' ','F','i','l','e','s',' ','(','x','8','6',')','\\','S','t','e','a','m','\\','s','t','e','a','m','c','l','i','e','n','t','6','4','.','d','l','l',0}; | |||||
+#else | |||||
+static const WCHAR steamclientW[] = {'s','t','e','a','m','c','l','i','e','n','t',0}; | |||||
+static const WCHAR steamclient_pathW[] = {'C',':','\\','P','r','o','g','r','a','m',' ','F','i','l','e','s',' ','(','x','8','6',')','\\','S','t','e','a','m','\\','s','t','e','a','m','c','l','i','e','n','t','.','d','l','l',0}; | |||||
+#endif | |||||
+static const WCHAR steamProgramPathW[] = {'C',':','\\','P','r','o','g','r','a','m',' ','F','i','l','e','s',' ','(','x','8','6',')','\\','S','t','e','a','m',0}; | |||||
+static const DWORD steamProgramPathW_len = 28; | |||||
+static const WCHAR steamdllW[] = {'S','t','e','a','m','.','d','l','l',0}; | |||||
+static const DWORD steamdllW_len = 9; | |||||
+static HMODULE steamclient_hmod = NULL; | |||||
+static HMODULE lsteamclient_hmod = NULL; | |||||
+ | |||||
+static WCHAR *strcasestrW( const WCHAR *str, const WCHAR *sub ) | |||||
+{ | |||||
+ while (*str) | |||||
+ { | |||||
+ const WCHAR *p1 = str, *p2 = sub; | |||||
+ while (*p1 && *p2 && tolowerW(*p1) == tolowerW(*p2)) { p1++; p2++; } | |||||
+ if (!*p2) return (WCHAR *)str; | |||||
+ str++; | |||||
+ } | |||||
+ return NULL; | |||||
+} | |||||
+ | |||||
/**************************************************************************** | |||||
* GetDllDirectoryA (KERNEL32.@) | |||||
*/ | |||||
@@ -445,10 +471,16 @@ BOOL WINAPI GetModuleHandleExW( DWORD fl | |||||
{ | |||||
void *dummy; | |||||
if (!(ret = RtlPcToFileHeader( (void *)name, &dummy ))) status = STATUS_DLL_NOT_FOUND; | |||||
+ if(steamclient_hmod != NULL && ret == lsteamclient_hmod) | |||||
+ ret = steamclient_hmod; | |||||
} | |||||
else | |||||
{ | |||||
UNICODE_STRING wstr; | |||||
+ if(steamclient_hmod != NULL && strcasestrW(name, steamclientW)){ | |||||
+ *module = steamclient_hmod; | |||||
+ return TRUE; | |||||
+ } | |||||
RtlInitUnicodeString( &wstr, name ); | |||||
status = LdrGetDllHandle( NULL, 0, &wstr, &ret ); | |||||
} | |||||
@@ -557,6 +589,11 @@ DWORD WINAPI GetModuleFileNameW( HMODULE | |||||
NTSTATUS nts; | |||||
WIN16_SUBSYSTEM_TIB *win16_tib; | |||||
+ if(steamclient_hmod != NULL && hModule == steamclient_hmod){ | |||||
+ memcpy(lpFileName, steamclient_pathW, sizeof(steamclient_pathW)); | |||||
+ return sizeof(steamclient_pathW)/sizeof(WCHAR); | |||||
+ } | |||||
+ | |||||
if (!hModule && ((win16_tib = NtCurrentTeb()->Tib.SubSystemTib)) && win16_tib->exe_name) | |||||
{ | |||||
len = min(size, win16_tib->exe_name->Length / sizeof(WCHAR)); | |||||
@@ -600,11 +637,16 @@ static const WCHAR *get_dll_system_path( | |||||
if (!cached_path) | |||||
{ | |||||
WCHAR *p, *path; | |||||
- int len = 1; | |||||
+ int len = 2; | |||||
+ | |||||
+ len += steamProgramPathW_len; | |||||
len += 2 * GetSystemDirectoryW( NULL, 0 ); | |||||
len += GetWindowsDirectoryW( NULL, 0 ); | |||||
p = path = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ); | |||||
+ strcpyW(p, steamProgramPathW); | |||||
+ p += steamProgramPathW_len; | |||||
+ *p++ = ';'; | |||||
GetSystemDirectoryW( p, path + len - p); | |||||
p += strlenW(p); | |||||
/* if system directory ends in "32" add 16-bit version too */ | |||||
@@ -933,6 +975,7 @@ static HMODULE load_library( const UNICO | |||||
NTSTATUS nts; | |||||
HMODULE hModule; | |||||
WCHAR *load_path; | |||||
+ const WCHAR *p; | |||||
const DWORD load_library_search_flags = (LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR | | |||||
LOAD_LIBRARY_SEARCH_APPLICATION_DIR | | |||||
LOAD_LIBRARY_SEARCH_USER_DIRS | | |||||
@@ -946,6 +989,36 @@ static HMODULE load_library( const UNICO | |||||
if( flags & unsupported_flags) | |||||
FIXME("unsupported flag(s) used (flags: 0x%08x)\n", flags); | |||||
+ if((p = strcasestrW(libname->Buffer, steamclientW)) && | |||||
+ (p == libname->Buffer || | |||||
+ *(p - 1) != 'l')){ | |||||
+ | |||||
+ if(!lsteamclient_hmod) | |||||
+ lsteamclient_hmod = LoadLibraryA("lsteamclient.dll"); | |||||
+ | |||||
+ if(!steamclient_hmod){ | |||||
+ HANDLE f = CreateFileW(steamclient_pathW, | |||||
+ GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, | |||||
+ NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); | |||||
+ if(f != INVALID_HANDLE_VALUE){ | |||||
+ DWORD sz, readed; | |||||
+ | |||||
+ sz = GetFileSize(f, NULL); | |||||
+ | |||||
+ steamclient_hmod = HeapAlloc(GetProcessHeap(), 0, sz); | |||||
+ ReadFile(f, steamclient_hmod, sz, &readed, NULL); | |||||
+ | |||||
+ CloseHandle(f); | |||||
+ }else{ | |||||
+ /* this will fail DRM checks, but otherwise should work */ | |||||
+ ERR("somehow failed to load steamclient\n"); | |||||
+ steamclient_hmod = lsteamclient_hmod; | |||||
+ } | |||||
+ } | |||||
+ | |||||
+ return steamclient_hmod; | |||||
+ } | |||||
+ | |||||
if (flags & load_library_search_flags) | |||||
load_path = get_dll_load_path_search_flags( libname->Buffer, flags ); | |||||
else | |||||
@@ -1101,6 +1174,9 @@ BOOL WINAPI DECLSPEC_HOTPATCH FreeLibrar | |||||
return FALSE; | |||||
} | |||||
+ if(steamclient_hmod != NULL && hLibModule == steamclient_hmod) | |||||
+ return TRUE; | |||||
+ | |||||
if ((ULONG_PTR)hLibModule & 3) /* this is a datafile module */ | |||||
{ | |||||
void *ptr = (void *)((ULONG_PTR)hLibModule & ~3); | |||||
@@ -1155,6 +1231,9 @@ FARPROC get_proc_address( HMODULE hModul | |||||
if (!hModule) hModule = NtCurrentTeb()->Peb->ImageBaseAddress; | |||||
+ if(steamclient_hmod != NULL && hModule == steamclient_hmod) | |||||
+ hModule = lsteamclient_hmod; | |||||
+ | |||||
if ((ULONG_PTR)function >> 16) | |||||
{ | |||||
ANSI_STRING str; | |||||
--- a/dlls/kernel32/process.c | |||||
+++ b/dlls/kernel32/process.c | |||||
@@ -3412,6 +3412,22 @@ HANDLE WINAPI OpenProcess( DWORD access, | |||||
OBJECT_ATTRIBUTES attr; | |||||
CLIENT_ID cid; | |||||
+ if(id == 0xfffe) | |||||
+ /* STEAMOS HACK: | |||||
+ * On Windows, the Steam client puts its process ID into the registry | |||||
+ * at: | |||||
+ * | |||||
+ * [HKCU\Software\Valve\Steam\ActiveProcess] | |||||
+ * PID=dword:00000008 | |||||
+ * | |||||
+ * Games get that pid from the registry and then query it with | |||||
+ * OpenProcess to ensure Steam is running. Since we aren't running the | |||||
+ * Windows Steam in Wine, instead we hack this magic number into the | |||||
+ * registry and then substitute the game's process itself in its place | |||||
+ * so it can query a valid process. | |||||
+ */ | |||||
+ id = GetCurrentProcessId(); | |||||
+ | |||||
cid.UniqueProcess = ULongToHandle(id); | |||||
cid.UniqueThread = 0; /* FIXME ? */ | |||||
--- a/loader/wine.inf.in | |||||
+++ b/loader/wine.inf.in | |||||
@@ -181,6 +181,7 @@ | |||||
CurrentVersionNT="Software\Microsoft\Windows NT\CurrentVersion" | |||||
FontSubStr="Software\Microsoft\Windows NT\CurrentVersion\FontSubstitutes" | |||||
Control="System\CurrentControlSet\Control" | |||||
+FontsNT="Software\Microsoft\Windows NT\CurrentVersion\Fonts" | |||||
[Classes] | |||||
HKCR,.chm,,2,"chm.file" | |||||
@@ -627,6 +628,11 @@ | |||||
HKLM,%FontSubStr%,"Times New Roman Greek,161",,"Times New Roman,161" | |||||
HKLM,%FontSubStr%,"Times New Roman TUR,162",,"Times New Roman,162" | |||||
HKLM,System\CurrentControlSet\Hardware Profiles\Current\Software\Fonts,"LogPixels",0x10003,0x00000060 | |||||
+HKLM,%FontsNT%,"Arial (TrueType)",,"arial.ttf" | |||||
+HKLM,%FontsNT%,"Arial Bold (TrueType)",,"arialbd.ttf" | |||||
+HKLM,%FontsNT%,"Times New Roman (TrueType)",,"times.ttf" | |||||
+HKLM,%FontsNT%,"Courier New (TrueType)",,"cour.ttf" | |||||
+HKCU,Software\Wine\Fonts\Replacements,"Palatino Linotype",,"Times New Roman" | |||||
[MCI] | |||||
HKLM,%Mci32Str%,"AVIVideo",,"mciavi32.dll" |