diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 00000000..cfe4615e --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "godot_rl_agents_plugin"] + path = godot_rl_agents_plugin + url = git@github.com:edbeeching/godot_rl_agents_plugin.git \ No newline at end of file diff --git a/examples/clean_rl_example.py b/examples/clean_rl_example.py index 593f98f9..e5deed78 100644 --- a/examples/clean_rl_example.py +++ b/examples/clean_rl_example.py @@ -35,8 +35,10 @@ def parse_args(): help="whether to capture videos of the agent performances (check out `videos` folder)") # Algorithm specific arguments - parser.add_argument("--env-id", type=str, default="examples/godot_rl_JumperHard/bin/JumperHard.x86_64", #examples/godot_rl_BallChase/bin/BallChase.x86_64 + parser.add_argument("--env_path", type=str, default="examples/godot_rl_JumperHard/bin/JumperHard.x86_64", #examples/godot_rl_BallChase/bin/BallChase.x86_64 help="the id of the environment") + parser.add_argument("--speedup", type=int, default=8, + help="the speedup of the godot environment") parser.add_argument("--total-timesteps", type=int, default=1000000, help="total timesteps of the experiments") parser.add_argument("--learning-rate", type=float, default=3e-4, @@ -75,9 +77,9 @@ def parse_args(): return args -def make_env(env_id): +def make_env(env_path, speedup): def thunk(): - env = CleanRLGodotEnv(env_path=env_id, show_window=True, speedup=8) + env = CleanRLGodotEnv(env_path=env_path, show_window=True, speedup=speedup) return env return thunk @@ -122,7 +124,7 @@ def get_action_and_value(self, x, action=None): if __name__ == "__main__": args = parse_args() - run_name = f"{args.env_id}__{args.exp_name}__{args.seed}__{int(time.time())}" + run_name = f"{args.env_path}__{args.exp_name}__{args.seed}__{int(time.time())}" if args.track: import wandb @@ -151,7 +153,7 @@ def get_action_and_value(self, x, action=None): # env setup - envs = env = CleanRLGodotEnv(env_path=args.env_id, show_window=True, speedup=8, convert_action_space=True) # Godot envs are already vectorized + envs = env = CleanRLGodotEnv(env_path=args.env_path, show_window=True, speedup=args.speedup, convert_action_space=True) # Godot envs are already vectorized #assert isinstance(envs.single_action_space, gym.spaces.Box), "only continuous action space is supported" args.num_envs = envs.num_envs args.batch_size = int(args.num_envs * args.num_steps) diff --git a/godot_rl/core/godot_env.py b/godot_rl/core/godot_env.py index 616f1132..e63895aa 100644 --- a/godot_rl/core/godot_env.py +++ b/godot_rl/core/godot_env.py @@ -10,7 +10,7 @@ import numpy as np from gym import spaces -from godot_rl.core.utils import ActionSpaceProcessor +from godot_rl.core.utils import ActionSpaceProcessor, convert_macos_path class GodotEnv: @@ -54,17 +54,20 @@ def __init__( def check_platform(self, filename: str): if platform == "linux" or platform == "linux2": + # Linux assert ( pathlib.Path(filename).suffix == ".x86_64" - ), f"incorrect file suffix for fileman {filename} suffix {pathlib.Path(filename).suffix }" + ), f"Incorrect file suffix for filename {filename} suffix {pathlib.Path(filename).suffix }. Please provide a .x86_64 file" elif platform == "darwin": - assert 0, "mac is not supported, yet" - # OS X + # OSX + assert ( + pathlib.Path(filename).suffix == ".app" + ), f"Incorrect file suffix for filename {filename} suffix {pathlib.Path(filename).suffix }. Please provide a .app file" elif platform == "win32": # Windows... assert ( pathlib.Path(filename).suffix == ".exe" - ), f"incorrect file suffix for fileman {filename} suffix {pathlib.Path(filename).suffix }" + ), f"Incorrect file suffix for filename {filename} suffix {pathlib.Path(filename).suffix }. Please provide a .exe file" else: assert 0, f"unknown filetype {pathlib.Path(filename).suffix}" @@ -159,7 +162,9 @@ def _close(self): def _launch_env(self, env_path, port, show_window, framerate, seed, action_repeat, speedup): # --fixed-fps {framerate} - launch_cmd = f"{env_path} --port={port} --env_seed={seed}" + path = convert_macos_path(env_path) if platform == "darwin" else env_path + + launch_cmd = f"{path} --port={port} --env_seed={seed}" if show_window == False: launch_cmd += " --disable-render-loop --headless" diff --git a/godot_rl/core/utils.py b/godot_rl/core/utils.py index 08df235b..19ea0e4a 100644 --- a/godot_rl/core/utils.py +++ b/godot_rl/core/utils.py @@ -1,5 +1,6 @@ import gym import numpy as np +import re def lod_to_dol(lod): @@ -9,6 +10,21 @@ def lod_to_dol(lod): def dol_to_lod(dol): return [dict(zip(dol, t)) for t in zip(*dol.values())] +def convert_macos_path(env_path): + """ + On MacOs the user is supposed to provide a application.app file to env_path. + However the actual binary is in application.app/Contents/Macos/application. + This helper function converts the path to the path of the actual binary. + + Example input: ./Demo.app + Example output: ./Demo.app/Contents/Macos/Demo + """ + + filenames = re.findall(r'[^\/]+(?=\.)', env_path) + assert ( + len(filenames) == 1 + ), f"An error occured while converting the env path for MacOS." + return env_path + "/Contents/MacOS/" + filenames[0] class ActionSpaceProcessor: # can convert tuple action dists to a single continuous action distribution diff --git a/setup.cfg b/setup.cfg index 7048db9a..4fd5875e 100644 --- a/setup.cfg +++ b/setup.cfg @@ -12,6 +12,7 @@ classifiers = packages = find: install_requires = numpy + tensorboard wget huggingface_hub>=0.10 @@ -43,10 +44,11 @@ sb3 = gym==0.21 stable-baselines3 huggingface_sb3 - tensorboard + sf = sample-factory gym==0.26.2 + rllib = ray[rllib]