From 747da8d6b7a804e28b7c9adc98d9dbe2de00ff59 Mon Sep 17 00:00:00 2001 From: Jerom Venneker Date: Wed, 28 May 2025 14:53:59 +0200 Subject: [PATCH] Added auto disconnect if loading a save accosiated with the wrong slot --- soh/soh/Network/Archipelago/Archipelago.cpp | 53 ++++++++++++++++++++- soh/soh/Network/Archipelago/Archipelago.h | 6 ++- 2 files changed, 56 insertions(+), 3 deletions(-) diff --git a/soh/soh/Network/Archipelago/Archipelago.cpp b/soh/soh/Network/Archipelago/Archipelago.cpp index 539ff836a..e40336161 100644 --- a/soh/soh/Network/Archipelago/Archipelago.cpp +++ b/soh/soh/Network/Archipelago/Archipelago.cpp @@ -29,6 +29,7 @@ ArchipelagoClient::ArchipelagoClient() { gameWon = false; itemQueued = false; + disconnecting = false; // call poll every frame COND_HOOK(GameInteractor::OnGameFrameUpdate, true, [](){ArchipelagoClient::GetInstance().Poll();}); @@ -45,6 +46,7 @@ bool ArchipelagoClient::StartClient() { apClient.reset(); } + disconnecting = false; apClient = std::unique_ptr( new APClient(uuid, AP_Client_consts::AP_GAME_NAME, CVarGetString(CVAR_REMOTE_ARCHIPELAGO("ServerAddress"), "localhost:38281"), "cacert.pem")); @@ -66,12 +68,22 @@ bool ArchipelagoClient::StartClient() { // if we are already in game when we connect // we won't have to request an itemSynch if(GameInteractor::IsSaveLoaded(true)) { + if(!isRightSaveLoaded()) { + disconnecting = true; + ArchipelagoConsole_SendMessage("[ERROR] Connected to incorrect slot, disconnecting..."); + return; + } + SynchSentLocations(); SynchReceivedLocations(); } }); apClient->set_items_received_handler([&](const std::list& items) { + if(disconnecting) { + return; + } + for(const APClient::NetworkItem& item : items) { ApItem apItem; const std::string game = apClient->get_player_game(item.player); @@ -85,6 +97,10 @@ bool ArchipelagoClient::StartClient() { }); apClient->set_location_info_handler([&](const std::list& items) { + if(disconnecting) { + return; + } + scoutedItems.clear(); for(const APClient::NetworkItem& item: items) { @@ -108,12 +124,20 @@ bool ArchipelagoClient::StartClient() { }); // todo maybe move these functions to a lambda, since they don't have to be static anymore apClient->set_location_checked_handler([&](const std::list locations) { + if(disconnecting) { + return; + } + for(const int64_t apLoc : locations) { QueueExternalCheck(apLoc); } }); apClient->set_print_json_handler([&](const APClient::PrintJSONArgs& arg) { + if(disconnecting) { + return; + } + std::string tag = "[" + arg.type + "] "; const int slot = apClient->get_player_number(); @@ -139,7 +163,14 @@ void ArchipelagoClient::GameLoaded() { // if its not an AP save, disconnect if(!IS_ARCHIPELAGO) { - apClient->reset(); + ArchipelagoConsole_SendMessage("[ERROR] Loaded save is not not an archipelago save, disconnecting..."); + disconnecting = true; + return; + } + + if(!isRightSaveLoaded()) { + ArchipelagoConsole_SendMessage("[ERROR] Loaded save is not associated with connected slot, disconnecting..."); + disconnecting = true; return; } @@ -282,6 +313,12 @@ void ArchipelagoClient::Poll() { return; } + if(disconnecting) { + apClient->reset(); + apClient = nullptr; + return; + } + // queue another item to be received if(!itemQueued && receiveQueue.size() > 0) { @@ -293,6 +330,12 @@ void ArchipelagoClient::Poll() { apClient->poll(); } +bool ArchipelagoClient::isRightSaveLoaded() const { + const bool seedMatch = apClient->get_seed().compare(gSaveContext.ship.quest.data.archipelago.roomHash) == 0; + const bool slotMatch = GetSlotName().compare(gSaveContext.ship.quest.data.archipelago.slotName) == 0; + return seedMatch && slotMatch; +} + const std::string ArchipelagoClient::GetSlotName() const { if(apClient == NULL) { return ""; @@ -311,7 +354,7 @@ const std::vector& ArchipelagoClient::GetScoutedItems const char* ArchipelagoClient::GetConnectionStatus() { if (!apClient) { - return ""; + return "Disconnected!"; } APClient::State clientStatus = apClient->get_state(); @@ -345,6 +388,12 @@ extern "C" void Archipelago_InitSaveFile() { std::vector scoutedItems = ArchipelagoClient::GetInstance().GetScoutedItems(); + ArchipelagoClient& client = ArchipelagoClient::GetInstance(); + SohUtils::CopyStringToCharArray(gSaveContext.ship.quest.data.archipelago.roomHash, client.apClient->get_seed(), + ARRAY_COUNT(gSaveContext.ship.quest.data.archipelago.roomHash)); + SohUtils::CopyStringToCharArray(gSaveContext.ship.quest.data.archipelago.slotName, client.apClient->get_slot(), + ARRAY_COUNT(gSaveContext.ship.quest.data.archipelago.slotName)); + for (uint32_t i = 0; i < scoutedItems.size(); i++) { RandomizerCheck rc = Rando::StaticData::locationNameToEnum[scoutedItems[i].locationName]; diff --git a/soh/soh/Network/Archipelago/Archipelago.h b/soh/soh/Network/Archipelago/Archipelago.h index 46b7adb07..c52a7bea9 100644 --- a/soh/soh/Network/Archipelago/Archipelago.h +++ b/soh/soh/Network/Archipelago/Archipelago.h @@ -58,6 +58,7 @@ class ArchipelagoClient{ std::unique_ptr apClient; bool itemQueued; + bool disconnecting; protected: ArchipelagoClient(); @@ -65,9 +66,12 @@ class ArchipelagoClient{ private: ArchipelagoClient(ArchipelagoClient &) = delete; void operator=(const ArchipelagoClient &) = delete; + + bool isRightSaveLoaded() const; + std::string uuid; - static std::shared_ptr instance; // is this even used? + static std::shared_ptr instance; static bool initialized; bool gameWon;