def test_game_with_same_slug_is_updated(self): games_db.add_game(name="some game", runner="linux") game = games_db.get_game_by_field("some-game", "slug") self.assertFalse(game['directory']) games_db.add_or_update(name="some game", runner='linux', directory="/foo") game = games_db.get_game_by_field("some-game", "slug") self.assertEqual(game['directory'], '/foo')
def _get_installed_dependency(dependency): """Return whether a dependency is installed""" game = get_game_by_field(dependency, field="installer_slug") if not game: game = get_game_by_field(dependency, "slug") if bool(game) and bool(game["directory"]): return game
def _get_game_dependency(dependency): """Return a game database row from a dependency name""" game = get_game_by_field(dependency, field="installer_slug") if not game: game = get_game_by_field(dependency, "slug") # Game must be installed and have a directory # set so we can use that as the destination if game and game["installed"] and game["directory"]: return game
def install_from_steam(self, manifest): """Create a new Lutris game based on an existing Steam install""" if not manifest.is_installed(): return appid = manifest.steamid if appid in self.excluded_appids: return service_game = ServiceGameCollection.get_game(self.id, appid) if not service_game: return lutris_game_id = "%s-%s" % (self.id, appid) existing_game = get_game_by_field(lutris_game_id, "slug") if existing_game: return game_config = LutrisConfig().game_level game_config["game"]["appid"] = appid configpath = write_game_config(lutris_game_id, game_config) game_id = add_game( name=service_game["name"], runner="steam", slug=slugify(service_game["name"]), installed=1, installer_slug=lutris_game_id, configpath=configpath, platform="Linux", service=self.id, service_id=appid, ) return game_id
def get_game_config(self): """Return the game configuration""" if self.requires: # Load the base game config required_game = get_game_by_field(self.requires, field="installer_slug") base_config = LutrisConfig( runner_slug=self.runner, game_config_id=required_game["configpath"] ) config = base_config.game_level else: config = {"game": {}} # Config update if "system" in self.script: config["system"] = self._substitute_config(self.script["system"]) if self.runner in self.script and self.script[self.runner]: config[self.runner] = self._substitute_config(self.script[self.runner]) launcher, launcher_config = self.get_game_launcher_config(self.interpreter.game_files) if launcher: config["game"][launcher] = launcher_config if "game" in self.script: try: config["game"].update(self.script["game"]) except ValueError: raise ScriptingError("Invalid 'game' section", self.script["game"]) config["game"] = self._substitute_config(config["game"]) if AUTO_ELF_EXE in config["game"].get("exe", ""): config["game"]["exe"] = find_linux_game_executable(self.interpreter.target_path, make_executable=True) elif AUTO_WIN32_EXE in config["game"].get("exe", ""): config["game"]["exe"] = find_windows_game_executable(self.interpreter.target_path) return config
def install_from_origin(self, origin_game, manifest): offer_id = manifest["id"].split("@")[0] logger.debug("Installing Origin game %s", offer_id) service_game = ServiceGameCollection.get_game("origin", offer_id) if not service_game: logger.error( "Aborting install, %s is not present in the game library.", offer_id) return lutris_game_id = slugify(service_game["name"]) + "-" + self.id existing_game = get_game_by_field(lutris_game_id, "installer_slug") if existing_game: return game_config = LutrisConfig( game_config_id=origin_game["configpath"]).game_level game_config["game"]["args"] = get_launch_arguments(manifest["id"]) configpath = write_game_config(lutris_game_id, game_config) game_id = add_game( name=service_game["name"], runner=origin_game["runner"], slug=slugify(service_game["name"]), directory=origin_game["directory"], installed=1, installer_slug=lutris_game_id, configpath=configpath, service=self.id, service_id=offer_id, ) return game_id
def get_game_id(self): """Return the ID of the game in the local DB if one exists""" # If the game is in the library and uninstalled, the first installation # updates it existing_game = get_game_by_field(self.game_slug, "slug") if existing_game and not existing_game["installed"]: return existing_game["id"]
def install_from_egs(self, egs_game, manifest): """Create a new Lutris game based on an existing EGS install""" app_name = manifest["AppName"] logger.debug("Installing EGS game %s", app_name) service_game = ServiceGameCollection.get_game("egs", app_name) if not service_game: logger.error("Aborting install, %s is not present in the game library.", app_name) return lutris_game_id = slugify(service_game["name"]) + "-" + self.id existing_game = get_game_by_field(lutris_game_id, "installer_slug") if existing_game: return game_config = LutrisConfig(game_config_id=egs_game["configpath"]).game_level game_config["game"]["args"] = get_launch_arguments(app_name) configpath = write_game_config(lutris_game_id, game_config) game_id = add_game( name=service_game["name"], runner=egs_game["runner"], slug=slugify(service_game["name"]), directory=egs_game["directory"], installed=1, installer_slug=lutris_game_id, configpath=configpath, service=self.id, service_id=app_name, ) return game_id
def on_game_selection_changed(self, view, selection): if not selection: GLib.idle_add(self.update_revealer) return False game_id = view.get_model().get_value(selection, COL_ID) if not game_id: GLib.idle_add(self.update_revealer) return False if self.service: game = ServiceGameCollection.get_game(self.service.id, game_id) else: game = games_db.get_game_by_field(int(game_id), "id") if not game: game = { "id": game_id, "appid": game_id, "name": view.get_model().get_value(selection, COL_NAME), "slug": game_id, "service": self.service.id if self.service else None, } logger.warning("No game found. Replacing with placeholder %s", game) GLib.idle_add(self.update_revealer, game) return False
def __init__(self, config=None): """Initialize runner.""" self.config = config if config: self.game_data = get_game_by_field(self.config.game_config_id, "configpath") else: self.game_data = {}
def install_from_ubisoft(self, ubisoft_connect, game): app_name = game["name"] lutris_game_id = slugify(game["name"]) + "-" + self.id existing_game = get_game_by_field(lutris_game_id, "installer_slug") if existing_game: logger.debug("Ubisoft Connect game %s is already installed", app_name) return logger.debug("Installing Ubisoft Connect game %s", app_name) game_config = LutrisConfig( game_config_id=ubisoft_connect["configpath"]).game_level game_config["game"]["args"] = f"uplay://launch/{game['appid']}" configpath = write_game_config(lutris_game_id, game_config) game_id = add_game( name=game["name"], runner=self.runner, slug=slugify(game["name"]), directory=ubisoft_connect["directory"], installed=1, installer_slug=lutris_game_id, configpath=configpath, service=self.id, service_id=game["appid"], ) return game_id
def play(self): launch_info = {} launch_info["env"] = self.get_env(os_env=False) game_data = get_game_by_field(self.config.game_config_id, "configpath") command = self.launch_args if self.is_native: if not self.runner_config.get("splore"): command.append("-run") cartPath = self.cart_path if not os.path.exists(cartPath): return {"error": "FILE_NOT_FOUND", "file": cartPath} command.append(cartPath) else: command.append("--name") command.append(game_data.get("name") + " - PICO-8") # icon = datapath.get_icon_path(game_data.get("slug")) # if icon: # command.append("--icon") # command.append(icon) webargs = { "cartridge": self.cart_path, "engine": self.engine_path, "fullscreen": self.runner_config.get("fullscreen") is True, } command.append("--execjs") command.append("load_config(" + json.dumps(webargs) + ")") launch_info["command"] = command return launch_info
def on_game_duplicate(self, _widget): confirm_dlg = QuestionDialog({ "parent": self.window, "question": _("Do you wish to duplicate %s?\nThe configuration will be duplicated, " "but the games files will <b>not be duplicated</b>.") % gtk_safe(self.game.name), "title": _("Duplicate game?"), }) if confirm_dlg.result != Gtk.ResponseType.YES: return assigned_name = get_unusued_game_name(self.game.name) old_config_id = self.game.game_config_id if old_config_id: new_config_id = duplicate_game_config(self.game.slug, old_config_id) else: new_config_id = None db_game = get_game_by_field(self.game.id, "id") db_game["name"] = assigned_name db_game["configpath"] = new_config_id db_game.pop("id") # Disconnect duplicate from service- there should be at most # 1 PGA game for a service game. db_game.pop("service", None) db_game.pop("service_id", None) game_id = add_game(**db_game) new_game = Game(game_id) new_game.save()
def on_game_activated(self, view, game_id): """Handles view activations (double click, enter press)""" if self.service: if self.service.id != "lutris": db_game = games_db.get_game_for_service( self.service.id, game_id) if db_game: game_id = db_game["id"] else: db_game = ServiceGameCollection.get_game( self.service.id, game_id) if db_game: game_id = self.service.install(db_game) else: game_id = self.service.install(game_id) else: db_game = games_db.get_game_by_field(game_id) if not db_game: self.service.install(game_id) return if db_game["installed"] != 1: self.service.install(game_id) return game_id = db_game["id"] if game_id: game = Game(game_id) game.emit("game-launch")
def on_game_install_dlc(self, game): service = get_enabled_services()[game.service]() db_game = games_db.get_game_by_field(game.id, "id") installers = service.get_dlc_installers(db_game) if installers: self.show_installer_window(installers, service, game.appid) else: ErrorDialog(_("No DLC found")) return True
def on_game_selection_changed(self, view, game_id): if not game_id: GLib.idle_add(self.update_revealer) return False if self.service: game = ServiceGameCollection.get_game(self.service.id, game_id) else: game = games_db.get_game_by_field(int(game_id), "id") GLib.idle_add(self.update_revealer, game) return False
def on_game_updated(self, game): if game.appid and self.service: db_game = ServiceGameCollection.get_game(self.service.id, game.appid) else: db_game = games_db.get_game_by_field(game.id, "id") updated = self.game_store.update(db_game) if not updated: self.game_store.add_game(db_game) return True
def __init__(self, db_game, game_actions, application): """Create the game bar with a database row""" super().__init__(orientation=Gtk.Orientation.VERTICAL, visible=True, margin_top=12, margin_left=12, margin_bottom=12, margin_right=12, spacing=6) self.game_start_hook_id = GObject.add_emission_hook( Game, "game-start", self.on_game_state_changed) self.game_started_hook_id = GObject.add_emission_hook( Game, "game-started", self.on_game_state_changed) self.game_stopped_hook_id = GObject.add_emission_hook( Game, "game-stopped", self.on_game_state_changed) self.game_updated_hook_id = GObject.add_emission_hook( Game, "game-updated", self.on_game_state_changed) self.game_removed_hook_id = GObject.add_emission_hook( Game, "game-removed", self.on_game_state_changed) self.game_installed_hook_id = GObject.add_emission_hook( Game, "game-installed", self.on_game_state_changed) self.connect("destroy", self.on_destroy) self.set_margin_bottom(12) self.game_actions = game_actions self.db_game = db_game self.service = None if db_game.get("service"): try: self.service = services.SERVICES[db_game["service"]]() except KeyError: pass game_id = None if "service_id" in db_game: self.appid = db_game["service_id"] game_id = db_game["id"] elif self.service: self.appid = db_game["appid"] if self.service.id == "lutris": game = get_game_by_field(self.appid, field="slug") else: game = get_game_for_service(self.service.id, self.appid) if game: game_id = game["id"] if game_id: self.game = application.get_game_by_id(game_id) or Game(game_id) else: self.game = Game() self.game.name = db_game["name"] self.game.slug = db_game["slug"] self.game.appid = self.appid self.game.service = self.service.id if self.service else None game_actions.set_game(self.game) self.update_view()
def install(self, db_game): egs_game = get_game_by_field(self.client_installer, "installer_slug") application = Gio.Application.get_default() if not egs_game or not egs_game["installed"]: installers = get_installers(game_slug=self.client_installer, ) application.show_installer_window(installers) else: application.show_installer_window( [self.generate_installer(db_game, egs_game)], service=self, appid=db_game["appid"])
def get_configurations(self): ubi_game = get_game_by_field("ubisoft-connect", "slug") if not ubi_game: return base_dir = ubi_game["directory"] configurations_path = os.path.join( base_dir, "drive_c/Program Files (x86)/Ubisoft/Ubisoft Game Launcher/" "cache/configuration/configurations") with open(configurations_path, "rb") as config_file: content = config_file.read() return content
def add_installed_games(self): origin_game = get_game_by_field("origin", "slug") if not origin_game: logger.error("Origin is not installed") origin_prefix = origin_game["directory"].split("drive_c")[0] if not os.path.exists(os.path.join(origin_prefix, "drive_c")): logger.error("Invalid install of Origin at %s", origin_prefix) return origin_launcher = OriginLauncher(origin_prefix) for manifest in origin_launcher.iter_manifests(): self.install_from_origin(origin_game, manifest) logger.debug("All EGS games imported")
def install(self, db_game): origin_game = get_game_by_field(self.client_installer, "slug") application = Gio.Application.get_default() if not origin_game or not origin_game["installed"]: logger.warning("Installing the Origin client") installers = get_installers(game_slug=self.client_installer) application.show_installer_window(installers) else: application.show_installer_window( [self.generate_installer(db_game, origin_game)], service=self, appid=db_game["appid"])
def add_installed_games(self): ubisoft_connect = get_game_by_field(self.client_installer, "slug") if not ubisoft_connect: logger.warning("Ubisoft Connect not installed") return prefix_path = ubisoft_connect["directory"].split("drive_c")[0] prefix = WinePrefixManager(prefix_path) for game in ServiceGameCollection.get_for_service(self.id): details = json.loads(game["details"]) install_path = get_ubisoft_registry(prefix, details.get("registryPath")) exe = get_ubisoft_registry(prefix, details.get("exe")) if install_path and exe: self.install_from_ubisoft(ubisoft_connect, game)
def install(self, db_game): """Install a game or Ubisoft Connect if not already installed""" ubisoft_connect = get_game_by_field(self.client_installer, "slug") application = Gio.Application.get_default() if not ubisoft_connect or not ubisoft_connect["installed"]: logger.warning("Ubisoft Connect (%s) not installed", self.client_installer) installers = get_installers(game_slug=self.client_installer) application.show_installer_window(installers) else: application.show_installer_window( [self.generate_installer(db_game, ubisoft_connect)], service=self, appid=db_game["appid"])
def on_game_updated(self, game): """Updates an individual entry in the view when a game is updated""" if game.appid and self.service: db_game = ServiceGameCollection.get_game(self.service.id, game.appid) else: db_game = games_db.get_game_by_field(game.id, "id") if not self.is_game_displayed(game): self.game_store.remove_game(db_game["id"]) return True updated = self.game_store.update(db_game) if not updated: self.update_store() return True
def _get_runner_version(self): """Return the version of the runner used for the installer""" if self.installer.runner == "wine": # If a version is specified in the script choose this one if self.installer.script.get(self.installer.runner): return self.installer.script[self.installer.runner].get( "version") # If the installer is a extension, use the wine version from the base game if self.installer.requires: db_game = get_game_by_field(self.installer.requires, field="installer_slug") if not db_game: db_game = get_game_by_field(self.installer.requires, field="slug") if not db_game: logger.warning("Can't find game %s", self.installer.requires) return None game = Game(db_game["id"]) return game.config.runner_config["version"] if self.installer.runner == "libretro": return self.installer.script["game"]["core"] return None
def add_installed_games(self): """Scan an existing EGS install for games""" egs_game = get_game_by_field("epic-games-store", "slug") if not egs_game: logger.error("EGS is not installed in Lutris") return egs_prefix = egs_game["directory"].split("drive_c")[0] logger.info("EGS detected in %s", egs_prefix) if not system.path_exists(os.path.join(egs_prefix, "drive_c")): logger.error("Invalid install of EGS at %s", egs_prefix) return egs_launcher = EGSLauncher(egs_prefix) for manifest in egs_launcher.iter_manifests(): self.install_from_egs(egs_game, manifest) logger.debug("All EGS games imported")
def __init__(self, db_game, game_actions, application): """Create the game bar with a database row""" super().__init__(visible=True) GObject.add_emission_hook(Game, "game-start", self.on_game_state_changed) GObject.add_emission_hook(Game, "game-started", self.on_game_state_changed) GObject.add_emission_hook(Game, "game-stopped", self.on_game_state_changed) GObject.add_emission_hook(Game, "game-updated", self.on_game_state_changed) GObject.add_emission_hook(Game, "game-removed", self.on_game_state_changed) GObject.add_emission_hook(Game, "game-installed", self.on_game_state_changed) self.set_margin_bottom(12) self.game_actions = game_actions self.db_game = db_game self.service = None if db_game.get("service"): try: self.service = services.get_services()[db_game["service"]]() except KeyError: logger.warning("Non existent service '%s'", db_game["service"]) game_id = None if "service_id" in db_game: self.appid = db_game["service_id"] game_id = db_game["id"] elif self.service: self.appid = db_game["appid"] if self.service.id == "lutris": game = get_game_by_field(self.appid, field="slug") else: game = get_game_for_service(self.service.id, self.appid) if game: game_id = game["id"] if game_id: self.game = application.get_game_by_id(game_id) or Game(game_id) game_actions.set_game(self.game) else: self.game = Game() self.game_name = db_game["name"] self.game_slug = db_game["slug"] self.update_view()
def download(self, slug, url): if url.startswith("http"): return super().download(slug, url) if not url.endswith(".jpg"): return ubi_game = get_game_by_field("ubisoft-connect", "slug") if not ubi_game: return base_dir = ubi_game["directory"] asset_file = os.path.join( base_dir, "drive_c/Program Files (x86)/Ubisoft/Ubisoft Game Launcher/cache/assets", url) cache_path = os.path.join(self.dest_path, self.get_filename(slug)) if os.path.exists(asset_file): shutil.copy(asset_file, cache_path) else: logger.warning("No thumbnail in %s", asset_file)
def __init__(self, game_id=None): super().__init__() self.id = game_id # pylint: disable=invalid-name self.runner = None self.config = None # Load attributes from database game_data = games_db.get_game_by_field(game_id, "id") self.slug = game_data.get("slug") or "" self.runner_name = game_data.get("runner") or "" self.directory = game_data.get("directory") or "" self.name = game_data.get("name") or "" self.game_config_id = game_data.get("configpath") or "" self.is_installed = bool( game_data.get("installed") and self.game_config_id) self.is_hidden = bool(game_data.get("hidden")) self.platform = game_data.get("platform") or "" self.year = game_data.get("year") or "" self.lastplayed = game_data.get("lastplayed") or 0 self.has_custom_banner = bool(game_data.get("has_custom_banner")) self.has_custom_icon = bool(game_data.get("has_custom_icon")) self.service = game_data.get("service") self.appid = game_data.get("service_id") self.discord_presence = DiscordPresence() self.playtime = game_data.get("playtime") or 0.0 if self.game_config_id: self.load_config() self.game_uuid = None self.game_thread = None self.prelaunch_pids = [] self.prelaunch_executor = None self.heartbeat = None self.killswitch = None self.state = self.STATE_STOPPED self.game_runtime_config = {} self.resolution_changed = False self.compositor_disabled = False self.original_outputs = None self._log_buffer = None self.timer = Timer() self.screen_saver_inhibitor_cookie = None