gameboy_worlds.emulation.pokemon.emulators

 1from gameboy_worlds.emulation.emulator import Emulator, LowLevelActions
 2from gameboy_worlds.emulation.pokemon.parsers import PokemonStateParser, AgentState
 3from gameboy_worlds.emulation.pokemon.trackers import CorePokemonTracker
 4from gameboy_worlds.utils import log_error
 5from typing import Tuple
 6import numpy as np
 7
 8
 9class PokemonEmulator(Emulator):
10    """
11    Almost the exact same as Emulator, but forces the agent to not mess with the menu options cursor. Also auto skips naming screens.
12    """
13
14    REQUIRED_STATE_PARSER = PokemonStateParser
15    REQUIRED_STATE_TRACKER = CorePokemonTracker
16    _MAXIMUM_DIALOGUE_PRESSES = 2000  # For now set a crazy high value
17    """ Maximum number of times the agent will click B to get through a dialogue. """
18    _SKIP_DIALOGUE = False
19    """ Whether to auto skip dialogue by clicking B repeatedly until we are no longer in dialogue."""
20
21    def step(self, action=None) -> Tuple[np.ndarray, bool]:
22        frames, done = super().step(action)
23        self.state_parser: PokemonStateParser
24        current_frame = self.get_current_frame()
25        if self.state_parser.is_hovering_over_options_in_menu(current_frame):
26            # WARNING: see the state parser method for details, but this currently does not work before the agent gets the pokedex
27            # force the agent to click the up button to get off the options
28            self.run_action_on_emulator(LowLevelActions.PRESS_ARROW_UP)
29        all_next_frames = [frames]
30        # If we are on a naming screen, just don't pick a name and get out.
31        if self.state_parser.named_region_matches_target(
32            current_frame, name="name_entity_top_left"
33        ):
34            # then enter and get out
35            next_frames = self.run_action_on_emulator(
36                LowLevelActions.PRESS_BUTTON_START
37            )
38            all_next_frames.append(next_frames)
39            next_frames = self.run_action_on_emulator(LowLevelActions.PRESS_BUTTON_A)
40            all_next_frames.append(next_frames)
41        if (
42            self._SKIP_DIALOGUE
43        ):  # Make this True to auto skip dialogue and accumilate it into the frames returned.
44            current_state = self.state_parser.get_agent_state(current_frame)
45            n_clicks = 0
46            # Clicks through any dialogue popups.
47            while (
48                n_clicks < self._MAXIMUM_DIALOGUE_PRESSES
49            ) and current_state == AgentState.IN_DIALOGUE:
50                next_frames = self.run_action_on_emulator(
51                    LowLevelActions.PRESS_BUTTON_B
52                )
53                current_state = self.state_parser.get_agent_state(next_frames[-1])
54                all_next_frames.append(next_frames)
55                n_clicks += 1
56        if len(all_next_frames) > 1:
57            frames = np.concatenate(all_next_frames)
58            self._update_listeners_after_actions(
59                self._get_unique_frames(frames[1:])
60            )  # Skip the first frame as that is already counted
61            frames = self._get_unique_frames(frames)
62        return frames, done
63
64    def _open_to_first_state(self):
65        self._pyboy.tick(10000, False)  # get to opening menu
66        self.run_action_on_emulator(
67            LowLevelActions.PRESS_BUTTON_A
68        )  # press A to get past opening menu
69        self._pyboy.tick(1000, False)  # wait for load
70        self.run_action_on_emulator(
71            LowLevelActions.PRESS_BUTTON_A
72        )  # press A to load game
73        self._pyboy.tick(1000, False)  # wait for file select
74        self.run_action_on_emulator(
75            LowLevelActions.PRESS_BUTTON_A
76        )  # press A to confirm load
77        self._pyboy.tick(5000, False)  # wait for game to load
class PokemonEmulator(gameboy_worlds.emulation.emulator.Emulator):
10class PokemonEmulator(Emulator):
11    """
12    Almost the exact same as Emulator, but forces the agent to not mess with the menu options cursor. Also auto skips naming screens.
13    """
14
15    REQUIRED_STATE_PARSER = PokemonStateParser
16    REQUIRED_STATE_TRACKER = CorePokemonTracker
17    _MAXIMUM_DIALOGUE_PRESSES = 2000  # For now set a crazy high value
18    """ Maximum number of times the agent will click B to get through a dialogue. """
19    _SKIP_DIALOGUE = False
20    """ Whether to auto skip dialogue by clicking B repeatedly until we are no longer in dialogue."""
21
22    def step(self, action=None) -> Tuple[np.ndarray, bool]:
23        frames, done = super().step(action)
24        self.state_parser: PokemonStateParser
25        current_frame = self.get_current_frame()
26        if self.state_parser.is_hovering_over_options_in_menu(current_frame):
27            # WARNING: see the state parser method for details, but this currently does not work before the agent gets the pokedex
28            # force the agent to click the up button to get off the options
29            self.run_action_on_emulator(LowLevelActions.PRESS_ARROW_UP)
30        all_next_frames = [frames]
31        # If we are on a naming screen, just don't pick a name and get out.
32        if self.state_parser.named_region_matches_target(
33            current_frame, name="name_entity_top_left"
34        ):
35            # then enter and get out
36            next_frames = self.run_action_on_emulator(
37                LowLevelActions.PRESS_BUTTON_START
38            )
39            all_next_frames.append(next_frames)
40            next_frames = self.run_action_on_emulator(LowLevelActions.PRESS_BUTTON_A)
41            all_next_frames.append(next_frames)
42        if (
43            self._SKIP_DIALOGUE
44        ):  # Make this True to auto skip dialogue and accumilate it into the frames returned.
45            current_state = self.state_parser.get_agent_state(current_frame)
46            n_clicks = 0
47            # Clicks through any dialogue popups.
48            while (
49                n_clicks < self._MAXIMUM_DIALOGUE_PRESSES
50            ) and current_state == AgentState.IN_DIALOGUE:
51                next_frames = self.run_action_on_emulator(
52                    LowLevelActions.PRESS_BUTTON_B
53                )
54                current_state = self.state_parser.get_agent_state(next_frames[-1])
55                all_next_frames.append(next_frames)
56                n_clicks += 1
57        if len(all_next_frames) > 1:
58            frames = np.concatenate(all_next_frames)
59            self._update_listeners_after_actions(
60                self._get_unique_frames(frames[1:])
61            )  # Skip the first frame as that is already counted
62            frames = self._get_unique_frames(frames)
63        return frames, done
64
65    def _open_to_first_state(self):
66        self._pyboy.tick(10000, False)  # get to opening menu
67        self.run_action_on_emulator(
68            LowLevelActions.PRESS_BUTTON_A
69        )  # press A to get past opening menu
70        self._pyboy.tick(1000, False)  # wait for load
71        self.run_action_on_emulator(
72            LowLevelActions.PRESS_BUTTON_A
73        )  # press A to load game
74        self._pyboy.tick(1000, False)  # wait for file select
75        self.run_action_on_emulator(
76            LowLevelActions.PRESS_BUTTON_A
77        )  # press A to confirm load
78        self._pyboy.tick(5000, False)  # wait for game to load

