feat(builder): the damaged game files a build replaced are listed in the game folder (#2237) #2254

Merged
bronze-ff merged 2 commits from feat/damaged-files-note into main 2026-11-11 16:58:45 +00:00
bronze-ff commented 2026-11-11 12:02:30 +00:00 (Migrated from github.com)

Part of #2237 (its item 2: write the list into the game folder).

The problem

When a dump is incomplete, the build replaces each damaged game file with a similar one and prints the list (Your game dump is incomplete: ...). The list is easy to miss in the build's output, and it is printed only once per unpack: a later build or update of the same folder skips the check. The player then reports a missing floor or a wrong texture (#1700), and nothing in the game folder says the dump was the cause.

The change

  • stand_in_damaged_files() also writes the same text to hookshot_damaged_files.txt in the game folder, beside hookshot_version.txt.
  • The file is removed when a later unpack finds no damaged file (a complete dump built into the same folder).
  • The readme's problem table has a row for it, so triage can ask "is there a hookshot_damaged_files.txt in your game folder?".

The printed text is unchanged. Items 1, 3 and 4 of #2237 are not in this change.

Tests

nx2/test_nup_zstd_heads.py checks that the file is written with the damaged file and its stand-in, and that it is removed after an unpack with no damage.

Run on Windows 11, Python 3.14:

  • python -I -B nx2/test_nup_zstd_heads.py: 5 tests, OK
  • python -I -B nx2/test_nup_stand_in.py: ok
  • python -I -B tests/test_make_game_cache.py: 11 tests, OK (1 skipped)
  • python -I -B tests/test_missing_nup.py: 8 tests, OK

Not tested: a full build from a real incomplete dump.

Note: #2096 and #2253 touch the same function; whichever lands second needs a small rebase, which I will do.

🤖 Generated with Claude Code

Part of #2237 (its item 2: write the list into the game folder). ## The problem When a dump is incomplete, the build replaces each damaged game file with a similar one and prints the list (`Your game dump is incomplete: ...`). The list is easy to miss in the build's output, and it is printed only once per unpack: a later build or update of the same folder skips the check. The player then reports a missing floor or a wrong texture (#1700), and nothing in the game folder says the dump was the cause. ## The change - `stand_in_damaged_files()` also writes the same text to `hookshot_damaged_files.txt` in the game folder, beside `hookshot_version.txt`. - The file is removed when a later unpack finds no damaged file (a complete dump built into the same folder). - The readme's problem table has a row for it, so triage can ask "is there a `hookshot_damaged_files.txt` in your game folder?". The printed text is unchanged. Items 1, 3 and 4 of #2237 are not in this change. ## Tests `nx2/test_nup_zstd_heads.py` checks that the file is written with the damaged file and its stand-in, and that it is removed after an unpack with no damage. Run on Windows 11, Python 3.14: - `python -I -B nx2/test_nup_zstd_heads.py`: 5 tests, OK - `python -I -B nx2/test_nup_stand_in.py`: ok - `python -I -B tests/test_make_game_cache.py`: 11 tests, OK (1 skipped) - `python -I -B tests/test_missing_nup.py`: 8 tests, OK Not tested: a full build from a real incomplete dump. Note: #2096 and #2253 touch the same function; whichever lands second needs a small rebase, which I will do. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
hckrman101 (Migrated from github.com) approved these changes 2026-11-11 16:49:23 +00:00
hckrman101 (Migrated from github.com) left a comment

Looks good. The note is written beside hookshot_version.txt, the printed text is unchanged, and the stale note is removed when a later unpack finds no damage. It only holds text the builder already prints: romfs-relative file names from the user's own dump, plus the stand-in's basename. No game data is added to the repo. The test covers the write and the removal, and the readme row is useful for triage.

One thing to settle before merge, with #2096 (Arkex-ai, "stop when damaged resources have no replacement", approved, not merged yet). It rewrites the same print block and adds a fail() after it when a file has no replacement. Whichever lands second needs a rebase, and the order matters:

  • If #2096 lands first, this PR must write hookshot_damaged_files.txt before the fail(), right after the list is printed. Written after it, as it is now, the unresolved case (the one where the build stops, and the one that most needs a record in the game folder) never gets a note, because fail() ends the run first.
  • After #2096 the checked stamp is also not written on that path, so the next build re-checks and reaches the same place. The note must still be there, and rewritten each time.
  • Also keep the removal in the not done branch where #2096 leaves it (it moves the early return).

Nit: the other files in that function go through check_cache_paths(out, ...), which refuses links. The note is opened for writing without that, so a link at hookshot_damaged_files.txt would be followed. Adding note to that tuple is cheap.

CI is green except appimage, which failed after 10 minutes. It is a Linux packaging job and this PR touches none of that, so it looks unrelated. Please check it is a known failure on main.

Looks good. The note is written beside `hookshot_version.txt`, the printed text is unchanged, and the stale note is removed when a later unpack finds no damage. It only holds text the builder already prints: romfs-relative file names from the user's own dump, plus the stand-in's basename. No game data is added to the repo. The test covers the write and the removal, and the readme row is useful for triage. One thing to settle before merge, with #2096 (Arkex-ai, "stop when damaged resources have no replacement", approved, not merged yet). It rewrites the same print block and adds a `fail()` after it when a file has no replacement. Whichever lands second needs a rebase, and the order matters: - If #2096 lands first, this PR must write `hookshot_damaged_files.txt` **before** the `fail()`, right after the list is printed. Written after it, as it is now, the unresolved case (the one where the build stops, and the one that most needs a record in the game folder) never gets a note, because `fail()` ends the run first. - After #2096 the `checked` stamp is also not written on that path, so the next build re-checks and reaches the same place. The note must still be there, and rewritten each time. - Also keep the removal in the `not done` branch where #2096 leaves it (it moves the early `return`). Nit: the other files in that function go through `check_cache_paths(out, ...)`, which refuses links. The note is opened for writing without that, so a link at `hookshot_damaged_files.txt` would be followed. Adding `note` to that tuple is cheap. CI is green except `appimage`, which failed after 10 minutes. It is a Linux packaging job and this PR touches none of that, so it looks unrelated. Please check it is a known failure on main.
Commenting is not possible because the repository is archived.
No description provided.