WIP: fix(update): an update stays in its build's folder, and a new build's is named after its channel #57

Draft
Victor wants to merge 1 commit from Victor/LongshotLauncher:fix/update-keeps-folder into main
First-time contributor

Every update of a build made a new game folder named after the new version (Games\Longshot\nightly-77-9f64464b), so the game's path changed at each update. A GPU driver's settings for the program stopped applying (MagicBeanDev/Longshot#224: NVIDIA Smooth Motion had to be set again after every update), the settings, mods and shader caches stayed behind in the old folder, and the old folder, a whole copy of the game, stayed on the disk with no row in the list to delete it from.

Why

  • BuildJob gave an update <builds>/<new version>; only a rebuild used its build's folder. BuildRegistry.Replace then moved the row to the new folder, and the README's design decisions said of the old one: "The old folder stays on the disk; nothing deletes it yet."
  • On the nightly channel every merge to Longshot's main is an update, so it happened several times a week.
  • Longshot's README says an update keeps longshot_options.ini, longshot_env.txt and mods. That is true of an update in the same folder, not of one built in a new folder.
  • make_game.py already builds over a game folder: it skips reading a .nup the folder was unpacked from, and it copies the new files in as <name>.new and swaps them only once all are complete, so a build that stops leaves the old game playable (nx2/make_game.py, read from its source, not run here).

What changed

  • Core/BuildRegistry.cs
    • FolderOf: an update or a rebuild is built in its build's own folder; a new build goes in NewFolder.
    • NewFolder: the channel's folder in the builds folder, past the folders other builds have and past anything on the disk that is not a game folder. A game folder no build lists is built in again, as one the player picks already was.
    • PickedFolder: the rule for a folder the player picks in step 2 (a folder that holds other things gets the build's own folder in it), moved here from SettingsStepViewModel so the tests reach it.
    • Replace: when the folder stays, a row named after its version takes the new version's name.
  • Core/LauncherSettings.cs: FolderFor names a new build's folder after its channel (nightly, rc, stable, then nightly (2)), not its version.
  • App/ViewModels/WizardViewModel.cs: BuildJob takes its folder from FolderOf.
  • App/ViewModels/SettingsStepViewModel.cs: ChangeInstallAsync uses PickedFolder. Start does not start a build into a folder that has a game while Longshot runs ("Save and close Longshot first: this replaces the game in its folder."), as Delete already refuses: on Windows make_game.py would build for minutes and stop at its last step, the swap.
  • App/Views/SettingsView.axaml: the hint under Where builds go.
  • Core/Lang/*.json: the 12 full catalogs have the new hint in place of the old one, and the new toast.
  • README.md: the design decision is now "An update stays in its build's folder", with a new one for the folder's name; Planned next says <channel> where it said <version>.
  • tests/launcher_core/ScreenChecks.cs: UpdateFolderChecks (new) and the FolderFor check.

Builds made before this keep the folder they have, named after a version: their next update stays in it. Nothing is renamed or deleted.

For you to decide

  1. The folder's name is a proposal. With updates in place, a version in the name is wrong after the first update, so new builds get their channel's name. Keeping the version's name, or a neutral one, is a one-line change in FolderFor. A build whose channel the player changes later keeps its folder's name.
  2. Planned next has builds in ~/Games/Longshot/versions/<version>. A folder per version would bring back the path change at every update.
  3. Left for follow-ups:
    • Deleting the folders earlier updates left. It could join Settings' Free up space: LauncherService.GatherSaves already finds the game folders in the builds folder that no build lists, and BuildRegistry.DeleteFolder has the checks.
    • Step 2 still wants 45 GB free (Disk.BuildBytes) for an update in its folder, which needs less. Not changed: I have no measurement.
    • The wizard still asks for the game file at an update. make_game.py's --update (BuildSource.Update) builds from the files the folder keeps.
  4. The translations of the two new texts need a native speaker's eye. They were written with the tool that assisted this change, each on its catalog's own wording for "Each version gets its own folder in here." and "Close Longshot first: {0} is not deleted while a game runs.". I can only vouch for the Spanish.

Testing

Linux (Arch), .NET SDK 10.0.100, this branch @ 6e56794 on main @ 01f2797.

  • python3 -I tests/test_launcher_core.py --strict --longshot <Longshot @ 514591a3>: 970 checks passed (main @ 01f2797: 956).
  • With FolderOf giving an update a new folder again, the run stops at "An update or a rebuild is built in its build's own folder, wherever new builds go."
  • python3 -I scripts/translations.py: 522 texts, 15 catalogs, all complete.
  • python3 -I tests/test_release.py: 28 tests, OK.
  • dotnet build LongshotLauncher.slnx: 0 warnings, 0 errors.

Not tested: the launcher's window was not run, and no real build was updated: there is no game dump on this PC. Nothing was run on Windows, and the NVIDIA settings themselves were not checked. No screenshot of the Settings hint.

How to test

Wanted on Windows with an NVIDIA card; on Linux the same steps without the driver's part. WIP until someone has. You need a build on the nightly channel with an update waiting (any nightly but the newest). It is your real build that gets updated.

  1. In the NVIDIA app, add the build's bin\longshot.exe and change one setting for it (Smooth Motion, say).

  2. In the game, change a row in the Insert menu, and put a mod in the game folder's mods. Leave the game running, and close the launcher.

  3. Run this PR's launcher (it needs the .NET 10 SDK). It uses the installed launcher's data, so your builds are listed:

    git clone --depth 1 https://git.magicbean.dev/MagicBeanDev/LongshotLauncher.git
    cd LongshotLauncher
    git fetch --depth 1 origin pull/57/head
    git checkout FETCH_HEAD
    dotnet run --project App
    
  4. Press Update on the build. At step 2, Game folder should be the folder the build already has. With the game still running, Update to … should say "Save and close Longshot first" and start nothing. Close the game, press it again and let the build finish.

  5. Check, and say in a comment here what you saw, with your Windows version, GPU and driver:

    • the game is in the same folder, and no new folder appeared beside it;
    • the NVIDIA app still lists the program with your setting, and it applies in the game;
    • the Insert menu's row and the mod are as you left them;
    • the home shows the new version on the same row.
  6. Optional, a whole build: build another channel's version (stable, say) from the channel picker. Its folder should be named after the channel (stable).

Issue: MagicBeanDev/Longshot#224

Every update of a build made a new game folder named after the new version (`Games\Longshot\nightly-77-9f64464b`), so the game's path changed at each update. A GPU driver's settings for the program stopped applying (https://git.magicbean.dev/MagicBeanDev/Longshot/issues/224: NVIDIA Smooth Motion had to be set again after every update), the settings, mods and shader caches stayed behind in the old folder, and the old folder, a whole copy of the game, stayed on the disk with no row in the list to delete it from. ## Why - `BuildJob` gave an update `<builds>/<new version>`; only a rebuild used its build's folder. `BuildRegistry.Replace` then moved the row to the new folder, and the README's design decisions said of the old one: "The old folder stays on the disk; nothing deletes it yet." - On the nightly channel every merge to Longshot's `main` is an update, so it happened several times a week. - Longshot's README says an update keeps `longshot_options.ini`, `longshot_env.txt` and `mods`. That is true of an update in the same folder, not of one built in a new folder. - make_game.py already builds over a game folder: it skips reading a `.nup` the folder was unpacked from, and it copies the new files in as `<name>.new` and swaps them only once all are complete, so a build that stops leaves the old game playable (`nx2/make_game.py`, read from its source, not run here). ## What changed - `Core/BuildRegistry.cs` - `FolderOf`: an update or a rebuild is built in its build's own folder; a new build goes in `NewFolder`. - `NewFolder`: the channel's folder in the builds folder, past the folders other builds have and past anything on the disk that is not a game folder. A game folder no build lists is built in again, as one the player picks already was. - `PickedFolder`: the rule for a folder the player picks in step 2 (a folder that holds other things gets the build's own folder in it), moved here from `SettingsStepViewModel` so the tests reach it. - `Replace`: when the folder stays, a row named after its version takes the new version's name. - `Core/LauncherSettings.cs`: `FolderFor` names a new build's folder after its channel (`nightly`, `rc`, `stable`, then `nightly (2)`), not its version. - `App/ViewModels/WizardViewModel.cs`: `BuildJob` takes its folder from `FolderOf`. - `App/ViewModels/SettingsStepViewModel.cs`: `ChangeInstallAsync` uses `PickedFolder`. `Start` does not start a build into a folder that has a game while Longshot runs ("Save and close Longshot first: this replaces the game in its folder."), as Delete already refuses: on Windows make_game.py would build for minutes and stop at its last step, the swap. - `App/Views/SettingsView.axaml`: the hint under *Where builds go*. - `Core/Lang/*.json`: the 12 full catalogs have the new hint in place of the old one, and the new toast. - `README.md`: the design decision is now "An update stays in its build's folder", with a new one for the folder's name; *Planned next* says `<channel>` where it said `<version>`. - `tests/launcher_core/ScreenChecks.cs`: `UpdateFolderChecks` (new) and the `FolderFor` check. Builds made before this keep the folder they have, named after a version: their next update stays in it. Nothing is renamed or deleted. ## For you to decide 1. **The folder's name is a proposal.** With updates in place, a version in the name is wrong after the first update, so new builds get their channel's name. Keeping the version's name, or a neutral one, is a one-line change in `FolderFor`. A build whose channel the player changes later keeps its folder's name. 2. **Planned next** has builds in `~/Games/Longshot/versions/<version>`. A folder per version would bring back the path change at every update. 3. **Left for follow-ups:** - Deleting the folders earlier updates left. It could join Settings' *Free up space*: `LauncherService.GatherSaves` already finds the game folders in the builds folder that no build lists, and `BuildRegistry.DeleteFolder` has the checks. - Step 2 still wants 45 GB free (`Disk.BuildBytes`) for an update in its folder, which needs less. Not changed: I have no measurement. - The wizard still asks for the game file at an update. make_game.py's `--update` (`BuildSource.Update`) builds from the files the folder keeps. 4. **The translations of the two new texts need a native speaker's eye.** They were written with the tool that assisted this change, each on its catalog's own wording for "Each version gets its own folder in here." and "Close Longshot first: {0} is not deleted while a game runs.". I can only vouch for the Spanish. ## Testing Linux (Arch), .NET SDK 10.0.100, this branch @ 6e56794 on main @ 01f2797. - `python3 -I tests/test_launcher_core.py --strict --longshot <Longshot @ 514591a3>`: 970 checks passed (main @ 01f2797: 956). - With `FolderOf` giving an update a new folder again, the run stops at "An update or a rebuild is built in its build's own folder, wherever new builds go." - `python3 -I scripts/translations.py`: 522 texts, 15 catalogs, all complete. - `python3 -I tests/test_release.py`: 28 tests, OK. - `dotnet build LongshotLauncher.slnx`: 0 warnings, 0 errors. **Not tested:** the launcher's window was not run, and no real build was updated: there is no game dump on this PC. Nothing was run on Windows, and the NVIDIA settings themselves were not checked. No screenshot of the Settings hint. ## How to test Wanted on Windows with an NVIDIA card; on Linux the same steps without the driver's part. WIP until someone has. You need a build on the nightly channel with an update waiting (any nightly but the newest). It is your real build that gets updated. 1. In the NVIDIA app, add the build's `bin\longshot.exe` and change one setting for it (Smooth Motion, say). 2. In the game, change a row in the Insert menu, and put a mod in the game folder's `mods`. Leave the game running, and close the launcher. 3. Run this PR's launcher (it needs the .NET 10 SDK). It uses the installed launcher's data, so your builds are listed: ``` git clone --depth 1 https://git.magicbean.dev/MagicBeanDev/LongshotLauncher.git cd LongshotLauncher git fetch --depth 1 origin pull/57/head git checkout FETCH_HEAD dotnet run --project App ``` 4. Press **Update** on the build. At step 2, *Game folder* should be the folder the build already has. With the game still running, **Update to …** should say "Save and close Longshot first" and start nothing. Close the game, press it again and let the build finish. 5. Check, and say in a comment here what you saw, with your Windows version, GPU and driver: - the game is in the same folder, and no new folder appeared beside it; - the NVIDIA app still lists the program with your setting, and it applies in the game; - the Insert menu's row and the mod are as you left them; - the home shows the new version on the same row. 6. Optional, a whole build: build another channel's version (stable, say) from the channel picker. Its folder should be named after the channel (`stable`). Issue: https://git.magicbean.dev/MagicBeanDev/Longshot/issues/224
fix: build an update in its build's own folder
Some checks are pending
CI / Conventional Commit title (pull_request) Blocked by required conditions
CI / Compile and test (pull_request) Blocked by required conditions
6e56794bab
Stops each update from making a new folder named after its version, which changed the game's path and left its settings, mods and the version before behind. Names a new build's folder after its channel, and waits for Longshot to be closed before building over a game.

Co-Authored-By: Claude Fable 5.2 <[email protected]>
Some checks are pending
CI / Conventional Commit title (pull_request) Blocked by required conditions
CI / Compile and test (pull_request) Blocked by required conditions
This pull request is marked as a work in progress.
Some workflows are waiting to be reviewed.
This branch is out-of-date with the base branch
View command line instructions

Checkout

From your project repository, check out a new branch and test the changes.
git fetch -u 'fix/update-keeps-folder:Victor-fix/update-keeps-folder'
git switch 'Victor-fix/update-keeps-folder'
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
MagicBeanDev/LongshotLauncher!57
No description provided.