class Analyzer: def __init__(self): self.match_metadata = MatchMetadata() self.server_info = ServerInfo() self.team_lifecycle = TeamLifecycle() self.player_scores = PlayerScores() self.players = {} self.special_scores = SpecialScores(self.player_scores) self.badger = Badger(self.player_scores, self.special_scores) self.player_stats = {} self.specific_analyzer = None def analyze(self, full_match_info) -> AnalysisResult: """ :param full_match_info: FullMatchInfo :return: AnalysisResult """ self.full_match_info = full_match_info self.match_guid = full_match_info.match_guid self.player_scores.match_duration = self.full_match_info.duration self.team_lifecycle.match_duration = self.full_match_info.duration self.match_metadata.from_full_match_info(full_match_info) self.server_info.from_full_match_info(full_match_info) for raw_event in full_match_info.events: self.analyze_event(raw_event) self.badger.assign() # report generation report = AnalysisResult() report.server_info = self.server_info report.players = self.players report.scores = self.player_scores.scores report.final_scores = self.player_scores.player_score report.special_scores = self.special_scores.scores report.team_scores = "NOT IMPLEMENTED" report.team_switches = self.team_lifecycle.switches report.teams = self.team_lifecycle.team_map report.match_metadata = self.match_metadata report.kills = self.player_scores.kills report.badges = self.badger.badges report.player_stats = list(self.player_stats.values()) report.generate_summary() return report def analyze_event(self, raw_event): event = Event.from_dict(raw_event) dispatcher = { "MATCH_REPORT": self.on_match_report, "MATCH_STARTED": self.on_match_start, "PLAYER_DEATH": self.on_player_death, "PLAYER_DISCONNECT": self.on_player_disconnect, "PLAYER_KILL": self.on_player_kill, "PLAYER_SWITCHTEAM": self.on_player_switchteam, "PLAYER_STATS": self.on_player_stats, } try: handler = dispatcher[event.type] except KeyError: return handler(event) def add_player_if_needed(self, player_id, player_name): if player_id not in self.players: player_info = PlayerInfo() player_info.steam_id = player_id player_info.name = player_name self.players[player_id] = player_info def on_match_report(self, event): self.match_metadata.from_match_report(event) self.server_info.from_match_report(event) self.player_scores.from_match_report(event) self.special_scores.from_match_report(event) def on_match_start(self, event): self.match_metadata.from_match_started(event) for player in event.iter_players(): self.add_player_if_needed(player.id, player.name) self.team_lifecycle.from_match_started(event) self.player_scores.from_match_started(event) if self.match_metadata.game_type == "CA": self.specific_analyzer = CA_Analyzer(self.players, self.team_lifecycle) else: self.specific_analyzer = SpecializedAnalyzer( self.players, self.team_lifecycle) def on_player_switchteam(self, event): self.team_lifecycle.from_player_switchteam(event) player_id = event.player_id player_name = event.player_name self.add_player_if_needed(player_id, player_name) self.player_scores.from_player_switchteam(event) def on_player_disconnect(self, event): self.player_scores.from_player_disconnect(event) self.team_lifecycle.from_player_disconnect(event) def on_player_kill(self, event): # in q3 player can change his nickname. the generated id is # properly preserved between events but the name is not player_id = event.killer_id if event.killer_name: self.players[player_id].name = event.killer_name self.player_scores.from_player_kill(event) self.special_scores.from_player_kill(event) def on_player_death(self, event): # nice to have it here self.player_scores.from_player_death(event) self.specific_analyzer.on_player_death(event) self.special_scores.from_player_death(event) def on_player_stats(self, event): # if player has multiple stats events just use the last one # TODO consider merging stats (e.g. player reconnects/rejoins match) # ordinary stats sum grouped by player_id would be sufficient self.player_stats[event.player_id] = { "player_id": event.player_id, "total_armor_pickup": event.total_armor, "total_health_pickup": event.total_health, "damage_dealt": event.damage_dealt, "damage_taken": event.damage_taken, "weapons": event.weapon_stats, }
class Analyzer(): def __init__(self): self.match_metadata = MatchMetadata() self.server_info = ServerInfo() self.team_lifecycle = TeamLifecycle() self.player_scores = PlayerScores() self.players = {} self.special_scores = SpecialScores(self.player_scores) self.badger = Badger(self.player_scores, self.special_scores) self.specific_analyzer = None def analyze(self, full_match_info): """ :param full_match_info: FullMatchInfo :return: AnalysisResult """ self.full_match_info = full_match_info self.match_guid = full_match_info.match_guid self.player_scores.match_duration = self.full_match_info.duration self.team_lifecycle.match_duration = self.full_match_info.duration self.match_metadata.from_full_match_info(full_match_info) self.server_info.from_full_match_info(full_match_info) for raw_event in full_match_info.events: self.analyze_event(raw_event) self.badger.assign() # report generation report = AnalysisResult() report.server_info = self.server_info report.players = self.players report.scores = self.player_scores.scores report.final_scores = self.player_scores.player_score report.special_scores = self.special_scores.scores report.team_scores = "NOT IMPLEMENTED" report.team_switches = self.team_lifecycle.switches report.teams = self.team_lifecycle.team_map report.match_metadata = self.match_metadata report.kills = self.player_scores.kills report.badges = self.badger.badges return report def analyze_event(self, raw_event): event = Event.from_dict(raw_event) dispatcher = { 'MATCH_REPORT': self.on_match_report, 'MATCH_STARTED': self.on_match_start, 'PLAYER_DEATH': self.on_player_death, 'PLAYER_DISCONNECT': self.on_player_disconnect, 'PLAYER_KILL': self.on_player_kill, 'PLAYER_SWITCHTEAM': self.on_player_switchteam, } try: handler = dispatcher[event.type] except KeyError: return handler(event) def add_player_if_needed(self, player_id, player_name): if player_id not in self.players: player_info = PlayerInfo() player_info.steam_id = player_id player_info.name = player_name self.players[player_id] = player_info def on_match_report(self, event): self.match_metadata.from_match_report(event['DATA']) self.server_info.from_match_report(event['DATA']) self.player_scores.from_match_report(event['DATA']) self.special_scores.from_match_report(event['DATA']) def on_match_start(self, event): self.match_metadata.from_match_started(event['DATA']) if 'PLAYERS' in event['DATA']: self.team_lifecycle.from_match_started(event['DATA']) self.player_scores.from_match_started(event['DATA']) for player in event['DATA']['PLAYERS']: self.add_player_if_needed( player['STEAM_ID'], player['NAME']) if self.match_metadata.game_type == 'CA': self.specific_analyzer = CA_Analyzer( self.players, self.team_lifecycle) else: self.specific_analyzer = SpecializedAnalyzer( self.players, self.team_lifecycle) def on_player_switchteam(self, event): self.team_lifecycle.from_player_switchteam(event) player_id = event.player_id player_name = event.player_name self.add_player_if_needed(player_id, player_name) self.player_scores.from_player_switchteam(event) def on_player_disconnect(self, event): self.player_scores.from_player_disconnect(event['DATA']) self.team_lifecycle.from_player_disconnect(event['DATA']) def on_player_kill(self, event): # in q3 player can change his nickname. the generated id is # properly preserved between events but the name is not player_id = event.killer_id self.players[player_id].name = event.killer_name self.player_scores.from_player_kill(event) self.special_scores.from_player_kill(event) def on_player_death(self, event): # nice to have it here self.player_scores.from_player_death(event) self.specific_analyzer.on_player_death(event) self.special_scores.from_player_death(event)