3 from pyramid.response import Response
4 from pyramid.view import view_config
6 from xonstat.models import *
9 log = logging.getLogger(__name__)
11 ##########################################################################
12 # This is the main index - the entry point to the entire site
13 ##########################################################################
14 @view_config(renderer='index.jinja2')
15 def main_index(request):
16 log.debug("testing logging; entered MainHandler.index()")
17 return {'project':'xonstat'}
19 ##########################################################################
20 # This is the player views area - only views pertaining to Xonotic players
21 # and their related information goes here
22 ##########################################################################
23 @view_config(renderer='player_index.mako')
24 def player_index(request):
25 players = DBSession.query(Player)
26 log.debug("testing logging; entered PlayerHandler.index()")
27 return {'players':players}
29 @view_config(renderer='player_info.mako')
30 def player_info(request):
31 player = DBSession.query(Player).filter_by(player_id=p_player_id)
32 log.debug("testing logging; entered PlayerHandler.info()")
33 return {'player':player}
35 ##########################################################################
36 # This is the stats views area - only views pertaining to Xonotic
37 # statistics and its related information goes here
38 ##########################################################################
39 def get_or_create_server(session=None, name=None):
42 # find one by that name, if it exists
43 server = session.query(Server).filter_by(name=name).one()
44 log.debug("Found server id {0} with name {1}.".format(
45 server.server_id, server.name))
47 # otherwise create a new one
48 server = Server(name=name)
51 log.debug("Created server id {0} with name {1}".format(
52 server.server_id, server.name))
56 def get_or_create_map(session=None, name=None):
59 # find one by the name, if it exists
60 gmap = session.query(Map).filter_by(name=name).one()
61 log.debug("Found map id {0} with name {1}.".format(gmap.map_id,
64 # otherwise create a new one
68 log.debug("Created map id {0} with name {1}.".format(gmap.map_id,
73 def create_game(session=None, start_dt=None, game_type_cd=None,
74 server_id=None, map_id=None, winner=None):
75 game = Game(start_dt=start_dt, game_type_cd=game_type_cd,
76 server_id=server_id, map_id=map_id, winner=winner)
79 log.debug("Created game id {0} on server {1}, map {2} at time \
80 {3} and on map {4}".format(game.game_id,
81 server_id, map_id, start_dt, map_id))
85 # search for a player and if found, create a new one (w/ hashkey)
86 def get_or_create_player(session=None, hashkey=None):
87 # the player object we'll return
91 if re.search('^bot#\d+$', hashkey):
92 player = session.query(Player).filter_by(player_id=1).one()
93 # if we have an untracked player
94 elif re.search('^player#\d+$', hashkey):
95 player = session.query(Player).filter_by(player_id=2).one()
96 # else it is a tracked player
98 # see if the player is already in the database
99 # if not, create one and the hashkey along with it
101 hashkey = session.query(Hashkey).filter_by(
102 hashkey=hashkey).one()
103 player = session.query(Player).filter_by(
104 player_id=hashkey.player_id).one()
105 log.debug("Found existing player {0} with hashkey {1}.".format(
106 player.player_id, hashkey.hashkey)
111 hashkey = Hashkey(player_id=player.player_id, hashkey=hashkey)
113 log.debug("Created player {0} with hashkey {1}.".format(
114 player.player_id, hashkey.hashkey)
118 def create_player_game_stat(session=None, player=None,
119 game=None, player_events=None):
121 # in here setup default values (e.g. if game type is CTF then
122 # set kills=0, score=0, captures=0, pickups=0, fckills=0, etc
123 # TODO: use game's create date here instead of now()
124 pgstat = PlayerGameStat(create_dt=datetime.datetime.now())
126 # set player id from player record
127 pgstat.player_id = player.player_id
129 #set game id from game record
130 pgstat.game_id = game.game_id
132 # all games have a score
135 if game.game_type_cd == 'dm':
139 elif game.game_type_cd == 'ctf':
145 pgstat.carrier_frags = 0
147 for (key,value) in player_events.items():
148 if key == 'n': pgstat.nick = value
149 if key == 't': pgstat.team = value
150 if key == 'scoreboard-drops': pgstat.drops = value
151 if key == 'scoreboard-returns': pgstat.returns = value
152 if key == 'scoreboard-fckills': pgstat.carrier_frags = value
153 if key == 'scoreboard-pickups': pgstat.pickups = value
154 if key == 'scoreboard-caps': pgstat.caps = value
155 if key == 'scoreboard-score': pgstat.score = value
156 if key == 'scoreboard-deaths': pgstat.deaths = value
157 if key == 'scoreboard-kills': pgstat.kills = value
158 if key == 'scoreboard-suicides': pgstat.suicides = value
161 # check to see if we had a name, and if
162 # not use the name from the player id
163 if pgstat.nick == None:
164 pgstat.nick = player.nick
172 def create_player_weapon_stats(session=None, player=None,
173 game=None, player_events=None):
176 for (key,value) in player_events.items():
177 matched = re.search("acc-(.*?)-cnt-fired", key)
179 weapon_cd = match.group(1)
181 pwstat = PlayerWeaponStat()
182 pwstat.player_id = player.player_id
183 pwstat.game_id = game.game_id
184 pwstat.weapon_cd = weapon_cd
185 pwstat.max = player_events['acc-' + weapon_cd + '-fired']
186 pwstat.actual = player_events['acc-' + weapon_cd + '-hit']
187 pwstat.fired = player_events['acc-' + weapon_cd + '-cnt-fired']
188 pwstat.hit = player_events['acc-' + weapon_cd + '-cnt-hit']
189 pwstat.frags = player_events['acc-' + weapon_cd + '-frags']
191 pwstats.append(pwstat)
198 def parse_body(request):
199 # storage vars for the request body
205 log.debug(request.body)
207 for line in request.body.split('\n'):
209 (key, value) = line.strip().split(' ', 1)
211 if key in 'V' 'T' 'G' 'M' 'S' 'C' 'R' 'W':
212 game_meta[key] = value
218 # if we were working on a player record already, append
219 # it and work on a new one (only set team info)
220 if len(player_events) != 0:
221 players.append(player_events)
222 player_events = {'t':current_team}
224 player_events[key] = value
227 (subkey, subvalue) = value.split(' ', 1)
228 player_events[subkey] = subvalue
231 player_events[key] = value
233 # no key/value pair - move on to the next line
236 # add the last player we were working on
237 players.append(player_events)
239 return (game_meta, players)
242 @view_config(renderer='stats_submit.mako')
243 def stats_submit(request):
244 session = DBSession()
246 (game_meta, players) = parse_body(request)
248 # verify required metadata is present
249 if 'T' not in game_meta or\
250 'G' not in game_meta or\
251 'M' not in game_meta or\
252 'S' not in game_meta or\
253 'W' not in game_meta:
254 log.debug("Required game meta fields (T, G, M, S, or W) missing. "\
256 return {'msg':'Error processing the request.'}
258 server = get_or_create_server(session=session, name=game_meta['S'])
259 gmap = get_or_create_map(session=session, name=game_meta['M'])
260 # FIXME: don't use python now() here, convert from epoch T value
261 game = create_game(session=session, start_dt=datetime.datetime.now(),
262 server_id=server.server_id, game_type_cd=game_meta['G'],
263 map_id=gmap.map_id, winner=game_meta['W'])
265 # find or create a record for each player
266 # and add stats for each if they were present at the end
268 has_real_players = False
269 for player_events in players:
270 if not player_events['P'].startswith('bot'):
271 has_real_players = True
272 player = get_or_create_player(session=session,
273 hashkey=player_events['P'])
274 if 'joins' in player_events and 'matches' in player_events:
275 pgstat = create_player_game_stat(session=session,
276 player=player, game=game, player_events=player_events)
277 pwstats = create_player_weapon_stats(session=session,
278 player=player, game=game, player_events=player_events)
282 log.debug('Success! Stats recorded.')
283 return {'msg':'Success! Stats recorded.'}
286 log.debug('No real players found. Stats ignored.')
287 return {'msg':'No real players found. Stats ignored.'}