mirror of
https://github.com/tangerineturtle1/NX2navi.git
synced 2026-11-15 19:19:58 -04:00
The physics' two water managers and the game's interactive floor simulation (the Deku Tree's ground webs) step their surfaces in fixed steps of 1/60 s, as many whole steps as the frame's time holds, and drop the fraction, so every frame shorter than 1/60 s ran none and the surfaces stood still above 60 fps. The new set owater (water_steps, on by default) calls the page between the division and the game's cut, which keeps the fraction per object; at 60 fps the count is the game's. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
100 lines
3.8 KiB
C
100 lines
3.8 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. 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
|
|
|
|
// The debug menu's free camera (debug_tools.c dbg_freecam_host): the site of the set freecam calls the page's +0xf70.
|
|
// Registered here, in the file that has the game version's page address.
|
|
#ifdef RT_PATCH_PAGE
|
|
#include "debug_tools.h"
|
|
__attribute__((constructor)) static void freecam_register(void) { rt_register_host(RT_PATCH_PAGE + 0xf70, dbg_freecam_host); }
|
|
// The time of day's site of the set ostep (patches-v111.txt) calls the page's +0xf60, the water renderer's site its
|
|
// +0xf50, and the surfaces' fixed-step sites of the set owater its +0xf20 (frame_rate.c).
|
|
__attribute__((constructor)) static void day_register(void) {
|
|
if (!RT_V111) return;
|
|
rt_register_host(RT_PATCH_PAGE + 0xf60, frame_rate_day_host);
|
|
rt_register_host(RT_PATCH_PAGE + 0xf50, frame_rate_water_host);
|
|
rt_register_host(RT_PATCH_PAGE + 0xf20, frame_rate_sim_host);
|
|
}
|
|
#endif
|
|
|
|
#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
|
|
}
|