fix(mods): merge a mod's resource size table with the button prompts' instead of switching the icons off #2270
No reviewers
Labels
No labels
accessibility
autorelease: pending
autorelease: tagged
bug
dependencies
documentation
duplicate
enhancement
github_actions
good first issue
help wanted
invalid
question
testing wanted
wontfix
No milestone
No assignees
1 participant
Due date
No due date set.
Dependencies
No dependencies set
Reference
MagicBeanDev/Hookshot!2270
Loading…
Reference in a new issue
No description provided.
Delete branch "mods-size-table-merge"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
While a mod that ships its own resource size table is loaded, the button icons in every text go back to the Switch's,
whatever controller and Button prompts setting the player has. Every randomizer seed made by
Clawshot ships one, and Clawshot lists this as a known issue ("While a seed is
loaded, button icons in text show Switch buttons instead of your controller's").
Fixes #2329.
Why it happens
The game reads one size table. The button prompts' fonts are larger than the game's, so Hookshot serves the game's table
with the font's entry raised (
prompts/rsizetable.zs). A mod that makes files bigger has to ship the table with itsown entries raised (#1325), and the mod's file wins, as any mod file does.
host/prompts.cthen saw a mod table andturned the prompts' font off (
prompts: a mod has the resource size table: the game's own icons in texts), because thelarger font would not fit the mod's entry. The textures and layouts stayed the controller's, so the pause menu showed
the controller's pictures and Switch letters side by side.
What changed
host/prompts.c,host/mods.c: when the size table the game opens is a mod's file, it is served with the prompts'entries merged into it: each file gets the larger of the two entries, entries only one side has are kept, sorted as
the game's (
merge_restbl). The result is written once per run as raw zstd blocks toprompts/rsizetable.mod.zs, asthe font already is, and the prompts' font is served as without a mod. Any other mod file is served as before.
entries are merged into it.
not give its size) is served as it is, with the game's icons, as before; the log says why.
mods: System/Resource/ResourceSizeTable.Product.111.Nin_Ounce_NVN2.rsizetable.zs <- <file> (with the button prompts' sizes merged in)andprompts: <file>: the button prompts' sizes merged into the mod's resource size table (1 entries raised or added).nx2/build.py: zstd's decoder (third_party/zstd, already compiled intohookshot_vk) is compiled into the runtimetoo, from one
zstd_jobs()both use. The readme's Mods section says what happens to a mod's table.How it was tested
tests/test_mods_size_table.py(new):merge_restblcut out ofprompts.con made-up tables against an independentmodel, and seven tables it must refuse; then, on Linux,
mods.candprompts.cas they are over real folders: nomod, a mod with a table, a mod without a table that grows a file, two mods with tables, a table that cannot be merged,
no prompts table, a mod with its own font, and with
zstandarda level-19 frame and one without its size. It failson
main.python -I -B tests/run_all.pyon Linux, before a rebase onto currentmain(the new test and the two tests this change edits were run again after it and pass): 361 passed, 10 skipped; the failures are the two that fail onmainonthis machine (
test_updater_asset_digest.py: no .NET 8 packs offline;test_wayland_libdecor_hint.py: a clang 23warning) and
test_bake_mimo.py, whose shader-recompiler compile failed with an empty error at load 134 and passesrun alone (103 s).
In the game (RTX 4090, NVIDIA 615.78.08, Arch Linux, headless; Button prompts set to PlayStation 5, as a run
without a controller needs; a Clawshot seed as a mod; a save in Kokiri Forest, the pause menu's Basic Controls page):
main): the DualSense picture next to Switch icons in the texts (ZL, minus, A, B, X, Y, "Select (A) Back(B)"), and
prompts: a mod has the resource size table: the game's own icons in textsin the log;same build without the mod; the log says
(with the button prompts' sizes merged in)after the table's line andprompts: ps5 icons, 16 buttons on this pad's controls. The seed's Kokiri Forest and Hyrule Field placement fileswere read from the mod and the forest loaded. The table the game wrote has all 19 entries the seed raised and the
font's entry raised, and equals the merge computed separately in Python.
Not tested
Windows:
host/prompts.candhost/mods.ccompile forx86_64-w64-mingw32with-Wall -Wextraand no warning, butwere not built into a Windows game or run there; the folder part of the test runs on Linux only (it uses host/posix's
file calls), the merge part on both. AMD and Intel: nothing here touches the GPU. Real controllers: the face was chosen
with the Button prompts setting, as a run without a controller needs.
Found while helping with Clawshot's known issue; I'll tell its maintainer about this pull request.
Assisted-by: Claude Opus 5.5
Co-Authored-By: Claude Opus 5.5 [email protected]
Looks good to me. I read the merge and the precedence carefully.
Precedence: a mod's table still wins as a file (hos_mods_romfs keeps
e->host), and the prompts' entries are only raised into it: max of the two sizes per file, entries only one side has are kept, sorted as the game's. The merge refuses anything that is not the game's format (header, name-field size, byte-length check, out-of-order parts, a name field that differs), and then the mod's table is served as it is with the game's icons, as before. The mod's version and name field are kept. Both parts are bounded (name field <= 1024, frame <= 64 MB, output buffer sized for the worst case). The ordering is right for both the CRC part and the name part. The non-table keys return 0 when a mod has the file, so a mod's own font/textures/layouts still win. Merged once per run, and the state machine withfromguards the second-table case.Nothing game-derived is added: the new test builds made-up tables, there is no binary in the diff, and the zstd change is the existing vendored decoder reused (PROVENANCE updated).
Two small nits, not blocking:
build()picks the mod table withhos_mods_find, which returns the first match in hash order, whilehos_mods_romfspasses the path actually opened. If a mod ever carried two files ending in.rsizetable.zs(another product number besides 111), the merge could be made from the one the game never opens, and the one it opens is then served unmerged next to the larger font, which the game drops. Unlikely, but picking the keyhos_mods_romfsgets for the real table name would remove it.No prior comments or reviews on the PR to answer.
@hckrman101 thanks for the review here. #2592 now selects the mod table by the game's own RomFS table name instead of hash order, and made-up two-version tables prove both font-first and table-first requests with GCC and Clang (both fail on main). Your other point was CI visibility: the follow-up records the local suite separately and still needs the full GitHub regression checks approved and green, not just the title check.
github-sync referenced this pull request2026-11-12 06:22:54 +00:00