]> de.git.xonotic.org Git - xonotic/xonstat.git/blobdiff - xonstat/views/submission.py
Remove more refs to sqlahelper.
[xonotic/xonstat.git] / xonstat / views / submission.py
index b4059e5ad06c2bbe3863587c7b3499ed0f5521b1..567d8a4777ba67eb3e6b3c48be0d32a8230e4b37 100644 (file)
@@ -9,7 +9,7 @@ from sqlalchemy import Sequence
 from sqlalchemy.orm.exc import NoResultFound
 from xonstat.elo import EloProcessor
 from xonstat.models import DBSession, Server, Map, Game, PlayerGameStat, PlayerWeaponStat
-from xonstat.models import PlayerRank, PlayerCaptime
+from xonstat.models import PlayerRank, PlayerCaptime, PlayerGameFragMatrix
 from xonstat.models import TeamGameStat, PlayerGameAnticheat, Player, Hashkey, PlayerNick
 from xonstat.util import strip_colors, qfont_decode, verify_request, weapon_map
 
@@ -79,6 +79,9 @@ class Submission(object):
         # bots who played in the match
         self.bots = []
 
+        # player indexes for those who played
+        self.player_indexes = set()
+
         # distinct weapons that we have seen fired
         self.weapons = set()
 
@@ -165,6 +168,9 @@ class Submission(object):
         played = self.played_in_game(player)
         human = self.is_human_player(player)
 
+        if played:
+            self.player_indexes.add(int(player["i"]))
+
         if played and human:
             self.humans.append(player)
 
@@ -340,6 +346,10 @@ def has_minimum_real_players(settings, submission):
     except:
         minimum_required_players = 2
 
+    # Make an exception for CTS since it can be done by individuals and there is no Elo anyway
+    if submission.game_type_cd == "cts":
+        minimum_required_players = 1
+
     return len(submission.humans) >= minimum_required_players
 
 
@@ -399,6 +409,13 @@ def should_do_weapon_stats(game_type_cd):
     return game_type_cd not in {'cts'}
 
 
+def should_do_frag_matrix(game_type_cd):
+    """True if the game type should record frag matrix values. False otherwise."""
+    return game_type_cd in {
+        'as', 'ca', 'ctf', 'dm', 'dom', 'ft', 'freezetag', 'ka', 'kh', 'rune', 'tdm',
+    }
+
+
 def gametype_elo_eligible(game_type_cd):
     """True of the game type should process Elos. False otherwise."""
     return game_type_cd in {'duel', 'dm', 'ca', 'ctf', 'tdm', 'ka', 'ft'}
@@ -606,7 +623,7 @@ def create_game(session, game_type_cd, server_id, map_id, match_id, start_dt, du
     game.mod = mod[:64]
 
     # There is some drift between start_dt (provided by app) and create_dt
-    # (default in the database), so we'll make them the same until this is 
+    # (default in the database), so we'll make them the same until this is
     # resolved.
     game.create_dt = start_dt
 
@@ -697,10 +714,6 @@ def create_default_game_stat(session, game_type_cd):
     if game_type_cd in 'ca' 'dm' 'duel' 'rune' 'tdm':
         pgstat.kills = pgstat.deaths = pgstat.suicides = 0
 
-    if game_type_cd == 'cq':
-        pgstat.kills = pgstat.deaths = pgstat.suicides = pgstat.captures = 0
-        pgstat.drops = 0
-
     if game_type_cd == 'ctf':
         pgstat.kills = pgstat.captures = pgstat.pickups = pgstat.drops = 0
         pgstat.returns = pgstat.carrier_frags = 0
@@ -725,16 +738,10 @@ def create_default_game_stat(session, game_type_cd):
         pgstat.captures = pgstat.drops = pgstat.pushes = pgstat.destroys = 0
         pgstat.carrier_frags = 0
 
-    if game_type_cd == 'lms':
-        pgstat.kills = pgstat.deaths = pgstat.suicides = pgstat.lives = 0
-
     if game_type_cd == 'nb':
         pgstat.kills = pgstat.deaths = pgstat.suicides = pgstat.captures = 0
         pgstat.drops = 0
 
-    if game_type_cd == 'rc':
-        pgstat.kills = pgstat.deaths = pgstat.suicides = pgstat.laps = 0
-
     return pgstat
 
 
@@ -844,7 +851,7 @@ def create_default_team_stat(session, game_type_cd):
     # all team game modes have a score, so we'll zero that out always
     teamstat.score = 0
 
-    if game_type_cd in 'ca' 'ft' 'lms' 'ka':
+    if game_type_cd in 'ca' 'ft' 'ka':
         teamstat.rounds = 0
 
     if game_type_cd == 'ctf':
@@ -1044,6 +1051,34 @@ def get_or_create_players(session, events_by_hashkey):
     return players_by_hashkey
 
 
+def create_frag_matrix(session, player_indexes, pgstat, events):
+    """
+    Construct a PlayerFragMatrix object from the events of a given player.
+
+    :param session: The DBSession we're adding objects to.
+    :param player_indexes: The set of player indexes of those that actually played in the game.
+    :param pgstat: The PlayerGameStat object of the player whose frag matrix we want to create.
+    :param events: The raw player events of the above player.
+    :return: PlayerFragMatrix
+    """
+    player_index = int(events.get("i", None))
+
+    # "kills-4" -> 4
+    victim_index = lambda x: int(x.split("-")[1])
+
+    matrix = {victim_index(k): int(v) for (k, v) in events.items()
+              if k.startswith("kills-") and victim_index(k) in player_indexes}
+
+    if len(matrix) > 0:
+        pfm = PlayerGameFragMatrix(pgstat.game_id, pgstat.player_game_stat_id, pgstat.player_id,
+                                   player_index, matrix)
+
+        session.add(pfm)
+        return pfm
+    else:
+        return None
+
+
 def submit_stats(request):
     """
     Entry handler for POST stats submissions.
@@ -1107,11 +1142,18 @@ def submit_stats(request):
         hashkeys_by_player_id = {}
         for hashkey, player in players_by_hashkey.items():
             events = events_by_hashkey[hashkey]
+
             pgstat = create_game_stat(session, game, gmap, player, events)
             pgstats.append(pgstat)
 
+            if should_do_frag_matrix(submission.game_type_cd):
+                create_frag_matrix(session, submission.player_indexes, pgstat, events)
+
             # player ranking opt-out
-            if 'r' in events and events['r'] != '0':
+            if 'r' in events and events['r'] == '0':
+                log.debug("Excluding player {} from ranking calculations (opt-out)"
+                          .format(pgstat.player_id))
+            else:
                 elo_pgstats.append(pgstat)
 
             if player.player_id > 1: