import json import os from datetime import datetime from logic.time_handler import get_time from logic.queue_handler import matchmaking_queue from flask_definitions import * @app.route("/api/v1/config/MATCH_MAKING_REGIONS/raw", methods=["GET"]) def match_making_regions_raw(): check_for_game_client("strict") try: return jsonify(["EU"]) except TimeoutError: return jsonify({"status": "error"}) except Exception as e: logger.graylog_logger(level="error", handler="matchmaking_RegionsRAW", message=e) @app.route("/api/v1/queue/info", methods=["GET"]) def queue_info(): try: # ?category=Steam-te-23ebf96c-27498-ue4-7172a3f5&gameMode=Default®ion=US&countA=1&countB=5 check_for_game_client("strict") session_cookie = sanitize_input(request.cookies.get("bhvrSession")) userid = session_manager.get_user_id(session_cookie) category = sanitize_input(request.args.get("category")) game_mode = sanitize_input(request.args.get("gameMode")) region = sanitize_input(request.args.get("region")) count_a = request.args.get("countA") # Hunter Count count_b = request.args.get("countB") # Runner Count side = sanitize_input(request.args.get("side", "")) session = matchmaking_queue.getSession(userid) if not side: return jsonify({"A": {"Size": 1, "ETA": 100, "stable": True}, "B": {"Size": 5, "ETA": 100, "stable": True}, "SizeA": count_a, "SizeB": count_b}) if side not in ["A", "B"]: return jsonify({"message": "Invalid side parameter"}), 400 response_data = matchmaking_queue.getQueueStatus(side, session, region) return jsonify(response_data) # return jsonify({"A": {"Size": 1, "ETA": 100, "stable": True}, "B": {"Size": 5, "ETA": 100, "stable": True}, "SizeA": count_a, "SizeB": count_b}) except TimeoutError: return jsonify({"status": "TimeoutError"}) except Exception as e: logger.graylog_logger(level="error", handler="queue_info", message=e) @app.route("/api/v1/queue", methods=["POST"]) def queue(): # {"category":"Steam-te-18f25613-36778-ue4-374f864b","rank":1,"side":"B","latencies":[],"additionalUserIds":[], # "checkOnly":false,"gameMode":"08d2279d2ed3fba559918aaa08a73fa8-Default","region":"US","countA":1,"countB":5} check_for_game_client("strict") session_cookie = sanitize_input(request.cookies.get("bhvrSession")) userid = session_manager.get_user_id(session_cookie) category = sanitize_input(request.json.get("category")) rank = request.json.get("rank") side = sanitize_input(request.json.get("side")) latencies = sanitize_input("latencies") additional_user_ids = request.json.get("additionalUserIds") check_only = request.json.get("checkOnly") # False = Searching. True = Is searching and waiting for match game_mode = sanitize_input(request.json.get("gameMode")) region = sanitize_input(request.json.get("region")) count_a = request.json.get("countA") count_b = request.json.get("countB") epoch = datetime.now().timestamp() if additional_user_ids: logger.graylog_logger(level="info", handler="logging_queue", message=f"User {userid} is queueing for {category} in " f"{region} with {count_a} hunters and {count_b} " f"runners and these additional Users {additional_user_ids}") else: logger.graylog_logger(level="info", handler="logging_queue", message=f"User {userid} is queueing for {category} in {region} with " f"{count_a} hunters and {count_b} runners") try: if not check_only: matchmaking_queue.queuePlayer(side=side, userId=userid) if additional_user_ids: for user in additional_user_ids: matchmaking_queue.queuePlayer(side=side, userId=user) response_data = { "queueData": { "ETA": -10000, "position": 0, "sizeA": 1 if side == "A" else 0, "sizeB": 1 if side == "B" else 0, "stable": False, }, "status": "QUEUED", } return jsonify(response_data) else: response_data = matchmaking_queue.getQueueStatus(side, userid, region) return jsonify(response_data) except Exception as e: logger.graylog_logger(level="error", handler="queue", message=e) return jsonify({"message": "Internal Server Error"}), 500 # if region == "DEV": # all_users = [userid] # if additional_user_ids: # all_users.append(additional_user_ids) # return jsonify( # {"status": "MATCHED", "QueueData": {"Position": 0, "ETA": 0, "Stable": False, "SizeA": 1, "SizeB": 4}, # "MatchData": {"MatchId": spoofed_match_id, "Category": category, "Rank": rank, # "CreationDateTime": epoch, "ExcludeFriends": False, # "ExcludeClanMembers": False, "Status": "CREATED", # "Creator": userid, # "Players": [all_users], # "SideA": [userid], # "SideB": [additional_user_ids], "CustomData": {}, # "Props": {"isDedicated": False, "gameMode": "08d2279d2ed3fba559918aaa08a73fa8-Default", # 'MatchConfiguration': '/Game/Configuration/MatchConfig/MatchConfig_Demo.MatchConfig_Demo'}, # "Schema": 11122334455666}}) # else: # return {"status": "QUEUED", "queueData": {"ETA": -10000, "position": 0, "stable": False}} # eta, position = match_manager.find_eta_and_position(data["_match_uuid"]) @app.route("/api/v1/queue/cancel", methods=["POST"]) def cancel_queue(): check_for_game_client("strict") session_cookie = sanitize_input(request.cookies.get("bhvrSession")) userid = session_manager.get_user_id(session_cookie) try: matchmaking_queue.removePlayerFromQueue(userid) except Exception as e: logger.graylog_logger(level="error", handler="queue", message=e) return jsonify({"message": "Internal Server Error"}), 500 return "", 204 @app.route("/api/v1/match/", methods=["GET"]) def match(matchid_unsanitized): matchid = sanitize_input(matchid_unsanitized) check_for_game_client("strict") session_cookie = sanitize_input(request.cookies.get("bhvrSession")) userid = session_manager.get_user_id(session_cookie) try: response_data = matchmaking_queue.createMatchResponse(matchId=matchid, userId=userid) # logger.graylog_logger(level="debug", handler="match", message=response_data) if response_data == "null" or response_data is None: logger.graylog_logger(level="error", handler="match", message=f"MatchResponse is null for MatchID: {matchid}") return { "Category": "Steam-te-18f25613-36778-ue4-374f864b", "creationDateTime": 0, "creator": None, "customData": { }, "MatchId": matchid, "props": { "countA": 0, "countB": 0, "gameMode": None, "MatchConfiguration": None, "platform": "Windows", }, "rank": 1, "Schema": 3, "sideA": [], "sideB": [], "Players": [], "status": "Destroyed" } # response_data = matchmaking_queue.getKilledLobbyById(matchid) # logger.graylog_logger(level="debug", handler="match", message=response_data) return jsonify(response_data) except Exception as e: logger.graylog_logger(level="error", handler="match", message=e) return jsonify({"message": "Internal Server Error"}), 500 @app.route("/api/v1/match//Kill", methods=["PUT"]) def match_kill(matchid_unsanitized): matchid = sanitize_input(matchid_unsanitized) check_for_game_client("strict") session_cookie = sanitize_input(request.cookies.get("bhvrSession")) userid = session_manager.get_user_id(session_cookie) try: lobby, _ = matchmaking_queue.getLobbyById(matchid) if lobby and matchmaking_queue.isOwner(matchid, userid): response_data = matchmaking_queue.createMatchResponse(matchId=matchid, killed=True) matchmaking_queue.deleteMatch(matchid) logger.graylog_logger(level="info", handler="match_kill", message=f"Killed Match: {matchid}" f"by User: {userid}") return jsonify(response_data) else: return jsonify({"message": "Unauthorized"}), 401 except Exception as e: logger.graylog_logger(level="error", handler="match", message=e) return jsonify({"message": "Internal Server Error"}), 500 @app.route("/api/v1/match//register", methods=["POST"]) def match_register(match_id_unsanitized): try: check_for_game_client("strict") session_cookie = sanitize_input(request.cookies.get("bhvrSession")) userid = session_manager.get_user_id(session_cookie) match_id = sanitize_input(match_id_unsanitized) logger.graylog_logger(level="info", handler="match_register", message=f"User {userid} is registering to match {match_id}") data = request.json custom_data = data.get("customData", {}) session_settings = custom_data.get("SessionSettings", "") response = matchmaking_queue.registerMatch(match_id, session_settings, userid) if response: if use_discord: game_mode = response["props"]["gameMode"] if game_mode == "789c81dfb11fe39b7247c7e488e5b0d4-Default": game_mode = "Default" elif game_mode == "08d2279d2ed3fba559918aaa08a73fa8-Default": game_mode = "Default" elif game_mode == "d071fb6678668246d6d999c9892c2a60-Default": game_mode = "Default" elif game_mode == "e3744bb4acbc0e5dc107e999c6132f18-Default": game_mode = "REMIX" elif game_mode == "a0fdf9ce92261dcc5492f353b62f34f3-Default": game_mode = "4 Needles" else: game_mode = "Default" match_configuration = response["props"]["MatchConfiguration"] if match_configuration == "/Game/Configuration/MatchConfig/MatchConfig_Demo_HarvestYourExit_1v5.MatchConfig_Demo_HarvestYourExit_1v5": match_configuration = "Harvest Your Exit 1v5" elif match_configuration == "/Game/Configuration/MatchConfig/MatchConfig_Demo.MatchConfig_Demo": match_configuration = "Survival" elif match_configuration == "/Game/Configuration/MatchConfig/MatchConfig_ARC_Fortress.MatchConfig_ARC_Fortress": match_configuration = "Arctic Fortress" elif match_configuration == "/Game/Configuration/MatchConfig/MatchConfig_CustomMatch.MatchConfig_CustomMatch": match_configuration = "REMIX Deathgarden - Gold Rush" elif match_configuration == "/Game/Configuration/MatchConfig/MatchConfig_Demo_2v8_4Needles.MatchConfig_Demo_2v8_4Needles": match_configuration = "Harvest Your Exit 4Needles" elif match_configuration == "/Game/Configuration/MatchConfig/MatchConfig_DES_City_2Hunters.MatchConfig_DES_City_2Hunters": match_configuration = "Desert City 5 needles" elif match_configuration == "/Game/Configuration/MatchConfig/MatchConfig_WA_Rivers.MatchConfig_WA_Rivers": match_configuration = "Creek" elif match_configuration == "/Game/Configuration/MatchConfig/MatchConfig_WA_Cemetery.MatchConfig_WA_Cemetery": match_configuration = "Tombstone" elif match_configuration == "/Game/Configuration/MatchConfig/MatchConfig_DES_Oilfield.MatchConfig_DES_Oilfield": match_configuration = "Blowout" elif match_configuration == "/Game/Configuration/MatchConfig/MatchConfig_ARC_BlastFurnace.MatchConfig_ARC_BlastFurnace": match_configuration = "Fire in the Sky" elif match_configuration == "/Game/Configuration/MatchConfig/MatchConfig_DES_Mayan.MatchConfig_DES_Mayan": match_configuration = "Dust & Blood" elif match_configuration == "/Game/Configuration/MatchConfig/MatchConfig_ARC_Expedition.MatchConfig_ARC_Expedition": match_configuration = "Arctic Expedition" elif match_configuration == "/Game/Configuration/MatchConfig/MatchConfig_RUI_All.MatchConfig_RUI_All": match_configuration = "First Strike" if dev_env == "false": webhook_data = { "content": "", "embeds": [ { "title": f"Match Registered", "description": f"MatchID: {match_id} \n GameMode: {game_mode} \n MatchConfiguration: {match_configuration}", "color": 7932020 } ], "attachments": [] } try: discord_webhook(url_list, webhook_data) except Exception as e: logger.graylog_logger(level="error", handler="discord_webhook_message", message=e) return jsonify(response) else: return jsonify({"message": "Match registration failed"}), 500 except Exception as e: logger.graylog_logger(level="error", handler="match_register", message=e) return jsonify({"message": "Internal Server Error"}), 500 @app.route("/api/v1/match//Quit", methods=["PUT"]) def match_quit(match_id_unsanitized): try: # todo If OWNER Crash -> Runner sends QUIT acknowledge when players less then 2 check_for_game_client("strict") session_cookie = sanitize_input(request.cookies.get("bhvrSession")) userid = session_manager.get_user_id(session_cookie) match_id = sanitize_input(match_id_unsanitized) logger.graylog_logger(level="info", handler="logging_queue", message=f"User {userid} is quitting match {match_id}") lobby, _ = matchmaking_queue.getLobbyById(match_id) if lobby: if matchmaking_queue.isOwner(match_id, userid): matchmaking_queue.deleteMatch(match_id) else: matchmaking_queue.removePlayerFromQueue(userid) matchmaking_queue.remove_player_from_match(match_id, userid) return "", 204 else: return jsonify({"message": "Match not found"}), 404 except Exception as e: logger.graylog_logger(level="error", handler="logging_queue", message=e) return jsonify({"status": "ERROR"}), 500 @app.route("/api/v1/match//Close", methods=["PUT"]) def close_lobby(match_id_unsanitized): check_for_game_client("strict") session_cookie = sanitize_input(request.cookies.get("bhvrSession")) userid = session_manager.get_user_id(session_cookie) match_id = sanitize_input(match_id_unsanitized) try: lobby, _ = matchmaking_queue.getLobbyById(match_id) if lobby: if matchmaking_queue.isOwner(match_id, userid): #matchmaking_queue.deleteMatch(match_id) #return "", 204 # set lobby.status to "Closed" matchmaking_queue.closeMatch(match_id) data = matchmaking_queue.createMatchResponse(matchId=match_id, killed=False, userId=userid) return jsonify(data), 200 else: return jsonify({"message": "Unauthorized"}), 401 else: return jsonify({"message": "Match not found"}), 404 except Exception as e: logger.graylog_logger(level="error", handler="close_lobby", message=e) return jsonify({"message": "Internal Server Error"}), 500 @app.route("/api/v1/match/create", methods=["POST"]) def match_create(): # {'category': 'Steam-te-18f25613-36778-ue4-374f864b', 'region': 'US', 'playersA': [], # 'playersB': ['00658d11-2dfd-41e8-b6d2-2462e8f3aa47', '95041085-e7e4-4759-be3d-e72c69167578', # '0385496c-f0ae-44d3-a777-26092750f39c'], # 'props': {'MatchConfiguration': '/Game/Configuration/MatchConfig/MatchConfig_Demo.MatchConfig_Demo'}, # 'latencies': []} check_for_game_client("strict") session_cookie = sanitize_input(request.cookies.get("bhvrSession")) userid = session_manager.get_user_id(session_cookie) category = sanitize_input(request.json.get("category")) region = sanitize_input(request.json.get("region")) players_a = request.json.get("playersA") players_b = request.json.get("playersB") props = request.json.get("props")["MatchConfiguration"] # match_send = matchmaking_queue.createQueueResponseMatched(userid, matchid, joinerId=players_a) epoch = datetime.now().timestamp() player_list = [] for player in players_a: player_list.append(player) for player in players_b: player_list.append(player) matchid, Match_Config = matchmaking_queue.register_private_match(players_a=players_a, players_b=players_b, match_config=props) # EPrivateMatchState: # Disabled # InGameSession # NotCreated # NotEnoughPlayers # HunterNotSelected # CanStart # EMatchmakingState: # None # SearchingForMatch # WaitingForPlayers data = {"MatchId": matchid, "Category": category, "Rank": 1, "Region": region, "CreationDateTime": epoch, "ExcludeFriends": False, "ExcludeClanMembers": False, "Status": "OPEN", "Reason": "FString", "Creator": userid, "Players": player_list, "SideA": players_a, "SideB": players_b, "CustomData": {}, "Props": props, "Schema": 1} users = players_a.copy() users.append(players_b) current_time = get_time()[0] countB = len(players_b) data = { "status": "PendingWarparty", "QueueData": { "Position": 1, "ETA": 0, "Stable": False, "SizeA": 1, "SizeB": countB }, "matchData": { "category": "Steam-te-18f25613-36778-ue4-374f864b", "creationDateTime": current_time, "creator": players_a, "customData": {}, "matchId": matchid, "props": { "countA": 1, "countB": countB, "gameMode": Match_Config["gameMode"], "MatchConfiguration": Match_Config["MatchConfiguration"], "platform": "Windows", }, "rank": 1, "schema": 3, "sideA": players_a, "sideB": players_b, "Players": users, "status": "CREATED" } } return jsonify(data) @app.route("/api/v1/extensions/progression/playerEndOfMatch", methods=["POST"]) def progression_player_end_of_match(): # { # "data":{ # "playerId":"00658d11-2dfd-41e8-b6d2-2462e8f3aa47", # "faction":"Runner", # "characterGroup":"RunnerGroupE", # "playtime":547, # "platform":"PC", # "hasQuit":false, # "characterState":"Escaped", # "matchId":"A9B72FEC485695753C8181AE3168877B-1", # "experienceEvents":[ # { # "type":"MarkedSupplier", # "amount":600 # }, # { # "type":"ResourceLootBonus", # "amount":510 # }, # { # "type":"PlayTime", # "amount":45 # }, # { # "type":"FriendlyEffectBonus", # "amount":975 # }, # { # "type":"ResourceDepositBonus", # "amount":3750 # }, # { # "type":"GoldenCrateLootBonus", # "amount":5 # }, # { # "type":"EscapeBonus", # "amount":1000 # }, # { # "type":"ResourceEscapeBonus", # "amount":20 # }, # { # "type":"BloodModeEscapeBonus", # "amount":100 # } # ], # "earnedCurrencies":[ # { # "currencyName":"CurrencyA", # "amount":617 # }, # { # "currencyName":"CurrencyB", # "amount":620 # }, # { # "currencyName":"CurrencyC", # "amount":619 # } # ], # "completedChallenges":[ # { # "challengeId":"24CE65364362CB2A90C0E08876176937", # "challengeType":"Challenge.Type.Progression" # }, # { # "challengeId":"B4B156CC47C8D987B9BDBEB910B12C9E", # "challengeType":"Challenge.Type.Progression" # }, # { # "challengeId":"ECCBA78D4055676F9C17D79B9D5FA2D4", # "challengeType":"Challenge.Type.Progression" # } # ] # } # } # check_for_game_client("strict") session_cookie = sanitize_input(request.cookies.get("bhvrSession")) # userid = session_manager.get_user_id(session_cookie) try: logger.graylog_logger(level="info", handler="matchmaking_playerEndOfMatch", message=request.get_json()) data = request.get_json()["data"] userid = data["playerId"] characterGroup = data["characterGroup"] experience = 0 for event in data["experienceEvents"]: experience += event["amount"] update_user_xp(userid, experience, characterGroup) user_wallet = mongo.get_data_with_list(login=userid, login_steam=False, items={"currency_iron", "currency_blood_cells", "currency_ink_cells"}) CurrencyA = user_wallet["currency_iron"] CurrencyB = user_wallet["currency_blood_cells"] CurrencyC = user_wallet["currency_ink_cells"] wallet = [] for currency in data["earnedCurrencies"]: if currency["currencyName"] == "CurrencyA": wallet.append({"Currency": "CurrencyA", "Amount": currency["amount"]}) CurrencyA += currency["amount"] elif currency["currencyName"] == "CurrencyB": wallet.append({"Currency": "CurrencyB", "Amount": currency["amount"]}) CurrencyB += currency["amount"] elif currency["currencyName"] == "CurrencyC": wallet.append({"Currency": "CurrencyC", "Amount": currency["amount"]}) CurrencyC += currency["amount"] mongo.write_data_with_list(login=userid, login_steam=False, items_dict={"currency_iron": CurrencyA, "currency_blood_cells": CurrencyB, "currency_ink_cells": CurrencyC}) # return jsonify({ # "Player": { # "InitialExperienceProgressions": [ # FGMProgressionExperienceModel # ], # "NewExperienceProgressions": [ # FGMProgressionExperienceModel # ], # "TotalEarnedCurrency": [ # FCurrencyModel # ], # "Wallet": [ # FCurrencyModel # ], # "Events": [ # FGMExperienceEvent # ] # } # }) # MirrorsExtModelProgressionPlayerEndOfMatchResponse # todo remove this test return jsonify({"Player": {"Success": True}}) return jsonify({ "Player": { "InitialExperienceProgressions": [ { "ObjectId": characterGroup, "Level": 1, "ExperienceToReach": 100000, "CurrentExperience": 1 } ], "NewExperienceProgressions": [ { "ObjectId": characterGroup, "Level": 1, "ExperienceToReach": 100000, "CurrentExperience": experience } ], "TotalEarnedCurrency": wallet, "Wallet": wallet, "Events": [ ] } }) except TimeoutError: return jsonify({"status": "error"}) except Exception as e: logger.graylog_logger(level="error", handler="matchmaking_playerEndOfMatch", message=e) @app.route("/api/v1/extensions/progression/endOfMatch", methods=["POST"]) def progression_end_of_match(): # todo Implement this fully # { # "data":{ # "players":[ # { # "playerId":"619d6f42-db87-4f3e-8dc9-3c9995613614", # "faction":"Runner", # "characterGroup":"RunnerGroupE", # "platform":"PC", # "hasQuit":false, # "characterState":"Dead" # }, # { # "playerId":"95041085-e7e4-4759-be3d-e72c69167578", # "faction":"Hunter", # "characterGroup":"HunterGroupB", # "platform":"PC", # "hasQuit":false, # "characterState":"InArena" # }, # { # "playerId":"00658d11-2dfd-41e8-b6d2-2462e8f3aa47", # "faction":"Runner", # "characterGroup":"RunnerGroupB", # "platform":"PC", # "hasQuit":false, # "characterState":"Dead" # } # ], # "dominantFaction":"Hunter", # "matchId":"df9655d9-63ac-4dde-a9e9-129aaa249356" # } # } check_for_game_client("strict") session_cookie = sanitize_input(request.cookies.get("bhvrSession")) userid = session_manager.get_user_id(session_cookie) try: players = [] for player in request.get_json()["data"]["players"]: player = player["playerId"] response = { "playerId": player, # What could this struct be???? } logger.graylog_logger(level="info", handler="matchmaking_endOfMatch", message=request.get_json()) matchId = request.get_json()["data"]["matchId"] matchmaking_queue.deleteMatch(matchId) return jsonify({"Success": True}) except TimeoutError: return jsonify({"Success": False}) except Exception as e: logger.graylog_logger(level="error", handler="matchmaking_endOfMatch", message=e) return jsonify({"Success": False}) @app.route("/metrics/endofmatch/event", methods=["POST"]) def metrics_end_of_match_event(): # # { # "matchId": "A9B72FEC485695753C8181AE3168877B-1", # "gameVersion": "te-f9b4768a-26590-ue4-cefc1aee", # "roundEvents": [ # { # "round": 1, # "roundLength": 547, # "gamemode": "None", # "biomeName": "", # "randomSeed": 0, # "runnerCount": 2, # "hunterCount": 0, # "weather": "", # "supplierCounts": [], # "endOfRoundObjectiveState": # { # "bAreObjectivesCompleted": false, # "fullyCapturedObjectivesCount": 0, # "objectivesFilledCompartmentsCount": 0, # "progressionByObjective": [] # }, # "endOfRoundExitState": # { # "bAreExitOpened": true, # "openTime": 548.63604736328125, # "openReason": "HunterDomination", # "exitCoords": [ # { # "x": -4371.796875, # "y": -7400, # "z": -400 # }, # { # "x": 3942.046875, # "y": 7000, # "z": -400 # } # ] # } # } # ], # "runnerMatchAnalytics": [ # { # "roundEvents": [ # { # "caltrops": [], # "specialArrows": [], # "role": "PlayerRole.Support", # "state": "Escaped", # "suicideCount": 0, # "timeOfDeath": -1, # "rescueCount": 0, # "rescuedCount": 0, # "downedCount": 0, # "damageDealtToHunter": 0, # "damageDealtToMines": 0, # "damageDealtToTurrets": 0, # "damageDealtToDrones": 44, # "arenaObjectivesMarked": 0, # "resourceSuppliersMarked": 1, # "totalObjectsMarked": 1, # "murderPostRescueCount": 0, # "rescuedFromMurderPostCount": 0, # "sentToMurderPostCount": 0, # "hunterHitsCount": 0, # "unsecuredBloodCount": 0, # "bankedBloodCount": 0, # "round": 1, # "gamemode": "", # "country": "DE", # "gender": "Male", # "damageTaken": 0, # "headshotCount": 0, # "longestHeadshotDistance": -1, # "totalShotsFired": 3, # "supplierUsedCounts": [ # { # "type": "SupplyCrate_AmmunitionPack_C", # "count": 3 # }, # { # "type": "SupplyCrate_WeaponParts_C", # "count": 1 # }, # { # "type": "BP_ResourceCrate_ResourceTypeB_C", # "count": 66 # }, # { # "type": "GoldenCrate_Unlimited_C", # "count": 1 # } # ], # "resourcesUsage": [ # { # "type": "Resource.Ammo.ReserveEarned", # "amount": 34 # }, # { # "type": "Resource.NPIEarned", # "amount": 3 # }, # { # "type": "Resource.NPIExpended", # "amount": 3 # }, # { # "type": "Resource.ResourceCharge.TypeB.UnsecuredEarned", # "amount": 66 # }, # { # "type": "Resource.ResourceCharge.TypeB.UnsecuredExpended", # "amount": 56 # }, # { # "type": "Resource.ResourceCharge.TypeB.BankedEarned", # "amount": 56 # }, # { # "type": "Resource.Ammo.ClipExpended", # "amount": 2 # } # ], # "pingInformation": # { # "readCount": 108, # "average": 0, # "variance": 0, # "maximum": 0, # "minimum": 0 # }, # "crouchingTime": 18.294017791748047, # "capturingObjectivesTime": 0, # "holdingKeyTime": 0, # "keysDelivered": 0, # "objectsDestroyedCount": 1, # "perksChosen": [ # "Shimmey", # "Ammo Opportunist" # ], # "chatMessagesCounts": [], # "effectsAppliedCounts": [], # "customizationItems": [ # { # "itemSlot": "Head", # "customizationItem": "Default Smoke Head" # }, # { # "itemSlot": "Outfit", # "customizationItem": "Default Smoke Upperbody" # }, # { # "itemSlot": "Lower Body Section", # "customizationItem": "Default Smoke Lowerbody" # }, # { # "itemSlot": "Gauntlet", # "customizationItem": "Default Smoke Vambrace" # } # ], # "customizationWeaponSkins": [], # "chaseAmount": 0, # "chaseAmountEscape": 0 # } # ], # "playerName": "HEX: Dino Nuggies", # "playerUniqueId": "619d6f42-db87-4f3e-8dc9-3c9995613614", # "playerSessionId": "71E8AFB54DFFCC83A69D3F80A5CBADD5" # }, # { # "roundEvents": [ # { # "caltrops": [], # "specialArrows": [], # "role": "PlayerRole.Support", # "state": "Escaped", # "suicideCount": 0, # "timeOfDeath": -1, # "rescueCount": 0, # "rescuedCount": 0, # "downedCount": 0, # "damageDealtToHunter": 0, # "damageDealtToMines": 0, # "damageDealtToTurrets": 0, # "damageDealtToDrones": 0, # "arenaObjectivesMarked": 5, # "resourceSuppliersMarked": 26, # "totalObjectsMarked": 31, # "murderPostRescueCount": 0, # "rescuedFromMurderPostCount": 0, # "sentToMurderPostCount": 0, # "hunterHitsCount": 0, # "unsecuredBloodCount": 0, # "bankedBloodCount": 0, # "round": 1, # "gamemode": "", # "country": "DE", # "gender": "Male", # "damageTaken": 0, # "headshotCount": 0, # "longestHeadshotDistance": -1, # "totalShotsFired": 76, # "supplierUsedCounts": [ # { # "type": "SupplyCrate_AmmunitionPack_C", # "count": 3 # }, # { # "type": "SupplyCrate_WeaponParts_C", # "count": 2 # }, # { # "type": "BP_ResourceCrate_ResourceTypeB_C", # "count": 51 # }, # { # "type": "GoldenCrate_Unlimited_C", # "count": 1 # } # ], # "resourcesUsage": [ # { # "type": "Resource.Ammo.ReserveEarned", # "amount": 34 # }, # { # "type": "Resource.Ammo.ClipExpended", # "amount": 35 # }, # { # "type": "Resource.NPIEarned", # "amount": 6 # }, # { # "type": "Resource.NPIExpended", # "amount": 6 # }, # { # "type": "Resource.ResourceCharge.TypeB.UnsecuredEarned", # "amount": 51 # }, # { # "type": "Resource.ResourceCharge.TypeB.UnsecuredExpended", # "amount": 50 # }, # { # "type": "Resource.ResourceCharge.TypeB.BankedEarned", # "amount": 50 # } # ], # "pingInformation": # { # "readCount": 110, # "average": 225, # "variance": 82.481819152832031, # "maximum": 268, # "minimum": 215 # }, # "crouchingTime": 13.677490234375, # "capturingObjectivesTime": 0, # "holdingKeyTime": 0, # "keysDelivered": 0, # "objectsDestroyedCount": 0, # "perksChosen": [ # "Shimmey", # "Ammo Opportunist" # ], # "chatMessagesCounts": [ # { # "messageType": "IntelliCommsMsgNoChannel", # "messageCount": 3 # }, # { # "messageType": "IntelliCommsMsgFaction", # "messageCount": 23 # } # ], # "effectsAppliedCounts": [ # { # "effectSource": "BP_Arrow_SmokeScreen_C", # "count": 39 # } # ], # "customizationItems": [ # { # "itemSlot": "Head", # "customizationItem": "Default Smoke Head" # }, # { # "itemSlot": "Outfit", # "customizationItem": "Default Smoke Upperbody" # }, # { # "itemSlot": "Lower Body Section", # "customizationItem": "Default Smoke Lowerbody" # }, # { # "itemSlot": "Gauntlet", # "customizationItem": "Default Smoke Vambrace" # } # ], # "customizationWeaponSkins": [], # "chaseAmount": 0, # "chaseAmountEscape": 0 # } # ], # "playerName": "Miraak", # "playerUniqueId": "00658d11-2dfd-41e8-b6d2-2462e8f3aa47", # "playerSessionId": "B9BB33074498771555A3DBAF95D124CE" # }, # { # "roundEvents": [ # { # "caltrops": [], # "specialArrows": [], # "role": "", # "state": "Alive", # "suicideCount": 0, # "timeOfDeath": -1, # "rescueCount": 0, # "rescuedCount": 0, # "downedCount": 0, # "damageDealtToHunter": 0, # "damageDealtToMines": 0, # "damageDealtToTurrets": 0, # "damageDealtToDrones": 0, # "arenaObjectivesMarked": 0, # "resourceSuppliersMarked": 0, # "totalObjectsMarked": 0, # "murderPostRescueCount": 0, # "rescuedFromMurderPostCount": 0, # "sentToMurderPostCount": 0, # "hunterHitsCount": 0, # "unsecuredBloodCount": 0, # "bankedBloodCount": 0, # "round": 1, # "gamemode": "", # "country": "", # "gender": "", # "damageTaken": 0, # "headshotCount": 0, # "longestHeadshotDistance": -1, # "totalShotsFired": 0, # "supplierUsedCounts": [], # "resourcesUsage": [], # "pingInformation": # { # "readCount": 1, # "average": 0, # "variance": 0, # "maximum": 0, # "minimum": 0 # }, # "crouchingTime": 0, # "capturingObjectivesTime": 0, # "holdingKeyTime": 0, # "keysDelivered": 0, # "objectsDestroyedCount": 0, # "perksChosen": [], # "chatMessagesCounts": [], # "effectsAppliedCounts": [], # "customizationItems": [], # "customizationWeaponSkins": [], # "chaseAmount": 0, # "chaseAmountEscape": 0 # } # ], # "playerName": "", # "playerUniqueId": "", # "playerSessionId": "" # } # ], # "hunterMatchAnalytics": [], # "hitDetectionErrorRate": 0, # "hitDetectionErrors": [], # "lobbyAnalytics": [], # "eventType": "Server" # } # check_for_game_client("strict") try: data = request.get_json() # Keys LV 1 match_id = data["matchId"] game_version = data["gameVersion"] round_events = data["roundEvents"] runner_match_analytics = data["runnerMatchAnalytics"] hunter_match_analytics = data["hunterMatchAnalytics"] hit_detection_error_rate = data["hitDetectionErrorRate"] hit_detection_errors = data["hitDetectionErrors"] lobby_analytics = data["lobbyAnalytics"] event_type = data["eventType"] # Keys round_events round_events_item1 = round_events[0] round_value = round_events_item1["round"] round_length = round_events_item1["roundLength"] # gamemode = round_events_item1["gamemode"] biome_name = round_events_item1["biomeName"] random_seed = round_events_item1["randomSeed"] runner_count = round_events_item1["runnerCount"] hunter_count = round_events_item1["hunterCount"] weather = round_events_item1["weather"] supplier_counts = round_events_item1["supplierCounts"] end_of_round_objective_state = round_events_item1["endOfRoundObjectiveState"] end_of_round_exit_state = round_events_item1["endOfRoundExitState"] # Keys end_of_round_objective_state b_are_objectives_completed = end_of_round_objective_state["bAreObjectivesCompleted"] fully_captured_objectives_count = end_of_round_objective_state["fullyCapturedObjectivesCount"] objectives_filled_compartments_count = end_of_round_objective_state["objectivesFilledCompartmentsCount"] progression_by_objective = end_of_round_objective_state["progressionByObjective"] # Keys end_of_round_exit_state b_are_exit_opened = end_of_round_exit_state["bAreExitOpened"] open_time = end_of_round_exit_state["openTime"] open_reason = end_of_round_exit_state["openReason"] exit_coords = end_of_round_exit_state["exitCoords"] # keys exit_coords # Per Player XYZ # Keys runner_match_analytics # For all players in game LOOP Func roundEvents = runner_match_analytics[0]["roundEvents"] playerName = runner_match_analytics[0]["playerName"] playerUniqueId = runner_match_analytics[0]["playerUniqueId"] playerSessionId = runner_match_analytics[0]["playerSessionId"] # Keys hunter_match_analytics # Keys hit_detection_errors # Keys lobby_analytics logger.graylog_logger(level="info", handler="logging_endOfMatch_Event", message=data) return jsonify({"Success": True}) except TimeoutError: return jsonify({"Success": False}) except Exception as e: logger.graylog_logger(level="error", handler="logging_endOfMatch_Event", message=e) @app.route("/file///", methods=["POST", "GET"]) def file_gold_rush(seed_unsanitized, map_name_unsanitized, game_version_unsanitized): check_for_game_client("strict") session_cookie = sanitize_input(request.cookies.get("bhvrSession")) game_version = sanitize_input(game_version_unsanitized) seed = sanitize_input(seed_unsanitized) map_name = sanitize_input(map_name_unsanitized) userid = session_manager.get_user_id(session_cookie) file_name = f"{game_version}_{seed}_{map_name}.raw" folder_path = os.path.join(app.root_path, "map_seeds") file_path = os.path.join(folder_path, file_name) os.makedirs(folder_path, exist_ok=True) if request.method == "GET": if os.path.isfile(file_path): with open(file_path, "rb") as files: data = files.read() return data if request.method == "POST": data = request.get_data() with open(file_path, "wb") as files: files.write(data) return {"status": "success"} @app.route("/metrics/matchmaking/event", methods=["POST"]) def metrics_matchmaking_event(): check_for_game_client("strict") session_cookie = sanitize_input(request.cookies.get("bhvrSession")) userid = session_manager.get_user_id(session_cookie) try: logger.graylog_logger(level="info", handler="logging_matchmaking_Event", message=request.get_json()) # { # "playerId": "619d6f42-db87-4f3e-8dc9-3c9995613614", # "matchId": "", # "playerRole": "Leader", # "faction": "Runner", # "endState": "Cancelled", # "group": "Default", # "region": "EU", # "groupSize": 1, # "beginTime": 1707419672, # "endTime": 1707419822, # "eventType": "Client" # } endState = request.get_json()["endState"] if endState == "Cancelled": matchmaking_queue.removePlayerFromQueue(userid) return jsonify({"status": "success"}) return jsonify({"status": "success"}) except TimeoutError: return jsonify({"status": "error"}) except Exception as e: logger.graylog_logger(level="error", handler="logging_matchmaking_Event", message=e) @app.route("/api/v1/match//user/", methods=["DELETE"]) def remove_player_from_match(match_id_unsanitized, user_id): check_for_game_client("strict") session_cookie = sanitize_input(request.cookies.get("bhvrSession")) userid = session_manager.get_user_id(session_cookie) match_id = sanitize_input(match_id_unsanitized) try: response = matchmaking_queue.remove_player_from_match(match_id, user_id) if response == {"status": "success"}: return "", 204 else: return jsonify({"message": "Something is fucked"}), 500 except Exception as e: logger.graylog_logger(level="error", handler="remove_player_from_match", message=e) return jsonify({"message": "Internal Server Error"}), 500