Exemple #1
0
def get_dataset_data(header):
    """Get dataset."""
    sample = header.initial.players[0].attributes.player_stats
    mod = None
    if 'mod' in sample:
        mod = (sample.mod.get('id'), sample.mod.get('version'))
    _, ref = get_dataset(header.version, mod)
    if header.version == Version.DE:
        return {
            'id': 100,
            'name': 'Definitive Edition',
            'version': None
        }, ref
    elif header.version == Version.HD:
        return {
            'id': 300,
            'name': 'HD Edition',
            'version': resolve_hd_version(header.hd, header.save_version)
        }, ref
    if 'mod' in sample and sample.mod['id'] == 0 and sample.mod['version'] == '2':
        raise ValueError("invalid mod version")
    if 'mod' in sample and sample.mod['id'] > 0:
        return sample.mod, ref
    if 'trickle_food' in sample and sample.trickle_food:
        return {
            'id': 1,
            'name': mgz.const.MODS.get(1),
            'version': '<5.7.2'
        }, ref
    if header.version == Version.AOK:
        return {
            'id': 200,
            'name': 'Age of Kings',
            'version': '2.0a'
        }, ref
    if header.version == Version.AOC10:
        return {
            'id': 0,
            'name': 'The Conquerors',
            'version': '1.0'
        }, ref
    return {
        'id': 0,
        'name': 'The Conquerors',
        'version': '1.0c'
    }, ref
Exemple #2
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)
    body_pos = handle.tell() - 4  # log version
    consts = get_consts()

    dataset_id, dataset = get_dataset(data['version'], data['mod'])
    map_id = data['hd']['map_id'] if data['version'] is Version.HD else data[
        'scenario']['map_id']
    try:
        map_data, encoding, language = get_map_data(
            map_id,
            data['scenario']['instructions'],
            data['map']['dimension'],
            data['version'],
            dataset_id,
            dataset,
            data['map']['tiles'],
            de_seed=data['lobby']['seed'])
    except ValueError:
        raise RuntimeError("could not get map data")

    # 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['class_id'],
               obj['object_id'], obj['instance_id'], obj['index'],
               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['number'], player['name'].decode(encoding),
            consts['player_colors'][str(player['color_id'])],
            player['color_id'],
            dataset['civilizations'][str(player['civilization_id'])]['name'],
            player['civilization_id'], Position(pos_x, pos_y), [
                Object(dataset['objects'].get(str(
                    obj['object_id'])), obj['class_id'], obj['object_id'],
                       obj['instance_id'], obj['index'],
                       Position(obj['position']['x'], obj['position']['y']))
                for obj in player['objects']
            ], player.get('profile_id'), player.get('prefer_random'))

    # Assign teams
    if de_players:
        by_team = collections.defaultdict(list)
        for number, player in de_players.items():
            if player['team_id'] > 1:
                by_team[player['team_id']].append(number)
            elif player['team_id'] == 1:
                by_team[number + 9].append(number)
        team_ids = by_team.values()
    else:
        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['type'] == ChatEnum.DISCARD or chat[
                'player_number'] not in players:
            continue
        chats.append(
            Chat(timedelta(milliseconds=chat['timestamp']), chat['message'],
                 chat['origination'], chat['audience'],
                 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'] +
                                      data['map']['restore_time']),
                            chat['message'], chat['origination'],
                            chat['audience'], 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 and action_data[
                        'player_id'] in players:
                    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])
        if resigned:
            for player in team:
                player.winner = winner

    handle.seek(body_pos)
    file_bytes = handle.read()
    file_size = body_pos + 4 + len(file_bytes)
    file_hash = hashlib.sha1(file_bytes).hexdigest()
    return Match(
        list(players.values()), teams, gaia,
        Map(
            map_id, map_data['name'], map_data['dimension'],
            consts['map_sizes'][str(map_data['dimension'])],
            map_data['custom'], map_data['seed'], data['de']['rms_mod_id']
            if data['version'] is Version.DE else None,
            map_data['name'].startswith('ZR@'), map_data['modes'], [
                Tile(tile['terrain_id'], tile['elevation'],
                     Position(tile['x'], tile['y']))
                for tile in map_data['tiles']
            ]),
        File(codecs.lookup(encoding), language, file_hash, file_size,
             players[data['metadata']['owner_id']],
             viewlocks), data['map']['restore_time'] > 0,
        timedelta(milliseconds=data['map']['restore_time']),
        consts['speeds'][str(int(round(data['metadata']['speed'], 2) * 100))],
        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'])], data['lobby']['game_type_id'],
        consts['map_reveal_choices'][str(data['lobby']['reveal_map_id'])],
        data['lobby']['reveal_map_id'],
        consts['difficulties'].get(str(get_difficulty(data))),
        get_difficulty(data),
        consts['starting_ages'].get(str(get_starting_age(data))),
        get_starting_age(data), get_team_together(data), get_lock_speed(data),
        get_all_technologies(data),
        True if data['version'] is Version.DE else None,
        timedelta(milliseconds=timestamp + data['map']['restore_time']),
        diplomacy_type, bool(resigned), data['version'], data['game_version'],
        data['save_version'], data['log_version'],
        data['de']['build'] if data['version'] is Version.DE else None,
        datetime.fromtimestamp(data['de']['timestamp'])
        if data['version'] is Version.DE and data['de']['timestamp'] else None,
        timedelta(seconds=data['de']['spec_delay'])
        if data['version'] is Version.DE else None,
        data['de']['allow_specs'] if data['version'] is Version.DE else None,
        data['de']['hidden_civs'] if data['version'] is Version.DE else None,
        data['de']['visibility_id'] == 2 if data['version'] is Version.DE else
        None, get_hash(data), actions, inputs.inputs)
Exemple #3
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)