예제 #1
0
def test_options_packet_with_errors():
    parser = LogParser()
    parser.read(StringIO(INITIAL_GAME))

    parser.read(StringIO(OPTIONS_WITH_ERRORS))
    parser.flush()
    packet_tree = parser.games[0]

    options_packet = packet_tree.packets[-1]

    op0 = options_packet.options[0]
    assert op0.id == 0
    assert op0.type == OptionType.END_TURN
    assert op0.entity is None
    assert op0.error == PlayReq.INVALID
    assert op0.error_param is None

    op1 = options_packet.options[1]
    assert op1.id == 1
    assert op1.type == OptionType.POWER
    assert op1.entity == 33
    assert op1.error is None
    assert op1.error_param is None

    assert len(op1.options) == 12
    target = op1.options[11]
    assert target.id == 11
    assert target.entity == 37
    assert target.error == PlayReq.REQ_TARGET_MAX_ATTACK
    assert target.error_param == 3
예제 #2
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()
예제 #3
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
예제 #4
0
def test_warn_level():
    parser = LogParser()
    parser.read(StringIO(INITIAL_GAME))
    parser.flush()

    line = u"W 09:09:23.1428700 GameState.ReportStuck() - Stuck for 10s 89ms. {...}"
    parser.read(StringIO(line))
    parser.flush()
예제 #5
0
def test_error_level():
	parser = LogParser()
	parser.read(StringIO(data.INITIAL_GAME))
	parser.flush()

	line = u"E 02:08:13.8318679 SubSpellController {...}"
	parser.read(StringIO(line))
	parser.flush()
예제 #6
0
def test_unroundable_timestamp():
	parser = LogParser()
	parser.read(StringIO(data.INITIAL_GAME))
	parser.read(StringIO(data.UNROUNDABLE_TIMESTAMP))
	parser.flush()

	# Timestamp has to be truncated
	assert parser.games[0].packets[1].ts == time(14, 43, 59, 999999)
예제 #7
0
def test_info_outside_of_metadata():
    parser = LogParser()
    parser.read(StringIO(INITIAL_GAME))
    parser.flush()

    info = u"D 02:59:14.6500380 GameState.DebugPrintPower() -             Info[0] = 99"
    parser.read(StringIO(info))
    parser.flush()
예제 #8
0
def test_error_unhandled_powtype():
    parser = LogParser()
    parser.read(StringIO(INITIAL_GAME))

    # This shouldn't raise an exception
    parser.read(
        StringIO("D 02:13:03.1360001 GameState.DebugPrintPower() - "
                 "ERROR: unhandled PowType RESET_GAME"))
    parser.flush()
예제 #9
0
def test_empty_entity_in_options():
    parser = LogParser()
    parser.read(StringIO(INITIAL_GAME))
    parser.flush()

    data = "target 0 entity="
    with pytest.raises(ParsingError):
        # This can happen, but the game is corrupt
        parser.handle_options(None, data)
예제 #10
0
def test_reset_game():
	parser = LogParser()
	parser.read(StringIO(data.INITIAL_GAME))

	# This shouldn't raise an exception
	parser.read(StringIO(
		"D 15:39:19.3190860 GameState.DebugPrintPower() - BLOCK_START BlockType=GAME_RESET Entity=[entityName=Temporal Loop id=17 zone=PLAY zonePos=0 cardId=GILA_900p player=1] EffectCardId= EffectIndex=-1 Target=0 SubOption=-1\n" # noqa
		"D 15:39:19.3190860 GameState.DebugPrintPower() -     RESET_GAME\n"
	))
	parser.flush()
예제 #11
0
def test_create_empty_game():
    parser = LogParser()
    parser.read(StringIO(EMPTY_GAME))
    parser.flush()

    # Test resulting game/entities
    assert len(parser.games) == 1

    packet_tree = parser.games[0]
    game = packet_tree.export().game
    assert len(game.entities) == 3
    assert len(game.players) == 2
    assert game.entities[0] is game
    assert game.entities[0].id == 1
    assert game.entities[1] is game.players[0]
    assert game.entities[2] is game.players[1]
    assert game.initial_state == State.INVALID
    assert game.initial_step == Step.INVALID

    # Test player objects
    assert game.players[0].id == 2
    assert game.players[0].player_id == 1
    assert game.players[0].account_hi == 1
    assert game.players[0].account_lo == 0
    assert game.players[0].is_ai
    assert not game.players[0].name

    assert game.players[1].id == 3
    assert game.players[1].player_id == 2
    assert game.players[1].account_hi == 3
    assert game.players[1].account_lo == 2
    assert not game.players[1].is_ai
    assert not game.players[1].name

    # Test packet structure
    assert len(packet_tree.packets) == 1
    packet = packet_tree.packets[0]
    assert packet.power_type == PowerType.CREATE_GAME
    assert packet.entity == game.id == 1

    # Player packet objects are not the same as players
    assert int(packet.players[0].entity) == game.players[0].id
    assert packet.players[0].player_id == game.players[0].player_id
    assert int(packet.players[1].entity) == game.players[1].id
    assert packet.players[1].player_id == game.players[1].player_id

    # All tags should be empty (we didn't pass any)
    assert not game.tags
    assert not game.players[0].tags
    assert not game.players[1].tags

    # Check some basic logic
    assert game.get_player(1) is game.players[0]
    assert game.get_player(2) is game.players[1]
