diff --git a/soh/soh/Enhancements/randomizer/hook_handlers.cpp b/soh/soh/Enhancements/randomizer/hook_handlers.cpp index c9fd6f7089..a49b4dfe9c 100644 --- a/soh/soh/Enhancements/randomizer/hook_handlers.cpp +++ b/soh/soh/Enhancements/randomizer/hook_handlers.cpp @@ -11,6 +11,7 @@ #include "soh/Enhancements/randomizer/fishsanity.h" #include "soh/Enhancements/randomizer/static_data.h" #include "soh/Enhancements/game-interactor/GameInteractor.h" +#include "soh/Enhancements/game-interactor/GameInteractor_Hooks.h" #include "soh/SohGui/ImGuiUtils.h" #include "soh/Notification/Notification.h" #include "soh/SaveManager.h" @@ -478,6 +479,9 @@ static void PlantAllBeans() { gSaveContext.sceneFlags[patch.scene].swch |= 1 << patch.swchFlag; if (gPlayState->sceneNum == patch.scene) { Flags_SetSwitch(gPlayState, patch.swchFlag); + } else { + // Flags_SetSwitch fires this for the current scene, other scenes need it so Anchor syncs them + GameInteractor_ExecuteOnSceneFlagSet(patch.scene, FLAG_SCENE_SWITCH, patch.swchFlag); } } ObjBean* bean = (ObjBean*)Actor_Find(&gPlayState->actorCtx, ACTOR_OBJ_BEAN, ACTORCAT_BG); diff --git a/soh/soh/Network/Anchor/DummyPlayer.cpp b/soh/soh/Network/Anchor/DummyPlayer.cpp index fae13d5849..71943745c4 100644 --- a/soh/soh/Network/Anchor/DummyPlayer.cpp +++ b/soh/soh/Network/Anchor/DummyPlayer.cpp @@ -254,4 +254,10 @@ void DummyPlayer_Destroy(Actor* actor, PlayState* play) { // asserts. Set the id back to ACTOR_PLAYER so that `numLoaded` will be decremented // correctly. actor->id = ACTOR_PLAYER; + + // Drop client's pointer so packet handlers don't use after free + uint32_t clientId = Anchor::Instance->GetDummyPlayerClientId(actor); + if (Anchor::Instance->clients.contains(clientId) && Anchor::Instance->clients[clientId].player == (Player*)actor) { + Anchor::Instance->clients[clientId].player = nullptr; + } } diff --git a/soh/soh/Network/Anchor/JsonConversions.hpp b/soh/soh/Network/Anchor/JsonConversions.hpp index 83c2f77304..bb8e9df9d5 100644 --- a/soh/soh/Network/Anchor/JsonConversions.hpp +++ b/soh/soh/Network/Anchor/JsonConversions.hpp @@ -104,18 +104,50 @@ inline void from_json(const json& j, SohStats& sohStats) { j.at("fileCreatedAt").get_to(sohStats.fileCreatedAt); } +#define SILVER_RUPEE_FIELDS(X) \ + X(silverShadowBlades) \ + X(silverShadowPit) \ + X(silverShadowSpikes) \ + X(silverSpiritChild) \ + X(silverSpiritSun) \ + X(silverSpiritBoulders) \ + X(silverBotw) \ + X(silverIceCavernBlades) \ + X(silverIceCavernBlock) \ + X(silverGtgSlope) \ + X(silverGtgLava) \ + X(silverGtgWater) \ + X(silverGanonLight) \ + X(silverGanonForest) \ + X(silverGanonFire) \ + X(silverGanonSpirit) \ + X(silverMqDodongosCavern) \ + X(silverMqShadowInvisibleBlades) \ + X(silverMqSpiritLobby) \ + X(silverMqSpiritBigWall) \ + X(silverMqGanonWater) \ + X(silverMqGanonShadow) + inline void to_json(json& j, const ShipRandomizerSaveContextData& shipRandomizerSaveContextData) { j = json{ { "triforcePiecesCollected", shipRandomizerSaveContextData.triforcePiecesCollected }, { "bombchuUpgradeLevel", shipRandomizerSaveContextData.bombchuUpgradeLevel }, }; +#define SILVER_TO_JSON(field) j[#field] = shipRandomizerSaveContextData.field; + SILVER_RUPEE_FIELDS(SILVER_TO_JSON) +#undef SILVER_TO_JSON } inline void from_json(const json& j, ShipRandomizerSaveContextData& shipRandomizerSaveContextData) { j.at("triforcePiecesCollected").get_to(shipRandomizerSaveContextData.triforcePiecesCollected); j.at("bombchuUpgradeLevel").get_to(shipRandomizerSaveContextData.bombchuUpgradeLevel); +#define SILVER_FROM_JSON(field) shipRandomizerSaveContextData.field = j.value(#field, (s8)0); + SILVER_RUPEE_FIELDS(SILVER_FROM_JSON) +#undef SILVER_FROM_JSON } +#undef SILVER_RUPEE_FIELDS + inline void to_json(json& j, const ShipQuestSpecificSaveContextData& shipQuestSpecificSaveContextData) { j = json{ { "randomizer", shipQuestSpecificSaveContextData.randomizer },