Update modern runtime for mod support, add some exports and events in the patches

This commit is contained in:
Mr-Wiseguy 2024-09-02 12:01:22 -04:00
parent d4a8cd351e
commit 5a8de31e82
12 changed files with 50 additions and 21 deletions

@ -1 +1 @@
Subproject commit 0a538553330ea5fdb1673708704bb92a854241b9 Subproject commit 5699906f34fcc82905303092d081ad92aa74f926

View File

@ -14,3 +14,5 @@ data_reference_syms_files = [ "Zelda64RecompSyms/mm.us.rev1.datasyms.toml", "Zel
output_binary_path = "patches/patches.bin" output_binary_path = "patches/patches.bin"
# Do not emit warnings for unpaired LO16 values, as clang produces many of them. # Do not emit warnings for unpaired LO16 values, as clang produces many of them.
unpaired_lo16_warnings = false unpaired_lo16_warnings = false
# Allow exporting functions and events for mods to use.
allow_exports = true

View File

@ -67,10 +67,10 @@ RECOMP_PATCH void KaleidoSetup_Update(PlayState* play) {
void Sram_SyncWriteToFlash(SramContext* sramCtx, s32 curPage, s32 numPages); void Sram_SyncWriteToFlash(SramContext* sramCtx, s32 curPage, s32 numPages);
void autosave_reset_timer(); void recomp_reset_autosave_timer();
void autosave_reset_timer_slow(); void recomp_reset_autosave_timer_slow();
void do_autosave(PlayState* play) { RECOMP_EXPORT void recomp_do_autosave(PlayState* play) {
// Transfer the scene flags into the cycle flags. // Transfer the scene flags into the cycle flags.
Play_SaveCycleSceneFlags(&play->state); Play_SaveCycleSceneFlags(&play->state);
// Transfer the cycle flags into the save buffer. Logic copied from func_8014546C. // Transfer the cycle flags into the save buffer. Logic copied from func_8014546C.
@ -176,7 +176,7 @@ RECOMP_PATCH void func_8014546C(SramContext* sramCtx) {
// @recomp Delete the owl save. // @recomp Delete the owl save.
delete_owl_save(sramCtx, gSaveContext.fileNum); delete_owl_save(sramCtx, gSaveContext.fileNum);
// @recomp Reset the autosave timer. // @recomp Reset the autosave timer.
autosave_reset_timer(); recomp_reset_autosave_timer();
for (i = 0; i < ARRAY_COUNT(gSaveContext.cycleSceneFlags); i++) { for (i = 0; i < ARRAY_COUNT(gSaveContext.cycleSceneFlags); i++) {
gSaveContext.save.saveInfo.permanentSceneFlags[i].chest = gSaveContext.cycleSceneFlags[i].chest; gSaveContext.save.saveInfo.permanentSceneFlags[i].chest = gSaveContext.cycleSceneFlags[i].chest;
gSaveContext.save.saveInfo.permanentSceneFlags[i].switch0 = gSaveContext.cycleSceneFlags[i].switch0; gSaveContext.save.saveInfo.permanentSceneFlags[i].switch0 = gSaveContext.cycleSceneFlags[i].switch0;
@ -344,11 +344,11 @@ void draw_autosave_icon(PlayState* play) {
CLOSE_DISPS(play->state.gfxCtx); CLOSE_DISPS(play->state.gfxCtx);
} }
void show_autosave_icon() { RECOMP_EXPORT void recomp_show_autosave_icon() {
autosave_icon_counter = AUTOSAVE_ICON_TOTAL_FRAMES; autosave_icon_counter = AUTOSAVE_ICON_TOTAL_FRAMES;
} }
u32 recomp_autosave_interval() { RECOMP_EXPORT u32 recomp_autosave_interval() {
return 2 * 60 * 1000; return 2 * 60 * 1000;
} }
@ -367,12 +367,12 @@ bool reached_final_three_hours() {
return false; return false;
} }
void autosave_reset_timer() { RECOMP_EXPORT void recomp_reset_autosave_timer() {
last_autosave_time = osGetTime(); last_autosave_time = osGetTime();
extra_autosave_delay_milliseconds = 0; extra_autosave_delay_milliseconds = 0;
} }
void autosave_reset_timer_slow() { RECOMP_EXPORT void recomp_reset_autosave_timer_slow() {
// Set the most recent autosave time in the future to give extra time before an autosave triggers. // Set the most recent autosave time in the future to give extra time before an autosave triggers.
last_autosave_time = osGetTime(); last_autosave_time = osGetTime();
extra_autosave_delay_milliseconds = 2 * 60 * 1000; extra_autosave_delay_milliseconds = 2 * 60 * 1000;
@ -425,20 +425,20 @@ void autosave_post_play_update(PlayState* play) {
frames_since_autosave_ready >= MIN_FRAMES_SINCE_READY && frames_since_autosave_ready >= MIN_FRAMES_SINCE_READY &&
time_now - last_autosave_time > (OS_USEC_TO_CYCLES(1000 * (recomp_autosave_interval() + extra_autosave_delay_milliseconds))) time_now - last_autosave_time > (OS_USEC_TO_CYCLES(1000 * (recomp_autosave_interval() + extra_autosave_delay_milliseconds)))
) { ) {
do_autosave(play); recomp_do_autosave(play);
show_autosave_icon(); recomp_show_autosave_icon();
autosave_reset_timer(); recomp_reset_autosave_timer();
} }
} }
else { else {
// Update the last autosave time to the current time to prevent autosaving immediately if autosaves are turned back on. // Update the last autosave time to the current time to prevent autosaving immediately if autosaves are turned back on.
autosave_reset_timer(); recomp_reset_autosave_timer();
} }
gCanPause = false; gCanPause = false;
} }
void autosave_init() { void autosave_init() {
autosave_reset_timer_slow(); recomp_reset_autosave_timer_slow();
Lib_MemCpy(&prev_save_ctx, &gSaveContext, offsetof(SaveContext, fileNum)); Lib_MemCpy(&prev_save_ctx, &gSaveContext, offsetof(SaveContext, fileNum));
} }
@ -705,7 +705,7 @@ RECOMP_PATCH void Sram_ResetSaveFromMoonCrash(SramContext* sramCtx) {
gSaveContext.jinxTimer = 0; gSaveContext.jinxTimer = 0;
// @recomp Use the slow autosave timer to give the player extra time to respond to the moon crashing to decide if they want to reload their autosave. // @recomp Use the slow autosave timer to give the player extra time to respond to the moon crashing to decide if they want to reload their autosave.
autosave_reset_timer_slow(); recomp_reset_autosave_timer_slow();
} }

View File

@ -4,6 +4,11 @@
#define RECOMP_EXPORT __attribute__((section(".recomp_export"))) #define RECOMP_EXPORT __attribute__((section(".recomp_export")))
#define RECOMP_PATCH __attribute__((section(".recomp_patch"))) #define RECOMP_PATCH __attribute__((section(".recomp_patch")))
#define RECOMP_FORCE_PATCH __attribute__((section(".recomp_force_patch"))) #define RECOMP_FORCE_PATCH __attribute__((section(".recomp_force_patch")))
#define RECOMP_DECLARE_EVENT(func) \
_Pragma("GCC diagnostic push") \
_Pragma("GCC diagnostic ignored \"-Wunused-parameter\"") \
__attribute__((noinline, weak, used, section(".recomp_event"))) void func {} \
_Pragma("GCC diagnostic pop")
// TODO fix renaming symbols in patch recompilation // TODO fix renaming symbols in patch recompilation
#define osCreateMesgQueue osCreateMesgQueue_recomp #define osCreateMesgQueue osCreateMesgQueue_recomp

View File

@ -1,5 +1,5 @@
RAMBASE = 0x80801000; /* Used to hold any new symbols */ RAMBASE = 0x80801000; /* Used to hold any new symbols */
EXTRA_RAM_SIZE = 0x01000000; /* Amount of extra ram allocated by recomp */ PATCH_RAM_END = 0x81000000; /* Amount of extra ram allocated by recomp */
MEMORY { MEMORY {
extram : ORIGIN = RAMBASE, LENGTH = 64M extram : ORIGIN = RAMBASE, LENGTH = 64M
@ -12,10 +12,11 @@ SECTIONS {
.text : { *(.text*) } >extram AT >rom .text : { *(.text*) } >extram AT >rom
.recomp_patch : { *(.recomp_patch*) *(.recomp_force_patch*) } >extram AT >rom .recomp_patch : { *(.recomp_patch*) *(.recomp_force_patch*) } >extram AT >rom
.recomp_export : { *(.recomp_export*) } >extram AT >rom .recomp_export : { *(.recomp_export*) } >extram AT >rom
.recomp_event : { *(.recomp_event*) } >extram AT >rom
.rodata : { *(.rodata*) } >extram AT >rom .rodata : { *(.rodata*) } >extram AT >rom
.data : { *(.data*) } >extram AT >rom .data : { *(.data*) } >extram AT >rom
.bss (NOLOAD) : { *(.bss*) *(COMMON) } >extram .bss (NOLOAD) : { *(.bss*) *(COMMON) } >extram
ASSERT(. < RAMBASE + EXTRA_RAM_SIZE, "Maxed out recomp extra ram") ASSERT(. <= PATCH_RAM_END, "Maxed out recomp extra ram")
.reloc 0 : { *(.reloc*) } .reloc 0 : { *(.reloc*) }
.symtab 0 : { *(.symtab) } .symtab 0 : { *(.symtab) }

View File

@ -4,6 +4,10 @@
extern Input D_801F6C18; extern Input D_801F6C18;
RECOMP_DECLARE_EVENT(recomp_on_play_main(PlayState* play));
RECOMP_DECLARE_EVENT(recomp_before_play_update(PlayState* play));
RECOMP_DECLARE_EVENT(recomp_after_play_update(PlayState* play));
void controls_play_update(PlayState* play) { void controls_play_update(PlayState* play) {
gSaveContext.options.zTargetSetting = recomp_get_targeting_mode(); gSaveContext.options.zTargetSetting = recomp_get_targeting_mode();
} }
@ -12,6 +16,7 @@ void controls_play_update(PlayState* play) {
RECOMP_PATCH void Play_Main(GameState* thisx) { RECOMP_PATCH void Play_Main(GameState* thisx) {
static Input* prevInput = NULL; static Input* prevInput = NULL;
PlayState* this = (PlayState*)thisx; PlayState* this = (PlayState*)thisx;
recomp_on_play_main(this);
// @recomp // @recomp
debug_play_update(this); debug_play_update(this);
@ -32,7 +37,9 @@ RECOMP_PATCH void Play_Main(GameState* thisx) {
this->state.gfxCtx = NULL; this->state.gfxCtx = NULL;
} }
camera_pre_play_update(this); camera_pre_play_update(this);
recomp_before_play_update(this);
Play_Update(this); Play_Update(this);
recomp_after_play_update(this);
camera_post_play_update(this); camera_post_play_update(this);
analog_cam_post_play_update(this); analog_cam_post_play_update(this);
autosave_post_play_update(this); autosave_post_play_update(this);

View File

@ -6,7 +6,7 @@ void* proutPrintf(void* dst, const char* fmt, size_t size) {
return (void*)1; return (void*)1;
} }
int recomp_printf(const char* fmt, ...) { RECOMP_EXPORT int recomp_printf(const char* fmt, ...) {
va_list args; va_list args;
va_start(args, fmt); va_start(args, fmt);

View File

@ -1266,7 +1266,7 @@ extern Gfx ovl_En_Tanron1_DL_001888[];
extern Gfx ovl_En_Tanron1_DL_001900[]; extern Gfx ovl_En_Tanron1_DL_001900[];
// @recomp Patched to interpolate the moths that circle torches. // @recomp Patched to interpolate the moths that circle torches.
void func_80BB5AAC(EnTanron1* this, PlayState* play) { RECOMP_PATCH void func_80BB5AAC(EnTanron1* this, PlayState* play) {
EnTanron1Struct* ptrBase = &this->unk_160[0]; EnTanron1Struct* ptrBase = &this->unk_160[0];
s16 i; s16 i;
u8 flag = 0; u8 flag = 0;

View File

@ -27,6 +27,7 @@
#include "zelda_render.h" #include "zelda_render.h"
#include "ovl_patches.hpp" #include "ovl_patches.hpp"
#include "librecomp/game.hpp" #include "librecomp/game.hpp"
#include "librecomp/mods.hpp"
#ifdef _WIN32 #ifdef _WIN32
#define WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN
@ -327,6 +328,7 @@ std::vector<recomp::GameEntry> supported_games = {
.rom_hash = 0xEF18B4A9E2386169ULL, .rom_hash = 0xEF18B4A9E2386169ULL,
.internal_name = "ZELDA MAJORA'S MASK", .internal_name = "ZELDA MAJORA'S MASK",
.game_id = u8"mm.n64.us.1.0", .game_id = u8"mm.n64.us.1.0",
.mod_game_id = "mm",
.is_enabled = true, .is_enabled = true,
.entrypoint_address = get_entrypoint_address(), .entrypoint_address = get_entrypoint_address(),
.entrypoint = recomp_entrypoint, .entrypoint = recomp_entrypoint,
@ -568,6 +570,8 @@ int main(int argc, char** argv) {
fprintf(stderr, "Failed to load controller mappings: %s\n", SDL_GetError()); fprintf(stderr, "Failed to load controller mappings: %s\n", SDL_GetError());
} }
recomp::register_config_path(zelda64::get_app_folder_path());
// Register supported games and patches // Register supported games and patches
for (const auto& game : supported_games) { for (const auto& game : supported_games) {
recomp::register_game(game); recomp::register_game(game);
@ -575,8 +579,6 @@ int main(int argc, char** argv) {
zelda64::register_overlays(); zelda64::register_overlays();
zelda64::register_patches(); zelda64::register_patches();
recomp::register_config_path(zelda64::get_app_folder_path());
zelda64::load_config(); zelda64::load_config();
recomp::rsp::callbacks_t rsp_callbacks{ recomp::rsp::callbacks_t rsp_callbacks{
@ -619,7 +621,10 @@ int main(int argc, char** argv) {
.get_game_thread_name = zelda64::get_game_thread_name, .get_game_thread_name = zelda64::get_game_thread_name,
}; };
recomp::mods::scan_mods();
recomp::start( recomp::start(
64 * 1024 * 1024, // 64MB to have plenty of room for loading mods
{}, {},
rsp_callbacks, rsp_callbacks,
renderer_callbacks, renderer_callbacks,

View File

@ -7,4 +7,6 @@
void zelda64::register_patches() { void zelda64::register_patches() {
recomp::overlays::register_patches(mm_patches_bin, sizeof(mm_patches_bin), section_table, ARRLEN(section_table)); recomp::overlays::register_patches(mm_patches_bin, sizeof(mm_patches_bin), section_table, ARRLEN(section_table));
recomp::overlays::register_base_exports(export_table);
recomp::overlays::register_base_events(event_name_table);
} }

View File

@ -1287,6 +1287,12 @@ void draw_hook(RT64::RenderCommandList* command_list, RT64::RenderFramebuffer* s
static recompui::Menu prev_menu = recompui::Menu::None; static recompui::Menu prev_menu = recompui::Menu::None;
recompui::Menu cur_menu = open_menu.load(); recompui::Menu cur_menu = open_menu.load();
// Return to the launcher if no menu is open and the game isn't started.
if (cur_menu == recompui::Menu::None && !ultramodern::is_game_started()) {
cur_menu = recompui::Menu::Launcher;
recompui::set_current_menu(cur_menu);
}
if (reload_sheets) { if (reload_sheets) {
ui_context->rml.load_documents(); ui_context->rml.load_documents();
prev_menu = recompui::Menu::None; prev_menu = recompui::Menu::None;

View File

@ -5,6 +5,7 @@ entrypoint = 0x80080000
# Paths are relative to the location of this config file. # Paths are relative to the location of this config file.
output_func_path = "RecompiledFuncs" output_func_path = "RecompiledFuncs"
relocatable_sections_path = "overlays.us.rev1.txt" relocatable_sections_path = "overlays.us.rev1.txt"
# elf_path = "mm.us.rev1.rom_uncompressed.elf"
symbols_file_path = "Zelda64RecompSyms/mm.us.rev1.syms.toml" symbols_file_path = "Zelda64RecompSyms/mm.us.rev1.syms.toml"
rom_file_path = "mm.us.rev1.rom_uncompressed.z64" rom_file_path = "mm.us.rev1.rom_uncompressed.z64"