예제 #1
0
    def __init__(self, header_file, filename=None, **options):
        super(MapHeader, self).__init__(header_file, filename, **options)
        self.data = BitPackedDecoder(header_file).read_struct()

        # Name
        self.name = self.data[0][1]

        # Blizzard
        self.blizzard = (self.data[0][11] == 'BLIZ')

        # Parse image hash
        parsed_hash = utils.parse_hash(self.data[0][1])
        self.image_hash = parsed_hash['hash']
        self.image_url = self.image_url_template.format(
            parsed_hash['server'], parsed_hash['hash'])

        # Parse map hash
        parsed_hash = utils.parse_hash(self.data[0][2])
        self.map_hash = parsed_hash['hash']
        self.map_url = self.base_url_template.format(parsed_hash['server'],
                                                     parsed_hash['hash'],
                                                     parsed_hash['type'])

        # Parse localization hashes
        l18n_struct = self.data[0][4][8]
        for l in l18n_struct:
            parsed_hash = utils.parse_hash(l[1][0])
            self.localization_urls[l[0]] = self.base_url_template.format(
                parsed_hash['server'], parsed_hash['hash'],
                parsed_hash['type'])
예제 #2
0
 def __init__(self, info_file, filename=None, **options):
     super(MapInfo, self).__init__(info_file, filename, **options)
     self.data = BitPackedDecoder(info_file).read_struct()
     self.map_name = self.data[0][7]
     self.language = self.data[0][13]
     parsed_hash = utils.parse_hash(self.data[0][1])
     self.s2mh_hash =  parsed_hash['hash']
     self.s2mh_url = MapHeader.url_template.format(parsed_hash['server'], self.s2mh_hash)
예제 #3
0
def read_file(filename):
    with open(filename, 'rb') as f:
        ext = os.path.splitext(filename)[1][1:]
        data = BitPackedDecoder(f.read()).read_struct()
        if ext == 's2mh':
            return read_s2mh(data)
        elif ext == 's2mi':
            return read_s2mi(data)
        else:
            raise Exception(ext)
        return data
예제 #4
0
    def __call__(self, data, replay):
        # The replay.message.events file is a single long list containing three
        # different element types (minimap pings, player messages, and some sort
        # of network packets); each differentiated by flags.
        data = BitPackedDecoder(data)
        pings = list()
        messages = list()
        packets = list()

        frame = 0
        while not data.done():
            # All the element types share the same time, pid, flags header.
            frame += data.read_frames()
            pid = data.read_bits(5)
            t = data.read_bits(3)
            flags = data.read_uint8()

            if flags in (0x83,0x89):
                # We need some tests for this, probably not right
                x = data.read_uint32()
                y = data.read_uint32()
                pings.append(PingEvent(frame, pid, flags, x, y))

            elif flags == 0x80:
                info = data.read_bytes(4)
                packets.append(PacketEvent(frame, pid, flags, info))

            elif flags & 0x80 == 0:
                lo_mask = 2**self.TARGET_BITS-1
                hi_mask = 0xFF ^ lo_mask
                target = flags & lo_mask
                extension = (flags & hi_mask) << 3
                length = data.read_uint8()
                text = data.read_bytes(length + extension)
                messages.append(ChatEvent(frame, pid, flags, target, text, (flags, lo_mask, hi_mask, length, extension)))

        return AttributeDict(pings=pings, messages=messages, packets=packets)
예제 #5
0
    def __init__(self, summary_file, filename=None, lang='enUS', **options):
        super(GameSummary, self).__init__(summary_file,
                                          filename,
                                          lang=lang,
                                          **options)

        #: A dict of team# -> teams
        self.team = dict()

        #: A list of teams
        self.teams = list()

        #: Players, a dict of :class`PlayerSummary` from the game
        self.players = list()

        self.observers = list()

        #: Game start and end times
        self.start_time = None
        self.end_time = None

        self.winners = list()
        self.player = dict()
        self.settings = dict()
        self.player_stats = dict()
        self.player_settings = defaultdict(dict)
        self.build_orders = defaultdict(list)
        self.image_urls = list()
        self.localization_urls = dict()
        self.lobby_properties = dict()
        self.lobby_player_properties = dict()
        self.game_type = str()
        self.real_type = str()

        # The first 16 bytes appear to be some sort of compression header
        buffer = BitPackedDecoder(zlib.decompress(summary_file.read()[16:]))

        # TODO: Is there a fixed number of entries?
        # TODO: Maybe the # of parts is recorded somewhere?
        self.parts = list()
        while not buffer.done():
            self.parts.append(buffer.read_struct())

        self.end_time = datetime.utcfromtimestamp(self.parts[0][8])
        self.game_speed = LOBBY_PROPERTIES[0xBB8][1][self.parts[0][0]
                                                     [1].decode('utf8')]
        self.game_length = utils.Length(seconds=self.parts[0][7])
        self.real_length = utils.Length(
            seconds=int(self.parts[0][7] / GAME_SPEED_FACTOR[self.game_speed]))
        self.start_time = datetime.utcfromtimestamp(self.parts[0][8] -
                                                    self.real_length.seconds)

        self.load_translations()
        self.load_map_info()
        self.load_settings()
        self.load_player_stats()
        self.load_players()

        dependencies = [sheet[1] for sheet in self.lang_sheets['enUS']]
        if 'Swarm (Mod)' in dependencies:
            self.expansion = 'HotS'
        elif 'Liberty (Mod)' in dependencies:
            self.expansion = 'WoL'
        else:
            self.expansion = ''

        self.game_type = self.settings['Teams'].replace(" ", "")
        self.real_type = utils.get_real_type(self.teams)

        # The s2gs file also keeps reference to a series of s2mv files
        # Some of these appear to be encoded bytes and others appear to be
        # the preview images that authors may bundle with their maps.
        self.s2mv_urls = [
            str(utils.DepotFile(file_hash))
            for file_hash in self.parts[0][6][7]
        ]
