class RPCS3Plugin(Plugin):
    def __init__(self, reader, writer, token):
        super().__init__(Platform.ColecoVision, get_version(), reader, writer, token)
        try:
            self.config = Config() # If we can't create a good config, we can't run the plugin.
        except FileNotFoundError:
            self.close()
        else:
            self.backend_client = BackendClient(self.config)
            self.games = []
            self.local_games_cache = self.local_games_list()
            self.process = None
            self.running_game_id = None


    async def authenticate(self, stored_credentials=None):
        return self.do_auth()


    async def pass_login_credentials(self, step, credentials, cookies):
        return self.do_auth()


    def do_auth(self):

        username = ''
        with open(self.config.localusername, 'r') as username_file:
            username = username_file.read()

        user_data = {}
        user_data['username'] = username
        self.store_credentials(user_data)
        return Authentication('rpcs3_user', user_data['username'])


    async def launch_game(self, game_id):

        args = []
        eboot_bin = self.config.joinpath(
            self.backend_client.get_game_path(game_id),
            'USRDIR', 
            'EBOOT.BIN')

        if self.config.no_gui:
            args.append('--no-gui')

        command = [self.config.rpcs3_exe, eboot_bin] + args
        self.process = subprocess.Popen(command)
        self.backend_client.start_game_time()
        self.running_game_id = game_id

        return


    # Only as placeholders so the feature is recognized
    async def install_game(self, game_id):
        pass

    async def uninstall_game(self, game_id):
        pass


    async def prepare_game_times_context(self, game_ids):
        return self.get_game_times(game_ids)


    async def prepare_achievements_context(self, game_ids):
        return self.get_trophy_achs()


    async def get_game_time(self, game_id, context):
        game_time = context.get(game_id)
        return game_time


    async def get_unlocked_achievements(self, game_id, context):
        achs = context.get(game_id)
        return achs    


    def get_game_times(self, game_ids):

        # Get the path of the game times file.
        base_path = os.path.dirname(os.path.realpath(__file__))
        game_times_path = os.path.join(base_path, 'game_times.json')
        game_times = {}

        # If the file does not exist, create it with default values.
        if not os.path.exists(game_times_path):
            for game in self.games:

                game_id = str(game[0])
                game_times[game_id] = GameTime(game_id, 0, None)

            with open(game_times_path, 'w', encoding='utf-8') as game_times_file:
                json.dump(game_times, game_times_file, indent=4)

        # If (when) the file exists, read it and return the game times.  
        with open(game_times_path, 'r', encoding='utf-8') as game_times_file:
            game_times_json = json.load(game_times_file)

            for game_id in game_times_json:
                if game_id in game_ids:
                    time_played = game_times_json.get(game_id).get('time_played')
                    last_time_played = game_times_json.get(game_id).get('last_time_played')

                    game_times[game_id] = GameTime(game_id, time_played, last_time_played)

        return game_times

    def get_trophy_achs(self):

        game_ids = []
        for game in self.games:
            game_ids.append(game[0])

        trophies = None
        all_achs = {}
        for game_id in game_ids:
            game_path = self.backend_client.get_game_path(game_id)

            try:
                trophies = Trophy(self.config, game_path)
                keys = trophies.tropusr.table6.keys()

                game_achs = []
                for key in keys:
                    ach = trophies.trop2ach(key)
                    if ach is not None:
                        game_achs.append(trophies.trop2ach(key))

                all_achs[game_id] = game_achs

            # If tropusr doesn't exist, this game has no trophies.
            except AttributeError:
                all_achs[game_id] = []

        return all_achs


    def tick(self):
        try:
            if self.process.poll() is not None:

                self.backend_client.end_game_time()
                self.update_json_game_time(
                    self.running_game_id,
                    self.backend_client.get_session_duration(),
                    int(time.time()))
    
                # Only update recently played games. Updating all game times every second fills up log way too quickly.
                self.create_task(self.update_galaxy_game_times(self.running_game_id), 'Update Galaxy game times')

                self.process = None
                self.running_game_id = None

        except AttributeError:
            pass

        self.create_task(self.update_local_games(), 'Update local games')
        self.create_task(self.update_achievements(), 'Update achievements')


    async def update_local_games(self):
        loop = asyncio.get_running_loop()

        new_list = await loop.run_in_executor(None, self.local_games_list)
        notify_list = self.backend_client.get_state_changes(self.local_games_cache, new_list)
        self.local_games_cache = new_list
        
        for local_game_notify in notify_list:
            self.update_local_game_status(local_game_notify)


    async def update_galaxy_game_times(self, game_id):

        # Leave time for Galaxy to fetch games before updating times
        await asyncio.sleep(60) 
        loop = asyncio.get_running_loop()

        game_times = await loop.run_in_executor(None, self.get_game_times, [game_id])
        for game_id in game_times:
            self.update_game_time(game_times[game_id])


    async def update_achievements(self):

        # Leave time for Galaxy to fetch games before updating times
        await asyncio.sleep(60) 
        loop = asyncio.get_running_loop()

        achs = await loop.run_in_executor(None, self.get_trophy_achs)
        # for ach in achs:
            # self.unlock_achievement(ach) # TODO - how/when to handle this?


    def update_json_game_time(self, game_id, duration, last_time_played):

        # Get the path of the game times file.
        base_path = os.path.dirname(os.path.realpath(__file__))
        game_times_path = '{}/game_times.json'.format(base_path)
        game_times_json = None

        with open(game_times_path, 'r', encoding='utf-8') as game_times_file:
            game_times_json = json.load(game_times_file)

        old_time_played = game_times_json.get(game_id).get('time_played')
        new_time_played = old_time_played + duration

        game_times_json[game_id]['time_played'] = new_time_played
        game_times_json[game_id]['last_time_played'] = last_time_played

        with open(game_times_path, 'w', encoding='utf-8') as game_times_file:
            json.dump(game_times_json, game_times_file, indent=4)

        self.update_game_time(GameTime(game_id, new_time_played, last_time_played))


    def local_games_list(self):
        local_games = []

        for game in self.games:
            local_games.append(LocalGame(
                game[0],
                LocalGameState.Installed))

        return local_games


    async def get_owned_games(self):
        self.games = self.backend_client.get_games()
        owned_games = []
        
        for game in self.games:
            owned_games.append(Game(
                game[0],
                game[1],
                None,
                LicenseInfo(LicenseType.SinglePurchase, None)))
            
        return owned_games


    async def get_local_games(self):
        return self.local_games_cache
