Ejemplo n.º 1
0
    def handleInitGame(self, event, replay):
        # without tracker events game heart games can't be fixed
        if len(replay.tracker_events) == 0:
            yield PluginExit(self, code=0, details=dict())
            return

        start_frame = -1
        actual_players = {}
        for event in replay.tracker_events:
            if start_frame != -1 and event.frame > start_frame + 5:  # fuzz it a little
                break
            if event.name == 'UnitBornEvent' and event.control_pid and event.unit_type_name in self.PRIMARY_BUILDINGS:
                # In normal replays, starting units are born on frame zero.
                if event.frame == 0:
                    yield PluginExit(self, code=0, details=dict())
                    return
                else:
                    start_frame = event.frame
                    actual_players[event.control_pid] = self.PRIMARY_BUILDINGS[
                        event.unit_type_name]

        self.fix_entities(replay, actual_players)
        self.fix_events(replay, start_frame)

        replay.frames -= start_frame
        replay.game_length = Length(seconds=replay.frames / 16)
        replay.real_type = get_real_type(replay.teams)
        replay.real_length = Length(
            seconds=int(replay.game_length.seconds /
                        GAME_SPEED_FACTOR[replay.speed]))
        replay.start_time = datetime.utcfromtimestamp(
            replay.unix_timestamp - replay.real_length.seconds)
Ejemplo n.º 2
0
    def handleInitGame(self, event, replay):
        # without tracker events game heart games can't be fixed
        if len(replay.tracker_events) == 0:
            yield PluginExit(self, code=0, details=dict())
            return

        start_frame = -1
        actual_players = {}
        for event in replay.tracker_events:
            if start_frame != -1 and event.frame > start_frame + 5:  # fuzz it a little
                break
            if event.name == 'UnitBornEvent' and event.control_pid and event.unit_type_name in self.PRIMARY_BUILDINGS:
                # In normal replays, starting units are born on frame zero.
                if event.frame == 0:
                    yield PluginExit(self, code=0, details=dict())
                    return
                else:
                    start_frame = event.frame
                    actual_players[event.control_pid] = self.PRIMARY_BUILDINGS[event.unit_type_name]

        self.fix_entities(replay, actual_players)
        self.fix_events(replay, start_frame)

        replay.frames -= start_frame
        replay.game_length = Length(seconds=replay.frames / 16)
        replay.real_type = get_real_type(replay.teams)
        replay.real_length = Length(seconds=int(replay.game_length.seconds/GAME_SPEED_FACTOR[replay.speed]))
        replay.start_time = datetime.utcfromtimestamp(replay.unix_timestamp-replay.real_length.seconds)
Ejemplo n.º 3
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]
        ]
Ejemplo n.º 4
0
    def load_players(self):
        #If we don't at least have details and attributes_events we can go no further
        if 'replay.details' not in self.raw_data:
            return
        if 'replay.attributes.events' not in self.raw_data:
            return
        if 'replay.initData' not in self.raw_data:
            return

        self.clients = list()
        self.client = dict()

        # For players, we can use the details file to look up additional
        # information. detail_id marks the current index into this data.
        detail_id = 0
        player_id = 1
        details = self.raw_data['replay.details']
        initData = self.raw_data['replay.initData']

        # Assume that the first X map slots starting at 1 are player slots
        # so that we can assign player ids without the map
        self.entities = list()
        for slot_id, slot_data in enumerate(initData['lobby_state']['slots']):
            user_id = slot_data['user_id']

            if slot_data['control'] == 2:
                if slot_data['observe'] == 0:
                    self.entities.append(
                        Participant(slot_id, slot_data, user_id,
                                    initData['user_initial_data'][user_id],
                                    player_id, details['players'][detail_id],
                                    self.attributes.get(player_id, dict())))
                    detail_id += 1
                    player_id += 1

                else:
                    self.entities.append(
                        Observer(slot_id, slot_data, user_id,
                                 initData['user_initial_data'][user_id],
                                 player_id))
                    player_id += 1

            elif slot_data['control'] == 3:
                self.entities.append(
                    Computer(slot_id, slot_data, player_id,
                             details['players'][detail_id],
                             self.attributes.get(player_id, dict())))
                detail_id += 1
                player_id += 1

        def get_team(team_id):
            if team_id is not None and team_id not in self.team:
                team = Team(team_id)
                self.team[team_id] = team
                self.teams.append(team)
            return self.team[team_id]

        # Set up all our cross reference data structures
        for entity in self.entities:
            if entity.is_observer is False:
                entity.team = get_team(entity.team_id)
                entity.team.players.append(entity)
                self.players.append(entity)
                self.player[entity.pid] = entity
            else:
                self.observers.append(entity)
                self.observer[entity.uid] = entity

            if entity.is_human:
                self.humans.append(entity)
                self.human[entity.uid] = entity
            else:
                self.computers.append(entity)
                self.computer[entity.pid] = entity

            # Index by pid so that we can match events to players in pre-HotS replays
            self.entity[entity.pid] = entity

        # Pull results up for teams
        for team in self.teams:
            results = set([p.result for p in team.players])
            if len(results) == 1:
                team.result = list(results)[0]
                if team.result == 'Win':
                    self.winner = team
            else:
                self.logger.warn(
                    "Conflicting results for Team {0}: {1}".format(
                        team.number, results))
                team.result = 'Unknown'

        self.teams.sort(key=lambda t: t.number)

        # These are all deprecated
        self.clients = self.humans
        self.people = self.entities
        self.client = self.human
        self.person = self.entity

        self.real_type = utils.get_real_type(self.teams)

        # Assign the default region to computer players for consistency
        # We know there will be a default region because there must be
        # at least 1 human player or we wouldn't have a replay.
        default_region = self.humans[0].region
        for entity in self.entities:
            if not entity.region:
                entity.region = default_region

        # Pretty sure this just never worked, forget about it for now
        self.recorder = None

        entity_names = sorted(map(lambda p: p.name, self.entities))
        hash_input = self.gateway + ":" + ','.join(entity_names)
        self.people_hash = hashlib.sha256(
            hash_input.encode('utf8')).hexdigest()

        # The presence of observers and/or computer players makes this not actually ladder
        # This became an issue in HotS where Training, vs AI, Unranked, and Ranked
        # were all marked with "amm" => Ladder
        if len(self.observers) > 0 or len(self.humans) != len(self.players):
            self.is_ladder = False
Ejemplo n.º 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]]
Ejemplo n.º 6
0
    def load_players(self):
        # If we don't at least have details and attributes_events we can go no further
        if 'replay.details' not in self.raw_data:
            return
        if 'replay.attributes.events' not in self.raw_data:
            return
        if 'replay.initData' not in self.raw_data:
            return

        self.clients = list()
        self.client = dict()

        # For players, we can use the details file to look up additional
        # information. detail_id marks the current index into this data.
        detail_id = 0
        player_id = 1
        details = self.raw_data['replay.details']
        initData = self.raw_data['replay.initData']

        # Assume that the first X map slots starting at 1 are player slots
        # so that we can assign player ids without the map
        self.entities = list()
        for slot_id, slot_data in enumerate(initData['lobby_state']['slots']):
            user_id = slot_data['user_id']

            if slot_data['control'] == 2:
                if slot_data['observe'] == 0:
                    self.entities.append(Participant(slot_id, slot_data, user_id, initData['user_initial_data'][user_id], player_id, details['players'][detail_id], self.attributes.get(player_id, dict())))
                    detail_id += 1
                    player_id += 1

                else:
                    self.entities.append(Observer(slot_id, slot_data, user_id, initData['user_initial_data'][user_id], player_id))
                    player_id += 1

            elif slot_data['control'] == 3:
                self.entities.append(Computer(slot_id, slot_data, player_id, details['players'][detail_id], self.attributes.get(player_id, dict())))
                detail_id += 1
                player_id += 1

        def get_team(team_id):
            if team_id is not None and team_id not in self.team:
                    team = Team(team_id)
                    self.team[team_id] = team
                    self.teams.append(team)
            return self.team[team_id]

        # Set up all our cross reference data structures
        for entity in self.entities:
            if entity.is_observer is False:
                entity.team = get_team(entity.team_id)
                entity.team.players.append(entity)
                self.players.append(entity)
                self.player[entity.pid] = entity
            else:
                self.observers.append(entity)
                self.observer[entity.uid] = entity

            if entity.is_human:
                self.humans.append(entity)
                self.human[entity.uid] = entity
            else:
                self.computers.append(entity)
                self.computer[entity.pid] = entity

            # Index by pid so that we can match events to players in pre-HotS replays
            self.entity[entity.pid] = entity

        # Pull results up for teams
        for team in self.teams:
            results = set([p.result for p in team.players])
            if len(results) == 1:
                team.result = list(results)[0]
                if team.result == 'Win':
                    self.winner = team
            else:
                self.logger.warn("Conflicting results for Team {0}: {1}".format(team.number, results))
                team.result = 'Unknown'

        self.teams.sort(key=lambda t: t.number)

        # These are all deprecated
        self.clients = self.humans
        self.people = self.entities
        self.client = self.human
        self.person = self.entity

        self.real_type = utils.get_real_type(self.teams)

        # Assign the default region to computer players for consistency
        # We know there will be a default region because there must be
        # at least 1 human player or we wouldn't have a replay.
        default_region = self.humans[0].region
        for entity in self.entities:
            if not entity.region:
                entity.region = default_region

        # Pretty sure this just never worked, forget about it for now
        self.recorder = None

        entity_names = sorted(map(lambda p: p.name, self.entities))
        hash_input = self.region+":"+','.join(entity_names)
        self.people_hash = hashlib.sha256(hash_input.encode('utf8')).hexdigest()

        # The presence of observers and/or computer players makes this not actually ladder
        # This became an issue in HotS where Training, vs AI, Unranked, and Ranked
        # were all marked with "amm" => Ladder
        if len(self.observers) > 0 or len(self.humans) != len(self.players):
            self.is_ladder = False