]> de.git.xonotic.org Git - xonotic/xonstat.git/commitdiff
Merge branch 'approved' of gitorious.org:xonotic/xonstat into approved
authorJan Behrens <zykure@web.de>
Wed, 16 Jan 2013 18:47:01 +0000 (19:47 +0100)
committerJan Behrens <zykure@web.de>
Wed, 16 Jan 2013 18:47:01 +0000 (19:47 +0100)
xonstat/batch/badges/gen_badges.py
xonstat/batch/badges/img/background_archer-v2.png [new file with mode: 0644]
xonstat/batch/badges/img/background_archer-v3.png [new file with mode: 0644]
xonstat/batch/badges/playerdata.py
xonstat/batch/badges/skin.py

index 44d73aec3da4f1ea2a16690cf9e965c954777b33..2f94920ede9b614324a2e6cbed02c2c66ff2b812 100644 (file)
@@ -19,6 +19,9 @@ NUM_PLAYERS = None
 # we look for players who have activity within the past DELTA hours
 DELTA = 6
 
+VERBOSE = False
+
+INIFILE = None  # keep this set to "None"
 
 # classic skin WITHOUT NAME - writes PNGs into "output//###.png"
 skin_classic = Skin( "",
@@ -28,8 +31,21 @@ skin_classic = Skin( "",
 
 # more fancy skin [** WIP **]- writes PNGs into "output/archer/###.png"
 skin_archer = Skin( "archer",
-        bg              = "background_archer-v1",
-        overlay         = None,
+        #bg              = "background_archer-v2_full",
+        bg              = "background_archer-v3",
+        overlay         = "",
+        nick_maxwidth  = 265,
+        gametype_pos    = (91,33),
+        nostats_pos            = (91,59),
+        elo_pos        = (91,47),
+        rank_pos       = (91,58),
+        winp_pos       = (509,20),
+        wins_pos       = (508,35),
+        loss_pos       = (508,45),
+        kdr_pos                = (392,20),
+        kills_pos      = (392,35),
+        deaths_pos     = (392,45),
+        ptime_color    = (0.05, 0.05, 0.1),
     )
 
 # minimal skin - writes PNGs into "output/minimal/###.png"
@@ -90,12 +106,17 @@ 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]
+            print """Usage:  gen_badges.py [options] <ini-file> [skin list]
     Options:
         -force      Force updating all badges (delta = 2^24)
         -test       Limit number of players to 100 (for testing)
+        -verbose    Show more verbose output
         -help       Show this help text
+    Ini-File:
+        Name of a Pyramid ini-file to use (e.g. prodution.ini or development.ini).
     Skin list:
         Space-separated list of skins to use when creating badges.
         Available skins:  classic, minimal, archer
@@ -104,18 +125,25 @@ for arg in sys.argv[1:]:
 """
             sys.exit(-1)
     else:
-        if arg == "classic":
-            skins.append(skin_classic)
-        elif arg == "minimal":
-            skins.append(skin_minimal)
-        elif arg == "archer":
-            skins.append(skin_archer)
+        if INIFILE == None:
+            INIFILE = arg
+        else:
+            if arg == "classic":
+                skins.append(skin_classic)
+            elif arg == "minimal":
+                skins.append(skin_minimal)
+            elif arg == "archer":
+                       skins.append(skin_archer)
 
 if len(skins) == 0:
-    skins = [ skin_classic, skin_minimal ]
+    skins = [ skin_classic, skin_minimal, skin_archer ]
+
+if not INIFILE:
+    print "You must provide the name of an ini-file to use! Type 'gen_badges.py -h' for help."
+    sys.exit(-1)
 
 # environment setup
-env = bootstrap('../../../development.ini')
+env = bootstrap(INIFILE)
 req = env['request']
 req.matchdict = {'id':3}
 
@@ -142,7 +170,7 @@ else:
             filter(Player.active_ind == True).\
             all()
 
-playerdata = PlayerData()
+playerdata = PlayerData
 
 if len(players) > 0:
     stop = datetime.now()
@@ -163,11 +191,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/img/background_archer-v2.png b/xonstat/batch/badges/img/background_archer-v2.png
new file mode 100644 (file)
index 0000000..0ae73bd
Binary files /dev/null and b/xonstat/batch/badges/img/background_archer-v2.png differ
diff --git a/xonstat/batch/badges/img/background_archer-v3.png b/xonstat/batch/badges/img/background_archer-v3.png
new file mode 100644 (file)
index 0000000..75b2483
Binary files /dev/null and b/xonstat/batch/badges/img/background_archer-v3.png differ
index 0990208f2e23af8044e5e050531602f224e203bb..e5b4046a7249f14a88e214ca9b199cc993f4ef6e 100644 (file)
@@ -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,
             }
+         
 
index 813594df2567cf560231bee4103556474cd991e7..3439a69400674360831b5763a2534a1db8a0aca3 100644 (file)
@@ -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
@@ -275,8 +289,15 @@ class Skin:
             break
 
         # determine width of single whitespace for later use
-        xoff, yoff, tw, th = ctx.text_extents("_")[:4]
+        xoff, yoff, tw, th = ctx.text_extents("_ _")[:4]
         space_w = tw
+        xoff, yoff, tw, th = ctx.text_extents("__")[:4]
+        space_w -= tw
+
+        # this hilarious code should determine the spacing between characters
+        sep_w = 0.25*space_w
+        if sep_w <= 0:
+            sep_w = 1
 
         # split nick into colored segments
         xoffset = 0
@@ -314,16 +335,16 @@ 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 + 2
+            xoffset += tw + sep_w
 
         ## print elos and ranks
         
         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
@@ -340,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
 
@@ -384,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]
@@ -427,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]