]> git.xonotic.org Git - xonotic/xonstat.git/commitdiff
Initial version of the "versus" view between two players.
authorAnt Zucaro <azucaro@gmail.com>
Sat, 12 Mar 2016 13:39:55 +0000 (08:39 -0500)
committerAnt Zucaro <azucaro@gmail.com>
Sat, 12 Mar 2016 13:39:55 +0000 (08:39 -0500)
xonstat/__init__.py
xonstat/templates/player_versus.mako [new file with mode: 0644]
xonstat/views/__init__.py
xonstat/views/helpers.py
xonstat/views/player.py

index ec8bc310a01798d741ab94006f6cffa44a40d96e..10632d627b4771b519ca6d0a443d7ba346aec79e 100644 (file)
@@ -110,6 +110,9 @@ def main(global_config, **settings):
     config.add_route("top_maps_index", "/topmaps")
     config.add_view(top_maps_index, route_name="top_maps_index", renderer="top_maps_index.mako")
 
+    config.add_route("player_versus", "/versus")
+    config.add_view(player_versus, route_name="player_versus", renderer="player_versus.mako")
+
     # GAME ROUTES
     config.add_route("game_info",      "/game/{id:\d+}")
     config.add_view(game_info,      route_name="game_info",      renderer="game_info.mako")
diff --git a/xonstat/templates/player_versus.mako b/xonstat/templates/player_versus.mako
new file mode 100644 (file)
index 0000000..8f81a45
--- /dev/null
@@ -0,0 +1,72 @@
+<%inherit file="base.mako"/>
+<%namespace name="nav" file="nav.mako" />
+<%namespace file="navlinks.mako" import="navlinks" />
+
+<%block name="navigation">
+  ${nav.nav('players')}
+</%block>
+
+<div class="row">
+  <div class="small-5 columns text-right">
+    <h3>${p1.nick_html_colors()|n}</h3>
+  </div>
+
+  <div class="small-2 columns text-center">
+    <h3>vs</h3>
+  </div>
+
+  <div class="small-5 columns text-left">
+    <h3>${p2.nick_html_colors()|n}</h3>
+  </div>
+</div>
+
+<div class="row">
+  <div class="small-5 columns text-right">
+    <h3>${p1_wins}</h3>
+  </div>
+
+  <div class="small-2 columns text-center">
+    <h3>wins</h3>
+  </div>
+
+  <div class="small-5 columns text-left">
+    <h3>${p2_wins}</h3>
+  </div>
+</div>
+
+% if len(recent_games) > 0:
+<div class="row">
+  <div class="small-12 columns">
+    <h5>Recent Games</h5>
+    <table class="table table-hover table-condensed">
+      <thead>
+        <tr>
+          <th class="small-1 text-center"></th>
+          <th class="small-1">Type</th>
+          <th class="show-for-medium-up small-3">Server</th>
+          <th class="show-for-medium-up small-2">Map</th>
+          <th class="show-for-large-up small-2">Time</th>
+          <th class="small-3">Winner</th>
+        </tr>
+      </thead>
+      <tbody>
+      % for rg in recent_games:
+        <tr>
+          <td class="text-center"><a class="button tiny" href="${request.route_url('game_info', id=rg.game_id)}" title="View detailed information about this game">view</a></td>
+          <td class="text-center"><span class="sprite sprite-${rg.game_type_cd}" alt="${rg.game_type_cd}" title="${rg.game_type_descr}"></span></td>
+          <td class="show-for-medium-up no-stretch"><a href="${request.route_url('server_info', id=rg.server_id)}" title="Go to the detail page for this server">${rg.server_name}</a></td>
+          <td class="show-for-medium-up"><a href="${request.route_url('map_info', id=rg.map_id)}" title="Go to the map detail page for this map">${rg.map_name}</a></td>
+          <td class="show-for-large-up"><span class="abstime" data-epoch="${rg.epoch}" title="${rg.start_dt.strftime('%a, %d %b %Y %H:%M:%S UTC')}">${rg.fuzzy_date}</span></td>
+          <td class="no-stretch">
+            % if rg.player_id > 2:
+            <a href="${request.route_url('player_info', id=rg.player_id)}" title="Go to the player info page for this player">${rg.nick_html_colors|n}</a></td>
+            % else:
+            ${rg.nick_html_colors|n}</td>
+            % endif
+        </tr>
+        % endfor
+        </tbody>
+    </table>
+  </div>
+</div>
+% endif
index 4ca67188b5d73bbccb46e09e00dcd80608ce7c88..ec60ac84a0d5360fcc42faeb463474782cf72996 100644 (file)
@@ -7,7 +7,7 @@ from xonstat.views.player import player_damage_json
 from xonstat.views.player import player_elo_info_text, player_elo_info_json
 from xonstat.views.player import player_hashkey_info_text, player_hashkey_info_json
 from xonstat.views.player import player_captimes, player_captimes_json
-from xonstat.views.player import player_weaponstats_data_json
+from xonstat.views.player import player_weaponstats_data_json, player_versus
 
 from xonstat.views.game   import game_info, rank_index
 from xonstat.views.game   import game_info_json, rank_index_json
index ec7219323f4a9e948f4ef3356aa81b3f35e93ed0..afaf9145c57cbaf688346e1ae8826a054e7269e7 100644 (file)
@@ -72,7 +72,7 @@ class RecentGame(object):
 
 def recent_games_q(server_id=None, map_id=None, player_id=None,
         game_type_cd=None, cutoff=None, force_player_id=False,
-        start_game_id=None, end_game_id=None):
+        start_game_id=None, end_game_id=None, player_id_2=None):
     '''
     Returns a SQLA query of recent game data. Parameters filter
     the results returned if they are provided. If not, it is
@@ -119,6 +119,12 @@ def recent_games_q(server_id=None, map_id=None, player_id=None,
                 filter(Game.game_id==pgstat_alias.game_id).\
                 filter(Game.players.contains([player_id])).\
                 filter(pgstat_alias.player_id==player_id)
+
+            # supports versus queries
+            if player_id_2 is not None:
+                recent_games_q = recent_games_q.\
+                        filter(Game.players.contains([player_id, player_id_2]))
+
     else:
         recent_games_q = recent_games_q.\
             filter(PlayerGameStat.scoreboardpos==1)
index 439f19dbf4f5304ef4c206c12ad7556fa4301115..7668774501756d054330a8920fce623aa6d168fc 100644 (file)
@@ -1104,3 +1104,79 @@ def player_weaponstats_data_json(request):
         "averages": avgs,
     }
 
+
+def player_versus_data(request):
+    try:
+        p1_id = int(request.params.get("p1", None))
+        p2_id = int(request.params.get("p2", None))
+
+        p1_wins = 0
+        p2_wins = 0
+
+        players = DBSession.query(Player).filter(sa.or_(Player.player_id ==
+            p1_id, Player.player_id == p2_id)).order_by(Player.player_id).all()
+
+
+        if len(players) < 2:
+            raise Exception("Not enough players found.")
+
+        # assign the players from the array retrieved above
+        if players[0].player_id == p1_id:
+            p1 = players[0]
+            p2 = players[1]
+        else:
+            p1 = players[1]
+            p2 = players[0]
+
+        # note that wins and losses are from p1's perspective
+        win_loss_sql = """select win_loss, count(1)
+            from (
+              select case 
+                when pgsp1.score >= pgsp2.score then 'win' 
+                else 'loss' 
+              end win_loss
+              from games g join player_game_stats pgsp1 
+                on g.game_id = pgsp1.game_id and pgsp1.player_id = :p1
+              join player_game_stats pgsp2 
+                on g.game_id = pgsp2.game_id and pgsp2.player_id = :p2
+              where g.players @> ARRAY[:p1,:p2]
+              and g.game_type_cd = 'duel'
+              and pgsp1.create_dt between g.create_dt - interval '1 hour' 
+                and g.create_dt + interval '1 hour'
+              and pgsp2.create_dt between g.create_dt - interval '1 hour' 
+                and g.create_dt + interval '1 hour'
+            ) wl
+            group by win_loss
+            """
+
+        wins_losses = DBSession.query("win_loss", "count").\
+                from_statement(win_loss_sql).\
+                params(p1=p1_id, p2=p2_id).all()
+
+        for row in wins_losses:
+            if row.win_loss == "win":
+                p1_wins = row.count
+            elif row.win_loss == "loss":
+                p2_wins = row.count
+
+        # grab the 20 most recent games between the two
+        rgs_raw = recent_games_q(player_id=p1_id, player_id_2=p2_id, 
+                game_type_cd="duel").limit(20).all()
+
+        rgs = [RecentGame(row) for row in rgs_raw]
+
+    except Exception as e:
+        log.debug(e)
+        raise pyramid.httpexceptions.HTTPNotFound
+
+    return {
+            "p1" : p1,
+            "p2" : p2,
+            "p1_wins" : p1_wins,
+            "p2_wins" : p2_wins,
+            "recent_games" : rgs,
+        }
+
+
+def player_versus(request):
+    return player_versus_data(request)