From 2418d51df56f54c7edc9969ab6d2b3edd11fcf40 Mon Sep 17 00:00:00 2001 From: FantaTanked <86494849+FantaTanked@users.noreply.github.com> Date: Wed, 1 Jul 2026 13:55:22 +0100 Subject: [PATCH] Fix for actors / crawlspaces / doors not loading after loading a savestate (#6838) Fixes an issue where actors do not load properly after creating a savestate and then going to either a new scene or loading a different area of the map (graveyard near shadow -> main section of graveyard dampes door is missing after loading again.) --- soh/soh/Enhancements/savestates.cpp | 24 ++++++++++++++++++++++-- soh/soh/z_scene_otr.cpp | 6 ++++++ 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/soh/soh/Enhancements/savestates.cpp b/soh/soh/Enhancements/savestates.cpp index 672de6658d..acf4fcd634 100644 --- a/soh/soh/Enhancements/savestates.cpp +++ b/soh/soh/Enhancements/savestates.cpp @@ -323,6 +323,9 @@ typedef struct SaveStateInfo { s16 sMessageHasSetSfx_copy; u16 sOcarinaSongBitFlags_copy; + u8 transitionActorCount_copy; + s16 transitionActorIds_copy[256]; + } SaveStateInfo; class SaveState { @@ -346,9 +349,10 @@ class SaveState { void LoadOnePointDemoData(void); void SaveOverlayStaticData(void); void LoadOverlayStaticData(void); - void SaveMiscCodeData(void); void LoadMiscCodeData(void); + void SaveTransitionActors(void); + void LoadTransitionActors(void); SaveStateInfo* GetSaveStateInfo(void); }; @@ -812,6 +816,20 @@ void SaveState::LoadMiscCodeData(void) { sOcarinaSongBitFlags = info->sOcarinaSongBitFlags_copy; } +void SaveState::SaveTransitionActors(void) { + info->transitionActorCount_copy = gPlayState->transiActorCtx.numActors; + for (u32 i = 0; i < info->transitionActorCount_copy; i++) { + info->transitionActorIds_copy[i] = gPlayState->transiActorCtx.list[i].id; + } +} + +void SaveState::LoadTransitionActors(void) { + u32 numActors = MIN(info->transitionActorCount_copy, gPlayState->transiActorCtx.numActors); + for (u32 i = 0; i < numActors; i++) { + gPlayState->transiActorCtx.list[i].id = info->transitionActorIds_copy[i]; + } +} + extern "C" void ProcessSaveStateRequests(void) { OTRGlobals::Instance->gSaveStateMgr->ProcessSaveStateRequests(); } @@ -918,6 +936,7 @@ void SaveState::Save(void) { SaveOnePointDemoData(); SaveOverlayStaticData(); SaveMiscCodeData(); + SaveTransitionActors(); } void SaveState::Load(void) { @@ -951,4 +970,5 @@ void SaveState::Load(void) { LoadOnePointDemoData(); LoadOverlayStaticData(); LoadMiscCodeData(); -} + LoadTransitionActors(); +} \ No newline at end of file diff --git a/soh/soh/z_scene_otr.cpp b/soh/soh/z_scene_otr.cpp index b5a82e6597..5b0132da2c 100644 --- a/soh/soh/z_scene_otr.cpp +++ b/soh/soh/z_scene_otr.cpp @@ -202,6 +202,12 @@ bool Scene_CommandTransitionActorList(PlayState* play, SOH::ISceneCommand* cmd) play->transiActorCtx.numActors = cmdActor->numTransitionActors; play->transiActorCtx.list = (TransitionActorEntry*)cmdActor->GetRawPointer(); + // Loops transition actors and sets them to default values (not spawned yet) + // used as fix for doors / crawlspaces not loading after they've already been loaded once. + for (s32 i = 0; i < play->transiActorCtx.numActors; i++) { + play->transiActorCtx.list[i].id = ABS(play->transiActorCtx.list[i].id); + } + return false; }