Exemple #1
0
    def on_steam_game_changed(self, operation, path):
        """Action taken when a Steam AppManifest file is updated"""
        appmanifest = steam.AppManifest(path)
        if self.running_game and 'steam' in self.running_game.runner_name:
            self.running_game.notify_steam_game_changed(appmanifest)

        runner_name = appmanifest.get_runner_name()
        games = pga.get_games_where(steamid=appmanifest.steamid)
        if operation == Gio.FileMonitorEvent.DELETED:
            for game in games:
                if game['runner'] == runner_name:
                    steam.mark_as_uninstalled(game)
                    self.view.set_uninstalled(Game(game['id']))
                    break
        elif operation in (Gio.FileMonitorEvent.CHANGED,
                           Gio.FileMonitorEvent.CREATED):
            if not appmanifest.is_installed():
                return
            if runner_name == 'winesteam':
                return
            game_info = None
            for game in games:
                if game['installed'] == 0:
                    game_info = game
                else:
                    # Game is already installed, don't do anything
                    return
            if not game_info:
                game_info = {
                    'name': appmanifest.name,
                    'slug': appmanifest.slug,
                }
            if steam in get_services_synced_at_startup():
                game_id = steam.mark_as_installed(appmanifest.steamid,
                                                  runner_name, game_info)
                game_ids = [game['id'] for game in self.game_list]
                if game_id not in game_ids:
                    self.add_game_to_view(game_id)
                else:
                    self.view.set_installed(Game(game_id))
Exemple #2
0
def fill_missing_platforms():
    """Sets the platform on games where it's missing.
    This should never happen.
    """
    pga_games = get_games(filters={"installed": 1})
    for pga_game in pga_games:
        if pga_game.get("platform") or not pga_game["runner"]:
            continue
        game = Game(game_id=pga_game["id"])
        game.set_platform_from_runner()
        if game.platform:
            logger.info("Platform for %s set to %s", game.name, game.platform)
            game.save(save_config=False)
Exemple #3
0
 def on_game_run(self, *args, game_id=None):
     """Launch a game, or install it if it is not"""
     if not game_id:
         game_id = self._get_current_game_id()
     if not game_id:
         return
     self.running_game = Game(game_id)
     if self.running_game.is_installed:
         self.running_game.play()
     else:
         game_slug = self.running_game.slug
         self.running_game = None
         InstallerDialog(game_slug=game_slug, parent=self)
