fix: the setup merges the third-party tool into the builder's third_party, and the Hookshot item is back #117

Merged
HumanBean merged 3 commits from HumanBean/Longshot:fix/rc1-third-party-hookshot into main 2026-11-13 05:12:12 +00:00
Owner

Why

The Windows setup cannot install the third-party build tool, because the builder zip already has the folder that tool is supposed to become, so the first Windows release (v3.0.0-rc.1) would not install. Also, the rename to Longshot renamed the game's Hookshot item to Longshot, so the Debug tab's inventory has two Longshots and no Hookshot.

What changed

  • setup: place_tool() in builder/setup/setup.c puts a tool's unpacked <prefix> folder at its <dest>. If nothing is there, it moves the folder whole, as before. If the builder zip already has the folder (LongshotBuilder\tools\third_party, the repository's sources), it moves the tool's files in one by one. It refuses a file both sides have (it never replaces one), a file where the other side has a folder, and links. The SHA-256 check still runs first, before anything is unpacked. All of this happens in the staged versions\<tag>.part, which is only published once complete, so a refusal never leaves a partial install.
  • setup: reuse_part() no longer moves or copies an installed version's tool folder onto a folder the staged install already has. That folder holds the old version's sources as well as the tool's files. In a portable home, the failed copy's rmtree(to) used to delete the new version's third_party sources. So the merged tool now comes from its checked archive on every install (26 MB). The other tools are still reused.
  • debug: gpu/vk/oot_cheat_items.h gets back OOT_ITEM("Hookshot", "Item_Hookshot", 0) and the probe Weapon_Range_Hookshot, as before e2a4d453. That commit had turned them into a second Longshot row and a second Weapon_Range_Longshot.
  • release: scripts/release.py's docstrings no longer mention "the tools release", and the unused TOOLS_TAG constant is gone. The build tools are generic packages now. The file is still byte-identical with LongshotLauncher's (MagicBeanDev/LongshotLauncher#6).
  • docs: docs/releases.md, "Installing", says a tool merges into a <dest> the builder already has. The launcher PR makes the same edit, so the file stays identical in both repositories.
  • tests: tests/test_setup_tool_merge.py and tests/test_cheat_items.py (below).

The sweep for the Hookshot item: I compared every line of e2a4d453 that lost a "Hookshot" (git diff e2a4d453^ e2a4d453, and the tree at e2a4d453^). I looked at the item and cheat tables, menu texts, gpu/vk/menu_i18n.h, teleport and inventory lists, nx2/ patches, host/, docs, the pipeline tour and tests. The only places where "Hookshot" meant the in-game item were the two lines in oot_cheat_items.h. The inventory's item labels are English only: menu_i18n.h has no item names, so there is no translation to restore. Every other "Hookshot" the rename changed meant the project, and stays Longshot.

Flags and settings

None.

Measurements

No measurement: this changes the Windows setup's install step, a Debug-tab item row and comments. None of them run while the game plays.

main: 94bbc205 (2026-11-12)
this PR: fix/rc1-third-party-hookshot @ 8264bb7c
Hardware: not applicable (no frame time or memory is affected)
Scene: not applicable
Method: the game-free checks (Testing)
How to reproduce: LONGSHOT_VULKAN_HEADERS=/usr/include python -I -B tests/run_all.py

main @ 94bbc205 this PR @ 8264bb7c
tests/test_setup_tool_merge.py fails (no place_tool) passes
tests/test_cheat_items.py fails (Longshot twice, no Hookshot) passes
main @ 94bbc205, run 1: 493 passed, 2 failed, 36 skipped (test_bake_portability, test_builder_log_read_only)
this PR @ 8264bb7c, run 1: 495 passed, 2 failed, 36 skipped (the same two)
main @ 94bbc205, run 2: 493 passed, 2 failed, 36 skipped (the same two)
this PR @ 8264bb7c, run 2: 495 passed, 2 failed, 36 skipped (the same two; test_setup_tool_merge and test_cheat_items pass)

Testing

Tested:

  • Linux (CachyOS, x86-64): tests/run_all.py, two runs each on main and on this branch, alternating. Main: 493 passed, 2 failed both times. This branch: 495 passed, 2 failed both times (the 2 new checks pass). Both fail the same two checks, tests/test_bake_portability.py and tests/test_builder_log_read_only.py, which are known failures on main and outside this change.

  • tests/test_setup_tool_merge.py (new) builds a fake builder zip with scripts/builder_package.py's make_zip, containing LongshotBuilder/tools/third_party/{a64-kit,sdl2,zbic} sources. It builds a fake third-party archive with scripts/tools.py's assemble_third_party (the prebuilt files only), and unpacks both the way the setup's tar.exe would. It then runs setup.c's own place_tool and reuse_part, cut from the source, over them. The cases:

    • The merge keeps every source and adds every prebuilt file.
    • A file both sides have is refused, and the builder's copy is kept.
    • A file where the builder has a folder is refused, and so is a link.
    • A <dest> the zip lacks is moved whole.
    • On an update, portable or not, the installed version's third_party is not moved or copied onto the new one, and the new one stays whole. It fails on the old reuse_part: "portable=1: the new version's third_party changed".
    • A tool folder the new version doesn't have yet is still taken from the installed version.

    On Windows the test compiles against windows.h. On Linux it compiles against a small POSIX stand-in for the Win32 file calls those functions make. There is no Wine on this PC, so the whole setup did not run.

  • tests/test_cheat_items.py (new) expands oot_cheat_items.h with the compiler. It checks that no label, pouch name or probe appears twice, that the Hookshot and Longshot rows both exist (Longshot right after Hookshot), and that both Weapon_Range_* probes exist. Against main's header it reports Longshot, Item_Longshot and Weapon_Range_Longshot twice, and no Hookshot.

  • builder/setup/setup.c builds with llvm-mingw 20261104 (x86_64-w64-mingw32-clang -O2 -Wall -Werror -mwindows -municode … -lwinhttp -lbcrypt -lcomctl32 -lshell32 -lole32).

Not tested:

  • The setup on a real Windows PC, the full install from the release zip with the real third-party package. No Windows PC and no Wine here, and there is no v3.0.0-rc.1 zip yet.
  • The Debug tab in the game, giving the Hookshot. No game here. The row is the same as before the rename, in the same place.

Needs other testers:

  • Windows 10/11: unpack a LongshotBuilder-<version>-windows-x64.zip built from this branch and run LongshotBuilder.exe. Expected: the setup finishes, and versions\<tag>\LongshotBuilder\tools\third_party\a64-kit\lift\a64emit.dll sits next to a64emit.cpp (request to open, with the first rc build)
  • Windows, in the game: the Debug tab's inventory shows Hookshot then Longshot, and Enter on Hookshot gives the Hookshot (request to open)

Screenshots

The only visible change is the Debug tab's inventory, which shows the Hookshot row again, under the same label as before the rename. No screenshot: no game on this PC.

Risk and rollback

  • The setup could refuse a tool whose archive has a file the builder zip also has. assemble third-party leaves out every file the repository tracks, so that shouldn't happen, and when it does the setup stops with a message instead of replacing the builder's file.
  • Each update now downloads the third-party tool again (26 MB) instead of reusing it.
  • Reverting the commits undoes all of this.

Reviewer notes

  • Start with place_tool and the new guard at the top of reuse_part in builder/setup/setup.c.
  • The launcher already did this correctly: it unpacks file by file with FileMode.CreateNew and reuses a tool by its own files. The launcher PR only adds a check for it, plus the shared release.py and docs/releases.md edits: MagicBeanDev/LongshotLauncher#6 (MagicBeanDev/LongshotLauncher#6).
  • scripts/tools.py install still keeps an existing <dest> that has no stamp. It is only used on Linux tools and fresh folders (CI, appimage.sh), where nothing overlaps, so I left it alone.

Issues

None filed.

Checklist

For everyone

  • One topic.
  • The title is a Conventional Commit (type(scope): description).
  • Rebased on current main.
  • python -I -B tests/run_all.py run and passing (any failure that also fails on main is named above).
  • Tested in the game, or what wasn't is named under Testing.
  • Testing filled in: what was tested, what wasn't, and what needs other testers (with test requests).
  • Measured: main and this PR at named commits, on the same PC, scene and settings, at least 2 interleaved runs each, the median reported.
  • No game files, dumps, build output or generated files.
  • third_party/ untouched (a new folder with a PROVENANCE.md instead).
  • The license is OK: GPL-3.0-or-later, nothing incompatible and nothing decompiled.

If applicable

  • A game-free test added for the fix, failing on main and passing here.
  • Host code builds on both Windows (llvm-mingw) and Linux, with UTF-8 paths.
  • Docs updated.
## Why The Windows setup cannot install the `third-party` build tool, because the builder zip already has the folder that tool is supposed to become, so the first Windows release (`v3.0.0-rc.1`) would not install. Also, the rename to Longshot renamed the game's Hookshot item to Longshot, so the Debug tab's inventory has two Longshots and no Hookshot. ## What changed - setup: `place_tool()` in `builder/setup/setup.c` puts a tool's unpacked `<prefix>` folder at its `<dest>`. If nothing is there, it moves the folder whole, as before. If the builder zip already has the folder (`LongshotBuilder\tools\third_party`, the repository's sources), it moves the tool's files in one by one. It refuses a file both sides have (it never replaces one), a file where the other side has a folder, and links. The SHA-256 check still runs first, before anything is unpacked. All of this happens in the staged `versions\<tag>.part`, which is only published once complete, so a refusal never leaves a partial install. - setup: `reuse_part()` no longer moves or copies an installed version's tool folder onto a folder the staged install already has. That folder holds the old version's sources as well as the tool's files. In a portable home, the failed copy's `rmtree(to)` used to delete the new version's `third_party` sources. So the merged tool now comes from its checked archive on every install (26 MB). The other tools are still reused. - debug: `gpu/vk/oot_cheat_items.h` gets back `OOT_ITEM("Hookshot", "Item_Hookshot", 0)` and the probe `Weapon_Range_Hookshot`, as before e2a4d453. That commit had turned them into a second Longshot row and a second `Weapon_Range_Longshot`. - release: `scripts/release.py`'s docstrings no longer mention "the tools release", and the unused `TOOLS_TAG` constant is gone. The build tools are generic packages now. The file is still byte-identical with LongshotLauncher's (MagicBeanDev/LongshotLauncher#6). - docs: `docs/releases.md`, "Installing", says a tool merges into a `<dest>` the builder already has. The launcher PR makes the same edit, so the file stays identical in both repositories. - tests: `tests/test_setup_tool_merge.py` and `tests/test_cheat_items.py` (below). The sweep for the Hookshot item: I compared every line of e2a4d453 that lost a "Hookshot" (`git diff e2a4d453^ e2a4d453`, and the tree at `e2a4d453^`). I looked at the item and cheat tables, menu texts, `gpu/vk/menu_i18n.h`, teleport and inventory lists, `nx2/` patches, `host/`, docs, the pipeline tour and tests. The only places where "Hookshot" meant the in-game item were the two lines in `oot_cheat_items.h`. The inventory's item labels are English only: `menu_i18n.h` has no item names, so there is no translation to restore. Every other "Hookshot" the rename changed meant the project, and stays Longshot. ## Flags and settings None. ## Measurements No measurement: this changes the Windows setup's install step, a Debug-tab item row and comments. None of them run while the game plays. main: 94bbc205 (2026-11-12) this PR: fix/rc1-third-party-hookshot @ 8264bb7c Hardware: not applicable (no frame time or memory is affected) Scene: not applicable Method: the game-free checks (Testing) How to reproduce: `LONGSHOT_VULKAN_HEADERS=/usr/include python -I -B tests/run_all.py` | | main @ 94bbc205 | this PR @ 8264bb7c | |---|---|---| | `tests/test_setup_tool_merge.py` | fails (no `place_tool`) | passes | | `tests/test_cheat_items.py` | fails (Longshot twice, no Hookshot) | passes | ``` main @ 94bbc205, run 1: 493 passed, 2 failed, 36 skipped (test_bake_portability, test_builder_log_read_only) this PR @ 8264bb7c, run 1: 495 passed, 2 failed, 36 skipped (the same two) main @ 94bbc205, run 2: 493 passed, 2 failed, 36 skipped (the same two) this PR @ 8264bb7c, run 2: 495 passed, 2 failed, 36 skipped (the same two; test_setup_tool_merge and test_cheat_items pass) ``` ## Testing **Tested:** - Linux (CachyOS, x86-64): `tests/run_all.py`, two runs each on main and on this branch, alternating. Main: 493 passed, 2 failed both times. This branch: 495 passed, 2 failed both times (the 2 new checks pass). Both fail the same two checks, `tests/test_bake_portability.py` and `tests/test_builder_log_read_only.py`, which are known failures on main and outside this change. - `tests/test_setup_tool_merge.py` (new) builds a fake builder zip with `scripts/builder_package.py`'s `make_zip`, containing `LongshotBuilder/tools/third_party/{a64-kit,sdl2,zbic}` sources. It builds a fake `third-party` archive with `scripts/tools.py`'s `assemble_third_party` (the prebuilt files only), and unpacks both the way the setup's `tar.exe` would. It then runs setup.c's own `place_tool` and `reuse_part`, cut from the source, over them. The cases: - The merge keeps every source and adds every prebuilt file. - A file both sides have is refused, and the builder's copy is kept. - A file where the builder has a folder is refused, and so is a link. - A `<dest>` the zip lacks is moved whole. - On an update, portable or not, the installed version's `third_party` is not moved or copied onto the new one, and the new one stays whole. It fails on the old `reuse_part`: "portable=1: the new version's third_party changed". - A tool folder the new version doesn't have yet is still taken from the installed version. On Windows the test compiles against `windows.h`. On Linux it compiles against a small POSIX stand-in for the Win32 file calls those functions make. There is no Wine on this PC, so the whole setup did not run. - `tests/test_cheat_items.py` (new) expands `oot_cheat_items.h` with the compiler. It checks that no label, pouch name or probe appears twice, that the Hookshot and Longshot rows both exist (Longshot right after Hookshot), and that both `Weapon_Range_*` probes exist. Against main's header it reports Longshot, `Item_Longshot` and `Weapon_Range_Longshot` twice, and no Hookshot. - `builder/setup/setup.c` builds with llvm-mingw 20261104 (`x86_64-w64-mingw32-clang -O2 -Wall -Werror -mwindows -municode … -lwinhttp -lbcrypt -lcomctl32 -lshell32 -lole32`). **Not tested:** - The setup on a real Windows PC, the full install from the release zip with the real `third-party` package. No Windows PC and no Wine here, and there is no `v3.0.0-rc.1` zip yet. - The Debug tab in the game, giving the Hookshot. No game here. The row is the same as before the rename, in the same place. **Needs other testers:** - Windows 10/11: unpack a `LongshotBuilder-<version>-windows-x64.zip` built from this branch and run `LongshotBuilder.exe`. Expected: the setup finishes, and `versions\<tag>\LongshotBuilder\tools\third_party\a64-kit\lift\a64emit.dll` sits next to `a64emit.cpp` (request to open, with the first rc build) - Windows, in the game: the Debug tab's inventory shows Hookshot then Longshot, and Enter on Hookshot gives the Hookshot (request to open) ## Screenshots The only visible change is the Debug tab's inventory, which shows the Hookshot row again, under the same label as before the rename. No screenshot: no game on this PC. ## Risk and rollback - The setup could refuse a tool whose archive has a file the builder zip also has. `assemble third-party` leaves out every file the repository tracks, so that shouldn't happen, and when it does the setup stops with a message instead of replacing the builder's file. - Each update now downloads the `third-party` tool again (26 MB) instead of reusing it. - Reverting the commits undoes all of this. ## Reviewer notes - Start with `place_tool` and the new guard at the top of `reuse_part` in `builder/setup/setup.c`. - The launcher already did this correctly: it unpacks file by file with `FileMode.CreateNew` and reuses a tool by its own files. The launcher PR only adds a check for it, plus the shared `release.py` and `docs/releases.md` edits: MagicBeanDev/LongshotLauncher#6 (https://git.magicbean.dev/MagicBeanDev/LongshotLauncher/pulls/6). - `scripts/tools.py install` still keeps an existing `<dest>` that has no stamp. It is only used on Linux tools and fresh folders (CI, `appimage.sh`), where nothing overlaps, so I left it alone. ## Issues None filed. ## Checklist ### For everyone - [x] One topic. - [x] The title is a Conventional Commit (`type(scope): description`). - [x] Rebased on current `main`. - [x] `python -I -B tests/run_all.py` run and passing (any failure that also fails on `main` is named above). - [x] Tested in the game, or what wasn't is named under Testing. - [x] Testing filled in: what was tested, what wasn't, and what needs other testers (with test requests). - [x] Measured: main and this PR at named commits, on the same PC, scene and settings, at least 2 interleaved runs each, the median reported. - [x] No game files, dumps, build output or generated files. - [x] `third_party/` untouched (a new folder with a `PROVENANCE.md` instead). - [x] The license is OK: GPL-3.0-or-later, nothing incompatible and nothing decompiled. ### If applicable - [x] A game-free test added for the fix, failing on `main` and passing here. - [x] Host code builds on both Windows (llvm-mingw) and Linux, with UTF-8 paths. - [x] Docs updated.
The Windows builder zip carries LongshotBuilder/tools/third_party (the
repository's sources), and tools.lock's third-party tool (the prebuilt
a64emit.dll, lld-link.exe, SDL2/SDL3 and zbic.dll that go among them)
has that folder as its dest. setup.c moved the tool's unpacked folder
onto it, which fails when the folder is there: no install got past it.

place_tool merges the tool's files in, file by file, and refuses a file
both have (never replaced) and links; all in the staged <tag>.part, so
a refusal publishes nothing. reuse_part no longer moves or copies an
installed version's folder onto one the staged install has already: in
a portable home its failed copy removed the new version's third_party.

tests/test_setup_tool_merge.py runs the setup's own place_tool and
reuse_part over a fake builder zip and a fake third-party archive.
The project's rename to Longshot (e2a4d453) also renamed the game's
Hookshot item, a different item from the Longshot: the Debug tab's
inventory had two Longshot rows (Item_Longshot twice) and no Hookshot,
and the probe list named Weapon_Range_Longshot twice.

tests/test_cheat_items.py expands oot_cheat_items.h and checks that no
label, pouch name or probe is there twice, and that both items are.
docs(release): the build tools are generic packages, not a tools release
Some checks failed
CI / Python source checks (ubuntu-24.04, part 1/2) (pull_request) Has been skipped
CI / Python source checks (ubuntu-24.04, part 2/2) (pull_request) Has been skipped
CI / SPIR-V fixtures (global narrow load/store, direct surface atomics, F2I immediate) (pull_request) Has been skipped
Third-party parts / The same as upstream (pull_request) Has been skipped
CI / Conventional Commit title (pull_request) Successful in 3s
CI / Workflow lint (actionlint) (pull_request) Failing after 5s
Third-party parts / As their notes say (pull_request) Successful in 6s
PR description / Description follows the template (pull_request_target) Successful in 3s
8264bb7c04
release.py's docstrings still named the tools release, and TOOLS_TAG,
used nowhere, described it. Byte-identical with LongshotLauncher's.
HumanBean changed title from WIP: fix: the setup merges the third-party tool into the builder's third_party, and the Hookshot item is back to fix: the setup merges the third-party tool into the builder's third_party, and the Hookshot item is back 2026-11-13 05:02:05 +00:00
HumanBean deleted branch fix/rc1-third-party-hookshot 2026-11-13 05:12:12 +00:00
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/Longshot!117
No description provided.