예제 #12
0
def test_shuffle_deck_only():
	parser = LogParser()
	parser.read(StringIO(data.INITIAL_GAME))
	parser.read(StringIO(data.SHUFFLE_DECK))
	parser.flush()

	packet_tree = parser.games[0]

	shuffle_deck_packet = packet_tree.packets[1]

	assert shuffle_deck_packet.player_id == 2
예제 #13
0
def test_cached_tag_for_dormant_change_entity_id_only():
	parser = LogParser()
	parser.read(StringIO(data.INITIAL_GAME))
	parser.read(StringIO(data.CACHED_TAG_FOR_DORMANT_CHANGE_SHORT_ENTITY))
	parser.flush()

	packet_tree = parser.games[0]

	cached_tag_packet = packet_tree.packets[1]

	assert cached_tag_packet.entity == 593
	assert cached_tag_packet.tag == GameTag.DEATHRATTLE
	assert cached_tag_packet.value == 1
예제 #14
0
class BattlefieldCollector(BaseCollector):
    def __init__(self, game):
        super().__init__(game)
        self.path = path.join(game.path, "Power.log")
        print(game.path)
        self.last_ts = datetime.time(0)
        self.last_turn = None
        self.parser = LogParser()

    def run(self):
        with open(self.path) as f:
            self.parser.read(f)
            self.parser.flush()
            tps = self.parser.games
            fp_id = FriendlyPlayerExporter(tps[-1]).export()
            turn = LastTurnExporter(tps[-1], self.last_ts, fp_id).export()
            if not self.last_turn:
                self.last_turn = turn
            if (turn.ts > self.last_turn.ts and turn.player):
                ## GET MINIONS / HAND_CARDS / HERO_POWERS
                time.sleep(1.2)
                img = screen.shot()
                print("EMinions {}  - PMinions {}  - HandCards {}".format(
                    turn.enemy_minions, turn.player_minions, turn.hand_cards))

                base_name = "em{}_pm{}_hc{}".format(turn.enemy_minions,
                                                    turn.player_minions,
                                                    turn.hand_cards)

                count = len([
                    f for f in listdir("images") if isfile(join("images", f))
                    and base_name in f and ".png" in f
                ])
                if (count > 2):
                    count = randrange(0, 2)
                base_name = "images/{}_{}".format(count, base_name)

                img_name = base_name + ".png"
                xml_name = base_name + ".xml"

                temp = create_battlefield(img, turn.hand_cards,
                                          turn.enemy_minions,
                                          turn.player_minions,
                                          turn.enemy_power, turn.player_power)
                temp.save(xml_name)

                screen.save(img, img_name)
                self.game.show_img(img_name)
                self.last_turn = turn
예제 #15
0
def test_game_initialization():
    parser = LogParser()
    parser.read(StringIO(INITIAL_GAME))
    parser.flush()

    assert len(parser.games) == 1
    packet_tree = parser.games[0]
    game = packet_tree.export().game
    assert len(game.entities) == 3
    assert len(game.players) == 2

    assert game.tags == {
        GameTag.TURN: 1,
        GameTag.ZONE: Zone.PLAY,
        GameTag.ENTITY_ID: 1,
        GameTag.NEXT_STEP: Step.BEGIN_MULLIGAN,
        GameTag.CARDTYPE: CardType.GAME,
        GameTag.STATE: State.RUNNING,
    }
    assert game.initial_state == State.RUNNING
    assert game.initial_step == Step.INVALID

    assert game.players[0].tags == {
        GameTag.PLAYSTATE: PlayState.PLAYING,
        GameTag.PLAYER_ID: 1,
        GameTag.TEAM_ID: 1,
        GameTag.ZONE: Zone.PLAY,
        GameTag.CONTROLLER: 1,
        GameTag.ENTITY_ID: 2,
        GameTag.CARDTYPE: CardType.PLAYER,
    }

    assert game.players[1].tags == {
        GameTag.PLAYSTATE: PlayState.PLAYING,
        GameTag.CURRENT_PLAYER: 1,
        GameTag.FIRST_PLAYER: 1,
        GameTag.PLAYER_ID: 2,
        GameTag.TEAM_ID: 2,
        GameTag.ZONE: Zone.PLAY,
        GameTag.CONTROLLER: 2,
        GameTag.ENTITY_ID: 3,
        GameTag.CARDTYPE: CardType.PLAYER,
    }

    # Test that there should be no friendly player
    fpe = FriendlyPlayerExporter(packet_tree)
    friendly_player = fpe.export()
    assert not friendly_player
