From e0726f2e9df756651f04ecb3d180f817b0d0e8df Mon Sep 17 00:00:00 2001 From: Mr_Goldberg Date: Sun, 7 Aug 2022 23:10:03 -0400 Subject: [PATCH] Add controller config, multi lang achievements, DLC to generate_emu_config. --- .../parse_controller_vdf.py | 217 +++++++++--------- scripts/generate_emu_config.py | 98 +++++++- .../achievements_gen.py | 7 - 3 files changed, 207 insertions(+), 115 deletions(-) diff --git a/scripts/controller_config_generator/parse_controller_vdf.py b/scripts/controller_config_generator/parse_controller_vdf.py index 569aeb0..4c9495e 100644 --- a/scripts/controller_config_generator/parse_controller_vdf.py +++ b/scripts/controller_config_generator/parse_controller_vdf.py @@ -53,125 +53,128 @@ def add_input_bindings(group, bindings, force_binding=None, keymap=keymap_digita bindings[action_name] = [binding] return bindings -if len(sys.argv) < 2: - print("format: {} xbox_controller_config.vdf".format(sys.argv[0])) - exit(0) -with open(sys.argv[1], 'rb') as f: - t = f.read().decode('utf-8') +def generate_controller_config(controller_vdf, config_dir): + d = vdf.loads(controller_vdf, mapper=vdf.VDFDict, merge_duplicate_keys=False) -d = vdf.loads(t, mapper=vdf.VDFDict, merge_duplicate_keys=False) + controller_mappings = d["controller_mappings"] -controller_mappings = d["controller_mappings"] + groups = controller_mappings.get_all_for("group") + groups_byid = {} + for g in groups: + groups_byid[g["id"]] = g -groups = controller_mappings.get_all_for("group") -groups_byid = {} -for g in groups: - groups_byid[g["id"]] = g + actions = controller_mappings.get_all_for("actions") + action_list = [] + for a in actions: + for k in a: + action_list.append(k) -actions = controller_mappings.get_all_for("actions") -action_list = [] -for a in actions: - for k in a: - action_list.append(k) - -presets = controller_mappings.get_all_for("preset") -all_bindings = {} -for p in presets: - name = p["name"] - if name not in action_list: - continue - group_bindings = p["group_source_bindings"] - bindings = {} - for number in group_bindings: - s = group_bindings[number].split() - if s[1] != "active": + presets = controller_mappings.get_all_for("preset") + all_bindings = {} + for p in presets: + name = p["name"] + if name not in action_list: continue + group_bindings = p["group_source_bindings"] + bindings = {} + for number in group_bindings: + s = group_bindings[number].split() + if s[1] != "active": + continue - #print(s) - if s[0] in ["switch", "button_diamond", "dpad"]: - group = groups_byid[number] - #print(group) - bindings = add_input_bindings(group, bindings) + #print(s) + if s[0] in ["switch", "button_diamond", "dpad"]: + group = groups_byid[number] + #print(group) + bindings = add_input_bindings(group, bindings) - if s[0] in ["left_trigger", "right_trigger"]: - group = groups_byid[number] - if group["mode"] == "trigger": - for g in group: - if g == "gameactions": - #print(group) - action_name = group["gameactions"][name] - if s[0] == "left_trigger": - binding = "LTRIGGER" - else: - binding = "RTRIGGER" - if action_name in bindings: - if binding not in bindings[action_name] and (binding + "=trigger") not in bindings[action_name]: - bindings[action_name].insert(0, binding) - else: - bindings[action_name] = [binding + "=trigger"] - if g == "inputs": - if s[0] == "left_trigger": - binding = "DLTRIGGER" - else: - binding = "DRTRIGGER" - bindings = add_input_bindings(group, bindings, binding) + if s[0] in ["left_trigger", "right_trigger"]: + group = groups_byid[number] + if group["mode"] == "trigger": + for g in group: + if g == "gameactions": + #print(group) + action_name = group["gameactions"][name] + if s[0] == "left_trigger": + binding = "LTRIGGER" + else: + binding = "RTRIGGER" + if action_name in bindings: + if binding not in bindings[action_name] and (binding + "=trigger") not in bindings[action_name]: + bindings[action_name].insert(0, binding) + else: + bindings[action_name] = [binding + "=trigger"] + if g == "inputs": + if s[0] == "left_trigger": + binding = "DLTRIGGER" + else: + binding = "DRTRIGGER" + bindings = add_input_bindings(group, bindings, binding) - else: - print("unhandled trigger mode", group["mode"]) - if s[0] in ["joystick", "right_joystick", "dpad"]: - group = groups_byid[number] - if group["mode"] == "joystick_move": - for g in group: - if g == "gameactions": - #print(group) - action_name = group["gameactions"][name] - if s[0] == "joystick": - binding = "LJOY" - elif s[0] == "right_joystick": - binding = "RJOY" - elif s[0] == "dpad": - binding = "DPAD" - else: - print("could not handle", s[0]) - if action_name in bindings: - if binding not in bindings[action_name] and (binding + "=joystick_move") not in bindings[action_name]: - bindings[action_name].insert(0, binding) - else: - bindings[action_name] = [binding + "=joystick_move"] - if g == "inputs": - if s[0] == "joystick": - binding = "LSTICK" - else: - binding = "RSTICK" - bindings = add_input_bindings(group, bindings, binding) - - elif group["mode"] == "dpad": - if s[0] == "joystick": - binding_map = {"dpad_north":"DLJOYUP", "dpad_south": "DLJOYDOWN", "dpad_west": "DLJOYLEFT", "dpad_east": "DLJOYRIGHT", "click": "LSTICK"} - bindings = add_input_bindings(group, bindings, keymap=binding_map) - elif s[0] == "right_joystick": - binding_map = {"dpad_north":"DRJOYUP", "dpad_south": "DRJOYDOWN", "dpad_west": "DRJOYLEFT", "dpad_east": "DRJOYRIGHT", "click": "RSTICK"} - bindings = add_input_bindings(group, bindings, keymap=binding_map) else: - if s[0] != "dpad": - print("no pad", s[0]) - else: - print("unhandled joy mode", group["mode"]) + print("unhandled trigger mode", group["mode"]) + if s[0] in ["joystick", "right_joystick", "dpad"]: + group = groups_byid[number] + if group["mode"] == "joystick_move": + for g in group: + if g == "gameactions": + #print(group) + action_name = group["gameactions"][name] + if s[0] == "joystick": + binding = "LJOY" + elif s[0] == "right_joystick": + binding = "RJOY" + elif s[0] == "dpad": + binding = "DPAD" + else: + print("could not handle", s[0]) + if action_name in bindings: + if binding not in bindings[action_name] and (binding + "=joystick_move") not in bindings[action_name]: + bindings[action_name].insert(0, binding) + else: + bindings[action_name] = [binding + "=joystick_move"] + if g == "inputs": + if s[0] == "joystick": + binding = "LSTICK" + else: + binding = "RSTICK" + bindings = add_input_bindings(group, bindings, binding) - all_bindings[name] = bindings + elif group["mode"] == "dpad": + if s[0] == "joystick": + binding_map = {"dpad_north":"DLJOYUP", "dpad_south": "DLJOYDOWN", "dpad_west": "DLJOYLEFT", "dpad_east": "DLJOYRIGHT", "click": "LSTICK"} + bindings = add_input_bindings(group, bindings, keymap=binding_map) + elif s[0] == "right_joystick": + binding_map = {"dpad_north":"DRJOYUP", "dpad_south": "DRJOYDOWN", "dpad_west": "DRJOYLEFT", "dpad_east": "DRJOYRIGHT", "click": "RSTICK"} + bindings = add_input_bindings(group, bindings, keymap=binding_map) + else: + if s[0] != "dpad": + print("no pad", s[0]) + else: + print("unhandled joy mode", group["mode"]) + + all_bindings[name] = bindings + + #print(controller_mappings["preset"][(0, "group_source_bindings")]) + + #print(all_bindings) + + if not os.path.exists(config_dir): + os.makedirs(config_dir) + + for k in all_bindings: + with open(os.path.join(config_dir, k + '.txt'), 'w') as f: + for b in all_bindings[k]: + f.write(b + "=" + ','.join(all_bindings[k][b]) + "\n") +if __name__ == '__main__': + if len(sys.argv) < 2: + print("format: {} xbox_controller_config.vdf".format(sys.argv[0])) + exit(0) -#print(controller_mappings["preset"][(0, "group_source_bindings")]) + with open(sys.argv[1], 'rb') as f: + t = f.read().decode('utf-8') -#print(all_bindings) - -config_directory = sys.argv[1] + "_config/steam_settings" + "/controller/" -if not os.path.exists(config_directory): - os.makedirs(config_directory) - -for k in all_bindings: - with open(config_directory + k + '.txt', 'w') as f: - for b in all_bindings[k]: - f.write(b + "=" + ','.join(all_bindings[k][b]) + "\n") + generate_controller_config(t, os.path.join(sys.argv[1] + "_config/steam_settings", "controller")) diff --git a/scripts/generate_emu_config.py b/scripts/generate_emu_config.py index 7b5fd2d..be0df7c 100644 --- a/scripts/generate_emu_config.py +++ b/scripts/generate_emu_config.py @@ -3,9 +3,10 @@ USERNAME = "" PASSWORD = "" #steam ids with public profiles that own a lot of games -TOP_OWNER_IDS = [76561198028121353, 76561198001237877, 76561198355625888, 76561198001678750, 76561198237402290] +TOP_OWNER_IDS = [76561198028121353, 76561198001237877, 76561198355625888, 76561198001678750, 76561198237402290, 76561197979911851, 76561198152618007, 76561197969050296, 76561198213148949, 76561198037867621, 76561198108581917] from stats_schema_achievement_gen import achievements_gen +from controller_config_generator import parse_controller_vdf from steam.client import SteamClient from steam.client.cdn import CDNClient from steam.enums import common @@ -15,6 +16,7 @@ from steam.core.msg import MsgProto import os import sys import json +import urllib.request prompt_for_unavailable = True @@ -35,6 +37,7 @@ if (len(USERNAME) == 0 or len(PASSWORD) == 0): client.cli_login() else: result = client.login(USERNAME, password=PASSWORD) + auth_code, two_factor_code = None, None while result in (EResult.AccountLogonDenied, EResult.InvalidLoginAuthCode, EResult.AccountLoginDeniedNeedTwoFactor, EResult.TwoFactorCodeMismatch, EResult.TryAnotherCM, EResult.ServiceUnavailable, @@ -92,6 +95,65 @@ def generate_achievement_stats(client, game_id, output_directory, backup_directo else: print("no schema", out) +def get_ugc_info(client, published_file_id): + return client.send_um_and_wait('PublishedFile.GetDetails#1', { + 'publishedfileids': [published_file_id], + 'includetags': False, + 'includeadditionalpreviews': False, + 'includechildren': False, + 'includekvtags': False, + 'includevotes': False, + 'short_description': True, + 'includeforsaledata': False, + 'includemetadata': False, + 'language': 0 + }) + +def download_published_file(client, published_file_id, backup_directory): + ugc_info = get_ugc_info(client, published_file_id) + + if (ugc_info is None): + print("failed getting published file", published_file_id) + return None + + file_details = ugc_info.body.publishedfiledetails[0] + if (file_details.result != EResult.OK): + print("failed getting published file", published_file_id, file_details.result) + return None + + if not os.path.exists(backup_directory): + os.makedirs(backup_directory) + + with open(os.path.join(backup_directory, "info.txt"), "w") as f: + f.write(str(ugc_info.body)) + + with urllib.request.urlopen(file_details.file_url) as response: + data = response.read() + with open(os.path.join(backup_directory, file_details.filename.replace("/", "_").replace("\\", "_")), "wb") as f: + f.write(data) + return data + return None + +def get_dlc(raw_infos): + try: + try: + dlc_list = set(map(lambda a: int(a), raw_infos["extended"]["listofdlc"].split(","))) + except: + dlc_list = set() + depot_app_list = set() + if "depots" in raw_infos: + depots = raw_infos["depots"] + for dep in depots: + depot_info = depots[dep] + if "dlcappid" in depot_info: + dlc_list.add(int(depot_info["dlcappid"])) + if "depotfromapp" in depot_info: + depot_app_list.add(int(depot_info["depotfromapp"])) + return (dlc_list, depot_app_list) + except: + print("could not get dlc infos, are there any dlcs ?") + return (set(), set()) + for appid in appids: backup_dir = os.path.join("backup","{}".format(appid)) out_dir = os.path.join("{}".format( "{}_output".format(appid)), "steam_settings") @@ -123,6 +185,40 @@ for appid in appids: with open(os.path.join(out_dir, "build_id.txt"), 'w') as f: f.write(str(buildid)) + dlc_config_list = [] + dlc_list, depot_app_list = get_dlc(game_info) + if (len(dlc_list) > 0): + dlc_raw = client.get_product_info(apps=dlc_list)["apps"] + for dlc in dlc_raw: + try: + dlc_config_list.append((dlc, dlc_raw[dlc]["common"]["name"])) + except: + dlc_config_list.append((dlc, None)) + + with open(os.path.join(out_dir, "DLC.txt"), 'w') as f: + for x in dlc_config_list: + if (x[1] is not None): + f.write("{}={}\n".format(x[0], x[1])) + + config_generated = False + if "config" in game_info: + if "steamcontrollerconfigdetails" in game_info["config"]: + controller_details = game_info["config"]["steamcontrollerconfigdetails"] + for id in controller_details: + details = controller_details[id] + controller_type = "" + enabled_branches = "" + if "controller_type" in details: + controller_type = details["controller_type"] + if "enabled_branches" in details: + enabled_branches = details["enabled_branches"] + print(id, controller_type) + out_vdf = download_published_file(client, int(id), os.path.join(backup_dir, controller_type + str(id))) + if out_vdf is not None and not config_generated: + if (controller_type in ["controller_xbox360", "controller_xboxone"] and (("default" in enabled_branches) or ("public" in enabled_branches))): + parse_controller_vdf.generate_controller_config(out_vdf.decode('utf-8'), os.path.join(out_dir, "controller")) + config_generated = True + game_info_backup = json.dumps(game_info, indent=4) with open(os.path.join(backup_dir, "product_info.json"), "w") as f: f.write(game_info_backup) diff --git a/scripts/stats_schema_achievement_gen/achievements_gen.py b/scripts/stats_schema_achievement_gen/achievements_gen.py index 5d34108..1870a67 100644 --- a/scripts/stats_schema_achievement_gen/achievements_gen.py +++ b/scripts/stats_schema_achievement_gen/achievements_gen.py @@ -4,8 +4,6 @@ import os import json -language = 'english' - STAT_TYPE_INT = '1' STAT_TYPE_FLOAT = '2' STAT_TYPE_AVGRATE = '3' @@ -35,11 +33,6 @@ def generate_stats_achievements(schema, config_directory): x = 'description' if x == 'Hidden': x = 'hidden' - if type(value) is dict: - if language in value: - value = value[language] - else: - value = '' out[x] = value out['name'] = ach['name'] if 'progress' in ach: