def __item_update(self, gamestate, event_bytes): projectile = Projectile() projectile.position.x = np.ndarray((1,), ">f", event_bytes, 0x14)[0] projectile.position.y = np.ndarray((1,), ">f", event_bytes, 0x18)[0] projectile.x = projectile.position.x projectile.y = projectile.position.y projectile.speed.x = np.ndarray((1,), ">f", event_bytes, 0xc)[0] projectile.speed.y = np.ndarray((1,), ">f", event_bytes, 0x10)[0] projectile.x_speed = projectile.speed.x projectile.y_speed = projectile.speed.y try: projectile.owner = np.ndarray((1,), ">B", event_bytes, 0x2A)[0] + 1 if projectile.owner > 4: projectile.owner = -1 except TypeError: projectile.owner = -1 try: projectile.type = enums.ProjectileType(np.ndarray((1,), ">H", event_bytes, 0x5)[0]) except ValueError: projectile.type = enums.ProjectileType.UNKNOWN_PROJECTILE try: projectile.frame = int(np.ndarray((1,), ">f", event_bytes, 0x1E)[0]) except ValueError: projectile.frame = -1 projectile.subtype = np.ndarray((1,), ">B", event_bytes, 0x7)[0] # Ignore exploded Samus bombs. They are subtype 3 if projectile.type == enums.ProjectileType.SAMUS_BOMB and projectile.subtype == 3: return # Ignore exploded Samus missles if projectile.type == enums.ProjectileType.SAMUS_MISSLE and projectile.subtype in [2, 3]: return # Ignore Samus charge beam while charging (not firing) if projectile.type == enums.ProjectileType.SAMUS_CHARGE_BEAM and projectile.subtype == 0: return # Add the projectile to the gamestate list gamestate.projectiles.append(projectile)
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
def __item_update(self, gamestate, event_bytes): projectile = Projectile() projectile.x = np.ndarray((1, ), ">f", event_bytes, 0x14)[0] projectile.y = np.ndarray((1, ), ">f", event_bytes, 0x18)[0] projectile.x_speed = np.ndarray((1, ), ">f", event_bytes, 0xc)[0] projectile.y_speed = np.ndarray((1, ), ">f", event_bytes, 0x10)[0] try: projectile.owner = np.ndarray( (1, ), ">B", event_bytes, 0x2A)[0] + 1 if projectile.owner > 4: projectile.owner = -1 except TypeError: projectile.owner = -1 try: projectile.subtype = enums.ProjectileSubtype( np.ndarray((1, ), ">H", event_bytes, 0x5)[0]) except ValueError: projectile.subtype = enums.ProjectileSubtype.UNKNOWN_PROJECTILE # Add the projectile to the gamestate list gamestate.projectiles.append(projectile)
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