Exemple #2
0
class DolphinPlugin(Plugin):
    def __init__(self, reader, writer, token):
        super().__init__(Platform.NintendoGameCube, __version__, reader,
                         writer, token)
        self.backend_client = BackendClient()
        self.games = []
        self.game_times = get_the_game_times()
        self.local_games_cache = self.local_games_list()

    async def authenticate(self, stored_credentials=None):
        return self.do_auth()

    async def pass_login_credentials(self, step, credentials, cookies):
        return self.do_auth()

    def do_auth(self):
        user_data = {}
        username = user_config.roms_path
        user_data["username"] = username
        self.store_credentials(user_data)
        return Authentication("Dolphin", user_data["username"])

    async def launch_game(self, game_id):
        emu_path = user_config.emu_path
        for game in self.games:
            if str(game[1]) == game_id:
                if user_config.retroarch is not True:
                    subprocess.Popen([emu_path, "-b", "-e", game[0]])
                    subprocess.Popen([
                        os.path.dirname(os.path.realpath(__file__)) +
                        r'\TimeTracker.exe', game_id, game_id
                    ])
                else:
                    subprocess.Popen([
                        user_config.retroarch_executable, "-L",
                        user_config.core_path + r'\dolphin_libretro.dll',
                        game[0]
                    ])
                break
        return

    async def install_game(self, game_id):
        pass

    async def uninstall_game(self, game_id):
        pass

    async def get_game_time(self, game_id, context=None):
        self.game_times = get_the_game_times()
        game_times = self.game_times
        game_time = int(game_times[game_id][0])
        game_time /= 60
        return GameTime(game_id, game_time, game_times[game_id][1])

    def local_games_list(self):
        local_games = []
        for game in self.games:
            local_games.append(
                LocalGame(str(game[1]), LocalGameState.Installed))
        return local_games

    def tick(self):
        async def update_local_games():
            loop = asyncio.get_running_loop()
            new_local_games_list = await loop.run_in_executor(
                None, self.local_games_list)
            notify_list = self.backend_client.get_state_changes(
                self.local_games_cache, new_local_games_list)
            self.local_games_cache = new_local_games_list
            for local_game_notify in notify_list:
                self.update_local_game_status(local_game_notify)

        asyncio.create_task(update_local_games())

    async def get_owned_games(self):
        self.games = self.backend_client.get_games_db()
        owned_games = []

        for game in self.games:
            owned_games.append(
                Game(str(game[1]), game[2], None,
                     LicenseInfo(LicenseType.SinglePurchase, None)))

        return owned_games

    async def get_local_games(self):
        return self.local_games_cache

    def shutdown(self):
        pass