예제 #6
0
    def __init__(self,
                 replay_file,
                 filename=None,
                 load_level=4,
                 engine=sc2reader.engine,
                 **options):
        super(Replay, self).__init__(replay_file, filename, **options)
        self.datapack = None
        self.raw_data = dict()

        # The current load level of the replay
        self.load_level = None

        #default values, filled in during file read
        self.player_names = list()
        self.other_people = set()
        self.speed = ""
        self.type = ""
        self.game_type = ""
        self.real_type = ""
        self.category = ""
        self.is_ladder = False
        self.is_private = False
        self.map = None
        self.map_hash = ""
        self.gateway = ""
        self.events = list()
        self.events_by_type = defaultdict(list)
        self.teams, self.team = list(), dict()

        self.player = utils.PersonDict()
        self.observer = utils.PersonDict()
        self.human = utils.PersonDict()
        self.computer = utils.PersonDict()
        self.entity = utils.PersonDict()

        self.players = list()
        self.observers = list()  # Unordered list of Observer
        self.humans = list()
        self.computers = list()
        self.entities = list()

        self.attributes = defaultdict(dict)
        self.messages = list()
        self.recorder = None  # Player object
        self.packets = list()
        self.objects = {}
        self.active_units = {}
        self.game_fps = 16.0

        self.tracker_events = list()
        self.game_events = list()

        # Bootstrap the readers.
        self.registered_readers = defaultdict(list)
        self.register_default_readers()

        # Bootstrap the datapacks.
        self.registered_datapacks = list()
        self.register_default_datapacks()

        # Unpack the MPQ and read header data if requested
        # Since the underlying traceback isn't important to most people, don't expose it in python2 anymore
        if load_level >= 0:
            self.load_level = 0
            try:
                self.archive = mpyq.MPQArchive(replay_file, listfile=False)
            except Exception as e:
                raise exceptions.MPQError("Unable to construct the MPQArchive",
                                          e)

            header_content = self.archive.header['user_data_header']['content']
            header_data = BitPackedDecoder(header_content).read_struct()
            self.versions = list(header_data[1].values())
            self.frames = header_data[3]
            self.build = self.versions[4]
            self.base_build = self.versions[5]
            self.release_string = "{0}.{1}.{2}.{3}".format(*self.versions[1:5])
            self.game_length = utils.Length(seconds=self.frames / 16)
            self.length = self.real_length = utils.Length(
                seconds=int(self.frames / self.game_fps))

        # Load basic details if requested
        if load_level >= 1:
            self.load_level = 1
            for data_file in [
                    'replay.initData', 'replay.details',
                    'replay.attributes.events'
            ]:
                self._read_data(data_file, self._get_reader(data_file))
            self.load_details()
            self.datapack = self._get_datapack()

            # Can only be effective if map data has been loaded
            if options.get('load_map', False):
                self.load_map()

        # Load players if requested
        if load_level >= 2:
            self.load_level = 2
            for data_file in ['replay.message.events']:
                self._read_data(data_file, self._get_reader(data_file))
            self.load_message_events()
            self.load_players()

        # Load tracker events if requested
        if load_level >= 3:
            self.load_level = 3
            for data_file in ['replay.tracker.events']:
                self._read_data(data_file, self._get_reader(data_file))
            self.load_tracker_events()

        # Load events if requested
        if load_level >= 4:
            self.load_level = 4
            for data_file in ['replay.game.events']:
                self._read_data(data_file, self._get_reader(data_file))
            self.load_game_events()

        # Run this replay through the engine as indicated
        if engine:
            engine.run(self)
