Name the 1.1.0 update 1.1.0 instead of 1.1.1

The update this port builds for has version value 0x20000, which is Tears of the Kingdom 1.1.0, not 1.1.1: the upstream expected-v1.1.2.json carries 0x40000 and the other expected files step 0x10000 per release, so 0x20000 is 1.1.0 and 0x30000 is 1.1.1. Pull request #220 introduced the wrong label in expected-v1.1.1.json.

Expected hashes, patch sites, boot constants and the RomFS layout are unchanged; only names change:
- tools/data/expected-v1.1.1.json -> expected-v1.1.0.json, display_version 1.1.0
- recomp/patches-v111.txt -> patches-v110.txt
- installer/layout.py SUPPORTED and tools/build_game.py DISPLAY_VERSIONS
- make_romfs_patches.py --version choices and its COMMON table key (the RomFS archive name stays Common.Product.110)
- runtime RT_V111 -> RT_V110, the inits_111 and expect_111 tables, the probe's census folder v110
- README, docs and the installer texts

Co-authored-by: deepseek-v4.1-flash-1017 <noreply@deepseek.com>
This commit is contained in:
shenjackanddeepseek-v4.1-flash-1017 committed 2026-11-01 21:08:13 +08:00
1 parent c46b4c2cad
commit a7b988b417
19 files changed
+51 -51

No files matched your search

