]> de.git.xonotic.org Git - xonotic/xonstat.git/blob - xonstat/views/game.py
Clean up the accuracy tables, make them mobile friendly.
[xonotic/xonstat.git] / xonstat / views / game.py
1 import datetime
2 import logging
3 import re
4 import time
5 from collections import OrderedDict
6 from pyramid.response import Response
7 from sqlalchemy import desc, func, over
8 from webhelpers.paginate import Page, PageURL
9 from xonstat.models import *
10 from xonstat.util import page_url
11 from xonstat.views.helpers import RecentGame, recent_games_q
12
13
14 log = logging.getLogger(__name__)
15
16
17 def _game_info_data(request):
18     game_id = request.matchdict['id']
19
20     if request.params.has_key('show_elo'):
21         show_elo = True
22     else:
23         show_elo = False
24
25     show_latency = False
26
27     try:
28         notfound = False
29
30         (game, server, map, gametype) = DBSession.query(Game, Server, Map, GameType).\
31                 filter(Game.game_id == game_id).\
32                 filter(Game.server_id == Server.server_id).\
33                 filter(Game.map_id == Map.map_id).\
34                 filter(Game.game_type_cd == GameType.game_type_cd).one()
35
36         pgstats = DBSession.query(PlayerGameStat).\
37                 filter(PlayerGameStat.game_id == game_id).\
38                 order_by(PlayerGameStat.scoreboardpos).\
39                 order_by(PlayerGameStat.score).\
40                 all()
41
42         # if at least one player has a valid latency, we'll show the column
43         for pgstat in pgstats:
44             if pgstat.avg_latency is not None:
45                 show_latency = True
46
47         q = DBSession.query(TeamGameStat).\
48                 filter(TeamGameStat.game_id == game_id)
49         if game.game_type_cd == 'ctf':
50             q = q.order_by(TeamGameStat.caps.desc())
51         elif game.game_type_cd == 'ca':
52             q = q.order_by(TeamGameStat.rounds.desc())
53         # dom -> ticks, rc -> laps, nb -> goals, as -> objectives
54
55         q = q.order_by(TeamGameStat.score.desc())
56
57         tgstats = q.all()
58
59         stats_by_team = OrderedDict()
60         for pgstat in pgstats:
61             if pgstat.team not in stats_by_team.keys():
62                 stats_by_team[pgstat.team] = []
63             stats_by_team[pgstat.team].append(pgstat)
64
65         captimes = []
66         if game.game_type_cd == 'ctf':
67             for pgstat in pgstats:
68                 if pgstat.fastest is not None:
69                     captimes.append(pgstat)
70             captimes = sorted(captimes, key=lambda x:x.fastest)
71
72         pwstats = {}
73         for (pwstat, pgstat, weapon) in DBSession.query(PlayerWeaponStat, PlayerGameStat, Weapon).\
74                 filter(PlayerWeaponStat.game_id == game_id).\
75                 filter(PlayerWeaponStat.weapon_cd == Weapon.weapon_cd).\
76                 filter(PlayerWeaponStat.player_game_stat_id == \
77                     PlayerGameStat.player_game_stat_id).\
78                 order_by(PlayerGameStat.scoreboardpos).\
79                 order_by(PlayerGameStat.score).\
80                 order_by(Weapon.descr).\
81                 all():
82                     if pgstat.player_game_stat_id not in pwstats:
83                         pwstats[pgstat.player_game_stat_id] = []
84
85                     # NOTE adding pgstat to position 6 in order to display nick.
86                     # You have to use a slice [0:5] to pass to the accuracy
87                     # template
88                     pwstats[pgstat.player_game_stat_id].append((weapon.descr,
89                         weapon.weapon_cd, pwstat.actual, pwstat.max,
90                         pwstat.hit, pwstat.fired, pwstat.frags, pgstat))
91
92     except Exception as inst:
93         game = None
94         server = None
95         map = None
96         gametype = None
97         pgstats = None
98         tgstats = None
99         pwstats = None
100         captimes = None
101         show_elo = False
102         show_latency = False
103         stats_by_team = None
104         raise inst
105
106     return {'game':game,
107             'server':server,
108             'map':map,
109             'gametype':gametype,
110             'pgstats':pgstats,
111             'tgstats':tgstats,
112             'pwstats':pwstats,
113             'captimes':captimes,
114             'show_elo':show_elo,
115             'show_latency':show_latency,
116             'stats_by_team':stats_by_team,
117             }
118
119
120 def game_info(request):
121     """
122     List the game stats (scoreboard) for a particular game. Paginated.
123     """
124     return _game_info_data(request)
125
126
127 def game_info_json(request):
128     """
129     List the game stats (scoreboard) for a particular game. Paginated. JSON.
130     """
131     return [{'status':'not implemented'}]
132
133
134 def _rank_index_data(request):
135     if request.params.has_key('page'):
136         current_page = request.params['page']
137     else:
138         current_page = 1
139
140     game_type_cd = request.matchdict['game_type_cd']
141
142     ranks_q = DBSession.query(PlayerRank).\
143             filter(PlayerRank.game_type_cd==game_type_cd).\
144             order_by(PlayerRank.rank)
145
146     ranks = Page(ranks_q, current_page, url=page_url)
147
148     if len(ranks) == 0:
149         ranks = None
150
151     return {
152             'ranks':ranks,
153             'game_type_cd':game_type_cd,
154            }
155
156
157 def rank_index(request):
158     """
159     Provide a list of gametype ranks, paginated.
160     """
161     return _rank_index_data(request)
162
163
164 def rank_index_json(request):
165     """
166     Provide a list of gametype ranks, paginated. JSON.
167     """
168     return [{'status':'not implemented'}]
169
170
171 def game_finder_data(request):
172     if request.params.has_key('page'):
173         current_page = request.params['page']
174     else:
175         current_page = 1
176
177     query = {}
178
179     server_id, map_id, player_id = None, None, None
180     game_type_cd, start_game_id, end_game_id = None, None, None
181     game_type_descr = None
182
183     # these become WHERE clauses when present
184     if request.params.has_key('server_id'):
185         server_id = request.params['server_id']
186         query['server_id'] = server_id
187
188     if request.params.has_key('map_id'):
189         map_id = request.params['map_id']
190         query['map_id'] = map_id
191
192     if request.params.has_key('player_id'):
193         player_id = request.params['player_id']
194         query['player_id'] = player_id
195
196     if request.params.has_key('start_game_id'):
197         start_game_id = request.params['start_game_id']
198         query['start_game_id'] = start_game_id
199
200     if request.params.has_key('end_game_id'):
201         end_game_id = request.params['end_game_id']
202         query['end_game_id'] = end_game_id
203
204     if request.params.has_key('type'):
205         game_type_cd = request.params['type']
206         query['type'] = game_type_cd
207         try:
208             game_type_descr = DBSession.query(GameType.descr).\
209                 filter(GameType.game_type_cd == game_type_cd).\
210                 one()[0]
211         except Exception as e:
212             game_type_cd = None
213
214     rgs_q = recent_games_q(server_id=server_id, map_id=map_id,
215             player_id=player_id, game_type_cd=game_type_cd,
216             start_game_id=start_game_id, end_game_id=end_game_id)
217
218     recent_games = [RecentGame(row) for row in rgs_q.limit(20).all()]
219     
220     if len(recent_games) > 0:
221         query['start_game_id'] = recent_games[-1].game_id + 1
222
223     # build the list of links for the stripe across the top
224     game_type_links = []
225
226     # clear out the game_id window
227     gt_query = query.copy()
228     if 'start_game_id' in gt_query:
229         del gt_query['start_game_id']
230     if 'end_game_id' in gt_query:
231         del gt_query['end_game_id']
232
233     for gt in ('overall','duel','ctf','dm','tdm','ca','kh','ft',
234             'lms','as','dom','nb','cts','rc'):
235         gt_query['type'] = gt
236         url = request.route_url("game_index", _query=gt_query)
237         game_type_links.append((gt, url))
238
239     return {
240             'recent_games':recent_games,
241             'query':query,
242             'game_type_cd':game_type_cd,
243             'game_type_links':game_type_links,
244            }
245
246 def game_finder(request):
247     """
248     Provide a list of recent games with an advanced filter.
249     """
250     return game_finder_data(request)