예제 #7
0
    def __init__(self, summary_file, filename=None, lang='enUS', **options):
        super(GameSummary, self).__init__(summary_file, filename, lang=lang, **options)

        #: A dict of team# -> teams
        self.team = dict()

        #: A list of teams
        self.teams = list()

        #: Players, a dict of :class`PlayerSummary` from the game
        self.players = list()

        self.observers = list()

        #: Game start and end times
        self.start_time = None
        self.end_time = None

        self.winners = list()
        self.player = dict()
        self.settings = dict()
        self.player_stats = dict()
        self.player_settings = defaultdict(dict)
        self.build_orders = defaultdict(list)
        self.image_urls = list()
        self.localization_urls = dict()
        self.lobby_properties = dict()
        self.lobby_player_properties = dict()
        self.game_type = str()
        self.real_type = str()

        # The first 16 bytes appear to be some sort of compression header
        buffer = BitPackedDecoder(zlib.decompress(summary_file.read()[16:]))

        # TODO: Is there a fixed number of entries?
        # TODO: Maybe the # of parts is recorded somewhere?
        self.parts = list()
        while not buffer.done():
            self.parts.append(buffer.read_struct())

        self.end_time = datetime.utcfromtimestamp(self.parts[0][8])
        self.game_speed = LOBBY_PROPERTIES[0xBB8][1][self.parts[0][0][1].decode('utf8')]
        self.game_length = utils.Length(seconds=self.parts[0][7])
        self.real_length = utils.Length(seconds=int(self.parts[0][7]/GAME_SPEED_FACTOR[self.game_speed]))
        self.start_time = datetime.utcfromtimestamp(self.parts[0][8] - self.real_length.seconds)

        self.load_translations()
        self.load_map_info()
        self.load_settings()
        self.load_player_stats()
        self.load_players()

        dependencies = [sheet[1] for sheet in self.lang_sheets['enUS']]
        if 'Swarm (Mod)' in dependencies:
            self.expansion = 'HotS'
        elif 'Liberty (Mod)' in dependencies:
            self.expansion = 'WoL'
        else:
            self.expansion = ''

        self.game_type = self.settings['Teams'].replace(" ", "")
        self.real_type = utils.get_real_type(self.teams)

        # The s2gs file also keeps reference to a series of s2mv files
        # Some of these appear to be encoded bytes and others appear to be
        # the preview images that authors may bundle with their maps.
        self.s2mv_urls = [str(utils.DepotFile(file_hash)) for file_hash in self.parts[0][6][7]]
예제 #8
0
    def __call__(self, data, replay):
        data = BitPackedDecoder(data)
        game_events = list()
        fstamp = 0
        debug = replay.opt.debug
        data_length = data.length
        read_frames =  data.read_frames
        read_bits = data.read_bits
        read_uint8 = data.read_uint8
        tell = data.tell
        read_bytes = data.read_bytes
        byte_align = data.byte_align
        append = game_events.append
        event_start = 0

        try:
            while event_start != data_length:
                fstamp += read_frames()
                pid = read_bits(5)
                event_type = read_bits(7)

                # Check for a lookup
                if event_type in self.EVENT_DISPATCH:
                    event = self.EVENT_DISPATCH[event_type](data, fstamp, pid, event_type)
                    if debug:
                        event.bytes = data.read_range(event_start, tell())
                    append(event)

                # Otherwise maybe it is an unknown chunk
                elif event_type == 0x26:
                    read_bytes(8)
                elif event_type == 0x27:
                    read_bytes(4)
                elif event_type == 0x37:
                    read_bytes(8)
                elif event_type == 0x38:
                    arr1 = [read_bits(32) for i in range(read_bits(8))]
                    arr2 = [read_bits(32) for i in range(read_bits(8))]
                elif event_type == 0x3c:
                    read_bytes(2)
                elif event_type == 0x47:
                    read_bytes(4)
                elif event_type == 0x48:
                    read_bytes(4)
                elif event_type == 0x4C:
                    read_bits(4)
                elif event_type == 0x59:
                    read_bytes(4)
                elif event_type == 0x00:
                    read_bytes(1)

                # Otherwise throw a read error
                else:
                    raise ReadError("Event type {0} unknown at position {1}.".format(hex(event_type),hex(event_start)), event_type, event_start, replay, game_events, data)

                byte_align()
                event_start = tell()

            return game_events
        except ParseError as e:
            raise ReadError("Parse error '{0}' unknown at position {1}.".format(e.msg, hex(event_start)), event_type, event_start, replay, game_events, data)
        except EOFError as e:
            raise ReadError("EOFError error '{0}' unknown at position {1}.".format(e.msg, hex(event_start)), event_type, event_start, replay, game_events, data)
