From 50f599f2cea1ec585dbcd93c843077be4605a1fe Mon Sep 17 00:00:00 2001 From: Jan Behrens Date: Mon, 1 Oct 2012 21:48:47 +0200 Subject: [PATCH] Moved over to new Xonstat API (using functions xonstat.views.player directly); enabled UTF-8 encoded playernicks for testing (FIXME: it is known that some nicks cause problems with cairo currently) --- xonstat/batch/badges/gen_badges.py | 11 +++- xonstat/batch/badges/playerdata.py | 89 +++++++----------------------- xonstat/batch/badges/skin.py | 74 ++++++++++++++----------- 3 files changed, 71 insertions(+), 103 deletions(-) diff --git a/xonstat/batch/badges/gen_badges.py b/xonstat/batch/badges/gen_badges.py index e3b8c1f..d798547 100644 --- a/xonstat/batch/badges/gen_badges.py +++ b/xonstat/batch/badges/gen_badges.py @@ -19,6 +19,8 @@ NUM_PLAYERS = None # we look for players who have activity within the past DELTA hours DELTA = 6 +VERBOSE = False + # classic skin WITHOUT NAME - writes PNGs into "output//###.png" skin_classic = Skin( "", @@ -103,6 +105,8 @@ for arg in sys.argv[1:]: DELTA = 2**24 # large enough to enforce update, and doesn't result in errors elif arg == "test": NUM_PLAYERS = 100 + elif arg == "verbose": + VERBOSE = True else: print """Usage: gen_badges.py [options] [skin list] Options: @@ -155,7 +159,7 @@ else: filter(Player.active_ind == True).\ all() -playerdata = PlayerData() +playerdata = PlayerData if len(players) > 0: stop = datetime.now() @@ -176,11 +180,14 @@ if len(players) > 0: sstart = datetime.now() for sk in skins: - sk.render_image(playerdata, "output/%s/%d.png" % (str(sk), player_id[0])) + sk.render_image(playerdata.data, "output/%s/%d.png" % (str(sk), player_id[0])) sstop = datetime.now() td = sstop-sstart render_time += datetime_seconds(td) + if VERBOSE == True: + print player_id, unicode(playerdata.data['player'].nick) + stop = datetime.now() td = stop-start total_seconds = datetime_seconds(td) diff --git a/xonstat/batch/badges/playerdata.py b/xonstat/batch/badges/playerdata.py index 0990208..e5b4046 100644 --- a/xonstat/batch/badges/playerdata.py +++ b/xonstat/batch/badges/playerdata.py @@ -1,6 +1,7 @@ import sqlalchemy as sa import sqlalchemy.sql.functions as func from xonstat.models import * +from xonstat.views.player import get_games_played, get_overall_stats, get_ranks, get_elos class PlayerData: @@ -16,6 +17,7 @@ class PlayerData: return self.data[key] return None + @classmethod def get_data(self, player_id): """Return player data as dict. @@ -25,87 +27,34 @@ class PlayerData: # total games # wins/losses # kills/deaths + # duel/dm/tdm/ctf elo + rank + player = DBSession.query(Player).filter_by(player_id=player_id).\ + filter(Player.active_ind == True).one() + games_played = get_games_played(player_id) + overall_stats = get_overall_stats(player_id) + ranks = get_ranks(player_id) + elos = get_elos(player_id) - player = DBSession.query(Player).filter(Player.player_id == player_id).one() - - games_played = DBSession.query( - Game.game_type_cd, func.count(), func.sum(PlayerGameStat.alivetime)).\ - filter(Game.game_id == PlayerGameStat.game_id).\ - filter(PlayerGameStat.player_id == player_id).\ - group_by(Game.game_type_cd).\ - order_by(func.count().desc()).\ - all() - - total_stats = {} - total_stats['games'] = 0 - total_stats['games_breakdown'] = {} # this is a dictionary inside a dictionary .. dictception? - total_stats['games_alivetime'] = {} - total_stats['gametypes'] = [] - for (game_type_cd, games, alivetime) in games_played: - total_stats['games'] += games - total_stats['gametypes'].append(game_type_cd) - total_stats['games_breakdown'][game_type_cd] = games - total_stats['games_alivetime'][game_type_cd] = alivetime - - (total_stats['kills'], total_stats['deaths'], total_stats['alivetime'],) = DBSession.query( - func.sum(PlayerGameStat.kills), - func.sum(PlayerGameStat.deaths), - func.sum(PlayerGameStat.alivetime)).\ - filter(PlayerGameStat.player_id == player_id).\ - one() - - (total_stats['wins'], total_stats['losses']) = DBSession.\ - query("wins", "losses").\ - from_statement( - "SELECT SUM(win) wins, SUM(loss) losses " - "FROM (SELECT g.game_id, " - " CASE " - " WHEN g.winner = pgs.team THEN 1 " - " WHEN pgs.rank = 1 THEN 1 " - " ELSE 0 " - " END win, " - " CASE " - " WHEN g.winner = pgs.team THEN 0 " - " WHEN pgs.rank = 1 THEN 0 " - " ELSE 1 " - " END loss " - " FROM games g, " - " player_game_stats pgs " - " WHERE g.game_id = pgs.game_id " - " AND pgs.player_id = :player_id) win_loss").\ - params(player_id=player_id).one() - - ranks = DBSession.query("game_type_cd", "rank", "max_rank").\ - from_statement( - "SELECT pr.game_type_cd, pr.rank, overall.max_rank " - "FROM player_ranks pr, " - " (SELECT game_type_cd, max(rank) max_rank " - " FROM player_ranks " - " GROUP BY game_type_cd) overall " - "WHERE pr.game_type_cd = overall.game_type_cd " - " AND player_id = :player_id " - "ORDER BY rank").\ - params(player_id=player_id).all() + games_played_dict = {} + for game in games_played: + games_played_dict[game.game_type_cd] = game ranks_dict = {} - for gtc,rank,max_rank in ranks: - ranks_dict[gtc] = (rank, max_rank) - - elos = DBSession.query(PlayerElo).\ - filter_by(player_id=player_id).\ - order_by(PlayerElo.elo.desc()).\ - all() + for gt,rank in ranks.items(): + ranks_dict[gt] = (rank.rank, rank.max_rank) elos_dict = {} - for elo in elos: + for gt,elo in elos.items(): if elo.games >= 32: - elos_dict[elo.game_type_cd] = elo.elo + elos_dict[gt] = elo.elo self.data = { 'player':player, - 'total_stats':total_stats, + 'games_played':games_played_dict, + 'overall_stats':overall_stats, 'ranks':ranks_dict, 'elos':elos_dict, } + diff --git a/xonstat/batch/badges/skin.py b/xonstat/batch/badges/skin.py index b01e42d..3439a69 100644 --- a/xonstat/batch/badges/skin.py +++ b/xonstat/batch/badges/skin.py @@ -190,15 +190,29 @@ class Skin: """Render an image for the given player id.""" # setup variables - - player = data.player - elos = data.elos - ranks = data.ranks - #games = data.total_stats['games'] - wins, losses = data.total_stats['wins'], data.total_stats['losses'] - games = wins + losses - kills, deaths = data.total_stats['kills'], data.total_stats['deaths'] - alivetime = data.total_stats['alivetime'] + + player = data['player'] + elos = data['elos'] + ranks = data['ranks'] + games_played = data['games_played']['overall'] + overall_stats = data['overall_stats']['overall'] + + wins, losses, win_pct = games_played.wins, games_played.losses, games_played.win_pct + games = games_played.games + kills, deaths, kd_ratio = overall_stats.total_kills, overall_stats.total_deaths, overall_stats.k_d_ratio + alivetime = overall_stats.total_playing_time + + # make sorted list of gametypes + game_types = [] + num_games = 0 + for gt,info in data['games_played'].items(): + if gt == "overall": + continue + if info.games > num_games: + game_types.insert(0, gt) + else: + game_types.append(gt) + # build image @@ -255,12 +269,12 @@ class Skin: # deocde nick, strip all weird-looking characters qstr = qfont_decode(player.nick).replace('^^', '^').replace(u'\x00', '') - chars = [] - for c in qstr: - # replace weird characters that make problems - TODO - if ord(c) < 128: - chars.append(c) - qstr = ''.join(chars) + #chars = [] + #for c in qstr: + # # replace weird characters that make problems - TODO + # if ord(c) < 128: + # chars.append(c) + #qstr = ''.join(chars) stripped_nick = strip_colors(qstr.replace(' ', '_')) # fontsize is reduced if width gets too large @@ -283,7 +297,7 @@ class Skin: # this hilarious code should determine the spacing between characters sep_w = 0.25*space_w if sep_w <= 0: - sep_w = 1 + sep_w = 1 # split nick into colored segments xoffset = 0 @@ -321,7 +335,7 @@ class Skin: xoff, yoff, tw, th = ctx.text_extents(txt)[:4] ctx.set_source_rgb(r, g, b) ctx.move_to(self.nick_pos[0] + xoffset - xoff, self.nick_pos[1]) - ctx.show_text(txt) + ctx.show_text(txt.encode("utf-8")) tw += (len(txt)-len(txt.strip())) * space_w # account for lost whitespaces xoffset += tw + sep_w @@ -330,7 +344,7 @@ class Skin: xoffset, yoffset = 0, 0 count = 0 - for gt in data.total_stats['gametypes'][:self.num_gametypes]: + for gt in game_types[:self.num_gametypes]: if not elos.has_key(gt) or not ranks.has_key(gt): continue count += 1 @@ -347,7 +361,7 @@ class Skin: yoffset += 0.5 * diff * self.gametype_height # show a number gametypes the player has participated in - for gt in data.total_stats['gametypes'][:self.num_gametypes]: + for gt in game_types[:self.num_gametypes]: if not elos.has_key(gt) or not ranks.has_key(gt): continue @@ -391,19 +405,18 @@ class Skin: txt = "???" try: - ratio = float(wins)/games - txt = "%.2f%%" % round(ratio * 100, 2) + txt = "%.2f%%" % round(win_pct * 100, 2) except: - ratio = 0 + win_pct = 0 if self.winp_pos: - if ratio >= 0.5: - nr = 2*(ratio-0.5) + if win_pct >= 0.5: + nr = 2*(win_pct-0.5) r = nr*self.winp_colortop[0] + (1-nr)*self.winp_colormid[0] g = nr*self.winp_colortop[1] + (1-nr)*self.winp_colormid[1] b = nr*self.winp_colortop[2] + (1-nr)*self.winp_colormid[2] else: - nr = 2*ratio + nr = 2*win_pct r = nr*self.winp_colormid[0] + (1-nr)*self.winp_colorbot[0] g = nr*self.winp_colormid[1] + (1-nr)*self.winp_colorbot[1] b = nr*self.winp_colormid[2] + (1-nr)*self.winp_colorbot[2] @@ -434,21 +447,20 @@ class Skin: txt = "???" try: - ratio = float(kills)/deaths - txt = "%.3f" % round(ratio, 3) + txt = "%.3f" % round(kd_ratio, 3) except: - ratio = 0 + kd_ratio = 0 if self.kdr_pos: - if ratio >= 1.0: - nr = ratio-1.0 + if kd_ratio >= 1.0: + nr = kd_ratio-1.0 if nr > 1: nr = 1 r = nr*self.kdr_colortop[0] + (1-nr)*self.kdr_colormid[0] g = nr*self.kdr_colortop[1] + (1-nr)*self.kdr_colormid[1] b = nr*self.kdr_colortop[2] + (1-nr)*self.kdr_colormid[2] else: - nr = ratio + nr = kd_ratio r = nr*self.kdr_colormid[0] + (1-nr)*self.kdr_colorbot[0] g = nr*self.kdr_colormid[1] + (1-nr)*self.kdr_colorbot[1] b = nr*self.kdr_colormid[2] + (1-nr)*self.kdr_colorbot[2] -- 2.39.2