def play(self): rompath = self.runner_config.get("rompath") or "" if not system.path_exists(rompath): logger.warning("BIOS path provided in %s doesn't exist", rompath) rompath = os.path.join(settings.RUNNER_DIR, "mess/bios") if not system.path_exists(rompath): logger.error("Couldn't find %s", rompath) return {"error": "NO_BIOS"} machine = self.game_config.get("machine") if not machine: return {"error": "INCOMPLETE_CONFIG"} rom = self.game_config.get("main_file") or "" if rom and not system.path_exists(rom): return {"error": "FILE_NOT_FOUND", "file": rom} device = self.game_config.get("device") command = [self.get_executable()] if self.runner_config.get("uimodekey"): command += ["-uimodekey", self.runner["uimodekey"]] command += ["-rompath", rompath, machine] if device: command.append("-" + device) if rom: command.append(rom) return {"command": command}
def get_wine_versions(): """Return the list of Wine versions installed""" versions = [] for build in sorted(WINE_PATHS.keys()): version = get_system_wine_version(WINE_PATHS[build]) if version: versions.append(build) if system.path_exists(WINE_DIR): dirs = version_sort(os.listdir(WINE_DIR), reverse=True) for dirname in dirs: if is_version_installed(dirname): versions.append(dirname) for proton_path in get_proton_paths(): proton_versions = [p for p in os.listdir(proton_path) if "Proton" in p] for version in proton_versions: path = os.path.join(proton_path, version, "dist/bin/wine") if os.path.isfile(path): versions.append(version) if POL_PATH: for arch in ['x86', 'amd64']: builds_path = os.path.join(POL_PATH, "wine/linux-%s" % arch) if not system.path_exists(builds_path): continue for version in os.listdir(builds_path): if system.path_exists(os.path.join(builds_path, version, "bin/wine")): logger.debug("Adding PoL version %s", version) versions.append("PlayOnLinux %s-%s" % (version, arch)) else: logger.warning(os.path.join(builds_path, "bin/wine")) return versions
def play(self): arguments = [self.get_executable()] if self.runner_config.get("fullscreen"): arguments.append("-fullscreen") else: arguments.append("-windowed") resolution = self.runner_config.get("resolution") if resolution: if resolution == "desktop": width, height = display.DISPLAY_MANAGER.get_current_resolution() else: width, height = resolution.split("x") arguments += ["-fs-width", "%s" % width, "-fs-height", "%s" % height] if self.runner_config.get("machine"): arguments.append("-%s" % self.runner_config["machine"]) bios_path = self.runner_config.get("bios_path") if not system.path_exists(bios_path): return {"error": "NO_BIOS"} good_bios = self.find_good_bioses(bios_path) for bios, filename in good_bios.items(): arguments.append("-%s" % bios) arguments.append(os.path.join(bios_path, filename)) rom = self.game_config.get("main_file") or "" if not system.path_exists(rom): return {"error": "FILE_NOT_FOUND", "file": rom} arguments.append(rom) return {"command": arguments}
def is_installed(self, version=None, fallback=True, min_version=None): """Checks if wine is installed and if the steam executable is on the drive""" if not super().is_installed(version=version, fallback=fallback, min_version=min_version): return False if not system.path_exists(self.get_default_prefix(arch=self.default_arch)): return False return system.path_exists(self.get_steam_path())
def play(self): arguments = [self.get_executable()] if self.runner_config.get("fullscreen"): arguments.append("-fullscreen") else: arguments.append("-windowed") resolution = self.runner_config.get("resolution") if resolution: if resolution == 'desktop': resolution = display.get_current_resolution() width, height = resolution.split('x') arguments += ["-fs-width", "%s" % width, "-fs-height", "%s" % height] if self.runner_config.get("machine"): arguments.append("-%s" % self.runner_config["machine"]) bios_path = self.runner_config.get("bios_path") if not system.path_exists(bios_path): return {'error': 'NO_BIOS'} good_bios = self.find_good_bioses(bios_path) for bios in good_bios.keys(): arguments.append("-%s" % bios) arguments.append(os.path.join(bios_path, good_bios[bios])) rom = self.game_config.get('main_file') or '' if not system.path_exists(rom): return {'error': 'FILE_NOT_FOUND', 'file': rom} arguments.append(rom) return {"command": arguments}
def set_drive_path(prefix, letter, path): """Changes the path to a Wine drive""" dosdevices_path = os.path.join(prefix, "dosdevices") if not system.path_exists(dosdevices_path): raise OSError("Invalid prefix path %s" % prefix) drive_path = os.path.join(dosdevices_path, letter + ":") if system.path_exists(drive_path): os.remove(drive_path) logger.debug("Linking %s to %s", drive_path, path) os.symlink(path, drive_path)
def is_installed(self, version=None, fallback=True, min_version=None): """Checks if pico8 runner is installed and if the pico8 executable available. """ if self.is_native and system.path_exists( self.runner_config.get("runner_executable") ): return True return system.path_exists( os.path.join(settings.RUNNER_DIR, "pico8/web/player.html") )
def extract_7zip(path, dest, archive_type=None): _7zip_path = os.path.join(settings.RUNTIME_DIR, 'p7zip/7z') if not system.path_exists(_7zip_path): _7zip_path = system.find_executable('7z') if not system.path_exists(_7zip_path): raise OSError("7zip is not found in the lutris runtime or on the system") command = [_7zip_path, 'x', path, '-o{}'.format(dest), '-aoa'] if archive_type: command.append('-t{}'.format(archive_type)) subprocess.call(command)
def get_default_folder(self): """Return the default folder for the file picker""" default_path = self.path or self.default_path or "" if not default_path or not system.path_exists(default_path): current_entry = self.get_text() if system.path_exists(current_entry): default_path = current_entry if not os.path.isdir(default_path): default_path = os.path.dirname(default_path) return os.path.expanduser(default_path or "~")
def remove_launcher(game_slug, game_id, desktop=False, menu=False): """Remove existing .desktop file.""" if desktop: launcher_path = get_launcher_path(game_slug, game_id) if system.path_exists(launcher_path): os.remove(launcher_path) if menu: menu_path = get_menu_launcher_path(game_slug, game_id) if system.path_exists(menu_path): os.remove(menu_path)
def get_banner(cls, gog_game): """Return the path to the game banner. Downloads the banner if not present. """ image_url = "https:%s_prof_game_100x60.jpg" % gog_game['image'] image_hash = gog_game['image'].split("/")[-1] cache_dir = os.path.join(settings.CACHE_DIR, "gog/banners/small/") if not system.path_exists(cache_dir): os.makedirs(cache_dir) cache_path = os.path.join(cache_dir, "%s.jpg" % image_hash) if not system.path_exists(cache_path): download_media(image_url, cache_path) return cache_path
def set_option(self, option, value): config_file = os.path.expanduser("~/.snes9x/snes9x.xml") if not system.path_exists(config_file): subprocess.Popen([self.get_executable(), "-help"]) if not system.path_exists(config_file): logger.error("Snes9x config file creation failed") return tree = etree.parse(config_file) node = tree.find("./preferences/option[@name='%s']" % option) if value.__class__.__name__ == "bool": value = "1" if value else "0" node.attrib["value"] = value tree.write(config_file)
def is_installed_systemwide(): """Return whether Wine is installed outside of Lutris""" for build in WINE_PATHS.values(): if system.find_executable(build): if ( build == "wine" and system.path_exists("/usr/lib/wine/wine64") and not system.path_exists("/usr/lib/wine/wine") ): logger.warning("wine32 is missing from system") return False return True return False
def get_pixbuf(image, size, fallback=None): """Return a pixbuf from file `image` at `size` or fallback to `fallback`""" width, heigth = size if system.path_exists(image): try: return GdkPixbuf.Pixbuf.new_from_file_at_size(image, width, heigth) except GLib.GError: logger.error("Unable to load icon from image %s", image) if system.path_exists(fallback): return GdkPixbuf.Pixbuf.new_from_file_at_size(fallback, width, heigth) if image and not image.startswith("/"): return get_stock_icon(image, width) return None
def download(self, downloader): if self.uses_pga_cache() and system.path_exists(self.dest_file): logger.info("File %s already cached", self) return False if not system.path_exists(self.cache_path): os.makedirs(self.cache_path) downloader( self.url, self.dest_file, callback=self.check_hash, referer=self.referer ) return True
def play(self): game_args = self.game_config.get("args") or "" binary_path = self.game_config.get("steamless_binary") if self.game_config.get("run_without_steam") and binary_path: # Start without steam if not system.path_exists(binary_path): return {"error": "FILE_NOT_FOUND", "file": binary_path} self.original_steampid = None command = [binary_path] else: # Start through steam # Get current steam pid to act as the root pid instead of lutris self.original_steampid = get_steam_pid() command = self.launch_args if self.runner_config.get("start_in_big_picture") or not game_args: command.append("steam://rungameid/%s" % self.appid) else: command.append("-applaunch") command.append(self.appid) if game_args: for arg in shlex.split(game_args): command.append(arg) return { "command": command, "env": self.get_env(), }
def play(self): command = [self.get_executable()] command += self.get_runner_parameters() # Core core = self.game_config.get("core") if not core: return { "error": "CUSTOM", "text": "No core has been selected for this game", } command.append("--libretro={}".format(self.get_core_path(core))) # Ensure the core is available if not self.is_installed(core): self.install(core) # Main file file = self.game_config.get("main_file") if not file: return {"error": "CUSTOM", "text": "No game file specified"} if not system.path_exists(file): return {"error": "FILE_NOT_FOUND", "file": file} command.append(file) return {"command": command}
def iter_game_files(self): """Iterate through game files, downloading them or querying them from the user""" if self.files: if ( self.target_path and not system.path_exists(self.target_path) and self.creates_game_folder ): try: os.makedirs(self.target_path) except PermissionError: raise ScriptingError( "Lutris does not have the necessary permissions to install to path:", self.target_path, ) self.game_dir_created = True if len(self.game_files) < len(self.files): logger.info( "Downloading file %d of %d", len(self.game_files) + 1, len(self.files) ) file_index = len(self.game_files) try: current_file = self.files[file_index] except KeyError: raise ScriptingError( "Error getting file %d in %s" % file_index, self.files ) self._download_file(current_file) else: self.current_command = 0 self._prepare_commands()
def enable_dxvk_dll(self, system_dir, dxvk_arch, dll): """Copies DXVK dlls to the appropriate destination""" # Copying DXVK's version dxvk_dll_path = os.path.join(self.dxvk_path, dxvk_arch, "%s.dll" % dll) if system.path_exists(dxvk_dll_path): wine_dll_path = os.path.join(system_dir, "%s.dll" % dll) logger.info("Replacing %s/%s with "+self.base_name.upper()+" version", system_dir, dll) if not self.is_dxvk_dll(wine_dll_path): # Backing up original version (may not be needed) if system.path_exists(wine_dll_path): shutil.move(wine_dll_path, wine_dll_path + ".orig") if system.path_exists(wine_dll_path): os.remove(wine_dll_path) os.symlink(dxvk_dll_path, wine_dll_path) else: self.disable_dxvk_dll(system_dir, dxvk_arch, dll)
def enable(self): """Enable DXVK for the current prefix""" if not system.path_exists(self.dxvk_path): logger.error(self.base_name.upper()+" %s is not available locally", self.version) return for system_dir, dxvk_arch, dll in self._iter_dxvk_dlls(): self.enable_dxvk_dll(system_dir, dxvk_arch, dll)
def remove(self, game=None): """Delete the configuration file from disk.""" if path_exists(self.game_config_path): os.remove(self.game_config_path) logger.debug("Removed config %s", self.game_config_path) else: logger.debug("No config file at %s", self.game_config_path)
def get_executable(self, version=None, fallback=True): """Return the path to the Wine executable. A specific version can be specified if needed. """ if version is None: version = self.get_version() if not version: return wine_path = self.get_path_for_version(version) if system.path_exists(wine_path): return wine_path if fallback: # Fallback to default version default_version = get_default_version() wine_path = self.get_path_for_version(default_version) if wine_path: # Update the version in the config if version == self.runner_config.get("version"): self.runner_config["version"] = default_version # TODO: runner_config is a dict so we have to instanciate a # LutrisConfig object to save it. # XXX: The version key could be either in the game specific # config or the runner specific config. We need to know # which one to get the correct LutrisConfig object. return wine_path
def dosexec(config_file=None, executable=None, args=None, exit=True, working_dir=None): """Execute Dosbox with given config_file.""" if config_file: run_with = "config {}".format(config_file) if not working_dir: working_dir = os.path.dirname(config_file) elif executable: run_with = "executable {}".format(executable) if not working_dir: working_dir = os.path.dirname(executable) else: raise ValueError("Neither a config file or an executable were provided") logger.debug("Running dosbox with %s", run_with) working_dir = system.create_folder(working_dir) dosbox = import_runner("dosbox") dosbox_runner = dosbox() command = [dosbox_runner.get_executable()] if config_file: command += ["-conf", config_file] if executable: if not system.path_exists(executable): raise OSError("Can't find file {}".format(executable)) command += [executable] if args: command += args.split() if exit: command.append("-exit") system.execute(command, cwd=working_dir)
def get_or_create_default_prefix(self, arch=None): """Return the default prefix' path. Create it if it doesn't exist""" if not arch or arch == "auto": arch = self.default_arch prefix = self.get_default_prefix(arch=arch) if not system.path_exists(prefix): self.create_default_prefix(prefix, arch=arch) return prefix
def play(self): for option_name in self.config.runner_config: self.set_option(option_name, self.runner_config.get(option_name)) rom = self.game_config.get("main_file") or "" if not system.path_exists(rom): return {"error": "FILE_NOT_FOUND", "file": rom} return {"command": [self.get_executable(), rom]}
def is_installed(self, core=None): if self.game_config.get("core") and core is None: core = self.game_config["core"] if not core or self.runner_config.get("runner_executable"): return self.is_retroarch_installed() is_core_installed = system.path_exists(self.get_core_path(core)) return self.is_retroarch_installed() and is_core_installed
def detect_arch(prefix_path=None, wine_path=None): """Given a Wine prefix path, return its architecture""" arch = detect_prefix_arch(prefix_path) if arch: return arch if wine_path and system.path_exists(wine_path + "64"): return "win64" return "win32"
def play(self): """Run the game.""" arguments = [self.get_executable()] rom = self.game_config.get("main_file") or "" if not system.path_exists(rom): return {"error": "FILE_NOT_FOUND", "file": rom} arguments.append(rom) return {"command": arguments}
def play(self): params = [self.get_executable()] if self.runner_config.get("fullscreen"): params.append("--fullscreen") else: params.append("--window") params.append("--zoom") if self.runner_config.get("zoom"): params.append("2") else: params.append("1") params.append("--borders") if self.runner_config.get("borders"): params.append("true") else: params.append("false") params.append("--statusbar") if self.runner_config.get("status"): params.append("true") else: params.append("false") if self.runner_config.get("joy0"): params.append("--joy0") params.append(self.runner_config["joy0"]) if self.runner_config.get("joy1"): params.append("--joy1") params.append(self.runner_config["joy1"]) if system.path_exists(self.runner_config.get("bios_file", "")): params.append("--tos") params.append(self.runner_config["bios_file"]) else: return {"error": "NO_BIOS"} diska = self.game_config.get("disk-a") if not system.path_exists(diska): return {"error": "FILE_NOT_FOUND", "file": diska} params.append("--disk-a") params.append(diska) return {"command": params}
def play(self): params = [self.get_executable()] if self.runner_config.get("fullscreen"): params.append("--fullscreen") else: params.append("--window") params.append("--zoom") if self.runner_config.get("zoom"): params.append("2") else: params.append("1") params.append('--borders') if self.runner_config.get("borders"): params.append('true') else: params.append('false') params.append('--statusbar') if self.runner_config.get("status"): params.append('true') else: params.append('false') if self.runner_config.get("joy0"): params.append("--joy0") params.append(self.runner_config['joy0']) if self.runner_config.get("joy1"): params.append("--joy1") params.append(self.runner_config['joy1']) if system.path_exists(self.runner_config.get('bios_file', '')): params.append('--tos') params.append(self.runner_config["bios_file"]) else: return {'error': 'NO_BIOS'} diska = self.game_config.get('disk-a') if not system.path_exists(diska): return {'error': 'FILE_NOT_FOUND', 'file': diska} params.append("--disk-a") params.append(diska) return {"command": params}
def play(self): url = self.game_config.get("main_file") if not url: return { "error": "CUSTOM", "text": ("The web address is empty, \n" "verify the game's configuration."), } # check if it's an url or a file is_url = urlparse(url).scheme != "" if not is_url: if not system.path_exists(url): return { "error": "CUSTOM", "text": ("The file " + url + " does not exist, \n" "verify the game's configuration."), } url = "file://" + url game_data = pga.get_game_by_field(self.config.game_config_id, "configpath") # keep the old behavior from browser runner, but with support for extra arguments! if self.runner_config.get("external_browser"): # is it possible to disable lutris runtime here? browser = self.runner_config.get( "custom_browser_executable") or "xdg-open" args = self.runner_config.get("custom_browser_args") args = args or '"$GAME"' arguments = string.Template(args).safe_substitute({ "GAME": url, "URL": url }) command = [browser] for arg in shlex.split(arguments): command.append(arg) return {"command": command} icon = resources.get_icon_path(game_data.get("slug")) if not system.path_exists(icon): icon = DEFAULT_ICON command = [ self.get_executable(), os.path.join(settings.RUNNER_DIR, "web/electron/resources/app.asar"), url, "--name", game_data.get("name"), "--icon", icon, ] for key in [ "fullscreen", "frameless", "devtools", "disable_resizing", "disable_menu_bar", "maximize_window", "disable_scrolling", "hide_cursor", "open_links", "remove_margin", ]: if self.runner_config.get(key): converted_opt_name = key.replace("_", "-") command.append("--{option}".format(option=converted_opt_name)) if self.runner_config.get("window_size"): command.append("--window-size") command.append(self.runner_config.get("window_size")) return {"command": command, "env": self.get_env(False)}
def is_installed(self): """Return whether the runner is installed""" return system.path_exists(self.get_executable())
def prelaunch(self): config_file = self.get_config_file() # Create retroarch.cfg if it doesn't exist. if not system.path_exists(config_file): f = open(config_file, "w") f.write("# Lutris RetroArch Configuration") f.close() # Build the default config settings. retro_config = RetroConfig(config_file) retro_config["libretro_directory"] = get_default_config_path( "cores") retro_config["libretro_info_path"] = get_default_config_path( "info") retro_config["content_database_path"] = get_default_config_path( "database/rdb") retro_config["cheat_database_path"] = get_default_config_path( "database/cht") retro_config["cursor_directory"] = get_default_config_path( "database/cursors") retro_config["screenshot_directory"] = get_default_config_path( "screenshots") retro_config[ "input_remapping_directory"] = get_default_config_path( "remaps") retro_config["video_shader_dir"] = get_default_config_path( "shaders") retro_config["core_assets_directory"] = get_default_config_path( "downloads") retro_config["thumbnails_directory"] = get_default_config_path( "thumbnails") retro_config["playlist_directory"] = get_default_config_path( "playlists") retro_config["joypad_autoconfig_dir"] = get_default_config_path( "autoconfig") retro_config["rgui_config_directory"] = get_default_config_path( "config") retro_config["overlay_directory"] = get_default_config_path( "overlay") retro_config["assets_directory"] = get_default_config_path( "assets") retro_config.save() else: retro_config = RetroConfig(config_file) core = self.game_config.get("core") info_file = os.path.join(get_default_config_path("info"), "{}_libretro.info".format(core)) if system.path_exists(info_file): core_config = RetroConfig(info_file) try: firmware_count = int(core_config["firmware_count"]) except (ValueError, TypeError): firmware_count = 0 system_path = self.get_system_directory(retro_config) notes = core_config["notes"] or "" checksums = {} if notes.startswith("Suggested md5sums:"): parts = notes.split("|") for part in parts[1:]: checksum, filename = part.split(" = ") checksums[filename] = checksum for index in range(firmware_count): firmware_filename = core_config["firmware%d_path" % index] firmware_path = os.path.join(system_path, firmware_filename) if system.path_exists(firmware_path): if firmware_filename in checksums: checksum = system.get_md5_hash(firmware_path) if checksum == checksums[firmware_filename]: checksum_status = "Checksum good" else: checksum_status = "Checksum failed" else: checksum_status = "No checksum info" logger.info("Firmware '%s' found (%s)", firmware_filename, checksum_status) else: logger.warning("Firmware '%s' not found!", firmware_filename) # Before closing issue #431 # TODO check for firmware*_opt and display an error message if # firmware is missing # TODO Add dialog for copying the firmware in the correct # location return True
def xboxdrv_stop(): os.system("pkexec xboxdrvctl --shutdown") if system.path_exists("/usr/share/lutris/bin/resetxpad"): os.system("pkexec /usr/share/lutris/bin/resetxpad")
def is_available(self): """Return whether component is cached locally""" return system.path_exists(self.path)
def disconnect(): """Removes the API token, disconnecting the user""" if system.path_exists(API_KEY_FILE_PATH): os.remove(API_KEY_FILE_PATH)
def exists(self, slug): """Whether the icon for the specified slug exists locally""" return system.path_exists(self.get_absolute_path(slug))
def get_updated_at(self): """Return the modification date of the runtime folder""" if not system.path_exists(self.local_runtime_path): return None return time.gmtime(os.path.getmtime(self.local_runtime_path))
def __init__( self, game_slug=None, installer_file=None, revision=None, parent=None, application=None, ): super().__init__(application=application) self.install_in_progress = False self.interpreter = None self.parent = parent self.game_slug = game_slug self.revision = revision self.desktop_shortcut_box = None self.menu_shortcut_box = None self.log_buffer = None self.log_textview = None self.title_label = InstallerLabel() self.title_label.set_selectable(False) self.vbox.add(self.title_label) self.status_label = InstallerLabel() self.status_label.set_max_width_chars(80) self.status_label.set_property("wrap", True) self.status_label.set_selectable(True) self.vbox.add(self.status_label) self.widget_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) self.vbox.pack_start(self.widget_box, True, True, 0) self.vbox.add(Gtk.HSeparator()) self.action_buttons = Gtk.Box(spacing=6) action_buttons_alignment = Gtk.Alignment.new(1, 0, 0, 0) action_buttons_alignment.add(self.action_buttons) self.vbox.pack_start(action_buttons_alignment, False, True, 0) self.manual_button = self.add_button(_("Configure m_anually"), self.on_manual_clicked) self.cancel_button = self.add_button( _("C_ancel"), self.cancel_installation, tooltip=_("Abort and revert the installation") ) self.eject_button = self.add_button(_("_Eject"), self.on_eject_clicked) self.source_button = self.add_button(_("_View source"), self.on_source_clicked) self.install_button = self.add_button(_("_Install"), self.on_install_clicked) self.continue_button = self.add_button(_("_Continue")) self.play_button = self.add_button(_("_Launch"), self.launch_game) self.close_button = self.add_button(_("_Close"), self.on_destroy) self.continue_handler = None # check if installer is local or online if system.path_exists(installer_file): self.on_scripts_obtained(interpreter.read_script(installer_file)) else: self.title_label.set_markup(_("Waiting for response from %s") % (settings.SITE_URL)) self.add_spinner() self.widget_box.show() self.title_label.show() jobs.AsyncCall( interpreter.fetch_script, self.on_scripts_obtained, self.game_slug, self.revision, ) self.present()
def is_mingw_build(wine_path): """Returns whether a wine build is built with MingW""" base_path = os.path.dirname(os.path.dirname(wine_path)) # A MingW build has an .exe file while a GCC one will have a .so return system.path_exists(os.path.join(base_path, "lib/wine/iexplore.exe"))
def is_available(self): """Return whether DXVK is cached locally""" return system.path_exists(self.dxvk_path)
def prelaunch(self): config_file = self.get_config_file() # Create retroarch.cfg if it doesn't exist. if not system.path_exists(config_file): f = open(config_file, 'w') f.write('# Lutris RetroArch Configuration') f.close() # Build the default config settings. retro_config = RetroConfig(config_file) retro_config['libretro_directory'] = get_default_config_path( 'cores') retro_config['libretro_info_path'] = get_default_config_path( 'info') retro_config['content_database_path'] = get_default_config_path( 'database/rdb') retro_config['cheat_database_path'] = get_default_config_path( 'database/cht') retro_config['cursor_directory'] = get_default_config_path( 'database/cursors') retro_config['screenshot_directory'] = get_default_config_path( 'screenshots') retro_config[ 'input_remapping_directory'] = get_default_config_path( 'remaps') retro_config['video_shader_dir'] = get_default_config_path( 'shaders') retro_config['core_assets_directory'] = get_default_config_path( 'downloads') retro_config['thumbnails_directory'] = get_default_config_path( 'thumbnails') retro_config['playlist_directory'] = get_default_config_path( 'playlists') retro_config['joypad_autoconfig_dir'] = get_default_config_path( 'autoconfig') retro_config['rgui_config_directory'] = get_default_config_path( 'config') retro_config['overlay_directory'] = get_default_config_path( 'overlay') retro_config['assets_directory'] = get_default_config_path( 'assets') retro_config.save() else: retro_config = RetroConfig(config_file) core = self.game_config.get('core') info_file = os.path.join(get_default_config_path('info'), '{}_libretro.info'.format(core)) if system.path_exists(info_file): core_config = RetroConfig(info_file) try: firmware_count = int(core_config['firmware_count']) except (ValueError, TypeError): firmware_count = 0 system_path = self.get_system_directory(retro_config) notes = core_config['notes'] or '' checksums = {} if notes.startswith('Suggested md5sums:'): parts = notes.split('|') for part in parts[1:]: checksum, filename = part.split(' = ') checksums[filename] = checksum for index in range(firmware_count): firmware_filename = core_config['firmware%d_path' % index] firmware_path = os.path.join(system_path, firmware_filename) if system.path_exists(firmware_path): if firmware_filename in checksums: checksum = system.get_md5_hash(firmware_path) if checksum == checksums[firmware_filename]: checksum_status = 'Checksum good' else: checksum_status = 'Checksum failed' else: checksum_status = 'No checksum info' logger.info("Firmware '%s' found (%s)", firmware_filename, checksum_status) else: logger.warning("Firmware '%s' not found!", firmware_filename) # Before closing issue #431 # TODO check for firmware*_opt and display an error message if # firmware is missing # TODO Add dialog for copying the firmware in the correct # location return True
def get_env(self, os_env=False): """Return environment variables used for a game.""" env = {} if os_env: env.update(os.environ.copy()) # By default we'll set NVidia's shader disk cache to be # per-game, so it overflows less readily. env["__GL_SHADER_DISK_CACHE"] = "1" env["__GL_SHADER_DISK_CACHE_PATH"] = self.game_path # Override SDL2 controller configuration sdl_gamecontrollerconfig = self.system_config.get( "sdl_gamecontrollerconfig") if sdl_gamecontrollerconfig: path = os.path.expanduser(sdl_gamecontrollerconfig) if system.path_exists(path): with open(path, "r", encoding='utf-8') as controllerdb_file: sdl_gamecontrollerconfig = controllerdb_file.read() env["SDL_GAMECONTROLLERCONFIG"] = sdl_gamecontrollerconfig # Set monitor to use for SDL 1 games if self.system_config.get("sdl_video_fullscreen"): env["SDL_VIDEO_FULLSCREEN_DISPLAY"] = self.system_config[ "sdl_video_fullscreen"] # DRI Prime if self.system_config.get("dri_prime"): env["DRI_PRIME"] = "1" # Prime vars prime = self.system_config.get("prime") if prime: env["__NV_PRIME_RENDER_OFFLOAD"] = "1" env["__GLX_VENDOR_LIBRARY_NAME"] = "nvidia" env["__VK_LAYER_NV_optimus"] = "NVIDIA_only" # Set PulseAudio latency to 60ms if self.system_config.get("pulse_latency"): env["PULSE_LATENCY_MSEC"] = "60" # Vulkan ICD files vk_icd = self.system_config.get("vk_icd") if vk_icd: env["VK_ICD_FILENAMES"] = vk_icd runtime_ld_library_path = None if self.use_runtime(): runtime_env = self.get_runtime_env() if "LD_LIBRARY_PATH" in runtime_env: runtime_ld_library_path = runtime_env["LD_LIBRARY_PATH"] if runtime_ld_library_path: ld_library_path = env.get("LD_LIBRARY_PATH") if not ld_library_path: ld_library_path = "$LD_LIBRARY_PATH" env["LD_LIBRARY_PATH"] = ":".join( [runtime_ld_library_path, ld_library_path]) # Apply user overrides at the end env.update(self.system_config.get("env") or {}) return env
def on_runner_installed(*args): if not system.path_exists(self.bios_path): os.makedirs(self.bios_path) if callback: callback()
def has_icon(self, game_slug, media_type=None): """Return True if the game_slug has the icon of `icon_type`""" media_type = media_type or self.icon_type return system.path_exists(get_icon_path(game_slug, media_type))
def is_authenticated(self): """Return whether the service is authenticated""" return all( [system.path_exists(path) for path in self.credential_files])
def __init__(self): if self.dest_path and not system.path_exists(self.dest_path): os.makedirs(self.dest_path)
def prepare(self): """Prepare the file for download""" if not system.path_exists(self.cache_path): os.makedirs(self.cache_path)
def desktop_integration(self, desktop_dir=None, restore=False): # noqa: C901 """Overwrite desktop integration""" # pylint: disable=too-many-branches # TODO: reduce complexity (18) user = os.getenv("USER") if not user: user = '******' user_dir = os.path.join(self.path, "drive_c/users/", user) desktop_folders = self.get_desktop_folders() if desktop_dir: desktop_dir = os.path.expanduser(desktop_dir) else: desktop_dir = user_dir if system.path_exists(user_dir): # Replace or restore desktop integration symlinks for i, item in enumerate(desktop_folders): path = os.path.join(user_dir, item) old_path = path + ".winecfg" if os.path.islink(path): if not restore: os.unlink(path) elif os.path.isdir(path): try: os.rmdir(path) # We can't delete nonempty dir, so we rename as wine do. except OSError: os.rename(path, old_path) # if we want to create a symlink and one is already there, just # skip to the next item. this also makes sure the elif doesn't # find a dir (isdir only looks at the target of the symlink). if restore and os.path.islink(path): continue if restore and not os.path.isdir(path): src_path = get_xdg_entry(DESKTOP_XDG[i]) if not src_path: logger.error( "No XDG entry found for %s, launcher not created", DESKTOP_XDG[i]) else: os.symlink(src_path, path) # We don't need all the others process of the loop continue if desktop_dir != user_dir: try: src_path = os.path.join(desktop_dir, item) except TypeError: # There is supposedly a None value in there # The current code shouldn't allow that # Just raise a exception with the values raise RuntimeError( "Missing value desktop_dir=%s or item=%s" % (desktop_dir, item)) os.makedirs(src_path, exist_ok=True) os.symlink(src_path, path) else: # We use first the renamed dir, otherwise we make it. if os.path.isdir(old_path): os.rename(old_path, path) else: os.makedirs(path, exist_ok=True) # Security: Remove other symlinks. for item in os.listdir(user_dir): path = os.path.join(user_dir, item) if item not in desktop_folders and os.path.islink(path): os.unlink(path) os.makedirs(path)
def is_cached(self): """Is the file available in the local PGA cache?""" return self.uses_pga_cache() and system.path_exists(self.dest_file)
def execute(self, data): """Run an executable file.""" args = [] terminal = None working_dir = None env = {} if isinstance(data, dict): self._check_required_params([("file", "command")], data, "execute") if "command" in data and "file" in data: raise ScriptingError( "Parameters file and command can't be used " "at the same time for the execute command", data, ) file_ref = data.get("file", "") command = data.get("command", "") args_string = data.get("args", "") for arg in shlex.split(args_string): args.append(self._substitute(arg)) terminal = data.get("terminal") working_dir = data.get("working_dir") if not data.get("disable_runtime"): # Possibly need to handle prefer_system_libs here env.update(runtime.get_env()) # Loading environment variables set in the script env.update(self.script_env) # Environment variables can also be passed to the execute command local_env = data.get("env") or {} env.update({ key: self._substitute(value) for key, value in local_env.items() }) include_processes = shlex.split(data.get("include_processes", "")) exclude_processes = shlex.split(data.get("exclude_processes", "")) elif isinstance(data, str): command = data include_processes = [] exclude_processes = [] else: raise ScriptingError("No parameters supplied to execute command.", data) if command: file_ref = "bash" args = ["-c", self._get_file(command.strip())] include_processes.append("bash") else: # Determine whether 'file' value is a file id or a path file_ref = self._get_file(file_ref) if system.path_exists(file_ref) and not system.is_executable(file_ref): logger.warning("Making %s executable", file_ref) system.make_executable(file_ref) exec_path = system.find_executable(file_ref) if not exec_path: raise ScriptingError("Unable to find executable %s" % file_ref) if terminal: terminal = linux.get_default_terminal() if not working_dir or not os.path.exists(working_dir): working_dir = self.target_path command = MonitoredCommand( [exec_path] + args, env=env, term=terminal, cwd=working_dir, include_processes=include_processes, exclude_processes=exclude_processes, ) command.start() GLib.idle_add(self.parent.attach_logger, command) self.heartbeat = GLib.timeout_add(1000, self._monitor_task, command) return "STOP"
def configure_game(self, prelaunched, error=None): # noqa: C901 """Get the game ready to start, applying all the options This methods sets the game_runtime_config attribute. """ # pylint: disable=too-many-locals,too-many-branches,too-many-statements # TODO: split into multiple methods to reduce complexity (42) if error: logger.error(error) dialogs.ErrorDialog(str(error)) if not prelaunched: logger.error("Game prelaunch unsuccessful") dialogs.ErrorDialog("An error prevented the game from running") self.state = self.STATE_STOPPED self.emit("game-stop") return system_config = self.runner.system_config self.original_outputs = DISPLAY_MANAGER.get_config() gameplay_info = self.runner.play() if "error" in gameplay_info: self.show_error_message(gameplay_info) self.state = self.STATE_STOPPED self.emit("game-stop") return logger.debug("Launching %s", self.name) logger.debug(json.dumps(gameplay_info, indent=2)) env = {} sdl_gamecontrollerconfig = system_config.get( "sdl_gamecontrollerconfig") if sdl_gamecontrollerconfig: path = os.path.expanduser(sdl_gamecontrollerconfig) if system.path_exists(path): with open(path, "r") as controllerdb_file: sdl_gamecontrollerconfig = controllerdb_file.read() env["SDL_GAMECONTROLLERCONFIG"] = sdl_gamecontrollerconfig sdl_video_fullscreen = system_config.get("sdl_video_fullscreen") or "" env["SDL_VIDEO_FULLSCREEN_DISPLAY"] = sdl_video_fullscreen restrict_to_display = system_config.get("display") if restrict_to_display != "off": if restrict_to_display == "primary": restrict_to_display = None for output in self.original_outputs: if output.primary: restrict_to_display = output.name break if not restrict_to_display: logger.warning("No primary display set") else: found = False for output in self.original_outputs: if output.name == restrict_to_display: found = True break if not found: logger.warning("Selected display %s not found", restrict_to_display) restrict_to_display = None if restrict_to_display: turn_off_except(restrict_to_display) time.sleep(3) self.resolution_changed = True resolution = system_config.get("resolution") if resolution != "off": DISPLAY_MANAGER.set_resolution(resolution) time.sleep(3) self.resolution_changed = True if system_config.get("reset_pulse"): audio.reset_pulse() self.killswitch = system_config.get("killswitch") if self.killswitch and not system.path_exists(self.killswitch): # Prevent setting a killswitch to a file that doesn't exists self.killswitch = None # Command launch_arguments = gameplay_info["command"] optimus = system_config.get("optimus") if optimus == "primusrun" and system.find_executable("primusrun"): launch_arguments.insert(0, "primusrun") elif optimus == "optirun" and system.find_executable("optirun"): launch_arguments.insert(0, "virtualgl") launch_arguments.insert(0, "-b") launch_arguments.insert(0, "optirun") elif optimus == "pvkrun" and system.find_executable("pvkrun"): launch_arguments.insert(0, "pvkrun") xephyr = system_config.get("xephyr") or "off" if xephyr != "off": if not system.find_executable("Xephyr"): raise GameConfigError( "Unable to find Xephyr, install it or disable the Xephyr option" ) xephyr_depth = "8" if xephyr == "8bpp" else "16" xephyr_resolution = system_config.get( "xephyr_resolution") or "640x480" xephyr_command = [ "Xephyr", ":2", "-ac", "-screen", xephyr_resolution + "x" + xephyr_depth, "-glamor", "-reset", "-terminate", ] if system_config.get("xephyr_fullscreen"): xephyr_command.append("-fullscreen") xephyr_thread = MonitoredCommand(xephyr_command) xephyr_thread.start() time.sleep(3) env["DISPLAY"] = ":2" if system_config.get("use_us_layout"): setxkbmap_command = [ "setxkbmap", "-model", "pc101", "us", "-print" ] xkbcomp_command = ["xkbcomp", "-", os.environ.get("DISPLAY", ":0")] xkbcomp = subprocess.Popen(xkbcomp_command, stdin=subprocess.PIPE) subprocess.Popen(setxkbmap_command, env=os.environ, stdout=xkbcomp.stdin).communicate() xkbcomp.communicate() if system_config.get("aco"): env["RADV_PERFTEST"] = "aco" pulse_latency = system_config.get("pulse_latency") if pulse_latency: env["PULSE_LATENCY_MSEC"] = "60" vk_icd = system_config.get("vk_icd") if vk_icd and vk_icd != "off" and system.path_exists(vk_icd): env["VK_ICD_FILENAMES"] = vk_icd fps_limit = system_config.get("fps_limit") or "" if fps_limit: strangle_cmd = system.find_executable("strangle") if strangle_cmd: launch_arguments = [strangle_cmd, fps_limit] + launch_arguments else: logger.warning( "libstrangle is not available on this system, FPS limiter disabled" ) prefix_command = system_config.get("prefix_command") or "" if prefix_command: launch_arguments = ( shlex.split(os.path.expandvars(prefix_command)) + launch_arguments) single_cpu = system_config.get("single_cpu") or False if single_cpu: logger.info("The game will run on a single CPU core") launch_arguments.insert(0, "0") launch_arguments.insert(0, "-c") launch_arguments.insert(0, "taskset") terminal = system_config.get("terminal") if terminal: terminal = system_config.get("terminal_app", system.get_default_terminal()) if terminal and not system.find_executable(terminal): dialogs.ErrorDialog("The selected terminal application " "could not be launched:\n" "%s" % terminal) self.state = self.STATE_STOPPED self.emit("game-stop") return # Env vars game_env = gameplay_info.get("env") or self.runner.get_env() env.update(game_env) env["game_name"] = self.name # Prime vars prime = system_config.get("prime") if prime: env["__NV_PRIME_RENDER_OFFLOAD"] = "1" env["__GLX_VENDOR_LIBRARY_NAME"] = "nvidia" env["__VK_LAYER_NV_optimus"] = "NVIDIA_only" # LD_PRELOAD ld_preload = gameplay_info.get("ld_preload") if ld_preload: env["LD_PRELOAD"] = ld_preload # Feral gamemode gamemode = system_config.get("gamemode") if gamemode: env["LD_PRELOAD"] = ":".join([ path for path in [ env.get("LD_PRELOAD"), "libgamemodeauto.so", ] if path ]) # LD_LIBRARY_PATH game_ld_libary_path = gameplay_info.get("ld_library_path") if game_ld_libary_path: ld_library_path = env.get("LD_LIBRARY_PATH") if not ld_library_path: ld_library_path = "$LD_LIBRARY_PATH" env["LD_LIBRARY_PATH"] = ":".join( [game_ld_libary_path, ld_library_path]) include_processes = shlex.split( system_config.get("include_processes", "")) exclude_processes = shlex.split( system_config.get("exclude_processes", "")) self.game_runtime_config = { "args": launch_arguments, "env": env, "terminal": terminal, "include_processes": include_processes, "exclude_processes": exclude_processes, } if system_config.get("disable_compositor"): self.set_desktop_compositing(False) prelaunch_command = system_config.get("prelaunch_command") if system.path_exists(prelaunch_command): self.prelaunch_executor = MonitoredCommand( [prelaunch_command], include_processes=[os.path.basename(prelaunch_command)], env=self.game_runtime_config["env"], cwd=self.directory, ) self.prelaunch_executor.start() logger.info("Running %s in the background", prelaunch_command) if system_config.get("prelaunch_wait"): self.heartbeat = GLib.timeout_add(HEARTBEAT_DELAY, self.prelaunch_beat) else: self.start_game()
def is_installed(self, version=None, fallback=True, min_version=None): """Checks if pico8 runner is installed and if the pico8 executable available. """ if self.is_native and system.path_exists(self.runner_config.get("runner_executable")): return True return system.path_exists(os.path.join(settings.RUNNER_DIR, "pico8/web/player.html"))
def __init__(self): if not system.path_exists(self.db_path): raise OSError( "Path to gamecontrollerdb.txt not provided or invalid") self.controllers = {} self.parsedb()
def desktop_launcher_exists(game_slug, game_id): """Return True if there is an existing desktop icon for a game""" return system.path_exists(get_launcher_path(game_slug, game_id))
def menu_launcher_exists(game_slug, game_id): """Return True if there is an existing application menu entry for a game""" return system.path_exists(get_menu_launcher_path(game_slug, game_id))
def get_playonlinux(): """Return the folder containing PoL config files""" pol_path = os.path.expanduser("~/.PlayOnLinux") if system.path_exists(os.path.join(pol_path, "wine")): return pol_path return None
def is_ready(self): """Whether the file is ready to be downloaded / fetched from its provider""" if (self.provider in ("user", "pga") and not system.path_exists(self.installer_file.dest_file)): return False return True
def is_retroarch_installed(self): return system.path_exists(self.get_executable())
def libs_dir(self): path = os.path.join(settings.RUNNER_DIR, "scummvm/lib") return path if system.path_exists(path) else ""