예제 #9
0
    def __call__(self, data, replay):
        data = BitPackedDecoder(data)

        init_data = dict( #58
            player_init_data = [dict( #38
                    name = data.read_aligned_bytes(data.read_uint8()),
                    clan_tag = None,
                    highest_league = None,
                    combined_race_levels = None,
                    random_seed = data.read_uint32(),
                    race_preference = data.read_uint8() if data.read_bool() else None, #38
                    team_preference = data.read_uint8() if data.read_bool() else None, #39
                    test_map = data.read_bool(),
                    test_auto = data.read_bool(),
                    examine = data.read_bool(),
                    custom_interface = None,
                    observe = data.read_bits(2),
                ) for i in range(data.read_bits(5))
            ],

            game_description = dict( # 48
                random_value = None,
                game_cache_name = None,
                game_options = dict( #40
                        lock_teams = None,
                        teams_together = None,
                        advanced_shared_control = None,
                        random_races = None,
                        battle_net = None,
                        amm = None,
                        competitive = None,
                        no_victory_or_defeat = None,
                        fog = None,
                        observers = None,
                        user_difficulty = None,
                        client_debug_flags = None,
                    ),
                game_speed = None,
                game_type = None,
                max_users = None,
                max_observers = None,
                max_players = None,
                max_teams = None,
                max_colors = None,
                max_races = None,
                max_controls = None,
                map_size_x = None,
                map_size_y = None,
                map_file_sync_checksum = None,
                map_file_name = None,
                map_author_name = None,
                mod_file_sync_checksum = None,
                slot_descriptions = [dict( #47
                        allowed_colors = None,
                        allowed_races = None,
                        allowedDifficulty = None,
                        allowedControls = None,
                        allowed_observe_types = None,
                        allowed_ai_builds = None,
                    ) for i in range(0)],
                default_difficulty = None,
                default_AI_build = None,
                cache_handles = [],
                is_blizzardMap = None,
                is_premade_ffa = None,
                is_coop_mode = None,
            ),

            lobby_state = dict( #56
                phase = None,
                max_users = None,
                max_observers = None,
                slots = [dict( #54
                        control = None,
                        user_id = None,
                        team_id = None,
                        colorPref = None,
                        race_pref = None,
                        difficulty = None,
                        ai_build = None,
                        handicap = None,
                        observe = None,
                        working_set_slot_id = None,
                        rewards = [],
                        toon_handle = None,
                        licenses = [],
                    ) for i in range(0)], # 58
                random_seed = None,
                host_user_id = None,
                is_single_player = None,
                game_duration = None,
                default_difficulty = None,
                default_ai_build = 0,
            ),
        )

        distance = data.read_range(data.tell(), data.length).find('s2ma')
        data.read_aligned_bytes(distance)

        map_data = list()
        while data.peek(4) == 's2ma':
            depot_file = DepotFile(data.read_aligned_bytes(40))
            init_data['game_description']['cache_handles'].append(depot_file)

        init_data.setdefault('game_description',dict())['cache_handles'] = map_data
        return init_data
예제 #10
0
    def __call__(self, data, replay):
        data = BitPackedDecoder(data)

        init_data = dict(
            player_init_data = [dict(
                    name = data.read_aligned_bytes(data.read_uint8()),
                    clan_tag = data.read_aligned_bytes(data.read_uint8()) if data.read_bool() else "", # 36
                    highest_league = data.read_uint8() if data.read_bool() else None, #20
                    combined_race_levels = data.read_uint32() if data.read_bool() else None, #37
                    random_seed = data.read_uint32(),
                    race_preference = data.read_uint8() if data.read_bool() else None, #38
                    team_preference = data.read_uint8() if data.read_bool() else None, #39
                    test_map = data.read_bool(),
                    test_auto = data.read_bool(),
                    examine = data.read_bool(),
                    custom_interface = data.read_bool(),
                    observe = data.read_bits(2),
                ) for i in range(data.read_bits(5))
            ],

            game_description = dict(
                random_value = data.read_uint32(), # 4
                game_cache_name = data.read_aligned_bytes(data.read_bits(10)), # 24
                game_options = dict(
                        lock_teams = data.read_bool(), #27
                        teams_together = data.read_bool(),
                        advanced_shared_control = data.read_bool(),
                        random_races = data.read_bool(),
                        battle_net = data.read_bool(),
                        amm = data.read_bool(),
                        competitive = data.read_bool(),
                        no_victory_or_defeat = data.read_bool(),
                        fog = data.read_bits(2), #19
                        observers = data.read_bits(2), #19
                        user_difficulty = data.read_bits(2), #19
                        client_debug_flags = data.read_uint64(), #15
                    ),
                game_speed = data.read_bits(3),
                game_type = data.read_bits(3),
                max_users = data.read_bits(5),
                max_observers = data.read_bits(5),
                max_players = data.read_bits(5),
                max_teams = data.read_bits(4)+1,
                max_colors = data.read_bits(6),
                max_races = data.read_uint8()+1,
                max_controls = data.read_uint8()+1,
                map_size_x = data.read_uint8(),
                map_size_y = data.read_uint8(),
                map_file_sync_checksum = data.read_uint32(),
                map_file_name = data.read_aligned_bytes(data.read_bits(11)),
                map_author_name = data.read_aligned_bytes(data.read_uint8()),
                mod_file_sync_checksum = data.read_uint32(),
                slot_descriptions = [dict( #50
                        allowed_colors = data.read_bits(data.read_bits(6)),
                        allowed_races = data.read_bits(data.read_uint8()),
                        allowedDifficulty = data.read_bits(data.read_bits(6)),
                        allowedControls = data.read_bits(data.read_uint8()),
                        allowed_observe_types = data.read_bits(data.read_bits(2)),
                        allowed_ai_builds = data.read_bits(data.read_bits(7)),
                    ) for i in range(data.read_bits(5))],
                default_difficulty = data.read_bits(6),
                default_AI_build = data.read_bits(7),
                cache_handles = [
                    DepotFile(data.read_aligned_bytes(40)) for i in range(data.read_bits(6))
                ],
                is_blizzardMap = data.read_bool(),
                is_premade_ffa = data.read_bool(),
                is_coop_mode = data.read_bool(),
            ),

            lobby_state = dict(
                phase = data.read_bits(3),
                max_users = data.read_bits(5),
                max_observers = data.read_bits(5),
                slots = [dict(
                        control = data.read_uint8(),
                        user_id = data.read_bits(4) if data.read_bool() else None,
                        team_id = data.read_bits(4),
                        colorPref = data.read_bits(5) if data.read_bool() else None,
                        race_pref = data.read_uint8() if data.read_bool() else None,
                        difficulty = data.read_bits(6),
                        ai_build = data.read_bits(7),
                        handicap = data.read_bits(7),
                        observe = data.read_bits(2),
                        working_set_slot_id = data.read_uint8() if data.read_bool() else None,
                        rewards = [data.read_uint32() for i in range(data.read_bits(6))],
                        toon_handle = data.read_aligned_bytes(data.read_bits(7)), # 14
                        licenses = [data.read_uint32() for i in range(data.read_bits(9))], # 56
                    ) for i in range(data.read_bits(5))], # 58
                random_seed = data.read_uint32(),
                host_user_id = data.read_bits(4) if data.read_bool() else None, # 52
                is_single_player = data.read_bool(), # 27
                game_duration = data.read_uint32(), # 4
                default_difficulty = data.read_bits(6), # 1
                default_ai_build = data.read_bits(7), # 0
            ),
        )

        return init_data
예제 #11
0
    def __init__(self, replay_file, filename=None, load_level=4, **options):
        super(Replay, self).__init__(replay_file, filename, **options)
        self.datapack = None
        self.raw_data = dict()

        #default values, filled in during file read
        self.player_names = list()
        self.other_people = set()
        self.speed = ""
        self.type = ""
        self.game_type = ""
        self.real_type = ""
        self.category = ""
        self.is_ladder = False
        self.is_private = False
        self.map = None
        self.map_hash = ""
        self.gateway = ""
        self.events = list()
        self.events_by_type = defaultdict(list)
        self.teams, self.team = list(), dict()
        self.players, self.player = list(), utils.PersonDict()
        self.observers = list()  #Unordered list of Observer
        self.people, self.humans = list(), list(
        )  #Unordered list of Players+Observers
        self.person = utils.PersonDict()  #Maps pid to Player/Observer
        self.attributes = defaultdict(dict)
        self.messages = list()
        self.recorder = None  # Player object
        self.packets = list()
        self.objects = {}
        self.active_units = {}
        self.game_fps = 16.0

        # Bootstrap the readers.
        self.registered_readers = defaultdict(list)
        self.register_default_readers()

        # Bootstrap the datapacks.
        self.registered_datapacks = list()
        self.register_default_datapacks()

        # Unpack the MPQ and read header data if requested
        if load_level >= 0:
            try:
                self.archive = mpyq.MPQArchive(replay_file, listfile=False)
            except Exception as e:
                trace = sys.exc_info()[2]
                raise exceptions.MPQError("Unable to construct the MPQArchive",
                                          e), None, trace

            header_content = self.archive.header['user_data_header']['content']
            header_data = BitPackedDecoder(header_content).read_struct()
            self.versions = header_data[1].values()
            self.frames = header_data[3]
            self.build = self.versions[4]
            self.release_string = "{0}.{1}.{2}.{3}".format(*self.versions[1:5])
            self.game_length = utils.Length(seconds=self.frames / 16)
            self.length = self.real_length = utils.Length(
                seconds=int(self.frames / self.game_fps))

        # Load basic details if requested
        if load_level >= 1:
            for data_file in [
                    'replay.initData', 'replay.details',
                    'replay.attributes.events'
            ]:
                self._read_data(data_file, self._get_reader(data_file))
            self.load_details()
            self.datapack = self._get_datapack()

            # Can only be effective if map data has been loaded
            if options.get('load_map', False):
                self.load_map()

        # Load players if requested
        if load_level >= 2:
            for data_file in ['replay.message.events']:
                self._read_data(data_file, self._get_reader(data_file))
            self.load_messages()
            self.load_players()

        # Load events if requested
        if load_level >= 3:
            for data_file in ['replay.game.events']:
                self._read_data(data_file, self._get_reader(data_file))
            self.load_events()

        # Load tracker events if requested
        if load_level >= 4:
            for data_file in ['replay.tracker.events']:
                self._read_data(data_file, self._get_reader(data_file))
            self.load_tracker_events()

        for event in self.events:
            event.load_context(self)
