Beispiel #1
0
    def __init__(self, os, linux_log=board_state):
        self.os = os
        parser = LogParser()

        if self.os == "Windows":
            log_dir = r"C:\Program Files (x86)\Hearthstone\Logs\Power.log"
            with io.open(log_dir, "r", encoding='utf8') as logs:
                k = 0
                lines = logs.readlines()
                for line in lines:
                    k += 1
                    if "GameState.DebugPrintPower() - CREATE_GAME" in line:
                        start = k
                parsed_lines = lines[start-1:]
                self.logs = ''.join(parsed_lines)
            parser.read(io.StringIO(self.logs))
        elif self.os == "Linux":
            parser.read(io.StringIO(linux_log))
            self.linux_log = linux_log
        parser.flush()

        packet_tree = parser.games[-1]
        while True:
            try:
                self.game = EntityTreeExporter(packet_tree).export().game
            except:
                print("Trapped")
                continue
            else:
                break
        self.player_names = ['Strafos', 'strafos']
        self.card_data = self.get_card_data()
        self.friendly_player, self.enemy_player = self.read_players()
Beispiel #2
0
    def update_state(self, hp=1):
        parser = LogParser()
        if self.os == "Windows":
            log_dir = r"C:\Program Files (x86)\Hearthstone\Logs\Power.log"
            with io.open(log_dir, "r", encoding='utf8') as logs:
                lines = logs.readlines()
                self.logs = ''.join(lines)
            parser.read(io.StringIO(self.logs))
        elif self.os == "Linux":
            parser.read(io.StringIO(self.linux_log))
        parser.flush()

        packet_tree = parser.games[-1]
        while True:
            try:
                self.game = EntityTreeExporter(packet_tree).export().game
            except:
                print("Trapped")
                continue
            else:
                break

        packet_tree = parser.games[-1]
        self.friendly_player, self.enemy_player = self.read_players()

        turn = self.get_current_player().name in self.player_names
        board = self.get_current_board()
        hand = self.get_current_hand(hp, board)
        game_step = self.get_game_step()
        mana = self.get_current_mana()
        return hand, turn, board, game_step, mana
Beispiel #3
0
def test_shuffle_deck(parser):
    with open(logfile("54613_shuffle_deck.power.log")) as f:
        parser.read(f)

    packet_tree = parser.games[0]
    exporter = EntityTreeExporter(packet_tree)
    exporter.export()
    assert True
Beispiel #4
0
def test_bad_ids(parser):
    with open(logfile("chaos/change_entity_null_id.power.log")) as f:
        parser.read(f)

    packet_tree = parser.games[0]
    exporter = EntityTreeExporter(packet_tree)
    with pytest.raises(ExporterError):
        exporter.export()
Beispiel #5
0
def test_game_reset(parser):
    with open(logfile("toki.power.log")) as f:
        parser.read(f)

    packet_tree = parser.games[0]
    exporter = EntityTreeExporter(packet_tree)
    exporter.export()
    assert True
Beispiel #6
0
def test_cached_tag_for_dormant_change(parser):
    with open(logfile("49534_cached_tag_for_dormant_change.power.log")) as f:
        parser.read(f)

    packet_tree = parser.games[0]
    exporter = EntityTreeExporter(packet_tree)
    exporter.export()
    assert True
Beispiel #7
0
def test_vo_spell(parser):
    with open(logfile("49534_vo_spell.power.log")) as f:
        parser.read(f)

    packet_tree = parser.games[0]
    exporter = EntityTreeExporter(packet_tree)
    exporter.export()
    assert True
Beispiel #8
0
def test_inferrable_player(parser):
    with open(logfile("25770_inferrable_player.power.log")) as f:
        parser.read(f)

    packet_tree = parser.games[0]
    exporter = EntityTreeExporter(packet_tree)
    exporter.export()
    assert True
