Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Upgradable Games #2596

Open
wants to merge 48 commits into
base: main
Choose a base branch
from
Open

Upgradable Games #2596

wants to merge 48 commits into from

Conversation

halgari
Copy link
Collaborator

@halgari halgari commented Feb 4, 2025

This PR does the following:

  • Adds LocatorIDs onto each loadout. These are opaque strings that each game locator (for Stem, Gog, etc. ) can use to tie back to a game build of some sort
  • Adds methods for getting game files, human-friendly version numbers, etc. from the LocatorIDs
  • Removes the Game Files mod from the loadouts instead these files are injected into the synchronizer before it starts processing the diffs
  • Rewrites most of ALoadoutSynchronizer to use massively less memory allocation, and to support injecting game files
  • Adds CLI commands for changing the game versions on a loadout
  • Adds diagnostics for files that are not backed up, and that are not deployable
  • Adds support for Stardew Valley and Steam/Gog. For other games we'll need to add in the version mappings

Known limitations:

  • No way to back up game files currently. This will be added next in a CLI command and later into the UI
  • No way to use Steam/GOG as a data source for files. This feature may wait until next sprint
  • Version numbers in the loadout creation screen are stubbed out. They don't make sense there so much now that we can technically create a loadout for any game version
  • There's no migration routine yet for updating old loadouts to this new format. It's trivial to write, but not part of this PR.
  • The Preview changes dialog isn't updating. I'm not sure why, I'm sure it's simple, but it's late here and I'm not going to figure out tonight. I plan on fixing this issue before merging this PR.

@halgari halgari requested a review from a team February 4, 2025 04:39
@halgari halgari marked this pull request as ready for review February 4, 2025 04:43
@Al12rs Al12rs self-requested a review February 4, 2025 09:01
Copy link
Contributor

@Al12rs Al12rs left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Partial review

@halgari
Copy link
Collaborator Author

halgari commented Feb 4, 2025

Also implemented the backup files command in this PR.

@halgari halgari requested a review from Al12rs February 4, 2025 22:19
Copy link
Contributor

@Al12rs Al12rs Feb 5, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

GetOrCreateInitialDiskState() is unused, so are IndexNewState() and HashGameFile(), are there plans for them or should we remove them?