예제 #12
0
    def __call__(self, data, replay):
        data = BitPackedDecoder(data)
        game_events = list()
        fstamp = 0
        debug = replay.opt.debug
        data_length = data.length
        read_frames = data.read_frames
        read_bits = data.read_bits
        read_uint8 = data.read_uint8
        tell = data.tell
        read_bytes = data.read_bytes
        byte_align = data.byte_align
        append = game_events.append
        event_start = 0

        try:
            while event_start != data_length:
                fstamp += read_frames()
                pid = read_bits(5)
                event_type = read_bits(7)

                # Check for a lookup
                if event_type in self.EVENT_DISPATCH:
                    event = self.EVENT_DISPATCH[event_type](data, fstamp, pid,
                                                            event_type)
                    if debug:
                        event.bytes = data.read_range(event_start, tell())
                    append(event)

                # Otherwise maybe it is an unknown chunk
                elif event_type == 0x26:
                    read_bytes(8)
                elif event_type == 0x27:
                    read_bytes(4)
                elif event_type == 0x37:
                    read_bytes(8)
                elif event_type == 0x38:
                    arr1 = [read_bits(32) for i in range(read_bits(8))]
                    arr2 = [read_bits(32) for i in range(read_bits(8))]
                elif event_type == 0x3c:
                    read_bytes(2)
                elif event_type == 0x47:
                    read_bytes(4)
                elif event_type == 0x48:
                    read_bytes(4)
                elif event_type == 0x4C:
                    read_bits(4)
                elif event_type == 0x59:
                    read_bytes(4)
                elif event_type == 0x00:
                    read_bytes(1)

                # Otherwise throw a read error
                else:
                    raise ReadError(
                        "Event type {0} unknown at position {1}.".format(
                            hex(event_type), hex(event_start)), event_type,
                        event_start, replay, game_events, data)

                byte_align()
                event_start = tell()

            return game_events
        except ParseError as e:
            raise ReadError(
                "Parse error '{0}' unknown at position {1}.".format(
                    e.msg, hex(event_start)), event_type, event_start, replay,
                game_events, data)
        except EOFError as e:
            raise ReadError(
                "EOFError error '{0}' unknown at position {1}.".format(
                    e.msg, hex(event_start)), event_type, event_start, replay,
                game_events, data)
예제 #13
0
    def __call__(self, data, replay):
        # The replay.message.events file is a single long list containing three
        # different element types (minimap pings, player messages, and some sort
        # of network packets); each differentiated by flags.
        data = BitPackedDecoder(data)
        pings = list()
        messages = list()
        packets = list()

        frame = 0
        while not data.done():
            # All the element types share the same time, pid, flags header.
            frame += data.read_frames()
            pid = data.read_bits(5)
            t = data.read_bits(3)
            flags = data.read_uint8()

            if flags in (0x83, 0x89):
                # We need some tests for this, probably not right
                x = data.read_uint32()
                y = data.read_uint32()
                pings.append(PingEvent(frame, pid, flags, x, y))

            elif flags == 0x80:
                info = data.read_bytes(4)
                packets.append(PacketEvent(frame, pid, flags, info))

            elif flags & 0x80 == 0:
                lo_mask = 2**self.TARGET_BITS - 1
                hi_mask = 0xFF ^ lo_mask
                target = flags & lo_mask
                extension = (flags & hi_mask) << 3
                length = data.read_uint8()
                text = data.read_bytes(length + extension)
                messages.append(
                    ChatEvent(frame, pid, flags, target, text,
                              (flags, lo_mask, hi_mask, length, extension)))

        return AttributeDict(pings=pings, messages=messages, packets=packets)