Beispiel #9
0
def test_full_entity_defined_in_subspell(parser):
    with open(logfile("34104_subspell.power.log")) as f:
        parser.read(f)

    packet_tree = parser.games[0]
    exporter = EntityTreeExporter(packet_tree)
    exporter.export()
    assert True
Beispiel #10
0
def test_puzzle_lab(parser):
    with open(logfile("puzzlelab.power.log")) as f:
        parser.read(f)

    packet_tree = parser.games[0]
    exporter = EntityTreeExporter(packet_tree)
    exporter.export()
    assert True
Beispiel #11
0
def test_puzzle_lab_player(parser: LogParser):
    with open(logfile("puzzle_player.power.log")) as f:
        parser.read(f)

    packet_tree = parser.games[0]
    exporter = EntityTreeExporter(packet_tree,
                                  player_manager=parser.player_manager)
    exporter.export()
    assert True
Beispiel #12
0
def test_mercenaries_solo_pvp(parser: LogParser):
    with open(logfile("93227_mercenaries_solo_pvp.power.log")) as f:
        parser.read(f)

    packet_tree = parser.games[0]
    exporter = EntityTreeExporter(packet_tree,
                                  player_manager=parser.player_manager)
    exporter.export()
    assert True
Beispiel #13
0
def test_name_aliasing(parser: LogParser):
    with open(logfile("88998_missing_player_hash.power.log")) as f:
        parser.read(f)

    packet_tree = parser.games[0]
    exporter = EntityTreeExporter(packet_tree,
                                  player_manager=parser.player_manager)
    exporter.export()
    assert True
Beispiel #14
0
def test_async_player_names(parser: LogParser):
    with open(logfile("88998_async_player_name.power.log")) as f:
        parser.read(f)

    packet_tree = parser.games[0]
    exporter = EntityTreeExporter(packet_tree,
                                  player_manager=parser.player_manager)

    with pytest.raises(MissingPlayerData):
        exporter.export()
Beispiel #15
0
def test_20457(parser):
    with open(logfile("20457_broken_names.power.log")) as f:
        parser.read(f)

    assert len(parser.games) == 1
    packet_tree = parser.games[0]
    exporter = EntityTreeExporter(packet_tree)
    game = exporter.export()
    assert game.game.players[0].name == "Necroessenza"
    assert game.game.players[1].name == "Heigan l'Impuro"
Beispiel #16
0
def test_unknown_human_player(parser: LogParser):
    with open(logfile("25770_unknown_human_player.power.log")) as f:
        parser.read(f)

    packet_tree = parser.games[0]
    exporter = EntityTreeExporter(packet_tree,
                                  player_manager=parser.player_manager)

    with pytest.raises(MissingPlayerData):
        exporter.export()
Beispiel #17
0
def test_battlegrounds(parser):
    with open(logfile("36393_battlegrounds.power.log")) as f:
        parser.read(f)

    assert len(parser.games) == 1
    packet_tree = parser.games[0]
    exporter = EntityTreeExporter(packet_tree)
    game = exporter.export()
    assert game.game.setup_done
    assert game.game.players[0].name == "BehEh#1355"
    assert len([
        packet for packet in packet_tree if isinstance(packet, packets.Options)
    ]) == 96
Beispiel #18
0
 def __init__(self, filepath="Power.log"):
     self.parser: LogParser = LogParser()
     with open(filepath) as f:
         self.parser.read(f)
     self.packet_tree: PacketTree = self.parser.games[0]
     self.exporter: EntityTreeExporter = EntityTreeExporter(
         self.packet_tree)
     self.export: EntityTreeExporter = self.exporter.export()
Beispiel #19
0
def print_board_at_combat(k):
    pt = copy.copy(packet_tree)
    pt.packets = []
    current_fight = 0
    for i, packet in enumerate(packet_tree.packets):
        if is_starting_block(packet):
            current_fight += 1
            if current_fight == k:
                n = 10
                if i+n < len(packet_tree.packets):
                    pt.packets = packet_tree.packets[:i+n]
                    break
    exporter = EntityTreeExporter(pt)
    export = exporter.export()
    if hasattr(export, "game"):
        game = export.game
        breeky = game.players[0]
        bob = game.players[1]
        bob.minions = get_current_minions(bob)
        breeky.minions = get_current_minions(breeky)
        print("Bob : ", bob.minions)
        print("Breeky : ", breeky.minions)
        print(breeky.minions[0].tags[GameTag.HEALTH])
Beispiel #20
0
from hslog.export import FriendlyPlayerExporter, EntityTreeExporter
from hearthstone.enums import (
    CardType, ChoiceType, GameTag, OptionType, BlockType,
    PlayReq, PlayState, PowerType, State, Step, Zone
)

# logging.getLogger().setLevel(logging.CRITICAL)

start = time.time()
parser = LogParser()
with open("Power.log") as f:
    parser.read(f)

packet_tree = parser.games[0]
print("Reading packets took ", time.time()-start, "s.")
exporter = EntityTreeExporter(packet_tree)
export = exporter.export()
game = export.game
breeky = game.players[0]
bob = game.players[1]
print("Export took ", time.time()-start, "s.")


def get_current_minions(player):
    minions = []
    for e in player.entities:
        if e.tags[GameTag.CONTROLLER] == player.tags[GameTag.CONTROLLER] and e.zone == Zone.PLAY:
            if GameTag.CARDTYPE in e.tags.keys() and e.tags[GameTag.CARDTYPE] == CardType.MINION:
                minions.append(e)
    return minions
