示例#1
0
def run_read(output_pipe):
    addresses = {
        "test1": Address("0x00000000", "u8"),
        "test2": Address("0x00000001", "u16")
    }
    screen_dims = {"width": 1, "height": 1}
    data_pipe = DataPipe("env1", screen_dims, addresses, "../mame/pipes")
    write_pipe = setup_data_pipe(data_pipe)
    write_pipe.write("1+2+abc\n")
    write_pipe.flush()

    output_pipe.put(data_pipe.read_data())
示例#2
0
    def test_empty_lua_string(self):
        data_pipe, write_pipe = [None] * 2
        try:
            bitmap_format = BitmapFormat.RGB32
            addresses = {}
            screen_dims = {"width": 1, "height": 1}
            data_pipe = DataPipe("env1", screen_dims, bitmap_format, addresses,
                                 "../mame/pipes")
            write_pipe = setup_data_pipe(data_pipe)
            write_pipe.write("1+2+abc\n")
            write_pipe.flush()

            assert_that(
                data_pipe.get_lua_string(),
                equal_to(
                    'dataPipe:write(s:bitmap_binary().."\\n"); dataPipe:flush(); '
                ))
        finally:
            close_pipes(data_pipe, write_pipe)
示例#3
0
    def __init__(self,
                 env_id,
                 roms_path,
                 game_id,
                 memory_addresses,
                 frame_ratio=3,
                 render=True,
                 throttle=False,
                 frame_skip=0,
                 debug=False,
                 binary_path=None):
        self.memory_addresses = memory_addresses
        self.frame_ratio = frame_ratio

        # setup lua engine
        self.console = Console(roms_path,
                               game_id,
                               render=render,
                               throttle=throttle,
                               frame_skip=frame_skip,
                               debug=debug,
                               binary_path=binary_path)
        atexit.register(self.close)
        self.wait_for_resource_registration()
        self.create_lua_variables()
        bitmap_format = self.get_bitmap_format()
        screen_width = self.setup_screen_width()
        screen_height = self.setup_screen_height()
        self.screenDims = {"width": screen_width, "height": screen_height}

        # open pipes
        pipes_path = f"{os.path.dirname(os.path.abspath(__file__))}/mame/pipes"
        self.actionPipe = Pipe(env_id, "action", 'w', pipes_path)
        self.actionPipe.open(self.console)

        self.dataPipe = DataPipe(env_id, self.screenDims, bitmap_format,
                                 memory_addresses, pipes_path)
        self.dataPipe.open(self.console)

        # Connect inter process communication
        self.setup_frame_access_loop()

        self.first = True
示例#4
0
    def test_lua_string(self):
        data_pipe, write_pipe = [None] * 2
        try:
            addresses = {
                "test1": Address("0x00000000", "u8"),
                "test2": Address("0x00000001", "u16")
            }
            screen_dims = {"width": 1, "height": 1}
            data_pipe = DataPipe("env1", screen_dims, addresses,
                                 "../mame/pipes")
            write_pipe = setup_data_pipe(data_pipe)
            write_pipe.write("1+2+abc\n")
            write_pipe.flush()

            assert_that(
                data_pipe.get_lua_string(),
                equal_to(
                    'dataPipe:write(mem:read_u8(0x00000000).."+"..mem:read_u16(0x00000001).."+"..s:bitmap_binary().."\\n"); dataPipe:flush(); '
                ))
        finally:
            close_pipes(data_pipe, write_pipe)
示例#5
0
    def test_read_data(self):
        data_pipe, write_pipe = [None] * 2
        try:
            addresses = {
                "test1": Address("0x00000000", "u8"),
                "test2": Address("0x00000001", "u16")
            }
            screen_dims = {"width": 1, "height": 1}
            data_pipe = DataPipe("env1", screen_dims, addresses,
                                 "../mame/pipes")
            write_pipe = setup_data_pipe(data_pipe)
            write_pipe.write("1+2+abc\n")
            write_pipe.flush()

            data = data_pipe.read_data()
            assert_that(len(data), is_(equal_to(3)))
            assert_that(data["frame"][0][0][0], is_(equal_to(97)))
            assert_that(data["frame"][0][0][1], is_(equal_to(98)))
            assert_that(data["frame"][0][0][2], is_(equal_to(99)))
            assert_that(data["test1"], is_(equal_to(1)))
            assert_that(data["test2"], is_(equal_to(2)))
        finally:
            close_pipes(data_pipe, write_pipe)
