Skip to content

Commit 4bd9a37

Browse files
Look for RLBotServer in cwd or %localappdata% if not specified
1 parent 8537bfa commit 4bd9a37

File tree

6 files changed

+94
-66
lines changed

6 files changed

+94
-66
lines changed

rlbot/managers/match.py

Lines changed: 57 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import os
2+
import stat
13
from pathlib import Path
24
from time import sleep
35

@@ -7,7 +9,7 @@
79
from rlbot.interface import RLBOT_SERVER_IP, RLBOT_SERVER_PORT, SocketRelay
810
from rlbot.utils import fill_desired_game_state, gateway
911
from rlbot.utils.logging import DEFAULT_LOGGER
10-
from rlbot.utils.os_detector import MAIN_EXECUTABLE_NAME
12+
from rlbot.utils.os_detector import RLBOT_SERVER_NAME, OS, CURRENT_OS
1113

1214

1315
class MatchManager:
@@ -23,11 +25,17 @@ class MatchManager:
2325

2426
def __init__(
2527
self,
26-
main_executable_path: Path | None = None,
27-
main_executable_name: str = MAIN_EXECUTABLE_NAME,
28+
rlbot_server_path: Path | None = None
2829
):
29-
self.main_executable_path = main_executable_path
30-
self.main_executable_name = main_executable_name
30+
"""
31+
Initialize a MatchManager.
32+
Args:
33+
rlbot_server_path: The path to the RLBotServer executable. The path is used to launch the server
34+
if it is not already running. If set to None, the RLBotServer in the current working directory will
35+
be used, and otherwise the globally installed RLBotServer will be used.
36+
"""
37+
38+
self.rlbot_server_path = rlbot_server_path
3139

3240
self.rlbot_interface: SocketRelay = SocketRelay("")
3341
self.rlbot_interface.packet_handlers.append(self._packet_reporter)
@@ -41,27 +49,60 @@ def __exit__(self, exc_type, exc_val, exc_tb) -> None:
4149
def ensure_server_started(self):
4250
"""
4351
Ensures that RLBotServer is running, starting it if it is not.
52+
If no path to an RLBotServer executable was passed during initialization of the MatchManager,
53+
the function will use the RLBotServer executable in the current working directory, if any, or
54+
otherwise the global installed RLBotServer will be used, if any.
4455
"""
4556

46-
self.rlbot_server_process, self.rlbot_server_port = gateway.find_server_process(
47-
self.main_executable_name
48-
)
57+
exe_name = self.rlbot_server_path.stem if self.rlbot_server_path is not None and self.rlbot_server_path.is_file() else RLBOT_SERVER_NAME
58+
self.rlbot_server_process, self.rlbot_server_port = gateway.find_server_process(exe_name)
4959
if self.rlbot_server_process is not None:
50-
self.logger.info("Already have %s running!", self.main_executable_name)
60+
self.logger.info("%s is already running!", exe_name)
5161
return
5262

53-
if self.main_executable_path is None:
54-
self.main_executable_path = Path.cwd()
63+
if self.rlbot_server_path is None:
64+
# Look in cwd or localappdata
65+
path = Path.cwd() / RLBOT_SERVER_NAME
66+
if not path.exists() and CURRENT_OS == OS.WINDOWS:
67+
self.logger.debug(f"Could not find RLBotServer in cwd ('{path.parent}'), trying %localappdata% instead.")
68+
path = Path(os.environ.get("LOCALAPPDATA")) / "RLBot5" / "bin" / RLBOT_SERVER_NAME
69+
if not path.exists():
70+
raise FileNotFoundError(
71+
"Unable to find RLBotServer in the current working directory "
72+
"or in the default installation location. "
73+
"Is your antivirus messing you up? Check "
74+
"https://github.com/RLBot/RLBot/wiki/Antivirus-Notes."
75+
)
76+
else:
77+
# User specified path
78+
path = self.rlbot_server_path
79+
if path.exists() and path.is_dir():
80+
path = path / RLBOT_SERVER_NAME
81+
if not path.exists():
82+
raise FileNotFoundError(f"Unable to find RLBotServer at the specified path '{path}'.")
83+
84+
if path is None or not os.access(path, os.F_OK):
85+
raise FileNotFoundError(
86+
f"Unable to find RLBotServer at '{path}'. "
87+
"Is your antivirus messing you up? Check "
88+
"https://github.com/RLBot/RLBot/wiki/Antivirus-Notes."
89+
)
90+
91+
if not os.access(path, os.X_OK):
92+
os.chmod(path, stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH)
5593

56-
rlbot_server_process, self.rlbot_server_port = gateway.launch(
57-
self.main_executable_path,
58-
self.main_executable_name,
59-
)
94+
if not os.access(path, os.X_OK):
95+
raise PermissionError(
96+
"Unable to execute RLBotServer due to file permissions! Is your antivirus messing you up? "
97+
f"Check https://github.com/RLBot/RLBot/wiki/Antivirus-Notes. The exact path is '{path}'"
98+
)
99+
100+
rlbot_server_process, self.rlbot_server_port = gateway.launch(path)
60101
self.rlbot_server_process = psutil.Process(rlbot_server_process.pid)
61102

62103
self.logger.info(
63104
"Started %s with process id %s",
64-
self.main_executable_name,
105+
path,
65106
self.rlbot_server_process.pid,
66107
)
67108

rlbot/utils/gateway.py

Lines changed: 23 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -14,21 +14,23 @@
1414
import shlex
1515

1616

17-
def find_main_executable_path(
18-
main_executable_path: Path, main_executable_name: str
19-
) -> tuple[Path, Path | None]:
20-
main_executable_path = main_executable_path.absolute().resolve()
21-
22-
# check if the path is directly to the main executable
23-
if main_executable_path.is_file():
24-
return main_executable_path.parent, main_executable_path
25-
26-
# search subdirectories for the main executable
27-
for path in main_executable_path.glob(f"**/{main_executable_name}"):
17+
def find_file(
18+
base_dir: Path, file_name: str
19+
) -> Path | None:
20+
"""
21+
Looks for a file called `file_name` in the given `base_dir` directory and its subdirectories.
22+
Returns the path to the file, or None if it was not found.
23+
"""
24+
25+
base_dir = base_dir.absolute().resolve()
26+
assert base_dir.exists() and base_dir.is_dir(), f"'{base_dir}' is not a directory!"
27+
28+
# Search subdirectories for the file
29+
for path in base_dir.glob(f"**/{file_name}"):
2830
if path.is_file():
29-
return path.parent, path
31+
return path
3032

31-
return main_executable_path, None
33+
return None
3234

3335

3436
def is_port_accessible(port: int):
@@ -51,47 +53,26 @@ def find_open_server_port() -> int:
5153
)
5254

5355

54-
def launch(
55-
main_executable_path: Path, main_executable_name: str
56-
) -> tuple[subprocess.Popen[bytes], int]:
57-
directory, path = find_main_executable_path(
58-
main_executable_path, main_executable_name
59-
)
60-
61-
if path is None or not os.access(path, os.F_OK):
62-
raise FileNotFoundError(
63-
f"Unable to find RLBotServer at '{main_executable_path}'. "
64-
"Is your antivirus messing you up? Check "
65-
"https://github.com/RLBot/RLBot/wiki/Antivirus-Notes."
66-
)
67-
68-
if not os.access(path, os.X_OK):
69-
os.chmod(path, stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH)
70-
71-
if not os.access(path, os.X_OK):
72-
raise PermissionError(
73-
"Unable to execute RLBotServer due to file permissions! Is your antivirus messing you up? "
74-
f"Check https://github.com/RLBot/RLBot/wiki/Antivirus-Notes. The exact path is {path}"
75-
)
56+
def launch(exe_path: Path) -> tuple[subprocess.Popen[bytes], int]:
7657

7758
port = find_open_server_port()
7859

7960
if CURRENT_OS == "Windows":
80-
args = [str(path), str(port)]
61+
args = [str(exe_path), str(port)]
8162
else:
82-
args = f"{shlex.quote(path.as_posix())} {port}" # on Unix, when shell=True, args must be a string for flags to reach the executable
83-
DEFAULT_LOGGER.info("Launching RLBotServer with via %s", args)
63+
args = f"{shlex.quote(exe_path.as_posix())} {port}" # on Unix, when shell=True, args must be a string for flags to reach the executable
64+
DEFAULT_LOGGER.info("Launching RLBotServer via %s", args)
8465

85-
return subprocess.Popen(args, shell=True, cwd=directory), port
66+
return subprocess.Popen(args, shell=True, cwd=exe_path.parent), port
8667