Beispiel #21
0
class GameReader:
    def __init__(self, os, linux_log=board_state):
        self.os = os
        parser = LogParser()

        if self.os == "Windows":
            log_dir = r"C:\Program Files (x86)\Hearthstone\Logs\Power.log"
            with io.open(log_dir, "r", encoding='utf8') as logs:
                k = 0
                lines = logs.readlines()
                for line in lines:
                    k += 1
                    if "GameState.DebugPrintPower() - CREATE_GAME" in line:
                        start = k
                parsed_lines = lines[start-1:]
                self.logs = ''.join(parsed_lines)
            parser.read(io.StringIO(self.logs))
        elif self.os == "Linux":
            parser.read(io.StringIO(linux_log))
            self.linux_log = linux_log
        parser.flush()

        packet_tree = parser.games[-1]
        while True:
            try:
                self.game = EntityTreeExporter(packet_tree).export().game
            except:
                print("Trapped")
                continue
            else:
                break
        self.player_names = ['Strafos', 'strafos']
        self.card_data = self.get_card_data()
        self.friendly_player, self.enemy_player = self.read_players()

    ## Read card.json for Hearthstone card data
    def get_card_data(self):
        if self.os == "Windows":
            json_dir = r"C:\Users\Zaibo\Desktop\playground\sai\plugins\SerpentHearthstoneGameAgentPlugin\files\cards.json"
        elif self.os == "Linux":
            json_dir = "/home/zaibo/code/Hearthstone-Quest-Bot/plugins/SerpentHearthstoneGameAgentPlugin/files/cards.json"
        else:
            raise Exception("Invalid OS")
        with io.open(json_dir, 'r', encoding='utf8') as json_file:
            json_str = json_file.read()
        return json.loads(json_str)

    ## Access json for card data given card_id
    def get_card_info(self, card_id):
        for card in self.card_data:
            if card['id'] == card_id:
                return card

    def get_current_player(self):
        return self.game.current_player

    def get_game(self):
        return self.game

    def get_game_step(self):
        return self.game.tags.get(GameTag.STEP, 0)

    # Return Hand of BaseCard objects sorted by increasing cost
    def get_current_hand(self, hp, board):
        hand = entities.Hand()
        for card_in_hand in self.game.in_zone(3):
            id = card_in_hand.card_id
            if id:
                card_info = self.get_card_info(id)
                card_type = card_info['type']
                tags = card_in_hand.tags
                if card_type == "MINION":
                    minion = entities.HandMinion(
                        card_info['name'], 
                        id, 
                        tags.get(GameTag.COST, 0), 
                        tags.get(GameTag.ZONE_POSITION, 0), 
                        card_info['attack'], 
                        card_info['health'], 
                        card_info.get('mechanics', None))
                    hand.add_card(minion)
                elif card_type == "SPELL":
                    spell = entities.HandSpell(
                        card_info['name'], 
                        id, 
                        tags.get(GameTag.COST, 0), 
                        tags.get(GameTag.ZONE_POSITION, 0),
                        card_info.get('playRequirements', None))
                    hand.add_card(spell)
                elif card_type == "WEAPON":
                    weapon = entities.HandWeapon(
                        card_info['name'], 
                        id, 
                        tags.get(GameTag.COST, 0), 
                        tags.get(GameTag.ZONE_POSITION, 0), 
                        card_info['attack'], 
                        card_info['durability'])
                    hand.add_card(weapon)
        if hp and board.enemy:
            hero_power = entities.HeroPower('Hero Power', 2, -2, 'Hunter', board.enemy.health)
            hand.add_card(hero_power)
        hand.sort_by_cost()
        return hand
    
    ## Create board object
    def get_current_board(self):
        minions = []
        weapons = []
        heroes = []
        for board_card in self.game.in_zone(1):
            if type(board_card) == Card:
                id = board_card.card_id
                if id:
                    card_info = self.get_card_info(id)
                    card_type = card_info['type']
                    if card_info and card_type != "HERO_POWER":
                        tags = board_card.tags
                        if card_type == 'WEAPON':
                            weapon = entities.BoardWeapon(
                                card_info['name'], 
                                id, 
                                tags.get(GameTag.ZONE_POSITION, 0), 
                                board_card.controller, 
                                tags.get(GameTag.ATK, 0), 
                                tags.get(GameTag.DURABILITY, 0))
                            weapons.append(weapon)
                        elif card_type == 'MINION':
                            exhaust = tags.get(GameTag.EXHAUSTED, not tags.get(GameTag.CHARGE, 0))
                            if tags.get(GameTag.FROZEN):
                                exhaust = 1
                            minion = entities.BoardMinion(
                                card_info['name'], 
                                id, 
                                tags[GameTag.ZONE_POSITION], 
                                board_card.controller, 
                                tags.get(GameTag.ATK, 0), 
                                tags.get(GameTag.HEALTH, 0), 
                                tags.get(GameTag.TAUNT, 0), 
                                exhaust)
                            minions.append(minion)
                        elif card_type == 'HERO':
                            hero = entities.BoardHero(
                                card_info['name'],
                                id,
                                None,
                                board_card.controller,
                                tags.get(GameTag.HEALTH, 30) - tags.get(GameTag.DAMAGE, 0),
                                tags.get(GameTag.EXHAUSTED, 0)
                            )
                            heroes.append(hero)
        return entities.Board(minions, heroes, weapons)

    ## Update Game object by rereading logs
    def update_state(self, hp=1):
        parser = LogParser()
        if self.os == "Windows":
            log_dir = r"C:\Program Files (x86)\Hearthstone\Logs\Power.log"
            with io.open(log_dir, "r", encoding='utf8') as logs:
                lines = logs.readlines()
                self.logs = ''.join(lines)
            parser.read(io.StringIO(self.logs))
        elif self.os == "Linux":
            parser.read(io.StringIO(self.linux_log))
        parser.flush()

        packet_tree = parser.games[-1]
        while True:
            try:
                self.game = EntityTreeExporter(packet_tree).export().game
            except:
                print("Trapped")
                continue
            else:
                break

        packet_tree = parser.games[-1]
        self.friendly_player, self.enemy_player = self.read_players()

        turn = self.get_current_player().name in self.player_names
        board = self.get_current_board()
        hand = self.get_current_hand(hp, board)
        game_step = self.get_game_step()
        mana = self.get_current_mana()
        return hand, turn, board, game_step, mana

    def read_players(self):
        friendly = None
        enemy = None
        for player in self.game.players:
            if player.name in self.player_names:
                friendly = player
            else:
                enemy = player
        return friendly, enemy

    def get_current_mana(self):
        if self.friendly_player:
            tags = self.friendly_player.tags
            return tags.get(GameTag.RESOURCES, 0) - tags.get(GameTag.RESOURCES_USED, 0) + tags.get(GameTag.TEMP_RESOURCES, 0)
        return 0
Beispiel #22
0
def test_replays_api(auth_token, client, mocker):
    mocker.patch("hsreplaynet.api.serializers.replays.classify_deck",
                 return_value=1)
    upload_event = UploadEvent(
        id="1",
        shortid="ccSgiGQaenVzXzwGYbaUTPGrv",
        token_uuid=auth_token.key,
    )

    path = os.path.join(LOG_DATA_DIR, "hsreplaynet-tests", "replays",
                        "whizbang_friendly.annotated.xml")
    with open(path, "r") as f:
        replay = HSReplayDocument.from_xml_file(f)
    packet_tree = replay.to_packet_tree()[0]

    meta = {
        "game_type": enums.BnetGameType.BGT_RANKED_STANDARD,
        "ladder_season": 42,
        "format": enums.FormatType.FT_STANDARD,
        "friendly_player": 1,
        "reconnecting": False,
        "scenario_id": 2,
        "start_time": packet_tree.start_time,
        "end_time": packet_tree.end_time,
        "player1": {
            "rank":
            20,
            "stars":
            30,
            "deck": [
                "BOT_447",
                "BOT_447",
                "EX1_319",
                "EX1_319",
                "LOOT_014",
                "LOOT_014",
                "BOT_263",
                "BOT_263",
                "BOT_568",
                "CS2_065",
                "CS2_065",
                "EX1_596",
                "EX1_596",
                "BOT_443",
                "BOT_443",
                "LOOT_013",
                "LOOT_013",
                "BOT_224",
                "BOT_224",
                "BOT_226",
                "BOT_226",
                "ICC_466",
                "ICC_466",
                "ICC_075",
                "ICC_075",
                "EX1_310",
                "EX1_310",
                "BOT_521",
                "BOT_521",
                "ICC_831",
            ],
            "deck_id":
            1337,
            "cardback":
            136,
        },
        "player2": {
            "rank": 19,
            "cardback": 138,
        },
    }

    entity_tree = EntityTreeExporter(packet_tree).export().game
    replay_xml = "foo.xml"

    replay = create_dynamodb_game_replay(upload_event, meta, entity_tree,
                                         replay_xml)
    replay.save()

    user_id = auth_token.user.id

    response = client.get("/api/v1/replays/?user_id=%d" % (user_id))
    assert response.status_code == status.HTTP_200_OK
    payload = _parse_streaming_json(response.streaming_content)[0]

    assert payload["user_id"] == user_id
    assert payload["match_start"] == "2018-08-08T21:20:02.610000Z"
    assert payload["match_end"] == "2018-08-08T21:31:10.236000Z"
    assert payload["shortid"] == "ccSgiGQaenVzXzwGYbaUTPGrv"
    assert payload["game_type"] == enums.BnetGameType.BGT_RANKED_STANDARD
    assert payload["format_type"] == enums.FormatType.FT_STANDARD

    assert payload["friendly_player_account_hi"] == "144115193835963207"
    assert payload["friendly_player_account_lo"] == "127487329"
    assert payload["friendly_player_battletag"] == "Masture#1176"
    assert payload["friendly_player_rank"] == 20

    assert payload["friendly_player_archetype_id"] == 1

    assert payload["opponent_account_hi"] == "144115193835963207"
    assert payload["opponent_account_lo"] == "50318740"
    assert payload["opponent_battletag"] == "GinyuGamer#1677"
    assert payload["opponent_rank"] == 19

    assert payload["opponent_archetype_id"] is None

    assert payload["replay_xml"] == "foo.xml"
    assert payload["disconnected"] is False
    assert payload["reconnecting"] is False
    assert payload["visibility"] == Visibility.Public
    assert payload["views"] == 0
Beispiel #23
0
    def scrape_board_state(self, parser: LogParser):
        packet_tree = parser.games[len(parser.games) - 1]
        exporter = EntityTreeExporter(packet_tree)
        export = exporter.export()

        minions = []
        enchantments = []
        hero_powers = []
        entities = {}  # For Debug inspection
        friendly_player = friendly_hero = None
        enemy_player = enemy_hero = None

        for e in export.game.entities:
            entities[e.id] = e

            if e.type == CardType.ENCHANTMENT:
                enchantments.append(e)

            if e.zone == Zone.PLAY:
                if e.type == CardType.HERO_POWER:
                    hero_powers.append(e)
                elif e.type == CardType.MINION:
                    minions.append(e)
                elif e.type == CardType.PLAYER:
                    if e.is_ai:
                        enemy_player = e
                    else:
                        friendly_player = e
                elif e.type == CardType.HERO:
                    if e.controller == enemy_player:
                        enemy_hero = e
                    elif e.controller == friendly_player:
                        friendly_hero = e

        friendlyMinions = []
        enemyMinions = []

        for minion in minions:
            # Create list to hold deathrattle entity ids to convert to ghastcoiler ones
            minion.deathrattle_ids = []
            if GameTag.ATK not in minion.tags:
                # Minions with 0 power dont have an ATK tag. Make sure it exists here
                minion.tags[GameTag.ATK] = 0
            enemyMinions.append(
                minion) if minion.controller.is_ai else friendlyMinions.append(
                    minion)

        self.attach_enchantments(enchantments, minions)

        friendlyMinions.sort(
            key=lambda minion: minion.tags[GameTag.ZONE_POSITION])
        enemyMinions.sort(
            key=lambda minion: minion.tags[GameTag.ZONE_POSITION])

        friendly_health, friendly_tech_level = self.get_hero_tags(
            friendly_hero.tags)
        enemy_health, enemy_tech_level = self.get_hero_tags(enemy_hero.tags)

        state = BoardState(friendlyBoard=friendlyMinions,
                           friendlyPlayerHealth=friendly_health,
                           friendlyTechLevel=friendly_tech_level,
                           friendlyHero=self.get_hero(friendly_hero.card_id),
                           enemyBoard=enemyMinions,
                           enemyPlayerHealth=enemy_health,
                           enemyTechLevel=enemy_tech_level,
                           enemyHero=self.get_hero(enemy_hero.card_id))
        self.apply_hero_powers(state, hero_powers)

        return state