예제 #16
0
def test_vo_spell_only():
	parser = LogParser()
	parser.read(StringIO(data.INITIAL_GAME))
	parser.read(StringIO(data.VO_SPELL))
	parser.flush()

	packet_tree = parser.games[0]

	vo_spell_packet = packet_tree.packets[1]

	assert vo_spell_packet.brguid == (
		"VO_BTA_BOSS_07h2_Female_NightElf_Mission_Fight_07_PlayerStart_01.prefab:616c9e5" +
		"7bb7fce54684e26be50462d17"
	)
	assert vo_spell_packet.vospguid == ""
	assert vo_spell_packet.blocking is True
	assert vo_spell_packet.delayms == 1000
예제 #17
0
def test_tag_change_unknown_entity_format():
    # Format changed in 15590
    parser = LogParser()
    parser.read(StringIO(INITIAL_GAME))
    parser.flush()

    entity_format = (
        "[name=UNKNOWN ENTITY [cardType=INVALID] id=24 zone=DECK zonePos=0 cardId= player=1]"
    )
    id = parse_entity_id(entity_format)
    assert id == 24

    data = "TAG_CHANGE Entity=%s tag=ZONE value=HAND" % (entity_format)
    packet = parser.handle_power(None, "TAG_CHANGE", data)
    assert packet.power_type == PowerType.TAG_CHANGE
    assert packet.entity == id
    assert packet.tag == GameTag.ZONE
    assert packet.value == Zone.HAND
예제 #18
0
def test_sub_spell():
	parser = LogParser()
	parser.read(StringIO(data.INITIAL_GAME))

	parser.read(StringIO(data.SUB_SPELL_BLOCK))
	parser.flush()

	packet_tree = parser.games[0]
	play_block = packet_tree.packets[-1]
	power_block = play_block.packets[0]
	assert len(power_block.packets) == 1
	sub_spell_packet = power_block.packets[0]

	assert sub_spell_packet.spell_prefab_guid == (
		"CannonBarrage_Missile_FX:e26b4681614e0964aa8ef7afebc560d1"
	)
	assert sub_spell_packet.source == 59
	assert sub_spell_packet.target_count == 1
	assert sub_spell_packet.targets == [41]
예제 #19
0
def test_sub_spell_battlegrounds():
	parser = LogParser()
	parser.read(StringIO(data.INITIAL_GAME))

	parser.read(StringIO(data.BGS_SUB_SPELL_BLOCK))
	parser.flush()

	packet_tree = parser.games[0]
	play_block = packet_tree.packets[-1]
	power_block = play_block.packets[0]
	assert len(power_block.packets) == 1
	sub_spell_packet = power_block.packets[0]

	assert sub_spell_packet.spell_prefab_guid == (
		"Bacon_FreezeMinions_AE_Super.prefab:49de73d8b72602f47994a795a78f050d"
	)
	assert sub_spell_packet.source == 0
	assert sub_spell_packet.target_count == 0
	assert sub_spell_packet.targets == []
예제 #20
0
def test_empty_tasklist():
    parser = LogParser()
    parser.read(StringIO(INITIAL_GAME))
    parser.flush()

    ts = datetime.now()
    msg = "id=4 Player=The Innkeeper TaskList=1 ChoiceType=GENERAL CountMin=1 CountMax=1"
    choices = parser.handle_entity_choices(ts, msg)
    assert choices
    assert choices.id == 4
    assert choices.player.name == "The Innkeeper"
    assert choices.tasklist == 1
    assert choices.type == ChoiceType.GENERAL
    assert choices.min == 1
    assert choices.max == 1

    # Test empty tasklist
    msg = "id=4 Player=The Innkeeper TaskList= ChoiceType=GENERAL CountMin=1 CountMax=1"
    choices = parser.handle_entity_choices(ts, msg)
    assert choices.tasklist is None
