Exemple #1
0
def game(key: str):
    try:
        summary = ValorantGameSummary.get(key)
    except ValorantGameSummary.DoesNotExist:
        return 'Game does not exist', 404

    game, metadata = load_game(summary)
    dev_info = get_dev_info(summary, game, metadata)

    if game.won is not None:
        result = ['LOSS', 'WIN'][game.won]
    elif game.rounds.has_game_resets:
        result = 'SCRIM'
    else:
        result = 'game'

    if game.teams.firstperson:
        title = f'{game.teams.firstperson.name}\'s {result} on {game.map}'
    else:
        title = f'{result[0].capitalize() + result[1:]} on {game.map}'

    imagehash = hashlib.md5(
        str((game.won, game.game_mode, game.rounds.final_score,
             summary.agent)).encode()).hexdigest()

    def is_first_round(round: Round) -> bool:
        return round.attacking == game.rounds.rounds[0].attacking

    rounds_first = takewhile(is_first_round, game.rounds.rounds)
    rounds_second = dropwhile(is_first_round, game.rounds.rounds)

    return render_template(
        'valorant/game/game.html',
        title=title,
        meta=Meta(title=title,
                  image_url=url_for(
                      'valorant.game.game_card_png', key=key, _external=True) +
                  f'?_cachebust={imagehash}',
                  twitter_image_url=url_for(
                      'valorant.game.game_card_png', key=key, _external=True) +
                  f'?height=190&_cachebust={imagehash}',
                  summary_large_image=True,
                  colour=COLOURS.get(result, 'gray')),
        summary=summary,
        game=game,
        rounds_combined=list(zip_longest(rounds_first, rounds_second)),

        # show_edit=check_authentication() is None and (summary.user_id == session.user_id or session.superuser),
        dev_info=dev_info,
    )
Exemple #2
0
def game(key: str):
    try:
        summary = OverwatchGameSummary.get(key)
    except OverwatchGameSummary.DoesNotExist:
        return 'Game does not exist', 404

    if summary.player_name and summary.result != 'UNKNOWN':
        title = f'{summary.player_name}\'s {summary.result} on {summary.map}'
    elif summary.player_name:
        title = f'{summary.player_name}\'s game on {summary.map}'
    else:
        title = f'{key.split("/", 1)[0]}\'s game on {summary.map}'

    if not summary.game_version or summary.game_version < OLDEST_SUPPORTED_GAME_VERSION or 'legacy' in request.args:
        return render_template(
            'overwatch/game/legacy_game.html',
            title=title,
            legacy_base=LEGACY_URL,
            legacy_scripts=legacy_scripts,
            legacy_stylesheet=legacy_stylesheet,
        )

    if not summary.viewable and not(check_authentication() is None and session.superuser):
        return 'Please subscribe to view game details', 403

    if summary.game_type == 'custom' and (check_authentication() is not None or (not session.superuser and session.user_id != summary.user_id)):
        return 'Custom games are restricted to being viewed by their owner', 403

    game, metadata = load_game(summary)
    game.timestamp = summary.time

    if game.teams.owner and game.result != 'UNKNOWN':
        title = f'{game.teams.owner.name}\'s {game.result} on {game.map.name}'
    elif game.teams.owner:
        title = f'{game.teams.owner.name}\'s game on {game.map.name}'

    dev_info = get_dev_info(summary, game, metadata)

    imagehash = hashlib.md5(str((game.result, game.start_sr, game.end_sr)).encode()).hexdigest()

    try:
        tfs = game.teamfights
        stat_totals = {
            'eliminations.during_fights': len(tfs.eliminations_during_fights),
            'deaths.during_fights': len(tfs.eliminations_during_fights) + len(tfs.suicides_during_fights),
            'killfeed_assists.during_fights': len(tfs.killfeed_assists_during_fights),
            'first_elims': len(tfs.first_bloods),
            'first_deaths': len(tfs.first_bloods),
            'eliminations.outside_fights': len(tfs.eliminations_outside_fights),
            'deaths.outside_fights': len(tfs.eliminations_outside_fights) + len(tfs.suicides_outside_fights),
            'killfeed_assists.outside_fights': len(tfs.killfeed_assists_outside_fights),
            'fight_starts_missed': len(tfs.teamfights),
            'times_staggered': len(tfs.teamfights),
        }
    except AttributeError:
        stat_totals = {}

    return render_template(
        'overwatch/game/game.html',

        title=title,
        meta=Meta(
            title=title,
            image_url=url_for('overwatch.game.game_card_png', key=key, _external=True) + f'?_cachebust={imagehash}',
            twitter_image_url=url_for('overwatch.game.game_card_png', key=key, _external=True) + f'?height=190&_cachebust={imagehash}',
            summary_large_image=True,
            colour=COLOURS.get(game.result, 'gray')
        ),

        # show_stats=show_stats,
        stat_totals=stat_totals,
        # get_top_heroes=get_top_heroes,
        # get_hero_color=get_hero_color,
        # get_hero_image=get_hero_image,
        # process_stat=process_stat,

        summary=summary,
        game=game,

        show_edit=check_authentication() is None and (summary.user_id == session.user_id or session.superuser),

        dev_info=dev_info,

        OLDEST_SUPPORTED_GAME_VERSION=OLDEST_SUPPORTED_GAME_VERSION,
    )
Exemple #3
0
def game(key: str):
    try:
        summary = ApexGameSummary.get(key)
    except ApexGameSummary.DoesNotExist:
        return 'Game does not exist', 404
    logger.info(f'Fetching {summary.url}')

    try:
        url = urlparse(summary.url)
        game_object = s3.get_object(Bucket=url.netloc.split('.')[0],
                                    Key=url.path[1:])
        game_data = json.loads(game_object['Body'].read())
    except:
        game_object = None
        logger.exception('Failed to fetch game data from S3 - trying HTTP')
        r = requests.get(summary.url)
        r.raise_for_status()
        game_data = r.json()

    game_data = compat_game_data(game_data)
    game = referenced_typedload.load(game_data, ApexGame)

    # used for link previews
    og_description = make_game_description(summary, divider='\n')
    meta = Meta(
        title=
        f'{game.squad.player.name} placed #{summary.placed}',  # TODO: find another way of getting the name,
        description=og_description,
        colour={
            1: '#ffdf00',
            2: '#ef20ff',
            3: '#d95ff'
        }.get(summary.placed, '#992e26'),
        image_url=image_url(game.squad.player.champion))

    scrim_details = None
    if summary.scrims and summary.match_id and game.match_id:
        champion_name = (game.champion or
                         {}).get('ocr_name') or summary.match_id.split('/')[1]
        matching_games = []
        for match_id in game.match_ids:
            logger.info(
                f'Checking for matching scrims with match_id={match_id}')
            for other_game in ApexGameSummary.match_id_index.query(
                    match_id,
                (ApexGameSummary.scrims == summary.scrims
                 )  # & (ApexGameSummary.key != summary.key)
            ):
                if not any(
                        any(other_game.key == g.key for g in gs)
                        for gs in matching_games):
                    for gamesets in matching_games:
                        if any(g.placed == other_game.placed
                               for g in gamesets):
                            gamesets.append(other_game)
                            break
                    else:
                        matching_games.append([other_game])

        # TODO: dedupe
        # for g in matching_games:
        #     g.player_name = ' / '.join(filter(None, [g.player_name] + list(g.squadmate_names or ())))
        scrim_details = ScrimDetails(
            champion_name,
            'Mendo Scrims (Beta)',
            sorted(matching_games, key=lambda gs: gs[0].placed),
        )
    logger.info(f'Scrim details: {scrim_details}')

    if logs and check_authentication(
    ) is None and session.superuser and game_object:
        try:
            admin_data = get_admin_data(summary, game_object)
        except:
            logger.exception('Failed to get admin data for game')
            admin_data = None
    else:
        admin_data = None

    return render_template('apex/game/game.html',
                           summary=summary,
                           game=game,
                           is_ranked=summary.rank is not None,
                           scrim_details=scrim_details,
                           meta=meta,
                           admin_data=admin_data)
Exemple #4
0
import os

from overtrack_web.data import apex_data, overwatch_data
from overtrack_web.data.apex_data import ApexRankSummary, ApexSeason
from overtrack_web.lib.opengraph import Meta

CDN_URL = os.environ.get('CDN_URL', 'https://cdn.overtrack.gg/static')

WELCOME_META = Meta(
    title='Apex Legends Automatic Match History',
    description=
    '''Automatically track your Apex Legends games with computer vision!
Tracks your rank, placement, kills, downs, route, weapons, and stats.''',
    image_url=f'{CDN_URL}/apex_teaser.png',
    summary_large_image=True,
    oembed=f'{CDN_URL}/oembed.json')
import os

from overtrack_web.data import apex_data, overwatch_data
from overtrack_web.data.apex_data import ApexRankSummary, ApexSeason
from overtrack_web.lib.opengraph import Meta

CDN_URL = os.environ.get('CDN_URL', 'https://cdn.overtrack.gg/static')

WELCOME_META = Meta(
    title='Match History for Overwatch, Valorant, and Apex Legends',
    description=(
        'Automatically track your Overwatch, Valorant, and Apex Legends games with computer vision.\n '
        'Get full match history with details on everything that happened over the course of your games; '
        'kills, deaths, winrate statistics, composition, ults (Overwatch, Valorant), and map route + circles (Apex Legends)'
    ),
    image_url=f'{CDN_URL}/images/teaser_ow_val.jpg',
    summary_large_image=True,
    oembed=f'{CDN_URL}/oembed.json'
)

VALORANT_WELCOME_META = Meta(
    title='Match History for Valorant, Overwatch, and Apex Legends',
    description=(
        'Automatically track your Valorant games with computer vision.\n '
        'Get full match history with details on everything that happened over the course of your games; '
        'rounds, kills, deaths, ults, agent/map winrates, and more.'
    ),
    image_url=f'{CDN_URL}/images/valorant_teaser.png',
    summary_large_image=True,
    oembed=f'{CDN_URL}/oembed.json'
)
def render_games_list(user: User,
                      public=False,
                      meta_title: Optional[str] = None) -> FlaskResponse:
    user.refresh()
    games_it, is_ranked, season = get_games(user, limit=PAGINATION_SIZE)
    games, next_from = paginate(games_it,
                                username=user.username if public else None)

    from pprint import pprint
    pprint([g.season for g in games])

    if not len(games):
        logger.info(f'User {user.username} has no games')
        if not public and 'season' not in request.args:
            return render_template('client.html',
                                   no_games_alert=True,
                                   meta=WELCOME_META)

    # TODO: don't list ranked/unranked if a player has e.g. no ranked games in a season
    seasons = []
    for sid in user.apex_seasons:
        if sid in apex_data.seasons:
            seasons.append(apex_data.seasons[sid])

    logger.info(
        f'User {user.username} has user.apex_seasons={user.apex_seasons} => {seasons}'
    )
    seasons = sorted(seasons, key=lambda s: s.start, reverse=True)

    t0 = time.time()
    if len(games) and games[0].url:
        try:
            url = urlparse(games[0].url)
            game_object = s3.get_object(Bucket=url.netloc.split('.')[0],
                                        Key=url.path[1:])
            latest_game_data = json.loads(game_object['Body'].read())
        except:
            logger.exception('Failed to fetch game data from S3 - trying HTTP')
            r = requests.get(games[0].url)
            r.raise_for_status()
            latest_game_data = r.json()
        latest_game_data = compat_game_data(latest_game_data)
        latest_game = referenced_typedload.load(latest_game_data, ApexGame)
    else:
        latest_game = None
    t1 = time.perf_counter()
    logger.info(f'latest game fetch: {(t1 - t0) * 1000:.2f}ms')

    is_rank_valid = (is_ranked and latest_game and latest_game.rank
                     and latest_game.rank.rp is not None
                     and latest_game.rank.rp_change is not None)
    if is_rank_valid:
        rp = latest_game.rank.rp + latest_game.rank.rp_change
        derived_rank = None
        derived_tier = None
        for rank, (lower, upper) in apex_data.rank_rp.items():
            if lower <= rp < upper:
                derived_rank = rank
                rank_floor, rank_ceil = apex_data.get_tier_window(
                    rp, lower, (upper - lower) // 4)
                if rank != 'apex_predator':
                    division = (upper - lower) // 4
                    tier_ind = (rp - lower) // division
                    derived_tier = ['IV', 'III', 'II', 'I'][tier_ind]
                else:
                    derived_rank = 'apex predator'
                    derived_tier = ''
                    rank_floor = 1000
                    rank_ceil = rp
                break
        rank_summary = ApexRankSummary(rp, rank_floor, rank_ceil, derived_rank,
                                       derived_tier)
    else:
        rank_summary = None

    if is_ranked and len(games):
        rp_data = [
            game.rank.rp for game in reversed(games)
            if game.rank and game.rank.rp
        ]
        if games[0].rank and games[0].rank.rp is not None and games[
                0].rank.rp_change is not None:
            rp_data.append(games[0].rank.rp + games[0].rank.rp_change)
    else:
        rp_data = None

    if public and latest_game:
        # description = f'{len(games)} Season {season.index} games\n'
        description = ''
        if rank_summary:
            description += 'Rank: ' + rank_summary.rank.title()
            if rank_summary.tier:
                description += ' ' + rank_summary.tier
            description += '\n'
        description += f'Last game: {make_game_description(games[0], divider=" / ", include_knockdowns=False)}'
        summary_meta = Meta(
            title=(meta_title or user.username) + "'s Games",
            description=description,
            colour=rank_summary.color if rank_summary else '#992e26',
            image_url=url_for('static',
                              filename=f'images/apex/{games[0].rank.rank}.png')
            if games[0].rank else None)
    else:
        summary_meta = WELCOME_META

    return render_template(
        'apex/games_list/games_list.html',
        title=f"Apex Legends | {user.username}'s Games"
        if public else "My Games",
        games=games,
        next_from=next_from,
        meta=summary_meta,
        season=season,
        seasons=seasons,
        is_ranked=is_ranked,
        rank_summary=rank_summary,
        rp_data=rp_data,
        latest_game=latest_game,
        show_sub_request=not public and not session.user.subscription_active,
    )