def test_create_dynamodb_game_replay(auth_token):
    upload_event = UploadEvent(
        id="1",
        shortid="ccSgiGQaenVzXzwGYbaUTPGrv",
        token_uuid=auth_token.key,
    )

    meta = {
        "game_type":
        enums.BnetGameType.BGT_RANKED_STANDARD,
        "ladder_season":
        42,
        "format":
        enums.FormatType.FT_STANDARD,
        "friendly_player":
        1,
        "reconnecting":
        False,
        "scenario_id":
        2,
        "start_time":
        datetime(year=2018,
                 month=8,
                 day=8,
                 hour=19,
                 minute=20,
                 second=2,
                 microsecond=606936),
        "end_time":
        datetime(year=2018, month=8, day=8, hour=19, minute=31, second=10),
        "player1": {
            "rank":
            20,
            "stars":
            30,
            "deck": [
                "BOT_447",
                "BOT_447",
                "EX1_319",
                "EX1_319",
                "LOOT_014",
                "LOOT_014",
                "BOT_263",
                "BOT_263",
                "BOT_568",
                "CS2_065",
                "CS2_065",
                "EX1_596",
                "EX1_596",
                "BOT_443",
                "BOT_443",
                "LOOT_013",
                "LOOT_013",
                "BOT_224",
                "BOT_224",
                "BOT_226",
                "BOT_226",
                "ICC_466",
                "ICC_466",
                "ICC_075",
                "ICC_075",
                "EX1_310",
                "EX1_310",
                "BOT_521",
                "BOT_521",
                "ICC_831",
            ],
            "deck_id":
            1337,
            "cardback":
            136,
        },
        "player2": {
            "rank": 19,
            "cardback": 138,
        },
    }

    path = os.path.join(LOG_DATA_DIR, "hsreplaynet-tests", "replays",
                        "whizbang_friendly.annotated.xml")
    with open(path, "r") as f:
        replay = HSReplayDocument.from_xml_file(f)
    packet_tree = replay.to_packet_tree()[0]
    entity_tree = EntityTreeExporter(packet_tree).export().game
    replay_xml = "foo.xml"

    replay = create_dynamodb_game_replay(upload_event, meta, entity_tree,
                                         replay_xml)
    assert replay

    assert replay.user_id == auth_token.user.id
    assert replay.match_start == 1533756002606
    assert replay.match_end == 1533756670000

    assert replay.short_id == upload_event.shortid
    assert replay.digest is None

    assert replay.game_type == enums.BnetGameType.BGT_RANKED_STANDARD
    assert replay.format_type == enums.FormatType.FT_STANDARD

    assert replay.game_type_match_start == "2:1533756002606"

    assert replay.ladder_season == 42
    assert replay.brawl_season is None
    assert replay.scenario_id == 2
    assert replay.num_turns == 31

    assert replay.friendly_player_account_hilo == "144115193835963207_127487329"
    assert replay.friendly_player_battletag == "Masture#1176"
    assert replay.friendly_player_is_first
    assert replay.friendly_player_rank == 20
    assert replay.friendly_player_rank_stars == 30
    assert replay.friendly_player_legend_rank is None
    assert replay.friendly_player_wins is None
    assert replay.friendly_player_losses is None
    assert replay.friendly_player_class == enums.CardClass.WARLOCK
    assert replay.friendly_player_deck == \
     "AAECAf0GApfTAo+CAw4w9wTCCPYIm8sC980C8dAC8tAC9PcC0/gCqvkCt/0Cw/0C+v4CAA=="
    assert replay.friendly_player_blizzard_deck_id == 1337
    assert replay.friendly_player_cardback_id == 136
    assert replay.friendly_player_final_state == enums.PlayState.WON

    assert replay.opponent_account_hilo == "144115193835963207_50318740"
    assert replay.opponent_battletag == "GinyuGamer#1677"
    assert not replay.opponent_is_ai
    assert replay.opponent_rank == 19
    assert replay.opponent_legend_rank is None
    assert replay.opponent_class == enums.CardClass.PALADIN
    assert replay.opponent_hero == 671
    assert replay.opponent_revealed_deck == \
     "AAECAZ8FDYoGlgm5wQLjywKc4gKL5QKb8AKl9QKE/ALW/gKggAPMgQPeggMEiMcC/PwC4f4CkYADAA=="
    assert replay.opponent_predicted_deck is None
    assert replay.opponent_final_state == enums.PlayState.LOST

    assert replay.replay_xml == replay_xml
    assert not replay.disconnected
    assert not replay.reconnecting
    assert replay.hslog_version
    assert replay.visibility == auth_token.user.default_replay_visibility
    assert replay.views == 0