예제 #14
0
    def __call__(self, data, replay):
        # The entire details file is just a serialized data structure
        #
        # See: utils.Replaydata.read_struct for a format description
        #
        # The general file structure is as follows:
        #   TODO: add the data types for each node in the structure
        #
        #   List of Players:
        #       Name
        #       BnetData:
        #           unknown1
        #           unknown2
        #           subregion_id
        #           bnet_id
        #       actual_race (Terran, Protoss, Zerg)
        #       ColorData:
        #           alpha (0-255)
        #           red (0-255)
        #           green (0-255)
        #           blue (0-255)
        #       Unknown1
        #       Unknown2
        #       handicap (0-100)
        #       Team Number - according to András
        #       Result (0,1,2) - (Unknown, Win, Loss), thanks András
        #   Map
        #   Unknown1
        #   Unknown2
        #   Unknown3
        #   file_time - Time file was created/replay was made
        #   utc_adjustment
        #   Unknown4
        #   Unknown5
        #   Unknown6
        #   Unknown7
        #   Unknown8
        #   Unknown9
        #   Unknown10
        #
        details = BitPackedDecoder(data).read_struct()

        # To make things a little more meaningful in the rest of the code we
        # step through all the gathered data and map it into namedtuples so that
        # we don't need to use data[0][0][1][3] to get the battle.net player id.
        # The field names are documented in the namedtuples section of the
        # objects file. The ordered_values function extracts the values while
        # maintaining key order required for proper mapping
        ordered_values = lambda dict: [v for k, v in sorted(dict.iteritems())]

        # Because named tuples are read only, we need to build them in pieces
        # from the bottom up instead of in place from the top down.
        players = list()
        for pdata in details[0]:
            pdata[1] = BnetData(*ordered_values(pdata[1]))
            pdata[3] = ColorData(*ordered_values(pdata[3]))
            player = self.PlayerData(*ordered_values(pdata))
            players.append(player)
        details[0] = players
        details[10] = [DepotFile(bytes) for bytes in details[10]]
        # As a final touch, label all extracted information using the Details
        # named tuple from objects.py
        return self.Details(*ordered_values(details))
예제 #15
0
    def __call__(self, data, replay):
        data = BitPackedDecoder(data)

        init_data = dict(
            player_init_data=[
                dict(
                    name=data.read_aligned_bytes(data.read_uint8()),
                    clan_tag=data.read_aligned_bytes(data.read_uint8())
                    if data.read_bool() else "",  # 36
                    highest_league=data.read_uint8()
                    if data.read_bool() else None,  #20
                    combined_race_levels=data.read_uint32()
                    if data.read_bool() else None,  #37
                    random_seed=data.read_uint32(),
                    race_preference=data.read_uint8()
                    if data.read_bool() else None,  #38
                    team_preference=data.read_uint8()
                    if data.read_bool() else None,  #39
                    test_map=data.read_bool(),
                    test_auto=data.read_bool(),
                    examine=data.read_bool(),
                    custom_interface=data.read_bool(),
                    observe=data.read_bits(2),
                ) for i in range(data.read_bits(5))
            ],
            game_description=dict(
                random_value=data.read_uint32(),  # 4
                game_cache_name=data.read_aligned_bytes(
                    data.read_bits(10)),  # 24
                game_options=dict(
                    lock_teams=data.read_bool(),  #27
                    teams_together=data.read_bool(),
                    advanced_shared_control=data.read_bool(),
                    random_races=data.read_bool(),
                    battle_net=data.read_bool(),
                    amm=data.read_bool(),
                    competitive=data.read_bool(),
                    no_victory_or_defeat=data.read_bool(),
                    fog=data.read_bits(2),  #19
                    observers=data.read_bits(2),  #19
                    user_difficulty=data.read_bits(2),  #19
                    client_debug_flags=data.read_uint64(),  #15
                ),
                game_speed=data.read_bits(3),
                game_type=data.read_bits(3),
                max_users=data.read_bits(5),
                max_observers=data.read_bits(5),
                max_players=data.read_bits(5),
                max_teams=data.read_bits(4) + 1,
                max_colors=data.read_bits(6),
                max_races=data.read_uint8() + 1,
                max_controls=data.read_uint8() + 1,
                map_size_x=data.read_uint8(),
                map_size_y=data.read_uint8(),
                map_file_sync_checksum=data.read_uint32(),
                map_file_name=data.read_aligned_bytes(data.read_bits(11)),
                map_author_name=data.read_aligned_bytes(data.read_uint8()),
                mod_file_sync_checksum=data.read_uint32(),
                slot_descriptions=[
                    dict(  #50
                        allowed_colors=data.read_bits(data.read_bits(6)),
                        allowed_races=data.read_bits(data.read_uint8()),
                        allowedDifficulty=data.read_bits(data.read_bits(6)),
                        allowedControls=data.read_bits(data.read_uint8()),
                        allowed_observe_types=data.read_bits(
                            data.read_bits(2)),
                        allowed_ai_builds=data.read_bits(data.read_bits(7)),
                    ) for i in range(data.read_bits(5))
                ],
                default_difficulty=data.read_bits(6),
                default_AI_build=data.read_bits(7),
                cache_handles=[
                    DepotFile(data.read_aligned_bytes(40))
                    for i in range(data.read_bits(6))
                ],
                is_blizzardMap=data.read_bool(),
                is_premade_ffa=data.read_bool(),
                is_coop_mode=data.read_bool(),
            ),
            lobby_state=dict(
                phase=data.read_bits(3),
                max_users=data.read_bits(5),
                max_observers=data.read_bits(5),
                slots=[
                    dict(
                        control=data.read_uint8(),
                        user_id=data.read_bits(4)
                        if data.read_bool() else None,
                        team_id=data.read_bits(4),
                        colorPref=data.read_bits(5)
                        if data.read_bool() else None,
                        race_pref=data.read_uint8()
                        if data.read_bool() else None,
                        difficulty=data.read_bits(6),
                        ai_build=data.read_bits(7),
                        handicap=data.read_bits(7),
                        observe=data.read_bits(2),
                        working_set_slot_id=data.read_uint8()
                        if data.read_bool() else None,
                        rewards=[
                            data.read_uint32()
                            for i in range(data.read_bits(6))
                        ],
                        toon_handle=data.read_aligned_bytes(
                            data.read_bits(7)),  # 14
                        licenses=[
                            data.read_uint32()
                            for i in range(data.read_bits(9))
                        ],  # 56
                    ) for i in range(data.read_bits(5))
                ],  # 58
                random_seed=data.read_uint32(),
                host_user_id=data.read_bits(4)
                if data.read_bool() else None,  # 52
                is_single_player=data.read_bool(),  # 27
                game_duration=data.read_uint32(),  # 4
                default_difficulty=data.read_bits(6),  # 1
                default_ai_build=data.read_bits(7),  # 0
            ),
        )

        return init_data