示例#6
0
class Emulator(object):

    # env_id - the unique id of the emulator, used for fifo pipes
    # game_id - the game id being used
    # memory_addresses - The internal memory addresses of the game which this class will return the value of at every time step
    # frame_ratio - the ratio of frames that will be returned, 3 means 1 out of every 3 frames will be returned. Note that his also effects how often memory addresses are read and actions are sent
    # See console for render, throttle & debug
    def __init__(self,
                 env_id,
                 roms_path,
                 game_id,
                 memory_addresses,
                 frame_ratio=3,
                 render=True,
                 throttle=False,
                 debug=False):
        self.memoryAddresses = memory_addresses
        self.frameRatio = frame_ratio

        # setup lua engine
        self.console = Console(roms_path,
                               game_id,
                               render=render,
                               throttle=throttle,
                               debug=debug)
        atexit.register(self.close)
        self.wait_for_resource_registration()
        self.create_lua_variables()
        bitmap_format = self.get_bitmap_format()
        screen_width = self.setup_screen_width()
        screen_height = self.setup_screen_height()
        self.screenDims = {"width": screen_width, "height": screen_height}

        # open pipes
        pipes_path = f"{os.path.dirname(os.path.abspath(__file__))}/mame/pipes"
        self.actionPipe = Pipe(env_id, "action", 'w', pipes_path)
        self.actionPipe.open(self.console)

        self.dataPipe = DataPipe(env_id, self.screenDims, bitmap_format,
                                 memory_addresses, pipes_path)
        self.dataPipe.open(self.console)

        # Connect inter process communication
        self.setup_frame_access_loop()

    def get_bitmap_format(self):
        bitmap_format = self.console.writeln('print(s:bitmap_format())',
                                             expect_output=True)
        if len(bitmap_format) != 1:
            raise IOError(
                'Expected one result from "print(s:bitmap_format())", but received: ',
                bitmap_format)
        try:
            return {
                "RGB32 - 32bpp 8-8-8 RGB": BitmapFormat.RGB32,
                "ARGB32 - 32bpp 8-8-8-8 ARGB": BitmapFormat.ARGB32
            }[bitmap_format[0]]
        except KeyError:
            self.console.close()
            raise EnvironmentError(
                "MAMEToolkit only supports RGB32 and ARGB32 frame bit format games"
            )

    def create_lua_variables(self):
        self.console.writeln('iop = manager:machine():ioport()')
        self.console.writeln('s = manager:machine().screens[":screen"]')
        self.console.writeln(
            'mem = manager:machine().devices[":maincpu"].spaces["program"]')
        self.console.writeln('releaseQueue = {}')

    def wait_for_resource_registration(self, max_attempts=10):
        screen_registered = False
        program_registered = False
        attempt = 0
        while not screen_registered or not program_registered:
            if not screen_registered:
                result = self.console.writeln(
                    'print(manager:machine().screens[":screen"])',
                    expect_output=True,
                    timeout=3,
                    raiseError=False)
                screen_registered = result is not None and result is not "nil"
            if not program_registered:
                result = self.console.writeln(
                    'print(manager:machine().devices[":maincpu"].spaces["program"])',
                    expect_output=True,
                    timeout=3,
                    raiseError=False)
                program_registered = result is not None and result is not "nil"
            if attempt == max_attempts:
                raise EnvironmentError("Failed to register MAME resources!")
            attempt += 1

    # Gets the game screen width in pixels
    def setup_screen_width(self):
        output = self.console.writeln('print(s:width())',
                                      expect_output=True,
                                      timeout=1)
        if len(output) != 1:
            raise IOError(
                'Expected one result from "print(s:width())", but received: ',
                output)
        return int(output[0])

    # Gets the game screen height in pixels
    def setup_screen_height(self):
        output = self.console.writeln('print(s:height())',
                                      expect_output=True,
                                      timeout=1)
        if len(output) != 1:
            raise IOError(
                'Expected one result from "print(s:height())"", but received: ',
                output)
        return int(output[0])

    # Pauses the emulator
    def pause_game(self):
        self.console.writeln('emu.pause()')

    # Unpauses the emulator
    def unpause_game(self):
        self.console.writeln('emu.unpause()')

    # Sets up the callback function written in Lua that the Lua engine will execute each time a frame done
    def setup_frame_access_loop(self):
        pipe_data_func = 'function pipeData() ' \
                            'if (math.fmod(tonumber(s:frame_number()),' + str(self.frameRatio) +') == 0) then ' \
                                'for i=1,#releaseQueue do ' \
                                    'releaseQueue[i](); ' \
                                    'releaseQueue[i]=nil; ' \
                                'end; ' \
                                '' + self.dataPipe.get_lua_string() + '' \
                                'actions = ' + self.actionPipe.get_lua_string() + '' \
                                'if (string.len(actions) > 1) then ' \
                                    'for action in string.gmatch(actions, "[^+]+") do ' \
                                        'actionFunc = loadstring(action..":set_value(1)"); ' \
                                        'actionFunc(); ' \
                                        'releaseFunc = loadstring(action..":set_value(0)"); ' \
                                        'table.insert(releaseQueue, releaseFunc); ' \
                                    'end; ' \
                                'end; ' \
                            'end; ' \
                        'end'
        self.console.writeln(pipe_data_func)
        self.console.writeln('emu.register_frame_done(pipeData, "data")')

    # Steps the emulator along one time step
    def step(self, actions):
        # Will need to shuffle this for self-play?, right
        data = self.dataPipe.read_data(
            timeout=10)  # gathers the frame data and memory address values
        action_string = actions_to_string(actions)
        self.actionPipe.writeln(
            action_string
        )  # sends the actions for the game to perform before the next step
        return data

    # Testing
    # Safely stops all of the processes related to running the emulator
    def close(self):
        self.console.close()
        self.actionPipe.close()
        self.dataPipe.close()