{
// Make sure the file hashes are up to date
await _fileHashService.GetFileHashesDb();
return await ReindexState(gameInstallation, Connection);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ReindexState() is the only thing that actually is indexing game files from what I can tell now, and it isn't using the minimal hash stuff. So from what I can tell we aren't using minimal hashes anywhere at the moment.

Is the plan still to use them? If so in which situation?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed the dead code

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These tests have the concept of initial state, which we don't have anymore.
They were supposed to have "bin/originalGameFile.txt" as part of the initial state, but now it is just getting discarded on loadout creation.

We talked yesterday that we should put any unrecognized files into Overrides on initial management of the game. With that we could have these tests make behave more like they were supposed to.

Do you want to implement putting unrecognized files in override on game manage as a separate PR or as part of this one?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above, also counts for GeneralFileManagementTests

Copy link
Contributor

@Al12rs Al12rs left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried doing some basic tests with a Stardew installation:
Adding a new file in the game folder causes Apply to fail due to exception:

Steps:

  • Manage clean SDV game
  • Close app
  • Add a new text file in the game folder (I used test/newfile.txt)
  • Open the app (this will run an ingest on startup)
  • Open preview and notice the new file is marked as something to be removed
  • Which shouldn't be correct
  • Attempt to apply -> get exception:
System.ArgumentException: An item with the same key has already been added. Key: {Game}/test/newfile.txt
   at System.Collections.Generic.Dictionary`2.TryInsert(TKey key, TValue value, InsertionBehavior behavior)
   at System.Collections.Generic.Dictionary`2.Add(TKey key, TValue value)
   at System.Linq.Enumerable.ToDictionary[TSource,TKey](IEnumerable`1 source, Func`2 keySelector, IEqualityComparer`1 comparer)
   at System.Linq.Enumerable.ToDictionary[TSource,TKey](IEnumerable`1 source, Func`2 keySelector)
   at NexusMods.Abstractions.Loadouts.Synchronizers.ALoadoutSynchronizer.ReindexState(GameInstallation installation, IConnection connection, ITransaction tx) in C:\Dev\Repos\NexusMods.App\src\Abstractions\NexusMods.Abstractions.Loadouts.Synchronizers\ALoadoutSynchronizer.cs:line 985
   at NexusMods.Abstractions.Loadouts.Synchronizers.ALoadoutSynchronizer.ReindexState(GameInstallation installation, IConnection connection) in C:\Dev\Repos\NexusMods.App\src\Abstractions\NexusMods.Abstractions.Loadouts.Synchronizers\ALoadoutSynchronizer.cs:line 961
   at NexusMods.Abstractions.Loadouts.Synchronizers.ALoadoutSynchronizer.BuildSyncTree(ReadOnly loadout) in C:\Dev\Repos\NexusMods.App\src\Abstractions\NexusMods.Abstractions.Loadouts.Synchronizers\ALoadoutSynchronizer.cs:line 355
   at NexusMods.Abstractions.Loadouts.Synchronizers.ALoadoutSynchronizer.Synchronize(ReadOnly loadout) in C:\Dev\Repos\NexusMods.App\src\Abstractions\NexusMods.Abstractions.Loadouts.Synchronizers\ALoadoutSynchronizer.cs:line 762
   at NexusMods.DataModel.Synchronizer.SynchronizerService.Synchronize(LoadoutId loadoutId) in C:\Dev\Repos\NexusMods.App\src\NexusMods.DataModel\Synchronizer\SynchronizerService.cs:line 66
   at NexusMods.App.UI.LeftMenu.Items.ApplyControlViewModel.<Apply>b__28_0() in C:\Dev\Repos\NexusMods.App\src\NexusMods.App.UI\LeftMenu\Items\ApplyControl\ApplyControlViewModel.cs:line 115
   at NexusMods.App.UI.LeftMenu.Items.ApplyControlViewModel.Apply() in C:\Dev\Repos\NexusMods.App\src\NexusMods.App.UI\LeftMenu\Items\ApplyControl\ApplyControlViewModel.cs:line 113
   at NexusMods.App.UI.LeftMenu.Items.ApplyControlViewModel.<>c__DisplayClass27_0.<<-ctor>b__0>d.MoveNext() in C:\Dev\Repos\NexusMods.App\src\NexusMods.App.UI\LeftMenu\Items\ApplyControl\ApplyControlViewModel.cs:line 55

EDIT:
I just tested and starting with a completely clean SDV, you are asked to Apply when you create the first loadout, which is a regression. Applying caused a bunch of exceptions, but here the Apply button then got hidden.

A lot of exceptions from NoWayToSourceFilesOnDisk diagnostic going through the synchronizer:

System.ArgumentException: An item with the same key has already been added. Key: {Game}/api-ms-win-core-console-l1-1-0.dll
   at System.Collections.Generic.Dictionary`2.TryInsert(TKey key, TValue value, InsertionBehavior behavior)
   at System.Collections.Generic.Dictionary`2.Add(TKey key, TValue value)
   at System.Linq.Enumerable.ToDictionary[TSource,TKey](IEnumerable`1 source, Func`2 keySelector, IEqualityComparer`1 comparer)
   at System.Linq.Enumerable.ToDictionary[TSource,TKey](IEnumerable`1 source, Func`2 keySelector)
   at NexusMods.Abstractions.Loadouts.Synchronizers.ALoadoutSynchronizer.ReindexState(GameInstallation installation, IConnection connection, ITransaction tx) in C:\Dev\Repos\NexusMods.App\src\Abstractions\NexusMods.Abstractions.Loadouts.Synchronizers\ALoadoutSynchronizer.cs:line 985
   at NexusMods.Abstractions.Loadouts.Synchronizers.ALoadoutSynchronizer.ReindexState(GameInstallation installation, IConnection connection) in C:\Dev\Repos\NexusMods.App\src\Abstractions\NexusMods.Abstractions.Loadouts.Synchronizers\ALoadoutSynchronizer.cs:line 961
   at NexusMods.Abstractions.Loadouts.Synchronizers.ALoadoutSynchronizer.BuildSyncTree(ReadOnly loadout) in C:\Dev\Repos\NexusMods.App\src\Abstractions\NexusMods.Abstractions.Loadouts.Synchronizers\ALoadoutSynchronizer.cs:line 355
   at NexusMods.Games.FileHashes.Emitters.NoWayToSourceFilesOnDisk.Diagnose(ReadOnly loadout, CancellationToken cancellationToken)+MoveNext() in C:\Dev\Repos\NexusMods.App\src\NexusMods.Games.FileHashes\Emitters\NoWayToSourceFilesOnDisk.cs:line 16
   at NexusMods.Games.FileHashes.Emitters.NoWayToSourceFilesOnDisk.Diagnose(ReadOnly loadout, CancellationToken cancellationToken)+System.Threading.Tasks.Sources.IValueTaskSource<System.Boolean>.GetResult()
   at NexusMods.DataModel.Diagnostics.DiagnosticManager.<>c__DisplayClass8_1.<<GetLoadoutDiagnostics>b__0>d.MoveNext() in C:\Dev\Repos\NexusMods.App\src\NexusMods.DataModel\Diagnostics\DiagnosticManager.cs:line 92
--- End of stack trace from previous location ---
   at NexusMods.DataModel.Diagnostics.DiagnosticManager.<>c__DisplayClass8_1.<<GetLoadoutDiagnostics>b__0>d.MoveNext() in C:\Dev\Repos\NexusMods.App\src\NexusMods.DataModel\Diagnostics\DiagnosticManager.cs:line 92

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants