def test_config_with_data(fake_data): "Test effects of tweaks with downloaded files" config_file = os.path.expanduser( '~/.local/share/Steam/config/config.vdf') user_config_file = os.path.expanduser( '~/.local/share/Steam/userdata/12345678/config/localconfig.vdf') steam_config.apply_all_tweaks() assert(os.path.exists(config_file)) conf_vdf = vdf.load(open(config_file)) compat = (conf_vdf['InstallConfigStore']['Software']['Valve']['Steam'] ['CompatToolMapping']) assert(compat['221380']['name'] == 'proton_411') assert(compat['409710']['name'] == 'proton_513') assert(compat['409710']['config'] == 'noesync,nofsync') assert(os.path.exists(user_config_file)) conf_vdf = vdf.load(open(user_config_file)) launch_options = (conf_vdf['UserLocalConfigStore']['Software']['Valve'] ['Steam']['Apps']) assert(launch_options['285820']['LaunchOptions'] == 'LD_LIBRARY_PATH= %command%') assert(launch_options['331870']['LaunchOptions'] == '%command% -screen-fullscreen 0') assert(launch_options['409710']['LaunchOptions'] == '-nointro') steam_input = conf_vdf['UserLocalConfigStore']['Apps'] assert(steam_input['285820']['UseSteamControllerConfig'] == '2')
def getGamePath(self): if os.path.isfile("C:/ProgramData/Microsoft/Windows/Start Menu/Programs/Steam/Steam.lnk"): steam = win32com.client.Dispatch("WScript.Shell").CreateShortCut("C:/ProgramData/Microsoft/Windows/Start Menu/Programs/Steam/Steam.lnk").Targetpath.split("\\") del steam[-1] steam = "/".join(steam) s_install_folders = [steam] with open(steam+"/config/config.vdf", "r") as file: try: d = vdf.load(file)["InstallConfigStore"]["Software"]["valve"]["Steam"] except: d = vdf.load(file)["InstallConfigStore"]["Software"]["Valve"]["Steam"] base_number = 1 while True: if "BaseInstallFolder_"+str(base_number) in d: s_install_folders.append(d["BaseInstallFolder_"+str(base_number)]) base_number += 1 else: break for folder in s_install_folders: if os.path.isdir(folder+"/steamapps/common/Risk of Rain 2") and os.path.isfile(folder+"/steamapps/common/Risk of Rain 2/Risk of Rain 2.exe"): print("Found RoR2 install automatically at "+folder+"/steamapps/common/Risk of Rain 2") return folder+"/steamapps/common/Risk of Rain 2" w = QWidget() w.setWindowTitle("Select Risk Of Rain 2 Directory") w.show() return str(QFileDialog.getExistingDirectory(w, "Select Risk Of Rain 2 Directory"))
def BuildGamesList(self): # Setup default paths self.steamRootPath = "C:\\Program Files (x86)\\Steam" self.steamPath = self.steamRootPath + "\\steam.exe" librariesPath = self.steamRootPath + "\\steamapps\\libraryfolders.vdf" self.Games = {} self.gamesList = [] # Convert vdf library data to all library paths librariesData = vdf.load(open(librariesPath)) libraryPaths = [] # First add default path libraryPaths.append(self.steamRootPath + "\\steamapps\\") # Then additional libraries libraryPaths.append(librariesData["LibraryFolders"]["1"] + "\\\\steamapps\\\\") numPaths = self.getMaxLibraryFolder(librariesData["LibraryFolders"]) # Iterate over all the library paths if numPaths > 0: for i in range(1, numPaths): libraryPaths.append(librariesData["LibraryFolders"][str(i)] + "\\\\steamapps\\\\") # Extract games from libraries for libraryPath in libraryPaths: for file in os.listdir(libraryPath): if file.endswith(".acf"): gameData = vdf.load(open(libraryPath + file)) gameData = gameData["AppState"] self.gamesList.append(Game(gameData)) # Convert to game object for game in self.gamesList: self.Games[game.name] = game.appid
def get_particle_file_systems(d, units, npc_heroes): files = [] with open(dota_file("particles/particles_manifest.txt"), "rt", encoding="utf-8") as s: l = s.readline().rstrip("\n") l = "\"" + l + "\"" l += s.read() m = load(StringIO(l)) for k, v in m["particles_manifest"]: assert k == "file", k if v.startswith("!"): v = v[1:] files.append(v) for id, item in chain(units["DOTAUnits"], npc_heroes["DOTAHeroes"]): if "ParticleFile" in item and item["ParticleFile"] not in files: files.append(item["ParticleFile"]) with open(dota_file("scripts/precache.txt"), "rt", encoding="utf-8") as s: p = load(s) for k, v in p["precache"]: if k == "particlefile" and v not in files: files.append(v) for id, item in d["items_game"]["items"]: if "particle_file" in item and item["particle_file"] not in files: files.append(item["particle_file"]) for id, v in d["items_game"]["attribute_controlled_attached_particles"]: if v.get("resource") is not None and v["resource"] not in files: files.append(v["resource"]) for k, v in d["items_game"]["asset_modifiers"]: if "file" in v and v["file"] not in files: files.append(v["file"]) particle_file_systems = OrderedDict() for file in files: if not exists(source_file(file)): print("Warning: referenced particle file '{}' doesn't exist.".format(file), file=stderr) continue particle_file_systems[file] = [] pcf = PCF(include_attributes=False) with open(source_file(file), "rb") as s: pcf.unpack(s) for e in pcf["elements"]: if e["type"].data == "DmeParticleSystemDefinition": system_name = e["name"].data.lower() if system_name not in particle_file_systems[file]: particle_file_systems[file].append(system_name) else: print("Warning: double particle system definition '{}' in '{}'".format(system_name, file), file=stderr) return particle_file_systems
def test_routines_mapper_passing(self, mock_parse): vdf.load(sys.stdin, mapper=dict) mock_parse.assert_called_with(sys.stdin, mapper=dict) vdf.loads("", mapper=dict) mock_parse.assert_called_with("", mapper=dict) class CustomDict(dict): pass vdf.load(sys.stdin, mapper=CustomDict) mock_parse.assert_called_with(sys.stdin, mapper=CustomDict) vdf.loads("", mapper=CustomDict) mock_parse.assert_called_with("", mapper=CustomDict)
def __init__(self, file: AnyTextIO, fs: VMFFileSystem = VMFFileSystem(), allow_patch: bool = False) -> None: self.fs = fs vdf_dict: dict = vdf.load(file, escaped=False) if len(vdf_dict) != 1: raise VMTParseException("material does not contain exactly 1 member") shader_name: str = next(iter(vdf_dict)) self.shader = shader_name.lower() shader_dict: dict = vdf_dict[shader_name] if not isinstance(shader_dict, dict): raise VMTParseException("shader is not a dict") if self.shader == "patch": if not allow_patch: raise VMTParseException("patch materials are not allowed") if "include" not in shader_dict: raise VMTParseException("patch material doesn't include another material") included_name = shader_dict["include"] patch_params = {} if "insert" in shader_dict: inserted = shader_dict["insert"] if not isinstance(inserted, dict): raise VMTParseException("included insert is not a dict") patch_params.update(inserted) if "replace" in shader_dict: replaced = shader_dict["replace"] if not isinstance(replaced, dict): raise VMTParseException("included replace is not a dict") patch_params.update(replaced) vdf_dict = vdf.load(fs.open_file_utf8(included_name), escaped=False) if len(vdf_dict) != 1: raise VMTParseException("included material does not contain exactly 1 member") shader_name = next(iter(vdf_dict)) self.shader = shader_name.lower() shader_dict = vdf_dict[shader_name] if not isinstance(shader_dict, dict): raise VMTParseException("included shader is not a dict") shader_dict.update(patch_params) self.parameters: Dict[str, str] = {} for key in shader_dict: key_l = key.lower() if key.startswith("$") or key.startswith("%"): value = shader_dict[key] if not isinstance(value, str): raise VMTParseException(f"{key} is not a str") self.parameters[key_l] = value elif key_l == "proxies": self.proxies: dict = shader_dict[key] if not isinstance(self.proxies, dict): raise VMTParseException("proxies is not a dict")
def get_install_dir(): # there's one steam library we know exists: the one we found in the registry. steamapps = [get_steamapps_dir()] # steam keeps track of multiple libraries via this file fp = path.join(steamapps[0], 'libraryfolders.vdf') logging.debug('Reading %s', fp) library_dict = vdf.load(open(fp)) # and numbers the libraries from 1 to however many libraries the user has. # here we assume that no sane person has more than 16 steam libraries. for i in range(1, 16): try: f = library_dict['LibraryFolders'][str(i)] steamapps.append(path.join(f, 'steamapps')) logging.debug('Detected library folder %s', f) except KeyError: logging.debug('Detected %d libraries.', i - 1) break # next we loop over every library, and check if there's an appmanifest for assetto corsa. logging.debug('Searching for the appmanifest') for library in steamapps: if 'appmanifest_244210.acf' in listdir(library): logging.debug('AC detected in library: %s', library) return path.join(library, 'common', 'assettocorsa') else: logging.debug('AC not detected in library: %s', library) return None
def main(): steamapps = check_args() print('Scanning manifests') for manifest in glob(join(steamapps, '*.acf')): with open(manifest, 'r') as manifile: vdf = load(manifile, mapper=VDFDict) changed = False # Disable autoupdate if vdf[0, 'AppState'][0, 'AutoUpdateBehavior'] != '0': vdf[0, 'AppState'][0, 'AutoUpdateBehavior'] = '0' print('Disabled', vdf[0, 'AppState'][0, 'name']) changed = True state_flag = int(vdf[0, 'AppState'][0, 'StateFlags']) # If it's in ready state make sure state is 4 # Sometimes it goes to 6 for some reason # See https://github.com/lutris/lutris/blob/master/docs/steam.rst if state_flag != 4 and state_flag & 4: vdf[0, 'AppState'][0, 'StateFlags'] = '4' print('Marking as updated', vdf[0, 'AppState'][0, 'name']) changed = True if changed: with open(manifest, 'w') as manifile: dump(vdf, manifile, pretty=True) print('Done')
def __init__(self, path_to_file): """ :param path_to_file: acf 文件所在位置 """ with open(path_to_file) as file: self.__dic = vdf.load(file)
def set_download_throttle(rate): close_steam() path = f"{all_steam_directories[0]}\\config\\config.vdf" config_vdf = vdf.load(open(path), mapper=vdf.VDFDict) # Load VDF file old_value = config_vdf['InstallConfigStore']['Software']['Valve']['steam'][ 'DownloadThrottleKbps'] if int(old_value) == rate: print( f"Your download rate was not changed because it was already set to" f" {'unlimited' if old_value == '0' else f'{old_value} Kbps'}.") return # Delete old value and add new value del config_vdf['InstallConfigStore']['Software']['Valve']['steam'][ 'DownloadThrottleKbps'] config_vdf['InstallConfigStore']['Software']['Valve']['steam'].update( {'DownloadThrottleKbps': rate}) # Backup and then output to file Tools.backup_file(path) vdf.dump(config_vdf, open(path, "w"), pretty=True) print( f"Your download rate was change from {'unlimited' if old_value == '0' else f'{old_value} Kbps'} to" f" {'unlimited' if rate == 0 else f'{rate} Kbps'}.")
def logged_user(cls) -> SteamAccount: # TODO: Windows with open(STEAMREGISTRY, 'r') as f: registry = vdf.load(f) return cls.account_by_login(registry["Registry"]["HKCU"]["Software"] ["Valve"]["Steam"]["AutoLoginUser"])
def get_installed_apps(self): """ Enumerate IDs of installed apps in given library """ def _getpath(folder_obj): if isinstance(folder_obj, dict): return Path(folder_obj["path"]) if isinstance(folder_obj, str): return Path(folder_obj) raise TypeError(folder_obj) apps = [] logging.info('Searching library folders') library_paths = { _getpath(f).resolve() for f in self.read_library_folders() } for folder_path in {self.steam_root} | library_paths: logging.info('Collecting apps in folder %s', folder_path) for app in (folder_path / 'steamapps').glob('appmanifest_*.acf'): with app.open('r') as amf: app_mainfest = vdf.load(amf) app_state = { k.lower(): v for k, v in app_mainfest['AppState'].items() } apps.append((folder_path, int(app_state['appid']))) return apps
def collectExistedScreenshot(): global existedScreenshot,syncFolder,ScreenshotsKey if os.path.exists(syncFolder+"\\..\\screenshots.vdf")==False: return fp=open(syncFolder+"\\..\\screenshots.vdf","r",encoding="utf8") screenshotCfg=vdf.load(fp) fp.close() if len(screenshotCfg)<1: return for x in screenshotCfg.keys(): if x.capitalize()=="Screenshots": ScreenshotsKey=x break for (app,app_content) in screenshotCfg[ScreenshotsKey].items(): if app.isnumeric()==False: continue for (screenshotIndex,screenshotItem) in app_content.items(): if screenshotItem["hscreenshot"]!="18446744073709551615": #图片已被上传 existedScreenshot.append(screenshotItem["hscreenshot"]) if CREATE_THUMBNAILS==True and not os.path.exists(syncFolder+"\\"+screenshotItem["thumbnail"]): ppath=os.path.abspath(syncFolder+"\\"+screenshotItem["thumbnail"]+"\\..\\") os.makedirs(ppath,exist_ok=True) img = Image.open(syncFolder+"\\"+screenshotItem["filename"]) img1=img.resize((200,int(200.0/img.size[0]*img.size[1])),Image.BILINEAR) img1.save(syncFolder+"\\"+screenshotItem["thumbnail"]) del img,img1
def enumerate_steam_accounts(steam_path): """ Returns a list of SteamAccounts that have signed into steam on this machine """ accounts = list() with os.scandir(os.path.join(steam_path, "userdata")) as childs: for child in childs: if not child.is_dir(): continue steamid = os.fsdecode(child.name) # we need to look inside this user's localconfig.vdf to figure out their # display name # here we just replace any malformed characters since we are only doing this to get the # display name with open(os.path.join(child.path, "config/localconfig.vdf"), "r", encoding="utf-8", errors="replace") as localconfig: cfg = vdf.load(localconfig) username = cfg["UserLocalConfigStore"]["friends"][ "PersonaName"] accounts.append(SteamAccount(steamid, username)) return accounts
def test_local_config_file_data(fake_data): local_config = LocalSteamConfig('12345678') main_tweaks = TweaksFile(context.MAIN_TWEAKS_FILE) assert (main_tweaks.exists()) assert (not local_config.exists()) local_config.apply_tweaks(main_tweaks.get_data()) local_config.save() assert (local_config.exists()) with open(local_config.path) as config_file: config_data = vdf.load(config_file) launch_options = (config_data['UserLocalConfigStore']['Software']['Valve'] ['Steam']['Apps']) steam_input = config_data['UserLocalConfigStore']['Apps'] assert (launch_options['285820']['LaunchOptions'] == 'LD_LIBRARY_PATH= %command%') assert (launch_options['331870']['LaunchOptions'] == '%command% -screen-fullscreen 0') assert (launch_options['409710']['LaunchOptions'] == '-nointro') assert (steam_input['285820']['UseSteamControllerConfig'] == '2')
def get_library_folders(): """ Get all Steam Library Folders """ library_folders = [STEAM_APPS] if not HAS_VDF: return library_folders with open(STEAM_VDF_CONFIG) as file_descriptor: vdata_config = vdf.load(file_descriptor) steam_data = vdata_config \ ["InstallConfigStore"] \ ["Software"] \ ["Valve"] \ ["Steam"] i = 0 while True: i += 1 try: library_folders.append( steam_data["BaseInstallFolder_{}".format(i)] + '/steamapps') except KeyError: return library_folders
def __init__(self, path: Path): self.path = path self.games = [] for filepath in path.joinpath("steamapps").glob("appmanifest_*.acf"): try: with open(filepath, "r", encoding="utf-8") as fp: info = vdf.load(fp) app_state = info["AppState"] except KeyError: print( f'Unable to read application state from "{filepath}"', file=sys.stderr, ) continue except Exception as e: print(f'Unable to parse file "{filepath}": {e}', file=sys.stderr) continue try: app_id = app_state["appid"] install_dir = app_state["installdir"] self.games.append(SteamGame(app_id, install_dir)) except KeyError: print( f"Unable to read application ID or installation folder " f'from "{filepath}"', file=sys.stderr, ) continue
def getusers(self): """ Retrieve users from the current steam directory. If vdf module is present, returns a list of tuples where ([FOLDER_NAME], [USER_NAME]); if an error getting the user name occurs, the username will be None. Executed once by body(), by _sel_dir(), and used to insert value into self.userselectvar. """ toget = os.path.join(self.steamdir_var.get(), CNST.STEAM_CFG_PATH0) try: users = os.listdir(toget) except (OSError, PermissionError, FileNotFoundError): self.errstates[ERR_IDX.STEAMDIR] = True return [] for index, user in enumerate(users): try: cnf_file = os.path.join(toget, user, CNST.STEAM_CFG_PATH1) with open(cnf_file, encoding="utf-8") as h: vdfdata = vdf.load(h) username = eval(f"vdfdata{CNST.STEAM_CFG_USER_NAME}") username = tk_secure_str(username) users[index] = (users[index], username) except (OSError, PermissionError, FileNotFoundError, KeyError, SyntaxError): users[index] = (users[index], None) self.errstates[ERR_IDX.STEAMDIR] = False return users
def get_client_users(): key = winreg.OpenKey(winreg.HKEY_CURRENT_USER, "SOFTWARE\Valve\Steam", 0, winreg.KEY_QUERY_VALUE) path, t = winreg.QueryValueEx(key, "SteamPath") users = {} path += "/config/loginusers.vdf" with open(path, "r", encoding="utf-8") as file: users = vdf.load(file) winreg.CloseKey(key) users = users["users"] rewrite = False for key, val in users.items(): if (users[key]["RememberPassword"] == 0): users.pop(key, None) continue if ("AccountID" not in val): users[key]["AccountID"] = str(Sid.SteamID(key).id) rewrite = True if (rewrite): print("重寫 loginusers.") with open(path, "w", encoding="utf-8") as file: vdf.dump({"users": users}, file) return (users)
def _load_apps(self): root_apps = self._path.joinpath("steamapps") fpath = root_apps.joinpath("libraryfolders.vdf") if not fpath.exists(): raise Exception("Unable to find libraryfolders.vdf!") with open(fpath, "r") as f: lib_vdf = vdf.load(f) logging.debug("libraryfolders.vdf found") libraries = [] folders = lib_vdf["LibraryFolders"] for k, v in folders.items(): if not k.isdigit(): continue libraries.append(Path(v).joinpath("steamapps").resolve()) libraries.append(root_apps.resolve()) logging.debug(f"{len(libraries)} num libraries detected") apps = [] for l in libraries: for path in l.glob("appmanifest_*.acf"): if not path.is_file(): continue app = SteamApp.from_acf(l, path) if not app.path.exists(): logging.warn( f"Skipping steam app {app.appid} as ACF reported as installed but we cannot locate the folder" ) continue apps.append(app) self.apps = apps
def heroes(self): if not self._heroes: self._heroes = vdf.load( self.pak1.get_file("scripts/npc/npc_heroes.txt")) self._heroes = self._heroes['DOTAHeroes'] del self._heroes['Version'] return self._heroes
def abilities(self): if not self._abilities: self._abilities = vdf.load( self.pak1.get_file("scripts/npc/npc_abilities.txt")) self._abilities = self._abilities['DOTAAbilities'] del self._abilities['Version'] return self._abilities
def finalizeLibraryInfo(self): # To "finalize" the library info, we need to fill out any missing entries. for key in self.new_config['libraryfolders']: if self._isint(key): if self.new_config['libraryfolders'][key]['contentid'] == '': # First try to find a libraryfolder.vdf in the specified path library_vdf_path = os.path.join( self.new_config['libraryfolders'][key]['path'], 'libraryfolder.vdf') if os.path.exists(library_vdf_path): info = vdf.load(open(library_vdf_path, 'r')) root = list(info.keys())[0] for subkey in info[root]: if subkey == 'contentid': self.new_config['libraryfolders'][key][ 'contentid'] = info[root]['contentid'] self.used_contentids.append( info[root]['contentid']) elif subkey == 'label': self.new_config['libraryfolders'][key][ 'label'] = info[root]['label'] # Check again as there might not have been a libraryfolder.vdf or it didn't have a valid ContentID if self.new_config['libraryfolders'][key]['contentid'] == '': # Create a random unused number and use that candidate = None while candidate is None or candidate in self.used_contentids: candidate = str(random.randint(1, 10000000000)) self.new_config['libraryfolders'][key][ 'contentid'] = candidate self.used_contentids.append(candidate)
def lookup_xf_user(steam_id64): filepath = os.path.join(paths.GAME_PATH, "addons/sourcemod/configs/databases.cfg") with open(filepath) as file: databases = vdf.load(file) database = databases['Databases']['xenforo'] connection = pymysql.connect( host=database['host'], user=database['user'], port=int(database['port']), password=database['pass'], database=database['database'], cursorclass=pymysql.cursors.DictCursor ) with connection.cursor() as cursor: query = ( "SELECT xf_user.user_id, xf_user.username, xf_user.user_group_id, xf_user.secondary_group_ids " "FROM xf_user INNER JOIN xf_user_external_auth ON xf_user.user_id=xf_user_external_auth.user_id " "WHERE provider='steam' AND provider_key=(%s) LIMIT 1" ) cursor.execute(query, (steam_id64)) result = cursor.fetchone() return result
def fix_launch_option(app_id, wm_name, wm_name_alt=''): """Add execution of fix-wm-class.sh file with wm_name of game as argument.""" if not wm_name_alt: wm_name_alt = wm_name for conf_file in localconfig_paths: loaded = vdf.load(open(conf_file)) steam = loaded['UserLocalConfigStore']['Software']['Valve']['Steam'] if 'Apps' in steam.keys(): apps = steam['Apps'] else: apps = steam['apps'] if app_id in apps.keys(): app = apps[app_id] if 'LaunchOptions' not in app.keys(): app['LaunchOptions'] = '' app['LaunchOptions'] = sub('&\\s/.*fix-wm-class\\.sh.*?;', '', app['LaunchOptions']) script = str(WM_CLASS_FIXER_SCRIPT) if wm_name_alt != wm_name: app['LaunchOptions'] += '& %s "%s" "%s";' % (script, wm_name, wm_name_alt) else: app['LaunchOptions'] += '& %s "%s";' % (script, wm_name) vdf.dump(loaded, open(conf_file, 'w'), pretty=True)
def _getlaunchoptions(self): try: tmp = self.userselectbox.current() if tmp == -1: raise KeyError("Bad or empty (?) steam folder") user_id = self.users[tmp][0] with open(os.path.join(self.steamdir_var.get(), CNST.STEAM_CFG_PATH0, user_id, CNST.STEAM_CFG_PATH1), encoding="utf-8") as h: subelem = vdf.load(h) for i in CNST.LAUNCHOPTIONSKEYS: if i in subelem: subelem = subelem[i] elif i.lower() in subelem: subelem = subelem[i.lower()] else: raise KeyError("Could not find launch options in vdf.") self.errstates[ERR_IDX.LAUNCHOPT] = False return subelem # SyntaxError raised by vdf module except (KeyError, FileNotFoundError, OSError, PermissionError, SyntaxError) as e: self.errstates[ERR_IDX.LAUNCHOPT] = True return ""
def load_data(self) -> None: if self.exists(): data = vdf.load(open(self.path)) else: data = vdf.VDFDict() data['InstallConfigStore'] = {'Software': {'Valve': {'Steam': {}}}} steam = data['InstallConfigStore']['Software']['Valve']['Steam'] if 'CompatToolMapping' not in steam: steam['CompatToolMapping'] = {} else: stale_entries = [] for game in steam['CompatToolMapping']: # remove entries that were disabled in the Steam UI by the user if 'name' in steam['CompatToolMapping'][game] \ and 'config' in steam['CompatToolMapping'][game] \ and steam['CompatToolMapping'][game]['name'] == '' \ and steam['CompatToolMapping'][game]['config'] == '': stale_entries.append(game) # remove all entries added by Chimera (they will be re-added if still configured) elif 'Priority' in steam['CompatToolMapping'][game] \ and (steam['CompatToolMapping'][game]['Priority'] == '209' \ or steam['CompatToolMapping'][game]['Priority'] == '229'): stale_entries.append(game) for entry in stale_entries: del steam['CompatToolMapping'][entry] self.config_data = data
def write_databases_config(self): """ write database config databases.cfg """ sourcemod_cfg = self._config.sourcemod configured_dbs = sourcemod_cfg.get("databases") if not configured_dbs: self._log.info("no databases configured") return True database_config_path = os.path.join( self._root_dir, "csgo/addons/sourcemod/configs/databases.cfg" ) db_config_file = open(database_config_path, "r") self._log.info( "loading databases configuration '%s' ..." % database_config_path ) db_config = vdf.load(db_config_file, mapper=OrderedDict) db_config_file.close() for database_name, database_config in configured_dbs.iteritems(): db_config["Databases"][database_name] = database_config self._log.info( "writing databases config '%s' ..." % database_config_path ) with open(database_config_path, "w") as config_file: config_file.write(vdf.dumps(db_config, pretty=True)) return True
def main(steam_path=None, mountpoint=None): # Setup XDG directories config_dir = BaseDirectory.save_config_path('steamfuse') data_dir = BaseDirectory.save_data_path('steamfuse') cache_dir = BaseDirectory.save_cache_path('steamfuse') # Check/Set path to steam installation if steam_path is None: steam_path = os.path.expanduser('~/.local/share/Steam') if not os.path.exists(steam_path): steam_path = os.path.expanduser('~/.var/app/com.valvesoftware.Steam/data/Steam/') if not os.path.exists(steam_path): print('Could not find Steam install dir. Specify as argument.') return -1 # Find libraries and installed games main_library = os.path.join(steam_path, 'steamapps') libraryfolders_vdf = vdf.load(open(os.path.join(main_library, 'libraryfolders.vdf'), 'r')) more_libraries = [ os.path.join(folder['path'], 'steamapps') for key, folder in libraryfolders_vdf['libraryfolders'].items() if key.isdigit() and int(key) > 0 ] # Setup mergerfs mount mergerfs_path = os.path.join(data_dir, 'mergerfs') if not os.path.exists(mergerfs_path): os.mkdir(mergerfs_path) proc = subprocess.Popen( ['mergerfs', f'{main_library}:{":".join(more_libraries)}', f'{mergerfs_path}'], stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=False, text=True) out, err = proc.communicate() if err: print(err) return -1 # Download applist from Steam applist = os.path.join(cache_dir, 'applist.json') if not os.path.exists(applist): url = 'https://api.steampowered.com/ISteamApps/GetAppList/v2/' res = requests.get(url, allow_redirects=True) open(applist, 'wb').write(res.content) if mountpoint is None: mountpoint = os.path.join(data_dir, 'SteamFuse') if not os.path.exists(mountpoint): os.mkdir(mountpoint) try: FUSE(SteamFuseTree(mergerfs_path, applist), mountpoint=mountpoint, nothreads=True, foreground=True) except RuntimeError: pass proc = subprocess.Popen( ['fusermount', '-u', f'{mergerfs_path}'], stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=False, text=True) out, err = proc.communicate() if err: print(err) return -1
def get_owned_packages(self): local_config_path = STEAM_USERCONFIG.format(self.steam_path, self.get_steam_id().as_32) with open(local_config_path, 'r', encoding='utf-8') as f: local_config = vdf.load(f) return list( int(pkgid) for pkgid in local_config['UserLocalConfigStore'] ['Licenses'].keys())
def get_installed_apps(steam_root): """ Enumerate IDs of installed apps in given library """ apps = [] logging.info('Searching library folders') with open(os.path.join(steam_root, 'steamapps', 'libraryfolders.vdf'), 'r') as lf: for k, v in vdf.load(lf)['LibraryFolders'].items(): if not k.isdigit(): continue logging.info(f'Collecting apps in folder {v}') for app in glob.glob( os.path.join(v, 'steamapps', 'appmanifest_*.acf')): with open(app, 'r') as amf: app_mainfest = vdf.load(amf) apps.append((v, int(app_mainfest['AppState']['appid']))) return apps
def test_routines_mapper_passing(self, mock_parse): vdf.load(sys.stdin, mapper=dict) mock_parse.assert_called_with(sys.stdin, mapper=dict) vdf.loads("", mapper=dict) (fp,), kw = mock_parse.call_args self.assertIsInstance(fp, StringIO) self.assertIs(kw['mapper'], dict) class CustomDict(dict): pass vdf.load(sys.stdin, mapper=CustomDict) mock_parse.assert_called_with(sys.stdin, mapper=CustomDict) vdf.loads("", mapper=CustomDict) (fp,), kw = mock_parse.call_args self.assertIsInstance(fp, StringIO) self.assertIs(kw['mapper'], CustomDict)
def test_routines_mapper_passing(self, mock_parse): vdf.load(sys.stdin, mapper=dict) mock_parse.assert_called_with(sys.stdin, mapper=dict) vdf.loads("", mapper=dict) (fp, ), kw = mock_parse.call_args self.assertIsInstance(fp, StringIO) self.assertIs(kw['mapper'], dict) class CustomDict(dict): pass vdf.load(sys.stdin, mapper=CustomDict) mock_parse.assert_called_with(sys.stdin, mapper=CustomDict) vdf.loads("", mapper=CustomDict) (fp, ), kw = mock_parse.call_args self.assertIsInstance(fp, StringIO) self.assertIs(kw['mapper'], CustomDict)
def fix_sounds(visuals): # get sound list sounds = KVList() hero_sound_dir = dota_file("scripts/game_sounds_heroes") for filename in listdir(hero_sound_dir): with open(join(hero_sound_dir, filename), "rt") as s: part_sounds = load(s) sounds.update(list(part_sounds)) # fix sound visuals sound_visuals, visuals = filtersplit(visuals, isvisualtype("sound")) for asset, modifier in assetmodifier(sound_visuals): asset_files = sound_files(sounds[asset]) modifier_files = sound_files(sounds[modifier]) for modifier_file in modifier_files: copy_wave("sound/" + asset_files[0], "sound/" + modifier_file) return visuals
def nohats(): header("Loading items_game.txt") with open(dota_file("scripts/items/items_game.txt"), "rt") as input: d = load(input) header("Getting defaults") defaults = get_defaults(d) default_ids = set(defaults.values()) header("Fixing simple model files") fix_models(d, defaults, default_ids) header("Getting visuals and sockets") visuals = get_visuals(d, default_ids) visuals = filter_visuals(visuals) sockets = get_sockets(d) header("Fixing alternate style models") visuals = fix_style_models(d, visuals, defaults) header("Fixing sounds") visuals = fix_sounds(visuals) header("Fixing icons") visuals = fix_hero_icons(visuals) visuals = fix_ability_icons(visuals) header("Loading npc_units.txt") units = get_units() header("Fixing summons") visuals = fix_summons(visuals, units) header("Fixing alternate hero models") visuals = fix_hero_forms(visuals) header("Fixing particle snapshots") visuals = fix_particle_snapshots(visuals) header("Loading npc_heroes.txt") npc_heroes = get_npc_heroes() header("Fixing animations") visuals = fix_animations(d, visuals, npc_heroes) header("Fixing particles") visuals = fix_particles(d, defaults, default_ids, visuals, sockets, units, npc_heroes) header("Fixing skins") courier_model = units["DOTAUnits"]["npc_dota_courier"]["Model"] flying_courier_model = units["DOTAUnits"]["npc_dota_flying_courier"]["Model"] fix_skins(courier_model, flying_courier_model) header("Fixing couriers") visuals = fix_couriers(visuals, units, courier_model) visuals = fix_flying_couriers(visuals, units, flying_courier_model) assert not visuals, visuals
def _api_request(self, caller, method, path, **kwargs): if method not in ('GET', 'POST'): raise NotImplemented("HTTP method: %s" % repr(self.method)) if 'params' not in kwargs: kwargs['params'] = {} onetime = {} for param in ('key', 'format', 'raw'): kwargs['params'][param] = onetime[param] = kwargs['params'].get(param, getattr(self, param) ) del kwargs['params']['raw'] if onetime['format'] not in ('json', 'vdf', 'xml'): raise ValueError("Expected format to be json,vdf or xml; got %s" % onetime['format']) # move params to data, if data is not specified for POST # simplifies code calling this method if method == 'POST' and 'data' not in kwargs: kwargs['data'] = kwargs['params'] del kwargs['params'] f = getattr(requests, method.lower()) resp = f(self._url_base + path, stream=True, **kwargs) if caller is not None: caller.last_response = resp if not resp.ok: raise requests.exceptions.HTTPError("%s %s" % (resp.status_code, resp.reason)) if onetime['raw']: return resp.content if onetime['format'] == 'json': return resp.json() elif onetime['format'] == 'xml': import lxml.etree return lxml.etree.parse(resp.raw) elif onetime['format'] == 'vdf': import vdf return vdf.load(resp.raw)
def fix_sounds(visuals): # get sound list sounds = KVList() for root, _, files in chain(walk(dota_file("sound")), walk(dota_file("scripts"))): for f in files: if not (f.startswith("game_sounds") and f.endswith(".txt")): continue if f.endswith("_phonemes.txt"): continue if f.endswith("_manifest.txt"): continue with open(join(root, f), "rt", encoding="utf-8") as s: part_sounds = load(s) sounds.update(list(part_sounds)) # fix sound visuals sound_visuals, visuals = filtersplit(visuals, isvisualtype("sound")) for asset, modifier in assetmodifier(sound_visuals): if not asset in sounds: print("Warning: can't find sound asset {}".format(asset), file=stderr) continue copy_sound_asset(sounds, asset, modifier) return visuals
def abilities(self): if not self._abilities: self._abilities = vdf.load(self.pak1.get_file("scripts/npc/npc_abilities.txt")) self._abilities = self._abilities['DOTAAbilities'] del self._abilities['Version'] return self._abilities
def nohats(): header("Loading items_game.txt") with open(dota_file("scripts/items/items_game.txt"), "rt", encoding="utf-8") as input: d = load(input) header("Getting defaults") defaults = get_defaults(d) default_ids = set(defaults.values()) header("Getting visuals") visuals = get_visuals(d, default_ids) visuals = filter_visuals(visuals) header("Loading npc_units.txt") units = get_units() header("Loading npc_heroes.txt") npc_heroes = get_npc_heroes() header("Fixing scaleform files") fix_scaleform() header("Fixing simple model files") fix_models(d, defaults, default_ids) header("Fixing alternate style models") visuals = fix_style_models(d, visuals, defaults) header("Fixing additional wearables") visuals = fix_additional_wearables(d, visuals, defaults) header("Fixing hex models") visuals = fix_hex_models(d, visuals) header("Fixing pet models") visuals = fix_pet_models(visuals) header("Fixing portrait models") visuals = fix_portrait_models(visuals) header("Fixing sounds") visuals = fix_sounds(visuals) header("Fixing icons") visuals = fix_hero_icons(visuals) visuals = fix_ability_icons(visuals) header("Fixing summons") visuals = fix_summons(visuals, units, d, default_ids) header("Fixing alternate hero models") visuals = fix_hero_forms(visuals) header("Fixing particle snapshots") visuals = fix_particle_snapshots(visuals) header("Fixing animations") visuals = fix_animations(d, visuals, npc_heroes) header("Fixing alternate base models") visuals = fix_base_models(visuals, npc_heroes) header("Fixing skins") courier_model = units["DOTAUnits"]["npc_dota_courier"]["Model"] flying_courier_model = units["DOTAUnits"]["npc_dota_flying_courier"]["Model"] fix_skins(courier_model, flying_courier_model) header("Fixing couriers") visuals = fix_couriers(visuals, units, courier_model) visuals = fix_flying_couriers(visuals, units, flying_courier_model) header("Fixing particle color") fix_particle_color(npc_heroes) header("Fixing effigies") fix_effigies() header("Fixing particles") visuals = fix_particles(d, defaults, default_ids, visuals, units, npc_heroes) assert not visuals, visuals
def test_routine_load(self, mock_parse): vdf.load(sys.stdin) mock_parse.assert_called_with(sys.stdin) vdf.load(self.f) mock_parse.assert_called_with(self.f)
import vdf import json print 'This program converts form and to the .txt format used by Source Engine to / from .json, ready to be used by POEditor. It differenciates between gameui_ and momentum_ by setting the context of the gameui_ tokens to "gameui". It is also capable of converting from the exported .json to an usable .txt by Source. It first aks for a language. You must enter the lowercase, english name of the language, so it will search for that language file. If you want to go from .json to .txt, you must name your .json with the language\'s name it contains.' while True: gam = raw_input("Look for gameui_*.txt?Y/N") files = ['momentum_'] if gam is "Y" or gam is "y": files.append('gameui_') lang = raw_input("Language?\n") option = raw_input("DECODE (D) (.txt to .json) or ENCODE (E) (.json to .txt)?\n") if option is "DECODE" or option is "D": print "Decoding..." for loclfile in files: d = vdf.load(open(loclfile + lang + '.txt'), mapper=vdf.VDFDict) tokens = [] for key, value in d['lang']['Tokens'].items(): if loclfile is 'gameui_': tokens.append({'term': key, 'definition': value, 'context':'gameui'}) else: tokens.append({'term': key, 'definition': value}) json.dump(tokens, open(loclfile+lang + '.json', 'w'), indent=4, sort_keys=True) print 'Tokens dumped to .json' elif option is "ENCODE" or option is "E": print "Encoding..." with open(lang + '.json') as filez: jos = json.load(filez) gui = vdf.VDFDict([('lang', vdf.VDFDict([('Language', lang.title()), ('Tokens', vdf.VDFDict())]))]) mom = vdf.VDFDict([('lang', vdf.VDFDict([('Language', lang.title()), ('Tokens', vdf.VDFDict())]))])
from vdf import load from collections import OrderedDict from sys import argv import csv with open(argv[1] + "/scripts/npc/npc_heroes.txt", "rt", encoding="utf-8") as input: d = load(input) with open(argv[2] + "dota/resource/dota_english.txt", "rt", encoding="utf-16") as input: l = load(input) fields = OrderedDict([ ("id", "HeroID"), ("name", None), ("team", "Team"), ("cm_enabled", "CMEnabled"), ("base_armor", "ArmorPhysical"), ("magical_resistance", "MagicalResistance"), ("ranged", None), ("attack_damage_min", "AttackDamageMin"), ("attack_damage_max", "AttackDamageMax"), ("base_attack_time", "AttackRate"), ("attack_range", "AttackRange"), ("projectile_speed", "ProjectileSpeed"), ("primary_attribute", None), ("base_str", "AttributeBaseStrength"), ("gain_str", "AttributeStrengthGain"), ("base_int", "AttributeBaseIntelligence"), ("gain_int", "AttributeIntelligenceGain"), ("base_agi", "AttributeBaseAgility"), ("gain_agi", "AttributeAgilityGain"),
def heroes(self): if not self._heroes: self._heroes = vdf.load(self.pak1.get_file("scripts/npc/npc_heroes.txt")) self._heroes = self._heroes['DOTAHeroes'] del self._heroes['Version'] return self._heroes
# Copyright (c) Victor van den Elzen # Released under the Expat license, see LICENSE file for details from vdf import load from sys import argv from operator import itemgetter with open(argv[1] + "/scripts/items/items_game.txt", "rt", encoding="utf-8") as input: d = load(input) fts = {} for k, v in d["items_game"]["items"]: tool = v.get("tool") if tool is not None: if tool.get("type") == "league_view_pass": usage = tool["usage"] free_to_spectate = usage.get("free_to_spectate") if free_to_spectate == "1": tier = usage["tier"] location = usage.get("location", "") if location == "unset": location = "" league_id = usage["league_id"] url = v["tournament_url"] name = v["name"] date = v["creation_date"] fts.setdefault(tier, {}).setdefault(location, []).append({"name": name, "url": url, "date": date, "id": league_id}) else: assert free_to_spectate in [None, "0"], v for tier in sorted(fts, key=lambda t: ["premium", "professional", "amateur"].index(t)): print() print("# {}".format(tier))
def get_npc_heroes(): with open(dota_file("scripts/npc/npc_heroes.txt"), "rt") as input: npc_heroes = load(input) return npc_heroes
def get_units(): # get unit model list with open(dota_file("scripts/npc/npc_units.txt"), "rt") as input: units = load(input) return units
import vdf import json print 'This program converts form and to the .txt format used by Source Engine to / from .json, ready to be used by POEditor. It is also capable of converting from the exported' \ ' .json to an usable .txt by Source. It first asks for a language. You must enter the lowercase, english name of the language, so it will search for that language file.' \ ' If you want to go from .json to .txt, you must name your .json with the language\'s name it contains. Encoding a file will also create a "_ref_exp" file.' lang = raw_input("Language?\n") option = raw_input("DECODE (D) (.txt to .json) or ENCODE (E) (.json to .txt)?\n") if option == "DECODE" or option == "D": print "Decoding..." d = vdf.load(open("momentum_" + lang + '.txt'), mapper=vdf.VDFDict) tokens = [] for key, value in d['lang']['Tokens'].items(): tokens.append({'term': key, 'definition': value}) json.dump(tokens, open("momentum_" + lang + '.json', 'w'), indent=4, sort_keys=True) print 'Tokens dumped to .json' elif option == "ENCODE" or option == "E": print "Encoding..." with open(lang + '.json') as filez: jos = json.load(filez) mom = vdf.VDFDict([('lang', vdf.VDFDict([('Language', lang.title()), ('Tokens', vdf.VDFDict())]))]) for key in jos: mom['lang']['Tokens'][key['term']] = key['definition'] vdf.dump(mom, open('momentum_' + lang + '.txt', 'w', encoding='utf_16_le'), pretty=True) print 'momentum_%s exported.' % lang if lang == 'english': vdf.dump(mom, open('momentum_english_ref_exp.txt', 'w', encoding='utf-8'), pretty=True) print 'momentum_english_ref_exp exported.'
import vdf item_schema = vdf.load(open('item_schema.txt')) num_items = 0 for item_id in item_schema['items_game']['items']: if "default" not in item_id: if "default_item" not in item_schema['items_game']['items'][item_id]['prefab']: if "league" not in item_schema['items_game']['items'][item_id]['prefab']: if "retired_treasure_chest" not in item_schema['items_game']['items'][item_id]['prefab']: num_items+=1 with open("items.txt", "a") as myfile: myfile.write(item_schema['items_game']['items'][item_id]['name'] + '\n') print "Parsed", num_items, "items"
def load_achievements(): return vdf.load(open(os.path.join(ROOT, "lang", "329130_loc_all.vdf")))["lang"]["english"]["Tokens"]
# clear output directory if os.path.exists("./out"): shutil.rmtree("./out") LOG.info("Reading VPK from %s" % repr(vpk_path)) # load game asset index pak1 = vpk.open(vpk_path) LOG.info("Reading items.txt") # load items.txt schema and save a local copy to track in repo with pak1.get_file("scripts/npc/items.txt") as vpkfile: vpkfile.save(os.path.join(src_root, 'items.txt')) items = vdf.load(vpkfile)['DOTAAbilities'] pt_names = ['power_treads_str.png', 'power_treads_agi.png', 'power_treads_int.png'] def get_file(filename): prerendered_path = os.path.join(src_preimages_root, filename) if os.path.exists(prerendered_path): return open(prerendered_path, 'rb') else: return pak1.get_file('/'.join([vpk_img_root, "items", filename])) LOG.info("Generating images for %d items" % len(items)) # find all items with mana or health requirements for item_name in items:
def items(self): if not self._items: self._items = vdf.load(self.pak1.get_file("scripts/npc/items.txt")) self._items = self._items['DOTAAbilities'] del self._items['Version'] return self._items