async def get_mod_versions(self, mod): query = """ SELECT `updates_{mod}_files`.`fileId` AS file_id, MAX(`updates_{mod}_files`.`version`) AS version FROM `updates_{mod}` INNER JOIN `updates_{mod}_files` ON `fileId` = `updates_{mod}`.`id` GROUP BY `updates_{mod}_files`.`fileId` """.format(mod=mod) logger.debug(f"Performing query: {query}") # This is a fix for FAF db updates_* tables shindig. Mod updates should # be kept in just a single set of tables, but instead each mod has its # own set - and some don't have any, like ladder1v1! # As a stopgap, we'll swallow all errors that happen to this query and # just return an empty dict. I can't be bothered to make some sort of # subquery to check if the table exists, or parse exception string for # that - we'll live with that until we make a new replay format. try: featured_mods = await self._db.execute(query) except BookkeepingError as e: if mod != "ladder1v1": logger.warning((f"Failed to query mod versions for {mod}: {e}" f", not saving them in replay")) return {} return {str(mod['file_id']): mod['version'] for mod in featured_mods}
async def save_replay(self, game_id, stream): try: logger.debug(f"Saving replay {game_id}") await self._saver.save_replay(game_id, stream) logger.debug(f"Saved replay {game_id}") metrics.saved_replays.inc() except BookkeepingError as e: logger.warning(f"Failed to save replay for game {game_id}: {e}") try: logger.debug(f"Analyzing replay {game_id}") ticks = self._analyzer.get_replay_ticks(stream.data.bytes()) logger.debug(f"Updating tick count for game {game_id}") await self._queries.update_game_stats(game_id, ticks) except BookkeepingError as e: logger.warning(f"Failed to analyze replay for game {game_id}: {e}")
async def get_teams_in_game(self, game_id): query = """ SELECT `login`.`login` AS login, `game_player_stats`.`team` AS team FROM `game_stats` INNER JOIN `game_player_stats` ON `game_player_stats`.`gameId` = `game_stats`.`id` INNER JOIN `login` ON `login`.id = `game_player_stats`.`playerId` WHERE `game_stats`.`id` = %s AND `game_player_stats`.`AI` = 0 """ logger.debug(f"Performing query: {query}") players = await self._db.execute(query, (game_id, )) if not players: logger.warning( f"No players found for game {game_id}, will try to save anyway." ) teams = {} for player in players: teams.setdefault(player['team'], []).append(player['login']) return teams
async def get_game_stats(self, game_id): """ Gets the game information. """ query = """ SELECT `game_stats`.`startTime` AS start_time, `game_stats`.`endTime` AS end_time, `game_stats`.`gameType` AS game_type, `login`.`login` AS host, `game_stats`.`gameName` AS game_name, `game_featuredMods`.`gamemod` AS game_mod, `table_map`.`filename` AS file_name FROM `game_stats` LEFT JOIN `table_map` ON `game_stats`.`mapId` = `table_map`.`id` LEFT JOIN `login` ON `login`.id = `game_stats`.`host` LEFT JOIN `game_featuredMods` ON `game_stats`.`gameMod` = `game_featuredMods`.`id` WHERE `game_stats`.`id` = %s """ player_query = """ SELECT COUNT(*) FROM `game_player_stats` WHERE `game_player_stats`.`gameId` = %s """ logger.debug(f"Performing query: {query}") game_stats = await self._db.execute(query, (game_id, )) logger.debug(f"Performing query: {player_query}") player_count = await self._db.execute(player_query, (game_id, )) player_count = player_count[0]['COUNT(*)'] if not game_stats: raise BookkeepingError(f"No stats found for game {game_id}") start_time = game_stats[0]['start_time'].timestamp() # 'mapname' is a filename on the content server containing the map mapname = game_stats[0]['file_name'] if mapname is None: # Legacy replay server is forgiving like this. We replicate its # behaviour. logger.warning(f"Map missing for game {game_id}! Saving anyway.") mapname = "None" else: mapname = os.path.splitext(os.path.basename(mapname))[0] # We might end a replay before end_time is set in the db! end_time = game_stats[0]['end_time'] if end_time is None: end_time = time.time() else: end_time = end_time.timestamp() return { 'featured_mod': game_stats[0]['game_mod'], 'game_type': game_stats[0]['game_type'], 'recorder': game_stats[0]['host'], 'host': game_stats[0]['host'], 'launched_at': start_time, 'game_end': end_time, 'title': game_stats[0]['game_name'], 'mapname': mapname, 'num_players': player_count }