Пример #1
0
    def __post_frame(self, gamestate, event_bytes):
        gamestate.stage = self._current_stage
        gamestate.frame = np.ndarray((1,), ">i", event_bytes, 0x1)[0]
        controller_port = np.ndarray((1,), ">B", event_bytes, 0x5)[0] + 1

        if controller_port not in gamestate.players:
            gamestate.players[controller_port] = PlayerState()
        playerstate = gamestate.players[controller_port]

        # Is this Nana?
        if np.ndarray((1,), ">B", event_bytes, 0x6)[0] == 1:
            playerstate.nana = PlayerState()
            playerstate = playerstate.nana

        playerstate.position.x = np.ndarray((1,), ">f", event_bytes, 0xa)[0]
        playerstate.position.y = np.ndarray((1,), ">f", event_bytes, 0xe)[0]

        playerstate.x = playerstate.position.x
        playerstate.y = playerstate.position.y

        playerstate.character = enums.Character(np.ndarray((1,), ">B", event_bytes, 0x7)[0])
        try:
            playerstate.action = enums.Action(np.ndarray((1,), ">H", event_bytes, 0x8)[0])
        except ValueError:
            playerstate.action = enums.Action.UNKNOWN_ANIMATION

        # Melee stores this in a float for no good reason. So we have to convert
        playerstate.facing = np.ndarray((1,), ">f", event_bytes, 0x12)[0] > 0

        playerstate.percent = int(np.ndarray((1,), ">f", event_bytes, 0x16)[0])
        playerstate.shield_strength = np.ndarray((1,), ">f", event_bytes, 0x1A)[0]
        playerstate.stock = np.ndarray((1,), ">B", event_bytes, 0x21)[0]
        playerstate.action_frame = int(np.ndarray((1,), ">f", event_bytes, 0x22)[0])

        try:
            playerstate.hitstun_frames_left = int(np.ndarray((1,), ">f", event_bytes, 0x2B)[0])
        except TypeError:
            playerstate.hitstun_frames_left = 0
        except ValueError:
            playerstate.hitstun_frames_left = 0
        try:
            playerstate.on_ground = not bool(np.ndarray((1,), ">B", event_bytes, 0x2F)[0])
        except TypeError:
            playerstate.on_ground = True
        try:
            playerstate.jumps_left = np.ndarray((1,), ">B", event_bytes, 0x32)[0]
        except TypeError:
            playerstate.jumps_left = 1

        try:
            playerstate.invulnerable = int(np.ndarray((1,), ">B", event_bytes, 0x34)[0]) != 0
        except TypeError:
            playerstate.invulnerable = False

        try:
            playerstate.speed_air_x_self = np.ndarray((1,), ">f", event_bytes, 0x35)[0]
        except TypeError:
            playerstate.speed_air_x_self = 0

        try:
            playerstate.speed_y_self = np.ndarray((1,), ">f", event_bytes, 0x39)[0]
        except TypeError:
            playerstate.speed_y_self = 0

        try:
            playerstate.speed_x_attack = np.ndarray((1,), ">f", event_bytes, 0x3D)[0]
        except TypeError:
            playerstate.speed_x_attack = 0

        try:
            playerstate.speed_y_attack = np.ndarray((1,), ">f", event_bytes, 0x41)[0]
        except TypeError:
            playerstate.speed_y_attack = 0

        try:
            playerstate.speed_ground_x_self = np.ndarray((1,), ">f", event_bytes, 0x45)[0]
        except TypeError:
            playerstate.speed_ground_x_self = 0

        try:
            playerstate.hitlag_left = int(np.ndarray((1,), ">f", event_bytes, 0x49)[0])
        except TypeError:
            playerstate.hitlag_left = 0

        # Keep track of a player's invulnerability due to respawn or ledge grab
        if controller_port in self._prev_gamestate.players:
            playerstate.invulnerability_left = max(0, self._invuln_start[controller_port][1] - (gamestate.frame - self._invuln_start[controller_port][0]))
        if playerstate.action == Action.ON_HALO_WAIT:
            playerstate.invulnerability_left = 120
            self._invuln_start[controller_port] = (gamestate.frame, 120)
        # Don't give invulnerability to the first descent
        if playerstate.action == Action.ON_HALO_DESCENT and gamestate.frame > 150:
            playerstate.invulnerability_left = 120
            self._invuln_start[controller_port] = (gamestate.frame, 120)
        if playerstate.action == Action.EDGE_CATCHING and playerstate.action_frame == 1:
            playerstate.invulnerability_left = 36
            self._invuln_start[controller_port] = (gamestate.frame, 36)
        # First frame of the game
        if gamestate.frame == -123:
            playerstate.invulnerability_left = 0
            self._invuln_start[controller_port] = (gamestate.frame, 0)

        # The pre-warning occurs when we first start a dash dance.
        if controller_port in self._prev_gamestate.players:
            if playerstate.action == Action.DASHING and \
                    self._prev_gamestate.players[controller_port].action not in [Action.DASHING, Action.TURNING]:
                playerstate.moonwalkwarning = True

        # Take off the warning if the player does an action other than dashing
        if playerstate.action != Action.DASHING:
            playerstate.moonwalkwarning = False

        # "off_stage" helper
        try:
            if (abs(playerstate.position.x) > stages.EDGE_GROUND_POSITION[gamestate.stage] or \
                    playerstate.y < -6) and not playerstate.on_ground:
                playerstate.off_stage = True
            else:
                playerstate.off_stage = False
        except KeyError:
            playerstate.off_stage = False

        # ECB top edge, x
        ecb_top_x = 0
        ecb_top_y = 0
        try:
            ecb_top_x = np.ndarray((1,), ">f", event_bytes, 0x4D)[0]
        except TypeError:
            ecb_top_x = 0
        # ECB Top edge, y
        try:
            ecb_top_y = np.ndarray((1,), ">f", event_bytes, 0x51)[0]
        except TypeError:
            ecb_top_y = 0
        playerstate.ecb.top = collections.namedtuple("Position", ['x', 'y'])
        playerstate.ecb.top.x = ecb_top_x
        playerstate.ecb.top.y = ecb_top_y
        playerstate.ecb_top = (ecb_top_x, ecb_top_y)

        # ECB bottom edge, x coord
        ecb_bot_x = 0
        ecb_bot_y = 0
        try:
            ecb_bot_x = np.ndarray((1,), ">f", event_bytes, 0x55)[0]
        except TypeError:
            ecb_bot_x = 0
        # ECB Bottom edge, y coord
        try:
            ecb_bot_y = np.ndarray((1,), ">f", event_bytes, 0x59)[0]
        except TypeError:
            ecb_bot_y = 0
        playerstate.ecb.bottom = collections.namedtuple("Position", ['x', 'y'])
        playerstate.ecb.bottom.x = ecb_bot_x
        playerstate.ecb.bottom.y = ecb_bot_y
        playerstate.ecb_bottom = (ecb_bot_x, ecb_bot_y)

        # ECB left edge, x coord
        ecb_left_x = 0
        ecb_left_y = 0
        try:
            ecb_left_x = np.ndarray((1,), ">f", event_bytes, 0x5D)[0]
        except TypeError:
            ecb_left_x = 0
        # ECB left edge, y coord
        try:
            ecb_left_y = np.ndarray((1,), ">f", event_bytes, 0x61)[0]
        except TypeError:
            ecb_left_y = 0
        playerstate.ecb.left = collections.namedtuple("Position", ['x', 'y'])
        playerstate.ecb.left.x = ecb_left_x
        playerstate.ecb.left.y = ecb_left_y
        playerstate.ecb_left = (ecb_left_x, ecb_left_y)

        # ECB right edge, x coord
        ecb_right_x = 0
        ecb_right_y = 0
        try:
            ecb_right_x = np.ndarray((1,), ">f", event_bytes, 0x65)[0]
        except TypeError:
            ecb_right_x = 0
        # ECB right edge, y coord
        try:
            ecb_right_y = np.ndarray((1,), ">f", event_bytes, 0x69)[0]
        except TypeError:
            ecb_right_y = 0
        playerstate.ecb.right = collections.namedtuple("Position", ['x', 'y'])
        playerstate.ecb.right.x = ecb_right_x
        playerstate.ecb.right.y = ecb_right_y
        playerstate.ecb_right = (ecb_right_x, ecb_right_y)
        if self._use_manual_bookends:
            self._frame = gamestate.frame
