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",
)
# 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
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).\
filter(Player.active_ind == True).\
all()
+playerdata = PlayerData()
+
if len(players) > 0:
stop = datetime.now()
td = stop-start
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:
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
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:
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
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,
- }
-