Skip to content

Commit dc50f65

Browse files
authored
6876 unreal detection (#3)
Revisited the logic to retrieve Unreal versions to just exploring well known paths, instead of relying on Windows registries on Windows. Retrieve full version major, minor, path from the sidecar version file.
1 parent 378d16e commit dc50f65

File tree

1 file changed

+36
-160
lines changed

1 file changed

+36
-160
lines changed

startup.py

Lines changed: 36 additions & 160 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,11 @@
33
# file included in this repository.
44

55
import os
6-
import re
76
import sys
87
import pprint
98
import json
109

10+
import sgtk
1111
from sgtk.platform import SoftwareLauncher, SoftwareVersion, LaunchInformation
1212

1313

@@ -33,6 +33,10 @@ class EngineLauncher(SoftwareLauncher):
3333
"darwin": [
3434
"/Users/Shared/Epic Games/UE_{version}/Engine/Binaries/Mac/UE{major}Editor.app"
3535
],
36+
"win32": [
37+
"C:/Program Files/Epic Games/UE_{version}/Engine/Binaries/Win64/UE{major}Editor.exe",
38+
"C:/Program Files/Epic Games/UE_{version}EA/Engine/Binaries/Win64/UnrealEditor.exe"
39+
],
3640
}
3741

3842
@property
@@ -137,17 +141,18 @@ def _find_software(self):
137141
:returns: List of :class:`SoftwareVersion` instances.
138142
"""
139143
self.logger.info("Finding Unreal Engine executables")
144+
sw_versions = []
145+
146+
# Get the executable templates for the current OS
147+
executable_templates = None
148+
if sgtk.util.is_macos():
149+
executable_templates = self.EXECUTABLE_TEMPLATES.get("darwin")
150+
elif sgtk.util.is_windows():
151+
executable_templates = self.EXECUTABLE_TEMPLATES.get("win32")
152+
elif sgtk.util.is_linux():
153+
executable_templates = self.EXECUTABLE_TEMPLATES.get("linux")
140154

141-
if sys.platform == "win32":
142-
# Determine a list of paths to search for Unreal Editor executables based on the windows registry
143-
search_paths = self._get_installation_paths_from_registry()
144-
sw_versions = self._get_software_from_search_paths(search_paths, "Unreal Engine")
145-
# Also look for custom developer builds
146-
search_paths = self._get_development_builds_paths_from_registry()
147-
sw_versions = sw_versions + self._get_software_from_search_paths(search_paths, "Unreal Engine (Dev Build)")
148-
elif sys.platform == "darwin":
149-
executable_templates = self.EXECUTABLE_TEMPLATES["darwin"]
150-
sw_versions = []
155+
if executable_templates:
151156
for executable_template in executable_templates:
152157
self.logger.debug("Processing template %s.", executable_template)
153158
executable_matches = self._glob_and_match(
@@ -158,6 +163,13 @@ def _find_software(self):
158163
# extract the matched keys form the key_dict (default to None if
159164
# not included)
160165
executable_version = key_dict.get("version")
166+
details = self._get_unreal_version_details(executable_path)
167+
if details and all(x in details for x in ["MajorVersion", "MinorVersion", "PatchVersion"]):
168+
executable_version = "%s.%s.%s" % (
169+
details["MajorVersion"],
170+
details["MinorVersion"],
171+
details["PatchVersion"],
172+
)
161173
sw_versions.append(
162174
SoftwareVersion(
163175
executable_version,
@@ -171,155 +183,19 @@ def _find_software(self):
171183

172184
return sw_versions
173185

174-
def _get_software_from_search_paths(self, search_paths, display_name):
175-
"""
176-
:returns: List of :class:`SoftwareVersion` instances.
177-
"""
178-
sw_versions = []
179-
for search_path in search_paths:
180-
# Construct the expected executable name for this path.
181-
# If it exists, add it to the list of exec_paths to check.
182-
exec_path, executable_version = self._find_exec_and_version(search_path)
183-
184-
if exec_path:
185-
# Create a SoftwareVersion using the information from executable
186-
# path(s) found in default locations.
187-
self.logger.debug("Creating SoftwareVersion for executable '%s'." % exec_path)
188-
sw_versions.append(SoftwareVersion(
189-
executable_version,
190-
display_name,
191-
exec_path,
192-
os.path.join(self.disk_location, "icon_256.png")
193-
))
194-
195-
return sw_versions
196-
197-
def _find_exec_and_version(self, root_path):
198-
"""
199-
Check if there's an Unreal executable in the given path.
200-
201-
:returns: A tuple with the path to executable and its version as a string
202-
or `None`, ``None`.
203-
"""
204-
# With the given root path, check if there's an Unreal executable in it and its version
205-
binary_folder = "Engine\\Binaries\\Win64"
206-
executable_filename = "UE4Editor.exe"
207-
version_filename = "UE4Editor.version"
208-
209-
# Construct the expected executable name for this root path.
210-
exec_path = os.path.join(root_path, binary_folder, executable_filename)
211-
exec_path = os.path.normpath(exec_path)
212-
versionfile_path = os.path.join(root_path, binary_folder, version_filename)
213-
self.logger.debug("Checking installation path %s" % exec_path)
214-
215-
if os.path.exists(exec_path):
216-
self.logger.debug("Found executable in installation path %s" % exec_path)
217-
218-
if os.path.exists(versionfile_path):
219-
self.logger.debug("Version file found in installation path %s" % versionfile_path)
220-
else:
221-
self.logger.debug("Version file not found in installation path %s" % versionfile_path)
222-
versionfile_path = None
223-
else:
224-
return None, None
225-
226-
executable_version = "0"
227-
# First, try to find the executable version from the version file
228-
if versionfile_path is not None:
229-
self.logger.debug("Parsing version from file '%s'." % versionfile_path)
230-
version_data = json.load(open(versionfile_path))
231-
executable_version = str(version_data["MajorVersion"]) + "." + str(version_data["MinorVersion"]) + "." + str(version_data["PatchVersion"])
232-
else:
233-
# As a fallback method:
234-
# Check to see if the version number can be parsed from the path name.
235-
# It's expected to find a subdir named "ue_x.yy", where x is the major, and yy the minor version
236-
self.logger.debug("Parsing version from path '%s'." % exec_path)
237-
path_sw_versions = [p.lower() for p in exec_path.split(os.path.sep)
238-
if re.match("ue_[0-9]+[.0-9]*$", p.lower()) is not None
239-
]
240-
if path_sw_versions:
241-
# Use this sub dir to determine the version of the executable
242-
executable_version = path_sw_versions[0].replace("ue_", "")
243-
self.logger.debug(
244-
"Resolved version '%s' from executable '%s'." %
245-
(executable_version, exec_path)
246-
)
247-
248-
return exec_path, executable_version
249-
250-
def _get_installation_paths_from_registry(self):
251-
"""
252-
Query Windows registry for Unreal installations.
253-
254-
:returns: List of paths where Unreal is installed
255-
"""
256-
try:
257-
import _winreg
258-
except ImportError:
259-
import winreg as _winreg
260-
self.logger.debug("Querying windows registry for key HKEY_LOCAL_MACHINE\\SOFTWARE\\EpicGames\\Unreal Engine")
261-
262-
base_key_name = "SOFTWARE\\EpicGames\\Unreal Engine"
263-
sub_key_names = []
264-
265-
# find all subkeys in key HKEY_LOCAL_MACHINE\SOFTWARE\EpicGames\Unreal Engine
266-
try:
267-
key = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE, base_key_name)
268-
sub_key_count = _winreg.QueryInfoKey(key)[0]
269-
i = 0
270-
while i < sub_key_count:
271-
sub_key_names.append(_winreg.EnumKey(key, i))
272-
i += 1
273-
_winreg.CloseKey(key)
274-
except WindowsError:
275-
self.logger.error("error opening key %s" % base_key_name)
276-
277-
install_paths = []
278-
# Query the value "InstalledDirectory" on all subkeys.
279-
try:
280-
for name in sub_key_names:
281-
key_name = base_key_name + "\\" + name
282-
key = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE, key_name)
283-
try:
284-
install_paths.append(_winreg.QueryValueEx(key, "InstalledDirectory")[0])
285-
self.logger.debug("Found InstalledDirectory value for key %s" % key_name)
286-
except WindowsError:
287-
self.logger.debug("value InstalledDirectory not found for key %s, skipping key" % key_name)
288-
_winreg.CloseKey(key)
289-
except WindowsError:
290-
self.logger.error("error opening key %s" % key_name)
291-
292-
return install_paths
293-
294-
def _get_development_builds_paths_from_registry(self):
186+
def _get_unreal_version_details(self, executable_path):
295187
"""
296-
Query Windows registry for Unreal custom developer builds.
188+
Return version details for the given Unreal executable, if any.
297189
298-
:returns: List of paths where Unreal executable is found
190+
:param str executable_path: Full path to an Unreal Editor executable.
191+
:returns: A dictionary with version details retrieved from the side car file for the
192+
given Unreal Editor executable, or ``None``.
299193
"""
300-
try:
301-
import _winreg
302-
except ImportError:
303-
import winreg as _winreg
304-
305-
self.logger.debug("Querying windows registry for key HKEY_CURRENT_USER\\SOFTWARE\\Epic Games\\Unreal Engine\\Builds")
306-
307-
base_key_name = "SOFTWARE\\Epic Games\\Unreal Engine\\Builds"
308-
install_paths = []
309-
310-
# find all values in key HKEY_CURRENT_USER\SOFTWARE\Epic Games\Unreal Engine\Builds
311-
try:
312-
key = _winreg.OpenKey(_winreg.HKEY_CURRENT_USER, base_key_name)
313-
values_count = _winreg.QueryInfoKey(key)[1]
314-
self.logger.debug("Found %d values." % values_count)
315-
i = 0
316-
while i < values_count:
317-
value = _winreg.EnumValue(key, i)
318-
install_paths.append(value[1])
319-
self.logger.debug("Found Unreal executable path '%s'." % value[1])
320-
i += 1
321-
_winreg.CloseKey(key)
322-
except WindowsError:
323-
self.logger.error("error opening key %s" % base_key_name)
324-
325-
return install_paths
194+
version_details = None
195+
path, exe = os.path.split(executable_path)
196+
version_file = "%s.version" % os.path.splitext(exe)[0]
197+
full_path = os.path.join(path, version_file)
198+
if os.path.exists(full_path):
199+
with open(full_path) as pf:
200+
version_details = json.load(pf)
201+
return version_details

0 commit comments

Comments
 (0)