Пример #2
0
    def __init__(self,
                 path=None,
                 is_dolphin=True,
                 dolphin_home_path=None,
                 tmp_home_directory=True,
                 slippi_address="127.0.0.1",
                 slippi_port=51441,
                 online_delay=2,
                 blocking_input=False,
                 polling_mode=False,
                 allow_old_version=False,
                 logger=None):
        """Create a Console object

        Args:
            path (str): Path to the directory where your dolphin executable is located.
                If None, will assume the dolphin is remote and won't try to configure it.
            dolphin_home_path (str): Path to dolphin user directory. Optional.
            is_dolphin (bool): Is this console a dophin instance, or SLP file?
            tmp_home_directory (bool): Use a temporary directory for the dolphin User path
                This is useful so instances don't interfere with each other.
            slippi_address (str): IP address of the Dolphin / Wii to connect to.
            slippi_port (int): UDP port that slippi will listen on
            online_delay (int): How many frames of delay to apply in online matches
            blocking_input (bool): Should dolphin block waiting for bot input
                This is only really useful if you're doing ML training.
            polling_mode (bool): Polls input to console rather than blocking for it
                When set, step() will always return immediately, but may be None if no
                gamestate is available yet.
            allow_old_version (bool): Allow SLP versions older than 3.0.0 (rollback era)
                Only enable if you know what you're doing. You probably don't want this.
                Gamestates will be missing key information, come in really late, or possibly not work at all
            logger (logger.Logger): Logger instance to use. None for no logger.
        """
        self.logger = logger
        self.is_dolphin = is_dolphin
        self.path = path
        self.dolphin_home_path = dolphin_home_path
        if tmp_home_directory and self.is_dolphin:
            temp_dir = tempfile.mkdtemp(prefix='libmelee_')
            temp_dir += "/User/"
            _copytree_safe(self._get_dolphin_home_path(), temp_dir)
            self.dolphin_home_path = temp_dir

        self.processingtime = 0
        self._frametimestamp = time.time()
        self.slippi_address = slippi_address
        """(str): IP address of the Dolphin / Wii to connect to."""
        self.slippi_port = slippi_port
        """(int): UDP port of slippi server. Default 51441"""
        self.eventsize = [0] * 0x100
        self.connected = False
        self.nick = ""
        """(str): The nickname the console has given itself."""
        self.version = ""
        """(str): The Slippi version of the console"""
        self.cursor = 0
        self.controllers = []
        self._current_stage = enums.Stage.NO_STAGE
        self._frame = 0
        self._polling_mode = polling_mode
        self.slp_version = "unknown"
        """(str): The SLP version this stream/file currently is."""
        self._allow_old_version = allow_old_version
        self._use_manual_bookends = False
        self._costumes = {0:0, 1:0, 2:0, 3:0}
        self._cpu_level = {0:0, 1:0, 2:0, 3:0}
        self._invuln_start = {1:(0,0), 2:(0,0), 3:(0,0), 4:(0,0)}

        # Keep a running copy of the last gamestate produced
        self._prev_gamestate = GameState()
        # Half-completed gamestate not yet ready to add to the list
        self._temp_gamestate = None
        self._process = None
        if self.is_dolphin:
            self._slippstream = SlippstreamClient(self.slippi_address, self.slippi_port)
            if self.path:
                # Setup some dolphin config options
                dolphin_ini_path = self._get_dolphin_config_path() + "Dolphin.ini"
                if not os.path.isfile(dolphin_ini_path):
                    raise InvalidDolphinPath(self._get_dolphin_config_path())
                config = configparser.ConfigParser()
                config.read(dolphin_ini_path)
                config.set("Core", 'slippienablespectator', "True")
                config.set("Core", 'slippispectatorlocalport', str(self.slippi_port))
                # Set online delay
                config.set("Core", 'slippionlinedelay', str(online_delay))
                # Turn on background input so we don't need to have window focus on dolphin
                config.set("Input", 'backgroundinput', "True")
                config.set("Core", 'BlockingPipes', str(blocking_input))
                with open(dolphin_ini_path, 'w') as dolphinfile:
                    config.write(dolphinfile)
        else:
            self._slippstream = SLPFileStreamer(self.path)

        # Prepare some structures for fixing melee data
        path = os.path.dirname(os.path.realpath(__file__))
        with open(path + "/actiondata.csv") as csvfile:
            #A list of dicts containing the frame data
            actiondata = list(csv.DictReader(csvfile))
            #Dict of sets
            self.zero_indices = defaultdict(set)
            for line in actiondata:
                if line["zeroindex"] == "True":
                    self.zero_indices[int(line["character"])].add(int(line["action"]))

        # Read the character data csv
        self.characterdata = dict()
        with open(path + "/characterdata.csv") as csvfile:
            reader = csv.DictReader(csvfile)
            for line in reader:
                del line["Character"]
                #Convert all fields to numbers
                for key, value in line.items():
                    line[key] = float(value)
                self.characterdata[enums.Character(line["CharacterIndex"])] = line
