mtkennerly / ludusavi-playnite

Playnite plugin for save backups via Ludusavi
MIT License
141 stars 9 forks source link

Why do certain games show saved backups but others not? #69

Closed darklinkpower closed 3 weeks ago

darklinkpower commented 2 months ago

Hi, just wondering about this. For a reason unknown to me, most games do show backed up items in the context menu correctly, e.g. Persona 5 Royal:

image

But others, like Nier: Automata do not show backed up items:

image

Saves are being backed up without issues on game close:

image

Another example is Resident Evil 2:

image

mtkennerly commented 2 months ago

This is because of name mismatches like Nier: Automata vs NieR: Automata.

When performing backups/restores, the plugin uses the ludusavi find command to normalize names, but it doesn't do that for the backup list. I tried experimenting with using find when opening the context menu, but it adds a delay of about 1 second, which isn't great. Maybe I could add a long-running background task that runs find pre-emptively, or maybe Ludusavi should have a bulk version of find.

For now, if you set "look up with another title" to the normalized title, then it'll list the backups.

darklinkpower commented 2 months ago

I see, that makes sense.I briefly checked the source code and from what I understand Ludusavi Playnite performs a backup list check and caches it to a dictionary. As far as I know, Ludusavi manifest obtains stores Ids already that could be used to match too.

This gives me the idea of separating the backups handling to an specific class that would also support obtaining backups by id by cache'ing the storeIds

public class BackupsManager
{
    private Dictionary<string, List<ApiBackup>> gameNameDictionary;
    private Dictionary<string, string> steamIdToNameDictionary;

    public void RefreshLudusaviBackups()
    {
        // Refresh gameNameDictionary
        // steamIdToNameDictionary is updated with the steam id as key and the name used in gameNameDictionary as a value
    }

    private List<ApiBackup> GetBackups(string gameName)
    {
        // Do what is already being done
    }

    private List<ApiBackup> GetBackupsBySteamId(string steamId)
    {
        if (steamIdToNameDictionary.TryGetValue(steamId, out var gameName))
        {
            return GetBackups(gameName);
        }

        return somethingsomething;
    }

    public string GetGameBackups(Game game)
    {
        if (gameNameDictionary.ContainsKey(storeId))
        {
            return gameNameDictionary[storeId];
        }
        else if (game.PluginId == steamPluginId)
        {
            return GetBackupsBySteamId(game.Id)
        }
    }

    ....
}

In this implementation, steamIdToNameDictionary contains the store Id as a key, and their values will be the key name to be used in gameNameDictionary to obtain the real backups. Other stores could be handled the same way. To obtain backups, GetGameBackups would be called with the game as the parameter.

In my opinion this approach could work, while making it more extensible in the future but without knowing how Ludusavi itself works I don't know if it's feasible. Separating backup concerns from the main plugin class is also in my opinion an added benefit.

mtkennerly commented 2 months ago

In my opinion this approach could work, while making it more extensible in the future but without knowing how Ludusavi itself works I don't know if it's feasible.

It could definitely work, but I'd like to keep the ID/normalization checks in Ludusavi for consistency and reuse. I think I'll explore adding a bulk equivalent of the find command, which would be much faster than the individual calls.

Separating backup concerns from the main plugin class is also in my opinion an added benefit.

Yeah, it could definitely use some cleanup. I'll look into that.

mtkennerly commented 3 weeks ago

This will be fixed once Ludusavi 0.24.0 comes out. It will include an api command that supports bulk title queries.