From 8e1fddf8910ef9fcef7af4c5ec6747e914757063 Mon Sep 17 00:00:00 2001 From: antzucaro Date: Sun, 30 Dec 2012 11:40:55 -0500 Subject: [PATCH] Add a plain text hashkey view for menu integration. This adds a plain text response view at the URL /player/, where hashkey is the idfp of a given player. The response is quite lengthy and won't be specified in this message, but suffice to say that the response roughly corresponds to the player_info JSON view currently at /player/.json. --- xonstat/__init__.py | 7 +- .../templates/player_hashkey_info_text.mako | 61 +++++++++++ xonstat/views/__init__.py | 2 +- xonstat/views/player.py | 100 +++++++++++------- 4 files changed, 126 insertions(+), 44 deletions(-) create mode 100644 xonstat/templates/player_hashkey_info_text.mako diff --git a/xonstat/__init__.py b/xonstat/__init__.py index a18a6a1..d4ccfde 100644 --- a/xonstat/__init__.py +++ b/xonstat/__init__.py @@ -44,8 +44,11 @@ def main(global_config, **settings): config.add_view(player_info, route_name="player_info", renderer="player_info.mako") config.add_view(player_info_json, route_name="player_info_json", renderer="jsonp") - config.add_route("player_hashkey_info_json", "/hashkey/{hashkey}") - config.add_view(player_hashkey_info_json, route_name="player_hashkey_info_json", renderer="jsonp") + config.add_route("player_hashkey_info_text", "/hashkey/{hashkey}") + config.add_view(player_hashkey_info_text, route_name="player_hashkey_info_text", renderer="player_hashkey_info_text.mako") + + #config.add_route("player_hashkey_info_json", "/hashkey/{hashkey}.json") + #config.add_view(player_hashkey_info_json, route_name="player_hashkey_info_json", renderer="jsonp") config.add_route("player_elo_info_json", "/elo/{hashkey}") config.add_view(player_elo_info_json, route_name="player_elo_info_json", renderer="jsonp") diff --git a/xonstat/templates/player_hashkey_info_text.mako b/xonstat/templates/player_hashkey_info_text.mako new file mode 100644 index 0000000..6d47e44 --- /dev/null +++ b/xonstat/templates/player_hashkey_info_text.mako @@ -0,0 +1,61 @@ +V 1 +R XonStat/1.0 +T ${now} +S ${request.route_url('player_info', id=player.player_id)} +P ${hashkey} +n ${player.nick} +i ${player.player_id} +# NOTE: using unixtime here +e joined ${player_joined} +% if player.active_ind == True: +e active-ind 1 +% else: +e active-ind 0 +% endif +e location +% if 'overall' in elos.keys(): +# NOTE: need game type here to specify which elo is being shown as "best" +e elo ${elos['overall'].elo} ${elos['overall'].game_type_cd} +% endif +% if 'overall' in ranks.keys(): +# NOTE: need game type here to specify which percentile is being shown as "best" +e percentile ${ranks['overall'].percentile} ${ranks['overall'].game_type_cd} +% endif +e matches ${games_played[0].games} +% if 'overall' in ranks.keys(): +# NOTE: need game type here to specify which rank is being shown as "best" +e rank ${ranks['overall'].rank} ${ranks['overall'].game_type_cd} +% endif +e total-deaths ${overall_stats['overall'].total_deaths} +e total-fckills ${overall_stats['overall'].total_carrier_frags} +e alivetime ${overall_stats['overall'].total_playing_time_secs} +e total-kills ${overall_stats['overall'].total_kills} +e wins ${games_played[0].wins} +e favorite-map ${fav_maps['overall'].map_name} ${fav_maps['overall'].times_played} ${fav_maps['overall'].game_type_cd} +% for game_type_cd in overall_stats.keys(): +{ G ${game_type_cd} +% if game_type_cd in elos.keys(): +e elo ${elos[game_type_cd].elo} +% endif +% if game_type_cd in ranks.keys(): +e percentile ${ranks[game_type_cd].percentile} +% endif +% for gp in games_played: +% if gp.game_type_cd == game_type_cd: +e matches ${gp.games} +% endif +% endfor +% if game_type_cd in ranks.keys(): +e rank ${ranks[game_type_cd].rank} +% endif +e total-deaths ${overall_stats[game_type_cd].total_deaths} +e alivetime ${overall_stats[game_type_cd].total_playing_time_secs} +e total-kills ${overall_stats[game_type_cd].total_kills} +% for gp in games_played: +% if gp.game_type_cd == game_type_cd: +e wins ${gp.wins} +% endif +% endfor +e favorite-map ${fav_maps[game_type_cd].map_name} ${fav_maps[game_type_cd].times_played} +} +% endfor diff --git a/xonstat/views/__init__.py b/xonstat/views/__init__.py index ac029db..0d9fd13 100644 --- a/xonstat/views/__init__.py +++ b/xonstat/views/__init__.py @@ -4,7 +4,7 @@ from xonstat.views.player import player_accuracy from xonstat.views.player import player_index_json, player_info_json from xonstat.views.player import player_game_index_json, player_accuracy_json from xonstat.views.player import player_damage_json, player_hashkey_info_json -from xonstat.views.player import player_elo_info_json +from xonstat.views.player import player_hashkey_info_text, player_elo_info_json from xonstat.views.game import game_index, game_info, rank_index from xonstat.views.game import game_index_json, game_info_json, rank_index_json diff --git a/xonstat/views/player.py b/xonstat/views/player.py index d773e13..8514260 100644 --- a/xonstat/views/player.py +++ b/xonstat/views/player.py @@ -12,7 +12,7 @@ from pyramid.url import current_route_url from sqlalchemy import desc, distinct from webhelpers.paginate import Page, PageURL from xonstat.models import * -from xonstat.util import page_url, to_json, pretty_date +from xonstat.util import page_url, to_json, pretty_date, datetime_seconds from xonstat.views.helpers import RecentGame, recent_games_q log = logging.getLogger(__name__) @@ -135,6 +135,7 @@ def get_overall_stats(player_id): - last_played_epoch (same as above, but in seconds since epoch) - last_played_fuzzy (same as above, but in relative date) - total_playing_time (total amount of time played the game type) + - total_playing_time_secs (same as the above, but in seconds) - total_pickups (ctf only) - total_captures (ctf only) - cap_ratio (ctf only) @@ -146,7 +147,7 @@ def get_overall_stats(player_id): """ OverallStats = namedtuple('OverallStats', ['total_kills', 'total_deaths', 'k_d_ratio', 'last_played', 'last_played_epoch', 'last_played_fuzzy', - 'total_playing_time', 'total_pickups', 'total_captures', 'cap_ratio', + 'total_playing_time', 'total_playing_time_secs', 'total_pickups', 'total_captures', 'cap_ratio', 'total_carrier_frags', 'game_type_cd']) raw_stats = DBSession.query('game_type_cd', 'total_kills', @@ -166,28 +167,25 @@ def get_overall_stats(player_id): "WHERE g.game_id = pgs.game_id " "AND pgs.player_id = :player_id " "GROUP BY g.game_type_cd " + "UNION " + "SELECT 'overall' game_type_cd, " + "Sum(pgs.kills) total_kills, " + "Sum(pgs.deaths) total_deaths, " + "Max(pgs.create_dt) last_played, " + "Sum(pgs.alivetime) total_playing_time, " + "Sum(pgs.pickups) total_pickups, " + "Sum(pgs.captures) total_captures, " + "Sum(pgs.carrier_frags) total_carrier_frags " + "FROM games g, " + "player_game_stats pgs " + "WHERE g.game_id = pgs.game_id " + "AND pgs.player_id = :player_id " ).params(player_id=player_id).all() # to be indexed by game_type_cd overall_stats = {} - # sums for the "overall" game type (which is fake) - overall_kills = 0 - overall_deaths = 0 - overall_last_played = None - overall_playing_time = datetime.timedelta(seconds=0) - overall_carrier_frags = 0 - for row in raw_stats: - # running totals or mins - overall_kills += row.total_kills or 0 - overall_deaths += row.total_deaths or 0 - - if overall_last_played is None or row.last_played > overall_last_played: - overall_last_played = row.last_played - - overall_playing_time += row.total_playing_time - # individual gametype ratio calculations try: k_d_ratio = float(row.total_kills)/row.total_deaths @@ -199,8 +197,6 @@ def get_overall_stats(player_id): except: cap_ratio = None - overall_carrier_frags += row.total_carrier_frags or 0 - # everything else is untouched or "raw" os = OverallStats(total_kills=row.total_kills, total_deaths=row.total_deaths, @@ -209,6 +205,7 @@ def get_overall_stats(player_id): last_played_epoch=timegm(row.last_played.timetuple()), last_played_fuzzy=pretty_date(row.last_played), total_playing_time=row.total_playing_time, + total_playing_time_secs=int(datetime_seconds(row.total_playing_time)), total_pickups=row.total_pickups, total_captures=row.total_captures, cap_ratio=cap_ratio, @@ -217,27 +214,6 @@ def get_overall_stats(player_id): overall_stats[row.game_type_cd] = os - # and lastly, the overall stuff - try: - overall_k_d_ratio = float(overall_kills)/overall_deaths - except: - overall_k_d_ratio = None - - os = OverallStats(total_kills=overall_kills, - total_deaths=overall_deaths, - k_d_ratio=overall_k_d_ratio, - last_played=overall_last_played, - last_played_epoch=timegm(overall_last_played.timetuple()), - last_played_fuzzy=pretty_date(overall_last_played), - total_playing_time=overall_playing_time, - total_pickups=None, - total_captures=None, - cap_ratio=None, - total_carrier_frags=overall_carrier_frags, - game_type_cd='overall') - - overall_stats['overall'] = os - return overall_stats @@ -773,6 +749,7 @@ def player_hashkey_info_data(request): ranks = None return {'player':player, + 'hashkey':hashkey, 'games_played':games_played, 'overall_stats':overall_stats, 'fav_maps':fav_maps, @@ -822,6 +799,47 @@ def player_hashkey_info_json(request): }] +def player_hashkey_info_text(request): + """ + Provides detailed information on a specific player. Plain text. + """ + # UTC epoch + now = timegm(datetime.datetime.utcnow().timetuple()) + + # All player_info fields are converted into JSON-formattable dictionaries + player_info = player_hashkey_info_data(request) + + # gather all of the data up into aggregate structures + player = player_info['player'] + games_played = player_info['games_played'] + overall_stats = player_info['overall_stats'] + elos = player_info['elos'] + ranks = player_info['ranks'] + fav_maps = player_info['fav_maps'] + + # one-offs for things needing conversion for text/plain + player_joined = timegm(player.create_dt.timetuple()) + alivetime = int(datetime_seconds(overall_stats['overall'].total_playing_time)) + + # this is a plain text response, if we don't do this here then + # Pyramid will assume html + request.response.content_type = 'text/plain' + + return { + 'version': 1, + 'now': now, + 'player': player, + 'hashkey': player_info['hashkey'], + 'player_joined': player_joined, + 'games_played': games_played, + 'overall_stats': overall_stats, + 'alivetime': alivetime, + 'fav_maps': fav_maps, + 'elos': elos, + 'ranks': ranks, + } + + def player_elo_info_data(request): """ Provides elo information on a specific player. Raw data is returned. -- 2.39.2