示例#1
0
    def save(self, path=None, fps=60):
        logger.info("ScreenRecorder saving...")

        if path is None:
            directory = os.path.join(os.path.curdir, "recordings")
            if not os.path.exists(directory):
                os.makedirs(directory, mode=0o755)
            path = os.path.join(
                directory,
                time.strftime(
                    f"{self.pyboy.cartridge_title()}-%Y.%m.%d-%H.%M.%S.gif"))

        if len(self.frames) > 0:
            self.frames[0].save(path,
                                save_all=True,
                                interlace=False,
                                loop=0,
                                optimize=True,
                                append_images=self.frames[1:],
                                duration=int(round(1000 / fps, -1)))

            logger.info("Screen recording saved in {}".format(path))
        else:
            logger.error("Screen recording failed: no frames")
        self.frames = []
示例#2
0
文件: pyboy.py 项目: chrsbell/PyBoy
    def openai_gym(self,
                   observation_type="tiles",
                   action_type="press",
                   simultaneous_actions=False,
                   **kwargs):
        """
        For Reinforcement learning, it is often easier to use the standard gym environment. This method will provide one.
        This function requires PyBoy to implement a Game Wrapper for the loaded ROM. You can find the supported games in pyboy.plugins.
        Additional kwargs are passed to the start_game method of the game_wrapper.

        Args:
            observation_type (str): Define what the agent will be able to see:
            * `"raw"`: Gives the raw pixels color
            * `"tiles"`:  Gives the id of the sprites in 8x8 pixel zones of the game_area defined by the game_wrapper.
            * `"compressed"`: Gives a more detailled but heavier representation than `"minimal"`.
            * `"minimal"`: Gives a minimal representation defined by the game_wrapper (recommended).

            action_type (str): Define how the agent will interact with button inputs
            * `"press"`: The agent will only press inputs for 1 frame an then release it.
            * `"toggle"`: The agent will toggle inputs, first time it press and second time it release.
            * `"all"`: The agent have acces to all inputs, press and release are separated.

            simultaneous_actions (bool): Allow to inject multiple input at once. This dramatically increases the action_space: \\(n \\rightarrow 2^n\\)

        Returns
        -------
        `pyboy.openai_gym.PyBoyGymEnv`:
            A Gym environment based on the `Pyboy` object.
        """
        if gym_enabled:
            return PyBoyGymEnv(self, observation_type, action_type,
                               simultaneous_actions, **kwargs)
        else:
            logger.error(f"{__name__}: Missing dependency \"gym\". ")
            return None
示例#3
0
 def _handle_events(self, events):
     # This feeds events into the tick-loop from the window. There might already be events in the list from the API.
     events = self.plugin_manager.handle_events(events)
     for event in events:
         if event == WindowEvent.QUIT:
             self.done = True
         elif event == WindowEvent.RELEASE_SPEED_UP:
             # Switch between unlimited and 1x real-time emulation speed
             self.target_emulationspeed = int(bool(self.target_emulationspeed) ^ True)
             logger.info("Speed limit: %s" % self.target_emulationspeed)
         elif event == WindowEvent.STATE_SAVE:
             with open(self.gamerom_file + ".state", "wb") as f:
                 self.mb.save_state(IntIOWrapper(f))
         elif event == WindowEvent.STATE_LOAD:
             state_path = self.gamerom_file + ".state"
             if not os.path.isfile(state_path):
                 logger.error(f"State file not found: {state_path}")
                 continue
             with open(state_path, "rb") as f:
                 self.mb.load_state(IntIOWrapper(f))
         elif event == WindowEvent.PASS:
             pass # Used in place of None in Cython, when key isn't mapped to anything
         elif event == WindowEvent.PAUSE_TOGGLE:
             if self.paused:
                 self._unpause()
             else:
                 self._pause()
         elif event == WindowEvent.PAUSE:
             self._pause()
         elif event == WindowEvent.UNPAUSE:
             self._unpause()
         elif event == WindowEvent._INTERNAL_RENDERER_FLUSH:
             self.plugin_manager._post_tick_windows()
         else:
             self.mb.buttonevent(event)
示例#4
0
    def getitem(self, address):
        if 0x0000 <= address < 0x4000:
            if self.memorymodel == 1:
                self.rombank_selected = (
                    self.bank_select_register2 << 5) % self.external_rom_count
            else:
                self.rombank_selected = 0
            return self.rombanks[self.rombank_selected][address]
        elif 0x4000 <= address < 0x8000:
            self.rombank_selected = \
                    (self.bank_select_register2 << 5) % self.external_rom_count | self.bank_select_register1
            return self.rombanks[self.rombank_selected %
                                 len(self.rombanks)][address - 0x4000]
        elif 0xA000 <= address < 0xC000:
            if not self.rambank_initialized:
                logger.error("RAM banks not initialized: %s" % hex(address))

            if not self.rambank_enabled:
                return 0xFF

            if self.memorymodel == 1:
                self.rambank_selected = self.bank_select_register2
            else:
                self.rambank_selected = 0
            return self.rambanks[self.rambank_selected %
                                 self.external_ram_count][address - 0xA000]
        else:
            logger.error("Reading address invalid: %s" % address)
