def _find_executable(search): # First, look for any executables in the root directory exes = filesystem.execute('find "{}" -iname "*.exe" || true'.format(search)).rstrip().split("\n") if len(exes) == 1: return exes[0] # Look for something that appears to link against steam_api.dll options = [] for exe in exes: stdout = filesystem.execute( 'strings "{}" | grep "steam_api\\.dll" || true'.format(os.path.abspath(exe)) ).rstrip() if stdout != "": options.append(exe) if len(options) == 1: return options[0] # If nothing seems to link against steam_api.dll, compare all executables if len(options) == 0: options = exes # And default to the largest one, which probably isn't correct # Actually, the smallest miiight be the better option final = None size = 0 for exe in options: s = os.path.getsize(exe) if s > size: final = exe size = s return final
def do(appid): app = appdb.Entry(appid) if not app.exists(): raise ExecuteException( "Can't run {} because it isn't configured".format(appid, appid)) app.load() if not app.validate(): raise ExecuteException("Can't run {} because it has an invalid internal configuration" \ .format(appid)) # Copy the proxy DLL shutil.copyfile(config.PROXY_DLL, app.workingdir + "/steam_api.dll") # Set appid.txt, if it doesn't already exist # TODO: Check to make sure the existing appid.txt has the right value? if not os.path.isfile(app.workingdir + "/steam_appid.txt"): with open(app.workingdir + "/steam_appid.txt", 'w') as f: f.write(app.appid()) # Change to the installation directory and execute using wine os.chdir(app.installdir) # TODO: wineprefix print "Executing {}".format(app.executable) print "stderr output is stored in {}/stderr.txt (usually Wine side output)" \ .format(app.directory()) print "stdout output is stored in {}/stdout.txt (usually Application side output)" \ .format(app.directory()) cmd = 'WINEDEBUG="+steambridge,warn+all" WINEDLLPATH="{}" wine "{}" 2>"{}/stderr.txt" >"{}/stdout.txt"' \ .format(config.WINEDLLPATH, app.executable, app.directory(), app.directory()) filesystem.execute(cmd, ignore_results=True)
def do(appid): app = appdb.Entry(appid) if not app.exists(): raise ExecuteException("Can't run {} because it isn't configured".format(appid, appid)) app.load() if not app.validate(): raise ExecuteException("Can't run {} because it has an invalid internal configuration" \ .format(appid)) # Copy the proxy DLL shutil.copyfile(config.PROXY_DLL, app.workingdir + "/steam_api.dll") # Set appid.txt, if it doesn't already exist # TODO: Check to make sure the existing appid.txt has the right value? if not os.path.isfile(app.workingdir + "/steam_appid.txt"): with open(app.workingdir + "/steam_appid.txt", 'w') as f: f.write(app.appid()) # Change to the installation directory and execute using wine os.chdir(app.installdir) # TODO: wineprefix print "Executing {}".format(app.executable) print "stderr output is stored in {}/stderr.txt (usually Wine side output)" \ .format(app.directory()) print "stdout output is stored in {}/stdout.txt (usually Application side output)" \ .format(app.directory()) cmd = 'WINEDEBUG="+steambridge,warn+all" WINEDLLPATH="{}" wine "{}" 2>"{}/stderr.txt" >"{}/stdout.txt"' \ .format(config.WINEDLLPATH, app.executable, app.directory(), app.directory()) filesystem.execute(cmd, ignore_results=True)
def _find_version(dll, search, name): st, api = _process_output(filesystem.execute('strings "{}" | grep "^{}$" || true'.format(dll, search))) if st == False and api == "Multiple": raise SetupException("Cannot setup {} because multiple API versions found for '{}'".format(appid, name)) if st == False: return None return api
def _find_version(dll, search, name): st, api = _process_output(filesystem.execute( \ 'strings "{}" | grep "^{}$" || true'.format(dll, search))) if st == False and api == 'Multiple': raise SetupException("Cannot setup {} because multiple API versions found for '{}'" \ .format(appid, name)) if st == False: return None return api
def _find_executable(search): # First, look for any executables in the root directory exes = filesystem.execute('ls "{}" | grep "\\.exe$" || true'.format(search)) \ .rstrip().split('\n') # Didn't find any? Do a recursive find if len(exes) == 1 and exes[0] == '': exes = filesystem.execute('ls -R "{}" | grep "\\.exe$" || true' \ .format(search)).rstrip().split('\n') if len(exes) == 1 and exes[0] == '': raise SetupException('Cannot setup {} because no executable (*.exe) files were found' \ .format(appid)) if len(exes) == 1: return exes[0] # Look for something that appears to link against steam_api.dll options = [] for exe in exes: stdout = filesystem.execute( \ 'strings "{}" | grep "steam_api\\.dll" || true' \ .format(os.path.abspath(search + '/' + exe))).rstrip() if stdout != '': options.append(exe) if len(options) == 1: return options[0] # If nothing seems to link against steam_api.dll, compare all executables if len(options) == 0: options = exes # And default to the largest one, which probably isn't correct # Actually, the smallest miiight be the better option final = None size = 0 for exe in options: s = os.path.getsize(exe) if s > size: final = exe size = s return final
def do(appid): manifest = appmanifest.AppManifest(appid) if not manifest.exists(): raise SetupException("Cannot setup {} because it lacks a manifest".format(appid)) if not manifest.parse(): raise SetupException("Cannot setup {} because the manifest appears corrupted".format(appid)) if not manifest.is_ready(): raise SetupException("Cannot setup {} because is not finished downloading".format(appid)) if not manifest.is_valid(): raise SetupException("Cannot setup {} because the manifest lacks required data".format(appid)) app = appdb.Entry(manifest.appid()) app.installdir = manifest.installdir() app.name = manifest.name() # TODO: Get the icon from steam. On Windows it's an icon, on Linux it's a # zip containing pngs of the various sizes. Stored in # steam/games/<id>.zip (or .ico). <id> isn't the appid however. # SteamDb.info contains the metadata to know how <id> applies to # appids (Information.clienticon). However, it's not clear how # to get this data. I believe SteamDb.info parses the internal # data sent to Steam clients. # TODO: Once done, save that icon inside the appdb directory # Find the main executable app.executable = os.path.abspath(_find_executable(app.installdir)) print "WARN: Using a temporary algorithm to find the main executable, found {}".format(app.executable) # Find the steam_api.dll and back it up st, dll = _process_output(filesystem.execute('find "{}" -name steam_api.dll'.format(app.installdir))) if st == -1: raise SetupException("Cannot setup {} because it lacks a steam_api.dll in {}".format(appid, app.installdir)) elif st == -2: raise SetupException( "Cannot setup {} because it has mulitple steam_api.dlls in {}".format(appid, app.installdir) ) dll = os.path.abspath(dll) app.workingdir = os.path.dirname(dll) dllorig = dll + ".original" if not os.path.isfile(dllorig): shutil.copyfile(dll, dllorig) else: print "steam_api.dll.original already exists, not backing up..." # Get the API versions from the native steam_api.dll (Yuck, but it works consistently) app.setapiversion("user", _find_version(dllorig, "SteamUser[[:digit:]]\{3\}", "SteamUser")) app.setapiversion("friends", _find_version(dllorig, "SteamFriends[[:digit:]]\{3\}", "SteamFriends")) app.setapiversion("utils", _find_version(dllorig, "SteamUtils[[:digit:]]\{3\}", "SteamUtils")) app.setapiversion("matchmaking", _find_version(dllorig, "SteamMatchMaking[[:digit:]]\{3\}", "SteamMatchmaking")) app.setapiversion( "matchmaking_servers", _find_version(dllorig, "SteamMatchMakingServers[[:digit:]]\{3\}", "MatchmakingServers") ) app.setapiversion( "user_stats", _find_version(dllorig, "STEAMUSERSTATS_INTERFACE_VERSION[[:digit:]]\{3\}", "SteamUserStats") ) app.setapiversion("apps", _find_version(dllorig, "STEAMAPPS_INTERFACE_VERSION[[:digit:]]\{3\}", "SteamApps")) app.setapiversion("networking", _find_version(dllorig, "SteamNetworking[[:digit:]]\{3\}", "SteamNetworking")) app.setapiversion( "remote_storage", _find_version(dllorig, "STEAMREMOTESTORAGE_INTERFACE_VERSION[[:digit:]]\{3\}", "SteamRemoteStorage"), ) app.setapiversion( "screenshots", _find_version(dllorig, "STEAMSCREENSHOTS_INTERFACE_VERSION[[:digit:]]\{3\}", "SteamScreenshots") ) app.setapiversion("http", _find_version(dllorig, "STEAMHTTP_INTERFACE_VERSION[[:digit:]]\{3\}", "SteamHTTP")) app.setapiversion( "unified_messages", _find_version(dllorig, "STEAMUNIFIEDMESSAGES_INTERFACE_VERSION[[:digit:]]\{3\}", "SteamUnifiedMessages"), ) app.setapiversion("ugc", _find_version(dllorig, "STEAMUGC_INTERFACE_VERSION[[:digit:]]\{3\}", "SteamUGC")) if not app.validate(): raise SetupException("Cannot setup {} because of an invalid appdb object (internal error?)".format(appid)) # Save the appdb file app.save() # Create a .desktop file on the desktop desktop = os.path.expanduser("~") + "/Desktop/{}.desktop".format(manifest.appid()) with open(desktop, "w") as f: f.write("[Desktop Entry]\n") # TODO: Icon would go here f.write("Type=Application\n") f.write("Name={} (Wine)\n".format(app.name)) f.write("Exec=steambridge execute {}\n".format(manifest.appid())) os.chmod(desktop, 0755) # Note that it's possible to add this to the shortcuts.vdf file # located... somewhere... in the Steam install. Might be a better way to # go about this than creating a complete .desktop file. print "Done. A newly created .desktop file should be on your desktop."
def do(appid): manifest = appmanifest.AppManifest(appid) if not manifest.exists(): raise SetupException( 'Cannot setup {} because it lacks a manifest'.format(appid)) if not manifest.parse(): raise SetupException( 'Cannot setup {} because the manifest appears corrupted'.format( appid)) if not manifest.is_ready(): raise SetupException( 'Cannot setup {} because is not finished downloading'.format( appid)) if not manifest.is_valid(): raise SetupException( 'Cannot setup {} because the manifest lacks required data'.format( appid)) app = appdb.Entry(manifest.appid()) app.installdir = manifest.installdir() app.name = manifest.name() # TODO: Get the icon from steam. On Windows it's an icon, on Linux it's a # zip containing pngs of the various sizes. Stored in # steam/games/<id>.zip (or .ico). <id> isn't the appid however. # SteamDb.info contains the metadata to know how <id> applies to # appids (Information.clienticon). However, it's not clear how # to get this data. I believe SteamDb.info parses the internal # data sent to Steam clients. # TODO: Once done, save that icon inside the appdb directory # Find the main executable app.executable = os.path.abspath(app.installdir + '/' + _find_executable(app.installdir)) print 'WARN: Using a temporary algorithm to find the main executable, found {}' \ .format(app.executable) # Find the steam_api.dll and back it up st, dll = _process_output(filesystem.execute('find "{}" -name steam_api.dll' \ .format(app.installdir))) if st == -1: raise SetupException('Cannot setup {} because it lacks a steam_api.dll in {}' \ .format(appid, app.installdir)) elif st == -2: raise SetupException('Cannot setup {} because it has mulitple steam_api.dlls in {}' \ .format(appid, app.installdir)) dll = os.path.abspath(dll) app.workingdir = os.path.dirname(dll) dllorig = dll + ".original" if not os.path.isfile(dllorig): shutil.copyfile(dll, dllorig) else: print 'steam_api.dll.original already exists, not backing up...' # Get the API versions from the native steam_api.dll (Yuck, but it works consistently) app.setapiversion('user', _find_version(dllorig, \ "SteamUser[[:digit:]]\{3\}", "SteamUser")) app.setapiversion('friends', _find_version(dllorig, \ "SteamFriends[[:digit:]]\{3\}", "SteamFriends")) app.setapiversion('utils', _find_version(dllorig, \ "SteamUtils[[:digit:]]\{3\}", "SteamUtils")) app.setapiversion('matchmaking', _find_version(dllorig, \ "SteamMatchMaking[[:digit:]]\{3\}", "SteamMatchmaking")) app.setapiversion('matchmaking_servers', _find_version(dllorig, \ "SteamMatchMakingServers[[:digit:]]\{3\}", "MatchmakingServers")) app.setapiversion('user_stats', _find_version(dllorig, \ "STEAMUSERSTATS_INTERFACE_VERSION[[:digit:]]\{3\}", "SteamUserStats")) app.setapiversion('apps', _find_version(dllorig, \ "STEAMAPPS_INTERFACE_VERSION[[:digit:]]\{3\}", "SteamApps")) app.setapiversion('networking', _find_version(dllorig, \ "SteamNetworking[[:digit:]]\{3\}", "SteamNetworking")) app.setapiversion('remote_storage', _find_version(dllorig, \ "STEAMREMOTESTORAGE_INTERFACE_VERSION[[:digit:]]\{3\}", \ "SteamRemoteStorage")) app.setapiversion('screenshots', _find_version(dllorig, \ "STEAMSCREENSHOTS_INTERFACE_VERSION[[:digit:]]\{3\}", "SteamScreenshots")) app.setapiversion('http', _find_version(dllorig, \ "STEAMHTTP_INTERFACE_VERSION[[:digit:]]\{3\}", "SteamHTTP")) app.setapiversion('unified_messages', _find_version(dllorig, \ "STEAMUNIFIEDMESSAGES_INTERFACE_VERSION[[:digit:]]\{3\}", \ "SteamUnifiedMessages")) app.setapiversion('ugc', _find_version(dllorig, \ "STEAMUGC_INTERFACE_VERSION[[:digit:]]\{3\}", "SteamUGC")) if not app.validate(): raise SetupException('Cannot setup {} because of an invalid appdb object (internal error?)' \ .format(appid)) # Save the appdb file app.save() # Create a .desktop file on the desktop desktop = os.path.expanduser("~") + "/Desktop/{}.desktop".format( manifest.appid()) with open(desktop, 'w') as f: f.write("[Desktop Entry]\n") # TODO: Icon would go here f.write("Type=Application\n") f.write("Name={} (Wine)\n".format(app.name)) f.write("Exec=steambridge execute {}\n".format(manifest.appid())) os.chmod(desktop, 0755) # Note that it's possible to add this to the shortcuts.vdf file # located... somewhere... in the Steam install. Might be a better way to # go about this than creating a complete .desktop file. print "Done. A newly created .desktop file should be on your desktop."