예제 #21
0
def test_target_no_entity():
	parser = LogParser()
	parser.read(StringIO(data.INITIAL_GAME))

	parser.read(StringIO(
		"D 01:02:58.3254653 GameState.DebugPrintOptions() - id=2\n" # noqa
		"D 01:02:58.3254653 GameState.DebugPrintOptions() -   option 0 type=END_TURN mainEntity= error=INVALID errorParam=\n" # noqa
		"D 01:02:58.3254653 GameState.DebugPrintOptions() -   option 1 type=POWER mainEntity= error=NONE errorParam=\n" # noqa
		"D 01:02:58.3254653 GameState.DebugPrintOptions() -     target 0 entity= error=NONE errorParam=\n" # noqa
		"D 01:02:58.3254653 GameState.DebugPrintOptions() -     target 1 entity= error=NONE errorParam=\n" # noqa
	))
	parser.flush()

	packet_tree = parser.games[0]

	options_packet = packet_tree.packets[-1]
	option = options_packet.options[1]
	target = option.options[0]
	assert target.entity is None
	assert target.error is None
	assert target.error_param is None
예제 #22
0
def test_initial_deck_initial_controller():
    parser = LogParser()
    parser.read(StringIO(INITIAL_GAME))
    parser.read(StringIO(FULL_ENTITY))
    parser.flush()
    packet_tree = parser.games[0]
    game = packet_tree.export().game

    assert len(list(game.players[0].initial_deck)) == 1
    assert len(list(game.players[1].initial_deck)) == 0

    parser = LogParser()
    parser.read(StringIO(INITIAL_GAME))
    parser.read(StringIO(FULL_ENTITY))
    parser.read(StringIO(CONTROLLER_CHANGE))
    parser.flush()
    packet_tree = parser.games[0]
    game = packet_tree.export().game

    assert len(list(game.players[0].initial_deck)) == 1
    assert len(list(game.players[1].initial_deck)) == 0
예제 #23
0
def test_timestamp_parsing():
    parser = LogParser()
    parser.read(StringIO(INITIAL_GAME))
    parser.flush()

    assert parser.games[0].packets[0].ts == time(2, 59, 14, 608862)

    # Test with an initial datetime
    parser2 = LogParser()
    parser2._current_date = datetime(2015, 1, 1)
    parser2.read(StringIO(INITIAL_GAME))
    parser2.flush()

    assert parser2.games[0].packets[0].ts == datetime(2015, 1, 1, 2, 59, 14,
                                                      608862)

    # Same test, with timezone
    parser2 = LogParser()
    parser2._current_date = parse_datetime("2015-01-01T02:58:00+0200")
    parser2.read(StringIO(INITIAL_GAME))
    parser2.flush()

    ts = parser2.games[0].packets[0].ts
    assert ts.year == 2015
    assert ts.hour == 2
    assert ts.second == 14
    assert ts.tzinfo
    assert ts.utcoffset() == timedelta(hours=2)
예제 #24
0
def test_options_missing_block_end():
	parser = LogParser()
	parser.read(StringIO(data.INITIAL_GAME))

	parser.read(StringIO(
		"D 09:01:05.7959635 GameState.DebugPrintPower() - BLOCK_START BlockType=ATTACK Entity=[entityName=Rat Pack id=2974 zone=PLAY zonePos=2 cardId=CFM_316 player=3] EffectCardId= EffectIndex=1 Target=0 SubOption=-1 \n" # noqa
		"D 09:01:05.7959635 GameState.DebugPrintPower() -     BLOCK_START BlockType=TRIGGER Entity=[entityName=3ofKindCheckPlayerEnchant id=3319 zone=PLAY zonePos=0 cardId=TB_BaconShop_3ofKindChecke player=3] EffectCardId= EffectIndex=-1 Target=0 SubOption=-1 TriggerKeyword=0\n" # noqa
		"D 09:01:05.7959635 GameState.DebugPrintPower() -     BLOCK_END\n" # noqa
		"D 09:01:05.7959635 GameState.DebugPrintPower() -     TAG_CHANGE Entity=BehEh#1355 tag=NUM_OPTIONS_PLAYED_THIS_TURN value=15 \n" # noqa
		"D 09:01:05.8620235 GameState.DebugPrintOptions() - id=76\n" # noqa
		"D 09:01:05.8620235 GameState.DebugPrintOptions() -   option 0 type=END_TURN mainEntity= error=INVALID errorParam=\n" # noqa
	))
	parser.flush()

	packet_tree = parser.games[0]

	block_without_end = packet_tree.packets[1]
	assert isinstance(block_without_end, packets.Block)
	assert block_without_end.ended

	options_packet = packet_tree.packets[-1]
	assert isinstance(options_packet, packets.Options)