class DolphinPlugin(Plugin):
    def __init__(self, reader, writer, token):
        super().__init__(Platform.NintendoWii, __version__, reader, writer,
                         token)
        self.backend_client = BackendClient()
        self.games = []
        if not os.path.exists(
                os.path.dirname(os.path.realpath(__file__)) +
                r'\gametimes.xml'):
            copyfile(
                os.path.dirname(os.path.realpath(__file__)) +
                r'\files\gametimes.xml',
                os.path.dirname(os.path.realpath(__file__)) +
                r'\gametimes.xml')
        self.game_times = self.get_the_game_times()
        self.local_games_cache = self.local_games_list()
        self.runningGame = self.runningGame = {
            "game_id": "",
            "starting_time": 0,
            "dolphin_running": None,
            "launched": False
        }

    async def authenticate(self, stored_credentials=None):
        return self.do_auth()

    def get_the_game_times(self):
        file = ElementTree.parse(
            os.path.dirname(os.path.realpath(__file__)) + r'\gametimes.xml')
        game_times = {}
        games_xml = file.getroot()
        for game in games_xml.iter('game'):
            game_id = str(game.find('id').text)
            tt = game.find('time').text
            ltp = game.find('lasttimeplayed').text
            game_times[game_id] = [tt, ltp]
        return game_times

    async def pass_login_credentials(self, step, credentials, cookies):
        return self.do_auth()

    def do_auth(self):
        user_data = {}
        username = user_config.roms_path
        user_data["username"] = username
        self.store_credentials(user_data)
        return Authentication("Dolphin", user_data["username"])

    async def launch_game(self, game_id):
        emu_path = user_config.emu_path
        for game in self.games:
            if game.id == game_id:
                if not user_config.retroarch:
                    openDolphin = Popen([emu_path, "-b", "-e", game.path])
                    gameStartingTime = time.time()
                    self.runningGame = {
                        "game_id": game_id,
                        "starting_time": gameStartingTime,
                        "dolphin_running": openDolphin
                    }
                else:
                    Popen([
                        user_config.retroarch_executable, "-L",
                        user_config.core_path + r'\dolphin_libretro.dll',
                        game.path
                    ])
                break
        return

    async def install_game(self, game_id):
        pass

    async def uninstall_game(self, game_id):
        pass

    async def get_game_time(self, game_id, context=None):
        game_times = self.game_times
        game_time = int(game_times[game_id][0])
        game_time /= 60
        return GameTime(game_id, game_time, game_times[game_id][1])

    def local_games_list(self):
        local_games = []
        for game in self.games:
            local_games.append(LocalGame(game.id, LocalGameState.Installed))
        return local_games

    def tick(self):
        async def update_local_games():
            loop = asyncio.get_running_loop()
            new_local_games_list = await loop.run_in_executor(
                None, self.local_games_list)
            notify_list = self.backend_client.get_state_changes(
                self.local_games_cache, new_local_games_list)
            self.local_games_cache = new_local_games_list
            for local_game_notify in notify_list:
                self.update_local_game_status(local_game_notify)

        file = ElementTree.parse(
            os.path.dirname(os.path.realpath(__file__)) + r'\gametimes.xml')
        if self.runningGame["dolphin_running"] is not None:
            if self.runningGame["dolphin_running"].poll() is None:
                self.runningGame["launched"] = True
            if self.runningGame["dolphin_running"].poll() is not None:
                if self.runningGame["launched"]:
                    current_time = round(time.time())
                    runtime = time.time() - self.runningGame["starting_time"]
                    games_xml = file.getroot()
                    for game in games_xml.iter('game'):
                        if str(game.find(
                                'id').text) == self.runningGame["game_id"]:
                            previous_time = int(game.find('time').text)
                            total_time = round(previous_time + runtime)
                            game.find('time').text = str(total_time)
                            game.find('lasttimeplayed').text = str(
                                current_time)
                            self.update_game_time(
                                GameTime(self.runningGame["game_id"],
                                         int(total_time / 60), current_time))
                    file.write(
                        os.path.dirname(os.path.realpath(__file__)) +
                        r'\gametimes.xml')
                    self.runningGame["launched"] = False

        asyncio.create_task(update_local_games())

    async def get_owned_games(self):
        self.games = self.backend_client.get_games_db()
        owned_games = []

        for game in self.games:
            owned_games.append(
                Game(game.id, game.name, None,
                     LicenseInfo(LicenseType.SinglePurchase, None)))
        return owned_games

    async def get_local_games(self):
        return self.local_games_cache

    def shutdown(self):
        pass