8768

8869
def find_server_process(
89-
main_executable_name: str,
70+
exe_name: str,
9071
) -> tuple[psutil.Process | None, int]:
9172
logger = DEFAULT_LOGGER
9273
for proc in psutil.process_iter():
9374
try:
94-
if proc.name() != main_executable_name:
75+
if proc.name() != exe_name:
9576
continue
9677

9778
args = proc.cmdline()
@@ -106,7 +87,7 @@ def find_server_process(
10687
except Exception as e:
10788
logger.error(
10889
"Failed to read the name of a process while hunting for %s: %s",
109-
main_executable_name,
90+
exe_name,
11091
e,
11192
)
11293

rlbot/utils/os_detector.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,15 @@ class OS(IntEnum):
1010

1111
match platform.system():
1212
case "Windows":
13-
MAIN_EXECUTABLE_NAME = "RLBotServer.exe"
13+
RLBOT_SERVER_NAME = "RLBotServer.exe"
1414
CURRENT_OS = OS.WINDOWS
1515
case "Linux":
16-
MAIN_EXECUTABLE_NAME = "RLBotServer"
16+
RLBOT_SERVER_NAME = "RLBotServer"
1717
CURRENT_OS = OS.LINUX
1818
case _ as unknown_os:
1919
from rlbot.utils.logging import get_logger
2020

21-
MAIN_EXECUTABLE_NAME = ""
21+
RLBOT_SERVER_NAME = ""
2222
CURRENT_OS = OS.UNKNOWN
2323

2424
get_logger("os_detector").warning("Unknown OS: %s", unknown_os)

tests/many_match.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,13 @@
44
from rlbot import flat
55
from rlbot.config import load_player_config
66
from rlbot.managers import MatchManager
7+
from rlbot.utils.gateway import find_file
8+
from rlbot.utils.os_detector import RLBOT_SERVER_NAME
79

810
DIR = Path(__file__).parent
911

1012
BOT_PATH = DIR / "atba/atba.bot.toml"
11-
RLBOT_SERVER_FOLDER = DIR / "../../core/RLBotCS/bin/Release/"
13+
RLBOT_SERVER_FOLDER = find_file(DIR / "../../core/RLBotCS/bin/Release/", RLBOT_SERVER_NAME)
1214

1315
num_comms = set()
1416

tests/run_forever.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,17 @@
44
from rlbot import flat
55
from rlbot.config import load_player_config
66
from rlbot.managers import MatchManager
7+
from rlbot.utils.gateway import find_file
78
from rlbot.utils.maps import GAME_MAP_TO_UPK, STANDARD_MAPS
9+
from rlbot.utils.os_detector import RLBOT_SERVER_NAME
810

911
DIR = Path(__file__).parent
1012

1113
BOT_PATH = DIR / "atba/atba.bot.toml"
12-
RLBOT_SERVER_FOLDER = DIR / "../../core/RLBotCS/bin/Release/"
14+
RLBOT_SERVER_PATH = find_file(DIR / "../../core/RLBotCS/bin/Release/", RLBOT_SERVER_NAME)
1315

1416
if __name__ == "__main__":
15-
match_manager = MatchManager(RLBOT_SERVER_FOLDER)
17+
match_manager = MatchManager(RLBOT_SERVER_PATH)
1618

1719
current_map = -1
1820

tests/run_match.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,16 @@
33

44
from rlbot import flat
55
from rlbot.managers import MatchManager
6+
from rlbot.utils.gateway import find_file
7+
from rlbot.utils.os_detector import RLBOT_SERVER_NAME
68

79
DIR = Path(__file__).parent
810

911
MATCH_CONFIG_PATH = DIR / "human_vs_atba.toml"
10-
RLBOT_SERVER_FOLDER = DIR / "../../core/RLBotCS/bin/Release/"
12+
RLBOT_SERVER_PATH = find_file(DIR / "../../core/RLBotCS/bin/Release/", RLBOT_SERVER_NAME)
1113

1214
if __name__ == "__main__":
13-
with MatchManager(RLBOT_SERVER_FOLDER) as man:
15+
with MatchManager(RLBOT_SERVER_PATH) as man:
1416
man.start_match(MATCH_CONFIG_PATH)
1517
assert man.packet is not None
1618

0 commit comments

Comments
 (0)