Пример #3
0
    def __handle_slippstream_events(self, event_bytes, gamestate):
        """ Handle a series of events, provided sequentially in a byte array """
        gamestate.menu_state = enums.Menu.IN_GAME
        while len(event_bytes) > 0:
            event_size = self.eventsize[event_bytes[0]]
            if len(event_bytes) < event_size:
                print("WARNING: Something went wrong unpacking events. Data is probably missing")
                print("\tDidn't have enough data for event")
                return False
            if EventType(event_bytes[0]) == EventType.PAYLOADS:
                cursor = 0x2
                payload_size = event_bytes[1]
                num_commands = (payload_size - 1) // 3
                for i in range(0, num_commands):
                    command, command_len = unpack(">bH", event_bytes[cursor:cursor+3])
                    self.eventsize[command] = command_len+1
                    cursor += 3
                event_bytes = event_bytes[payload_size + 1:]

            elif EventType(event_bytes[0]) == EventType.FRAME_START:
                event_bytes = event_bytes[event_size:]

            elif EventType(event_bytes[0]) == EventType.GAME_START:
                event_bytes = event_bytes[event_size:]

            elif EventType(event_bytes[0]) == EventType.GAME_END:
                event_bytes = event_bytes[event_size:]

            elif EventType(event_bytes[0]) == EventType.PRE_FRAME:
                event_bytes = event_bytes[event_size:]

            elif EventType(event_bytes[0]) == EventType.POST_FRAME:
                gamestate.frame = unpack(">i", event_bytes[0x1:0x1+4])[0]
                controller_port = unpack(">B", event_bytes[0x5:0x5+1])[0] + 1

                gamestate.player[controller_port].x = unpack(">f", event_bytes[0xa:0xa+4])[0]
                gamestate.player[controller_port].y = unpack(">f", event_bytes[0xe:0xe+4])[0]

                gamestate.player[controller_port].character = enums.Character(unpack(">B", event_bytes[0x7:0x7+1])[0])
                try:
                    gamestate.player[controller_port].action = enums.Action(unpack(">H", event_bytes[0x8:0x8+2])[0])
                except ValueError:
                    gamestate.player[controller_port].action = enums.Action.UNKNOWN_ANIMATION

                # Melee stores this in a float for no good reason. So we have to convert
                facing_float = unpack(">f", event_bytes[0x12:0x12+4])[0]
                gamestate.player[controller_port].facing = facing_float > 0

                gamestate.player[controller_port].percent = int(unpack(">f", event_bytes[0x16:0x16+4])[0])
                gamestate.player[controller_port].stock = unpack(">B", event_bytes[0x21:0x21+1])[0]
                gamestate.player[controller_port].action_frame = int(unpack(">f", event_bytes[0x22:0x22+4])[0])

                # Extract the bit at mask 0x20
                bitflags2 = unpack(">B", event_bytes[0x27:0x27+1])[0]
                gamestate.player[controller_port].hitlag = bool(bitflags2 & 0x20)

                try:
                    gamestate.player[controller_port].hitstun_frames_left = int(unpack(">f", event_bytes[0x2b:0x2b+4])[0])
                except ValueError:
                    gamestate.player[controller_port].hitstun_frames_left = 0
                gamestate.player[controller_port].on_ground = not bool(unpack(">B", event_bytes[0x2f:0x2f+1])[0])
                gamestate.player[controller_port].jumps_left = unpack(">B", event_bytes[0x32:0x32+1])[0]
                gamestate.player[controller_port].invulnerable = int(unpack(">B", event_bytes[0x34:0x34+1])[0]) != 0

                try:
                    gamestate.player[controller_port].speed_air_x_self = unpack(">f", event_bytes[0x35:0x35+4])[0]
                except error:
                    gamestate.player[controller_port].speed_air_x_self = 0

                try:
                    gamestate.player[controller_port].speed_y_self = unpack(">f", event_bytes[0x39:0x39+4])[0]
                except error:
                    gamestate.player[controller_port].speed_y_self = 0

                try:
                    gamestate.player[controller_port].speed_x_attack = unpack(">f", event_bytes[0x3d:0x3d+4])[0]
                except error:
                    gamestate.player[controller_port].speed_x_attack = 0

                try:
                    gamestate.player[controller_port].speed_y_attack = unpack(">f", event_bytes[0x41:0x41+4])[0]
                except error:
                    gamestate.player[controller_port].speed_y_attack = 0

                try:
                    gamestate.player[controller_port].speed_ground_x_self = unpack(">f", event_bytes[0x45:0x45+4])[0]
                except error:
                    gamestate.player[controller_port].speed_ground_x_self = 0

                # Keep track of a player's invulnerability due to respawn or ledge grab
                gamestate.player[controller_port].invulnerability_left = max(0, self._prev_gamestate.player[controller_port].invulnerability_left - 1)
                if gamestate.player[controller_port].action == Action.ON_HALO_WAIT:
                    gamestate.player[controller_port].invulnerability_left = 120
                # Don't give invulnerability to the first descent
                if gamestate.player[controller_port].action == Action.ON_HALO_DESCENT and gamestate.frame > 150:
                    gamestate.player[controller_port].invulnerability_left = 120
                if gamestate.player[controller_port].action == Action.EDGE_CATCHING and gamestate.player[controller_port].action_frame == 1:
                    gamestate.player[controller_port].invulnerability_left = 36

                # The pre-warning occurs when we first start a dash dance.
                if gamestate.player[controller_port].action == Action.DASHING and \
                        self._prev_gamestate.player[controller_port].action not in [Action.DASHING, Action.TURNING]:
                    gamestate.player[controller_port].moonwalkwarning = True

                # Take off the warning if the player does an action other than dashing
                if gamestate.player[controller_port].action != Action.DASHING:
                    gamestate.player[controller_port].moonwalkwarning = False

                # "off_stage" helper
                if (abs(gamestate.player[controller_port].x) > stages.EDGE_GROUND_POSITION[gamestate.stage] or \
                        gamestate.player[controller_port].y < -6) and not gamestate.player[controller_port].on_ground:
                    gamestate.player[controller_port].off_stage = True
                else:
                    gamestate.player[controller_port].off_stage = False

                event_bytes = event_bytes[event_size:]

            elif EventType(event_bytes[0]) == EventType.GECKO_CODES:
                event_bytes = event_bytes[event_size:]

            elif EventType(event_bytes[0]) == EventType.FRAME_BOOKEND:
                self._prev_gamestate = gamestate

                # Calculate helper distance variable
                #   This is a bit kludgey.... :/
                i = 0
                player_one_x, player_one_y, player_two_x, player_two_y = 0, 0, 0, 0
                for _, player_state in gamestate.player.items():
                    if i == 0:
                        player_one_x, player_one_y = player_state.x, player_state.y
                    if i == 1:
                        player_two_x, player_two_y = player_state.x, player_state.y
                    i += 1
                xdist = player_one_x - player_two_x
                ydist = player_one_y - player_two_y
                gamestate.distance = math.sqrt((xdist**2) + (ydist**2))
                event_bytes = event_bytes[event_size:]
                return True

            elif EventType(event_bytes[0]) == EventType.ITEM_UPDATE:
                projectile = Projectile()
                projectile.x = unpack(">f", event_bytes[0x14:0x14+4])[0]
                projectile.y = unpack(">f", event_bytes[0x18:0x18+4])[0]
                projectile.x_speed = unpack(">f", event_bytes[0x0c:0x0c+4])[0]
                projectile.y_speed = unpack(">f", event_bytes[0x10:0x10+4])[0]
                try:
                    projectile.owner = unpack(">B", event_bytes[0x2A:0x2A+1])[0] + 1
                    if projectile.owner > 4:
                        projectile.owner = -1
                except error:
                    projectile.owner = -1
                try:
                    projectile.subtype = enums.ProjectileSubtype(unpack(">H", event_bytes[0x05:0x05+2])[0])
                except ValueError:
                    projectile.subtype = enums.ProjectileSubtype.UNKNOWN_PROJECTILE
                # Add the projectile to the gamestate list
                gamestate.projectiles.append(projectile)

                event_bytes = event_bytes[event_size:]

            else:
                print("WARNING: Something went wrong unpacking events. " + \
                    "Data is probably missing")
                print("\tGot invalid event type: ", event_bytes[0])
                return False

        return False
Пример #4
0
    def __init__(self, is_dolphin, ai_port, opponent_port, opponent_type,
                 dolphin_executable_path=None, slippi_address="", logger=None):
        """Create a Console object

        Args:
            is_dolphin (boolean): Is this console a dolphin? (Or a Wii)
            ai_port (int): 1-4 for the controller port your bot will take
            opponent_port (int): 1-4 for the controller port your opponent will take
            opponent_type (:obj:`enums.ControllerType`): Enum of your opponent's controller type
            dolphin_executable_path (str): Path to the directory where your dolphin executable is
                located. (if applicable) None tells console to use the installed copy of the emulator
            slippi_address (str): IP address of the Dolphin / Wii to connect to.
                Empty string will try to autodiscover a nearby SlippiComm server
        """
        self.logger = logger
        self.ai_port = ai_port
        self.opponent_port = opponent_port
        self.is_dolphin = is_dolphin
        self.dolphin_executable_path = dolphin_executable_path
        self.processingtime = 0
        self._frametimestamp = time.time()
        self.slippi_address = slippi_address
        self.slippi_port = 51441
        self.eventsize = [0] * 0x100
        self.render = True

        # Keep a running copy of the last gamestate produced
        self._prev_gamestate = GameState(ai_port, opponent_port)
        self._process = None
        if self.is_dolphin:
            pipes_path = self._get_dolphin_home_path() + "Pipes/"
            path = os.path.dirname(os.path.realpath(__file__))

            if platform.system() != "Windows":
                #Create the Pipes directory if it doesn't already exist
                if not os.path.exists(pipes_path):
                    os.makedirs(pipes_path)
                    print("WARNING: Had to create a Pipes directory in Dolphin just now. " \
                          "You may need to restart Dolphin and this program in order for this to work. " \
                          "(You should only see this warning once)")

                pipes_path += "slippibot" + str(ai_port)
                if not os.path.exists(pipes_path):
                    os.mkfifo(pipes_path)

            #setup the controllers specified
            self.setup_dolphin_controller(ai_port)
            self.setup_dolphin_controller(opponent_port, opponent_type)
            self._slippstream = SlippstreamClient(self.slippi_address, self.slippi_port)

        # Prepare some structures for fixing melee data
        path = os.path.dirname(os.path.realpath(__file__))
        with open(path + "/actiondata.csv") as csvfile:
            #A list of dicts containing the frame data
            actiondata = list(csv.DictReader(csvfile))
            #Dict of sets
            self.zero_indices = defaultdict(set)
            for line in actiondata:
                if line["zeroindex"] == "True":
                    self.zero_indices[int(line["character"])].add(int(line["action"]))

        # Read the character data csv
        self.characterdata = dict()
        with open(path + "/characterdata.csv") as csvfile:
            reader = csv.DictReader(csvfile)
            for line in reader:
                del line["Character"]
                #Convert all fields to numbers
                for key, value in line.items():
                    line[key] = float(value)
                self.characterdata[enums.Character(line["CharacterIndex"])] = line
