]> de.git.xonotic.org Git - xonotic/xonstat.git/commitdiff
Merge branch 'master' into badges
authorJan D. Behrens <zykure@web.de>
Mon, 27 Aug 2012 22:35:34 +0000 (00:35 +0200)
committerJan D. Behrens <zykure@web.de>
Mon, 27 Aug 2012 22:36:52 +0000 (00:36 +0200)
Conflicts:
xonstat/batch/badges/gen_badges.py

1  2 
xonstat/batch/badges/gen_badges.py

index 905200d67b05b7315d9b055210eb79150f19c168,d59c336dd3273dea1005035a4fc0320985f88c9d..d554560712a4e6101e8ca72082b72fab361c0213
@@@ -1,18 -1,14 +1,16 @@@
  #-*- coding: utf-8 -*-
  
 +import sys
 +import re
  import cairo as C
+ from datetime import datetime
  import sqlalchemy as sa
  import sqlalchemy.sql.functions as func
- from datetime import datetime
- from mako.template import Template
+ from colorsys import rgb_to_hls, hls_to_rgb
  from os import system
  from pyramid.paster import bootstrap
  from xonstat.models import *
- from xonstat.views.player import player_info_data
 -from xonstat.util import qfont_decode
 +from xonstat.util import qfont_decode, _all_colors
- from colorsys import rgb_to_hls, hls_to_rgb
  
  
  # similar to html_colors() from util.py
@@@ -31,37 -27,11 +29,37 @@@ _dec_colors = [ (0.5,0.5,0.5)
              ]
  
  
- NUM_PLAYERS = 50
 +# maximal number of query results (for testing, set to 0 to get all)
++NUM_PLAYERS = 100
 +
 +# image dimensions (likely breaks layout if changed)
 +WIDTH   = 560
 +HEIGHT  = 70
 +
 +# output filename, parameter is player id
 +OUTPUT = "output/%d.png"
 +
 +
 +NICK_POS        = (5,18)
 +NICK_MAXWIDTH   = 330
 +
 +GAMES_POS       = (60,35)
 +GAMES_WIDTH     = 110
 +
 +WINLOSS_POS     = (508,6)
 +WINLOSS_WIDTH   = 104
 +
 +KILLDEATH_POS   = (390,6)
 +KILLDEATH_WIDTH = 104
 +
 +PLAYTIME_POS    = (452,64)
 +PLAYTIME_WIDTH  = 218
 +
 +
  # parameters to affect the output, could be changed via URL
  params = {
 -    'width':        560,
 -    'height':        70,
 -    'bg':           1,                      # 0 - black, 1 - dark_wall
 +    'bg':           1,                      # 0 - black, 1 - dark_wall, ...
 +    'overlay':      0,                      # 0 - none, 1 - default overlay, ...
      'font':         0,                      # 0 - xolonium, 1 - dejavu sans
  }
  