class NintendoWiiPlugin(Plugin):
    def __init__(self, reader, writer, token):
        super().__init__(Platform.NintendoWii, __version__, reader, writer, token)
        self.backend_client = BackendClient()
        self.games = []
        self.local_games_cache = self.local_games_list()

        
    async def authenticate(self, stored_credentials=None):
        return self.do_auth()

        
    async def pass_login_credentials(self, step, credentials, cookies):
        return self.do_auth()


    def do_auth(self):
        user_data = {}
        username = user_config.roms_path
        user_data["username"] = username
        self.store_credentials(user_data)
        return Authentication("dolphin_user", user_data["username"])


    async def launch_game(self, game_id):
        emu_path = user_config.emu_path
        
        for game in self.games:
            if str(game[1]) == game_id:
                subprocess.Popen([emu_path, "--exec=" + game[0]])
                break
        return

    async def install_game(self, game_id):
        pass

    async def uninstall_game(self, game_id):
        pass


    def local_games_list(self):
        local_games = []
        for game in self.games:
            local_games.append(
                LocalGame(
                    str(game[1]),
                    LocalGameState.Installed
                )
            )
        return local_games


    def tick(self):

        async def update_local_games():
            loop = asyncio.get_running_loop()
            new_local_games_list = await loop.run_in_executor(None, self.local_games_list)
            notify_list = self.backend_client.get_state_changes(self.local_games_cache, new_local_games_list)
            self.local_games_cache = new_local_games_list
            for local_game_notify in notify_list:
                self.update_local_game_status(local_game_notify)

        asyncio.create_task(update_local_games())


    async def get_owned_games(self):
        self.games = self.backend_client.get_games_gb()
        owned_games = []
        
        for game in self.games:
            owned_games.append(
                Game(
                    str(game[1]),
                    game[2],
                    None,
                    LicenseInfo(LicenseType.SinglePurchase, None)
                )
            )
            
        return owned_games

    async def get_local_games(self):
        return self.local_games_cache
class PlayStation2Plugin(Plugin):
    def __init__(self, reader, writer, token):
        super().__init__(Platform.PlayStation2, __version__, reader, writer, token)
        self.backend_client = BackendClient()
        self.games = []
        self.local_games_cache = self.local_games_list()

        
    async def authenticate(self, stored_credentials=None):
        return self.do_auth()

        
    async def pass_login_credentials(self, step, credentials, cookies):
        return self.do_auth()


    def do_auth(self):
        user_data = {}
        username = user_config.roms_path
        user_data["username"] = username
        self.store_credentials(user_data)
        return Authentication("pcsx2_user", user_data["username"])


    async def launch_game(self, game_id):
        emu_path = user_config.emu_path
        no_gui = user_config.emu_no_gui
        fullscreen = user_config.emu_fullscreen
        config = user_config.emu_config
        config_folder = user_config.config_path

        for game in self.games:
            if str(game[1]) == game_id:
                rom_file = os.path.splitext(os.path.basename(game[0]))[0]
                config_folder_game = config_folder + "/" + rom_file
                if config and os.path.isdir(config_folder_game):
                    config_arg = '--cfgpath=' + config_folder + "/" + rom_file
                    if no_gui and fullscreen:
                        subprocess.Popen([emu_path, "--nogui", "--fullscreen", config_arg, game[0]])
                        break
                    if no_gui and not fullscreen:
                        subprocess.Popen([emu_path, "--nogui", config_arg, game[0]])
                        break
                    if not no_gui and fullscreen:
                        subprocess.Popen([emu_path, "--fullscreen", config_arg, game[0]])
                        break
                    subprocess.Popen([emu_path, config_arg, game[0]])
                    break
                else:
                    if no_gui and fullscreen:
                        subprocess.Popen([emu_path, "--nogui", "--fullscreen", game[0]])
                        break
                    if no_gui and not fullscreen:
                        subprocess.Popen([emu_path, "--nogui", game[0]])
                        break
                    if not no_gui and fullscreen:
                        subprocess.Popen([emu_path, "--fullscreen", game[0]])
                        break
                    subprocess.Popen([emu_path, game[0]])
                    break
        return

    async def install_game(self, game_id):
        pass

    async def uninstall_game(self, game_id):
        pass


    def local_games_list(self):
        local_games = []
        for game in self.games:
            local_games.append(
                LocalGame(
                    str(game[1]),
                    LocalGameState.Installed
                )
            )
        return local_games


    def tick(self):

        async def update_local_games():
            loop = asyncio.get_running_loop()
            new_local_games_list = await loop.run_in_executor(None, self.local_games_list)
            notify_list = self.backend_client.get_state_changes(self.local_games_cache, new_local_games_list)
            self.local_games_cache = new_local_games_list
            for local_game_notify in notify_list:
                self.update_local_game_status(local_game_notify)

        asyncio.create_task(update_local_games())


    async def get_owned_games(self):
        if(user_config.use_database):
            self.games = self.backend_client.get_games_db()
        else:
            self.games = self.backend_client.get_games_gb()
        owned_games = []
        
        for game in self.games:
            owned_games.append(
                Game(
                    str(game[1]),
                    game[2],
                    None,
                    LicenseInfo(LicenseType.SinglePurchase, None)
                )
            )
            
        return owned_games

    async def get_local_games(self):
        return self.local_games_cache

    def shutdown(self):
        pass