async def launch_game(self, game_id): if sys.platform != 'win32': log.error(f"Incompatible platform {sys.platform}") return if not self.local_client.is_installed(): await self._open_betty_browser() return for product in self.products_cache: if self.products_cache[product]['local_id'] == game_id: if not self.products_cache[product]['installed']: if not self.local_client.betty_client_process: log.warning( "Got launch on a not installed game, installing") return await self.install_game(game_id) else: if not self.local_client.betty_client_process: self.launching_lock = time.time() + 45 else: self.launching_lock = time.time() + 30 self.running_games[game_id] = None self.update_local_game_status( LocalGame( game_id, LocalGameState.Installed | LocalGameState.Running)) self.update_game_running_status_task.cancel() cmd = f"start bethesdanet://run/{game_id}" log.info(f"Calling launch command for id {game_id}, {cmd}") subprocess.Popen(cmd, shell=True)
def test_local_game_running_state_notification( plugin_mock, prev_last_played: str, refr_last_played: str, new_state: Optional[LocalGameState]): # patch side-effects plugin_mock._notify_about_game_stop = Mock() plugin_mock.create_task = Mock() plugin_mock.update_local_game_status = Mock() GAME_ID = 's1' previous_games = { GAME_ID: Mock(InstalledGame, has_galaxy_installed_state=True, last_played=prev_last_played) } refreshed_games = { GAME_ID: Mock(InstalledGame, has_galaxy_installed_state=True, last_played=refr_last_played) } plugin_mock._update_statuses(refreshed_games, previous_games) if new_state is None: plugin_mock.update_local_game_status.assert_not_called() else: local_game = LocalGame(GAME_ID, new_state) plugin_mock.update_local_game_status.assert_called_once_with( local_game)
async def launch_game(self, game_id): if os.path.isfile(self.playlist_path): with open(self.playlist_path) as playlist_json: playlist_dict = json.load(playlist_json) for entry in playlist_dict["items"]: if game_id == entry["label"]: self.update_local_game_status(LocalGame(game_id, 2)) self.game_run = entry["label"] if user_config.core == 1: self.proc = subprocess.Popen( os.path.abspath( user_config.emu_path + "retroarch.exe" + " -L \"" + user_config.emu_path + "cores/pcsx_rearmed_libretro.dll\" \"" + entry["path"])) if user_config.core == 2: self.proc = subprocess.Popen( os.path.abspath(user_config.emu_path + "retroarch.exe" + " -L \"" + user_config.emu_path + "cores/mednafen_psx_libretro\" \"" + entry["path"])) if user_config.core == 3: self.proc = subprocess.Popen( os.path.abspath( user_config.emu_path + "retroarch.exe" + " -L \"" + user_config.emu_path + "cores/mednafen_psx_hw_libretro.dll\" \"" + entry["path"])) break
async def get_local_games(self): if self._local_provider.first_run: self._local_provider.setup() return [ LocalGame(app_name, state) for app_name, state in self._local_provider.games.items() ]
async def get_local_games(self): if not self.game_cache: self.update_game_cache() local_game_list = [] for game_entry in self.game_cache: local_game_list.append(LocalGame(game_entry.game_id, 1)) return local_game_list
def _light_installation_status_check(self): changed = False for local_game in self.local_client.local_games_cache: local_game_installed = self.local_client.is_local_game_installed(self.local_client.local_games_cache[local_game]) if local_game_installed and not self.products_cache[local_game]["installed"]: self.products_cache[local_game]["installed"] = True self.update_local_game_status(LocalGame(self.local_client.local_games_cache[local_game]['local_id'], LocalGameState.Installed)) changed = True elif not local_game_installed and self.products_cache[local_game]["installed"]: self.products_cache[local_game]["installed"] = False self.update_local_game_status(LocalGame(self.local_client.local_games_cache[local_game]['local_id'], LocalGameState.None_)) changed = True return changed
async def state_changed(self, old_dict, new_dict): # state changed for my_id in new_dict.keys() & old_dict.keys(): if new_dict[my_id] != old_dict[my_id]: logging.debug("changed") self.backend.my_queue_update_local_game_status.put( LocalGame(my_id, new_dict[my_id]))
async def get_local_games(self) -> List[LocalGame]: state = LocalGameState.None_ if self._local.is_installed: state |= LocalGameState.Installed if self._local.is_running: state |= LocalGameState.Running return [LocalGame(OSU, state)]
def get_local_games_from_manifests(manifests): local_games = [] running_processes = [exe for pid, exe in process_iter() if exe is not None] def is_game_running(game_folder_name): for exe in running_processes: if game_folder_name in exe: return True return False for manifest in manifests: state = LocalGameState.None_ game_state = read_state(manifest) if OriginGameState.Installed in game_state \ or OriginGameState.Playable in game_state: state |= LocalGameState.Installed if manifest.dipinstallpath and is_game_running( manifest.dipinstallpath): state |= LocalGameState.Running local_games.append(LocalGame(manifest.game_id, state)) return local_games
def update(game_id, status: LocalGameState): if self.status[game_id] != status: self.status[game_id] = status self.update_local_game_status(LocalGame(game_id, status)) log.info(f"Updated {game_id} to {status}") return True # return true if needed to update return False
def test_local_game_installation_state_notification( plugin_mock, prev: Optional[BlizzardGameState], refr: Optional[BlizzardGameState], new_state: Optional[LocalGameState]): def installed_game(playable: bool, installed: bool): with patch('local_games.pathfinder'): last_played = '' # to not affect the logic for running game detection return InstalledGame(Mock(Blizzard), Mock(str), Mock(str), last_played, Mock(str), playable=playable, installed=installed) plugin_mock.update_local_game_status = Mock() GAME_ID = 's1' previous_games = { GAME_ID: installed_game(prev.playable, prev.installed) } if prev else {} refreshed_games = { GAME_ID: installed_game(refr.playable, refr.installed) } if refr else {} plugin_mock._update_statuses(refreshed_games, previous_games) if new_state is None: plugin_mock.update_local_game_status.assert_not_called() else: local_game = LocalGame(GAME_ID, new_state) plugin_mock.update_local_game_status.assert_called_once_with( local_game)
async def get_local_games(self): games_path = self.local_client.games_path if not games_path: self.local_games_called = True return [] local_games = os.listdir(games_path) games_to_send = [] local_games_cache = {} for local_game in local_games: game_folder = os.path.join(games_path, local_game) game_cpatch = os.path.join(game_folder, '.cpatch', local_game) try: with open(os.path.join(game_cpatch, 'version')) as game_cp: version = game_cp.readline() with open(os.path.join(game_cpatch, 'repository.json'), 'r') as js: game_repository = json.load(js) exe_path = game_repository['content']['versions'][version][ 'exePath'] except FileNotFoundError: continue except Exception as e: log.error( f"Unable to parse local game {local_game} {repr(e)}") continue local_games_cache[local_game] = os.path.join( game_folder, exe_path) games_to_send.append( LocalGame(local_game, LocalGameState.Installed)) self.local_games_cache = local_games_cache self.local_games_called = True return games_to_send
def get_local_games_from_manifests(manifests): local_games = [] running_processes = [exe for pid, exe in process_iter() if exe is not None] def is_game_running(game_folder_name): for exe in running_processes: if game_folder_name in exe: return True return False for manifest in manifests: state = LocalGameState.None_ if ((manifest.state == _State.kReadyToStart and manifest.prev_state == _State.kCompleted) or manifest.ddinstallalreadycompleted == "1"): state |= LocalGameState.Installed if manifest.dipinstallpath and is_game_running(manifest.dipinstallpath): state |= LocalGameState.Running local_games.append(LocalGame(manifest.game_id, state)) return local_games
async def get_local_games(self): timeout = time.time() + 2 try: translated_installed_games = [] while not self.local_client.games_finished_parsing(): await asyncio.sleep(0.1) if time.time() >= timeout: break running_games = self.local_client.get_running_games() installed_games = self.local_client.get_installed_games() log.info(f"Installed games {installed_games.items()}") log.info(f"Running games {running_games}") for uid, game in installed_games.items(): if game.has_galaxy_installed_state: state = LocalGameState.Installed if uid in running_games: state |= LocalGameState.Running translated_installed_games.append(LocalGame(uid, state)) self.local_client.installed_games_cache = installed_games return translated_installed_games except Exception as e: log.exception(f"failed to get local games: {str(e)}") raise
async def uninstall_game(self, game_id): if not self.authentication_client.is_authenticated(): raise AuthenticationRequired() if game_id == 'wow_classic': # attempting to uninstall classic wow through protocol gives you a message that the game cannot # be uninstalled through protocol and you should use battle.net return self._open_battlenet_at_id(game_id) if SYSTEM == pf.MACOS: self._open_battlenet_at_id(game_id) else: try: installed_game = self.local_client.get_installed_games().get( game_id, None) if installed_game is None or not os.access( installed_game.install_path, os.F_OK): log.error(f'Cannot uninstall {game_id}') self.update_local_game_status( LocalGame(game_id, LocalGameState.None_)) return if not isinstance(installed_game.info, ClassicGame): if self.local_client.uninstaller is None: raise FileNotFoundError('Uninstaller not found') uninstall_tag = installed_game.uninstall_tag client_lang = self.local_client.config_parser.locale_language self.local_client.uninstaller.uninstall_game( installed_game, uninstall_tag, client_lang) except Exception as e: log.exception(f'Uninstalling game {game_id} failed: {e}')
def test_plugin_game_installed(tmpdir, plugin): mfst_file = tmpdir.mkdir("GameName1").join("gameid.mfst") mfst_file.write("?currentstate=kReadyToStart&id=OFB-EAST%3a48217&previousstate=kCompleted") loop = asyncio.get_event_loop() result = loop.run_until_complete(plugin.get_local_games()) assert result == [LocalGame("OFB-EAST:48217", LocalGameState.Installed)]
def local_games_list(self): local_games = [] for game in self.games: if os.path.exists(game[0]): local_games.append( LocalGame(str(game[1]), LocalGameState.Installed)) return local_games
async def get_local_games(self) -> List[Optional[LocalGame]]: local_games = [] for game in self.repo_metadata.values(): local_game = LocalGame( game_id=game.game_id, local_game_state=game.get_installation_status()) local_games.append(local_game) return local_games
async def get_local_games(self) -> List[LocalGame]: # all available games are installed, so we convert the Game list to a LocalGame list games = await self.get_games() local_games = [] for game in games: local_games.append(LocalGame(game_id=game.game_id, local_game_state=LocalGameState.Installed)) return local_games
def tick(self): if not self._install_path: self._install_path = self._get_install_path() current_game_state = self._get_game_state() if self._game_state != current_game_state: self._game_state = current_game_state self.update_local_game_status(LocalGame(self._GAME_ID, self._game_state))
def get_state_changes(old_list, new_list): old_dict = {x.game_id: x.local_game_state for x in old_list} new_dict = {x.game_id: x.local_game_state for x in new_list} result = [] # removed games result.extend( LocalGame(id, LocalGameState.None_) for id in old_dict.keys() - new_dict.keys()) # added games result.extend(local_game for local_game in new_list if local_game.game_id in new_dict.keys() - old_dict.keys()) # state changed result.extend( LocalGame(id, new_dict[id]) for id in new_dict.keys() & old_dict.keys() if new_dict[id] != old_dict[id]) return result
async def get_local_games(self): self._game_instances = gw2.gw2_localgame.get_game_instances() if len(self._game_instances) == 0: self._last_state = LocalGameState.None_ return [] self._last_state = LocalGameState.Installed return [ LocalGame(game_id=self.GAME_ID, local_game_state = self._last_state) ]
async def launch_game(self, game_id): try: game = self.local_client.get_installed_games().get(game_id, None) if game is None: log.error(f'Launching game that is not installed: {game_id}') return await self.install_game(game_id) if isinstance(game.info, ClassicGame): log.info( f'Launching game of id: {game_id}, {game} at path {os.path.join(game.install_path, game.info.exe)}' ) if SYSTEM == pf.WINDOWS: subprocess.Popen( os.path.join(game.install_path, game.info.exe)) elif SYSTEM == pf.MACOS: if not game.info.bundle_id: log.warning( f"{game.name} has no bundle id, help by providing us bundle id of this game" ) subprocess.Popen(['open', '-b', game.info.bundle_id]) self.update_local_game_status( LocalGame( game_id, LocalGameState.Installed | LocalGameState.Running)) asyncio.create_task(self._notify_about_game_stop(game, 6)) return self.local_client.refresh() log.info(f'Launching game of id: {game_id}, {game}') await self.local_client.launch_game(game, wait_sec=60) self.update_local_game_status( LocalGame(game_id, LocalGameState.Installed | LocalGameState.Running)) self.local_client.close_window() asyncio.create_task(self._notify_about_game_stop(game, 3)) except ClientNotInstalledError as e: log.warning(e) await self.open_battlenet_browser() except TimeoutError as e: log.warning(str(e)) except Exception as e: log.exception(f"Launching game {game_id} failed: {e}")
async def get_local_games(self): log.info("Getting local games") local_games = [] for game_id in GAME_IDS: if self.local_client.game_installed(game_id): local_game = LocalGame(game_id, LocalGameState.Installed) local_games.append(local_game) log.debug(f"RIOT_INSTALLED_GAMES: {local_games}") return local_games
async def get_local_games(self) -> List[LocalGame]: self.__rescan_games(False) result = list() for id, state in self.__local_games_states.items(): result.append(LocalGame(id, state)) self.__localgames_imported = True return result
async def get_local_games(self) -> List[LocalGame]: # await self.ensure_discord_scraped() local_games = [] for game in self.games: local_games.append( LocalGame(game_id=game.game_id, local_game_state=LocalGameState.Installed)) return local_games
def test_notify_removed(local_games_object, tmpdir): mfst_file = tmpdir.mkdir("GameName1").join("gameid.mfst") mfst_file.write("?currentstate=kReadyToStart&id=OFB-EAST%3a48217&previousstate=kCompleted") local_games_object.update() mfst_file.remove() games, changed = local_games_object.update() assert games == [] assert changed == [LocalGame("OFB-EAST:48217", LocalGameState.None_)]
def test_installing(local_games_object, tmpdir, game_id_raw, game_id_expected): mfst_file = tmpdir.mkdir("GameName").join("gameid.mfst") mfst_file.write(f"?currentstate=kInstalling&id={game_id_raw}&previousstate=kPostTransfer&ddinitialdownload=1") expected = [LocalGame(game_id_expected, LocalGameState.None_)] games, changed = local_games_object.update() assert games == expected assert changed == expected
def local_games_list(self): local_games = [] for game in self.games: local_games.append(LocalGame( game[0], LocalGameState.Installed)) return local_games
def __rescan_wgc(self): self._games_local.clear() self._wgc_games = self._wgc.get_local_applications() for id, game in self._wgc_games.items(): local_game_state = LocalGameState.Running if game.IsRunning( ) else LocalGameState.Installed self._games_local[id] = LocalGame(id, local_game_state)