158 lines
		
	
	
		
			4.6 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			158 lines
		
	
	
		
			4.6 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| import os
 | |
| import platform
 | |
| import re
 | |
| import sys
 | |
| from contextlib import suppress
 | |
| from pathlib import Path
 | |
| 
 | |
| from worlds._sc2common.bot import logger
 | |
| 
 | |
| from . import wsl
 | |
| 
 | |
| BASEDIR = {
 | |
|     "Windows": "C:/Program Files (x86)/StarCraft II",
 | |
|     "WSL1": "/mnt/c/Program Files (x86)/StarCraft II",
 | |
|     "WSL2": "/mnt/c/Program Files (x86)/StarCraft II",
 | |
|     "Darwin": "/Applications/StarCraft II",
 | |
|     "Linux": "~/StarCraftII",
 | |
|     "WineLinux": "~/.wine/drive_c/Program Files (x86)/StarCraft II",
 | |
| }
 | |
| 
 | |
| USERPATH = {
 | |
|     "Windows": "Documents\\StarCraft II\\ExecuteInfo.txt",
 | |
|     "WSL1": "Documents/StarCraft II/ExecuteInfo.txt",
 | |
|     "WSL2": "Documents/StarCraft II/ExecuteInfo.txt",
 | |
|     "Darwin": "Library/Application Support/Blizzard/StarCraft II/ExecuteInfo.txt",
 | |
|     "Linux": None,
 | |
|     "WineLinux": None,
 | |
| }
 | |
| 
 | |
| BINPATH = {
 | |
|     "Windows": "SC2_x64.exe",
 | |
|     "WSL1": "SC2_x64.exe",
 | |
|     "WSL2": "SC2_x64.exe",
 | |
|     "Darwin": "SC2.app/Contents/MacOS/SC2",
 | |
|     "Linux": "SC2_x64",
 | |
|     "WineLinux": "SC2_x64.exe",
 | |
| }
 | |
| 
 | |
| CWD = {
 | |
|     "Windows": "Support64",
 | |
|     "WSL1": "Support64",
 | |
|     "WSL2": "Support64",
 | |
|     "Darwin": None,
 | |
|     "Linux": None,
 | |
|     "WineLinux": "Support64",
 | |
| }
 | |
| 
 | |
| 
 | |
| def platform_detect():
 | |
|     pf = os.environ.get("SC2PF", platform.system())
 | |
|     if pf == "Linux":
 | |
|         return wsl.detect() or pf
 | |
|     return pf
 | |
| 
 | |
| 
 | |
| PF = platform_detect()
 | |
| 
 | |
| 
 | |
| def get_home():
 | |
|     """Get home directory of user, using Windows home directory for WSL."""
 | |
|     if PF in {"WSL1", "WSL2"}:
 | |
|         return wsl.get_wsl_home() or Path.home().expanduser()
 | |
|     return Path.home().expanduser()
 | |
| 
 | |
| 
 | |
| def get_user_sc2_install():
 | |
|     """Attempts to find a user's SC2 install if their OS has ExecuteInfo.txt"""
 | |
|     if USERPATH[PF]:
 | |
|         einfo = str(get_home() / Path(USERPATH[PF]))
 | |
|         if os.path.isfile(einfo):
 | |
|             with open(einfo) as f:
 | |
|                 content = f.read()
 | |
|             if content:
 | |
|                 base = re.search(r" = (.*)Versions", content).group(1)
 | |
|                 if PF in {"WSL1", "WSL2"}:
 | |
|                     base = str(wsl.win_path_to_wsl_path(base))
 | |
| 
 | |
|                 if os.path.exists(base):
 | |
|                     return base
 | |
|     return None
 | |
| 
 | |
| 
 | |
| def get_env():
 | |
|     # TODO: Linux env conf from: https://github.com/deepmind/pysc2/blob/master/pysc2/run_configs/platforms.py
 | |
|     return None
 | |
| 
 | |
| 
 | |
| def get_runner_args(cwd):
 | |
|     if "WINE" in os.environ:
 | |
|         runner_file = Path(os.environ.get("WINE"))
 | |
|         runner_file = runner_file if runner_file.is_file() else runner_file / "wine"
 | |
|         """
 | |
|         TODO Is converting linux path really necessary?
 | |
|         That would convert
 | |
|         '/home/burny/Games/battlenet/drive_c/Program Files (x86)/StarCraft II/Support64'
 | |
|         to
 | |
|         'Z:\\home\\burny\\Games\\battlenet\\drive_c\\Program Files (x86)\\StarCraft II\\Support64'
 | |
|         """
 | |
|         return [runner_file, "start", "/d", cwd, "/unix"]
 | |
|     return []
 | |
| 
 | |
| 
 | |
| def latest_executeble(versions_dir, base_build=None):
 | |
|     latest = None
 | |
| 
 | |
|     if base_build is not None:
 | |
|         with suppress(ValueError):
 | |
|             latest = (
 | |
|                 int(base_build[4:]),
 | |
|                 max(p for p in versions_dir.iterdir() if p.is_dir() and p.name.startswith(str(base_build))),
 | |
|             )
 | |
| 
 | |
|     if base_build is None or latest is None:
 | |
|         latest = max((int(p.name[4:]), p) for p in versions_dir.iterdir() if p.is_dir() and p.name.startswith("Base"))
 | |
| 
 | |
|     version, path = latest
 | |
| 
 | |
|     if version < 55958:
 | |
|         logger.critical("Your SC2 binary is too old. Upgrade to 3.16.1 or newer.")
 | |
|         sys.exit(1)
 | |
|     return path / BINPATH[PF]
 | |
| 
 | |
| 
 | |
| class _MetaPaths(type):
 | |
|     """"Lazily loads paths to allow importing the library even if SC2 isn't installed."""
 | |
| 
 | |
|     # pylint: disable=C0203
 | |
|     def __setup(self):
 | |
|         if PF not in BASEDIR:
 | |
|             logger.critical(f"Unsupported platform '{PF}'")
 | |
|             sys.exit(1)
 | |
| 
 | |
|         try:
 | |
|             base = os.environ.get("SC2PATH") or get_user_sc2_install() or BASEDIR[PF]
 | |
|             self.BASE = Path(base).expanduser()
 | |
|             self.EXECUTABLE = latest_executeble(self.BASE / "Versions")
 | |
|             self.CWD = self.BASE / CWD[PF] if CWD[PF] else None
 | |
| 
 | |
|             self.REPLAYS = self.BASE / "Replays"
 | |
| 
 | |
|             if (self.BASE / "maps").exists():
 | |
|                 self.MAPS = self.BASE / "maps"
 | |
|             else:
 | |
|                 self.MAPS = self.BASE / "Maps"
 | |
|         except FileNotFoundError as e:
 | |
|             logger.critical(f"SC2 installation not found: File '{e.filename}' does not exist.")
 | |
|             sys.exit(1)
 | |
| 
 | |
|     # pylint: disable=C0203
 | |
|     def __getattr__(self, attr):
 | |
|         # pylint: disable=E1120
 | |
|         self.__setup()
 | |
|         return getattr(self, attr)
 | |
| 
 | |
| 
 | |
| class Paths(metaclass=_MetaPaths):
 | |
|     """Paths for SC2 folders, lazily loaded using the above metaclass."""
 | 
