diff --git a/hslog/live/entities.py b/hslog/live/entities.py index e0e089e..31d7590 100644 --- a/hslog/live/entities.py +++ b/hslog/live/entities.py @@ -21,6 +21,7 @@ def game(self, value): if value is not None: terminal_output("ENTITY CREATED", self) # push data to an end-point + pass def tag_change(self, tag, value): if tag == GameTag.CONTROLLER and not self._initial_controller: @@ -28,10 +29,12 @@ def tag_change(self, tag, value): self.tags[tag] = value terminal_output("TAG UPDATED", self, tag, value) # push data to an end-point + pass def update_callback(self, caller): terminal_output("ENTITY UPDATED", self) # push data to an end-point + pass class LiveCard(Card, LiveEntity): diff --git a/hslog/live/export.py b/hslog/live/export.py index b6d0581..13be7fd 100644 --- a/hslog/live/export.py +++ b/hslog/live/export.py @@ -2,7 +2,6 @@ from hslog.export import EntityTreeExporter from hslog.live.entities import LiveCard, LiveGame, LivePlayer -from hslog.live.utils import ACCESS_DEBUG class LiveEntityTreeExporter(EntityTreeExporter): @@ -18,7 +17,6 @@ def __init__(self, packet_tree): super(LiveEntityTreeExporter, self).__init__(packet_tree) def handle_player(self, packet): - ACCESS_DEBUG(self.__class__, "handle_player") entity_id = int(packet.entity) if hasattr(self.packet_tree, "manager"): diff --git a/hslog/live/parser.py b/hslog/live/parser.py index 802ecd2..ea2033a 100644 --- a/hslog/live/parser.py +++ b/hslog/live/parser.py @@ -2,20 +2,18 @@ from collections import deque from threading import Thread -from hearthstone.enums import FormatType, GameType - from hslog import packets, tokens from hslog.exceptions import RegexParsingError from hslog.live.packets import LivePacketTree from hslog.live.player import LivePlayerManager from hslog.parser import LogParser from hslog.player import LazyPlayer -from hslog.utils import parse_enum, parse_tag +from hslog.utils import parse_tag class LiveLogParser(LogParser): """ - LiveLogParser adds live log translation into useful data. + LiveLogParser provides live log translation into useful data. Lines are read and pushed into a deque by a separate thread. Deque is emptied by parse_worker which replaces the read() @@ -46,14 +44,17 @@ def new_packet_tree(self, ts): self.current_block = self._packets self.games.append(self._packets) - """ - why is this return important? - it"s called only here: + def handle_entities_chosen(self, ts, data): + super(LiveLogParser, self).handle_entities_chosen(ts, data) + if data.startswith("id="): + sre = tokens.ENTITIES_CHOSEN_RE.match(data) + if not sre: + raise RegexParsingError(data) + player_name = sre.groups()[1] - def create_game(self, ts): - self.new_packet_tree(ts) - """ - return self._packets + # pick up opponent name from GameState.DebugPrintEntitiesChosen() + m = self._packets.manager + m.complete_player_names(player_name, self._packets) def handle_game(self, ts, data): if data.startswith("PlayerID="): @@ -62,25 +63,13 @@ def handle_game(self, ts, data): raise RegexParsingError(data) player_id, player_name = sre.groups() - # set the name of the player - players = self.games[-1].liveExporter.game.players - for p in players: - if p.player_id == int(player_id): - p.name = player_name + # set initial name based on GameState.DebugPrintGame() + m = self._packets.manager + m.set_initial_player_name(player_id, player_name, self._packets) player_id = int(player_id) else: - key, value = data.split("=") - key = key.strip() - value = value.strip() - if key == "GameType": - value = parse_enum(GameType, value) - elif key == "FormatType": - value = parse_enum(FormatType, value) - else: - value = int(value) - - self.game_meta[key] = value + super(LiveLogParser, self).handle_game(ts, data) def tag_change(self, ts, e, tag, value, def_change): entity_id = self.parse_entity_or_player(e) diff --git a/hslog/live/player.py b/hslog/live/player.py index 277dfd4..5e4203f 100644 --- a/hslog/live/player.py +++ b/hslog/live/player.py @@ -1,29 +1,45 @@ from hearthstone.enums import GameTag -from hslog.exceptions import ParsingError from hslog.player import PlayerManager class LivePlayerManager(PlayerManager): - def register_player_name_on_tag_change(self, player, tag, value): - """ - Triggers on every TAG_CHANGE where the corresponding entity is a LazyPlayer. - Will attempt to return a new value instead - """ - if tag == GameTag.ENTITY_ID: - # This is the simplest check. When a player entity is declared, - # its ENTITY_ID is not available immediately (in pre-6.0). - # If we get a matching ENTITY_ID, then we can use that to match it. - return self.register_player_name(player.name, value) - elif tag == GameTag.LAST_CARD_PLAYED: - # This is a fallback to register_player_name_mulligan in case the mulligan - # phase is not available in this game (spectator mode, reconnects). - if value not in self._entity_controller_map: - raise ParsingError("Unknown entity ID on TAG_CHANGE: %r" % (value)) - player_id = self._entity_controller_map[value] - entity_id = int(self._players_by_player_id[player_id]) - return self.register_player_name(player.name, entity_id) - elif tag == GameTag.MULLIGAN_STATE: - return None - return player + def __init__(self): + super(LivePlayerManager, self).__init__() + + self.actual_player_names = set() + self.names_used = set() + self.name_assignment_done = False + + def register_player_name_on_tag_change(self, player, tag, value): + if tag not in [GameTag.ENTITY_ID, GameTag.LAST_CARD_PLAYED]: + return None + super(LivePlayerManager, self).register_player_name_on_tag_change(player, tag, value) + + def set_initial_player_name(self, player_id, player_name, current_game): + players = current_game.liveExporter.game.players + for p in players: + if p.player_id == int(player_id): + p.name = player_name + + def complete_player_names(self, player_name, current_game): + # populate names if they haven"t been used already + if player_name not in self.names_used: + self.actual_player_names.add(player_name) + + # if there are two names available we have enough to assign + if len(self.actual_player_names) == 2 and not self.name_assignment_done: + unnamed = None + for p in current_game.liveExporter.game.players: + if p.name in self.actual_player_names: + self.names_used.add(p.name) + self.actual_player_names.remove(p.name) + else: + unnamed = p + if len(self.actual_player_names): + other_player_name = self.actual_player_names.pop() + self.names_used.add(other_player_name) + unnamed.name = other_player_name + + self.name_assignment_done = True diff --git a/hslog/live/utils.py b/hslog/live/utils.py index b2222d2..d3c15d8 100644 --- a/hslog/live/utils.py +++ b/hslog/live/utils.py @@ -48,3 +48,11 @@ def terminal_output(msg_type, obj, attr=None, value=None): align(repr(attr), 40), align(value, 30), ) + + +def debug_player_names(player_manager): + print("{} | {} | {}".format( + align(player_manager.actual_player_names, 40), + align(player_manager.names_used, 40), + align(player_manager.name_assignment_done, 10), + ))