Exemple #4
0
    def __init__(self, db_game, game_actions):
        """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
        if db_game.get("service"):
            self.service = services.get_services()[db_game["service"]]()
        else:
            self.service = None
        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"]
            game = get_game_for_service(self.service.id, self.appid)
            if game:
                game_id = game["id"]
        self.game = Game(game_id) if game_id else Game()
        self.game_name = db_game["name"]
        self.game_slug = db_game["slug"]

        if self.game:
            game_actions.set_game(self.game)
        self.update_view()
Exemple #5
0
    def on_game_installed(self, view, game_id):
        """Callback to handle newly installed games"""
        if not isinstance(game_id, int):
            raise ValueError("game_id must be an int")
        if not self.view.has_game_id(game_id):
            logger.debug("Adding new installed game to view (%d)", game_id)
            self.add_game_to_view(game_id, is_async=False)

        game = Game(game_id)
        view.set_installed(game)
        self.sidebar_treeview.update()
        GLib.idle_add(resources.fetch_icons, [game.slug],
                      self.on_image_downloaded)
Exemple #6
0
 def get_usage_stats(self):
     """Return the usage for each version"""
     runner_games = get_games_by_runner(self.runner)
     if self.runner == "wine":
         runner_games += get_games_by_runner("winesteam")
     version_usage = defaultdict(list)
     for db_game in runner_games:
         if not db_game["installed"]:
             continue
         game = Game(db_game["id"])
         version = game.config.runner_config["version"]
         version_usage[version].append(db_game["id"])
     return version_usage
Exemple #7
0
def fill_missing_platforms():
    """Sets the platform on games where it's missing.
    This should never happen.
    """
    pga_games = pga.get_games(filter_installed=True)
    for pga_game in pga_games:
        if pga_game.get("platform") or not pga_game["runner"]:
            continue
        game = Game(game_id=pga_game["id"])
        logger.error("Providing missing platorm for game %s", game.slug)
        game.set_platform_from_runner()
        if game.platform:
            game.save(metadata_only=True)
Exemple #8
0
 def platform(self):
     """Platform"""
     _platform = self._pga_data["platform"]
     if not _platform and self.installed:
         game_inst = Game(self._pga_data["id"])
         if game_inst.platform:
             _platform = game_inst.platform
         else:
             logger.debug("Game %s has no platform", self)
             # Save the game, which will call `set_platform_from_runner`
             game_inst.save()
             _platform = game_inst.platform
     return _platform
Exemple #9
0
 def run_no_installer_dialog(self):
     """Open dialog for 'no script available' situation."""
     dlg = NoInstallerDialog(self)
     if dlg.result == dlg.MANUAL_CONF:
         game_data = pga.get_game_by_field(self.game_slug, 'slug')
         game = Game(game_data['id'])
         AddGameDialog(
             self.parent,
             game=game,
             callback=lambda: self.notify_install_success(game_data['id'])
         )
     elif dlg.result == dlg.NEW_INSTALLER:
         webbrowser.open(settings.GAME_URL % self.game_slug)
Exemple #10
0
    def on_edit_game_configuration(self, widget):
        """Edit game preferences."""
        game = Game(self.view.selected_game)

        def on_dialog_saved():
            game_id = dialog.game.id
            self.view.remove_game(game_id)
            self.view.add_game_by_id(game_id)
            self.view.set_selected_game(game_id)
            self.sidebar_treeview.update()

        if game.is_installed:
            dialog = EditGameConfigDialog(self, game, on_dialog_saved)
Exemple #11
0
    def __init__(self, game_id, callback, parent=None):
        super().__init__(parent=parent)
        self.set_size_request(640, 128)
        self.game = Game(game_id)
        self.callback = callback
        self.delete_files = False
        container = Gtk.VBox(visible=True)
        self.get_content_area().add(container)

        title_label = Gtk.Label(visible=True)
        title_label.set_line_wrap(True)
        title_label.set_alignment(0, 0.5)
        title_label.set_line_wrap_mode(Pango.WrapMode.WORD_CHAR)
        title_label.set_markup(
            "<span font_desc='14'><b>Uninstall %s</b></span>" %
            gtk_safe(self.game.name))

        container.pack_start(title_label, False, False, 4)

        self.folder_label = Gtk.Label(visible=True)
        self.folder_label.set_alignment(0, 0.5)
        self.folder_label.set_margin_bottom(30)

        self.delete_button = Gtk.Button(_("Uninstall"), visible=True)
        self.delete_button.connect("clicked", self.on_delete_clicked)

        if not self.game.directory:
            self.folder_label.set_markup("No file will be deleted")
        elif len(get_games(searches={"directory": self.game.directory})) > 1:
            self.folder_label.set_markup(
                "The folder %s is used by other games and will be kept." %
                self.game.directory)
        elif is_removeable(self.game.directory):
            self.delete_button.set_sensitive(False)
            self.folder_label.set_markup("<i>Calculating size…</i>")
            AsyncCall(get_disk_size, self.folder_size_cb, self.game.directory)
        else:
            self.folder_label.set_markup(
                "Content of %s are protected and will not be deleted." %
                reverse_expanduser(self.game.directory))
        container.pack_start(self.folder_label, False, False, 4)

        button_box = Gtk.HBox(visible=True)
        style_context = button_box.get_style_context()
        style_context.add_class("linked")
        cancel_button = Gtk.Button(_("Cancel"), visible=True)
        cancel_button.connect("clicked", self.on_close)
        button_box.add(cancel_button)
        button_box.add(self.delete_button)
        container.pack_end(button_box, False, False, 0)
        self.show()
Exemple #12
0
 def install(self, db_game):
     appid = db_game["appid"]
     db_games = get_games(filters={"service_id": appid, "installed": "1", "service": "steam"})
     existing_game = self.match_existing_game(db_games, appid)
     if existing_game:
         logger.debug("Found steam game: %s", existing_game)
         game = Game(existing_game.id)
         game.save()
         return
     service_installers = self.get_installers_from_api(appid)
     if not service_installers:
         service_installers = [self.generate_installer(db_game)]
     application = Gio.Application.get_default()
     application.show_installer_window(service_installers, service=self, appid=appid)
Exemple #13
0
    def on_game_updated(self, game):
        """Callback to refresh the view when a game is updated"""
        logger.debug("Updating game %s", game)
        if not game.is_installed:
            game = Game(game_id=game.id)
            self.game_selection_changed(None, None)
        game.load_config()
        try:
            self.game_store.update_game_by_id(game.id)
        except ValueError:
            self.game_store.add_game_by_id(game.id)

        self.game_panel.refresh()
        return True
Exemple #14
0
    def on_edit_game_configuration(self, _widget):
        """Edit game preferences"""
        init_dxvk_versions()
        game = Game(self.view.selected_game)

        def on_dialog_saved():
            game_id = dialog.game.id
            self.view.remove_game(game_id)
            self.view.add_game_by_id(game_id)
            self.view.set_selected_game(game_id)
            self.sidebar_listbox.update()

        if game.is_installed:
            dialog = EditGameConfigDialog(self, game, on_dialog_saved)
Exemple #15
0
 def build_game_tab(self):
     if self.game and self.runner_name:
         self.game.runner_name = self.runner_name
         self.game_box = GameBox(self.lutris_config, "game", self.game)
         game_sw = self.build_scrolled_window(self.game_box)
     elif self.runner_name:
         game = Game(None)
         game.runner_name = self.runner_name
         self.game_box = GameBox(self.lutris_config, "game", game)
         game_sw = self.build_scrolled_window(self.game_box)
     else:
         game_sw = Gtk.Label(label=self.no_runner_label)
         game_sw.show()
     self.add_notebook_tab(game_sw, "Game configuration")
Exemple #16
0
    def add_game(self, game):
        name = game['name'].replace('&', '&amp;').replace('<', '&lt;').replace('>', '&gt;')
        runner = None
        platform = ''
        runner_name = game['runner']
        runner_human_name = ''
        if runner_name:
            game_inst = Game(game['id'])
            if not game_inst.is_installed:
                return
            if runner_name in self.runner_names:
                runner_human_name = self.runner_names[runner_name]
            else:
                try:
                    runner = runners.import_runner(runner_name)
                except runners.InvalidRunner:
                    game['installed'] = False
                else:
                    runner_human_name = runner.human_name
                    self.runner_names[runner_name] = runner_human_name
            platform = game_inst.platform
            if not platform:
                game_inst.set_platform_from_runner()
                platform = game_inst.platform

        lastplayed_text = ''
        if game['lastplayed']:
            lastplayed_text = time.strftime("%c", time.localtime(game['lastplayed']))

        installed_at_text = ''
        if game['installed_at']:
            installed_at_text = time.strftime("%c", time.localtime(game['installed_at']))

        pixbuf = get_pixbuf_for_game(game['slug'], self.icon_type,
                                     game['installed'])
        self.store.append((
            game['id'],
            game['slug'],
            name,
            pixbuf,
            str(game['year'] or ''),
            runner_name,
            runner_human_name,
            platform,
            game['lastplayed'],
            lastplayed_text,
            game['installed'],
            game['installed_at'],
            installed_at_text
        ))
Exemple #17
0
    def manually_configure_game(self):
        game_data = pga.get_game_by_field(self.game_slug, "slug")

        if game_data and "slug" in game_data:
            # Game data already exist locally.
            game = Game(game_data["id"])
        else:
            # Try to load game data from remote.
            games = api.get_api_games([self.game_slug])

            if games and len(games) >= 1:
                remote_game = games[0]
                game_data = {
                    "name": remote_game["name"],
                    "slug": remote_game["slug"],
                    "year": remote_game["year"],
                    "updated": remote_game["updated"],
                    "steamid": remote_game["steamid"],
                }
                game = Game(pga.add_game(**game_data))
            else:
                game = None
        AddGameDialog(self.parent, game=game)
Exemple #18
0
 def on_steam_game_changed(self, operation, path):
     appmanifest = steam.AppManifest(path)
     runner_name = appmanifest.get_runner_name()
     games = pga.get_game_by_field(appmanifest.steamid,
                                   field='steamid',
                                   all=True)
     if operation == Gio.FileMonitorEvent.DELETED:
         for game in games:
             if game['runner'] == runner_name:
                 steam.mark_as_uninstalled(game)
                 self.view.set_uninstalled(Game(game['id']))
                 break
     elif operation in (Gio.FileMonitorEvent.CHANGED,
                        Gio.FileMonitorEvent.CREATED):
         if not appmanifest.is_installed():
             return
         if runner_name == 'winesteam':
             return
         game_info = None
         for game in games:
             if game['installed'] == 0:
                 game_info = game
             else:
                 # Game is already installed, don't do anything
                 return
         if not game_info:
             game_info = {
                 'name': appmanifest.name,
                 'slug': appmanifest.slug,
             }
         game_id = steam.mark_as_installed(appmanifest.steamid, runner_name,
                                           game_info)
         game_ids = [game['id'] for game in self.game_list]
         if game_id not in game_ids:
             self.add_game_to_view(game_id)
         else:
             self.view.set_installed(Game(game_id))
Exemple #19
0
    def on_save(self, _button, callback=None):
        """Save game info and destroy widget. Return True if success."""
        if not self.is_valid():
            return False
        name = self.name_entry.get_text()

        if not self.slug:
            self.slug = slugify(name)

        if not self.game:
            self.game = Game()

        year = None
        if self.year_entry.get_text():
            year = int(self.year_entry.get_text())

        if self.lutris_config.game_config_id == TEMP_CONFIG:
            self.lutris_config.game_config_id = self.get_config_id()

        # Delete the old copy of the game if the runner changes
        runner_class = runners.import_runner(self.runner_name)
        runner = runner_class(self.lutris_config)
        if self.game.id and self.game.platform != runner.get_platform():
            self.game.remove()
        self.game.runner_name = self.runner_name

        self.game.name = name
        self.game.slug = self.slug
        self.game.year = year
        self.game.config = self.lutris_config

        fps_limit = self.game.config.system_config.get("fps_limit", None)
        if fps_limit:
            try:
                int(fps_limit)
            except ValueError:
                ErrorDialog("Fps limit only accept numbers")
                return

        self.game.directory = runner.game_path
        self.game.is_installed = True
        if self.runner_name in ("steam", "winesteam"):
            self.game.steamid = self.lutris_config.game_config["appid"]
        self.game.set_platform_from_runner()
        self.game.save()
        self.destroy()
        self.saved = True
        if callback:
            callback()
Exemple #20
0
 def on_game_activated(self, view, game_id):
     """Handles view activations (double click, enter press)"""
     if self.service:
         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)
             self.service.install(db_game)
             return
     game = Game(game_id)
     if game.is_installed:
         logger.info("Game is installed")
     game.emit("game-launch")
Exemple #21
0
    def get_runner_info(self, game):
        if not game["runner"]:
            return
        runner_human_name = self.runner_names.get(game["runner"], "")
        platform = game["platform"]
        if not platform and game["installed"]:
            game_inst = Game(game["id"])
            platform = game_inst.platform
            if not platform:
                game_inst.set_platform_from_runner()
                platform = game_inst.platform
                logger.debug("Setting platform for %s: %s", game["name"],
                             platform)

        return runner_human_name, platform
Exemple #22
0
    def on_game_clicked(self, *args):
        """Launch a game."""
        # Wait two seconds to avoid running a game twice
        if time.time() - self.game_launch_time < 2:
            return
        self.game_launch_time = time.time()

        game_slug = self.view.selected_game
        if game_slug:
            self.running_game = Game(game_slug)
            if self.running_game.is_installed:
                self.stop_button.set_sensitive(True)
                self.running_game.play()
            else:
                InstallerDialog(game_slug, self)
Exemple #23
0
    def add_installed_games(self):
        """Syncs installed Steam games with Lutris"""
        installed_appids = []
        for steamapps_path in self.steamapps_paths:
            for appmanifest_file in get_appmanifests(steamapps_path):
                app_manifest_path = os.path.join(steamapps_path,
                                                 appmanifest_file)
                app_manifest = AppManifest(app_manifest_path)
                installed_appids.append(app_manifest.steamid)
                self.install_from_steam(app_manifest)

        db_games = get_games(filters={"runner": "steam"})
        for db_game in db_games:
            steam_game = Game(db_game["id"])
            try:
                appid = steam_game.config.game_level["game"]["appid"]
            except KeyError:
                logger.warning("Steam game %s has no AppID")
                continue
            if appid not in installed_appids:
                steam_game.remove(no_signal=True)

        db_appids = defaultdict(list)
        db_games = get_games(filters={"service": "steam"})
        for db_game in db_games:
            db_appids[db_game["service_id"]].append(db_game["id"])

        for appid in db_appids:
            game_ids = db_appids[appid]
            if len(game_ids) == 1:
                continue
            for game_id in game_ids:
                steam_game = Game(game_id)
                if not steam_game.playtime:
                    steam_game.remove(no_signal=True)
                    steam_game.delete()
Exemple #24
0
    def on_add_manually(self, _widget, *_args):
        """Callback that presents the Add game dialog"""
        def on_game_added(game):
            self.view.set_installed(game)
            GLib.idle_add(resources.fetch_icon, game.slug,
                          self.on_image_downloaded)
            self.sidebar_listbox.update()

        game = Game(self.view.selected_game)
        AddGameDialog(
            self,
            game=game,
            runner=self.selected_runner,
            callback=lambda: on_game_added(game),
        )
Exemple #25
0
def scan_directory(dirname):
    files = os.listdir(dirname)
    folder_extentions = {os.path.splitext(filename)[1] for filename in files}
    core_matches = {}
    for core in RECOMMENDED_CORES:
        for ext in RECOMMENDED_CORES[core].get("extensions", []):
            if ext in folder_extentions:
                core_matches[ext] = core
    added_games = []
    for filename in files:
        name, ext = os.path.splitext(filename)
        if ext not in core_matches:
            continue
        for flag in ROM_FLAGS:
            name = name.replace(" (%s)" % flag, "")
        for flag in EXTRA_FLAGS:
            name = name.replace("[%s]" % flag, "")
        if ", The" in name:
            name = "The %s" % name.replace(", The", "")
        name = name.strip()
        print("Importing '%s'" % name)
        slug = slugify(name)
        core = core_matches[ext]
        config = {
            "game": {
                "core": core_matches[ext],
                "main_file": os.path.join(dirname, filename)
            }
        }
        installer_slug = "%s-libretro-%s" % (slug, core)
        existing_game = get_games(filters={
            "installer_slug": installer_slug,
            "installed": "1"
        })
        if existing_game:
            game = Game(existing_game[0]["id"])
            game.remove()
        configpath = write_game_config(slug, config)
        game_id = add_game(name=name,
                           runner="libretro",
                           slug=slug,
                           directory=dirname,
                           installed=1,
                           installer_slug=installer_slug,
                           configpath=configpath)
        print("Imported %s" % name)
        added_games.append(game_id)
    return added_games
def migrate():
    pcsxr_game_ids = sql.db_query(PGA_DB,
                                  "select id from games where runner='pcsxr'")
    for game_id in pcsxr_game_ids:
        game = Game(game_id["id"])
        main_file = game.config.raw_game_config.get("iso")
        game.config.game_level = {
            "game": {
                "core": "pcsx_rearmed",
                "main_file": main_file
            }
        }
        game.config.save()
    sql.db_update(PGA_DB,
                  "games", {"runner": "libretro"},
                  where=("runner", "pcsxr"))
Exemple #27
0
def migrate():
    pcsxr_game_ids = sql.db_query(PGA_DB,
                                  "select id from games where runner='pcsxr'")
    for game_id in pcsxr_game_ids:
        game = Game(game_id['id'])
        main_file = game.config.raw_game_config.get('iso')
        game.config.game_level = {
            'game': {
                'core': 'pcsx_rearmed',
                'main_file': main_file
            }
        }
        game.config.save()
    sql.db_update(PGA_DB,
                  'games', {'runner': 'libretro'},
                  where=('runner', 'pcsxr'))
Exemple #28
0
 def launch_service_game(self, runner, installer_slug):
     """For services that allow it, add the game to Lutris and launch it"""
     config_id = self.game_slug + "-" + self.service.id
     game_id = add_or_update(
         name=self.game_name,
         runner=runner,
         slug=self.game_slug,
         installed=1,
         configpath=config_id,
         installer_slug=installer_slug,
         service=self.service.id,
         service_id=self.db_game["appid"],
     )
     self.service.create_config(self.db_game, config_id)
     game = Game(game_id)
     game.emit("game-launch")
Exemple #29
0
 def on_game_run(self, *_args, game_id=None):
     """Launch a game, or install it if it is not"""
     if not game_id:
         game_id = self._get_current_game_id()
     if not game_id:
         return None
     self.running_game = Game(game_id)
     if self.running_game.is_installed:
         self.running_game.play()
     else:
         game_slug = self.running_game.slug
         logger.warning("%s is not available", game_slug)
         self.running_game = None
         InstallerWindow(game_slug=game_slug,
                         parent=self,
                         application=self.application)
Exemple #30
0
 def _build_game_tab(self):
     if self.game and self.runner_name:
         self.game.runner_name = self.runner_name
         try:
             self.game.runner = runners.import_runner(self.runner_name)
         except runners.InvalidRunner:
             pass
         self.game_box = GameBox(self.lutris_config, self.game)
         game_sw = self.build_scrolled_window(self.game_box)
     elif self.runner_name:
         game = Game(None)
         game.runner_name = self.runner_name
         self.game_box = GameBox(self.lutris_config, game)
         game_sw = self.build_scrolled_window(self.game_box)
     else:
         game_sw = Gtk.Label(label=self.no_runner_label)
     self._add_notebook_tab(game_sw, "Game options")