+\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-Forwarded-For' in request.headers:\r
+ return request.headers['X-Forwarded-For']\r
+ else:\r
+ return request.remote_addr\r
+\r
+\r
+def is_supported_gametype(gametype):\r
+ """Whether a gametype is supported or not"""\r
+ flg_supported = True\r
+\r
+ if gametype == 'cts' or gametype == 'ca' or gametype == 'lms':\r
+ flg_supported = False\r
+\r
+ return flg_supported\r
+\r
+\r
+def verify_request(request):\r
+ try:\r
+ (idfp, status) = d0_blind_id_verify(\r
+ sig=request.headers['X-D0-Blind-Id-Detached-Signature'],\r
+ querystring='',\r
+ postdata=request.body)\r
+\r
+ log.debug('\nidfp: {0}\nstatus: {1}'.format(idfp, status))\r
+ except: \r
+ idfp = None\r
+ status = None\r
+\r
+ return (idfp, status)\r
+\r
+\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
+ """\r
+ real_players = 0\r
+\r
+ for events in player_events:\r
+ if is_real_player(events, count_bots):\r
+ real_players += 1\r
+\r
+ return real_players\r
+\r
+\r
+def has_minimum_real_players(settings, player_events):\r
+ """\r
+ Determines if the collection of player events has enough "real" players\r
+ to store in the database. The minimum setting comes from the config file\r
+ under the setting xonstat.minimum_real_players.\r
+ """\r
+ flg_has_min_real_players = True\r
+\r
+ try:\r
+ minimum_required_players = int(\r
+ settings['xonstat.minimum_required_players'])\r
+ except:\r
+ minimum_required_players = 2\r
+\r
+ real_players = num_real_players(player_events)\r
+\r
+ #TODO: put this into a config setting in the ini file?\r
+ if real_players < minimum_required_players:\r
+ flg_has_min_real_players = False\r
+\r
+ return flg_has_min_real_players\r
+\r
+\r
+def has_required_metadata(metadata):\r
+ """\r
+ Determines if a give set of metadata has enough data to create a game,\r
+ server, and map with.\r
+ """\r
+ flg_has_req_metadata = True\r
+\r
+ if 'T' not in metadata or\\r
+ 'G' not in metadata or\\r
+ 'M' not in metadata or\\r
+ 'I' not in metadata or\\r
+ 'S' not in metadata:\r
+ flg_has_req_metadata = False\r
+\r
+ return flg_has_req_metadata\r
+\r
+\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
+ 1) is not a bot (P event does not look like a bot)\r
+ 2) played in the game (matches 1)\r
+ 3) was present at the end of the game (scoreboardvalid 1)\r
+\r
+ Returns True if the player meets the above conditions, and false otherwise.\r
+ """\r