예제 #1
0
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}")
예제 #2
0
파일: cli.py 프로젝트: tdraebing/sc-docker
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,