예제 #16
0
    def __call__(self, data, replay):
        data = BitPackedDecoder(data)

        init_data = dict(  #58
            player_init_data=[
                dict(  #38
                    name=data.read_aligned_bytes(data.read_uint8()),
                    clan_tag=None,
                    highest_league=None,
                    combined_race_levels=None,
                    random_seed=data.read_uint32(),
                    race_preference=data.read_uint8()
                    if data.read_bool() else None,  #38
                    team_preference=data.read_uint8()
                    if data.read_bool() else None,  #39
                    test_map=data.read_bool(),
                    test_auto=data.read_bool(),
                    examine=data.read_bool(),
                    custom_interface=None,
                    observe=data.read_bits(2),
                ) for i in range(data.read_bits(5))
            ],
            game_description=dict(  # 48
                random_value=None,
                game_cache_name=None,
                game_options=dict(  #40
                    lock_teams=None,
                    teams_together=None,
                    advanced_shared_control=None,
                    random_races=None,
                    battle_net=None,
                    amm=None,
                    competitive=None,
                    no_victory_or_defeat=None,
                    fog=None,
                    observers=None,
                    user_difficulty=None,
                    client_debug_flags=None,
                ),
                game_speed=None,
                game_type=None,
                max_users=None,
                max_observers=None,
                max_players=None,
                max_teams=None,
                max_colors=None,
                max_races=None,
                max_controls=None,
                map_size_x=None,
                map_size_y=None,
                map_file_sync_checksum=None,
                map_file_name=None,
                map_author_name=None,
                mod_file_sync_checksum=None,
                slot_descriptions=[
                    dict(  #47
                        allowed_colors=None,
                        allowed_races=None,
                        allowedDifficulty=None,
                        allowedControls=None,
                        allowed_observe_types=None,
                        allowed_ai_builds=None,
                    ) for i in range(0)
                ],
                default_difficulty=None,
                default_AI_build=None,
                cache_handles=[],
                is_blizzardMap=None,
                is_premade_ffa=None,
                is_coop_mode=None,
            ),
            lobby_state=dict(  #56
                phase=None,
                max_users=None,
                max_observers=None,
                slots=[
                    dict(  #54
                        control=None,
                        user_id=None,
                        team_id=None,
                        colorPref=None,
                        race_pref=None,
                        difficulty=None,
                        ai_build=None,
                        handicap=None,
                        observe=None,
                        working_set_slot_id=None,
                        rewards=[],
                        toon_handle=None,
                        licenses=[],
                    ) for i in range(0)
                ],  # 58
                random_seed=None,
                host_user_id=None,
                is_single_player=None,
                game_duration=None,
                default_difficulty=None,
                default_ai_build=0,
            ),
        )

        distance = data.read_range(data.tell(), data.length).find('s2ma')
        data.read_aligned_bytes(distance)

        map_data = list()
        while data.peek(4) == 's2ma':
            depot_file = DepotFile(data.read_aligned_bytes(40))
            init_data['game_description']['cache_handles'].append(depot_file)

        init_data.setdefault('game_description',
                             dict())['cache_handles'] = map_data
        return init_data