\r
log = logging.getLogger(__name__)\r
\r
+\r
+def is_blank_game(players):\r
+ """Determine if this is a blank game or not. A blank game is either:\r
+\r
+ 1) a match that ended in the warmup stage, where accuracy events are not\r
+ present\r
+\r
+ 2) a match in which no player made a positive or negative score AND was\r
+ on the scoreboard\r
+ """\r
+ r = re.compile(r'acc-.*-cnt-fired')\r
+ flg_nonzero_score = False\r
+ flg_acc_events = False\r
+\r
+ for events in players:\r
+ if is_real_player(events):\r
+ for (key,value) in events.items():\r
+ if key == 'scoreboard-score' and value != '0':\r
+ flg_nonzero_score = True\r
+ if r.search(key):\r
+ flg_acc_events = True\r
+\r
+ return not (flg_nonzero_score and flg_acc_events)\r
+\r
def get_remote_addr(request):\r
"""Get the Xonotic server's IP address"""\r
- if 'X-Server-IP' in request.headers:\r
- return request.headers['X-Server-IP']\r
+ if 'X-Forwarded-For' in request.headers:\r
+ return request.headers['X-Forwarded-For']\r
else:\r
- return os.environ.get('HTTP_X_FORWARDED_FOR', request.remote_addr)\r
+ return request.remote_addr\r
\r
\r
def is_supported_gametype(gametype):\r
return (idfp, status)\r
\r
\r
-def num_real_players(player_events):\r
+def num_real_players(player_events, count_bots=False):\r
"""\r
Returns the number of real players (those who played \r
and are on the scoreboard).\r
real_players = 0\r
\r
for events in player_events:\r
- if is_real_player(events):\r
+ if is_real_player(events, count_bots):\r
real_players += 1\r
\r
return real_players\r
return flg_has_req_metadata\r
\r
\r
-def is_real_player(events):\r
+def is_real_player(events, count_bots=False):\r
"""\r
Determines if a given set of player events correspond with a player who\r
\r
"""\r
flg_is_real = False\r
\r
- if not events['P'].startswith('bot'):\r
- # removing 'joins' here due to bug, but it should be here\r
- if 'matches' in events and 'scoreboardvalid' in events:\r
+ # removing 'joins' here due to bug, but it should be here\r
+ if 'matches' in events and 'scoreboardvalid' in events:\r
+ if (events['P'].startswith('bot') and count_bots) or \\r
+ not events['P'].startswith('bot'):\r
flg_is_real = True\r
\r
return flg_is_real\r
filter(Game.match_id==match_id).one()\r
# if a game under the same server and match_id found, \r
# this is a duplicate game and can be ignored\r
- raise pyramid.httpexceptions.HTTPOk\r
+ raise pyramid.httpexceptions.HTTPOk('OK')\r
except NoResultFound, e:\r
# server_id/match_id combination not found. game is ok to insert\r
session.add(game)\r
pgstat.nick = player.nick\r
\r
# whichever nick we ended up with, strip it and store as the stripped_nick\r
- pgstat.stripped_nick = qfont_decode(pgstat.nick)\r
+ pgstat.stripped_nick = qfont_decode(strip_colors(pgstat.nick))\r
\r
# if the nick we end up with is different from the one in the\r
# player record, change the nick to reflect the new value\r
log.debug("ERROR: Not enough real players")\r
raise pyramid.httpexceptions.HTTPOk("OK")\r
\r
+ if is_blank_game(players):\r
+ log.debug("ERROR: Blank game")\r
+ raise pyramid.httpexceptions.HTTPOk("OK")\r
+\r
# FIXME: if we have two players and game type is 'dm',\r
# change this into a 'duel' gametype. This should be\r
# removed when the stats actually send 'duel' instead of 'dm'\r
- if num_real_players(players) == 2 and game_meta['G'] == 'dm':\r
+ if num_real_players(players, count_bots=True) == 2 and \\r
+ game_meta['G'] == 'dm':\r
game_meta['G'] = 'duel'\r
\r
server = get_or_create_server(session=session, hashkey=idfp, \r
create_player_stats(session=session, player=player, game=game, \r
player_events=player_events)\r
\r
+ # update elos\r
+ try:\r
+ game.process_elos(session)\r
+ except Exception as e:\r
+ log.debug('Error (non-fatal): elo processing failed.')\r
+\r
session.commit()\r
log.debug('Success! Stats recorded.')\r
return Response('200 OK')\r