Ejemplo n.º 1
0
    def _start_gateway(self, p2=Machete):
        # auto select callback server port and reset it in java env
        self.gateway = JavaGateway(gateway_parameters=GatewayParameters(
            port=self.port), callback_server_parameters=CallbackServerParameters(port=0))
        python_port = self.gateway.get_callback_server().get_listening_port()
        self.gateway.java_gateway_server.resetCallbackClient(
            self.gateway.java_gateway_server.getCallbackClient().getAddress(), python_port)
        self.manager = self.gateway.entry_point

        # create pipe between gym_env_api and python_ai for java env
        server, client = Pipe()
        self.pipe = server
        self.p1 = GymAIDisplay(self.gateway, client, False)
        self.manager.registerAI(self.p1.__class__.__name__, self.p1)

        if isinstance(p2, str):
            # p2 is a java class name
            self.p2 = p2
            self.game_to_start = self.manager.createGame(
                "ZEN", "ZEN", self.p1.__class__.__name__, self.p2, self.freq_restart_java)
        else:
            # p2 is a python class
            self.p2 = p2(self.gateway)
            self.manager.registerAI(self.p2.__class__.__name__, self.p2)
            self.game_to_start = self.manager.createGame(
                "ZEN", "ZEN", self.p1.__class__.__name__, self.p2.__class__.__name__, self.freq_restart_java)
        self.game = Thread(target=game_thread,
                           name="game_thread", args=(self, ))
        self.game.start()

        self.game_started = True
        self.round_num = 0
    def _start_gateway(self):
        # auto select callback server port and reset it in java env
        self.gateway = JavaGateway(
            gateway_parameters=GatewayParameters(port=self.port),
            callback_server_parameters=CallbackServerParameters(
                port=self.port + 1))
        python_port = self.gateway.get_callback_server().get_listening_port()
        self.gateway.java_gateway_server.resetCallbackClient(
            self.gateway.java_gateway_server.getCallbackClient().getAddress(),
            python_port)
        self.manager = self.gateway.entry_point

        # check if pipe built
        if self.p1_server is None:
            raise Exception(
                "Must call build_pipe_and_return_p2 and also make p2 env after gym.make() but before env.reset()"
            )
        self.pipe = self.p1_server

        if self.display:
            self.p1 = GymAIDisplay(self.gateway, self.p1_client,
                                   self.frameskip)
            self.p2 = GymAIDisplay(self.gateway, self.p2_client,
                                   self.frameskip)
        else:
            self.p1 = GymAI(self.gateway, self.p1_client, self.frameskip)
            self.p2 = GymAI(self.gateway, self.p2_client, self.frameskip)

        self.manager.registerAI("P1", self.p1)
        self.manager.registerAI("P2", self.p2)

        self.game_to_start = self.manager.createGame("ZEN", "ZEN", "P1", "P2",
                                                     self.freq_restart_java)

        self.game = Thread(target=game_thread,
                           name="game_thread",
                           args=(self, ))
        self.game.start()
        self.game_started = True
        self.round_num = 0
    def _start_gateway(self):
        # auto select callback server port and reset it in java env
        self.gateway = JavaGateway(
            gateway_parameters=GatewayParameters(
                port=self.port,
                enable_memory_management=True,
                # read_timeout=5
            ),
            callback_server_parameters=CallbackServerParameters(
                port=self.port + 1
                # propagate_java_exceptions=True
            ),
        )
        self.python_port = self.gateway.get_callback_server().get_listening_port()
        # print("python_port:{}".format(self.python_port))
        self.gateway.java_gateway_server.resetCallbackClient(
            self.gateway.java_gateway_server.getCallbackClient().getAddress(), self.python_port)
        self.manager = self.gateway.entry_point

        # create pipe between gym_env_api and python_ai for java env
        server, client = Pipe()
        self.pipe = server
        self.client = client
        # change the no frameskip flag
        if self.display:
            self.p1 = GymAIDisplay(self.gateway, self.client, self.frameskip)
        else:
            self.p1 = GymAI(self.gateway, self.client, self.frameskip,self.use_sim)

        self.manager.registerAI(self.p1.__class__.__name__, self.p1)

        if isinstance(self.p2, str):
            # p2 is a java class name
            self.game_to_start = self.manager.createGame(
                "ZEN", "ZEN", self.p1.__class__.__name__, self.p2, self.freq_restart_java)
        else:
            # p2 is a python class
            self.p2 = self.p2(self.gateway)
            self.manager.registerAI(self.p2.__class__.__name__, self.p2)
            self.game_to_start = self.manager.createGame(
                "ZEN", "ZEN", self.p1.__class__.__name__, self.p2.__class__.__name__, self.freq_restart_java)

        self.game = Thread(target=game_thread, name="game_thread", args=(self, ))
        self.game.start()
        self.game_started = True
        self.round_num = 0
class FightingiceEnv_Display_NoFrameskip(gym.Env):
    metadata = {'render.modes': ['human']}

    def __init__(self, **kwargs):

        self.freq_restart_java = 3
        self.java_env_path = os.getcwd()

        if "java_env_path" in kwargs.keys():
            self.java_env_path = kwargs["java_env_path"]
        if "freq_restart_java" in kwargs.keys():
            self.freq_restart_java = kwargs["freq_restart_java"]
        if "port" in kwargs.keys():
            self.port = kwargs["port"]
        else:
            try:
                import port_for
                self.port = port_for.select_random(
                )  # select one random port for java env
            except:
                raise ImportError(
                    "Pass port=[your_port] when make env, or install port_for to set startup port automatically, maybe pip install port_for can help"
                )

        _actions = "AIR AIR_A AIR_B AIR_D_DB_BA AIR_D_DB_BB AIR_D_DF_FA AIR_D_DF_FB AIR_DA AIR_DB AIR_F_D_DFA AIR_F_D_DFB AIR_FA AIR_FB AIR_GUARD AIR_GUARD_RECOV AIR_RECOV AIR_UA AIR_UB BACK_JUMP BACK_STEP CHANGE_DOWN CROUCH CROUCH_A CROUCH_B CROUCH_FA CROUCH_FB CROUCH_GUARD CROUCH_GUARD_RECOV CROUCH_RECOV DASH DOWN FOR_JUMP FORWARD_WALK JUMP LANDING NEUTRAL RISE STAND STAND_A STAND_B STAND_D_DB_BA STAND_D_DB_BB STAND_D_DF_FA STAND_D_DF_FB STAND_D_DF_FC STAND_F_D_DFA STAND_F_D_DFB STAND_FA STAND_FB STAND_GUARD STAND_GUARD_RECOV STAND_RECOV THROW_A THROW_B THROW_HIT THROW_SUFFER"
        action_strs = _actions.split(" ")

        self.observation_space = spaces.Box(low=0, high=1, shape=(96, 64, 1))
        self.action_space = spaces.Discrete(len(action_strs))

        os_name = platform.system()
        if os_name.startswith("Linux"):
            self.system_name = "linux"
        elif os_name.startswith("Darwin"):
            self.system_name = "macos"
        else:
            self.system_name = "windows"

        if self.system_name == "linux":
            # first check java can be run, can only be used on Linux
            java_version = subprocess.check_output(
                'java -version 2>&1 | awk -F[\\\"_] \'NR==1{print $2}\'',
                shell=True)
            if java_version == b"\n":
                raise ModuleNotFoundError("Java is not installed")
        else:
            print("Please make sure you can run java if you see some error")

        # second check if FightingIce is installed correct
        start_jar_path = os.path.join(self.java_env_path, "FightingICE.jar")
        start_data_path = os.path.join(self.java_env_path, "data")
        start_lib_path = os.path.join(self.java_env_path, "lib")
        lwjgl_path = os.path.join(start_lib_path, "lwjgl", "*")
        lib_path = os.path.join(start_lib_path, "*")
        start_system_lib_path = os.path.join(self.java_env_path, "lib",
                                             "natives", self.system_name)
        natives_path = os.path.join(start_system_lib_path, "*")
        if os.path.exists(start_jar_path) and os.path.exists(
                start_data_path) and os.path.exists(
                    start_lib_path) and os.path.exists(start_system_lib_path):
            pass
        else:
            error_message = "FightingICE is not installed in your script launched path {}, set path when make() or start script in FightingICE path".format(
                self.java_env_path)
            raise FileExistsError(error_message)

        self.java_ai_path = os.path.join(self.java_env_path, "data", "ai")
        ai_path = os.path.join(self.java_ai_path, "*")
        if self.system_name == "windows":
            self.start_up_str = "{};{};{};{};{}".format(
                start_jar_path, lwjgl_path, natives_path, lib_path, ai_path)
            self.need_set_memory_when_start = True
        else:
            self.start_up_str = "{}:{}:{}:{}:{}".format(
                start_jar_path, lwjgl_path, natives_path, lib_path, ai_path)
            self.need_set_memory_when_start = False

        self.game_started = False
        self.round_num = 0

    def _start_java_game(self):
        # start game
        print("Start java env in {} and port {}".format(
            self.java_env_path, self.port))
        devnull = open(os.devnull, 'w')

        if self.system_name == "windows":
            # -Xms1024m -Xmx1024m we need set this in windows
            self.java_env = subprocess.Popen([
                "java", "-Xms1024m", "-Xmx1024m", "-cp", self.start_up_str,
                "Main", "--port",
                str(self.port), "--py4j", "--fastmode", "--grey-bg",
                "--inverted-player", "1", "--mute", "--limithp", "400", "400"
            ],
                                             stdout=devnull,
                                             stderr=devnull)
        elif self.system_name == "linux":
            self.java_env = subprocess.Popen([
                "java", "-cp", self.start_up_str, "Main", "--port",
                str(self.port), "--py4j", "--fastmode", "--grey-bg",
                "--inverted-player", "1", "--mute", "--limithp", "400", "400"
            ],
                                             stdout=devnull,
                                             stderr=devnull)
        elif self.system_name == "macos":
            self.java_env = subprocess.Popen([
                "java", "-XstartOnFirstThread", "-cp", self.start_up_str,
                "Main", "--port",
                str(self.port), "--py4j", "--fastmode", "--grey-bg",
                "--inverted-player", "1", "--mute", "--limithp", "400", "400"
            ],
                                             stdout=devnull,
                                             stderr=devnull)
        # self.java_env = subprocess.Popen(["java", "-cp", "/home/myt/gym-fightingice/gym_fightingice/FightingICE.jar:/home/myt/gym-fightingice/gym_fightingice/lib/lwjgl/*:/home/myt/gym-fightingice/gym_fightingice/lib/natives/linux/*:/home/myt/gym-fightingice/gym_fightingice/lib/*", "Main", "--port", str(self.free_port), "--py4j", "--c1", "ZEN", "--c2", "ZEN","--fastmode", "--grey-bg", "--inverted-player", "1", "--mute"])
        # sleep 3s for java starting, if your machine is slow, make it longer
        time.sleep(3)

    def _start_gateway(self, p2=Machete):
        # auto select callback server port and reset it in java env
        self.gateway = JavaGateway(
            gateway_parameters=GatewayParameters(port=self.port),
            callback_server_parameters=CallbackServerParameters(port=0))
        python_port = self.gateway.get_callback_server().get_listening_port()
        self.gateway.java_gateway_server.resetCallbackClient(
            self.gateway.java_gateway_server.getCallbackClient().getAddress(),
            python_port)
        self.manager = self.gateway.entry_point

        # create pipe between gym_env_api and python_ai for java env
        server, client = Pipe()
        self.pipe = server
        self.p1 = GymAIDisplay(self.gateway, client, False)
        self.manager.registerAI(self.p1.__class__.__name__, self.p1)

        if isinstance(p2, str):
            # p2 is a java class name
            self.p2 = p2
            self.game_to_start = self.manager.createGame(
                "ZEN", "ZEN", self.p1.__class__.__name__, self.p2,
                self.freq_restart_java)
        else:
            # p2 is a python class
            self.p2 = p2(self.gateway)
            self.manager.registerAI(self.p2.__class__.__name__, self.p2)
            self.game_to_start = self.manager.createGame(
                "ZEN", "ZEN", self.p1.__class__.__name__,
                self.p2.__class__.__name__, self.freq_restart_java)
        self.game = Thread(target=game_thread,
                           name="game_thread",
                           args=(self, ))
        self.game.start()

        self.game_started = True
        self.round_num = 0

    def _close_gateway(self):
        self.gateway.close_callback_server()
        self.gateway.close()
        del self.gateway

    def _close_java_game(self):
        self.java_env.kill()
        del self.java_env
        self.pipe.close()
        del self.pipe
        self.game_started = False

    def reset(self, p2=Machete):
        # start java game if game is not started
        if self.game_started is False:
            try:
                self._close_gateway()
                self._close_java_game()
            except:
                pass
            self._start_java_game()
            self._start_gateway(p2)

        # to provide crash, restart java game in some freq
        if self.round_num == self.freq_restart_java * 3:  # 3 is for round in one game
            try:
                self._close_gateway()
                self._close_java_game()
                self._start_java_game()
            except:
                raise SystemExit("Can not restart game")
            self._start_gateway(p2)

        # just reset is anything ok
        self.pipe.send("reset")
        self.round_num += 1
        obs = self.pipe.recv()
        return obs

    def step(self, action):
        # check if game is running, if not try restart
        # when restart, dict will contain crash info, agent should do something, it is a BUG in this version
        if self.game_started is False:
            dict = {}
            dict["pre_game_crashed"] = True
            return self.reset(), 0, None, dict

        self.pipe.send(["step", action])
        if self.pipe.poll(5):
            message = self.pipe.recv()
            new_obs, reward, done, dict = message
        else:
            new_obs, reward = self.p1.get_obs(), self.p1.get_reward()
            dict = {}
            dict["no_data_receive"] = True
            logging.warning(
                "server can not receive, request to reset the game")
            return new_obs, reward, True, dict
        return new_obs, reward, done, dict

    def render(self, mode='human'):
        # no need
        pass

    def close(self):
        if self.game_started:
            self._close_java_game()