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."""
|