def launch_image( # players info player: Player, nth_player: int, num_players: int, # game settings headless: bool, game_name: str, map_name: str, game_type: GameType, game_speed: int, timeout: Optional[int], timeout_at_frame: Optional[int], hide_names: bool, random_names: bool, drop_players: bool, allow_input: bool, auto_launch: bool, # mount dirs game_dir: str, bot_dir: str, map_dir: str, bwapi_data_bwta_dir: str, bwapi_data_bwta2_dir: str, vnc_base_port: int, vnc_host: int, capture_movement: bool, # docker docker_image: str, nano_cpus: Optional[int], mem_limit: Optional[str]) -> None: """ :raises docker,errors.APIError :raises DockerException """ container_name = f"{game_name}_{nth_player}_{player.name.replace(' ', '_')}" log_dir = f"{game_dir}/{game_name}/logs_{nth_player}" crashes_dir = f"{game_dir}/{game_name}/crashes_{nth_player}" os.makedirs(log_dir, mode=0o777, exist_ok=True) # todo: proper mode os.makedirs(crashes_dir, mode=0o777, exist_ok=True) # todo: proper mode volumes = { xoscmounts(log_dir): { "bind": LOG_DIR, "mode": "rw" }, xoscmounts(map_dir): { "bind": MAP_DIR, "mode": "rw" }, xoscmounts(crashes_dir): { "bind": ERRORS_DIR, "mode": "rw" }, xoscmounts(bwapi_data_bwta_dir): { "bind": BWAPI_DATA_BWTA_DIR, "mode": "rw" }, xoscmounts(bwapi_data_bwta2_dir): { "bind": BWAPI_DATA_BWTA2_DIR, "mode": "rw" }, } ports = {} if not headless: ports.update({"5900/tcp": vnc_base_port + nth_player}) env = dict( PLAYER_NAME=player.name if not random_names else random_string(8), PLAYER_RACE=player.race.value, NTH_PLAYER=nth_player, NUM_PLAYERS=num_players, GAME_NAME=game_name, MAP_NAME=f"/app/sc/maps/{map_name}", GAME_TYPE=game_type.value, SPEED_OVERRIDE=game_speed, HIDE_NAMES="1" if hide_names else "0", DROP_PLAYERS="1" if drop_players else "0", TM_LOG_RESULTS=f"../logs/scores.json", TM_LOG_FRAMETIMES=f"../logs/frames.csv", TM_LOG_UNIT_EVENTS=f"../logs/unit_events.csv", TM_SPEED_OVERRIDE=game_speed, TM_ALLOW_USER_INPUT="1" if isinstance(player, HumanPlayer) or allow_input else "0", TM_TIME_OUT_AT_FRAME=timeout_at_frame or "-1", EXIT_CODE_REALTIME_OUTED=EXIT_CODE_REALTIME_OUTED, CAPTURE_MOUSE_MOVEMENT="1" if capture_movement else "0", HEADFUL_AUTO_LAUNCH="1" if auto_launch else "0", JAVA_DEBUG="0") if timeout is not None: env["PLAY_TIMEOUT"] = timeout if isinstance(player, BotPlayer): # Only mount write directory, read and AI # are copied from the bot directory in proper places in bwapi-data bot_data_write_dir = f"{game_dir}/{game_name}/write_{nth_player}/" os.makedirs(bot_data_write_dir, mode=0o777, exist_ok=True) # todo: proper mode volumes.update({ xoscmounts(bot_data_write_dir): { "bind": BOT_DATA_WRITE_DIR, "mode": "rw" }, xoscmounts(player.bot_dir): { "bind": BOT_DIR, "mode": "ro" }, }) env["BOT_FILE"] = player.bot_basefilename env["BOT_BWAPI"] = player.bwapi_version env["JAVA_DEBUG"] = "0" env["JAVA_DEBUG_PORT"] = "" env["JAVA_OPTS"] = "" command = ["/app/play_bot.sh"] if player.meta.javaDebugPort is not None: ports.update({ f"{player.meta.javaDebugPort}/tcp": player.meta.javaDebugPort }) env["JAVA_DEBUG"] = "1" env["JAVA_DEBUG_PORT"] = player.meta.javaDebugPort if player.meta.javaOpts is not None: env["JAVA_OPTS"] = player.meta.javaOpts if player.meta.port is not None: if isinstance(player.meta.port, int) or player.meta.port.isdigit(): ports.update( {str(player.meta.port) + '/tcp': int(player.meta.port)}) else: forward, local = [int(x) for x in player.meta.port.split(':')] ports.update({str(local) + '/tcp': forward}) else: command = ["/app/play_human.sh"] is_server = nth_player == 0 entrypoint_opts = ["--headful"] if headless: entrypoint_opts = [ "--game", game_name, "--name", player.name, "--race", player.race.value, "--lan" ] if is_server: entrypoint_opts += ["--host", "--map", f"/app/sc/maps/{map_name}"] else: entrypoint_opts += ["--join"] command += entrypoint_opts logger.debug("\n" f"docker_image={docker_image}\n" f"command={pformat(command, indent=4)}\n" f"name={container_name}\n" f"detach={True}\n" f"environment={pformat(env, indent=4)}\n" f"volumes={pformat(volumes, indent=4)}\n" f"network={DOCKER_STARCRAFT_NETWORK}\n" f"ports={ports}\n" f"nano_cpus={nano_cpus}\n" f"mem_limit={mem_limit}\n") container = docker_client.containers.run(docker_image, command=command, name=container_name, detach=True, environment=env, volumes=volumes, network=DOCKER_STARCRAFT_NETWORK, ports=ports, nano_cpus=nano_cpus, mem_limit=mem_limit or None) if container: container_id = running_containers(container_name) logger.info(f"launched {player}") logger.debug( f"container name = '{container_name}', container id = '{container_id}'" ) else: raise DockerException( f"could not launch {player} in container {container_name}")
parser.add_argument('--map', type=str, metavar="MAP.scx", default="sscai/(2)Benzene.scx", help="Name of map on which SC should be played,\n" "relative to --map_dir") parser.add_argument('--headless', action='store_true', help="Launch play in headless mode. \n" "No VNC viewer will be launched.") # Game settings parser.add_argument("--game_name", type=str, default=random_string(8), help="Override the auto-generated game name") parser.add_argument("--game_type", type=str, metavar="GAME_TYPE", default=GameType.FREE_FOR_ALL.value, choices=[game_type.value for game_type in GameType], help="Set game type. It can be one of:\n- " + "\n- ".join([game_type.value for game_type in GameType])) parser.add_argument("--game_speed", type=int, default=0, help="Set game speed (pause of ms between frames),\n" "use -1 for game default.") parser.add_argument("--timeout", type=int,