From 28dad5d3f70a02f515f0378d57dee7f7b4d2abac Mon Sep 17 00:00:00 2001 From: Ant Zucaro Date: Sat, 12 Mar 2016 08:39:55 -0500 Subject: [PATCH] Initial version of the "versus" view between two players. --- xonstat/__init__.py | 3 ++ xonstat/templates/player_versus.mako | 72 ++++++++++++++++++++++++++ xonstat/views/__init__.py | 2 +- xonstat/views/helpers.py | 8 ++- xonstat/views/player.py | 76 ++++++++++++++++++++++++++++ 5 files changed, 159 insertions(+), 2 deletions(-) create mode 100644 xonstat/templates/player_versus.mako diff --git a/xonstat/__init__.py b/xonstat/__init__.py index ec8bc31..10632d6 100644 --- a/xonstat/__init__.py +++ b/xonstat/__init__.py @@ -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 index 0000000..8f81a45 --- /dev/null +++ b/xonstat/templates/player_versus.mako @@ -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')} + + +
+
+

${p1.nick_html_colors()|n}

+
+ +
+

vs

+
+ +
+

${p2.nick_html_colors()|n}

+
+
+ +
+
+

${p1_wins}

+
+ +
+

wins

+
+ +
+

${p2_wins}

+
+
+ +% if len(recent_games) > 0: +
+
+
Recent Games
+ + + + + + + + + + + + + % for rg in recent_games: + + + + + + + + % else: + ${rg.nick_html_colors|n} + % endif + + % endfor + +
TypeServerMapTimeWinner
view${rg.server_name}${rg.map_name}${rg.fuzzy_date} + % if rg.player_id > 2: + ${rg.nick_html_colors|n}
+
+
+% endif diff --git a/xonstat/views/__init__.py b/xonstat/views/__init__.py index 4ca6718..ec60ac8 100644 --- a/xonstat/views/__init__.py +++ b/xonstat/views/__init__.py @@ -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 diff --git a/xonstat/views/helpers.py b/xonstat/views/helpers.py index ec72193..afaf914 100644 --- a/xonstat/views/helpers.py +++ b/xonstat/views/helpers.py @@ -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) diff --git a/xonstat/views/player.py b/xonstat/views/player.py index 439f19d..7668774 100644 --- a/xonstat/views/player.py +++ b/xonstat/views/player.py @@ -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) -- 2.39.2