Пример #5
0
    def __handle_slippstream_events(self, event_bytes, gamestate):
        """ Handle a series of events, provided sequentially in a byte array """
        lastmessage = EventType.GAME_START
        while len(event_bytes) > 0:
            lastmessage = EventType(event_bytes[0])
            event_size = self.eventsize[event_bytes[0]]
            if len(event_bytes) < event_size:
                print(
                    "WARNING: Something went wrong unpacking events. Data is probably missing"
                )
                print("\tDidn't have enough data for event")
                return False
            if (EventType(event_bytes[0]) == EventType.PAYLOADS):
                cursor = 0x2
                payload_size = event_bytes[1]
                num_commands = (payload_size - 1) // 3
                for i in range(0, num_commands):
                    command, command_len = unpack(
                        ">bH", event_bytes[cursor:cursor + 3])
                    self.eventsize[command] = command_len + 1
                    cursor += 3
                event_bytes = event_bytes[payload_size + 1:]
                continue

            elif (EventType(event_bytes[0]) == EventType.FRAME_START):
                self.frame_num = unpack(">i", event_bytes[1:5])[0]
                event_bytes = event_bytes[event_size:]
                continue

            elif (EventType(event_bytes[0]) == EventType.GAME_START):
                event_bytes = event_bytes[event_size:]
                continue

            elif (EventType(event_bytes[0]) == EventType.GAME_END):
                event_bytes = event_bytes[event_size:]
                continue

            elif (EventType(event_bytes[0]) == EventType.PRE_FRAME):
                event_bytes = event_bytes[event_size:]
                continue

            elif (EventType(event_bytes[0]) == EventType.POST_FRAME):
                gamestate.frame = unpack(">i", event_bytes[0x1:0x1 + 4])[0]
                controller_port = unpack(">B", event_bytes[0x5:0x5 + 1])[0] + 1

                gamestate.player[controller_port].x = unpack(
                    ">f", event_bytes[0xa:0xa + 4])[0]
                gamestate.player[controller_port].y = unpack(
                    ">f", event_bytes[0xe:0xe + 4])[0]

                gamestate.player[controller_port].character = enums.Character(
                    unpack(">B", event_bytes[0x7:0x7 + 1])[0])
                try:
                    gamestate.player[controller_port].action = enums.Action(
                        unpack(">H", event_bytes[0x8:0x8 + 2])[0])
                except ValueError:
                    gamestate.player[
                        controller_port].action = enums.Action.UNKNOWN_ANIMATION

                # Melee stores this in a float for no good reason. So we have to convert
                facing_float = unpack(">f", event_bytes[0x12:0x12 + 4])[0]
                gamestate.player[controller_port].facing = facing_float > 0

                gamestate.player[controller_port].percent = int(
                    unpack(">f", event_bytes[0x16:0x16 + 4])[0])
                gamestate.player[controller_port].stock = unpack(
                    ">B", event_bytes[0x21:0x21 + 1])[0]
                gamestate.player[controller_port].action_frame = int(
                    unpack(">f", event_bytes[0x22:0x22 + 4])[0])

                # Extract the bit at mask 0x20
                bitflags2 = unpack(">B", event_bytes[0x27:0x27 + 1])[0]
                gamestate.player[controller_port].hitlag = bool(bitflags2
                                                                & 0x20)

                gamestate.player[controller_port].hitstun_frames_left = int(
                    unpack(">f", event_bytes[0x2b:0x2b + 4])[0])
                gamestate.player[controller_port].on_ground = not bool(
                    unpack(">B", event_bytes[0x2f:0x2f + 1])[0])
                gamestate.player[controller_port].jumps_left = unpack(
                    ">B", event_bytes[0x32:0x32 + 1])[0]

                event_bytes = event_bytes[event_size:]
                continue

            elif (EventType(event_bytes[0]) == EventType.GECKO_CODES):
                event_bytes = event_bytes[event_size:]
                continue

            elif (EventType(event_bytes[0]) == EventType.FRAME_BOOKEND):
                event_bytes = event_bytes[event_size:]
                return True

            elif (EventType(event_bytes[0]) == EventType.ITEM_UPDATE):
                # TODO projectiles
                projectile = Projectile()
                projectile.x = unpack(">f", event_bytes[0x14:0x14 + 4])[0]
                projectile.y = unpack(">f", event_bytes[0x18:0x18 + 4])[0]
                projectile.x_speed = unpack(">f",
                                            event_bytes[0x0c:0x0c + 4])[0]
                projectile.y_speed = unpack(">f",
                                            event_bytes[0x10:0x10 + 4])[0]
                try:
                    projectile.subtype = enums.ProjectileSubtype(
                        unpack(">H", event_bytes[0x05:0x05 + 2])[0])
                except ValueError:
                    projectile.subtype = enums.UNKNOWN_PROJECTILE
                # Add the projectile to the gamestate list
                gamestate.projectiles.append(projectile)

                event_bytes = event_bytes[event_size:]
                continue

            else:
                print("WARNING: Something went wrong unpacking events. " + \
                    "Data is probably missing")
                print("\tGot invalid event type: ", event_bytes[0])
                return False

        return False
Пример #6
0
    def __init__(self,
                 path=None,
                 is_dolphin=True,
                 slippi_address="127.0.0.1",
                 logger=None):
        """Create a Console object

        Args:
            path (str): Path to the directory where your dolphin executable is
                located. (if applicable) None tells console to use the installed copy of the emulator
            slippi_address (str): IP address of the Dolphin / Wii to connect to.
                Empty string will try to autodiscover a nearby SlippiComm server
            logger (logger.Logger): Logger instance to use. None for no logger.
        """
        self.logger = logger
        self.is_dolphin = is_dolphin
        self.path = path
        self.processingtime = 0
        self._frametimestamp = time.time()
        self.slippi_address = slippi_address
        """(str): IP address of the Dolphin / Wii to connect to."""
        self.slippi_port = 51441
        """(int): TCP port of slippi server. Default 51441"""
        self.eventsize = [0] * 0x100
        self.render = True
        self.connected = False
        self.nick = ""
        """(str): The nickname the console has given itself."""
        self.version = ""
        """(str): The Slippi version of the console"""
        self.cursor = 0
        self.controllers = []
        self._current_stage = enums.Stage.NO_STAGE
        self._frame = 0
        self.slp_version = "unknown"
        """(str): The SLP version this stream/file currently is."""

        # Keep a running copy of the last gamestate produced
        self._prev_gamestate = GameState()
        self._process = None
        if self.is_dolphin:
            self._slippstream = SlippstreamClient(self.slippi_address,
                                                  self.slippi_port)
        else:
            self._slippstream = SLPFileStreamer(self.path)

        # Prepare some structures for fixing melee data
        path = os.path.dirname(os.path.realpath(__file__))
        with open(path + "/actiondata.csv") as csvfile:
            #A list of dicts containing the frame data
            actiondata = list(csv.DictReader(csvfile))
            #Dict of sets
            self.zero_indices = defaultdict(set)
            for line in actiondata:
                if line["zeroindex"] == "True":
                    self.zero_indices[int(line["character"])].add(
                        int(line["action"]))

        # Read the character data csv
        self.characterdata = dict()
        with open(path + "/characterdata.csv") as csvfile:
            reader = csv.DictReader(csvfile)
            for line in reader:
                del line["Character"]
                #Convert all fields to numbers
                for key, value in line.items():
                    line[key] = float(value)
                self.characterdata[enums.Character(
                    line["CharacterIndex"])] = line
Пример #7
0
    def __init__(self,
                 is_dolphin,
                 ai_port,
                 opponent_port,
                 opponent_type,
                 config_path="",
                 home_path="",
                 logger=None):
        self.logger = logger
        self.ai_port = ai_port
        self.opponent_port = opponent_port
        self.is_dolphin = is_dolphin
        self.config_path = config_path
        self.home_path = home_path

        self.processingtime = 0
        self._frametimestamp = time.time()
        self.slippi_address = ""
        self.slippi_port = 51441
        self.eventsize = [0] * 0x100

        # Keep a running copy of the last gamestate produced
        #   game info is only produced as diffs, not whole snapshots
        #   so if nothing changes, we need to know what the last value was
        self.render = True
        self._prev_gamestate = GameState(ai_port, opponent_port)
        self.process = None
        if self.is_dolphin:
            config_path = self.get_dolphin_home_path()
            pipes_path = config_path + "Pipes/"
            path = os.path.dirname(os.path.realpath(__file__))

            #Create the Pipes directory if it doesn't already exist
            if not os.path.exists(pipes_path):
                os.makedirs(pipes_path)
                print("WARNING: Had to create a Pipes directory in Dolphin just now. " \
                    "You may need to restart Dolphin and this program in order for this to work. " \
                    "(You should only see this warning once)")

            pipes_path += "Bot" + str(ai_port)
            if not os.path.exists(pipes_path):
                os.mkfifo(pipes_path)

            #setup the controllers specified
            self.setup_dolphin_controller(ai_port)
            self.setup_dolphin_controller(opponent_port, opponent_type)

        # Prepare some structures for fixing melee data
        path = os.path.dirname(os.path.realpath(__file__))
        with open(path + "/actiondata.csv") as csvfile:
            #A list of dicts containing the frame data
            actiondata = list(csv.DictReader(csvfile))
            #Dict of sets
            self.zero_indices = defaultdict(set)
            for line in actiondata:
                if line["zeroindex"] == "True":
                    self.zero_indices[int(line["character"])].add(
                        int(line["action"]))

        # Read the character data csv
        self.characterdata = dict()
        with open(path + "/characterdata.csv") as csvfile:
            reader = csv.DictReader(csvfile)
            for line in reader:
                del line["Character"]
                #Convert all fields to numbers
                for key, value in line.items():
                    line[key] = float(value)
                self.characterdata[enums.Character(
                    line["CharacterIndex"])] = line
Пример #8
0
    def update(self, mem_update):
        label = self.locations[mem_update[0]][0]
        player_int = int(self.locations[mem_update[0]][1])
        if label == "frame":
            self.frame = unpack('<I', mem_update[1])[0]
            self.newframe = True
            #Now that the frame is ready, let's calculate some derived information
            #   These are not stored inside Melee anywhere, but are nonetheless
            #   important pieces of information that we don't want to make the
            #   user have to re-calculate on their own
            for i in self.player:
                # Move current x,y over to prev
                self.player[i].prev_x = self.player[i].x
                self.player[i].prev_y = self.player[i].y
                # Move future x,y over to current
                self.player[i].x = self.player[i].next_x
                self.player[i].y = self.player[i].next_y

                if (abs(self.player[i].x) > stages.edgegroundposition(self.stage) or \
                        self.player[i].y < -6) and not self.player[i].on_ground:
                    self.player[i].off_stage = True
                else:
                    self.player[i].off_stage = False

                # Keep track of a player's invulnerability due to respawn or ledge grab
                self.player[i].invulnerability_left = max(
                    0, self.player[i].invulnerability_left - 1)
                if self.player[i].action == Action.ON_HALO_WAIT:
                    self.player[i].invulnerability_left = 120
                # Don't give invulnerability to the first descent
                if self.player[
                        i].action == Action.ON_HALO_DESCENT and self.frame > 150:
                    self.player[i].invulnerability_left = 120
                if self.player[
                        i].action == Action.EDGE_CATCHING and self.player[
                            i].action_frame == 1:
                    self.player[i].invulnerability_left = 36

                # Which character are we right now?
                if self.player[i].character in [
                        Character.SHEIK, Character.ZELDA
                ]:
                    if self.player[i].transformed == self.player[i].iszelda:
                        self.player[i].character = Character.SHEIK
                    else:
                        self.player[i].character = Character.ZELDA
                # If the player is transformed, then copy over the sub-character attributes
                if self.player[i].transformed:
                    self.player[i].action = self.player[i + 4].action
                    self.player[i].action_counter = self.player[
                        i + 4].action_counter
                    self.player[i].action_frame = self.player[i +
                                                              4].action_frame
                    self.player[i].invulnerable = self.player[i +
                                                              4].invulnerable
                    self.player[i].hitlag_frames_left = self.player[
                        i + 4].hitlag_frames_left
                    self.player[i].hitstun_frames_left = self.player[
                        i + 4].hitstun_frames_left
                    self.player[i].charging_smash = self.player[
                        i + 4].charging_smash
                    self.player[i].jumps_left = self.player[i + 4].jumps_left
                    self.player[i].on_ground = self.player[i + 4].on_ground
                    self.player[i].speed_air_x_self = self.player[
                        i + 4].speed_air_x_self
                    self.player[i].speed_y_self = self.player[i +
                                                              4].speed_y_self
                    self.player[i].speed_x_attack = self.player[
                        i + 4].speed_x_attack
                    self.player[i].speed_y_attack = self.player[
                        i + 4].speed_y_attack
                    self.player[i].speed_ground_x_self = self.player[
                        i + 4].speed_ground_x_self
                    self.player[i].x = self.player[i + 4].x
                    self.player[i].y = self.player[i + 4].y
                    self.player[i].percent = self.player[i + 4].percent
                    self.player[i].facing = self.player[i + 4].facing

                # The pre-warning occurs when we first start a dash dance.
                if self.player[i].action == Action.DASHING and self.player[
                        i].prev_action not in [Action.DASHING, Action.TURNING]:
                    self.player[i].moonwalkwarning = True

                # Take off the warning if the player does an action other than dashing
                if self.player[i].action != Action.DASHING:
                    self.player[i].moonwalkwarning = False

            #TODO: This needs updating in order to support >2 players
            xdist = self.ai_state.x - self.opponent_state.x
            ydist = self.ai_state.y - self.opponent_state.y
            self.distance = math.sqrt((xdist**2) + (ydist**2))
            self.fixiasa()
            self.fixframeindexing()
            return True
        if label == "stage":
            self.stage = unpack('<I', mem_update[1])[0]
            self.stage = self.stage >> 16
            self.stage &= 0x000000ff
            try:
                self.stage = enums.Stage(self.stage)
            except ValueError:
                self.stage = enums.Stage.NO_STAGE
            return False
        if label == "menu_state":
            self.menu_state = unpack('<I', mem_update[1])[0]
            self.menu_state &= 0x000000ff
            self.menu_state = enums.Menu(self.menu_state)
            return False
        #Player variables
        if label == "percent":
            if player_int > 4:
                try:
                    self.player[player_int].percent = int(
                        unpack('<f', mem_update[1])[0])
                except ValueError:
                    self.player[player_int].percent = 0
                return False
            self.player[player_int].percent = unpack('<I', mem_update[1])[0]
            self.player[
                player_int].percent = self.player[player_int].percent >> 16
            return False
        if label == "stock":
            self.player[player_int].stock = unpack('<I', mem_update[1])[0]
            self.player[player_int].stock = self.player[player_int].stock >> 24
            return False
        if label == "facing":
            self.player[player_int].facing = unpack('<I', mem_update[1])[0]
            self.player[player_int].facing = not bool(
                self.player[player_int].facing >> 31)
            return False
        if label == "x":
            self.player[player_int].next_x = unpack('<f', mem_update[1])[0]
            return False
        if label == "y":
            self.player[player_int].next_y = unpack('<f', mem_update[1])[0]
            return False
        if label == "character":
            temp = unpack('<I', mem_update[1])[0] >> 24
            try:
                self.player[player_int].character = enums.Character(temp)
            except ValueError:
                self.player[
                    player_int].character = enums.Character.UNKNOWN_CHARACTER
            return False
        if label == "cursor_x":
            self.player[player_int].cursor_x = unpack('<f', mem_update[1])[0]
            return False
        if label == "cursor_y":
            self.player[player_int].cursor_y = unpack('<f', mem_update[1])[0]
            return False
        if label == "action":
            temp = unpack('<I', mem_update[1])[0]
            try:
                # Keep track of old action
                self.player[player_int].prev_action = self.player[
                    player_int].action
                self.player[player_int].action = enums.Action(temp)
            except ValueError:
                self.player[player_int].action = enums.Action.UNKNOWN_ANIMATION
            return False
        if label == "action_counter":
            #TODO look if this is backwards
            temp = unpack('I', mem_update[1])[0]
            temp = temp >> 8
            self.player[player_int].action_counter = temp
            return False
        if label == "action_frame":
            temp = unpack('<f', mem_update[1])[0]
            try:
                self.player[player_int].action_frame = int(temp)
            except ValueError:
                pass
            return False
        if label == "invulnerable":
            self.player[player_int].invulnerable = unpack('<I',
                                                          mem_update[1])[0]
            self.player[player_int].invulnerable = self.player[
                player_int].invulnerable >> 31
            return False
        if label == "hitlag_frames_left":
            temp = unpack('<f', mem_update[1])[0]
            try:
                self.player[player_int].hitlag_frames_left = int(temp)
            except ValueError:
                pass
            return False
        if label == "hitstun_frames_left":
            temp = unpack('<f', mem_update[1])[0]
            try:
                self.player[player_int].hitstun_frames_left = int(temp)
            except ValueError:
                pass
            return False
        if label == "charging_smash":
            temp = unpack('<I', mem_update[1])[0]
            if temp == 2:
                self.player[player_int].charging_smash = True
            else:
                self.player[player_int].charging_smash = False
            return False
        if label == "jumps_left":
            temp = unpack('<I', mem_update[1])[0]
            temp = temp >> 24
            #This value is actually the number of jumps USED
            #   so we have to do some quick math to turn this into what we want
            try:
                totaljumps = int(self.characterdata[
                    self.player[player_int].character]["Jumps"])
                self.player[player_int].jumps_left = totaljumps - temp + 1
            # Key error will be expected when we first start
            except KeyError:
                self.player[player_int].jumps_left = 1
            return False
        if label == "on_ground":
            temp = unpack('<I', mem_update[1])[0]
            if temp == 0:
                self.player[player_int].on_ground = True
            else:
                self.player[player_int].on_ground = False
            return False
        if label == "speed_air_x_self":
            self.player[player_int].speed_air_x_self = unpack(
                '<f', mem_update[1])[0]
            return False
        if label == "speed_y_self":
            self.player[player_int].speed_y_self = unpack('<f',
                                                          mem_update[1])[0]
            return False
        if label == "speed_x_attack":
            self.player[player_int].speed_x_attack = unpack(
                '<f', mem_update[1])[0]
            return False
        if label == "speed_y_attack":
            self.player[player_int].speed_y_attack = unpack(
                '<f', mem_update[1])[0]
            return False
        if label == "speed_ground_x_self":
            self.player[player_int].speed_ground_x_self = unpack(
                '<f', mem_update[1])[0]
            return False
        if label == "coin_down":
            temp = unpack('<I', mem_update[1])[0]
            temp = temp & 0x000000ff
            self.player[player_int].coin_down = (temp == 2)
            return False
        if label == "stage_select_cursor_x":
            self.stage_select_cursor_x = unpack('<f', mem_update[1])[0]
            return False
        if label == "stage_select_cursor_y":
            self.stage_select_cursor_y = unpack('<f', mem_update[1])[0]
            return False
        if label == "ready_to_start":
            temp = unpack('>I', mem_update[1])[0]
            temp = temp & 0x000000ff
            self.ready_to_start = not bool(temp)
            return False
        if label == "controller_status":
            temp = unpack('>I', mem_update[1])[0]
            temp = temp & 0x000000ff
            self.player[player_int].controller_status = enums.ControllerStatus(
                temp)
            return False
        if label == "hitbox_1_size":
            self.player[player_int].hitbox_1_size = unpack(
                '<f', mem_update[1])[0]
            return False
        if label == "hitbox_2_size":
            self.player[player_int].hitbox_2_size = unpack(
                '<f', mem_update[1])[0]
            return False
        if label == "hitbox_3_size":
            self.player[player_int].hitbox_3_size = unpack(
                '<f', mem_update[1])[0]
            return False
        if label == "hitbox_4_size":
            self.player[player_int].hitbox_4_size = unpack(
                '<f', mem_update[1])[0]
            return False
        if label == "hitbox_1_status":
            temp = unpack('<I', mem_update[1])[0]
            status = True
            if temp == 0:
                status = False
            self.player[player_int].hitbox_1_status = status
            return False
        if label == "hitbox_2_status":
            temp = unpack('<I', mem_update[1])[0]
            status = True
            if temp == 0:
                status = False
            self.player[player_int].hitbox_2_status = status
            return False
        if label == "hitbox_3_status":
            temp = unpack('<I', mem_update[1])[0]
            status = True
            if temp == 0:
                status = False
            self.player[player_int].hitbox_3_status = status
            return False
        if label == "hitbox_4_status":
            temp = unpack('<I', mem_update[1])[0]
            status = True
            if temp == 0:
                status = False
            self.player[player_int].hitbox_4_status = status
            return False
        if label == "hitbox_1_x":
            self.player[player_int].hitbox_1_x = unpack('<f', mem_update[1])[0]
            return False
        if label == "hitbox_1_y":
            self.player[player_int].hitbox_1_y = unpack('<f', mem_update[1])[0]
            return False
        if label == "hitbox_2_x":
            self.player[player_int].hitbox_2_x = unpack('<f', mem_update[1])[0]
            return False
        if label == "hitbox_2_y":
            self.player[player_int].hitbox_2_y = unpack('<f', mem_update[1])[0]
            return False
        if label == "hitbox_3_x":
            self.player[player_int].hitbox_3_x = unpack('<f', mem_update[1])[0]
            return False
        if label == "hitbox_3_y":
            self.player[player_int].hitbox_3_y = unpack('<f', mem_update[1])[0]
            return False
        if label == "hitbox_4_x":
            self.player[player_int].hitbox_4_x = unpack('<f', mem_update[1])[0]
            return False
        if label == "hitbox_4_y":
            self.player[player_int].hitbox_4_y = unpack('<f', mem_update[1])[0]
            return False
        if label == "iasa":
            self.player[player_int].iasa = bool(
                unpack('<I', mem_update[1])[0] >> 31)
            return False
        if label == "transformed":
            temp = unpack('<I', mem_update[1])[0]
            status = False
            if temp == 16777216:
                status = True
            self.player[player_int].transformed = status
            return False
        if label == "iszelda":
            temp = unpack('<I', mem_update[1])[0]
            status = False
            if temp == 18:
                status = True
            self.player[player_int].iszelda = status
            return False
        if label == "projectiles":
            #Only once per new frame that we get a projectile, clear the list out
            if self.newframe:
                self.projectiles.clear()
                self.i = 0
            self.i += 1
            self.newframe = False
            if len(mem_update[1]) < 10:
                self.projectiles.clear()
                return False
            proj = Projectile()
            proj.x = unpack('>f', mem_update[1][0x4c:0x50])[0]
            proj.y = unpack('>f', mem_update[1][0x50:0x54])[0]
            proj.x_speed = unpack('>f', mem_update[1][0x40:0x44])[0]
            proj.y_speed = unpack('>f', mem_update[1][0x44:0x48])[0]
            try:
                proj.subtype = enums.ProjectileSubtype(
                    unpack('>I', mem_update[1][0x10:0x14])[0])
            except ValueError:
                return False
            self.projectiles.append(proj)
        return False
Пример #9
0
 def update(self, mem_update):
     label = self.locations[mem_update[0]][0]
     player_int = int(self.locations[mem_update[0]][1])
     if label == "frame":
         self.frame = unpack('<I', mem_update[1])[0]
         self.newframe = True
         #Now that the frame is ready, let's calculate some derived information
         #   These are not stored inside Melee anywhere, but are nonetheless
         #   important pieces of information that we don't want to make the
         #   user have to re-calculate on their own
         for i in self.player:
             if abs(self.player[i].x) > stages.edgegroundposition(
                     self.stage):
                 self.player[i].off_stage = True
             else:
                 self.player[i].off_stage = False
         #TODO: This needs updating in order to support >2 players
         xdist = self.ai_state.x - self.opponent_state.x
         ydist = self.ai_state.y - self.opponent_state.y
         self.distance = math.sqrt((xdist**2) + (ydist**2))
         self.fixframeindexing()
         return True
     if label == "stage":
         self.stage = unpack('<I', mem_update[1])[0]
         self.stage = self.stage >> 16
         self.stage &= 0x000000ff
         try:
             self.stage = enums.Stage(self.stage)
         except ValueError:
             self.stage = enums.Stage.NO_STAGE
         return False
     if label == "menu_state":
         self.menu_state = unpack('<I', mem_update[1])[0]
         self.menu_state &= 0x000000ff
         self.menu_state = enums.Menu(self.menu_state)
         return False
     #Player variables
     if label == "percent":
         self.player[player_int].percent = unpack('<I', mem_update[1])[0]
         self.player[
             player_int].percent = self.player[player_int].percent >> 16
         return False
     if label == "stock":
         self.player[player_int].stock = unpack('<I', mem_update[1])[0]
         self.player[player_int].stock = self.player[player_int].stock >> 24
         return False
     if label == "facing":
         self.player[player_int].facing = unpack('<I', mem_update[1])[0]
         self.player[player_int].facing = not bool(
             self.player[player_int].facing >> 31)
         return False
     if label == "x":
         self.player[player_int].x = unpack('<f', mem_update[1])[0]
         return False
     if label == "y":
         self.player[player_int].y = unpack('<f', mem_update[1])[0]
         return False
     if label == "character":
         temp = unpack('<I', mem_update[1])[0] >> 24
         try:
             self.player[player_int].character = enums.Character(temp)
         except ValueError:
             self.player[
                 player_int].character = enums.Character.UNKNOWN_CHARACTER
         return False
     if label == "cursor_x":
         self.player[player_int].cursor_x = unpack('<f', mem_update[1])[0]
         return False
     if label == "cursor_y":
         self.player[player_int].cursor_y = unpack('<f', mem_update[1])[0]
         return False
     if label == "action":
         temp = unpack('<I', mem_update[1])[0]
         try:
             self.player[player_int].action = enums.Action(temp)
         except ValueError:
             self.player[player_int].action = enums.Action.UNKNOWN_ANIMATION
         return False
     if label == "action_counter":
         #TODO look if this is backwards
         temp = unpack('I', mem_update[1])[0]
         temp = temp >> 8
         self.player[player_int].action_counter = temp
         return False
     if label == "action_frame":
         temp = unpack('<f', mem_update[1])[0]
         try:
             self.player[player_int].action_frame = int(temp)
         except ValueError:
             pass
         return False
     if label == "invulnerable":
         self.player[player_int].invulnerable = unpack('<I',
                                                       mem_update[1])[0]
         self.player[player_int].invulnerable = self.player[
             player_int].invulnerable >> 31
         return False
     if label == "hitlag_frames_left":
         temp = unpack('<f', mem_update[1])[0]
         try:
             self.player[player_int].hitlag_frames_left = int(temp)
         except ValueError:
             pass
         return False
     if label == "hitstun_frames_left":
         temp = unpack('<f', mem_update[1])[0]
         try:
             self.player[player_int].hitstun_frames_left = int(temp)
         except ValueError:
             pass
         return False
     if label == "charging_smash":
         temp = unpack('<I', mem_update[1])[0]
         if temp == 2:
             self.player[player_int].charging_smash = True
         else:
             self.player[player_int].charging_smash = False
         return False
     if label == "jumps_left":
         temp = unpack('<I', mem_update[1])[0]
         temp = temp >> 24
         #This value is actually the number of jumps USED
         #   so we have to do some quick math to turn this into what we want
         #TODO = characterstats.maxjumps(self.player[player_int].character) - temp + 1
         self.player[player_int].jumps_left = temp
         return False
     if label == "on_ground":
         temp = unpack('<I', mem_update[1])[0]
         if temp == 0:
             self.player[player_int].on_ground = True
         else:
             self.player[player_int].on_ground = False
         return False
     if label == "speed_air_x_self":
         self.player[player_int].speed_air_x_self = unpack(
             '<f', mem_update[1])[0]
         return False
     if label == "speed_y_self":
         self.player[player_int].speed_y_self = unpack('<f',
                                                       mem_update[1])[0]
         return False
     if label == "speed_x_attack":
         self.player[player_int].speed_x_attack = unpack(
             '<f', mem_update[1])[0]
         return False
     if label == "speed_y_attack":
         self.player[player_int].speed_y_attack = unpack(
             '<f', mem_update[1])[0]
         return False
     if label == "speed_ground_x_self":
         self.player[player_int].speed_ground_x_self = unpack(
             '<f', mem_update[1])[0]
         return False
     if label == "coin_down":
         temp = unpack('<I', mem_update[1])[0]
         temp = temp & 0x000000ff
         self.player[player_int].coin_down = (temp == 2)
         return False
     if label == "stage_select_cursor_x":
         self.stage_select_cursor_x = unpack('<f', mem_update[1])[0]
         return False
     if label == "stage_select_cursor_y":
         self.stage_select_cursor_y = unpack('<f', mem_update[1])[0]
         return False
     if label == "ready_to_start":
         temp = unpack('>I', mem_update[1])[0]
         temp = temp & 0x000000ff
         self.ready_to_start = not bool(temp)
         return False
     if label == "controller_status":
         temp = unpack('>I', mem_update[1])[0]
         temp = temp & 0x000000ff
         self.player[player_int].controller_status = enums.ControllerStatus(
             temp)
         return False
     if label == "hitbox_1_size":
         self.player[player_int].hitbox_1_size = unpack(
             '<f', mem_update[1])[0]
         return False
     if label == "hitbox_2_size":
         self.player[player_int].hitbox_2_size = unpack(
             '<f', mem_update[1])[0]
         return False
     if label == "hitbox_3_size":
         self.player[player_int].hitbox_3_size = unpack(
             '<f', mem_update[1])[0]
         return False
     if label == "hitbox_4_size":
         self.player[player_int].hitbox_4_size = unpack(
             '<f', mem_update[1])[0]
         return False
     if label == "hitbox_1_status":
         temp = unpack('<I', mem_update[1])[0]
         status = True
         if temp == 0:
             status = False
         self.player[player_int].hitbox_1_status = status
         return False
     if label == "hitbox_2_status":
         temp = unpack('<I', mem_update[1])[0]
         status = True
         if temp == 0:
             status = False
         self.player[player_int].hitbox_2_status = status
         return False
     if label == "hitbox_3_status":
         temp = unpack('<I', mem_update[1])[0]
         status = True
         if temp == 0:
             status = False
         self.player[player_int].hitbox_3_status = status
         return False
     if label == "hitbox_4_status":
         temp = unpack('<I', mem_update[1])[0]
         status = True
         if temp == 0:
             status = False
         self.player[player_int].hitbox_4_status = status
         return False
     if label == "hitbox_1_x":
         self.player[player_int].hitbox_1_x = unpack('<f', mem_update[1])[0]
         return False
     if label == "hitbox_1_y":
         self.player[player_int].hitbox_1_y = unpack('<f', mem_update[1])[0]
         return False
     if label == "hitbox_2_x":
         self.player[player_int].hitbox_2_x = unpack('<f', mem_update[1])[0]
         return False
     if label == "hitbox_2_y":
         self.player[player_int].hitbox_2_y = unpack('<f', mem_update[1])[0]
         return False
     if label == "hitbox_3_x":
         self.player[player_int].hitbox_3_x = unpack('<f', mem_update[1])[0]
         return False
     if label == "hitbox_3_y":
         self.player[player_int].hitbox_3_y = unpack('<f', mem_update[1])[0]
         return False
     if label == "hitbox_4_x":
         self.player[player_int].hitbox_4_x = unpack('<f', mem_update[1])[0]
         return False
     if label == "hitbox_4_y":
         self.player[player_int].hitbox_4_y = unpack('<f', mem_update[1])[0]
         return False
     if label == "projectiles":
         #Only once per new frame that we get a projectile, clear the list out
         if self.newframe:
             self.projectiles.clear()
             self.i = 0
         self.i += 1
         self.newframe = False
         if len(mem_update[1]) < 10:
             self.projectiles.clear()
             return False
         proj = Projectile()
         proj.x = unpack('>f', mem_update[1][0x4c:0x50])[0]
         proj.y = unpack('>f', mem_update[1][0x50:0x54])[0]
         proj.x_speed = unpack('>f', mem_update[1][0x40:0x44])[0]
         proj.y_speed = unpack('>f', mem_update[1][0x44:0x48])[0]
         try:
             proj.subtype = enums.ProjectileSubtype(
                 unpack('>I', mem_update[1][0x10:0x14])[0])
         except ValueError:
             proj.subtype = enums.ProjectileSubtype.UNKNOWN_PROJECTILE
         self.projectiles.append(proj)
     return False
