Exemple #1
0
def get_lobby_chat(header, encoding, diplomacy_type, players):
    """Get lobby chat."""
    chats = []
    for message in header.lobby.messages:
        if not message.message:
            continue
        try:
            chats.append(parse_chat(
                message.message.decode(encoding), 0, players, diplomacy_type, origination='lobby'
            ))
        except UnicodeDecodeError:
            LOGGER.warning('could not decode lobby chat')
    return chats
Exemple #2
0
async def get_extracted_data(  # pylint: disable=too-many-arguments, too-many-locals
        header, encoding, diplomacy_type, players, start_time, duration,
        playback, handle):
    """Get extracted data."""
    timeseries = []
    research = defaultdict(dict)
    market = []
    objects = {}
    state = []
    last = {}
    chats = get_lobby_chat(header, encoding, diplomacy_type, players)
    client = await Client.create(playback, handle.name, start_time, duration)

    async for tick, source, message in client.sync(timeout=120):
        if source == Source.MGZ and message[0] == fast.Operation.CHAT:
            try:
                chats.append(
                    parse_chat(message[1].decode(encoding), tick, players,
                               diplomacy_type))
            except UnicodeDecodeError:
                LOGGER.warning('could not decode chat')

        elif source == Source.MEMORY:
            update_market(tick, message.MarketCoefficients(), market)

            for i in range(0, message.ObjectsLength()):
                update_objects(tick, message.Objects(i), objects, state, last)

            for i in range(0, message.PlayersLength()):
                player = message.Players(i)
                timeseries.append(build_timeseries_record(tick, player))
                for j in range(0, player.TechsLength()):
                    update_research(player.Id(), player.Techs(j), research)

    handle.close()

    return {
        'chat': chats,
        'timeseries': timeseries,
        'research': flatten_research(research),
        'market': market,
        'objects': [dict(obj, instance_id=i) for i, obj in objects.items()],
        'state': state
    }
Exemple #3
0
 def _process_body(self):  # pylint: disable=too-many-locals, too-many-statements, too-many-branches
     """Process rec body."""
     start_time = time.time()
     ratings = {}
     checksums = []
     ladder = None
     voobly = False
     rated = None
     i = 0
     duration = self._header.initial.restore_time
     fast.meta(self._handle)
     self._actions = []
     while True:
         try:
             operation, payload = fast.operation(self._handle)
             if operation == fast.Operation.SYNC:
                 i += 1
                 duration += payload[0]
                 if payload[1] and len(checksums) < CHECKSUMS:
                     checksums.append(payload[1].to_bytes(8,
                                                          'big',
                                                          signed=True))
             elif operation == fast.Operation.ACTION:
                 self._actions.append((duration, *payload))
                 if payload[0] == fast.Action.POSTGAME:
                     self._cache[
                         'postgame'] = mgz.body.actions.postgame.parse(
                             payload[1]['bytes'])
                 elif payload[0] == fast.Action.RESIGN:
                     self._cache['resigned'].add(payload[1]['player_id'])
                 elif payload[0] == fast.Action.TRIBUTE and payload[1][
                         'player_id_to'] == 0:
                     self._cache['cheaters'].add(payload[1]['player_id'])
                 elif payload[0] == fast.Action.TRIBUTE and payload[1][
                         'player_id'] == 0:
                     self._cache['cheaters'].add(payload[1]['player_id_to'])
                 elif payload[0] == fast.Action.CREATE:
                     self._cache['cheaters'].add(payload[1]['player_id'])
                 elif payload[0] == fast.Action.BUILD and payload[1][
                         'building_id'] not in VALID_BUILDINGS:
                     self._cache['cheaters'].add(payload[1]['player_id'])
                 elif payload[0] == fast.Action.GAME and payload[1][
                         'mode_id'] in [2, 4, 6]:
                     self._cache['cheaters'].add(payload[1]['player_id'])
             elif operation == fast.Operation.CHAT:
                 text = payload
                 if text is None:
                     continue
                 try:
                     parsed = parse_chat(text, self.get_encoding(),
                                         duration, self.get_players(),
                                         self.get_diplomacy().get('type'))
                     self._chats.append(parsed)
                     if parsed['type'] == Chat.RATING:
                         ratings[parsed['player']] = parsed['rating']
                     elif parsed['type'] == Chat.LADDER:
                         ladder = parsed['ladder']
                     elif parsed['type'] == Chat.VOOBLY:
                         voobly = True
                 except UnicodeDecodeError:
                     pass
         except EOFError:
             break
     self._cache['duration'] = duration
     if voobly:
         rated = len(ratings) > 0 and set(ratings.values()) != {1600}
     if self._header.version == Version.DE:
         self._cache['hash'] = hashlib.sha1(self._header.de.guid)
     else:
         self._cache['hash'] = hashlib.sha1(b''.join(checksums)) \
             if len(checksums) == CHECKSUMS else None
     self._cache['from_voobly'] = voobly
     if voobly:
         self._cache['platform_id'] = 'voobly'
     if self._header.version == Version.DE and self._header.de.multiplayer:
         self._cache['platform_id'] = 'de'
     self._cache['ladder'] = ladder
     self._cache['rated'] = rated
     self._cache['ratings'] = ratings if rated else {}
     LOGGER.info("parsed body in %.2f seconds", time.time() - start_time)
Exemple #4
0
def parse_match(handle):
    """Parse a match.

    This is one big function because the dependency graph between
    the variables is dense.
    """

    data = parse(handle)
    consts = get_consts()

    dataset_id, dataset = get_dataset(data['version'], data['mod'])
    # self._header.hd.selected_map_id if self._header.hd else self._header.scenario.game_settings.map_id
    map_data, encoding, language = get_map_data(
        data['hd']['map_id']
        if data['version'] is Version.HD else data['scenario']['map_id'],
        data['scenario']['instructions'],
        data['map']['dimension'],
        data['version'],
        dataset_id,
        dataset,
        data['map']['tiles'],
        de_seed=data['lobby']['seed'])

    # Handle DE-specific data
    if data['de']:
        de_players = {
            player['number']: player
            for player in data['de']['players']
        }
        lobby = data['de']['lobby']
        guid = data['de']['guid']
    else:
        de_players = dict()
        lobby = None
        guid = None

    # Parse gaia objects
    gaia = [
        Object(dataset['objects'].get(str(obj['object_id'])),
               obj['instance_id'],
               Position(obj['position']['x'], obj['position']['y']))
        for obj in data['players'][0]['objects']
    ]

    inputs = Inputs({o.instance_id: o.name for o in gaia})

    # Parse players
    players = dict()
    allies = dict()
    for player in data['players'][1:]:
        allies[player['number']] = set([player['number']])
        for i, stance in enumerate(player['diplomacy']):
            if stance == 2:
                allies[player['number']].add(i)
        de_player = de_players.get(player['number'])
        if de_player:
            player.update(de_player)
        pos_x = None
        pos_y = None
        for obj in player['objects']:
            if obj['object_id'] in TC_IDS:
                pos_x = obj['position']['x']
                pos_y = obj['position']['y']
        players[player['number']] = Player(
            player['color_id'] + 1, player['name'].decode(encoding),
            consts['player_colors'][str(player['color_id'])],
            dataset['civilizations'][str(player['civilization_id'])]['name'],
            Position(pos_x, pos_y), [
                Object(dataset['objects'].get(str(obj['object_id'])),
                       obj['instance_id'],
                       Position(obj['position']['x'], obj['position']['y']))
                for obj in player['objects']
            ], player.get('profile_id'))

    # Assign teams
    team_ids = set([frozenset(s) for s in allies.values()])
    teams = []
    for team in team_ids:
        t = [players[x] for x in team]
        for x in team:
            players[x].team = t
        teams.append(t)

    # Compute diplomacy
    diplomacy_type = get_diplomacy_type(teams, players)

    # Extract lobby chat
    pd = [dict(name=p.name, number=n) for n, p in players.items()]
    chats = []
    for c in data['lobby']['chat']:
        chat = parse_chat(c, encoding, 0, pd, diplomacy_type, 'lobby')
        if chat['player_number'] not in players:
            continue
        chats.append(
            Chat(timedelta(milliseconds=chat['timestamp']), chat['message'],
                 players[chat['player_number']]))
        inputs.add_chat(chats[-1])

    # Parse player actions
    fast.meta(handle)
    timestamp = 0
    resigned = []
    actions = []
    viewlocks = []
    last_viewlock = None
    while True:
        try:
            op_type, op_data = fast.operation(handle)
            if op_type is fast.Operation.SYNC:
                timestamp += op_data[0]
            elif op_type is fast.Operation.VIEWLOCK:
                if op_data == last_viewlock:
                    continue
                viewlock = Viewlock(timedelta(milliseconds=timestamp),
                                    Position(*op_data),
                                    players[data['metadata']['owner_id']])
                viewlocks.append(viewlock)
                last_viewlock = op_data
            elif op_type is fast.Operation.CHAT:
                chat = parse_chat(op_data, encoding, timestamp, pd,
                                  diplomacy_type, 'game')
                if chat['type'] == ChatEnum.MESSAGE:
                    chats.append(
                        Chat(timedelta(milliseconds=chat['timestamp']),
                             chat['message'], players[chat['player_number']]))
                    inputs.add_chat(chats[-1])
            elif op_type is fast.Operation.ACTION:
                action_type, action_data = op_data
                action = Action(timedelta(milliseconds=timestamp), action_type,
                                action_data)
                if action_type is fast.Action.RESIGN:
                    resigned.append(players[action_data['player_id']])
                if 'player_id' in action_data:
                    action.player = players[action_data['player_id']]
                    del action.payload['player_id']
                enrich_action(action, action_data, dataset, consts)
                actions.append(action)
                inputs.add_action(action)
        except EOFError:
            break

    # Compute winner(s)
    for team in teams:
        winner = not any([player for player in team if player in resigned])
        for player in team:
            player.winner = winner

    return Match(
        list(players.values()), teams, gaia,
        Map(map_data['name'], map_data['dimension'],
            consts['map_sizes'][str(map_data['dimension'])],
            map_data['custom'], map_data['seed'], [
                Tile(tile['terrain_id'], tile['elevation'],
                     Position(tile['x'], tile['y']))
                for tile in map_data['tiles']
            ]),
        File(codecs.lookup(encoding), language,
             players[data['metadata']['owner_id']], viewlocks),
        consts['speeds'][str(int(round(data['metadata']['speed'], 2) * 100))],
        data['metadata']['cheats'], data['lobby']['lock_teams'],
        data['lobby']['population'], chats, guid, lobby,
        dataset['dataset']['name'],
        consts['game_types'][str(data['lobby']['game_type_id'])],
        consts['map_reveal_choices'][str(data['lobby']['reveal_map_id'])],
        timedelta(milliseconds=timestamp), diplomacy_type, data['version'],
        actions, inputs.inputs)