From f2c34d8c112247d63ddb99702b2caf716ff77516 Mon Sep 17 00:00:00 2001 From: Christopher Leggett Date: Fri, 20 Mar 2026 03:40:35 +0000 Subject: [PATCH] Fix Entrance Rando Grotto Voidout Crash when voiding back to an area with a background image (#6379) Hookify bgimage load cam check and add it to entrance rando --- .../Enhancements/Cheats/UnrestrictedItems.cpp | 6 +++ .../vanilla-behavior/GIVanillaBehavior.h | 8 ++++ soh/soh/Enhancements/randomizer/entrance.cpp | 36 +++++++++++++++ soh/soh/Network/CrowdControl/CrowdControl.cpp | 11 +++++ soh/src/code/z_room.c | 46 ++++++++----------- 5 files changed, 81 insertions(+), 26 deletions(-) diff --git a/soh/soh/Enhancements/Cheats/UnrestrictedItems.cpp b/soh/soh/Enhancements/Cheats/UnrestrictedItems.cpp index 0b5aaebbc..d6f92fea8 100644 --- a/soh/soh/Enhancements/Cheats/UnrestrictedItems.cpp +++ b/soh/soh/Enhancements/Cheats/UnrestrictedItems.cpp @@ -21,6 +21,12 @@ void OnGameFrameUpdateUnrestrictedItems() { void RegisterUnrestrictedItems() { COND_HOOK(OnGameFrameUpdate, CVAR_UNRESTRICTED_ITEMS_VALUE, OnGameFrameUpdateUnrestrictedItems); + COND_VB_SHOULD(VB_SHOULD_LOAD_BG_IMAGE, CVAR_UNRESTRICTED_ITEMS_VALUE, { + int32_t* camId = va_arg(args, int*); + if (*camId == -1) { + *should = false; + } + }); } static RegisterShipInitFunc initFunc(RegisterUnrestrictedItems, { CVAR_UNRESTRICTED_ITEMS_NAME }); diff --git a/soh/soh/Enhancements/game-interactor/vanilla-behavior/GIVanillaBehavior.h b/soh/soh/Enhancements/game-interactor/vanilla-behavior/GIVanillaBehavior.h index c55d830c1..938aa9338 100644 --- a/soh/soh/Enhancements/game-interactor/vanilla-behavior/GIVanillaBehavior.h +++ b/soh/soh/Enhancements/game-interactor/vanilla-behavior/GIVanillaBehavior.h @@ -2720,6 +2720,14 @@ typedef enum { // - `*BgHakaHuta` // - `*PlayState` VB_HAKA_HUTA_SPAWN_REDEAD, + + // #### `result` + // ```c + // true + // ``` + // #### `args` + // - `*int32_t (camId)` + VB_SHOULD_LOAD_BG_IMAGE } GIVanillaBehavior; #endif diff --git a/soh/soh/Enhancements/randomizer/entrance.cpp b/soh/soh/Enhancements/randomizer/entrance.cpp index f1532352f..9af7ddba7 100644 --- a/soh/soh/Enhancements/randomizer/entrance.cpp +++ b/soh/soh/Enhancements/randomizer/entrance.cpp @@ -4,9 +4,18 @@ #include "3drando/pool_functions.hpp" #include "3drando/item_pool.hpp" #include "../debugger/performanceTimer.h" +#include "soh/Enhancements/gameconsole.h" +#include "z64camera.h" +#include "z64scene.h" #include +extern "C" { +#include "variables.h" +#include "macros.h" +#include "functions.h" +} + namespace Rando { EntranceLinkInfo NO_RETURN_ENTRANCE = { EntranceType::None, RR_NONE, RR_NONE, -1 }; @@ -1727,3 +1736,30 @@ const Entrance* EntranceShuffler::GetEntranceByIndex(int16_t index) { extern "C" EntranceOverride* Randomizer_GetEntranceOverrides() { return Rando::Context::GetInstance()->GetEntranceShuffler()->entranceOverrides.data(); } + +static SceneID backedUpScene = (SceneID)0xFF; +static Camera backupCamera; + +void RegisterEntranceShuffleHooks() { + COND_VB_SHOULD(VB_SHOULD_LOAD_BG_IMAGE, IS_RANDO && RAND_GET_OPTION(RSK_SHUFFLE_ENTRANCES), { + int32_t* camId = va_arg(args, int*); + Camera* camera = GET_ACTIVE_CAM(gPlayState); + if (*camId == -1) { + if (backedUpScene != gPlayState->sceneNum) { + *should = false; + return; + } + memcpy(camera, &backupCamera, sizeof(Camera)); + Camera_ChangeMode(camera, CAM_MODE_TALK); + *should = false; + } else if (backedUpScene != gPlayState->sceneNum) { + memcpy(&backupCamera, camera, sizeof(Camera)); + backedUpScene = (SceneID)gPlayState->sceneNum; + } + }); + + COND_HOOK(OnLoadGame, IS_RANDO && RAND_GET_OPTION(RSK_SHUFFLE_ENTRANCES), + [](int32_t) { backedUpScene = (SceneID)0xFF; }); +} + +static RegisterShipInitFunc initFunc(RegisterEntranceShuffleHooks, { "IS_RANDO" }); diff --git a/soh/soh/Network/CrowdControl/CrowdControl.cpp b/soh/soh/Network/CrowdControl/CrowdControl.cpp index 9709fc452..f91d8d52f 100644 --- a/soh/soh/Network/CrowdControl/CrowdControl.cpp +++ b/soh/soh/Network/CrowdControl/CrowdControl.cpp @@ -627,3 +627,14 @@ CrowdControl::Effect* CrowdControl::ParseMessage(nlohmann::json dataReceived) { return effect; } + +void RegisterCrowdControlHooks() { + COND_VB_SHOULD(VB_SHOULD_LOAD_BG_IMAGE, CVarGetInteger(CVAR_REMOTE_CROWD_CONTROL("Enabled"), 0), { + int32_t* camId = va_arg(args, int*); + if (*camId == -1) { + *should = false; + } + }); +} + +static RegisterShipInitFunc initFunc(RegisterCrowdControlHooks, { CVAR_REMOTE_CROWD_CONTROL("Enabled") }); diff --git a/soh/src/code/z_room.c b/soh/src/code/z_room.c index 8b4f31eba..317ee0775 100644 --- a/soh/src/code/z_room.c +++ b/soh/src/code/z_room.c @@ -413,34 +413,28 @@ BgImage* func_80096A74(PolygonType1* polygon1, PlayState* play) { camera = GET_ACTIVE_CAM(play); camId = camera->camDataIdx; - if (camId == -1 && (CVarGetInteger(CVAR_CHEAT("NoRestrictItems"), 0) || - (CVarGetInteger(CVAR_REMOTE_CROWD_CONTROL("Enabled"), 0)))) { - // This prevents a crash when using items that change the - // camera (such as din's fire), voiding out or dying on - // scenes with prerendered backgrounds. - return NULL; - } - - // jfifid - camId2 = func_80041C10(&play->colCtx, camId, BGCHECK_SCENE)[2].y; - if (camId2 >= 0) { - camId = camId2; - } - - player = GET_PLAYER(play); - player->actor.params = (player->actor.params & 0xFF00) | camId; - - bgImage = SEGMENTED_TO_VIRTUAL(polygon1->multi.list); - for (i = 0; i < polygon1->multi.count; i++) { - if (bgImage->id == camId) { - return bgImage; + if (GameInteractor_Should(VB_SHOULD_LOAD_BG_IMAGE, true, &camId)) { + // jfifid + camId2 = func_80041C10(&play->colCtx, camId, BGCHECK_SCENE)[2].y; + if (camId2 >= 0) { + camId = camId2; } - bgImage++; - } - // "z_room.c: Data consistent with camera id does not exist camid=%d" - osSyncPrintf(VT_COL(RED, WHITE) "z_room.c:カメラIDに一致するデータが存在しません camid=%d\n" VT_RST, camId); - LOG_HUNGUP_THREAD(); + player = GET_PLAYER(play); + player->actor.params = (player->actor.params & 0xFF00) | camId; + + bgImage = SEGMENTED_TO_VIRTUAL(polygon1->multi.list); + for (i = 0; i < polygon1->multi.count; i++) { + if (bgImage->id == camId) { + return bgImage; + } + bgImage++; + } + + // "z_room.c: Data consistent with camera id does not exist camid=%d" + osSyncPrintf(VT_COL(RED, WHITE) "z_room.c:カメラIDに一致するデータが存在しません camid=%d\n" VT_RST, camId); + LOG_HUNGUP_THREAD(); + } return NULL; }