Пример #10
0
    def __init__(self, write):
        if write:
            self.csvfile = open('framedata.csv', 'a')
            fieldnames = [
                'character', 'action', 'frame', 'hitbox_1_status',
                'hitbox_1_size', 'hitbox_1_x', 'hitbox_1_y', 'hitbox_2_status',
                'hitbox_2_size', 'hitbox_2_x', 'hitbox_2_y', 'hitbox_3_status',
                'hitbox_3_size', 'hitbox_3_x', 'hitbox_3_y', 'hitbox_4_status',
                'hitbox_4_size', 'hitbox_4_x', 'hitbox_4_y'
            ]
            self.writer = csv.DictWriter(self.csvfile, fieldnames=fieldnames)
            self.writer.writeheader()
            self.rows = []
        #Read the existing framedata
        path = os.path.dirname(os.path.realpath(__file__))
        self.framedata = defaultdict(
            lambda: defaultdict(lambda: defaultdict(dict)))
        with open(path + "/framedata.csv") as csvfile:
            # A list of dicts containing the frame data
            csvreader = list(csv.DictReader(csvfile))
            # Build a series of nested dicts for faster read access
            for frame in csvreader:
                # Pull out the character, action, and frame
                character = enums.Character(int(frame["character"]))
                action = enums.Action(int(frame["action"]))
                action_frame = int(frame["frame"])
                self.framedata[character][action][action_frame] = \
                    {"hitbox_1_status": frame["hitbox_1_status"] == "True", \
                    "hitbox_1_size": float(frame["hitbox_1_size"]), \
                    "hitbox_1_x": float(frame["hitbox_1_x"]), \
                    "hitbox_1_y": float(frame["hitbox_1_y"]), \
                    "hitbox_2_status": frame["hitbox_2_status"] == "True", \
                    "hitbox_2_size": float(frame["hitbox_2_size"]), \
                    "hitbox_2_x": float(frame["hitbox_2_x"]), \
                    "hitbox_2_y": float(frame["hitbox_2_y"]), \
                    "hitbox_3_status": frame["hitbox_3_status"] == "True", \
                    "hitbox_3_size": float(frame["hitbox_3_size"]), \
                    "hitbox_3_x": float(frame["hitbox_3_x"]), \
                    "hitbox_3_y": float(frame["hitbox_3_y"]), \
                    "hitbox_4_status": frame["hitbox_4_status"] == "True", \
                    "hitbox_4_size": float(frame["hitbox_4_size"]), \
                    "hitbox_4_x": float(frame["hitbox_4_x"]), \
                    "hitbox_4_y": float(frame["hitbox_4_y"])}

        #Read the action state data csv
        path = os.path.dirname(os.path.realpath(__file__))
        with open(path + "/actiondata.csv") as csvfile:
            # A list of dicts containing the frame data
            self.actiondata = list(csv.DictReader(csvfile))

        #read the character data csv
        self.characterdata = dict()
        path = os.path.dirname(os.path.realpath(__file__))
        with open(path + "/characterdata.csv") as csvfile:
            reader = csv.DictReader(csvfile)
            for line in reader:
                del line["Character"]
                #Convert all fields to numbers
                for key, value in line.items():
                    line[key] = float(value)
                self.characterdata[enums.Character(
                    line["CharacterIndex"])] = line
