We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Lutris removes "DXVK" dlls even when they're not from DXVK
**Describe the bug**

It is currently not possible to use Gallium Nine, when DXVK is disabled in the settings (which would be what I thought would be necessary to run Gallium Nine). When I enable Gallium Nine and then run a game I get these messages in the console:

```
2019-06-17 10:21:30,859: Removing DXVK dll /home/bjoern/Games/starcraft-ii/drive_c/windows/system32/d3d9
2019-06-17 10:21:30,859: Removing DXVK dll /home/bjoern/Games/starcraft-ii/drive_c/windows/syswow64/d3d9
```

Afterwards the game complains about a missiing d3d9.dll
Enabling DXVK and setting the version to manual makes it work.

**Expected behavior**

Game runs with Gallium Nine.

**Current behavior**

Game complains about a missiing d3d9.dll

**Steps to reproduce**

* Install Gallium Nine via winetricks.
* Enable Gallium Nine by running drive_c/windows/syswo64/ninewinecfg.exe
* Disable DXVK.
* Run game.

**Workarounds**

Any of these should work:

* Set DXVK-version to manual and enable DXVK.
* Run the game manually from the console and not via lutris.
* It would probably work to run the game exe manually via "Run EXE inside wine prefix".

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `lutris/util/wine/dxvk.py`
Content:
```
1 """DXVK helper module"""
2 import os
3 import json
4 import time
5 import shutil
6 import urllib.request
7 
8 from lutris.settings import RUNTIME_DIR
9 from lutris.util.log import logger
10 from lutris.util.extract import extract_archive
11 from lutris.util.downloader import Downloader
12 from lutris.util import system
13 
14 CACHE_MAX_AGE = 86400  # Re-download DXVK versions every day
15 
16 
17 @system.run_once
18 def init_dxvk_versions():
19     def get_dxvk_versions(base_name, tags_url):
20         """Get DXVK versions from GitHub"""
21         logger.info("Updating "+base_name.upper()+" versions")
22         dxvk_path = os.path.join(RUNTIME_DIR, base_name)
23         if not os.path.isdir(dxvk_path):
24             os.mkdir(dxvk_path)
25         versions_path = os.path.join(dxvk_path, base_name+"_versions.json")
26 
27         urllib.request.urlretrieve(tags_url, versions_path)
28 
29         with open(versions_path, "r") as dxvk_tags:
30             dxvk_json = json.load(dxvk_tags)
31             dxvk_versions = list()
32             for x in dxvk_json:
33                 version_name = x["name"].replace("v", "")
34                 if version_name.startswith('m'):  # ignore master snapshots of d9vk
35                     continue
36                 dxvk_versions.append(version_name)
37         return dxvk_versions
38 
39     def init_versions(manager):
40         try:
41             manager.DXVK_VERSIONS \
42                 = get_dxvk_versions(manager.base_name, manager.DXVK_TAGS_URL)
43         except Exception as ex:  # pylint: disable= broad-except
44             logger.error(ex)
45         manager.DXVK_LATEST, manager.DXVK_PAST_RELEASES = manager.DXVK_VERSIONS[0], manager.DXVK_VERSIONS[1:9]
46 
47     init_versions(DXVKManager)
48     init_versions(D9VKManager)
49 
50 
51 class UnavailableDXVKVersion(RuntimeError):
52     """Exception raised when a version of DXVK is not found"""
53 
54 
55 class DXVKManager:
56     """Utility class to install DXVK dlls to a Wine prefix"""
57 
58     DXVK_TAGS_URL = "https://api.github.com/repos/doitsujin/dxvk/tags"
59     DXVK_VERSIONS = [
60         "0.94",
61     ]
62     DXVK_LATEST, DXVK_PAST_RELEASES = DXVK_VERSIONS[0], DXVK_VERSIONS[1:9]
63 
64     base_url = "https://github.com/doitsujin/dxvk/releases/download/v{}/dxvk-{}.tar.gz"
65     base_name = "dxvk"
66     base_dir = os.path.join(RUNTIME_DIR, base_name)
67     dxvk_dlls = ("dxgi", "d3d11", "d3d10core", "d3d10_1", "d3d10", "d3d9")
68     latest_version = DXVK_LATEST
69 
70     def __init__(self, prefix, arch="win64", version=None):
71         self.prefix = prefix
72         if not os.path.isdir(self.base_dir):
73             os.makedirs(self.base_dir)
74         self._version = version
75         self.wine_arch = arch
76 
77     @property
78     def version(self):
79         """Return version of DXVK (latest known version if not provided)"""
80         if self._version:
81             return self._version
82         return self.latest_version
83 
84     @property
85     def dxvk_path(self):
86         """Return path to DXVK local cache"""
87         return os.path.join(self.base_dir, self.version)
88 
89     @staticmethod
90     def is_dxvk_dll(dll_path):
91         """Check if a given DLL path is provided by DXVK
92 
93         Very basic check to see if a dll exists and is over 256K. If this is the
94         case, then consider the DLL to be from DXVK
95         """
96         if system.path_exists(dll_path, check_symlinks=True):
97             dll_stats = os.stat(dll_path)
98             dll_size = dll_stats.st_size
99         else:
100             dll_size = 0
101         return dll_size > 1024 * 256
102 
103     def is_available(self):
104         """Return whether DXVK is cached locally"""
105         return system.path_exists(self.dxvk_path)
106 
107     def dxvk_dll_exists(self, dll_name):
108         """Check if the dll exists as a DXVK variant"""
109         return system.path_exists(os.path.join(self.dxvk_path, "x64", dll_name + ".dll")) \
110             and system.path_exists(os.path.join(self.dxvk_path, "x32", dll_name + ".dll"))
111 
112     def download(self):
113         """Download DXVK to the local cache"""
114         dxvk_url = self.base_url.format(self.version, self.version)
115         if self.is_available():
116             logger.warning(self.base_name.upper()+" already available at %s", self.dxvk_path)
117 
118         dxvk_archive_path = os.path.join(self.base_dir, os.path.basename(dxvk_url))
119 
120         downloader = Downloader(dxvk_url, dxvk_archive_path)
121         downloader.start()
122         while downloader.check_progress() < 1 and downloader.state != downloader.ERROR:
123             time.sleep(0.3)
124         if not system.path_exists(dxvk_archive_path):
125             raise UnavailableDXVKVersion("Failed to download "+self.base_name.upper()+" %s" % self.version)
126         if os.stat(dxvk_archive_path).st_size:
127             extract_archive(dxvk_archive_path, self.dxvk_path, merge_single=True)
128             os.remove(dxvk_archive_path)
129         else:
130             os.remove(dxvk_archive_path)
131             raise UnavailableDXVKVersion("Failed to download "+self.base_name.upper()+" %s" % self.version)
132 
133     def enable_dxvk_dll(self, system_dir, dxvk_arch, dll):
134         """Copies DXVK dlls to the appropriate destination"""
135         # Copying DXVK's version
136         dxvk_dll_path = os.path.join(self.dxvk_path, dxvk_arch, "%s.dll" % dll)
137         if system.path_exists(dxvk_dll_path):
138             wine_dll_path = os.path.join(system_dir, "%s.dll" % dll)
139             logger.info("Replacing %s/%s with "+self.base_name.upper()+" version", system_dir, dll)
140             if not self.is_dxvk_dll(wine_dll_path):
141                 # Backing up original version (may not be needed)
142                 if system.path_exists(wine_dll_path):
143                     shutil.move(wine_dll_path, wine_dll_path + ".orig")
144             if system.path_exists(wine_dll_path):
145                 os.remove(wine_dll_path)
146             os.symlink(dxvk_dll_path, wine_dll_path)
147         else:
148             self.disable_dxvk_dll(system_dir, dxvk_arch, dll)
149 
150     def disable_dxvk_dll(self, system_dir, dxvk_arch, dll):
151         """Remove DXVK DLL from Wine prefix"""
152         wine_dll_path = os.path.join(system_dir, "%s.dll" % dll)
153         if self.is_dxvk_dll(wine_dll_path):
154             logger.info("Removing "+self.base_name.upper()+" dll %s/%s", system_dir, dll)
155             os.remove(wine_dll_path)
156         # Restoring original version (may not be needed)
157         if system.path_exists(wine_dll_path + ".orig"):
158             shutil.move(wine_dll_path + ".orig", wine_dll_path)
159 
160     def _iter_dxvk_dlls(self):
161         windows_path = os.path.join(self.prefix, "drive_c/windows")
162         if self.wine_arch == "win64":
163             system_dirs = {
164                 "x64": os.path.join(windows_path, "system32"),
165                 "x32": os.path.join(windows_path, "syswow64"),
166             }
167         elif self.wine_arch == "win32":
168             system_dirs = {"x32": os.path.join(windows_path, "system32")}
169 
170         for dxvk_arch, system_dir in system_dirs.items():
171             for dll in self.dxvk_dlls:
172                 yield system_dir, dxvk_arch, dll
173 
174     def enable(self):
175         """Enable DXVK for the current prefix"""
176         if not system.path_exists(self.dxvk_path):
177             logger.error(self.base_name.upper()+" %s is not available locally", self.version)
178             return
179         for system_dir, dxvk_arch, dll in self._iter_dxvk_dlls():
180             self.enable_dxvk_dll(system_dir, dxvk_arch, dll)
181 
182     def disable(self):
183         """Disable DXVK for the current prefix"""
184         for system_dir, dxvk_arch, dll in self._iter_dxvk_dlls():
185             self.disable_dxvk_dll(system_dir, dxvk_arch, dll)
186 
187 
188 class D9VKManager(DXVKManager):
189     DXVK_TAGS_URL = "https://api.github.com/repos/Joshua-Ashton/d9vk/tags"
190     DXVK_VERSIONS = [
191         "0.10",
192     ]
193     DXVK_LATEST, DXVK_PAST_RELEASES = DXVK_VERSIONS[0], DXVK_VERSIONS[1:9]
194 
195     base_url = "https://github.com/Joshua-Ashton/d9vk/releases/download/{}/d9vk-{}.tar.gz"
196     base_name = "d9vk"
197     base_dir = os.path.join(RUNTIME_DIR, base_name)
198     dxvk_dlls = ("d3d9",)
199     latest_version = DXVK_LATEST
200
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/lutris/util/wine/dxvk.py b/lutris/util/wine/dxvk.py
--- a/lutris/util/wine/dxvk.py
+++ b/lutris/util/wine/dxvk.py
@@ -23,25 +23,31 @@
         if not os.path.isdir(dxvk_path):
             os.mkdir(dxvk_path)
         versions_path = os.path.join(dxvk_path, base_name+"_versions.json")
-
-        urllib.request.urlretrieve(tags_url, versions_path)
-
+        internet_available = True
+        try:
+            urllib.request.urlretrieve(tags_url, versions_path)
+        except Exception as ex:  # pylint: disable= broad-except
+            logger.error(ex)
+            internet_available = False
+        dxvk_versions = list()
         with open(versions_path, "r") as dxvk_tags:
             dxvk_json = json.load(dxvk_tags)
-            dxvk_versions = list()
             for x in dxvk_json:
                 version_name = x["name"].replace("v", "")
                 if version_name.startswith('m'):  # ignore master snapshots of d9vk
                     continue
-                dxvk_versions.append(version_name)
-        return dxvk_versions
+                if internet_available or version_name in os.listdir(dxvk_path):
+                    dxvk_versions.append(version_name)
+        if not dxvk_versions:  # We don't want to set manager.DXVK_VERSIONS, if the list is empty
+            raise IndexError
+        return sorted(dxvk_versions, reverse=True)
 
     def init_versions(manager):
         try:
             manager.DXVK_VERSIONS \
                 = get_dxvk_versions(manager.base_name, manager.DXVK_TAGS_URL)
-        except Exception as ex:  # pylint: disable= broad-except
-            logger.error(ex)
+        except (IndexError, FileNotFoundError):
+            pass
         manager.DXVK_LATEST, manager.DXVK_PAST_RELEASES = manager.DXVK_VERSIONS[0], manager.DXVK_VERSIONS[1:9]
 
     init_versions(DXVKManager)
@@ -150,11 +156,9 @@
     def disable_dxvk_dll(self, system_dir, dxvk_arch, dll):
         """Remove DXVK DLL from Wine prefix"""
         wine_dll_path = os.path.join(system_dir, "%s.dll" % dll)
-        if self.is_dxvk_dll(wine_dll_path):
+        if self.is_dxvk_dll(wine_dll_path) and system.path_exists(wine_dll_path + ".orig"):
             logger.info("Removing "+self.base_name.upper()+" dll %s/%s", system_dir, dll)
             os.remove(wine_dll_path)
-        # Restoring original version (may not be needed)
-        if system.path_exists(wine_dll_path + ".orig"):
             shutil.move(wine_dll_path + ".orig", wine_dll_path)
 
     def _iter_dxvk_dlls(self):

{"golden_diff": "diff --git a/lutris/util/wine/dxvk.py b/lutris/util/wine/dxvk.py\n--- a/lutris/util/wine/dxvk.py\n+++ b/lutris/util/wine/dxvk.py\n@@ -23,25 +23,31 @@\n         if not os.path.isdir(dxvk_path):\n             os.mkdir(dxvk_path)\n         versions_path = os.path.join(dxvk_path, base_name+\"_versions.json\")\n-\n-        urllib.request.urlretrieve(tags_url, versions_path)\n-\n+        internet_available = True\n+        try:\n+            urllib.request.urlretrieve(tags_url, versions_path)\n+        except Exception as ex:  # pylint: disable= broad-except\n+            logger.error(ex)\n+            internet_available = False\n+        dxvk_versions = list()\n         with open(versions_path, \"r\") as dxvk_tags:\n             dxvk_json = json.load(dxvk_tags)\n-            dxvk_versions = list()\n             for x in dxvk_json:\n                 version_name = x[\"name\"].replace(\"v\", \"\")\n                 if version_name.startswith('m'):  # ignore master snapshots of d9vk\n                     continue\n-                dxvk_versions.append(version_name)\n-        return dxvk_versions\n+                if internet_available or version_name in os.listdir(dxvk_path):\n+                    dxvk_versions.append(version_name)\n+        if not dxvk_versions:  # We don't want to set manager.DXVK_VERSIONS, if the list is empty\n+            raise IndexError\n+        return sorted(dxvk_versions, reverse=True)\n \n     def init_versions(manager):\n         try:\n             manager.DXVK_VERSIONS \\\n                 = get_dxvk_versions(manager.base_name, manager.DXVK_TAGS_URL)\n-        except Exception as ex:  # pylint: disable= broad-except\n-            logger.error(ex)\n+        except (IndexError, FileNotFoundError):\n+            pass\n         manager.DXVK_LATEST, manager.DXVK_PAST_RELEASES = manager.DXVK_VERSIONS[0], manager.DXVK_VERSIONS[1:9]\n \n     init_versions(DXVKManager)\n@@ -150,11 +156,9 @@\n     def disable_dxvk_dll(self, system_dir, dxvk_arch, dll):\n         \"\"\"Remove DXVK DLL from Wine prefix\"\"\"\n         wine_dll_path = os.path.join(system_dir, \"%s.dll\" % dll)\n-        if self.is_dxvk_dll(wine_dll_path):\n+        if self.is_dxvk_dll(wine_dll_path) and system.path_exists(wine_dll_path + \".orig\"):\n             logger.info(\"Removing \"+self.base_name.upper()+\" dll %s/%s\", system_dir, dll)\n             os.remove(wine_dll_path)\n-        # Restoring original version (may not be needed)\n-        if system.path_exists(wine_dll_path + \".orig\"):\n             shutil.move(wine_dll_path + \".orig\", wine_dll_path)\n \n     def _iter_dxvk_dlls(self):\n", "issue": "Lutris removes \"DXVK\" dlls even when they're not from DXVK\n**Describe the bug**\r\n\r\nIt is currently not possible to use Gallium Nine, when DXVK is disabled in the settings (which would be what I thought would be necessary to run Gallium Nine). When I enable Gallium Nine and then run a game I get these messages in the console:\r\n\r\n```\r\n2019-06-17 10:21:30,859: Removing DXVK dll /home/bjoern/Games/starcraft-ii/drive_c/windows/system32/d3d9\r\n2019-06-17 10:21:30,859: Removing DXVK dll /home/bjoern/Games/starcraft-ii/drive_c/windows/syswow64/d3d9\r\n```\r\n\r\nAfterwards the game complains about a missiing d3d9.dll\r\nEnabling DXVK and setting the version to manual makes it work.\r\n\r\n**Expected behavior**\r\n\r\nGame runs with Gallium Nine.\r\n\r\n**Current behavior**\r\n\r\nGame complains about a missiing d3d9.dll\r\n\r\n**Steps to reproduce**\r\n\r\n* Install Gallium Nine via winetricks.\r\n* Enable Gallium Nine by running drive_c/windows/syswo64/ninewinecfg.exe\r\n* Disable DXVK.\r\n* Run game.\r\n\r\n**Workarounds**\r\n\r\nAny of these should work:\r\n\r\n* Set DXVK-version to manual and enable DXVK.\r\n* Run the game manually from the console and not via lutris.\r\n* It would probably work to run the game exe manually via \"Run EXE inside wine prefix\".\n", "before_files": [{"content": "\"\"\"DXVK helper module\"\"\"\nimport os\nimport json\nimport time\nimport shutil\nimport urllib.request\n\nfrom lutris.settings import RUNTIME_DIR\nfrom lutris.util.log import logger\nfrom lutris.util.extract import extract_archive\nfrom lutris.util.downloader import Downloader\nfrom lutris.util import system\n\nCACHE_MAX_AGE = 86400  # Re-download DXVK versions every day\n\n\n@system.run_once\ndef init_dxvk_versions():\n    def get_dxvk_versions(base_name, tags_url):\n        \"\"\"Get DXVK versions from GitHub\"\"\"\n        logger.info(\"Updating \"+base_name.upper()+\" versions\")\n        dxvk_path = os.path.join(RUNTIME_DIR, base_name)\n        if not os.path.isdir(dxvk_path):\n            os.mkdir(dxvk_path)\n        versions_path = os.path.join(dxvk_path, base_name+\"_versions.json\")\n\n        urllib.request.urlretrieve(tags_url, versions_path)\n\n        with open(versions_path, \"r\") as dxvk_tags:\n            dxvk_json = json.load(dxvk_tags)\n            dxvk_versions = list()\n            for x in dxvk_json:\n                version_name = x[\"name\"].replace(\"v\", \"\")\n                if version_name.startswith('m'):  # ignore master snapshots of d9vk\n                    continue\n                dxvk_versions.append(version_name)\n        return dxvk_versions\n\n    def init_versions(manager):\n        try:\n            manager.DXVK_VERSIONS \\\n                = get_dxvk_versions(manager.base_name, manager.DXVK_TAGS_URL)\n        except Exception as ex:  # pylint: disable= broad-except\n            logger.error(ex)\n        manager.DXVK_LATEST, manager.DXVK_PAST_RELEASES = manager.DXVK_VERSIONS[0], manager.DXVK_VERSIONS[1:9]\n\n    init_versions(DXVKManager)\n    init_versions(D9VKManager)\n\n\nclass UnavailableDXVKVersion(RuntimeError):\n    \"\"\"Exception raised when a version of DXVK is not found\"\"\"\n\n\nclass DXVKManager:\n    \"\"\"Utility class to install DXVK dlls to a Wine prefix\"\"\"\n\n    DXVK_TAGS_URL = \"https://api.github.com/repos/doitsujin/dxvk/tags\"\n    DXVK_VERSIONS = [\n        \"0.94\",\n    ]\n    DXVK_LATEST, DXVK_PAST_RELEASES = DXVK_VERSIONS[0], DXVK_VERSIONS[1:9]\n\n    base_url = \"https://github.com/doitsujin/dxvk/releases/download/v{}/dxvk-{}.tar.gz\"\n    base_name = \"dxvk\"\n    base_dir = os.path.join(RUNTIME_DIR, base_name)\n    dxvk_dlls = (\"dxgi\", \"d3d11\", \"d3d10core\", \"d3d10_1\", \"d3d10\", \"d3d9\")\n    latest_version = DXVK_LATEST\n\n    def __init__(self, prefix, arch=\"win64\", version=None):\n        self.prefix = prefix\n        if not os.path.isdir(self.base_dir):\n            os.makedirs(self.base_dir)\n        self._version = version\n        self.wine_arch = arch\n\n    @property\n    def version(self):\n        \"\"\"Return version of DXVK (latest known version if not provided)\"\"\"\n        if self._version:\n            return self._version\n        return self.latest_version\n\n    @property\n    def dxvk_path(self):\n        \"\"\"Return path to DXVK local cache\"\"\"\n        return os.path.join(self.base_dir, self.version)\n\n    @staticmethod\n    def is_dxvk_dll(dll_path):\n        \"\"\"Check if a given DLL path is provided by DXVK\n\n        Very basic check to see if a dll exists and is over 256K. If this is the\n        case, then consider the DLL to be from DXVK\n        \"\"\"\n        if system.path_exists(dll_path, check_symlinks=True):\n            dll_stats = os.stat(dll_path)\n            dll_size = dll_stats.st_size\n        else:\n            dll_size = 0\n        return dll_size > 1024 * 256\n\n    def is_available(self):\n        \"\"\"Return whether DXVK is cached locally\"\"\"\n        return system.path_exists(self.dxvk_path)\n\n    def dxvk_dll_exists(self, dll_name):\n        \"\"\"Check if the dll exists as a DXVK variant\"\"\"\n        return system.path_exists(os.path.join(self.dxvk_path, \"x64\", dll_name + \".dll\")) \\\n            and system.path_exists(os.path.join(self.dxvk_path, \"x32\", dll_name + \".dll\"))\n\n    def download(self):\n        \"\"\"Download DXVK to the local cache\"\"\"\n        dxvk_url = self.base_url.format(self.version, self.version)\n        if self.is_available():\n            logger.warning(self.base_name.upper()+\" already available at %s\", self.dxvk_path)\n\n        dxvk_archive_path = os.path.join(self.base_dir, os.path.basename(dxvk_url))\n\n        downloader = Downloader(dxvk_url, dxvk_archive_path)\n        downloader.start()\n        while downloader.check_progress() < 1 and downloader.state != downloader.ERROR:\n            time.sleep(0.3)\n        if not system.path_exists(dxvk_archive_path):\n            raise UnavailableDXVKVersion(\"Failed to download \"+self.base_name.upper()+\" %s\" % self.version)\n        if os.stat(dxvk_archive_path).st_size:\n            extract_archive(dxvk_archive_path, self.dxvk_path, merge_single=True)\n            os.remove(dxvk_archive_path)\n        else:\n            os.remove(dxvk_archive_path)\n            raise UnavailableDXVKVersion(\"Failed to download \"+self.base_name.upper()+\" %s\" % self.version)\n\n    def enable_dxvk_dll(self, system_dir, dxvk_arch, dll):\n        \"\"\"Copies DXVK dlls to the appropriate destination\"\"\"\n        # Copying DXVK's version\n        dxvk_dll_path = os.path.join(self.dxvk_path, dxvk_arch, \"%s.dll\" % dll)\n        if system.path_exists(dxvk_dll_path):\n            wine_dll_path = os.path.join(system_dir, \"%s.dll\" % dll)\n            logger.info(\"Replacing %s/%s with \"+self.base_name.upper()+\" version\", system_dir, dll)\n            if not self.is_dxvk_dll(wine_dll_path):\n                # Backing up original version (may not be needed)\n                if system.path_exists(wine_dll_path):\n                    shutil.move(wine_dll_path, wine_dll_path + \".orig\")\n            if system.path_exists(wine_dll_path):\n                os.remove(wine_dll_path)\n            os.symlink(dxvk_dll_path, wine_dll_path)\n        else:\n            self.disable_dxvk_dll(system_dir, dxvk_arch, dll)\n\n    def disable_dxvk_dll(self, system_dir, dxvk_arch, dll):\n        \"\"\"Remove DXVK DLL from Wine prefix\"\"\"\n        wine_dll_path = os.path.join(system_dir, \"%s.dll\" % dll)\n        if self.is_dxvk_dll(wine_dll_path):\n            logger.info(\"Removing \"+self.base_name.upper()+\" dll %s/%s\", system_dir, dll)\n            os.remove(wine_dll_path)\n        # Restoring original version (may not be needed)\n        if system.path_exists(wine_dll_path + \".orig\"):\n            shutil.move(wine_dll_path + \".orig\", wine_dll_path)\n\n    def _iter_dxvk_dlls(self):\n        windows_path = os.path.join(self.prefix, \"drive_c/windows\")\n        if self.wine_arch == \"win64\":\n            system_dirs = {\n                \"x64\": os.path.join(windows_path, \"system32\"),\n                \"x32\": os.path.join(windows_path, \"syswow64\"),\n            }\n        elif self.wine_arch == \"win32\":\n            system_dirs = {\"x32\": os.path.join(windows_path, \"system32\")}\n\n        for dxvk_arch, system_dir in system_dirs.items():\n            for dll in self.dxvk_dlls:\n                yield system_dir, dxvk_arch, dll\n\n    def enable(self):\n        \"\"\"Enable DXVK for the current prefix\"\"\"\n        if not system.path_exists(self.dxvk_path):\n            logger.error(self.base_name.upper()+\" %s is not available locally\", self.version)\n            return\n        for system_dir, dxvk_arch, dll in self._iter_dxvk_dlls():\n            self.enable_dxvk_dll(system_dir, dxvk_arch, dll)\n\n    def disable(self):\n        \"\"\"Disable DXVK for the current prefix\"\"\"\n        for system_dir, dxvk_arch, dll in self._iter_dxvk_dlls():\n            self.disable_dxvk_dll(system_dir, dxvk_arch, dll)\n\n\nclass D9VKManager(DXVKManager):\n    DXVK_TAGS_URL = \"https://api.github.com/repos/Joshua-Ashton/d9vk/tags\"\n    DXVK_VERSIONS = [\n        \"0.10\",\n    ]\n    DXVK_LATEST, DXVK_PAST_RELEASES = DXVK_VERSIONS[0], DXVK_VERSIONS[1:9]\n\n    base_url = \"https://github.com/Joshua-Ashton/d9vk/releases/download/{}/d9vk-{}.tar.gz\"\n    base_name = \"d9vk\"\n    base_dir = os.path.join(RUNTIME_DIR, base_name)\n    dxvk_dlls = (\"d3d9\",)\n    latest_version = DXVK_LATEST\n", "path": "lutris/util/wine/dxvk.py"}], "after_files": [{"content": "\"\"\"DXVK helper module\"\"\"\nimport os\nimport json\nimport time\nimport shutil\nimport urllib.request\n\nfrom lutris.settings import RUNTIME_DIR\nfrom lutris.util.log import logger\nfrom lutris.util.extract import extract_archive\nfrom lutris.util.downloader import Downloader\nfrom lutris.util import system\n\nCACHE_MAX_AGE = 86400  # Re-download DXVK versions every day\n\n\n@system.run_once\ndef init_dxvk_versions():\n    def get_dxvk_versions(base_name, tags_url):\n        \"\"\"Get DXVK versions from GitHub\"\"\"\n        logger.info(\"Updating \"+base_name.upper()+\" versions\")\n        dxvk_path = os.path.join(RUNTIME_DIR, base_name)\n        if not os.path.isdir(dxvk_path):\n            os.mkdir(dxvk_path)\n        versions_path = os.path.join(dxvk_path, base_name+\"_versions.json\")\n        internet_available = True\n        try:\n            urllib.request.urlretrieve(tags_url, versions_path)\n        except Exception as ex:  # pylint: disable= broad-except\n            logger.error(ex)\n            internet_available = False\n        dxvk_versions = list()\n        with open(versions_path, \"r\") as dxvk_tags:\n            dxvk_json = json.load(dxvk_tags)\n            for x in dxvk_json:\n                version_name = x[\"name\"].replace(\"v\", \"\")\n                if version_name.startswith('m'):  # ignore master snapshots of d9vk\n                    continue\n                if internet_available or version_name in os.listdir(dxvk_path):\n                    dxvk_versions.append(version_name)\n        if not dxvk_versions:  # We don't want to set manager.DXVK_VERSIONS, if the list is empty\n            raise IndexError\n        return sorted(dxvk_versions, reverse=True)\n\n    def init_versions(manager):\n        try:\n            manager.DXVK_VERSIONS \\\n                = get_dxvk_versions(manager.base_name, manager.DXVK_TAGS_URL)\n        except (IndexError, FileNotFoundError):\n            pass\n        manager.DXVK_LATEST, manager.DXVK_PAST_RELEASES = manager.DXVK_VERSIONS[0], manager.DXVK_VERSIONS[1:9]\n\n    init_versions(DXVKManager)\n    init_versions(D9VKManager)\n\n\nclass UnavailableDXVKVersion(RuntimeError):\n    \"\"\"Exception raised when a version of DXVK is not found\"\"\"\n\n\nclass DXVKManager:\n    \"\"\"Utility class to install DXVK dlls to a Wine prefix\"\"\"\n\n    DXVK_TAGS_URL = \"https://api.github.com/repos/doitsujin/dxvk/tags\"\n    DXVK_VERSIONS = [\n        \"0.94\",\n    ]\n    DXVK_LATEST, DXVK_PAST_RELEASES = DXVK_VERSIONS[0], DXVK_VERSIONS[1:9]\n\n    base_url = \"https://github.com/doitsujin/dxvk/releases/download/v{}/dxvk-{}.tar.gz\"\n    base_name = \"dxvk\"\n    base_dir = os.path.join(RUNTIME_DIR, base_name)\n    dxvk_dlls = (\"dxgi\", \"d3d11\", \"d3d10core\", \"d3d10_1\", \"d3d10\", \"d3d9\")\n    latest_version = DXVK_LATEST\n\n    def __init__(self, prefix, arch=\"win64\", version=None):\n        self.prefix = prefix\n        if not os.path.isdir(self.base_dir):\n            os.makedirs(self.base_dir)\n        self._version = version\n        self.wine_arch = arch\n\n    @property\n    def version(self):\n        \"\"\"Return version of DXVK (latest known version if not provided)\"\"\"\n        if self._version:\n            return self._version\n        return self.latest_version\n\n    @property\n    def dxvk_path(self):\n        \"\"\"Return path to DXVK local cache\"\"\"\n        return os.path.join(self.base_dir, self.version)\n\n    @staticmethod\n    def is_dxvk_dll(dll_path):\n        \"\"\"Check if a given DLL path is provided by DXVK\n\n        Very basic check to see if a dll exists and is over 256K. If this is the\n        case, then consider the DLL to be from DXVK\n        \"\"\"\n        if system.path_exists(dll_path, check_symlinks=True):\n            dll_stats = os.stat(dll_path)\n            dll_size = dll_stats.st_size\n        else:\n            dll_size = 0\n        return dll_size > 1024 * 256\n\n    def is_available(self):\n        \"\"\"Return whether DXVK is cached locally\"\"\"\n        return system.path_exists(self.dxvk_path)\n\n    def dxvk_dll_exists(self, dll_name):\n        \"\"\"Check if the dll exists as a DXVK variant\"\"\"\n        return system.path_exists(os.path.join(self.dxvk_path, \"x64\", dll_name + \".dll\")) \\\n            and system.path_exists(os.path.join(self.dxvk_path, \"x32\", dll_name + \".dll\"))\n\n    def download(self):\n        \"\"\"Download DXVK to the local cache\"\"\"\n        dxvk_url = self.base_url.format(self.version, self.version)\n        if self.is_available():\n            logger.warning(self.base_name.upper()+\" already available at %s\", self.dxvk_path)\n\n        dxvk_archive_path = os.path.join(self.base_dir, os.path.basename(dxvk_url))\n\n        downloader = Downloader(dxvk_url, dxvk_archive_path)\n        downloader.start()\n        while downloader.check_progress() < 1 and downloader.state != downloader.ERROR:\n            time.sleep(0.3)\n        if not system.path_exists(dxvk_archive_path):\n            raise UnavailableDXVKVersion(\"Failed to download \"+self.base_name.upper()+\" %s\" % self.version)\n        if os.stat(dxvk_archive_path).st_size:\n            extract_archive(dxvk_archive_path, self.dxvk_path, merge_single=True)\n            os.remove(dxvk_archive_path)\n        else:\n            os.remove(dxvk_archive_path)\n            raise UnavailableDXVKVersion(\"Failed to download \"+self.base_name.upper()+\" %s\" % self.version)\n\n    def enable_dxvk_dll(self, system_dir, dxvk_arch, dll):\n        \"\"\"Copies DXVK dlls to the appropriate destination\"\"\"\n        # Copying DXVK's version\n        dxvk_dll_path = os.path.join(self.dxvk_path, dxvk_arch, \"%s.dll\" % dll)\n        if system.path_exists(dxvk_dll_path):\n            wine_dll_path = os.path.join(system_dir, \"%s.dll\" % dll)\n            logger.info(\"Replacing %s/%s with \"+self.base_name.upper()+\" version\", system_dir, dll)\n            if not self.is_dxvk_dll(wine_dll_path):\n                # Backing up original version (may not be needed)\n                if system.path_exists(wine_dll_path):\n                    shutil.move(wine_dll_path, wine_dll_path + \".orig\")\n            if system.path_exists(wine_dll_path):\n                os.remove(wine_dll_path)\n            os.symlink(dxvk_dll_path, wine_dll_path)\n        else:\n            self.disable_dxvk_dll(system_dir, dxvk_arch, dll)\n\n    def disable_dxvk_dll(self, system_dir, dxvk_arch, dll):\n        \"\"\"Remove DXVK DLL from Wine prefix\"\"\"\n        wine_dll_path = os.path.join(system_dir, \"%s.dll\" % dll)\n        if self.is_dxvk_dll(wine_dll_path) and system.path_exists(wine_dll_path + \".orig\"):\n            logger.info(\"Removing \"+self.base_name.upper()+\" dll %s/%s\", system_dir, dll)\n            os.remove(wine_dll_path)\n            shutil.move(wine_dll_path + \".orig\", wine_dll_path)\n\n    def _iter_dxvk_dlls(self):\n        windows_path = os.path.join(self.prefix, \"drive_c/windows\")\n        if self.wine_arch == \"win64\":\n            system_dirs = {\n                \"x64\": os.path.join(windows_path, \"system32\"),\n                \"x32\": os.path.join(windows_path, \"syswow64\"),\n            }\n        elif self.wine_arch == \"win32\":\n            system_dirs = {\"x32\": os.path.join(windows_path, \"system32\")}\n\n        for dxvk_arch, system_dir in system_dirs.items():\n            for dll in self.dxvk_dlls:\n                yield system_dir, dxvk_arch, dll\n\n    def enable(self):\n        \"\"\"Enable DXVK for the current prefix\"\"\"\n        if not system.path_exists(self.dxvk_path):\n            logger.error(self.base_name.upper()+\" %s is not available locally\", self.version)\n            return\n        for system_dir, dxvk_arch, dll in self._iter_dxvk_dlls():\n            self.enable_dxvk_dll(system_dir, dxvk_arch, dll)\n\n    def disable(self):\n        \"\"\"Disable DXVK for the current prefix\"\"\"\n        for system_dir, dxvk_arch, dll in self._iter_dxvk_dlls():\n            self.disable_dxvk_dll(system_dir, dxvk_arch, dll)\n\n\nclass D9VKManager(DXVKManager):\n    DXVK_TAGS_URL = \"https://api.github.com/repos/Joshua-Ashton/d9vk/tags\"\n    DXVK_VERSIONS = [\n        \"0.10\",\n    ]\n    DXVK_LATEST, DXVK_PAST_RELEASES = DXVK_VERSIONS[0], DXVK_VERSIONS[1:9]\n\n    base_url = \"https://github.com/Joshua-Ashton/d9vk/releases/download/{}/d9vk-{}.tar.gz\"\n    base_name = \"d9vk\"\n    base_dir = os.path.join(RUNTIME_DIR, base_name)\n    dxvk_dlls = (\"d3d9\",)\n    latest_version = DXVK_LATEST\n", "path": "lutris/util/wine/dxvk.py"}]}