@@@ -109,31 -73,23 +107,31 @@@ def get_data(player)
          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['suicides'],
 -     total_stats['alivetime'],) = DBSession.query(
 +    (total_stats['kills'], total_stats['deaths'], total_stats['alivetime'],) = DBSession.query(
              func.sum(PlayerGameStat.kills),
              func.sum(PlayerGameStat.deaths),
 -            func.sum(PlayerGameStat.suicides),
              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(
 +#            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 "
  
  def render_image(data):
      """Render an image from the given data fields."""
-     
 -
 -    width, height = params['width'], params['height']
 -    output = "output/%s.png" % data['player'].player_id
 -
      font = "Xolonium"
      if params['font'] == 1:
          font = "DejaVu Sans"
  
      # draw background (just plain fillcolor)
      if params['bg'] == 0:
 -        ctx.rectangle(0, 0, width, height)
 -        ctx.set_source_rgba(0.2, 0.2, 0.2, 1.0)
 +        ctx.rectangle(0, 0, WIDTH, HEIGHT)
 +        ctx.set_source_rgb(0.04, 0.04, 0.04)  # bgcolor of Xonotic forum
          ctx.fill()
-     
      # draw background image (try to get correct tiling, too)
      if params['bg'] > 0:
          bg = None
                      ctx.paint()
                      bg_yoff += bg_h
                  bg_xoff += bg_w
-     
 +    # draw overlay graphic
 +    if params['overlay'] > 0:
 +        overlay = None
 +        if params['overlay'] == 1:
 +            overlay = C.ImageSurface.create_from_png("img/overlay.png")
 +        if overlay:
 +            ctx.set_source_surface(overlay, 0, 0)
 +            ctx.mask_surface(overlay)
 +            ctx.paint()
  
 -    ## draw player's nickname with fancy colors
  
-     qstr = qfont_decode(player.nick).replace('^^', '^').replace(u'\x00', '').replace(u' ', '    ')
 +    ## draw player's nickname with fancy colors
 +    
 +    # deocde nick, strip all weird-looking characters
++    qstr = qfont_decode(player.nick).replace('^^', '^').replace(u'\x00', '')
 +    chars = []
 +    for c in qstr:
 +        if ord(c) < 128:
 +            chars.append(c)
 +    qstr = ''.join(chars)
 +    stripped_nick = strip_colors(qstr)
 +    
      # fontsize is reduced if width gets too large
 -    nick_xmax = 335
      ctx.select_font_face(font, C.FONT_SLANT_NORMAL, C.FONT_WEIGHT_NORMAL)
      ctx.set_font_size(20)
 -    xoff, yoff, tw, th = ctx.text_extents(player.stripped_nick)[:4]
 -    if tw > nick_xmax:
 +    xoff, yoff, tw, th = ctx.text_extents(stripped_nick)[:4]
 +    if tw > NICK_MAXWIDTH:
          ctx.set_font_size(18)
 -        xoff, yoff, tw, th = ctx.text_extents(player.stripped_nick)[:4]
 -        if tw > nick_xmax:
 +        xoff, yoff, tw, th = ctx.text_extents(stripped_nick)[:4]
 +        if tw > NICK_MAXWIDTH:
              ctx.set_font_size(16)
 -            xoff, yoff, tw, th = ctx.text_extents(player.stripped_nick)[:4]
 -            if tw > nick_xmax:
 +            xoff, yoff, tw, th = ctx.text_extents(stripped_nick)[:4]
 +            if tw > NICK_MAXWIDTH:
                  ctx.set_font_size(14)
 -                xoff, yoff, tw, th = ctx.text_extents(player.stripped_nick)[:4]
 -                if tw > nick_xmax:
 +                xoff, yoff, tw, th = ctx.text_extents(stripped_nick)[:4]
 +                if tw > NICK_MAXWIDTH:
                      ctx.set_font_size(12)
 -
 +    
-     
      # split up nick into colored segments and draw each of them
 -    qstr = qfont_decode(player.nick).replace('^^', '^').replace('\x00', ' ')
 -    txt_xoff = 0
 -    txt_xpos, txt_ypos = 5,18
 -
 +    
      # split nick into colored segments
 -    parts = []
 -    pos = 1
 -    while True:
 -        npos = qstr.find('^', pos)
 -        if npos < 0:
 -            parts.append(qstr[pos-1:])
 -            break;
 -        parts.append(qstr[pos-1:npos])
 -        pos = npos+1
 -
 -    for txt in parts:
 +    xoffset = 0
 +    _all_colors = re.compile(r'(\^\d|\^x[\dA-Fa-f]{3})')
 +    #print qstr, _all_colors.findall(qstr), _all_colors.split(qstr)
 +    
 +    parts = _all_colors.split(qstr)
 +    while len(parts) > 0:
 +        tag = None
 +        txt = parts[0]
 +        if _all_colors.match(txt):
 +            tag = txt[1:]  # strip leading '^'
 +            if len(parts) < 2:
 +                break
 +            txt = parts[1]
 +            del parts[1]
 +        del parts[0]
 +            
 +        if not txt or len(txt) == 0:
 +            # only colorcode and no real text, skip this
 +            continue
 +            
          r,g,b = _dec_colors[7]
          try:
 -            if txt.startswith('^'):
 -                txt = txt[1:]
 -                if txt.startswith('x'):
 -                    r = int(txt[1] * 2, 16) / 255.0
 -                    g = int(txt[2] * 2, 16) / 255.0
 -                    b = int(txt[3] * 2, 16) / 255.0
 -                    hue, light, satur = rgb_to_hls(r, g, b)
 -                    if light < _contrast_threshold:
 -                        light = _contrast_threshold
 -                        r, g, b = hls_to_rgb(hue, light, satur)
 -                    txt = txt[4:]
 -                else:
 -                    r,g,b = _dec_colors[int(txt[0])]
 -                    txt = txt[1:]
 +            if tag.startswith('x'):
 +                r = int(tag[1] * 2, 16) / 255.0
 +                g = int(tag[2] * 2, 16) / 255.0
 +                b = int(tag[3] * 2, 16) / 255.0
 +                hue, light, satur = rgb_to_hls(r, g, b)
 +                if light < _contrast_threshold:
 +                    light = _contrast_threshold
 +                    r, g, b = hls_to_rgb(hue, light, satur)
 +            else:
 +                r,g,b = _dec_colors[int(tag[0])]
          except:
              r,g,b = _dec_colors[7]
 -
 -        if len(txt) < 1:
 -            # only colorcode and no real text, skip this
 -            continue
 -
 +        
          ctx.set_source_rgb(r, g, b)
 -        ctx.move_to(txt_xpos + txt_xoff, txt_ypos)
 +        ctx.move_to(NICK_POS[0] + xoffset, NICK_POS[1])
          ctx.show_text(txt)
  
          xoff, yoff, tw, th = ctx.text_extents(txt)[:4]
          ctx.set_source_rgb(1.0, 1.0, 1.0)
          txt = "[ %s ]" % gt.upper()
          xoff, yoff, tw, th = ctx.text_extents(txt)[:4]
 -        ctx.move_to(games_x-xoff-tw/2,games_y-yoff-4)
 +        ctx.move_to(GAMES_POS[0]+xoffset-xoff-tw/2, GAMES_POS[1]-yoff-4)
          ctx.show_text(txt)
 +        
          old_aa = ctx.get_antialias()
          ctx.set_antialias(C.ANTIALIAS_NONE)
          ctx.set_source_rgb(0.8, 0.8, 0.8)
          ctx.set_line_width(1)
 -        ctx.move_to(games_x-games_w/2+5, games_y+8)
 -        ctx.line_to(games_x+games_w/2-5, games_y+8)
 +        ctx.move_to(GAMES_POS[0]+xoffset-GAMES_WIDTH/2+5, GAMES_POS[1]+8)
 +        ctx.line_to(GAMES_POS[0]+xoffset+GAMES_WIDTH/2-5, GAMES_POS[1]+8)
          ctx.stroke()
 -        ctx.move_to(games_x-games_w/2+5, games_y+32)
 -        ctx.line_to(games_x+games_w/2-5, games_y+32)
 +        ctx.move_to(GAMES_POS[0]+xoffset-GAMES_WIDTH/2+5, GAMES_POS[1]+32)
 +        ctx.line_to(GAMES_POS[0]+xoffset+GAMES_WIDTH/2-5, GAMES_POS[1]+32)
          ctx.stroke()
          ctx.set_antialias(old_aa)
-         
          if not elos.has_key(gt) or not ranks.has_key(gt):
              ctx.select_font_face(font, C.FONT_SLANT_NORMAL, C.FONT_WEIGHT_BOLD)
              ctx.set_font_size(12)
  
  
      # print win percentage
-     
 -    win_x, win_y = 505,11
 -    win_w, win_h = 100,14
 -    ctx.rectangle(win_x-win_w/2,win_y-win_h/2,win_w,win_h)
 -    ctx.set_source_rgba(0.8, 0.8, 0.8, 0.1)
 -    ctx.fill();
 +    if params['overlay'] == 0:
 +        ctx.rectangle(WINLOSS_POS[0]-WINLOSS_WIDTH/2, WINLOSS_POS[1]-7, WINLOSS_WIDTH, 15)
 +        ctx.set_source_rgba(0.8, 0.8, 0.8, 0.1)
 +        ctx.fill();
-     
      ctx.select_font_face(font, C.FONT_SLANT_NORMAL, C.FONT_WEIGHT_NORMAL)
      ctx.set_font_size(10)
      ctx.set_source_rgb(0.8, 0.8, 0.8)
  
  
      # print kill/death ratio
-     
 -    kill_x, kill_y = 395,11
 -    kill_w, kill_h = 100,14
 -    ctx.rectangle(kill_x-kill_w/2,kill_y-kill_h/2,kill_w,kill_h)
 -    ctx.set_source_rgba(0.8, 0.8, 0.8, 0.1)
 -    ctx.fill()
 +    if params['overlay'] == 0:
 +        ctx.rectangle(KILLDEATH_POS[0]-KILLDEATH_WIDTH/2, KILLDEATH_POS[1]-7, KILLDEATH_WIDTH, 15)
 +        ctx.set_source_rgba(0.8, 0.8, 0.8, 0.1)
 +        ctx.fill()
-     
      ctx.select_font_face(font, C.FONT_SLANT_NORMAL, C.FONT_WEIGHT_NORMAL)
      ctx.set_font_size(10)
      ctx.set_source_rgb(0.8, 0.8, 0.8)
      txt = "Kill Ratio"
      xoff, yoff, tw, th = ctx.text_extents(txt)[:4]
 -    ctx.move_to(kill_x-xoff-tw/2,kill_y-yoff-3)
 +    ctx.move_to(KILLDEATH_POS[0]-xoff-tw/2, KILLDEATH_POS[1]-yoff-3)
      ctx.show_text(txt)
 -
 +    
 +    kills, deaths = total_stats['kills'] , total_stats['deaths'] 
      txt = "???"
 -    if total_stats['deaths'] > 0 and total_stats['kills'] is not None:
 -        ratio = float(total_stats['kills'])/total_stats['deaths']
 +    try:
 +        ratio = float(kills)/deaths
          txt = "%.3f" % round(ratio, 3)
 +    except:
 +        ratio = 0
++
      ctx.select_font_face(font, C.FONT_SLANT_NORMAL, C.FONT_WEIGHT_BOLD)
      ctx.set_font_size(12)
      if ratio >= 3:
  
  
      # print playing time
-     
 -    time_x, time_y = 450,64
 -    time_w, time_h = 210,10
 -    ctx.rectangle(time_x-time_w/2,time_y-time_h/2-1,time_w,time_y+time_h/2-1)
 -    ctx.set_source_rgba(0.8, 0.8, 0.8, 0.6)
 -    ctx.fill();
 +    if params['overlay'] == 0:
 +        ctx.rectangle( PLAYTIME_POS[0]-PLAYTIME_WIDTH/2, PLAYTIME_POS[1]-7, PLAYTIME_WIDTH, 14)
 +        ctx.set_source_rgba(0.8, 0.8, 0.8, 0.6)
 +        ctx.fill();
-     
      ctx.select_font_face(font, C.FONT_SLANT_NORMAL, C.FONT_WEIGHT_NORMAL)
      ctx.set_font_size(10)
      ctx.set_source_rgb(0.1, 0.1, 0.1)
@@@ -536,11 -459,13 +535,14 @@@ for player in players
      sstart = datetime.now()
      render_image(data)
      sstop = datetime.now()
-     render_time += (sstop-sstart).total_seconds()
- print
+     td = sstop-sstart
+     total_seconds = (td.microseconds + (td.seconds + td.days * 24 * 3600) * 10**6) / 10**6
+     render_time += total_seconds
  
  stop = datetime.now()
- print "Creating the badges took %.2f seconds (%.2f s per player)" % ((stop-start).total_seconds(), (stop-start).total_seconds()/float(len(players)))
- print " Total time for getting data: %.2f s" % data_time
- print " Total time for renering images: %.2f s" % render_time
+ td = stop-start
+ total_seconds = (td.microseconds + (td.seconds + td.days * 24 * 3600) * 10**6) / 10**6
+ print "Creating the badges took %.2f seconds (%.2f s per player)" % (total_seconds, total_seconds/float(len(players)))
+ print "Total time for redering images: %.2f s" % render_time
+ print "Total time for getting data: %.2f s" % data_time
 +