]> git.rm.cloudns.org Git - xonotic/xonstat.git/commitdiff
Added multiple skin support and better commandline parsing
authorJan D. Behrens <zykure@web.de>
Wed, 29 Aug 2012 10:58:31 +0000 (12:58 +0200)
committerJan D. Behrens <zykure@web.de>
Wed, 29 Aug 2012 11:07:05 +0000 (13:07 +0200)
- Skins other than "classic" will be put into a subdir in the output directory (e.g. output/minimal/###.png)
- By default, "classic" and "minimal" badges are created for all players that were active in the last 6 hours
- A skin list can be passed to the program for testing (e.g. "gen_badges.py classic archer")
- The "-force" parameter enforces an update of all badges by setting delta to 2^24 hours
- The "-test" parameter limits the number of players to be considered to 200 (used for testing)

xonstat/batch/badges/gen_badges.py
xonstat/batch/badges/output/_dummy_ [new file with mode: 0644]
xonstat/batch/badges/output/minimal/_dummy_ [new file with mode: 0644]
xonstat/batch/badges/render.py

index f556ab3d89a1a59fa633ff1e6604a480760353ed..dcb6a1e9db848557d7db4141fc230a0be57abc73 100644 (file)
@@ -8,26 +8,29 @@ from sqlalchemy import distinct
 from pyramid.paster import bootstrap
 from xonstat.models import *
 
-from render import Skin
+from render import PlayerData, Skin
 
 
 # maximal number of query results (for testing, set to 0 to get all)
-#NUM_PLAYERS = 200
+NUM_PLAYERS = None
 
 # we look for players who have activity within the past DELTA hours
 DELTA = 6
 
 
-skin_classic = Skin(
+# classic skin WITHOUT NAME - writes PNGs into "output//###.png"
+skin_classic = Skin( "",
         bg              = "asfalt",
     )
 
-skin_archer = Skin(
+# more fancy skin [** WIP **]- writes PNGs into "output/archer/###.png"
+skin_archer = Skin( "archer",
         bg              = "background_archer-v1",
         overlay         = "",
     )
 
-skin_minimal = Skin(
+# minimal skin - writes PNGs into "output/minimal/###.png"
+skin_minimal = Skin( "minimal",
         bg              = None,
         bgcolor         = (0.04, 0.04, 0.04, 1.0),
         overlay         = "overlay_minimal",
@@ -57,15 +60,38 @@ skin_minimal = Skin(
     )
 
 # parse cmdline parameters (for testing)
-skin = skin_classic
-if len(sys.argv) > 1:
-    arg = sys.argv[1].lower()
-    if arg == "classic":
-        skin = skin_classic
-    elif arg == "minimal":
-        skin = skin_minimal
-    elif arg == "archer":
-        skin = skin_archer
+
+skins = []
+for arg in sys.argv[1:]:
+    if arg.startswith("-"):
+        arg = arg[1:]
+        if arg == "force":
+            DELTA = 2**24   # large enough to enforce update, and doesn't result in errors
+        elif arg == "test":
+            NUM_PLAYERS = 200
+        else:
+            print """Usage:  gen_badges.py [options] [skin list]
+    Options:
+        -force      Force updating all badges (delta = 2^24)
+        -testing    Limit number of players to 200 (for testing)
+        -help       Show this help text
+    Skin list:
+        Space-separated list of skins to use when creating badges.
+        Available skins:  classic, minimal, archer
+        If no skins are given, classic and minmal will be used by default.
+        NOTE: Output directories must exists before running the program!
+"""
+        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 len(skins) == 0:
+    skins = [ skin_classic, skin_minimal ]
 
 
 # environment setup
@@ -77,7 +103,7 @@ print "Requesting player data from db ..."
 cutoff_dt = datetime.utcnow() - timedelta(hours=DELTA)
 start = datetime.now()
 players = []
-if locals().has_key('NUM_PLAYERS'):
+if NUM_PLAYERS:
     players = DBSession.query(distinct(Player.player_id)).\
             filter(Player.player_id == PlayerElo.player_id).\
             filter(Player.player_id == PlayerGameStat.player_id).\
@@ -96,6 +122,8 @@ else:
             filter(Player.active_ind == True).\
             all()
 
+playerdata = PlayerData()
+
 if len(players) > 0:
     stop = datetime.now()
     td = stop-start
@@ -109,24 +137,25 @@ if len(players) > 0:
         req.matchdict['id'] = player_id
 
         sstart = datetime.now()
-        skin.get_data(player_id)
+        playerdata.get_data(player_id)
         sstop = datetime.now()
         td = sstop-sstart
-        total_seconds = (td.microseconds + (td.seconds + td.days * 24 * 3600) * 10**6) / 10**6
+        total_seconds = float(td.microseconds + (td.seconds + td.days * 24 * 3600) * 10**6) / 10**6
         data_time += total_seconds
 
         sstart = datetime.now()
-        skin.render_image("output/%d.png" % player_id)
+        for sk in skins:
+            sk.render_image(playerdata, "output/%s/%d.png" % (str(sk), player_id[0]))
         sstop = datetime.now()
         td = sstop-sstart
-        total_seconds = (td.microseconds + (td.seconds + td.days * 24 * 3600) * 10**6) / 10**6
+        total_seconds = float(td.microseconds + (td.seconds + td.days * 24 * 3600) * 10**6) / 10**6
         render_time += total_seconds
 
     stop = datetime.now()
     td = stop-start
-    total_seconds = (td.microseconds + (td.seconds + td.days * 24 * 3600) * 10**6) / 10**6
+    total_seconds = float(td.microseconds + (td.seconds + td.days * 24 * 3600) * 10**6) / 10**6
     print "Creating the badges took %.1f seconds (%.3f s per player)" % (total_seconds, total_seconds/float(len(players)))
-    print "Total time for redering images: %.3f s" % render_time
+    print "Total time for rendering images: %.3f s" % render_time
     print "Total time for getting data: %.3f s" % data_time
 
 else:
diff --git a/xonstat/batch/badges/output/_dummy_ b/xonstat/batch/badges/output/_dummy_
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/xonstat/batch/badges/output/minimal/_dummy_ b/xonstat/batch/badges/output/minimal/_dummy_
new file mode 100644 (file)
index 0000000..e69de29
index d0fa9979731f257fbb6ff9d7e353ea8706165af8..685e649a2e7846dbe9a956478608e41280c0ef08 100644 (file)
@@ -47,16 +47,121 @@ def writepng(filename, buf, width, height):
         f.close()
 
 
-class Skin:
+class PlayerData:
 
     # player data, will be filled by get_data()
     data = {}
 
+    def __init__(self):
+        self.data = {}
+
+    def __getattr__(self, key):
+        if self.data.has_key(key):
+            return self.data[key]
+        return None
+
+    def get_data(self, player_id):
+        """Return player data as dict.
+
+        This function is similar to the function in player.py but more optimized
+        for this purpose.
+        """
+        # total games
+        # wins/losses
+        # kills/deaths
+        # duel/dm/tdm/ctf elo + rank
+
+        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()).\
+                limit(3).all()  # limit to 3 gametypes!
+
+        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'],) = DBSession.query(
+    #            func.count("*")).\
+    #            filter(Game.game_id == PlayerGameStat.game_id).\
+    #            filter(PlayerGameStat.player_id == player_id).\
+    #            filter(Game.winner == PlayerGameStat.team or PlayerGameStat.rank == 1).\
+    #            one()
+
+        (total_stats['wins'],) = DBSession.\
+                query("total_wins").\
+                from_statement(
+                    "select count(*) total_wins "
+                    "from games g, player_game_stats pgs "
+                    "where g.game_id = pgs.game_id "
+                    "and player_id=:player_id "
+                    "and (g.winner = pgs.team or pgs.rank = 1)"
+                ).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()
+
+        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()
+
+        elos_dict = {}
+        for elo in elos:
+            if elo.games > 32:
+                elos_dict[elo.game_type_cd] = elo.elo
+
+        self.data = {
+                'player':player,
+                'total_stats':total_stats,
+                'ranks':ranks_dict,
+                'elos':elos_dict,
+            }
+
+
+
+class Skin:
+
     # skin parameters, can be overriden by init
     params = {}
 
-    def __init__(self, **params):
+    # skin name
+    name = ""
+
+    def __init__(self, name, **params):
         # default parameters
+        self.name = name
         self.params = {
             'bg':               "dark_wall",    # None - plain; otherwise use given texture
             'bgcolor':          None,           # transparent bg when bgcolor==None
@@ -131,21 +236,23 @@ class Skin:
             if self.params.has_key(k):
                 self.params[k] = v
 
+    def __str__(self):
+        return self.name
+
     def __getattr__(self, key):
         if self.params.has_key(key):
             return self.params[key]
         return None
 
-    def render_image(self, output_filename):
+    def render_image(self, data, output_filename):
         """Render an image for the given player id."""
 
         # setup variables
 
-        player = self.data['player']
-        total_stats = self.data['total_stats']
-        total_games = total_stats['games']
-        elos  = self.data["elos"]
-        ranks = self.data["ranks"]
+        player      = data.player
+        total_stats = data.total_stats
+        elos        = data.elos
+        ranks       = data.ranks
 
         font = "Xolonium"
         if self.font == 1:
@@ -347,7 +454,8 @@ class Skin:
             ctx.move_to(self.wintext_pos[0]-xoff-tw/2, self.wintext_pos[1]-yoff)
             ctx.show_text(txt)
 
-        wins, losses = total_stats["wins"], total_games-total_stats["wins"]
+        total_games = total_stats['games']
+        wins, losses = total_stats['wins'], total_games-total_stats['wins']
         txt = "???"
         try:
             ratio = float(wins)/total_games
@@ -477,93 +585,3 @@ class Skin:
         imgdata = surf.get_data()
         writepng(output_filename, imgdata, self.width, self.height)
 
-
-    def get_data(self, player_id):
-        """Return player data as dict.
-
-        This function is similar to the function in player.py but more optimized
-        for this purpose.
-        """
-
-        # total games
-        # wins/losses
-        # kills/deaths
-        # duel/dm/tdm/ctf elo + rank
-        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()).\
-                limit(3).all()  # limit to 3 gametypes!
-
-        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'],) = DBSession.query(
-    #            func.count("*")).\
-    #            filter(Game.game_id == PlayerGameStat.game_id).\
-    #            filter(PlayerGameStat.player_id == player_id).\
-    #            filter(Game.winner == PlayerGameStat.team or PlayerGameStat.rank == 1).\
-    #            one()
-
-        (total_stats['wins'],) = DBSession.\
-                query("total_wins").\
-                from_statement(
-                    "select count(*) total_wins "
-                    "from games g, player_game_stats pgs "
-                    "where g.game_id = pgs.game_id "
-                    "and player_id=:player_id "
-                    "and (g.winner = pgs.team or pgs.rank = 1)"
-                ).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()
-
-        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()
-
-        elos_dict = {}
-        for elo in elos:
-            if elo.games > 32:
-                elos_dict[elo.game_type_cd] = elo.elo
-
-        self.data = {
-                'player':player,
-                'total_stats':total_stats,
-                'ranks':ranks_dict,
-                'elos':elos_dict,
-            }
-