示例#5
0
    def setitem(self, address, value):
        if 0x0000 <= address < 0x2000:
            self.rambank_enabled = (value & 0b00001111) == 0b1010
        elif 0x2000 <= address < 0x4000:
            value &= 0b00011111
            # The register cannot contain zero (0b00000) and will be initialized as 0b00001
            # Attempting to write 0b00000 will write 0b00001 instead.
            if value == 0:
                value = 1
            self.bank_select_register1 = value
        elif 0x4000 <= address < 0x6000:
            self.bank_select_register2 = value & 0b11
        elif 0x6000 <= address < 0x8000:
            self.memorymodel = value & 0b1
        elif 0xA000 <= address < 0xC000:
            if self.rambanks is None:
                logger.warning(
                    "Game tries to set value 0x%0.2x at RAM address 0x%0.4x, but RAM "
                    "banks are not initialized. Initializing %d RAM banks as "
                    "precaution" % (value, address, self.external_ram_count))
                self.init_rambanks(self.external_ram_count)

            if self.rambank_enabled:
                self.rambank_selected = self.bank_select_register2 if self.memorymodel == 1 else 0
                self.rambanks[self.rambank_selected %
                              self.external_ram_count][address -
                                                       0xA000] = value
        else:
            logger.error("Invalid writing address: %s" % hex(address))
示例#6
0
 def setitem(self, address, value):
     if 0x0000 <= address < 0x2000:
         # 8-bit register. All bits matter, so only 0b00001010 enables RAM.
         self.rambank_enabled = (value == 0b00001010)
     elif 0x2000 <= address < 0x3000:
         # 8-bit register used for the lower 8 bits of the ROM bank number.
         self.rombank_selected = (self.rombank_selected
                                  & 0b100000000) | value
     elif 0x3000 <= address < 0x4000:
         # 1-bit register used for the most significant bit of the ROM bank number.
         self.rombank_selected = (
             (value & 0x1) << 8) | (self.rombank_selected & 0xFF)
     elif 0x4000 <= address < 0x6000:
         self.rambank_selected = value & 0xF
     elif 0xA000 <= address < 0xC000:
         if self.rambanks is None:
             logger.warning(
                 "Game tries to set value 0x%0.2x at RAM address 0x%0.4x, but RAM "
                 "banks are not initialized. Initializing %d RAM banks as "
                 "precaution" % (value, address, self.external_ram_count))
             self.init_rambanks(self.external_ram_count)
         if self.rambank_enabled:
             self.rambanks[self.rambank_selected %
                           self.external_ram_count][address -
                                                    0xA000] = value
     else:
         logger.error("Unexpected write to 0x%0.4x, value: 0x%0.2x" %
                      (address, value))
示例#7
0
 def enabled(self):
     if self.pyboy_argv.get("window_type") == "OpenGL":
         if opengl_enabled:
             return True
         else:
             logger.error(
                 "Missing depencency \"PyOpenGL\". OpenGL window disabled")
     return False
示例#8
0
 def overrideitem(self, rom_bank, address, value):
     if 0x0000 <= address < 0x4000:
         logger.debug(
             "Performing overwrite on address: %s:%s. New value: %s Old value: %s" %
             (hex(rom_bank), hex(address), hex(value), self.rombanks[rom_bank][address])
         )
         self.rombanks[rom_bank][address] = value
     else:
         logger.error("Invalid override address: %s" % hex(address))
示例#9
0
    def getitem(self, address):
        if 0x0000 <= address < 0x4000:
            return self.rombanks[0][address]
        elif 0x4000 <= address < 0x8000:
            return self.rombanks[self.rombank_selected][address - 0x4000]
        elif 0xA000 <= address < 0xC000:
            if not self.rambank_initialized:
                raise logger.error("RAM banks not initialized: %s" %
                                   hex(address))

            if self.rtc_enabled and 0x08 <= self.rambank_selected <= 0x0C:
                return self.rtc.getregister(self.rambank_selected)
            else:
                return self.rambanks[self.rambank_selected][address - 0xA000]
        else:
            raise logger.error("Reading address invalid: %s" % address)
    def set_lives_left(self, amount):
        """
        Set the amount lives to any number between 0 and 99.

        This should only be called when the game has started.

        Args:
            amount (int): The wanted number of lives
        """
        if not self.game_has_started:
            logger.warning("Please call set_lives_left after starting the game")

        if 0 <= amount <= 99:
            tens = amount // 10
            ones = amount % 10
            self.pyboy.set_memory_value(ADDR_LIVES_LEFT, (tens << 4) | ones)
            self.pyboy.set_memory_value(ADDR_LIVES_LEFT_DISPLAY, tens)
            self.pyboy.set_memory_value(ADDR_LIVES_LEFT_DISPLAY + 1, ones)
        else:
            logger.error(f"{amount} is out of bounds. Only values between 0 and 99 allowed.")
示例#11
0
文件: mbc3.py 项目: thejomas/PyBoy
 def setitem(self, address, value):
     if 0x0000 <= address < 0x2000:
         if (value & 0b00001111) == 0b1010:
             self.rambank_enabled = True
         elif value == 0:
             self.rambank_enabled = False
         else:
             # Pan Docs: "Practically any value with 0Ah in the
             # lower 4 bits enables RAM, and any other value
             # disables RAM."
             self.rambank_enabled = False
             logger.warning(
                 "Unexpected command for MBC3: Address: 0x%0.4x, Value: 0x%0.2x"
                 % (address, value))
     elif 0x2000 <= address < 0x4000:
         if value == 0:
             value = 1
         # print "ROM Bank switch:", value & 0b01111111
         self.rombank_selected = value & 0b01111111  # sets 7LSB of ROM bank address
     elif 0x4000 <= address < 0x6000:
         self.rambank_selected = value
     elif 0x6000 <= address < 0x8000:
         if self.rtc_enabled:
             self.rtc.writecommand(value)
         else:
             # NOTE: Pokemon Red/Blue will do this, but it can safely be ignored:
             # https://github.com/pret/pokered/issues/155
             logger.warning(
                 "RTC not present. Game tried to issue RTC command: 0x%0.4x, 0x%0.2x"
                 % (address, value))
     elif 0xA000 <= address < 0xC000:
         if self.rambank_selected <= 0x03:
             self.rambanks[self.rambank_selected][address - 0xA000] = value
         elif 0x08 <= self.rambank_selected <= 0x0C:
             self.rtc.setregister(self.rambank_selected, value)
         else:
             raise logger.error("Invalid RAM bank selected: 0x%0.2x" %
                                self.rambank_selected)
     else:
         raise logger.error("Invalid writing address: 0x%0.4x" % address)
示例#12
0
文件: mbc1.py 项目: thejomas/PyBoy
 def setitem(self, address, value):
     if 0x0000 <= address < 0x2000:
         if (value & 0b00001111) == 0x0A:
             self.rambank_enabled = True
         else:
             self.rambank_enabled = False
     elif 0x2000 <= address < 0x4000:
         # But (when using the register below to specify the upper ROM Bank bits), the same
         # happens for Bank 20h, 40h, and 60h. Any attempt to address these ROM Banks will
         # select Bank 21h, 41h, and 61h instead.
         if value == 0:
             value = 1
         # sets 5LSB of ROM bank address
         self.rombank_selected = self.rombank_selected & 0b11100000 | value & 0b00011111
     elif 0x4000 <= address < 0x6000:
         # Note: 16Mbit = 2MB. 2MB/(8KB banks) = 128 banks. 128 is addressable with 7 bits
         if self.memorymodel == 0:  # 16/8 mode
             # sets 2MSB of ROM bank address
             self.rombank_selected = self.rombank_selected & 0b00011111 | (
                 address & 0b11) << 5
         # Note: 4Mbit = 0.5MB. 0.5MB/(8KB banks) = 32 banks. 32 is addressably with 5 bits
         elif self.memorymodel == 1:  # 4/32 mode
             self.rambank_selected = value & 0b00000011
         else:
             raise logger.error("Invalid memory model: %s" %
                                self.memorymodel)
     elif 0x6000 <= address < 0x8000:
         self.memorymodel = value & 0x1
     elif 0xA000 <= address < 0xC000:
         if self.rambanks is None:
             from . import EXTERNAL_RAM_TABLE
             logger.warning(
                 "Game tries to set value 0x%0.2x at RAM address 0x%0.4x, but RAM "
                 "banks are not initialized. Initializing %d RAM banks as "
                 "precaution" % (value, address, EXTERNAL_RAM_TABLE[0x02]))
             self.init_rambanks(EXTERNAL_RAM_TABLE[0x02])
         self.rambanks[self.rambank_selected][address - 0xA000] = value
     else:
         raise logger.error("Invalid writing address: %s" % hex(address))
示例#13
0
def valid_file_path(path):
    if not path == INTERNAL_LOADSTATE and not os.path.isfile(path):
        logger.error(f"Filepath '{path}' couldn't be found, or isn't a file!")
        exit(1)
    return path