From c86d6918d60d4bc2dc0e846886eb934a60b868f7 Mon Sep 17 00:00:00 2001 From: TakaRikka Date: Thu, 20 Aug 2026 00:22:01 -0700 Subject: [PATCH 1/2] hook up game mode service --- mods/randomizer/src/mod.cpp | 19 +++++---- mods/randomizer/src/session.cpp | 72 +++++++++++++++++++++++++++------ mods/randomizer/src/session.hpp | 7 ++++ 3 files changed, 75 insertions(+), 23 deletions(-) diff --git a/mods/randomizer/src/mod.cpp b/mods/randomizer/src/mod.cpp index 88edc0e9ab..f7869de603 100644 --- a/mods/randomizer/src/mod.cpp +++ b/mods/randomizer/src/mod.cpp @@ -16,11 +16,14 @@ IMPORT_SERVICE(ConfigService, svc_config); IMPORT_SERVICE(SaveService, svc_save); IMPORT_SERVICE(StageService, svc_stage); IMPORT_SERVICE(ItemService, svc_item); +IMPORT_SERVICE(FlowService, svc_flow); +IMPORT_SERVICE(MessageService, svc_message); +IMPORT_SERVICE(GameModeService, svc_game_mode); extern "C" { MOD_EXPORT ModResult mod_initialize(ModError* error) { - ModResult result = randomizer::session::initialize({ + ModResult result = randomizer::session::initialize({ mod_ctx, svc_host, svc_log, @@ -31,16 +34,14 @@ MOD_EXPORT ModResult mod_initialize(ModError* error) { svc_save, svc_stage, svc_item, + svc_flow, + svc_message, + svc_game_mode, }); if (result != MOD_OK) { return mods::set_error(error, result, "failed to initialize session"); } - result = randomizer::hooks::initialize(); - if (result != MOD_OK) { - return mods::set_error(error, result, "failed to initialize hooks"); - } - result = randomizer::ui::initialize(); if (result != MOD_OK) { return mods::set_error(error, result, "failed to initialize ui"); @@ -51,14 +52,12 @@ MOD_EXPORT ModResult mod_initialize(ModError* error) { } MOD_EXPORT ModResult mod_update(ModError*) { - randomizer::ui::update(); - randomizer::session::update(); + // we register update function with game mode service, so no need to do anything here return MOD_OK; } MOD_EXPORT ModResult mod_shutdown(ModError*) { - randomizer::session::deactivateSeed(); - randomizer::hooks::uninstall(); + randomizer::session::shutdown(); svc_log->info(mod_ctx, "randomizer unloaded"); return MOD_OK; } diff --git a/mods/randomizer/src/session.cpp b/mods/randomizer/src/session.cpp index ee88e8dca9..d3c4e54541 100644 --- a/mods/randomizer/src/session.cpp +++ b/mods/randomizer/src/session.cpp @@ -3,6 +3,8 @@ #include #include "randomizer_context.hpp" +#include "hooks.hpp" +#include "ui/ui.hpp" #include "flags.h" #include "item_ids.h" #include "tools.h" @@ -337,31 +339,38 @@ void registerStartingLocation() { dComIfGp_setNextStage("F_SP103", 1, 1, -1); } -void onNewSave(ModContext*, uint32_t, void*) { +void shutdown() { + deactivateSeed(); + hooks::uninstall(); + svc_mng.save->unobserve_saves(mod_ctx, s_save_observer); +} + +ModResult onNewSave(void*, ModError*) { const std::string hash = g_pending_seed_hash; if (hash.empty()) - return; + return MOD_ERROR; if (!activateSeed(hash.c_str())) - return; + return MOD_ERROR; svc_mng.save->set_blob(svc_mng.mod_ctx, kSeedHashBlobName, hash.data(), hash.size()); setupRandomizerFile(); + return MOD_OK; } -void onSaveLoaded(ModContext*, uint32_t, void*) { +ModResult onSaveLoaded(void*, ModError*) { size_t size = 0; if (svc_mng.save->get_blob(mod_ctx, kSeedHashBlobName, nullptr, &size) != MOD_OK || size == 0) { mods::log::error("seed_hash not found!"); deactivateSeed(); - return; + return MOD_ERROR; } std::string hash(size, '\0'); if (svc_mng.save->get_blob(mod_ctx, kSeedHashBlobName, hash.data(), &size) != MOD_OK) { mods::log::error("failed to get seed_hash!"); deactivateSeed(); - return; + return MOD_ERROR; } if (randomizer_GetContext().mHash != hash) { @@ -370,6 +379,7 @@ void onSaveLoaded(ModContext*, uint32_t, void*) { } loadAncientDocumentNum(); + return MOD_OK; } void onSaveWritten(ModContext*, uint32_t, void*) { @@ -377,20 +387,56 @@ void onSaveWritten(ModContext*, uint32_t, void*) { svc_mng.save->set_blob(svc_mng.mod_ctx, kSeedHashBlobName, hash.data(), hash.size()); } -ModResult initialize(const ServiceManager& services) { - svc_mng = services; +ModResult onGameModeActivated(void*, ModError* error) { + ModResult result = hooks::initialize(); + if (result != MOD_OK) { + return mods::set_error(error, result, "failed to initialize hooks"); + } - ModResult rt = svc_mng.save->observe_saves( + result = svc_mng.save->observe_saves( svc_mng.mod_ctx, - onNewSave, - onSaveLoaded, + nullptr, + nullptr, onSaveWritten, nullptr, &s_save_observer); - if (rt != MOD_OK) { - return rt; + if (result != MOD_OK) { + return mods::set_error(error, result, "failed to initialize save observation"); } + mods::log::info("randomizer game mode activated"); + return MOD_OK; +} + +ModResult onGameModeDeactivated(void*, ModError* error) { + shutdown(); + + mods::log::info("randomizer game mode deactivated"); + return MOD_OK; +} + +ModResult onGameModeUpdate(void*, ModError* error) { + ui::update(); + session::update(); + return MOD_OK; +} + +ModResult initialize(const ServiceManager& services) { + svc_mng = services; + + const GameModeDesc gameModeDesc = { + .struct_size = sizeof(GameModeDesc), + .game_mode_id = "randomizer", + .full_name = "Randomizer", + .save_name = "randomizer", + .user_data = nullptr, + .on_activated = onGameModeActivated, + .on_deactivated = onGameModeDeactivated, + .on_save_loaded = onSaveLoaded, + .on_new_save = onNewSave, + .on_tick = onGameModeUpdate, + }; + svc_mng.game_mode->register_game_mode(mod_ctx, &gameModeDesc); return MOD_OK; } diff --git a/mods/randomizer/src/session.hpp b/mods/randomizer/src/session.hpp index 002bba97d3..9d485da0ae 100644 --- a/mods/randomizer/src/session.hpp +++ b/mods/randomizer/src/session.hpp @@ -9,6 +9,9 @@ #include "mods/svc/save.h" #include "mods/svc/stage.h" #include "mods/svc/item.h" +#include "mods/svc/flow.h" +#include "mods/svc/message.h" +#include "mods/svc/game_mode.h" #include @@ -24,6 +27,9 @@ struct ServiceManager { const SaveService* save; const StageService* stage; const ItemService* item; + const FlowService* flow; + const MessageService* message; + const GameModeService* game_mode; }; extern ServiceManager svc_mng; @@ -31,6 +37,7 @@ extern std::string g_pending_seed_hash; ModResult initialize(const ServiceManager& services); void update(); +void shutdown(); void deactivateSeed(); void setupRandomizerFile(); From acc8cc2e6d984e8cf0d62beaf26a8a3bfc9e851e Mon Sep 17 00:00:00 2001 From: jdflyer Date: Thu, 20 Aug 2026 00:50:30 -0700 Subject: [PATCH 2/2] Fix signature on dMenu_Ring_c__destructor, Add play menu sound --- mods/randomizer/src/hooks.cpp | 9 ++++++++- mods/randomizer/src/ui/rando_config.cpp | 1 + 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/mods/randomizer/src/hooks.cpp b/mods/randomizer/src/hooks.cpp index 3c1725e60f..8ac4f230d4 100644 --- a/mods/randomizer/src/hooks.cpp +++ b/mods/randomizer/src/hooks.cpp @@ -181,7 +181,14 @@ DEFINE_HOOK(&daObjZraRock_c::create, daObjZraRock_c__create); // DEFINE_HOOK_SYMBOL(phase_1_dScnPly_sig, int(dScnPly_c*), phase_1__dScnPly_c); DEFINE_HOOK(&dMenu_Ring_c::textScaleHIO, dMenu_Ring_c__textScaleHIO); -DEFINE_HOOK_SYMBOL("dMenu_Ring_c::~dMenu_Ring_c", void(dMenu_Ring_c*), dMenu_Ring_c__destructor); + +#ifdef _MSVC_LANG +#define dMenu_Ring_c__destructor_sig "??1dMenu_Ring_c@@UEAA@XZ" +#else +#define dMenu_Ring_c__destructor_sig "_ZN12dMenu_Ring_cD1Ev" +#endif +DEFINE_HOOK_SYMBOL(dMenu_Ring_c__destructor_sig, void(dMenu_Ring_c*), dMenu_Ring_c__destructor); + DEFINE_HOOK(&dMenu_Ring_c::setActiveCursor, dMenu_Ring_c__setActiveCursor); DEFINE_HOOK(&dMenu_Ring_c::getItemMaxNum, dMenu_Ring_c__getItemMaxNum); DEFINE_HOOK(&dMenu_Ring_c::getItemNum, dMenu_Ring_c__getItemNum); diff --git a/mods/randomizer/src/ui/rando_config.cpp b/mods/randomizer/src/ui/rando_config.cpp index 633917bdac..b882b57fe7 100644 --- a/mods/randomizer/src/ui/rando_config.cpp +++ b/mods/randomizer/src/ui/rando_config.cpp @@ -1151,6 +1151,7 @@ ModResult buildPlayTab(ModContext* ctx, UiWindowHandle, UiElementHandle leftPane // set flag to move to name screen after window close g_file_select_window_ctx.is_proceed = true; session::svc_mng.ui->window_close(session::svc_mng.mod_ctx, *static_cast(userdata)); + mDoAud_seStartMenu(Z2SE_SY_NEW_FILE); }; desc.user_data = &g_file_select_window_ctx.window_handle; desc.is_disabled = [](ModContext*, void*) {