43 Commits
Author SHA1 Message Date
Valiantsin DzerakhandClaude Opus 5.5 396c4ae621 Describe the profile-guided build in docs/pgo.md: where and how to train, free play, merge, measure
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-10 19:07:38 +03:00
Valiantsin DzerakhandClaude Opus 5.5 2fe1ea1716 Bump the bundled Windows SDL to 3.4.20 (#912)
SDL 3.4.20 uses default Switch controller stick and IMU calibration when the
pad has none, which fixes the infinite gyro readings on the Beitong Asura 2 Pro+.
The pins in tools/make_release.py (version, zip and devel sha256, SDL3.dll sha256)
and the Windows rows of THIRD_PARTY_NOTICES.md follow. The sniper sysroot row stays.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-10 08:53:49 +03:00
Valiantsin DzerakhandClaude Opus 5.5 2d2c6782af Record the runtime headers a PGO profile was trained with and warn when they change
The floating-point helpers in simd.h and simd_fp.h inline into every lifted function before llvm-profdata matches
the profile, so the fpcheap change left pgo-v143 with a fifth of its weight while recomp/ stayed the same and
make_release saw nothing. pgo.py merge now reads the instrumented build's Ninja deps log and stores the digests of
the runtime/ headers the generated objects include (cpu.h, simd.h, simd_fp.h); make_release warns when one differs
or a record has none. docs/building.md says to retrain after a change to those headers, and build_game.py names the
libiconv-2.dll that MSYS2's SDL3.dll needs in deps-mingw/bin.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-09 18:50:36 +03:00
Valiantsin DzerakhandClaude Opus 5.5 38e2ae1b15 Ship every install-time runtime source in the Windows release
make_release.py copied a hand-written list of the sources build_game.py compiles at install time and missed
mouse_direct.c, so the 06005d4 installer failed to link with undefined input_direct_mouse_* symbols. It now copies
build_game.INSTALL_SIDE, and build_game.py --runtime-lib stops with the missing file names before the link.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-04 12:12:52 +03:00
Valiantsin DzerakhandClaude Opus 5.5 282130a128 Build the game code with an execution profile when the release has one
build_game.py --pgo gen builds an instrumented totk.exe (llvm-mingw: MSYS2's clang has no profile runtime) that adds
its counts to <out>/pgo/*.profraw every minute and at exit; plat_exit ends the process with ExitProcess, which skips
compiler-rt's atexit write. tools/pgo.py merges them into build/pgo/pgo-<ver>.profdata with a record of the recomp/
tree it fits. build_game.py --pgo FILE compiles the generated code at -O2 and the runtime with that profile.

make_release.py ships build/pgo's profiles in data/ and builds the runtime libraries with them; the installer passes
the update's profile to build_game.py, and builds at -O1 without one. Profiles name lifted functions by address and
hold branch counts and control-flow hashes of the generated C, no bytes of the game.

1.4.3 on machine A, mean frame by world clock: the fight2 bench 11.49 -> 10.06 ms (-12.5%), a fight outside the
training 13.00 -> 12.24 ms (-5.8%); every window CPU-bound. The profile was trained on scripted runs and 24 minutes
of play.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-04 11:04:31 +03:00
itaskaev2andClaude Opus 5.5 afe3404434 Accept NSZ and XCZ game files in the setup
The check step tells a compressed file by its content (an NSP or XCI holding NCZ files), whatever its name, and
unpacks it into the temp folder with tools/ncz.py before the extraction reads it. Every NCA comes back byte for byte
and is checked against the hash in its name. The file dialog has one filter for all game files, and the form says
that compressed files are unpacked automatically, in every setup language.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-02 18:03:27 +01:00
Valiantsin DzerakhandClaude Opus 5.5 e603095ffa Refuse instructions above x86-64-v2 in the runtime objects of a v2 build
-march=x86-64-v2 does not reach inline assembly, target attributes or intrinsics, which is how kern_ap_stub's YMM
saves got into libtotkrt-v2.a (issue #454). tools/check_isa.py disassembles objects and lists every function with
VEX/EVEX, BMI1/2, LZCNT, MOVBE, ADX, SHA, AES, PCLMUL or RDRAND/RDSEED code or YMM/ZMM/mask registers, except
functions in its DISPATCHED list (sha256.c blocks_ni, behind __builtin_cpu_supports). build_game.py --cpu v2 runs it
over the runtime objects after compiling and before linking or archiving, so make_release.py's v2 library build fails
too. Objects unchanged since the last clean scan are skipped; a full scan of the runtime takes about a second. The
release ships the script, and the installer's runtime fingerprint includes it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-02 14:06:40 +03:00
Valiantsin DzerakhandClaude Opus 5.5 a6c2c1b2e1 Merge pull request #358: Stop the Windows release on a translator older than its sources (m3rcury02)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-01 17:50:59 +03:00
Valiantsin DzerakhandClaude Opus 5.5 c3dae879cb Build the mods' ExeFS patches into the game and switch them with their mod
A mod that patched the game code (.ips, .pchtxt) stayed off as a whole.
tools/exefs_patches.py now reads IPS, IPS32 and IPSwitch files from each
mod's exefs folder and from atmosphere/exefs_patches/<name>/. It keeps the
ones whose build id is main's and turns their writes into main's code into
one patch set per file. The writes go through the same rules as the code
cheats (tools/cheats.py convert). A file that writes main's data, or that the
rules cannot express, is unsupported as a whole. The setup's lift runs it
after cheats.py and writes build-cache/exefs.status.

runtime/mods.c checks each patch file against that status:

- a built file's set is switched on with its mod;
- a file the build lacks keeps the mod off and starts the rebuild at the next
  start, like a code cheat does;
- an unsupported file keeps the mod off, and the Mods tab shows the reason;
- a file for another version is counted and left out.

A mod patch on a site of one of the port's own sets turns that set off while
the mod is on, and the Mods tab names it. The Mods tab also gets the "Rebuild
the game now" row.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-01 14:29:40 +03:00
m3rcury02andClaude Opus 5.5 33c2a1ac63 Stop the Windows release on a translator older than its sources.
make_release.py copied build/xlate as it found it, so a translator change reached no Windows release until someone rebuilt it by hand, and nothing failed when they did not: 0.2.1 and 0.2.8 shipped a translator from before the gather bias while the runtime logged that the bias was on. The Linux release builds its own.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-01 16:03:41 +05:30
Valiantsin DzerakhandClaude Opus 5.5 5e584ea966 Merge pull request #51: Load Atmosphere cheat files and switch their cheats from a Cheats tab in the menu (conongnang)
Merged onto the mods folder (task/mods1); the Cheats tab sits after Mods. The cheats' menu text and the cheat file's
place are reworked for the mods folder in the commits that follow.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-01 13:31:17 +03:00
Valiantsin DzerakhandClaude Opus 5.5 c0007bd16d Merge pull request #191: Add Simplified Chinese to the setup window and the in-game menu (tuwary)
The menu side is dev's: it has Simplified Chinese since #243, glyphs included. Simplified Chinese
joins the setup window as a fourth language beside Brazilian Portuguese, in the language switch,
the Windows and locale pick and the launcher; zh-Hans.json gets the nineteen texts added since
(fonts step, CPU level, base game checks, Linux checks) and the {game_exe} placeholder.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-01 12:29:30 +03:00
Valiantsin Dzerakh 4524fed813 Merge pull request #211: Show Xbox button icons in the prompts, with a Button prompts setting that follows the pad layout (waxyfeet)
# Conflicts:
#	docs/installer.md
#	runtime/cfg.c
#	runtime/ui/menu.cpp
#	runtime/ui_text.h
2026-11-01 11:14:40 +03:00
Valiantsin Dzerakh 57129898e8 Merge pull request #296: Run the game on x86-64-v2 CPUs without AVX2 (chen3feng)
# Conflicts:
#	README.md
2026-11-01 11:10:05 +03:00
Valiantsin Dzerakh fb99b2bab1 Merge pull request #186: Add a Brazilian Portuguese catalog for the installer window and the launcher (Lucas-blip-png) 2026-11-01 10:55:12 +03:00
conongnangandClaude Opus 5.5 bf40602179 Move the Cheats tab to its own file and leave menu.cpp's font ranges alone, to stay clear of other open PRs
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-01 09:15:54 +07:00
conongnangandClaude Opus 5.5 d8cbdf1067 Ship tools/cheats.py in the release, which runs it in the lift step
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-01 08:15:20 +07:00
CHEN Feng 34b4faee7c Run the game on x86-64-v2 CPUs without AVX2
-march=x86-64-v3 kept the port and the installer to CPUs with AVX2 and FMA. --cpu v2 compiles the generated code and the runtime for SSE4.2 instead. Without FMA3 the FP lowering calls fma/fmaf, so runtime/fma.c provides correctly rounded ones (musl, MIT) that honour MXCSR's rounding mode, FTZ and DAZ; the UCRT's software fallback rounds incorrectly by up to half an ulp. simd.h's fast paths keep their assumptions.

The installer's host check asks for x86-64-v2 and selects libtotkrt.a or libtotkrt-v2.a; both release scripts build and ship the pair. The differential tests compile fma.c as well, so a --cflags=-march=x86-64-v2 run tests it.

Tested on an i7-3770K (no AVX2, FMA or BMI) with an RTX 3060 Ti, game 1.4.3: the installer ran end to end, --selftest passed and play holds 40-60 fps at 1080p. fma and fmaf matched 152,288 exact vectors over two seeds, including ties, subnormals and every rounding mode, FTZ and DAZ combination. The v3 build is unchanged: fma.c is an empty translation unit there.
2026-11-01 07:09:13 +08:00
Valiantsin DzerakhandClaude Opus 5.5 47485da7d9 Merge pull request #262: Linux fixes (wdiasjunior)
Shader preparation reads MacNativeGames' whole shader list history,
release downloads resume from a .part file, appimagetool and the type-2
runtime come from release tags, and the preparation summary counts the
vertex and fragment variants it skips with the graphics pipeline library
off.

The gettid cache in runtime/platform/linux.c conflicted with the same fix
already on dev (8dd7e20, #236); dev's version is kept.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 20:45:06 +03:00
Wellington Dias 522c69e951 Download a cached release file again when its hash no longer matches its pin, in the same run, instead of stopping. 2026-10-31 12:40:55 -03:00
Wellington Dias 8f6664d758 Download the release's pinned files into a .part file that a rerun resumes, and delete a file whose hash is wrong, so a cut download no longer fails every later run. 2026-10-31 12:38:33 -03:00
Lucas-blip-png ff4d79c700 Merge remote-tracking branch 'origin/dev' into installer-ptbr
# Conflicts:
#	installer/guilogic.py
2026-10-31 09:42:07 -04:00
lcd1232 d0e27b95c4 Restore Cyrillic rendering in the Linux installer with Xft 2026-10-31 17:40:54 +04:00
Deon FoucheandClaude Opus 5.5 01d69bf6d1 Merge dev into xbox-button-icons, with the restart and the prompts on the Linux port's portable calls
The restart moves into gfx_present.c's gfx_window_closed, which the Win32 and SDL windows share, and linux.c gets
plat_restart and plat_restart_wait: posix_spawn of /proc/self/exe with no descriptor past stderr and the default
signals, and a wait on a pidfd. The prompts code takes plat_file_exists, plat_setenv, strcasecmp and strdup, and the
menu and the log say a game resolution of another shape than 16:9 (16:10 now as well as 21:9) keeps the Switch prompts.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 22:14:22 +10:00
Deon FoucheandClaude Opus 5.5 4c17621045 Write both Xbox prompt folders in the setup, the release and the builds
The setup runs make_romfs_patches.py --prompts xbox and --prompts xbox-label and warns once when either fails, the
release bundles tools/button_icons.py and fontTools, and build_game.py and package_build.py copy both folders.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 20:50:17 +10:00
Valiantsin DzerakhandClaude Opus 5.5 43a18a9bb1 Merge pull request #60: Linux port (AppImage) and Steam Deck support (wdiasjunior)
The branch forked 79 commits before main and 98 before dev. Resolutions:

1. Aspect ratio: dev's implementation stays (camera patch at page +56 on 1.4.3, tools/ultrawide_layout.py layouts per
   size in romfs-patches-<w>x<h>, the aspect = fit|stretch setting). The PR's second implementation is dropped: the
   aspect sets of patches-v121.txt and patches-v143.txt (the 1.4.3 one patched the same viewport sites as dev's),
   tools/aspect_layouts.py, the resolution.c shapes that limited game resolutions to 16:9, 16:10 and 21:9, and the
   picture_fit setting. Its letterbox code (gfx_fit_rect) is kept and reads TOTK_ASPECT.
2. Code dev changed where the PR moved it: the stick dead zone, the test gamepad and the paddles go to input.c; the
   DPI awareness, keep-awake and IME detach of gfx_window.c go to gfx_window_win.c; device fault reports and GPU
   breadcrumbs to gfx_present.c. gfx_window_dpi gets an SDL version.
3. dev's Win32 calls in shared code go through platform.h: the shader cache pack reader (PlatFile), the romfs
   overlay checks, the audio pacing waits, the motion, ASTC and device fault locks. plat_cpu_usable and
   plat_commit_info get Linux versions; plat_cpu_count counts the machine's processors on both. dpi_probe.c becomes
   dpi_probe_win.c.
4. assume_focus defaults to 1 as the PR has it (a load interrupted by a focus loss can stop for good) and stays live,
   with dev's Game tab row.
5. The frame limits 40 and 45 join dev's list. The BC 3D storage fallback for Vega only runs with
   TOTK_BLOCK_VIEWS_3D=1, since dev makes 3D BC images without block views by default.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 13:26:42 +03:00
tuwaryandClaude Opus 5.5 859ed28735 Add Simplified Chinese to the setup window and the in-game menu
The setup window gets installer/text/zh-Hans.json, a full copy of the English catalog, and a third entry in its
language switch. A Windows display language of zh-CN or zh-SG picks it; zh-TW, zh-HK and zh-MO write Traditional
Chinese and stay on English. A Chinese window still starts with English as the game language, because Chinese game
text needs the Switch shared fonts the installer does not extract. The launcher's message box and
make_release.py's launcher_text.h carry the Chinese strings too.

The menu and the performance overlay get a text_zh_hans table for every menu id, and TOTK_MENU_LANG takes zh-Hans.
Left unset, the menu follows the system UI language with the same Simplified Chinese regions. The font atlas merges
in every glyph of the menu language's text from the system font (Microsoft YaHei, else SimSun) and is built again
when the menu language changes. ov_probe checks that every menu id has Chinese text, that the printf formats keep
the English conversions, and how system language tags map to menu languages; installer_gui_test checks the new
catalog the same way as the Russian one.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DcYzeu7eb2tXZMU4bRVcGh
2026-10-31 16:33:53 +08:00
Lucas-blip-png 1e32d605ce Add a Brazilian Portuguese catalog for the installer window and the launcher
The installer had English and Russian. installer/text/pt-BR.json covers every id with the same placeholders; the window offers PT-BR beside EN and RU and picks it when the Windows display language is Portuguese (Brazil), LANGID 0x0416; Portugal's Portuguese stays English. make_release.py writes LAUNCHER_*_PT_BR into launcher_text.h and the launcher shows it on the same LANGID. The catalog tests check every window language against English.
2026-10-31 04:01:30 -04:00
Seth 582f675e88 Render a game resolution wider than 16:9 at its own shape, with black bars as the fallback
An output_res such as 3440x1440 now widens the camera's view to that shape on 1.4.3: patches-v143.txt
sets the aspect ratio at the camera and viewport sites that hand it to the perspective projection.
The HUD and menus come from a romfs-patches-<w>x<h> overlay that make_romfs_patches.py --aspect
builds through tools/ultrawide_layout.py, and romfs.c overlay_init picks that overlay when the game
resolution is not 16:9. The installer prepares it for 2560x1080, 3440x1440, 3840x1600 and 5120x2160.

When the window's shape differs from the game resolution's, the new aspect setting keeps the
picture's shape with black bars (fit, the default) or stretches it over the window.
2026-10-31 07:43:44 +03:00
Pasha Kagan 58b15ed069 Copy tools/pack_shader_cache.py into the release 2026-10-31 07:24:10 +03:00
Wellington Dias 7285688165 Give the interface its proportions at 16:10 and 21:9, and limit game resolutions to those shapes and 16:9.
The game lays its interface out in a 1920x1080 space and draws it over the whole output, so at 1280x800 every menu and
the HUD were 11 % taller than drawn, and at 21:9 34 % wider. tools/aspect_layouts.py rewrites the layout archive for
each shape: every layout's root pane scaled back, full-screen backgrounds kept full, the HUD moved to the screen's
edges, and the minimap, place name and dragon's tears map icon animations adjusted. It follows the behaviour of
Fruithapje21's TOTK-Ultrawide (GPL-3.0, read for behaviour only) and checks every original value before it writes.
make_romfs_patches.py writes the results to romfs-patches/16x10 and 21x9 at install and build time, and romfs.c serves
the one of the output's shape. resolution.c accepts 16:9, 16:10 and 21:9; another shape draws 16:9 with bars. The
menu lists the game resolutions by shape. Checked on 1.2.1 and 1.4.3 at 1280x800 and 3440x1440: HUD, minimap,
inventory, map, system tab and loading screen.
2026-10-30 16:23:58 -03:00
Wellington Dias 48d1a6d3a0 Build the release from either game version's generated C, so a checkout with only 1.4.3 can make it.
make_release.py and make_release_linux.py built the runtime library and the --prove build from generated/v121 alone.
The library reads only what both versions' layout.h share (MOD_COUNT, MOD_MAIN_BASE), so both scripts now take
generated/v121, else generated/v143, pass its --version, and name extract.py and gen.py when neither exists.
2026-10-30 14:56:25 -03:00
Valiantsin DzerakhandClaude Opus 5.5 a5711539e1 Size the code generator's worker pool by free memory so it stops running out of RAM
gen.py started one emit worker per CPU, about 1.3 GiB each on 1.4.3, so many-core machines with modest RAM died with a MemoryError during "Translating code to C" (issues 17, 28, probably 66). The default is now min(CPU count, 80% of the free physical memory / 1.5 GiB), at least 1, capped by the memory limit of the enclosing job object if there is one. --jobs still overrides it, and the chosen count and its reason are logged. The memory helper is tools/hostmem.py, shipped with the release tools.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-30 12:43:50 +03:00
Valiantsin DzerakhandClaude Opus 5.5 f4619f7b45 Add a VERSION file with the port's semver, shown beside the installer title and on the game menu's title line with the game update
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 11:40:01 +03:00
Valiantsin DzerakhandClaude Opus 5.5 456f3b7f92 Compile ov_zstd.c per install with patches.c: it includes the player's patches.h for the patch page its host functions sit on, so in the prebuilt runtime library of a release it compiled to nothing and the patched zstd calls would have reached no host function
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-28 19:08:44 +03:00
Valiantsin DzerakhandClaude Opus 5.5 eca89641fa Keep 1.2.1's scene at the wanted size, package zstd for the installer
1.2.1 renders the scene size it reads, while 1.4.3 scales it by output width / 1920: on 1.2.1 the scene set is on
whenever the output grows (2560x1440 gave a 1600x900 scene before, 2133x1199 now). An output at or below the shipped
size needs no grown HeapDef. The release deps carry the static libzstd and its header, totk.ini.example the four new
keys, THIRD_PARTY_NOTICES.md the MacNativeGames sites, FSR 1 and zstd.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-27 13:56:28 +03:00
Valiantsin DzerakhandClaude Opus 5.5 7fefa86fe3 Compile patches.c per install instead of into the prebuilt runtime library
The release built libtotkrt.a against generated/v121, so patches.c baked in 1.2.1's patch page (0x700472b000, the page
after 1.2.1's main). A 1.4.3 install lifts its code with the 1.4.3 patch table, whose patched sites read the page after
1.4.3's main (0x7003adf000): the runtime never committed it and the game faulted there soon after mounting the save, while
frame_rate.c wrote its frame step into sdk memory at the 1.2.1 address. patches.c now joins romfs.c in INSTALL_SIDE and
the release ships its source, so it compiles against the player's patches.h.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-27 09:12:15 +03:00
Valiantsin DzerakhandClaude Opus 5.5 875a4af317 Ship tools/build_shaders.py in the release: build_game.py imports it since the ASTC compute decode, and the installer's compile step failed on the missing module
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-27 08:26:57 +03:00
Valiantsin DzerakhandClaude Opus 5.5 d6e5b78252 Prepare every game shader's default variant and the shader list rows MacNativeGames pruned
MacNativeGames now translates each shader's default bind state when it builds and keeps only other variants in its
shared list, so the list at origin/HEAD has 134 rows of 1.4.3 shaders. prepare_shaders.py seeds the default variant of
every shader it finds and reads the list through tools/shader_list.py, which adds the V rows older revisions held. On
1.4.3 that prepares 29,587 variants in 7 min with 0 translation failures, and every one of the 1,095 variants the field
and intro runs met in play is among them. The installer's dev path and make_release.py read the list the same way.

Also record that 1.2.1 loads saves 1.4.3 wrote.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 19:53:16 +03:00
Valiantsin DzerakhandClaude Opus 5.5 a9a7762ead Give totk.exe, TotK-Setup.exe and the installer window the green ring icon: runtime/totk.ico is embedded through totk.rc and a new launcher.rc, and the release copies it into runtime/ for the Tk window
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 16:48:02 +03:00
Valiantsin DzerakhandClaude Opus 5.5 5c1626e7ac Build TotK-Setup.exe, write VERSION, copy installer/ and totk.ini.example into the release and run a check-only installer pass and the window selftest on the bundle
clean_env compared the upper-cased os.environ keys with mixed-case names and dropped SystemRoot, which crashed Tk in the bundled python.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-24 09:19:02 +03:00
Valiantsin DzerakhandClaude Opus 5.5 e8dab5f053 Put the release folder's own code on the bundled Python's search path and run build_game.py from it without -I
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-24 08:28:41 +03:00
Valiantsin DzerakhandClaude Opus 5.5 1ece856440 Add tools/make_release.py, which assembles the installer release folder from pinned downloads
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-24 08:22:46 +03:00