diff --git a/src/extract.py b/src/extract.py index 056f121..97416fc 100644 --- a/src/extract.py +++ b/src/extract.py @@ -1,9 +1,5 @@ import psycopg2 as pg from os import environ as env -from typing import TypeVar - -T = TypeVar("T") -U = TypeVar("U") def connect(): @@ -15,174 +11,3 @@ def connect(): port=env.get("POSTGRES_PORT"), ) - -def extract_cols(data: dict, cols: list[str]) -> dict: return {key: data.get(key) for key in cols} - - -def score_to_text(score: list[int]) -> str: - return "-".join(map(str, score)) - - -# maybe could get columns form db -def cols_from_player_stats(player_stats: dict) -> dict: - cols = [ - "id", - "gameId", - "gameFinishedAt", - "steam64Id", - "name", - "preaim", - "reactionTime", - "accuracy", - "accuracyEnemySpotted", - "accuracyHead", - "shotsFiredEnemySpotted", - "shotsFired", - "shotsHitEnemySpotted", - "shotsHitFriend", - "shotsHitFriendHead", - "shotsHitFoe", - "shotsHitFoeHead", - "utilityOnDeathAvg", - "heFoesDamageAvg", - "heFriendsDamageAvg", - "heThrown", - "molotovThrown", - "smokeThrown", - "smokeThrownCT", - "smokeThrownCTGood", - "smokeThrownCTGoodRatio", - "smokeThrownCTFoes", - "counterStrafingShotsAll", - "counterStrafingShotsBad", - "counterStrafingShotsGood", - "counterStrafingShotsGoodRatio", - "flashbangHitFoe", - "flashbangLeadingToKill", - "flashbangHitFoeAvgDuration", - "flashbangHitFriend", - "flashbangThrown", - "flashAssist", - "score", - "initialTeamNumber", - "mvps", - "ctRoundsWon", - "ctRoundsLost", - "tRoundsWon", - "tRoundsLost", - "sprayAccuracy", - "molotovFoesDamageAvg", - "molotovFriendsDamageAvg", - "color", - "totalKills", - "totalDeaths", - "kdRatio", - "multi2k", - "multi3k", - "multi4k", - "multi5k", - "hltvRating", - "hsp", - "roundsSurvived", - "roundsSurvivedPercentage", - "dpr", - "totalAssists", - "totalDamage", - "tradeKillOpportunities", - "tradeKillAttempts", - "tradeKillsSucceeded", - "tradeKillAttemptsPercentage", - "tradeKillsSuccessPercentage", - "tradeKillOpportunitiesPerRound", - "tradedDeathOpportunities", - "tradedDeathAttempts", - "tradedDeathAttemptsPercentage", - "tradedDeathsSucceeded", - "tradedDeathsSuccessPercentage", - "tradedDeathsOpportunitiesPerRound", - "leetifyRating", - "personalPerformanceRating", - "ctLeetifyRating", - "tLeetifyRating", - "leetifyUserId", - "isCollector", - "isProPlan", - "isLeetifyStaff", - ] - - return extract_cols(player_stats, cols) - - -def cols_from_profile_game(game: dict) -> dict: - cols = [ - "ctLeetifyRating", - "ctLeetifyRatingRounds", - "dataSource", - "elo", - "gameFinishedAt", - "gameId", - "isCs2", - "mapName", - "matchResult", - "scores", - "skillLevel", - "tLeetifyRating", - "tLeetifyRatingRounds", - "deaths", - "hasBannedPlayer", - "kills", - "partySize", - ] - return extract_cols(game, cols) - - -def meta_from_profile(profile: dict) -> dict: - meta = profile.get("meta") - if not meta: - raise Exception("Could not get profile metadata", profile) - - cols = [ - "name", - "steam64Id", - "isCollector", - "isLeetifyStaff", - "isProPlan", - "leetifyUserId", - "faceitNickname", - ] - - return extract_cols(meta, cols) - - -def insert_value(data: dict[T, U], key: T, value: U) -> dict[T, U]: - data[key] = value - return data - - -def convert_game_scores(game: dict) -> dict: - score = game.get("scores") - if not score: - raise Exception("Could not get score from prfile game", game) - - score = score_to_text(score) - game["scores"] = score - return game - - -def games_from_profile(profile: dict) -> list: - games = profile.get("games") - if not games and not type(games) == list: - raise Exception("Could not get games from profile", profile) - - meta = profile.get("meta") - if not meta: - raise Exception("Could not get profile metadata", profile) - - id = meta.get("leetifyUserId") - if not id: - raise Exception("Could not get id from profile metadata", meta, profile) - - games = map(cols_from_profile_game, games) - games = map(lambda game: insert_value(game, "leetifyUserId", id), games) - games = map(convert_game_scores, games) - return list(games) diff --git a/src/transform.py b/src/transform.py new file mode 100644 index 0000000..d8d3a66 --- /dev/null +++ b/src/transform.py @@ -0,0 +1,188 @@ +from typing import TypeVar + +T = TypeVar("T") +U = TypeVar("U") + + +def extract_cols(data: dict, cols: list[str]) -> dict: + return {key: data.get(key) for key in cols} + + +def score_to_text(score: list[int]) -> str: + return "-".join(map(str, score)) + + +# maybe could get columns form db +def cols_from_player_stats(player_stats: dict) -> dict: + cols = [ + "id", + "gameId", + "gameFinishedAt", + "steam64Id", + "name", + "preaim", + "reactionTime", + "accuracy", + "accuracyEnemySpotted", + "accuracyHead", + "shotsFiredEnemySpotted", + "shotsFired", + "shotsHitEnemySpotted", + "shotsHitFriend", + "shotsHitFriendHead", + "shotsHitFoe", + "shotsHitFoeHead", + "utilityOnDeathAvg", + "heFoesDamageAvg", + "heFriendsDamageAvg", + "heThrown", + "molotovThrown", + "smokeThrown", + "smokeThrownCT", + "smokeThrownCTGood", + "smokeThrownCTGoodRatio", + "smokeThrownCTFoes", + "counterStrafingShotsAll", + "counterStrafingShotsBad", + "counterStrafingShotsGood", + "counterStrafingShotsGoodRatio", + "flashbangHitFoe", + "flashbangLeadingToKill", + "flashbangHitFoeAvgDuration", + "flashbangHitFriend", + "flashbangThrown", + "flashAssist", + "score", + "initialTeamNumber", + "mvps", + "ctRoundsWon", + "ctRoundsLost", + "tRoundsWon", + "tRoundsLost", + "sprayAccuracy", + "molotovFoesDamageAvg", + "molotovFriendsDamageAvg", + "color", + "totalKills", + "totalDeaths", + "kdRatio", + "multi2k", + "multi3k", + "multi4k", + "multi5k", + "hltvRating", + "hsp", + "roundsSurvived", + "roundsSurvivedPercentage", + "dpr", + "totalAssists", + "totalDamage", + "tradeKillOpportunities", + "tradeKillAttempts", + "tradeKillsSucceeded", + "tradeKillAttemptsPercentage", + "tradeKillsSuccessPercentage", + "tradeKillOpportunitiesPerRound", + "tradedDeathOpportunities", + "tradedDeathAttempts", + "tradedDeathAttemptsPercentage", + "tradedDeathsSucceeded", + "tradedDeathsSuccessPercentage", + "tradedDeathsOpportunitiesPerRound", + "leetifyRating", + "personalPerformanceRating", + "ctLeetifyRating", + "tLeetifyRating", + "leetifyUserId", + "isCollector", + "isProPlan", + "isLeetifyStaff", + ] + + return extract_cols(player_stats, cols) + + +def cols_from_profile_game(game: dict) -> dict: + cols = [ + "ctLeetifyRating", + "ctLeetifyRatingRounds", + "dataSource", + "elo", + "gameFinishedAt", + "gameId", + "isCs2", + "mapName", + "matchResult", + "scores", + "skillLevel", + "tLeetifyRating", + "tLeetifyRatingRounds", + "deaths", + "hasBannedPlayer", + "kills", + "partySize", + ] + return extract_cols(game, cols) + + +def meta_from_profile(profile: dict) -> dict: + meta = profile.get("meta") + if not meta: + raise Exception("Could not get profile metadata", profile) + + cols = [ + "name", + "steam64Id", + "isCollector", + "isLeetifyStaff", + "isProPlan", + "leetifyUserId", + "faceitNickname", + ] + + return extract_cols(meta, cols) + + +def insert_value(data: dict[T, U], key: T, value: U) -> dict[T, U]: + data[key] = value + return data + + +def convert_game_scores(game: dict) -> dict: + score = game.get("scores") + if not score: + raise Exception("Could not get score from prfile game", game) + + score = score_to_text(score) + game["scores"] = score + return game + + +def games_from_profile(profile: dict) -> list: + games = profile.get("games") + # emtpy list is falsy but an acceptable value + if not games and not type(games) == list: + raise Exception("Could not get games from profile", profile) + + meta = profile.get("meta") + if not meta: + raise Exception("Could not get profile metadata", profile) + + id = meta.get("leetifyUserId") + if not id: + raise Exception("Could not get id from profile metadata", meta, profile) + + games = map(cols_from_profile_game, games) + games = map(lambda game: insert_value(game, "leetifyUserId", id), games) + games = map(convert_game_scores, games) + return list(games) + + +def player_stats_from_game(game: dict) -> list[dict]: + stats = game.get("playerStats") + if not stats: + raise Exception("Could not get stats from game", game) + + + stats = map(cols_from_player_stats,stats) + return list(stats) diff --git a/test/test_extract.py b/test/test_transform.py similarity index 57% rename from test/test_extract.py rename to test/test_transform.py index 2a2aa8f..f88c418 100644 --- a/test/test_extract.py +++ b/test/test_transform.py @@ -1,7 +1,6 @@ -from src import extract as ex +from src import transform as tr from pytest import fixture - @fixture def profile(): return { @@ -545,24 +544,356 @@ def profile(): @fixture -def games(profile): +def profile_games(profile): return profile["games"] +@fixture +def game(): + return { + "id": "a3f0c4b6-da37-43c4-8679-b6b858ec1600", + "dataSource": "faceit", + "isCs2": True, + "faceitMatchId": None, + "hltvMatchId": None, + "replayUrl": "https://demos-us-central1.faceit-cdn.net/cs2/1-55f0bdfc-d033-42d0-900d-9f0ec419946c-1-1.dem.gz", + "mapName": "de_ancient", + "teamScores": [10, 0], + "finishedAt": "2024-01-13T20:45:53.000Z", + "status": "ready", + "retries": 3, + "nextRetryAt": None, + "errorCode": None, + "recalculate": False, + "steamShareCode": None, + "createdAt": "2024-01-13T20:45:53.966Z", + "hasBannedPlayer": False, + "hasSkeletonStats": False, + "agents": [], + "details": { + "gameId": "a3f0c4b6-da37-43c4-8679-b6b858ec1600", + "gameFinishedAt": "2024-01-13T20:45:53.000Z", + "surrenderedByInitialTeamNumber": None, + "mpMaxrounds": 24, + "gameMode": None, + "gameType": None, + "tickrate": 64, + "ticks": 135463, + "serverName": "FACEIT.com register to play here", + }, + "playerStats": [ + { + "id": "f913fc05-40ff-4f55-b8b9-b46703317455", + "gameId": "a3f0c4b6-da37-43c4-8679-b6b858ec1600", + "gameFinishedAt": "2024-01-13T20:45:53.000Z", + "steam64Id": "76561198376400117", + "name": "TiMe_TrAvLeR", + "preaim": 8.5628, + "reactionTime": 0.75, + "accuracy": 0.2333, + "accuracyEnemySpotted": 0.4298, + "accuracyHead": 0.1774, + "shotsFiredEnemySpotted": 114, + "shotsFired": 270, + "shotsHitEnemySpotted": 49, + "shotsHitFriend": 0, + "shotsHitFriendHead": 0, + "shotsHitFoe": 63, + "shotsHitFoeHead": 0, + "utilityOnDeathAvg": 605.2632, + "heFoesDamageAvg": 14.25, + "heFriendsDamageAvg": 0, + "heThrown": 4, + "molotovThrown": 7, + "smokeThrown": 2, + "smokeThrownCT": 1, + "smokeThrownCTGood": 0, + "smokeThrownCTGoodRatio": 0, + "smokeThrownCTFoes": 0, + "counterStrafingShotsAll": 78, + "counterStrafingShotsBad": 10, + "counterStrafingShotsGood": 68, + "counterStrafingShotsGoodRatio": 0.8718, + "flashbangHitFoe": 0, + "flashbangLeadingToKill": 0, + "flashbangHitFoeAvgDuration": 0, + "flashbangHitFriend": 0, + "flashbangThrown": 0, + "flashAssist": 0, + "score": 39, + "initialTeamNumber": 3, + "mvps": 5, + "ctRoundsWon": 2, + "ctRoundsLost": 10, + "tRoundsWon": 8, + "tRoundsLost": 3, + "sprayAccuracy": 0.5405, + "utilityOnDeathValues": [], + "smokeThrownCTFoesDistances": [], + "heFoesDamages": [], + "heFriendsDamages": [], + "molotovFoesDamageAvg": 1.2857, + "molotovFriendsDamageAvg": 0, + "color": 0, + "achievements": { + "0": 0, + "1": 0, + "2": 0, + "3": 0, + "personal_best_all_time": 0, + }, + "totalKills": 17, + "totalDeaths": 19, + "kdRatio": 0.89, + "multi2k": 3, + "multi3k": 2, + "multi4k": 0, + "multi5k": 0, + "hltvRating": 0.99, + "hsp": 0.5882, + "roundsSurvived": 4, + "roundsSurvivedPercentage": 0.1739, + "dpr": 84.3, + "totalAssists": 5, + "totalDamage": 1939, + "tradeKillOpportunities": 2, + "tradeKillAttempts": 1, + "tradeKillsSucceeded": 0, + "tradeKillAttemptsPercentage": 0.5, + "tradeKillsSuccessPercentage": 0, + "tradeKillOpportunitiesPerRound": 0.087, + "tradedDeathOpportunities": 4, + "tradedDeathAttempts": 2, + "tradedDeathAttemptsPercentage": 0.5, + "tradedDeathsSucceeded": 1, + "tradedDeathsSuccessPercentage": 0.5, + "tradedDeathsOpportunitiesPerRound": 0.1739, + "leetifyRating": 0.009, + "personalPerformanceRating": 0.0199, + "ctLeetifyRating": -0.021, + "tLeetifyRating": 0.0417, + "leetifyUserId": "8c3a9cb5-faaf-4401-ae9a-72f5e8528651", + "isCollector": False, + "isProPlan": True, + "isLeetifyStaff": False, + }, + { + "id": "6b39dfc3-3d7d-42d0-b69e-a56289b7bd41", + "gameId": "a3f0c4b6-da37-43c4-8679-b6b858ec1600", + "gameFinishedAt": "2024-01-13T20:45:53.000Z", + "steam64Id": "76561198801253208", + "name": "Huaran070314", + "preaim": 5.5644, + "reactionTime": 0.5156, + "accuracy": 0.1693, + "accuracyEnemySpotted": 0.47, + "accuracyHead": 0.2419, + "shotsFiredEnemySpotted": 100, + "shotsFired": 378, + "shotsHitEnemySpotted": 47, + "shotsHitFriend": 0, + "shotsHitFriendHead": 0, + "shotsHitFoe": 64, + "shotsHitFoeHead": 0, + "utilityOnDeathAvg": 166.6667, + "heFoesDamageAvg": 20.1111, + "heFriendsDamageAvg": 1.5556, + "heThrown": 9, + "molotovThrown": 6, + "smokeThrown": 7, + "smokeThrownCT": 2, + "smokeThrownCTGood": 1, + "smokeThrownCTGoodRatio": 0.5, + "smokeThrownCTFoes": 2, + "counterStrafingShotsAll": 89, + "counterStrafingShotsBad": 10, + "counterStrafingShotsGood": 79, + "counterStrafingShotsGoodRatio": 0.8876, + "flashbangHitFoe": 10, + "flashbangLeadingToKill": 0, + "flashbangHitFoeAvgDuration": 3.0426, + "flashbangHitFriend": 8, + "flashbangThrown": 16, + "flashAssist": 1, + "score": 54, + "initialTeamNumber": 3, + "mvps": 3, + "ctRoundsWon": 2, + "ctRoundsLost": 10, + "tRoundsWon": 8, + "tRoundsLost": 3, + "sprayAccuracy": 0.6389, + "utilityOnDeathValues": [], + "smokeThrownCTFoesDistances": [], + "heFoesDamages": [], + "heFriendsDamages": [], + "molotovFoesDamageAvg": 5.6667, + "molotovFriendsDamageAvg": 0, + "color": 4, + "achievements": { + "0": 0, + "1": 0, + "2": 0, + "3": 0, + "personal_best_all_time": 0, + }, + "totalKills": 22, + "totalDeaths": 15, + "kdRatio": 1.47, + "multi2k": 4, + "multi3k": 2, + "multi4k": 0, + "multi5k": 0, + "hltvRating": 1.34, + "hsp": 0.6818, + "roundsSurvived": 8, + "roundsSurvivedPercentage": 0.3478, + "dpr": 109, + "totalAssists": 4, + "totalDamage": 2507, + "tradeKillOpportunities": 7, + "tradeKillAttempts": 5, + "tradeKillsSucceeded": 3, + "tradeKillAttemptsPercentage": 0.7143, + "tradeKillsSuccessPercentage": 0.6, + "tradeKillOpportunitiesPerRound": 0.35, + "tradedDeathOpportunities": 4, + "tradedDeathAttempts": 4, + "tradedDeathAttemptsPercentage": 1, + "tradedDeathsSucceeded": 2, + "tradedDeathsSuccessPercentage": 0.5, + "tradedDeathsOpportunitiesPerRound": 0.2, + "leetifyRating": 0.068, + "personalPerformanceRating": 0.0586, + "ctLeetifyRating": -0.0229, + "tLeetifyRating": 0.1672, + }, + { + "id": "67050cd7-efe3-42ad-8d8e-4f0687dd3180", + "gameId": "a3f0c4b6-da37-43c4-8679-b6b858ec1600", + "gameFinishedAt": "2024-01-13T20:45:53.000Z", + "steam64Id": "76561198883031817", + "name": "RIPMASTERR", + "preaim": 8.3357, + "reactionTime": 0.5781, + "accuracy": 0.2, + "accuracyEnemySpotted": 0.382, + "accuracyHead": 0.1163, + "shotsFiredEnemySpotted": 89, + "shotsFired": 225, + "shotsHitEnemySpotted": 34, + "shotsHitFriend": 0, + "shotsHitFriendHead": 0, + "shotsHitFoe": 45, + "shotsHitFoeHead": 0, + "utilityOnDeathAvg": 435.2941, + "heFoesDamageAvg": 5.2, + "heFriendsDamageAvg": 0, + "heThrown": 5, + "molotovThrown": 9, + "smokeThrown": 11, + "smokeThrownCT": 7, + "smokeThrownCTGood": 2, + "smokeThrownCTGoodRatio": 0.2857, + "smokeThrownCTFoes": 2, + "counterStrafingShotsAll": 29, + "counterStrafingShotsBad": 9, + "counterStrafingShotsGood": 20, + "counterStrafingShotsGoodRatio": 0.6897, + "flashbangHitFoe": 0, + "flashbangLeadingToKill": 0, + "flashbangHitFoeAvgDuration": 0, + "flashbangHitFriend": 0, + "flashbangThrown": 0, + "flashAssist": 0, + "score": 34, + "initialTeamNumber": 3, + "mvps": 0, + "ctRoundsWon": 2, + "ctRoundsLost": 10, + "tRoundsWon": 8, + "tRoundsLost": 3, + "sprayAccuracy": 0.2, + "utilityOnDeathValues": [], + "smokeThrownCTFoesDistances": [], + "heFoesDamages": [], + "heFriendsDamages": [], + "molotovFoesDamageAvg": 0.7778, + "molotovFriendsDamageAvg": 0, + "color": 3, + "achievements": { + "0": 0, + "1": 0, + "2": 0, + "3": 0, + "personal_best_all_time": 0, + }, + "totalKills": 12, + "totalDeaths": 17, + "kdRatio": 0.71, + "multi2k": 1, + "multi3k": 0, + "multi4k": 0, + "multi5k": 0, + "hltvRating": 0.67, + "hsp": 0.3333, + "roundsSurvived": 6, + "roundsSurvivedPercentage": 0.2609, + "dpr": 52.83, + "totalAssists": 3, + "totalDamage": 1215, + "tradeKillOpportunities": 6, + "tradeKillAttempts": 4, + "tradeKillsSucceeded": 3, + "tradeKillAttemptsPercentage": 0.6667, + "tradeKillsSuccessPercentage": 0.75, + "tradeKillOpportunitiesPerRound": 0.2609, + "tradedDeathOpportunities": 7, + "tradedDeathAttempts": 7, + "tradedDeathAttemptsPercentage": 1, + "tradedDeathsSucceeded": 2, + "tradedDeathsSuccessPercentage": 0.2857, + "tradedDeathsOpportunitiesPerRound": 0.3043, + "leetifyRating": -0.0432, + "personalPerformanceRating": -0.0347, + "ctLeetifyRating": -0.0801, + "tLeetifyRating": -0.003, + "leetifyUserId": "b94bd18e-9bb3-4150-aa5a-596adfe29103", + "isCollector": False, + "isProPlan": False, + "isLeetifyStaff": False, + }, + ], + "playerMatchResults": [], + "openingDuelPlayerStats": [], + "matchmakingGameStats": [], + "faceitGameStats": [], + "gamersClubGameStats": [], + "gamePlayerRoundSkeletonStats": [], + "replayFile": { + "id": "007d202f-8b72-4162-9f82-213c62dffef3", + "gameId": "a3f0c4b6-da37-43c4-8679-b6b858ec1600", + "createdAt": "2024-01-13T20:49:39.100Z", + "updatedAt": "2024-01-13T20:49:39.100Z", + }, + "parties": [], + } + + def test_extract_cols(profile): empty_dict = {} cols = ["meta"] - res = ex.extract_cols(empty_dict, []) + res = tr.extract_cols(empty_dict, []) assert res == {} - res = ex.extract_cols(empty_dict, cols) + res = tr.extract_cols(empty_dict, cols) assert res == {"meta": None} - res = ex.extract_cols(profile, []) + res = tr.extract_cols(profile, []) assert res == {} - res = ex.extract_cols(profile, cols) + res = tr.extract_cols(profile, cols) assert res == { "meta": { "name": "Skater", @@ -578,7 +909,7 @@ def test_extract_cols(profile): } cols.append("recentGameRatings") - res = ex.extract_cols(profile, cols) + res = tr.extract_cols(profile, cols) assert res == { "meta": { "name": "Skater", @@ -607,21 +938,21 @@ def test_extract_cols(profile): def test_score_to_text(): - text = ex.score_to_text([]) + text = tr.score_to_text([]) assert text == "" - text = ex.score_to_text([1]) + text = tr.score_to_text([1]) assert text == "1" - text = ex.score_to_text([1, 2]) + text = tr.score_to_text([1, 2]) assert text == "1-2" - text = ex.score_to_text([1, 2, 3]) + text = tr.score_to_text([1, 2, 3]) assert text == "1-2-3" def test_meta_from_profile(profile): - res = ex.meta_from_profile(profile) + res = tr.meta_from_profile(profile) assert res == { "name": "Skater", "steam64Id": "76561198036388580", @@ -637,11 +968,11 @@ def test_games_from_profile(profile): games = profile["games"].copy() profile["games"] = [] - res = ex.games_from_profile(profile) + res = tr.games_from_profile(profile) assert res == [] profile["games"] = games[:1] - res = ex.games_from_profile(profile) + res = tr.games_from_profile(profile) assert res == [ { "ctLeetifyRating": -0.0157, @@ -666,7 +997,7 @@ def test_games_from_profile(profile): ] profile["games"] = games - res = ex.games_from_profile(profile) + res = tr.games_from_profile(profile) assert res == [ { "ctLeetifyRating": -0.0157, @@ -789,3 +1120,261 @@ def test_games_from_profile(profile): "leetifyUserId": "6c53f87a-5877-4dd3-ab8f-527119ce4939", }, ] + + +def test_player_stats_from_game(game): + stats = tr.player_stats_from_game(game) + assert stats == [ + { + "id": "f913fc05-40ff-4f55-b8b9-b46703317455", + "gameId": "a3f0c4b6-da37-43c4-8679-b6b858ec1600", + "gameFinishedAt": "2024-01-13T20:45:53.000Z", + "steam64Id": "76561198376400117", + "name": "TiMe_TrAvLeR", + "preaim": 8.5628, + "reactionTime": 0.75, + "accuracy": 0.2333, + "accuracyEnemySpotted": 0.4298, + "accuracyHead": 0.1774, + "shotsFiredEnemySpotted": 114, + "shotsFired": 270, + "shotsHitEnemySpotted": 49, + "shotsHitFriend": 0, + "shotsHitFriendHead": 0, + "shotsHitFoe": 63, + "shotsHitFoeHead": 0, + "utilityOnDeathAvg": 605.2632, + "heFoesDamageAvg": 14.25, + "heFriendsDamageAvg": 0, + "heThrown": 4, + "molotovThrown": 7, + "smokeThrown": 2, + "smokeThrownCT": 1, + "smokeThrownCTGood": 0, + "smokeThrownCTGoodRatio": 0, + "smokeThrownCTFoes": 0, + "counterStrafingShotsAll": 78, + "counterStrafingShotsBad": 10, + "counterStrafingShotsGood": 68, + "counterStrafingShotsGoodRatio": 0.8718, + "flashbangHitFoe": 0, + "flashbangLeadingToKill": 0, + "flashbangHitFoeAvgDuration": 0, + "flashbangHitFriend": 0, + "flashbangThrown": 0, + "flashAssist": 0, + "score": 39, + "initialTeamNumber": 3, + "mvps": 5, + "ctRoundsWon": 2, + "ctRoundsLost": 10, + "tRoundsWon": 8, + "tRoundsLost": 3, + "sprayAccuracy": 0.5405, + "molotovFoesDamageAvg": 1.2857, + "molotovFriendsDamageAvg": 0, + "color": 0, + "totalKills": 17, + "totalDeaths": 19, + "kdRatio": 0.89, + "multi2k": 3, + "multi3k": 2, + "multi4k": 0, + "multi5k": 0, + "hltvRating": 0.99, + "hsp": 0.5882, + "roundsSurvived": 4, + "roundsSurvivedPercentage": 0.1739, + "dpr": 84.3, + "totalAssists": 5, + "totalDamage": 1939, + "tradeKillOpportunities": 2, + "tradeKillAttempts": 1, + "tradeKillsSucceeded": 0, + "tradeKillAttemptsPercentage": 0.5, + "tradeKillsSuccessPercentage": 0, + "tradeKillOpportunitiesPerRound": 0.087, + "tradedDeathOpportunities": 4, + "tradedDeathAttempts": 2, + "tradedDeathAttemptsPercentage": 0.5, + "tradedDeathsSucceeded": 1, + "tradedDeathsSuccessPercentage": 0.5, + "tradedDeathsOpportunitiesPerRound": 0.1739, + "leetifyRating": 0.009, + "personalPerformanceRating": 0.0199, + "ctLeetifyRating": -0.021, + "tLeetifyRating": 0.0417, + "leetifyUserId": "8c3a9cb5-faaf-4401-ae9a-72f5e8528651", + "isCollector": False, + "isProPlan": True, + "isLeetifyStaff": False, + }, + { + "id": "6b39dfc3-3d7d-42d0-b69e-a56289b7bd41", + "gameId": "a3f0c4b6-da37-43c4-8679-b6b858ec1600", + "gameFinishedAt": "2024-01-13T20:45:53.000Z", + "steam64Id": "76561198801253208", + "name": "Huaran070314", + "preaim": 5.5644, + "reactionTime": 0.5156, + "accuracy": 0.1693, + "accuracyEnemySpotted": 0.47, + "accuracyHead": 0.2419, + "shotsFiredEnemySpotted": 100, + "shotsFired": 378, + "shotsHitEnemySpotted": 47, + "shotsHitFriend": 0, + "shotsHitFriendHead": 0, + "shotsHitFoe": 64, + "shotsHitFoeHead": 0, + "utilityOnDeathAvg": 166.6667, + "heFoesDamageAvg": 20.1111, + "heFriendsDamageAvg": 1.5556, + "heThrown": 9, + "molotovThrown": 6, + "smokeThrown": 7, + "smokeThrownCT": 2, + "smokeThrownCTGood": 1, + "smokeThrownCTGoodRatio": 0.5, + "smokeThrownCTFoes": 2, + "counterStrafingShotsAll": 89, + "counterStrafingShotsBad": 10, + "counterStrafingShotsGood": 79, + "counterStrafingShotsGoodRatio": 0.8876, + "flashbangHitFoe": 10, + "flashbangLeadingToKill": 0, + "flashbangHitFoeAvgDuration": 3.0426, + "flashbangHitFriend": 8, + "flashbangThrown": 16, + "flashAssist": 1, + "score": 54, + "initialTeamNumber": 3, + "mvps": 3, + "ctRoundsWon": 2, + "ctRoundsLost": 10, + "tRoundsWon": 8, + "tRoundsLost": 3, + "sprayAccuracy": 0.6389, + "molotovFoesDamageAvg": 5.6667, + "molotovFriendsDamageAvg": 0, + "color": 4, + "totalKills": 22, + "totalDeaths": 15, + "kdRatio": 1.47, + "multi2k": 4, + "multi3k": 2, + "multi4k": 0, + "multi5k": 0, + "hltvRating": 1.34, + "hsp": 0.6818, + "roundsSurvived": 8, + "roundsSurvivedPercentage": 0.3478, + "dpr": 109, + "totalAssists": 4, + "totalDamage": 2507, + "tradeKillOpportunities": 7, + "tradeKillAttempts": 5, + "tradeKillsSucceeded": 3, + "tradeKillAttemptsPercentage": 0.7143, + "tradeKillsSuccessPercentage": 0.6, + "tradeKillOpportunitiesPerRound": 0.35, + "tradedDeathOpportunities": 4, + "tradedDeathAttempts": 4, + "tradedDeathAttemptsPercentage": 1, + "tradedDeathsSucceeded": 2, + "tradedDeathsSuccessPercentage": 0.5, + "tradedDeathsOpportunitiesPerRound": 0.2, + "leetifyRating": 0.068, + "personalPerformanceRating": 0.0586, + "ctLeetifyRating": -0.0229, + "tLeetifyRating": 0.1672, + "leetifyUserId": None, + "isCollector": None, + "isProPlan": None, + "isLeetifyStaff": None, + }, + { + "id": "67050cd7-efe3-42ad-8d8e-4f0687dd3180", + "gameId": "a3f0c4b6-da37-43c4-8679-b6b858ec1600", + "gameFinishedAt": "2024-01-13T20:45:53.000Z", + "steam64Id": "76561198883031817", + "name": "RIPMASTERR", + "preaim": 8.3357, + "reactionTime": 0.5781, + "accuracy": 0.2, + "accuracyEnemySpotted": 0.382, + "accuracyHead": 0.1163, + "shotsFiredEnemySpotted": 89, + "shotsFired": 225, + "shotsHitEnemySpotted": 34, + "shotsHitFriend": 0, + "shotsHitFriendHead": 0, + "shotsHitFoe": 45, + "shotsHitFoeHead": 0, + "utilityOnDeathAvg": 435.2941, + "heFoesDamageAvg": 5.2, + "heFriendsDamageAvg": 0, + "heThrown": 5, + "molotovThrown": 9, + "smokeThrown": 11, + "smokeThrownCT": 7, + "smokeThrownCTGood": 2, + "smokeThrownCTGoodRatio": 0.2857, + "smokeThrownCTFoes": 2, + "counterStrafingShotsAll": 29, + "counterStrafingShotsBad": 9, + "counterStrafingShotsGood": 20, + "counterStrafingShotsGoodRatio": 0.6897, + "flashbangHitFoe": 0, + "flashbangLeadingToKill": 0, + "flashbangHitFoeAvgDuration": 0, + "flashbangHitFriend": 0, + "flashbangThrown": 0, + "flashAssist": 0, + "score": 34, + "initialTeamNumber": 3, + "mvps": 0, + "ctRoundsWon": 2, + "ctRoundsLost": 10, + "tRoundsWon": 8, + "tRoundsLost": 3, + "sprayAccuracy": 0.2, + "molotovFoesDamageAvg": 0.7778, + "molotovFriendsDamageAvg": 0, + "color": 3, + "totalKills": 12, + "totalDeaths": 17, + "kdRatio": 0.71, + "multi2k": 1, + "multi3k": 0, + "multi4k": 0, + "multi5k": 0, + "hltvRating": 0.67, + "hsp": 0.3333, + "roundsSurvived": 6, + "roundsSurvivedPercentage": 0.2609, + "dpr": 52.83, + "totalAssists": 3, + "totalDamage": 1215, + "tradeKillOpportunities": 6, + "tradeKillAttempts": 4, + "tradeKillsSucceeded": 3, + "tradeKillAttemptsPercentage": 0.6667, + "tradeKillsSuccessPercentage": 0.75, + "tradeKillOpportunitiesPerRound": 0.2609, + "tradedDeathOpportunities": 7, + "tradedDeathAttempts": 7, + "tradedDeathAttemptsPercentage": 1, + "tradedDeathsSucceeded": 2, + "tradedDeathsSuccessPercentage": 0.2857, + "tradedDeathsOpportunitiesPerRound": 0.3043, + "leetifyRating": -0.0432, + "personalPerformanceRating": -0.0347, + "ctLeetifyRating": -0.0801, + "tLeetifyRating": -0.003, + "leetifyUserId": "b94bd18e-9bb3-4150-aa5a-596adfe29103", + "isCollector": False, + "isProPlan": False, + "isLeetifyStaff": False, + }, + ]