Almost the exact same as Emulator, but forces the agent to not mess with the menu options cursor. Also auto skips naming screens.

The minimal functionality StateParser needed for this emulator to run

The minimal functionality StateTracker needed for this emulator to run

def step(self, action=None) -> Tuple[numpy.ndarray, bool]:
22    def step(self, action=None) -> Tuple[np.ndarray, bool]:
23        frames, done = super().step(action)
24        self.state_parser: PokemonStateParser
25        current_frame = self.get_current_frame()
26        if self.state_parser.is_hovering_over_options_in_menu(current_frame):
27            # WARNING: see the state parser method for details, but this currently does not work before the agent gets the pokedex
28            # force the agent to click the up button to get off the options
29            self.run_action_on_emulator(LowLevelActions.PRESS_ARROW_UP)
30        all_next_frames = [frames]
31        # If we are on a naming screen, just don't pick a name and get out.
32        if self.state_parser.named_region_matches_target(
33            current_frame, name="name_entity_top_left"
34        ):
35            # then enter and get out
36            next_frames = self.run_action_on_emulator(
37                LowLevelActions.PRESS_BUTTON_START
38            )
39            all_next_frames.append(next_frames)
40            next_frames = self.run_action_on_emulator(LowLevelActions.PRESS_BUTTON_A)
41            all_next_frames.append(next_frames)
42        if (
43            self._SKIP_DIALOGUE
44        ):  # Make this True to auto skip dialogue and accumilate it into the frames returned.
45            current_state = self.state_parser.get_agent_state(current_frame)
46            n_clicks = 0
47            # Clicks through any dialogue popups.
48            while (
49                n_clicks < self._MAXIMUM_DIALOGUE_PRESSES
50            ) and current_state == AgentState.IN_DIALOGUE:
51                next_frames = self.run_action_on_emulator(
52                    LowLevelActions.PRESS_BUTTON_B
53                )
54                current_state = self.state_parser.get_agent_state(next_frames[-1])
55                all_next_frames.append(next_frames)
56                n_clicks += 1
57        if len(all_next_frames) > 1:
58            frames = np.concatenate(all_next_frames)
59            self._update_listeners_after_actions(
60                self._get_unique_frames(frames[1:])
61            )  # Skip the first frame as that is already counted
62            frames = self._get_unique_frames(frames)
63        return frames, done

Takes a step in the environment by performing the given action on the emulator. If saving video, starts the video recording on the first step.

Parameters
  • action: Lowest level action to perform on the emulator.
Returns
- The stack of frames that passed while performing the action, if rendering is enabled. Is of shape [n_frames (3 right now), height, width, channels]. Otherwise, None.

- Is max steps reached.