Files
Valiantsin DzerakhandClaude Opus 5.5 cd60d20a7f Boot 1.4.3 to its first NVN call with the 1.4.3 patch table, loader values and SDK 20.5 swkbd layout
recomp/patches-v143.txt ports MacNativeGames' 1.4.3 fps60, real-time step, cloth and bounce sites; the real-time
producer reads the nominal interval from patch page +8, which frame_rate.c now writes as seconds * 60.
make_romfs_patches.py takes --version (Common.Product.140 on 1.4.3).

SDK 20.5 grew KeyboardConfig to 0x518 bytes, so ShowKeyboardArg's work buffer is at +0x518; swkbd_win.c and the
services probe pick the offset by version. 1.4.3's movie::Decoder vtable names the complete-object destructor D1,
which gets the D2 override. The loader probe has the measured 1.4.3 import and relocation counts, and probe-ipc
expects REV15 from the 1.4.3 SDK and skips the 1.2.1 sf heap constructors (1.4.3 creates the audio heap lazily).
A non-1.2.1 build defaults to its own profile, build/profile-<version>: 1.4.3 rewrites the saves it loads.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 17:50:40 +03:00

85 lines
3.0 KiB
C

// Code patch sets (recomp/patches.py, gen.py --patches). The generator lifts both the original and the replacement
// instructions of every patched site, and rt_patch_on[set] picks one when the site runs, so a set is switched at start
// without touching code, and also while the game runs (rt_patch_switch: the frame-limit setting of the menu). The sets,
// their environment switches and defaults, and the patch page come from the generated patches.h; without it (C
// generated without --patches) there are no sets and every site runs the original.
//
// The patch page is the first 4 KiB page after main's image, inside the module window memory.c reserved: replacement
// code reaches it with one adrp, as MacNativeGames' data page after main (games/totk/runtime/game_patches.c). Its
// layout belongs to the sets that use it (frame_rate.c: +0 the 30 Hz ratio, +4 the frame step in seconds, +8 the
// step in 60 Hz ticks).
// Probe modes never call rt_patches_init: every set stays off.
#include "cfg.h"
#include "platform/platform.h"
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "host.h"
#if __has_include("patches.h")
#include "patches.h"
#endif
#ifndef RT_PATCH_COUNT
#define RT_PATCH_COUNT 0
#endif
uint8_t rt_patch_on[RT_PATCH_COUNT > 0 ? RT_PATCH_COUNT : 1]; // read by the generated C at every patched site
#if RT_PATCH_COUNT
static const struct { const char *name, *env; int on; } sets[] = {
#define X(i, n, e, d) {#n, e, d},
RT_PATCH_SETS(X)
#undef X
};
static void *page;
#endif
void rt_patches_init(void) {
#if RT_PATCH_COUNT
if (!plat_mem_commit(RT_PATCH_PAGE, 0x1000))
rt_fatal("patches: cannot commit the patch page at %#llx", RT_PATCH_PAGE);
page = (void *)(uintptr_t)RT_PATCH_PAGE;
char list[512];
size_t n = 0;
list[0] = 0;
for (int i = 0; i < RT_PATCH_COUNT; i++) {
const char *e = cfg_get(sets[i].env);
// a set with a row in the settings table takes its default from there; the generated default serves the rest
rt_patch_on[i] = (uint8_t)(cfg_meta(sets[i].env) ? cfg_bool(sets[i].env) : e && *e ? strcmp(e, "0") != 0 : sets[i].on);
n += (size_t)snprintf(list + n, sizeof list - n, "%s%s %s", i ? ", " : "", sets[i].name,
rt_patch_on[i] ? "on" : "off");
if (n >= sizeof list) n = sizeof list - 1;
}
rt_log("patches: %s (page %#llx)", list, RT_PATCH_PAGE);
#endif
}
int rt_patch_set(const char *name) {
#if RT_PATCH_COUNT
for (int i = 0; i < RT_PATCH_COUNT; i++)
if (!strcmp(sets[i].name, name)) return i;
#endif
(void)name;
return -1;
}
int rt_patch_enabled(int set) { return set >= 0 && set < RT_PATCH_COUNT && rt_patch_on[set]; }
void rt_patch_disable(int set) {
if (set >= 0 && set < RT_PATCH_COUNT) rt_patch_on[set] = 0;
}
void rt_patch_switch(int set, int on) {
if (set >= 0 && set < RT_PATCH_COUNT) __atomic_store_n(&rt_patch_on[set], (uint8_t)(on != 0), __ATOMIC_RELAXED);
}
void *rt_patch_page(void) {
#if RT_PATCH_COUNT
return page;
#else
return NULL;
#endif
}