Пример #11
0
    def __post_frame(self, gamestate, event_bytes):
        gamestate.stage = self._current_stage
        gamestate.frame = np.ndarray((1,), ">i", event_bytes, 0x1)[0]
        controller_port = np.ndarray((1,), ">B", event_bytes, 0x5)[0] + 1

        if controller_port not in gamestate.player:
            gamestate.player[controller_port] = PlayerState()

        playerstate = gamestate.player[controller_port]
        playerstate.x = np.ndarray((1,), ">f", event_bytes, 0xa)[0]
        playerstate.y = np.ndarray((1,), ">f", event_bytes, 0xe)[0]

        playerstate.character = enums.Character(np.ndarray((1,), ">B", event_bytes, 0x7)[0])
        try:
            playerstate.action = enums.Action(np.ndarray((1,), ">H", event_bytes, 0x8)[0])
        except ValueError:
            playerstate.action = enums.Action.UNKNOWN_ANIMATION

        # Melee stores this in a float for no good reason. So we have to convert
        playerstate.facing = np.ndarray((1,), ">f", event_bytes, 0x12)[0] > 0

        playerstate.percent = int(np.ndarray((1,), ">f", event_bytes, 0x16)[0])
        playerstate.shield_strength = np.ndarray((1,), ">f", event_bytes, 0x1A)[0]
        playerstate.stock = np.ndarray((1,), ">B", event_bytes, 0x21)[0]
        playerstate.action_frame = int(np.ndarray((1,), ">f", event_bytes, 0x22)[0])

        # Extract the bit at mask 0x20
        try:
            bitflags2 = np.ndarray((1,), ">B", event_bytes, 0x27)[0]
            playerstate.hitlag = bool(bitflags2 & 0x20)
        except TypeError:
            playerstate.hitlag = False

        try:
            playerstate.hitstun_frames_left = int(np.ndarray((1,), ">f", event_bytes, 0x2B)[0])
        except TypeError:
            playerstate.hitstun_frames_left = 0
        except ValueError:
            playerstate.hitstun_frames_left = 0
        try:
            playerstate.on_ground = not bool(np.ndarray((1,), ">B", event_bytes, 0x2F)[0])
        except TypeError:
            playerstate.on_ground = True
        try:
            playerstate.jumps_left = np.ndarray((1,), ">B", event_bytes, 0x32)[0]
        except TypeError:
            playerstate.jumps_left = 1

        try:
            playerstate.invulnerable = int(np.ndarray((1,), ">B", event_bytes, 0x34)[0]) != 0
        except TypeError:
            playerstate.invulnerable = False

        try:
            playerstate.speed_air_x_self = np.ndarray((1,), ">f", event_bytes, 0x35)[0]
        except TypeError:
            playerstate.speed_air_x_self = 0

        try:
            playerstate.speed_y_self = np.ndarray((1,), ">f", event_bytes, 0x39)[0]
        except TypeError:
            playerstate.speed_y_self = 0

        try:
            playerstate.speed_x_attack = np.ndarray((1,), ">f", event_bytes, 0x3D)[0]
        except TypeError:
            playerstate.speed_x_attack = 0

        try:
            playerstate.speed_y_attack = np.ndarray((1,), ">f", event_bytes, 0x41)[0]
        except TypeError:
            playerstate.speed_y_attack = 0

        try:
            playerstate.speed_ground_x_self = np.ndarray((1,), ">f", event_bytes, 0x45)[0]
        except TypeError:
            playerstate.speed_ground_x_self = 0

        # Keep track of a player's invulnerability due to respawn or ledge grab
        if controller_port in self._prev_gamestate.player:
            playerstate.invulnerability_left = max(0, self._prev_gamestate.player[controller_port].invulnerability_left - 1)
        if playerstate.action == Action.ON_HALO_WAIT:
            playerstate.invulnerability_left = 120
        # Don't give invulnerability to the first descent
        if playerstate.action == Action.ON_HALO_DESCENT and gamestate.frame > 150:
            playerstate.invulnerability_left = 120
        if playerstate.action == Action.EDGE_CATCHING and playerstate.action_frame == 1:
            playerstate.invulnerability_left = 36

        # The pre-warning occurs when we first start a dash dance.
        if controller_port in self._prev_gamestate.player:
            if playerstate.action == Action.DASHING and \
                    self._prev_gamestate.player[controller_port].action not in [Action.DASHING, Action.TURNING]:
                playerstate.moonwalkwarning = True

        # Take off the warning if the player does an action other than dashing
        if playerstate.action != Action.DASHING:
            playerstate.moonwalkwarning = False

        # "off_stage" helper
        if (abs(playerstate.x) > stages.EDGE_GROUND_POSITION[gamestate.stage] or \
                playerstate.y < -6) and not playerstate.on_ground:
            playerstate.off_stage = True
        else:
            playerstate.off_stage = False

        # ECB top edge, x
        ecb_top_x = 0
        ecb_top_y = 0
        try:
            ecb_top_x = np.ndarray((1,), ">f", event_bytes, 0x49)[0]
        except TypeError:
            ecb_top_x = 0
        # ECB Top edge, y
        try:
            ecb_top_y = np.ndarray((1,), ">f", event_bytes, 0x4D)[0]
        except TypeError:
            ecb_top_y = 0
        playerstate.ecb_top = (ecb_top_x, ecb_top_y)

        # ECB bottom edge, x coord
        ecb_bot_x = 0
        ecb_bot_y = 0
        try:
            ecb_bot_x = np.ndarray((1,), ">f", event_bytes, 0x51)[0]
        except TypeError:
            ecb_bot_x = 0
        # ECB Bottom edge, y coord
        try:
            ecb_bot_y = np.ndarray((1,), ">f", event_bytes, 0x55)[0]
        except TypeError:
            ecb_bot_y = 0
        playerstate.ecb_bottom = (ecb_bot_x, ecb_bot_y)

        # ECB left edge, x coord
        ecb_left_x = 0
        ecb_left_y = 0
        try:
            ecb_left_x = np.ndarray((1,), ">f", event_bytes, 0x59)[0]
        except TypeError:
            ecb_left_x = 0
        # ECB left edge, y coord
        try:
            ecb_left_y = np.ndarray((1,), ">f", event_bytes, 0x5D)[0]
        except TypeError:
            ecb_left_y = 0
        playerstate.ecb_left = (ecb_left_x, ecb_left_y)

        # ECB right edge, x coord
        ecb_right_x = 0
        ecb_right_y = 0
        try:
            ecb_right_x = np.ndarray((1,), ">f", event_bytes, 0x61)[0]
        except TypeError:
            ecb_right_x = 0
        # ECB right edge, y coord
        try:
            ecb_right_y = np.ndarray((1,), ">f", event_bytes, 0x65)[0]
        except TypeError:
            ecb_right_y = 0
        playerstate.ecb_right = (ecb_right_x, ecb_right_y)
        if self._allow_old_version:
            self._frame = gamestate.frame