+2 -2
View File
@@ -3,7 +3,7 @@
**TotK Recomp** is a static recompilation of *The Legend of Zelda: Tears of the Kingdom* (Nintendo Switch, 2023) into a native x86-64 application for Windows and Linux ([docs/architecture.md](docs/architecture.md)).
> [!IMPORTANT]
> **No game files are included.** You need your own legally obtained copy of *Tears of the Kingdom*, dumped from your own console: the base game and the 1.1.1, 1.2.1 or 1.4.3 update. Instructions for obtaining those files will not be provided.
> **No game files are included.** You need your own legally obtained copy of *Tears of the Kingdom*, dumped from your own console: the base game and the 1.1.0, 1.2.1 or 1.4.3 update. Instructions for obtaining those files will not be provided.
>
> The game is built from your files on your machine, so the result contains the game. It is for your own use. Do not share it.
@@ -16,7 +16,7 @@ Report problems as issues, following [CONTRIBUTING.md](CONTRIBUTING.md).
## Features
- Native code, not emulation
- Game updates 1.1.1, 1.2.1 and 1.4.3; 1.2.1 and 1.4.3 saves carry over between them
- Game updates 1.1.0, 1.2.1 and 1.4.3; 1.2.1 and 1.4.3 saves carry over between them
- 60 fps by default; up to 144 fps or the monitor's refresh rate (experimental)
- Custom resolutions (1080p, 2k...), supersampling and AMD FSR 1 upscaling
- HDR10 output with peak, game and HUD brightness settings
+1 -1
View File
@@ -54,7 +54,7 @@ hactool reads `-k <prod.keys>`; MSYS2 shells set `HOME`, which hides its default
## Build
From the repository root, in PowerShell. Every step that depends on the game version takes it as `<ver>`: `v143` for
1.4.3, `v121` for 1.2.1 or `v111` for 1.1.1. The tools default to `v121` when `--version` is left out. Saves load on any
1.4.3, `v121` for 1.2.1 or `v110` for 1.1.0. The tools default to `v121` when `--version` is left out. Saves load on any
of them.
1. Python environments (once). `.venv` runs the lifter and the build; `.venv-py314` runs the extraction scripts, which
+3 -3
View File
@@ -9,7 +9,7 @@ holds only the game; the installer and its tools stay outside it.
1. Downloads `TotK-Setup-<version>-windows.zip` from GitHub Releases (none is published yet), unpacks it anywhere and
starts `TotK-Setup.exe`.
2. Picks:
- the base game (XCI or NSP) and the 1.1.1, 1.2.1 or 1.4.3 update (NSP);
- the base game (XCI or NSP) and the 1.1.0, 1.2.1 or 1.4.3 update (NSP);
- their `prod.keys`;
- optionally the firmware folder (`system/Contents/registered` of an unpacked firmware or an emulator's install),
needed for Chinese, Korean and Traditional Chinese text;
@@ -37,13 +37,13 @@ The player runs a newer installer on the same folder. It reads `totk-install.jso
`shared-fonts/`, `profile/` and `totk.ini` after checking their hashes, rebuilds `totk.exe` and re-prepares the
shaders. A newer release that changes nothing game-derived skips the rebuild.
Given an update file other than the recorded one (1.1.1, then 1.2.1, then 1.4.3), the installer extracts and builds again from it
Given an update file other than the recorded one (1.1.0, then 1.2.1, then 1.4.3), the installer extracts and builds again from it
and keeps `profile/`. Saves carry over both ways between 1.2.1 and 1.4.3: 1.4.3 converts a 1.2.1 save on load, and 1.2.1
loads the saves 1.4.3 wrote.
## Setup steps
1. **Check** before writing anything: the files open with the keys, the update is 1.1.1, 1.2.1 or 1.4.3 (by hash, as
1. **Check** before writing anything: the files open with the keys, the update is 1.1.0, 1.2.1 or 1.4.3 (by hash, as
`tools/extract.py`), the keys are new enough for the update, enough space is free on the target disk (about 36 GiB at the peak of a
first install, 20 GiB after it), the CPU is at least x86-64-v2 (SSE4.2; with AVX2/FMA the faster `v3` build is used,
otherwise the `v2` one), a Vulkan 1.3 GPU exists. Each failure is one clear message.
+1 -1
View File
@@ -9,7 +9,7 @@ from it may be shared.
- Windows 10 or later, an x86-64 CPU with SSE4.2 (AVX2/FMA recommended: they build the default, faster version), about
60 GB free.
- A GPU with Vulkan 1.3 and `VK_EXT_external_memory_host`, with a current driver.
- *Tears of the Kingdom* base game (1.0.0) and the 1.1.1, 1.2.1 or 1.4.3 update, dumped from your own Switch as NSP or XCI.
- *Tears of the Kingdom* base game (1.0.0) and the 1.1.0, 1.2.1 or 1.4.3 update, dumped from your own Switch as NSP or XCI.
- `prod.keys` dumped from your own Switch. Never send it to anyone, and never paste it into a log or an issue.
## Build
+1 -1
View File
@@ -48,7 +48,7 @@ def cancel(signum, frame):
def main(argv=None):
ap = Parser(prog='python -m installer', description=__doc__.splitlines()[0])
ap.add_argument('--base', type=Path, help='base game, XCI or NSP')
ap.add_argument('--update', type=Path, help='the update NSP: 1.1.1, 1.2.1 or 1.4.3')
ap.add_argument('--update', type=Path, help='the update NSP: 1.1.0, 1.2.1 or 1.4.3')
ap.add_argument('--keys', type=Path, help='prod.keys')
ap.add_argument('--firmware', type=Path, help='Switch firmware folder (Contents/registered) for the shared fonts '
'of Chinese, Korean and Traditional Chinese text')
+1 -1
View File
@@ -37,7 +37,7 @@ from pathlib import Path
WIN = os.name == 'nt'
EXE = '.exe' if WIN else ''
UCRT = Path(r'C:\msys64\ucrt64\bin')
SUPPORTED = ('1.2.1', '1.4.3', '1.1.1') # updates the installer builds; the check identifies the player's by hash
SUPPORTED = ('1.2.1', '1.4.3', '1.1.0') # updates the installer builds; the check identifies the player's by hash
def version_tag(version):
+5 -5
View File
@@ -51,7 +51,7 @@
"check.vulkan_missing": "No Vulkan driver is installed. Install the latest driver for your graphics card.",
"check.vulkan_no_device": "Vulkan finds no graphics card. Install the latest driver for your graphics card.",
"check.vulkan_too_old": "The game needs a graphics card with Vulkan 1.3; found: {devices}. Update the graphics driver.",
"check.inputs_needed": "The game files are needed: choose the base game, the 1.1.1 or 1.2.1 or 1.4.3 update and prod.keys.",
"check.inputs_needed": "The game files are needed: choose the base game, the 1.1.0 or 1.2.1 or 1.4.3 update and prod.keys.",
"check.input_missing": "File not found ({input}): {path}",
"check.keys_unreadable": "The keys file cannot be read. Choose a prod.keys file.",
"check.keys_no_header_key": "The keys file has no header_key. Dump prod.keys from your console again.",
@@ -65,7 +65,7 @@
"check.base_is_update": "The base game file is an update. Choose the base game NSP or XCI (version 1.0.0) here and this file as the update.",
"check.base_combined": "The base game file holds several packages (base game, update or DLC in one file). Choose a base game dump that contains only the game.",
"check.update_not_nsp": "The update must be an NSP file.",
"check.update_is_base": "The update file holds a base game. Choose the 1.1.1 or 1.2.1 or 1.4.3 update NSP.",
"check.update_is_base": "The update file holds a base game. Choose the 1.1.0 or 1.2.1 or 1.4.3 update NSP.",
"check.update_not_totk": "The update file is not a Tears of the Kingdom update ({detail}).",
"check.exefs_failed": "The game code of the {input} file failed its checks; see {log}.",
"check.input_damaged": "The {input} file is damaged or incomplete: {path} ({detail}). Copy that file again from its source, or dump it again, then run the setup again.",
@@ -104,14 +104,14 @@
"ui.notice": "The folder this setup builds contains the game. It is for your own use only; do not share or upload it.",
"ui.keys_private": "The keys file is read in place. Its contents are never shown, copied or stored.",
"ui.base": "Base game (NSP or XCI)",
"ui.update": "Update 1.1.1 or 1.2.1 or 1.4.3 (NSP)",
"ui.update": "Update 1.1.0 or 1.2.1 or 1.4.3 (NSP)",
"ui.keys": "prod.keys",
"ui.firmware": "Firmware folder (optional)",
"ui.game_language": "Game language",
"ui.dest": "Install folder",
"ui.browse": "Browse...",
"ui.pick_game": "Choose the base game file",
"ui.pick_update": "Choose the 1.1.1 or 1.2.1 or 1.4.3 update file",
"ui.pick_update": "Choose the 1.1.0 or 1.2.1 or 1.4.3 update file",
"ui.pick_keys": "Choose prod.keys",
"ui.pick_firmware": "Choose the Switch firmware folder (Contents/registered)",
"ui.pick_dest": "Choose the install folder",
@@ -131,7 +131,7 @@
"ui.update_mode": "This folder holds an earlier installation. The setup continues or updates it; the game files are asked for only if they are needed again.",
"ui.need_dest": "Choose the install folder.",
"ui.need_base": "Choose the base game file.",
"ui.need_update": "Choose the 1.1.1 or 1.2.1 or 1.4.3 update file.",
"ui.need_update": "Choose the 1.1.0 or 1.2.1 or 1.4.3 update file.",
"ui.need_keys": "Choose the prod.keys file.",
"ui.need_lang": "Choose the game language.",
"ui.missing_base": "The base game file does not exist.",
+5 -5
View File
@@ -51,7 +51,7 @@
"check.vulkan_missing": "Драйвер Vulkan не установлен. Установите свежий драйвер видеокарты.",
"check.vulkan_no_device": "Vulkan не находит видеокарту. Установите свежий драйвер видеокарты.",
"check.vulkan_too_old": "Игре нужна видеокарта с Vulkan 1.3; найдено: {devices}. Обновите драйвер видеокарты.",
"check.inputs_needed": "Нужны игровые файлы: выберите базовую игру, обновление 1.1.1 или 1.2.1 или 1.4.3 и prod.keys.",
"check.inputs_needed": "Нужны игровые файлы: выберите базовую игру, обновление 1.1.0 или 1.2.1 или 1.4.3 и prod.keys.",
"check.input_missing": "Файл не найден ({input}): {path}",
"check.keys_unreadable": "Не удаётся прочитать файл ключей. Выберите файл prod.keys.",
"check.keys_no_header_key": "В файле ключей нет header_key. Снова получите prod.keys со своей консоли.",
@@ -65,7 +65,7 @@
"check.base_is_update": "Файл базовой игры — это обновление. Выберите здесь NSP или XCI базовой игры (версия 1.0.0), а этот файл укажите как обновление.",
"check.base_combined": "Файл базовой игры содержит несколько пакетов (игра, обновление или DLC в одном файле). Выберите дамп, в котором только базовая игра.",
"check.update_not_nsp": "Обновление должно быть файлом NSP.",
"check.update_is_base": "Файл обновления содержит базовую игру. Выберите NSP с обновлением 1.1.1 или 1.2.1 или 1.4.3.",
"check.update_is_base": "Файл обновления содержит базовую игру. Выберите NSP с обновлением 1.1.0 или 1.2.1 или 1.4.3.",
"check.update_not_totk": "Файл обновления — не обновление Tears of the Kingdom ({detail}).",
"check.exefs_failed": "Код игры из файла «{input}» не прошёл проверку; подробности в {log}.",
"check.input_damaged": "Файл «{input}» повреждён или скопирован не полностью: {path} ({detail}). Скопируйте этот файл заново из источника или сделайте дамп ещё раз, затем снова запустите установку.",
@@ -104,14 +104,14 @@
"ui.notice": "Папка, которую создаёт установка, содержит игру. Она предназначена только для личного использования: не передавайте и не выкладывайте её.",
"ui.keys_private": "Файл ключей читается на месте. Его содержимое не показывается, не копируется и не сохраняется.",
"ui.base": "Базовая игра (NSP или XCI)",
"ui.update": "Обновление 1.1.1 или 1.2.1 или 1.4.3 (NSP)",
"ui.update": "Обновление 1.1.0 или 1.2.1 или 1.4.3 (NSP)",
"ui.keys": "prod.keys",
"ui.firmware": "Папка прошивки (необязательно)",
"ui.game_language": "Язык игры",
"ui.dest": "Папка установки",
"ui.browse": "Обзор...",
"ui.pick_game": "Выберите файл базовой игры",
"ui.pick_update": "Выберите файл обновления 1.1.1 или 1.2.1 или 1.4.3",
"ui.pick_update": "Выберите файл обновления 1.1.0 или 1.2.1 или 1.4.3",
"ui.pick_keys": "Выберите prod.keys",
"ui.pick_firmware": "Выберите папку прошивки Switch (Contents/registered)",
"ui.pick_dest": "Выберите папку установки",
@@ -131,7 +131,7 @@
"ui.update_mode": "В этой папке уже есть установка. Программа продолжит или обновит её; файлы игры понадобятся, только если их снова придётся читать.",
"ui.need_dest": "Выберите папку установки.",
"ui.need_base": "Выберите файл базовой игры.",
"ui.need_update": "Выберите файл обновления 1.1.1 или 1.2.1 или 1.4.3.",
"ui.need_update": "Выберите файл обновления 1.1.0 или 1.2.1 или 1.4.3.",
"ui.need_keys": "Выберите файл prod.keys.",
"ui.need_lang": "Выберите язык игры.",
"ui.missing_base": "Файл базовой игры не найден.",
@@ -1,6 +1,6 @@
# Code patches for TotK 1.1.1 main (recomp/patches.py). The sites come from MacNativeGames
# Code patches for TotK 1.1.0 main (recomp/patches.py). The sites come from MacNativeGames
# games/totk/runtime/game_patches.c (MIT, Copyright (c) 2026 MacNativeGames contributors) at upstream ebe621d, through
# its 1.2.1 addresses in game_version.h (2db612b); each one was located again in 1.1.1 by instruction-window matching
# its 1.2.1 addresses in game_version.h (2db612b); each one was located again in 1.1.0 by instruction-window matching
# and its original words checked against this build's main. The patch page holds two floats the runtime writes at every
# present (frame_rate.c): +0 the 30 Hz ratio (seconds * 30), +4 the frame step in seconds.
@@ -35,7 +35,7 @@ site realtime main 90e5e8 1e210800 d503201f # fmul s0, s0, s1 -> nop
# Hair and cloth (upstream 290ec9f, 8f8022f): the actor animation update builds a second clock {seconds = factor / 30,
# ratio = factor} per rendered frame. Three inlined places: at the fmul, seconds = measured seconds * factor; at the
# store of the factor into the ratio slot, measured ratio * factor. The call of the shared update (1.1.1
# store of the factor into the ratio slot, measured ratio * factor. The call of the shared update (1.1.0
# main+0x8ecb40, 1.2.1 main+0x89822c) scales s2 (seconds) and s3 (ratio) by the measured ratio. Upstream's
# veneer bodies, inlined at the site.
site cloth main 9efc20 1e200900 f81f0fe9 @page:x9 bd400520 1e200900 f84107e9 # fmul s0, s8, s0
@@ -66,7 +66,7 @@ site scene main cea5e0 5e21d900 @page:x9 # scvtf s0, s8 -> adrp x9, page
site scene main cea5e8 bd0cc660 2d420520 # str s0, [x19, #0xcc4] -> ldp s0, s1, [x9, #16]
site scene main cea5ec 5e21d921 bd0cc660 # scvtf s1, s9 -> str s0, [x19, #0xcc4]
# Spin waits, from tools/spin_waits.py --exefs build/extracted/v111/exefs --patches recomp/patches-v111.txt: loops that only
# Spin waits, from tools/spin_waits.py --exefs build/extracted/v110/exefs --patches recomp/patches-v110.txt: loops that only
# another thread can end; their back-edges pass rt_spin_gate (runtime/kernel.c), TOTK_SPIN=0 keeps the core.
# spin waits found by tools/spin_waits.py on the 1.1.x modules
+7 -7
View File
@@ -4,7 +4,7 @@
// The boot driver: the guest main thread runs the game's own nn::init::Start
// with three host callbacks, the second of which runs DT_INIT of main, subsdk0 and sdk; Start then calls nnMain.
// --boot checks two checkpoints on the way and ends at the first nvnBootstrapLoader call, at the return address of
// each in main (1.1.1, 1.2.1, 1.4.3):
// each in main (1.1.0, 1.2.1, 1.4.3):
// SetFocusHandlingMode main+0xeb8c14 (1.2.1: +0xe7a954, 1.4.3: +0xbdb48c) in nnMain, every module's constructor
// flag reads 2
// nvnBootstrapLoader main+0xebcdec (1.2.1: +0xe7eb2c, 1.4.3: +0xbe0360) in the graphics bring-up; logs the
@@ -23,19 +23,19 @@
#include "platform/platform.h"
#define SYM_INIT_START "_ZN2nn4init5StartEmmPFvvES2_S2_"
// main: return addresses of nnMain's SetFocusHandlingMode call (1.1.1 and 1.2.1 from this port's analysis of main;
// main: return addresses of nnMain's SetFocusHandlingMode call (1.1.0 and 1.2.1 from this port's analysis of main;
// 1.4.3 from MacNativeGames' scripts/verify_boot.py) and of the first nvnBootstrapLoader call, per game version.
#define CHECKPOINT_RET (RT_V143 ? 0xbdb48cull : RT_V111 ? 0xeb8c14ull : 0xe7a954ull)
#define NVN_RET (RT_V143 ? 0xbe0360ull : RT_V111 ? 0xebcdecull : 0xe7eb2cull)
#define CHECKPOINT_RET (RT_V143 ? 0xbdb48cull : RT_V110 ? 0xeb8c14ull : 0xe7a954ull)
#define NVN_RET (RT_V143 ? 0xbe0360ull : RT_V110 ? 0xebcdecull : 0xe7eb2cull)
#define CTOR_DONE 2 // a module's constructor flag after its DT_INIT ran the init_array
// The init_array sizes (1.1.1 and 1.2.1: counted in the modules; 1.4.3: DT_INIT_ARRAYSZ); MacNativeGames' boot check
// The init_array sizes (1.1.0 and 1.2.1: counted in the modules; 1.4.3: DT_INIT_ARRAYSZ); MacNativeGames' boot check
// expects the same. The three tables carry the same rows, so cb_module_inits walks them by the size of one.
typedef struct { const char *name; uint64_t entries; } InitCount;
static const InitCount inits_111[] = {{"main", 10668}, {"subsdk0", 45}, {"sdk", 116}};
static const InitCount inits_110[] = {{"main", 10668}, {"subsdk0", 45}, {"sdk", 116}};
static const InitCount inits_121[] = {{"main", 10673}, {"subsdk0", 45}, {"sdk", 116}};
static const InitCount inits_143[] = {{"main", 10717}, {"subsdk0", 45}, {"sdk", 83}};
#define expected_inits (RT_V143 ? inits_143 : RT_V111 ? inits_111 : inits_121)
#define expected_inits (RT_V143 ? inits_143 : RT_V110 ? inits_110 : inits_121)
static volatile int32_t inits_done, checkpoint_seen;
uint64_t rt_guest_start_ns;
+3 -3
View File
@@ -180,13 +180,13 @@ static uint64_t read_ptr(uint64_t a) {
uint64_t p = 0;
return read_guest(a, &p, 8) ? p : 0;
}
// 1.2.1: [main+0x4728538] (1.1.1: [main+0x4630a68], 1.4.3: [main+0x3add238]) +0x1e8 scene, its component 13 lists the
// 1.2.1: [main+0x4728538] (1.1.0: [main+0x4630a68], 1.4.3: [main+0x3add238]) +0x1e8 scene, its component 13 lists the
// resident actors; the one named "Player" has its position at +0x2b4 (MacNativeGames world_survey.c, game_version.h
// TOTK_GAME_V121/V143). The 1.1.1 slot was measured from its own dereference chain: 181 scene accesses in that build
// TOTK_GAME_V121/V143). The 1.1.0 slot was measured from its own dereference chain: 181 scene accesses in that build
// read it, and one of them reproduces this walk (the 14-component check, component 13, the 0x70 stride and the name
// compare) instruction for instruction.
static int player_pos(float xyz[3]) {
uint64_t module = read_ptr(MOD_MAIN_BASE + (RT_V143 ? 0x3add238 : RT_V111 ? 0x4630a68 : 0x4728538)),
uint64_t module = read_ptr(MOD_MAIN_BASE + (RT_V143 ? 0x3add238 : RT_V110 ? 0x4630a68 : 0x4728538)),
scene = module ? read_ptr(module + 0x1e8) : 0;
int32_t count = 0;
if (!scene || !read_guest(scene + 0x50, &count, 4) || count < 14 || count > 256) return 0;
+3 -3
View File
@@ -53,9 +53,9 @@ static int hexval(char c) { return c <= '9' ? c - '0' : (c | 32) - 'a' + 10; }
// parent of totk.exe that has one with a jobs.json, the running game version's first, then the others' (any census
// serves a probe). 1 with that folder in dir.
int probe_census_dir(char *dir, size_t n) {
const char *const versions[3] = {RT_V111 ? "v111" : RT_V143 ? "v143" : "v121",
RT_V111 ? "v121" : RT_V143 ? "v121" : "v143",
RT_V111 ? "v143" : RT_V143 ? "v111" : "v111"};
const char *const versions[3] = {RT_V110 ? "v110" : RT_V143 ? "v143" : "v121",
RT_V110 ? "v121" : RT_V143 ? "v121" : "v143",
RT_V110 ? "v143" : RT_V143 ? "v110" : "v110"};
for (int v = 0; v < 3; v++) {
char exe[PLAT_PATH_MAX * 2];
int len = plat_exe_path(exe, sizeof exe);
+2 -2
View File
@@ -187,9 +187,9 @@ typedef struct { const char *file, *sha256; } RtFileHash;
extern const RtFileHash rt_exefs_sha256[]; // tools/data/expected-<version>.json "exefs_sha256"
extern const int rt_exefs_sha256_count;
extern const char rt_default_exefs[], rt_default_romfs[], rt_default_profile[];
extern const int rt_game_version; // the game build: 111 (1.1.1), 121 (1.2.1) or 143 (1.4.3)
extern const int rt_game_version; // the game build: 110 (1.1.0), 121 (1.2.1) or 143 (1.4.3)
extern const char rt_port_version[]; // VERSION at the build's root: 0.1.0, 0.1.0+973c626 in a release
#define RT_V111 (rt_game_version == 111) // 1.1.1: its own boot constants and data slots
#define RT_V110 (rt_game_version == 110) // 1.1.0: its own boot constants and data slots
#define RT_V143 (rt_game_version >= 143)
// ---- kernel (kernel.c)
+4 -4
View File
@@ -552,8 +552,8 @@ uint64_t ldr_plt_stub(const char *module, const char *name) {
}
// ---- --probe-loader
// Expected values, measured on the 1.1.1, 1.2.1 and 1.4.3 modules; the 1.4.3 relocation totals match the ones
// MacNativeGames' port notes give for that version. 1.1.1 shares subsdk0 and sdk with 1.2.1 down to every count.
// Expected values, measured on the 1.1.0, 1.2.1 and 1.4.3 modules; the 1.4.3 relocation totals match the ones
// MacNativeGames' port notes give for that version. 1.1.0 shares subsdk0 and sdk with 1.2.1 down to every count.
typedef struct {
const char *name;
uint64_t kinds[K_COUNT], total, sym_import, sym_own;
@@ -564,7 +564,7 @@ static const Expect expect_121[] = {
{"subsdk0", {1623, 12820, 1030, 3924}, 19397, 6576, 11198, 667, {9, 0, 654}, 4, 0x30, 45},
{"sdk", {10917, 13976, 1207, 8932}, 35032, 16, 24099, 13, {8, 0, 0}, 5, 0x30, 116},
};
static const Expect expect_111[] = {
static const Expect expect_110[] = {
{"main", {508604, 1412, 32, 639}, 510687, 2083, 0, 673, {0, 16, 645}, 12, 0x30, 10668},
{"subsdk0", {1623, 12820, 1030, 3924}, 19397, 6576, 11198, 667, {9, 0, 654}, 4, 0x30, 45},
{"sdk", {10917, 13976, 1207, 8932}, 35032, 16, 24099, 13, {8, 0, 0}, 5, 0x30, 116},
@@ -574,7 +574,7 @@ static const Expect expect_143[] = {
{"subsdk0", {3424, 10927, 905, 3817}, 19073, 6557, 9092, 663, {9, 0, 654}, 0, 0x20, 45},
{"sdk", {15013, 10135, 1079, 7832}, 34059, 10, 19036, 8, {8, 0, 0}, 0, 0x400, 83},
};
#define expect (RT_V143 ? expect_143 : RT_V111 ? expect_111 : expect_121)
#define expect (RT_V143 ? expect_143 : RT_V110 ? expect_110 : expect_121)
static int failures;
#define CHECK(cond, ...) do { if (!(cond)) { failures++; printf(" FAIL: " __VA_ARGS__); putchar('\n'); } } while (0)
+1 -1
View File
@@ -163,7 +163,7 @@ WINDRES = UCRT / 'windres.exe' # runtime/totk.rc: the manifest of totk.exe
TOOLCHAIN_BIN = None # llvm-mingw bin directory, set by main() for --toolchain
DEPS = None # the deps directory of an llvm-mingw build
# tools/data/expected-<display version>.json for each build version name.
DISPLAY_VERSIONS = {'v0': '1.0.0', 'v111': '1.1.1', 'v112': '1.1.2', 'v121': '1.2.1', 'v143': '1.4.3'}
DISPLAY_VERSIONS = {'v0': '1.0.0', 'v110': '1.1.0', 'v112': '1.1.2', 'v121': '1.2.1', 'v143': '1.4.3'}
GiB = 1 << 30
# Peak commit of one compile, 1.2.1 at -O1 (2026-10-20): 120-180 MiB per ~3 MiB chunk, 568 MiB for main_table.c
@@ -1,8 +1,8 @@
{
"_comment": "Written locally for the player's own 1.1.x update (version value 0x20000, seen as 1.1.1). RomFS hashes filled in after the first merge; no game data here. No rewritten_sha256: this dump was not run through MacNativeGames' NSO rewriter, so the three digests of the other versions have no reference here and none of the tools read them.",
"_comment": "Written locally for the player's own 1.1.0 update (version value 0x20000). RomFS hashes filled in after the first merge; no game data here. No rewritten_sha256: this dump was not run through MacNativeGames' NSO rewriter, so the three digests of the other versions have no reference here and none of the tools read them.",
"title_id": "0100F2C0115B6000",
"version": 131072,
"display_version": "1.1.1",
"display_version": "1.1.0",
"exefs_sha256": {
"main": "1664b8cf664524d90ca64deb3ce41709266457df966dcb499485267554eb8cec",
"main.npdm": "fa3f60922406ab9e2488c2b8d77b12e9869b435033fd8c27c543c347bc185587",
+4 -4
View File
@@ -1,6 +1,6 @@
# Adapted from MacNativeGames games/totk/scripts/make_romfs_patches.py @ ebe621d (MIT, Copyright (c) 2026
# MacNativeGames contributors).
"""Build the 60 fps RomFS overlay for TotK 1.1.1, 1.2.1 or 1.4.3 (runtime/romfs.c, TOTK_ROMFS_PATCHES).
"""Build the 60 fps RomFS overlay for TotK 1.1.0, 1.2.1 or 1.4.3 (runtime/romfs.c, TOTK_ROMFS_PATCHES).
UI/LayoutArchive/Common.Product.<110 or 140>.Nin_NX_NVN.blarc.zs: the weapon / shield / material quick menus capture the game
picture for their background when the panes C_CaptureBG_00, C_CaptureClearBG_00 and P_CaptureClearBG_00 become
@@ -8,7 +8,7 @@ visible at animation frame 1.0 (anim/ShortCutBG_00_In.bflan), AutoBuilder the sa
(anim/AutoBuilder_00_In.bflan). UI animations advance 0.5 frames per game frame at 60 fps, so the capture lands after
the world stopped drawing and the background can be black. The visibility keys move to frame 0.0: the live world is
captured at once (upstream checked weapon, shield, material and ability wheel at 60 fps, and 30 fps).
The game-over flow fix of the same upstream script is 1.0.0 only (1.1.1, 1.2.1 and 1.4.3 run DmF_SY_GameOver.110) and is
The game-over flow fix of the same upstream script is 1.0.0 only (1.1.0, 1.2.1 and 1.4.3 run DmF_SY_GameOver.110) and is
left out.
--aspect <w>x<h> (a game resolution of another shape than 16:9, such as 3440x1440 or 1280x800) also lays the UI out
@@ -53,7 +53,7 @@ from pathlib import Path
root = Path(__file__).resolve().parents[1]
ap = argparse.ArgumentParser(description=__doc__.splitlines()[0])
ap.add_argument('--version', choices=('v111', 'v121', 'v143'), default='v121')
ap.add_argument('--version', choices=('v110', 'v121', 'v143'), default='v121')
ap.add_argument('--romfs', type=Path, help='default build/extracted/<version>/romfs')
ap.add_argument('--out', type=Path,
help='default build/<version>/romfs-patches (romfs-patches-<style> with --prompts)')
@@ -208,7 +208,7 @@ def sarc_replace(data, new):
return bytes(out)
COMMON = {'v111': '110', 'v121': '110', 'v143': '140'} # the version in the name of each game's Common archive
COMMON = {'v110': '110', 'v121': '110', 'v143': '140'} # the version in the name of each game's Common archive
ARCHIVE = f'UI/LayoutArchive/Common.Product.{COMMON[args.version]}.Nin_NX_NVN.blarc.zs'
MEMBERS = {
'anim/ShortCutBG_00_In.bflan': ('C_CaptureBG_00', 'C_CaptureClearBG_00', 'P_CaptureClearBG_00'),
+1 -1
View File
@@ -156,7 +156,7 @@ def main():
extracted = ROOT / 'build' / 'extracted' / a.version
listed = len(variants)
shaders, _ = inventory(a.romfs or extracted / 'romfs', a.exefs or extracted / 'exefs', everything=False)
# A missing list row says nothing about the walk: the list covers several versions, and 1.1.1 holds 17,587 of its
# A missing list row says nothing about the walk: the list covers several versions, and 1.1.0 holds 17,587 of its
# 41,414 rows, so most rows are absent because the game does not have them, not because the walk missed them. A walk
# that found next to nothing does say something: the shader directories have moved.
if len(shaders) < max(64, listed // 20):
+1 -1
View File
@@ -173,7 +173,7 @@ def startup_package(name):
# The RomFS directories that can hold shaders: the agl and gsys packages, the effects, terrain, the UI layout archives
# and the game's own shader packs. Every shader of 1.1.1 (27,576) comes from these six; they are 1,996 entries and
# and the game's own shader packs. Every shader of 1.1.0 (27,576) comes from these six; they are 1,996 entries and
# 147 MiB, 0.9% of a RomFS whose every file the walk below used to read and decompress first (65 s against 2.8 s).
SHADER_DIRS = ('Shader/', 'Effect/', 'Lib/agl/', 'Lib/Terrain/', 'Lib/gsys/', 'UI/LayoutArchive/')