From 7a8a5a19a0aa1e2d0a76cca92509d552c1def5c6 Mon Sep 17 00:00:00 2001 From: Jerom Venneker Date: Wed, 28 May 2025 10:21:24 +0200 Subject: [PATCH 1/8] Don't Send or queue Unknown checks. Todo, figure out what triggers sending one --- soh/soh/Network/Archipelago/Archipelago.cpp | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/soh/soh/Network/Archipelago/Archipelago.cpp b/soh/soh/Network/Archipelago/Archipelago.cpp index 07263f213..8f5d08748 100644 --- a/soh/soh/Network/Archipelago/Archipelago.cpp +++ b/soh/soh/Network/Archipelago/Archipelago.cpp @@ -196,12 +196,17 @@ void ArchipelagoClient::QueueExternalCheck(const int64_t apLocation) { const std::string checkName = apClient->get_location_name(apLocation, AP_Client_consts::AP_GAME_NAME); const uint32_t RC = static_cast(Rando::StaticData::locationNameToEnum[checkName]); + if(RC == RC_UNKNOWN_CHECK) { + ArchipelagoConsole_SendMessage("[ERROR] Attempting to queue RC_UNKOWN_CHECK, skipping", false); + return; + } + // Don't queue checks we already have if(Rando::Context::GetInstance()->GetItemLocation(RC)->HasObtained()) { return; } - std::string locationLog = "[LOG] Externaly checking" + checkName; + std::string locationLog = "[LOG] Externaly checking: " + checkName; ArchipelagoConsole_SendMessage(locationLog.c_str(), true); GameInteractor_ExecuteOnRandomizerExternalCheck(RC); @@ -212,12 +217,17 @@ bool ArchipelagoClient::IsConnected() { } void ArchipelagoClient::CheckLocation(RandomizerCheck sohCheckId) { + if(sohCheckId == RC_UNKNOWN_CHECK) { + ArchipelagoConsole_SendMessage("[ERROR] trying to send RC_UNKNOWN_CHECK, skipping", false); + return; + } + std::string apName = Rando::StaticData::GetLocation(sohCheckId)->GetName(); if (apName.empty()) { return; } - int64_t apItemId = apClient->get_location_id(std::string(apName)); + int64_t apItemId = apClient->get_location_id(std::string(apName)); std::string logMessage = "[LOG] Checked: " + apName + "(" + std::to_string(apItemId) + "), sending to AP server"; ArchipelagoConsole_SendMessage(logMessage.c_str(), true); From d9d453501eff870c52405ae822995fb8c096dec3 Mon Sep 17 00:00:00 2001 From: Jerom Venneker Date: Wed, 28 May 2025 10:30:58 +0200 Subject: [PATCH 2/8] Corrected spelling on receive --- README.md | 2 +- .../GameInteractor_HookTable.h | 2 +- .../game-interactor/GameInteractor_Hooks.cpp | 4 +-- .../game-interactor/GameInteractor_Hooks.h | 2 +- soh/soh/Enhancements/randomizer/context.cpp | 10 +++---- soh/soh/Enhancements/randomizer/context.h | 4 +-- .../Enhancements/randomizer/hook_handlers.cpp | 10 +++---- .../Enhancements/randomizer/item_location.cpp | 2 +- .../Enhancements/randomizer/randomizerTypes.h | 2 +- soh/soh/Network/Archipelago/Archipelago.cpp | 26 +++++++++---------- soh/soh/Network/Archipelago/Archipelago.h | 4 +-- 11 files changed, 34 insertions(+), 34 deletions(-) diff --git a/README.md b/README.md index edae15c6b..6fa826854 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ You can currently connect to the multiworld server, scout the items. If you have no randomizer genereted (the `Randomizer` folder is empty) `Connect` to the multiworld from the main screen, click the `Scout` button to load all of the item locations and finally press the `Link up` button, you'll be able to start a randomizer save file. with the items populated with the location from the server. -Sending and Recieving should be implemented, Saving the game doesn't save the current item index localy (the library is a bit anoying with that). +Sending and Receiving should be implemented, Saving the game doesn't save the current item index localy (the library is a bit anoying with that). Not all checks have been mapped, and some may be mapped incorrectly. The victory condition should be implemented but has largely gone untested. diff --git a/soh/soh/Enhancements/game-interactor/GameInteractor_HookTable.h b/soh/soh/Enhancements/game-interactor/GameInteractor_HookTable.h index 73e447999..69118b5ab 100644 --- a/soh/soh/Enhancements/game-interactor/GameInteractor_HookTable.h +++ b/soh/soh/Enhancements/game-interactor/GameInteractor_HookTable.h @@ -71,5 +71,5 @@ DEFINE_HOOK(OnAssetAltChange, ()); DEFINE_HOOK(OnKaleidoUpdate, ()); DEFINE_HOOK(OnRandomizerItemGivenHooks, (uint32_t rc, GetItemEntry gi, uint8_t isGiSkipped)); -DEFINE_HOOK(OnArchipelagoItemRecieved, (uint32_t rg)); +DEFINE_HOOK(OnArchipelagoItemReceived, (uint32_t rg)); DEFINE_HOOK(OnRandomizerExternalCheck, (uint32_t rc)); diff --git a/soh/soh/Enhancements/game-interactor/GameInteractor_Hooks.cpp b/soh/soh/Enhancements/game-interactor/GameInteractor_Hooks.cpp index 238cff3b0..b1f4bb447 100644 --- a/soh/soh/Enhancements/game-interactor/GameInteractor_Hooks.cpp +++ b/soh/soh/Enhancements/game-interactor/GameInteractor_Hooks.cpp @@ -309,8 +309,8 @@ void GameInteractor_ExecuteOnRandomizerItemGivenHooks(uint32_t rc, GetItemEntry } // MARK: Archipelago -void GameInteractor_ExecuteOnArchipelagoItemRecieved(uint32_t rg) { - GameInteractor::Instance->ExecuteHooks(rg); +void GameInteractor_ExecuteOnArchipelagoItemReceived(uint32_t rg) { + GameInteractor::Instance->ExecuteHooks(rg); } void GameInteractor_ExecuteOnRandomizerExternalCheck(uint32_t rc) { diff --git a/soh/soh/Enhancements/game-interactor/GameInteractor_Hooks.h b/soh/soh/Enhancements/game-interactor/GameInteractor_Hooks.h index 17de14e5f..0306dc38d 100644 --- a/soh/soh/Enhancements/game-interactor/GameInteractor_Hooks.h +++ b/soh/soh/Enhancements/game-interactor/GameInteractor_Hooks.h @@ -85,7 +85,7 @@ void GameInteractor_ExecuteOnKaleidoUpdate(); void GameInteractor_ExecuteOnRandomizerItemGivenHooks(uint32_t rc, GetItemEntry gi, uint8_t isGiSkipped); // Mark: - Archipelago -void GameInteractor_ExecuteOnArchipelagoItemRecieved(uint32_t rg); +void GameInteractor_ExecuteOnArchipelagoItemReceived(uint32_t rg); void GameInteractor_ExecuteOnRandomizerExternalCheck(uint32_t rc); #ifdef __cplusplus diff --git a/soh/soh/Enhancements/randomizer/context.cpp b/soh/soh/Enhancements/randomizer/context.cpp index 149e656a5..af2d403db 100644 --- a/soh/soh/Enhancements/randomizer/context.cpp +++ b/soh/soh/Enhancements/randomizer/context.cpp @@ -346,27 +346,27 @@ void Context::SetSpoilerLoaded(const bool spoilerLoaded) { mSpoilerLoaded = spoilerLoaded; } -void Context::AddRecievedArchipelagoItem(const RandomizerGet item) { - mAPrecieveQueue.emplace(item); +void Context::AddReceivedArchipelagoItem(const RandomizerGet item) { + mAPreceiveQueue.emplace(item); std::string logMessage = "[LOG] Item Pushed: " + item; ArchipelagoConsole_SendMessage(logMessage.c_str(), true); } GetItemEntry Context::GetArchipelagoGIEntry() { ArchipelagoConsole_SendMessage("[LOG] Trying to get Item Entry", true); - if(mAPrecieveQueue.empty()) { + if(mAPreceiveQueue.empty()) { // something must have gone wrong here, just give a rupee return ItemTableManager::Instance->RetrieveItemEntry(MOD_NONE, GI_HEART); } // get the first item from the archipelago queue - RandomizerGet item_id = mAPrecieveQueue.front(); + RandomizerGet item_id = mAPreceiveQueue.front(); assert(item_id != RG_NONE); Item& item = StaticData::RetrieveItem(item_id); SPDLOG_TRACE("Found item! {}, {}", item.GetName().GetEnglish(), (int)item_id); GetItemEntry item_entry = item.GetGIEntry_Copy(); - mAPrecieveQueue.pop(); + mAPreceiveQueue.pop(); return item_entry; // todo: add custom text maybe? } diff --git a/soh/soh/Enhancements/randomizer/context.h b/soh/soh/Enhancements/randomizer/context.h index f97b21287..648b9c731 100644 --- a/soh/soh/Enhancements/randomizer/context.h +++ b/soh/soh/Enhancements/randomizer/context.h @@ -107,7 +107,7 @@ class Context { */ RandoOptionLACSCondition LACSCondition() const; GetItemEntry GetFinalGIEntry(RandomizerCheck rc, bool checkObtainability = true, GetItemID ogItemId = GI_NONE); - void AddRecievedArchipelagoItem(const RandomizerGet item); + void AddReceivedArchipelagoItem(const RandomizerGet item); GetItemEntry GetArchipelagoGIEntry(); void ParseSpoiler(const char* spoilerFileName); void ParseHashIconIndexesJson(nlohmann::json spoilerFileJson); @@ -189,6 +189,6 @@ class Context { std::string mHash; std::string mSeedString; uint32_t mFinalSeed = 0; - std::queue mAPrecieveQueue = {}; + std::queue mAPreceiveQueue = {}; }; } // namespace Rando \ No newline at end of file diff --git a/soh/soh/Enhancements/randomizer/hook_handlers.cpp b/soh/soh/Enhancements/randomizer/hook_handlers.cpp index 601b2be0d..d1e41bceb 100644 --- a/soh/soh/Enhancements/randomizer/hook_handlers.cpp +++ b/soh/soh/Enhancements/randomizer/hook_handlers.cpp @@ -222,11 +222,11 @@ static std::queue randomizerQueuedChecks; static RandomizerCheck randomizerQueuedCheck = RC_UNKNOWN_CHECK; static GetItemEntry randomizerQueuedItemEntry = GET_ITEM_NONE; -void ArchipelagoOnRecieveItem(const int32_t item) { +void ArchipelagoOnReceiveItem(const int32_t item) { std::string logMessage = "[LOG] Receive item handler called: " + item; ArchipelagoConsole_SendMessage(logMessage.c_str(), true); - randomizerQueuedChecks.push(RC_ARCHIPELAGO_RECIEVED_ITEM); - Rando::Context::GetInstance()->AddRecievedArchipelagoItem(static_cast(item)); + randomizerQueuedChecks.push(RC_ARCHIPELAGO_RECEIVED_ITEM); + Rando::Context::GetInstance()->AddReceivedArchipelagoItem(static_cast(item)); } void RandomizerOnFlagSetHandler(int16_t flagType, int16_t flag) { @@ -313,7 +313,7 @@ void RandomizerOnPlayerUpdateForRCQueueHandler() { auto loc = Rando::Context::GetInstance()->GetItemLocation(rc); uint8_t isGiSkipped = 0; - if (rc == RC_ARCHIPELAGO_RECIEVED_ITEM) { + if (rc == RC_ARCHIPELAGO_RECEIVED_ITEM) { getItemEntry = Rando::Context::GetInstance()->GetArchipelagoGIEntry(); } else { RandomizerGet vanillaRandomizerGet = Rando::StaticData::GetLocation(rc)->GetVanillaItem(); @@ -2540,7 +2540,7 @@ void RandomizerRegisterHooks() { onCuccoOrChickenHatchHook = GameInteractor::Instance->RegisterGameHook( RandomizerOnCuccoOrChickenHatch); - COND_HOOK(GameInteractor::OnArchipelagoItemRecieved, IS_ARCHIPELAGO, ArchipelagoOnRecieveItem); + COND_HOOK(GameInteractor::OnArchipelagoItemReceived, IS_ARCHIPELAGO, ArchipelagoOnReceiveItem); COND_HOOK(GameInteractor::OnRandomizerExternalCheck, IS_ARCHIPELAGO, RandomizerOnExternalCheckHandler) if (RAND_GET_OPTION(RSK_FISHSANITY) != RO_FISHSANITY_OFF) { diff --git a/soh/soh/Enhancements/randomizer/item_location.cpp b/soh/soh/Enhancements/randomizer/item_location.cpp index b31914548..3269287a2 100644 --- a/soh/soh/Enhancements/randomizer/item_location.cpp +++ b/soh/soh/Enhancements/randomizer/item_location.cpp @@ -133,7 +133,7 @@ bool ItemLocation::HasObtained() const { } void ItemLocation::SetCheckStatus(RandomizerCheckStatus status_) { - if(rc == RC_ARCHIPELAGO_RECIEVED_ITEM) // never count the AP recieve trigger as 'collected' + if(rc == RC_ARCHIPELAGO_RECEIVED_ITEM) // never count the AP receive trigger as 'collected' return; status = status_; } diff --git a/soh/soh/Enhancements/randomizer/randomizerTypes.h b/soh/soh/Enhancements/randomizer/randomizerTypes.h index 959e78f87..fe79f7c92 100644 --- a/soh/soh/Enhancements/randomizer/randomizerTypes.h +++ b/soh/soh/Enhancements/randomizer/randomizerTypes.h @@ -3472,7 +3472,7 @@ typedef enum { RC_DEKU_TREE_QUEEN_GOHMA_GRASS_8, // End Grass - RC_ARCHIPELAGO_RECIEVED_ITEM, + RC_ARCHIPELAGO_RECEIVED_ITEM, RC_MAX } RandomizerCheck; diff --git a/soh/soh/Network/Archipelago/Archipelago.cpp b/soh/soh/Network/Archipelago/Archipelago.cpp index 8f5d08748..539ff836a 100644 --- a/soh/soh/Network/Archipelago/Archipelago.cpp +++ b/soh/soh/Network/Archipelago/Archipelago.cpp @@ -67,7 +67,7 @@ bool ArchipelagoClient::StartClient() { // we won't have to request an itemSynch if(GameInteractor::IsSaveLoaded(true)) { SynchSentLocations(); - SynchRecievedLocations(); + SynchReceivedLocations(); } }); @@ -147,7 +147,7 @@ void ArchipelagoClient::GameLoaded() { SynchItems(); SynchSentLocations(); - SynchRecievedLocations(); + SynchReceivedLocations(); } void ArchipelagoClient::StartLocationScouts() { @@ -185,7 +185,7 @@ void ArchipelagoClient::SynchSentLocations() { apClient->LocationChecks(checkedLocations); } -void ArchipelagoClient::SynchRecievedLocations() { +void ArchipelagoClient::SynchReceivedLocations() { // Open checks that have been found previously but went unsaved for(const int64_t apLoc : apClient->get_checked_locations()) { QueueExternalCheck(apLoc); @@ -244,17 +244,17 @@ void ArchipelagoClient::OnItemReceived(const ApItem apItem) { return; } - std::string logMessage = "[LOG] Recieved " + apItem.itemName; + std::string logMessage = "[LOG] Received " + apItem.itemName; ArchipelagoConsole_SendMessage(logMessage.c_str(), true); // add item to the queue - recieveQueue.push(apItem); + receiveQueue.push(apItem); } void ArchipelagoClient::QueueItem(const ApItem item) { if(item.index < gSaveContext.ship.quest.data.archipelago.lastReceivedItemIndex) { // Skip queueing any items we already have - std::string logMessage = "[LOG] Skipping giving " + item.itemName + ". We recieved this previously."; + std::string logMessage = "[LOG] Skipping giving " + item.itemName + ". We received this previously."; ArchipelagoConsole_SendMessage(logMessage.c_str(), true); return; } @@ -267,7 +267,7 @@ void ArchipelagoClient::QueueItem(const ApItem item) { } itemQueued = true; - GameInteractor_ExecuteOnArchipelagoItemRecieved(static_cast(RG)); + GameInteractor_ExecuteOnArchipelagoItemReceived(static_cast(RG)); } void ArchipelagoClient::SendGameWon() { @@ -282,11 +282,11 @@ void ArchipelagoClient::Poll() { return; } - // queue another item to be recieved - if(!itemQueued && recieveQueue.size() > 0) { + // queue another item to be received + if(!itemQueued && receiveQueue.size() > 0) { - const ApItem item = recieveQueue.front(); - recieveQueue.pop(); + const ApItem item = receiveQueue.front(); + receiveQueue.pop(); QueueItem(item); } @@ -327,7 +327,7 @@ const char* ArchipelagoClient::GetConnectionStatus() { return "Socket Connected!"; } case APClient::State::ROOM_INFO: { - return "Room info Recieved!"; + return "Room info Received!"; } case APClient::State::SLOT_CONNECTED: { return "Slot Connected!"; @@ -425,7 +425,7 @@ void RegisterArchipelago() { COND_HOOK(GameInteractor::OnRandomizerItemGivenHooks, IS_ARCHIPELAGO, [](uint32_t rc, GetItemEntry gi, uint8_t isGiSkipped) { - if (rc == RC_ARCHIPELAGO_RECIEVED_ITEM) { + if (rc == RC_ARCHIPELAGO_RECEIVED_ITEM) { gSaveContext.ship.quest.data.archipelago.lastReceivedItemIndex++; ArchipelagoClient::GetInstance().itemQueued = false; } else { diff --git a/soh/soh/Network/Archipelago/Archipelago.h b/soh/soh/Network/Archipelago/Archipelago.h index 314c0a34a..46b7adb07 100644 --- a/soh/soh/Network/Archipelago/Archipelago.h +++ b/soh/soh/Network/Archipelago/Archipelago.h @@ -36,7 +36,7 @@ class ArchipelagoClient{ void StartLocationScouts(); void SynchItems(); void SynchSentLocations(); - void SynchRecievedLocations(); + void SynchReceivedLocations(); // getters const std::string GetSlotName() const; @@ -75,7 +75,7 @@ class ArchipelagoClient{ nlohmann::json slotData; std::set locations; std::vector scoutedItems; - std::queue recieveQueue; + std::queue receiveQueue; }; void LoadArchipelagoData(); From 747da8d6b7a804e28b7c9adc98d9dbe2de00ff59 Mon Sep 17 00:00:00 2001 From: Jerom Venneker Date: Wed, 28 May 2025 14:53:59 +0200 Subject: [PATCH 3/8] 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; From cc40d3ca8604d01d7d12bbecf8355507d23df557 Mon Sep 17 00:00:00 2001 From: Jerom Venneker Date: Wed, 28 May 2025 15:15:46 +0200 Subject: [PATCH 4/8] Moved hooks to Registration function and improved item queue filtering --- soh/soh/Network/Archipelago/Archipelago.cpp | 23 +++++++++++---------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/soh/soh/Network/Archipelago/Archipelago.cpp b/soh/soh/Network/Archipelago/Archipelago.cpp index e40336161..029c839e0 100644 --- a/soh/soh/Network/Archipelago/Archipelago.cpp +++ b/soh/soh/Network/Archipelago/Archipelago.cpp @@ -30,10 +30,6 @@ ArchipelagoClient::ArchipelagoClient() { gameWon = false; itemQueued = false; disconnecting = false; - - // call poll every frame - COND_HOOK(GameInteractor::OnGameFrameUpdate, true, [](){ArchipelagoClient::GetInstance().Poll();}); - COND_HOOK(GameInteractor::OnLoadGame, true, [](int32_t file_id){ArchipelagoClient::GetInstance().GameLoaded();}); } ArchipelagoClient& ArchipelagoClient::GetInstance() { @@ -278,18 +274,18 @@ void ArchipelagoClient::OnItemReceived(const ApItem apItem) { std::string logMessage = "[LOG] Received " + apItem.itemName; ArchipelagoConsole_SendMessage(logMessage.c_str(), true); + if(apItem.index < gSaveContext.ship.quest.data.archipelago.lastReceivedItemIndex) { + // Skip queueing any items we already have + std::string logMessage = "[LOG] Skipping giving " + apItem.itemName + ". We received this previously."; + ArchipelagoConsole_SendMessage(logMessage.c_str(), true); + return; + } + // add item to the queue receiveQueue.push(apItem); } void ArchipelagoClient::QueueItem(const ApItem item) { - if(item.index < gSaveContext.ship.quest.data.archipelago.lastReceivedItemIndex) { - // Skip queueing any items we already have - std::string logMessage = "[LOG] Skipping giving " + item.itemName + ". We received this previously."; - ArchipelagoConsole_SendMessage(logMessage.c_str(), true); - return; - } - std::string logMessage = "[LOG] Giving " + item.itemName; ArchipelagoConsole_SendMessage(logMessage.c_str(), true); const RandomizerGet RG = Rando::StaticData::itemNameToEnum[item.itemName]; @@ -470,8 +466,13 @@ void InitArchipelagoData(bool isDebug) { } void RegisterArchipelago() { + // make sure the client is constructed + ArchipelagoClient::GetInstance(); + CVarSetInteger(CVAR_REMOTE_ARCHIPELAGO("Connected"), 0); + COND_HOOK(GameInteractor::OnGameFrameUpdate, true, [](){ArchipelagoClient::GetInstance().Poll();}); + COND_HOOK(GameInteractor::OnLoadGame, true, [](int32_t file_id){ArchipelagoClient::GetInstance().GameLoaded();}); COND_HOOK(GameInteractor::OnRandomizerItemGivenHooks, IS_ARCHIPELAGO, [](uint32_t rc, GetItemEntry gi, uint8_t isGiSkipped) { if (rc == RC_ARCHIPELAGO_RECEIVED_ITEM) { From 422b7d1950a1a8ceafb6c3b3344f56db3e60d3ba Mon Sep 17 00:00:00 2001 From: Jerom Venneker Date: Wed, 28 May 2025 22:52:14 +0200 Subject: [PATCH 5/8] Added proper archipelago textclient colors to the console --- soh/soh/Network/Archipelago/Archipelago.cpp | 14 +- .../Archipelago/ArchipelagoConsoleWindow.cpp | 143 ++++++++++++------ .../Archipelago/ArchipelagoConsoleWindow.h | 5 + 3 files changed, 103 insertions(+), 59 deletions(-) diff --git a/soh/soh/Network/Archipelago/Archipelago.cpp b/soh/soh/Network/Archipelago/Archipelago.cpp index 029c839e0..c760f3f1a 100644 --- a/soh/soh/Network/Archipelago/Archipelago.cpp +++ b/soh/soh/Network/Archipelago/Archipelago.cpp @@ -134,19 +134,7 @@ bool ArchipelagoClient::StartClient() { return; } - std::string tag = "[" + arg.type + "] "; - - const int slot = apClient->get_player_number(); - if(arg.type == "ItemSend") { - if((*arg.item).player == slot) { - tag = "[Found] "; - } else if (*arg.receiving == slot ) { - tag = "[Received] "; - } - } - - std::string text = tag + apClient->render_json(arg.data, APClient::RenderFormat::TEXT); - ArchipelagoConsole_SendMessage(text.c_str(), false); + ArchipelagoConsole_PrintJson(arg.data); }); return true; diff --git a/soh/soh/Network/Archipelago/ArchipelagoConsoleWindow.cpp b/soh/soh/Network/Archipelago/ArchipelagoConsoleWindow.cpp index 2817b112e..169571c70 100644 --- a/soh/soh/Network/Archipelago/ArchipelagoConsoleWindow.cpp +++ b/soh/soh/Network/Archipelago/ArchipelagoConsoleWindow.cpp @@ -4,7 +4,7 @@ #include "soh/SohGui/SohGui.hpp" #include "soh/OTRGlobals.h" -ImVector Items; +std::vector> Items; bool autoScroll = true; using namespace UIWidgets; @@ -19,7 +19,22 @@ void ArchipelagoConsole_SendMessage(const char* fmt, bool debugMessage, ...) { vsnprintf(buf, IM_ARRAYSIZE(buf), fmt, args); buf[IM_ARRAYSIZE(buf) - 1] = 0; va_end(args); - Items.push_back(strdup(buf)); + APClient::TextNode node; + if (strstr(buf, "[ERROR]")) { + node.type = "ERROR"; + node.color = "ERROR"; + } else if (strstr(buf, "[LOG]")) { + node.type = "LOG"; + node.color = "LOG"; + } + node.text = std::string(buf); + std::list line; + line.push_back(node); + Items.push_back(line); +} + +void ArchipelagoConsole_PrintJson(const std::list nodes) { + Items.push_back(nodes); } void ArchipelagoConsoleWindow::DrawElement() { @@ -28,57 +43,60 @@ void ArchipelagoConsoleWindow::DrawElement() { ImGui::PushStyleColor(ImGuiCol_ChildBg, ImVec4(0.15f, 0.15f, 0.15f, 1.0f)); ImGui::PushStyleVar(ImGuiStyleVar_ChildRounding, 8.0f); ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(15.0f, 12.0f)); + ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0.0f, 2.0f)); if (ImGui::BeginChild("ScrollingRegion", ImVec2(0, 400), ImGuiChildFlags_AlwaysUseWindowPadding, ImGuiWindowFlags_HorizontalScrollbar)) { - for (int i = 0; i < Items.Size; i++) { - const char* item = Items[i]; - ImVec4 color; - bool hasColor = false; - if (strstr(item, "[ERROR]")) { - color = ImVec4(1.0f, 0.4f, 0.4f, 1.0f); - hasColor = true; - } else if (strstr(item, "[LOG]")) { - color = ImVec4(0.7f, 0.7f, 1.0f, 1.0f); - hasColor = true; - } else if (strstr(item, "[Found]")) { - color = ImVec4(0.24f, 0.64f, 0.69f, 1.00f); - hasColor = true; - } else if (strstr(item, "[Received]")) { - color = ImVec4(0.18f, 0.76f, 0.42f, 1.00f); - hasColor = true; - } else if (strstr(item, "[ItemCheat]")) { - color = ImVec4(0.97f, 0.26f, 0.26f, 1.00f); - hasColor = true; - } else if (strstr(item, "[Hint]")) { - color = ImVec4(0.89f, 0.45f, 1.00f, 1.00f); - hasColor = true; - } else if (strstr(item, "[Join]")) { - color = ImVec4(0.00f, 0.80f, 0.11f, 1.00f); - hasColor = true; - } else if (strstr(item, "[Part]")) { - color = ImVec4(1.00f, 0.01f, 0.01f, 1.00f); - hasColor = true; - } else if (strstr(item, "[Goal]")) { - color = ImVec4(0.00f, 0.70f, 0.21f, 1.00f); - hasColor = true; - } else if (strstr(item, "[Release]")) { - color = ImVec4(0.51f, 0.21f, 0.61f, 1.00f); - hasColor = true; - } else if (strstr(item, "[Collect]")) { - color = ImVec4(0.51f, 0.21f, 0.61f, 1.00f); - hasColor = true; - } - if (hasColor) { - ImGui::PushStyleColor(ImGuiCol_Text, color); - } + for (const std::list& line : Items) { + for(const APClient::TextNode& node : line) { + APClient* client = ArchipelagoClient::GetInstance().apClient.get(); + std::string color; + std::string text; - ImGui::TextUnformatted(item); + if(node.type == "player_id") { + int id = std::stoi(node.text); + if (color.empty() && id == client->get_player_number()) color = "magenta"; + else if(color.empty()) color = "yellow"; + text = client->get_player_alias(id); + } else if (node.type == "item_id") { + int64_t id = std::stoll(node.text); + if(color.empty()) { + if (node.flags & APClient::ItemFlags::FLAG_ADVANCEMENT) color = "plum"; + else if (node.flags & APClient::ItemFlags::FLAG_NEVER_EXCLUDE) color = "slateblue"; + else if (node.flags & APClient::ItemFlags::FLAG_TRAP) color = "salmon"; + else color = "cyan"; + } + text = client->get_item_name(id, client->get_player_game(node.player)); + } else if (node.type == "location_id") { + int64_t id = std::stoll(node.text); + if (color.empty()) color = "blue"; + text = client->get_location_name(id, client->get_player_game(node.player)); + } else if (node.type == "hint_status") { + text = node.text; + if (node.hintStatus == APClient::HINT_FOUND) color = "green"; + else if (node.hintStatus == APClient::HINT_UNSPECIFIED) color = "grey"; + else if (node.hintStatus == APClient::HINT_NO_PRIORITY) color = "slateblue"; + else if (node.hintStatus == APClient::HINT_AVOID) color = "salmon"; + else if (node.hintStatus == APClient::HINT_PRIORITY) color = "plum"; + else color = "red"; // unknown status -> red + } else if (node.type == "ERROR") { + color = "ERROR"; + text = node.text; + } else if (node.type == "LOG") { + color = "LOG"; + text = node.text; + } else { + color = "white"; + text = node.text; + } - if (hasColor) { + ImGui::PushStyleColor(ImGuiCol_Text, getColorVal(color)); + ImGui::TextUnformatted(text.c_str()); + ImGui::SameLine(); ImGui::PopStyleColor(); } + ImGui::NewLine(); } // Keep up at the bottom of the scroll region if we were already at the bottom at the beginning of the frame. @@ -89,5 +107,38 @@ void ArchipelagoConsoleWindow::DrawElement() { } ImGui::EndChild(); ImGui::PopStyleColor(); - ImGui::PopStyleVar(2); + ImGui::PopStyleVar(3); }; + +ImVec4 getColorVal(const std::string& color) { + if (color == "ERROR") { + return ImVec4(1.0f, 0.4f, 0.4f, 1.0f); + } else if(color =="LOG") { + return ImVec4(0.7f, 0.7f, 1.0f, 1.0f); + } else if(color == "black") { + return ImVec4(0.000f, 0.000f, 0.000f, 1.00f); + } else if(color == "red") { + return ImVec4(0.933f, 0.000f, 0.000f, 1.00f); + } else if(color == "green") { + return ImVec4(0.000f, 1.000f, 0.498f, 1.00f); + } else if(color == "yellow") { + return ImVec4(0.980f, 0.980f, 0.824f, 1.00f); + } else if(color == "blue") { + return ImVec4(0.392f, 0.584f, 0.929f, 1.00f); + } else if(color == "cyan") { + return ImVec4(0.000f, 0.933f, 0.933f, 1.00f); + } else if(color == "magenta") { + return ImVec4(0.933f, 0.000f, 0.933f, 1.00f); + } else if(color == "slateblue") { + return ImVec4(0.427f, 0.545f, 0.910f, 1.00f); + } else if(color == "plum") { + return ImVec4(0.686f, 0.600f, 0.937f, 1.00f); + } else if(color == "salmon") { + return ImVec4(0.980f, 0.502f, 0.447f, 1.00f); + } else if(color == "white") { + return ImVec4(0.93f, 0.93f, 0.93f, 1.00f); + } else if(color == "orange") { + return ImVec4(1.000, 0.467f, 0.000f, 1.000f); + } + return ImVec4(0.93f, 0.93f, 0.93f, 1.00f); +} \ No newline at end of file diff --git a/soh/soh/Network/Archipelago/ArchipelagoConsoleWindow.h b/soh/soh/Network/Archipelago/ArchipelagoConsoleWindow.h index 46cc3332e..60332e1b6 100644 --- a/soh/soh/Network/Archipelago/ArchipelagoConsoleWindow.h +++ b/soh/soh/Network/Archipelago/ArchipelagoConsoleWindow.h @@ -3,6 +3,9 @@ #define ARCHIPELAGO_CONSOLE_WINDOW_H #include +#include +#include +#include class ArchipelagoConsoleWindow final : public Ship::GuiWindow { public: @@ -16,5 +19,7 @@ class ArchipelagoConsoleWindow final : public Ship::GuiWindow { }; void ArchipelagoConsole_SendMessage(const char* fmt, bool debugMessage = false, ...); +void ArchipelagoConsole_PrintJson(const std::list nodes); +ImVec4 getColorVal(const std::string& color); #endif // ARCHIPELAGO_CONSOLE_WINDOW_H \ No newline at end of file From 7d49cb1281f8debb78b11150c343f3df9d920071 Mon Sep 17 00:00:00 2001 From: Jerom Venneker Date: Thu, 29 May 2025 00:00:13 +0200 Subject: [PATCH 6/8] Refactor so apclientpp.h doesn't have to be included a second time --- soh/soh/Network/Archipelago/Archipelago.cpp | 52 ++++++++++++++- soh/soh/Network/Archipelago/Archipelago.h | 5 ++ .../Archipelago/ArchipelagoConsoleWindow.cpp | 66 ++++--------------- .../Archipelago/ArchipelagoConsoleWindow.h | 4 +- 4 files changed, 70 insertions(+), 57 deletions(-) diff --git a/soh/soh/Network/Archipelago/Archipelago.cpp b/soh/soh/Network/Archipelago/Archipelago.cpp index c760f3f1a..6e64489cc 100644 --- a/soh/soh/Network/Archipelago/Archipelago.cpp +++ b/soh/soh/Network/Archipelago/Archipelago.cpp @@ -134,7 +134,57 @@ bool ArchipelagoClient::StartClient() { return; } - ArchipelagoConsole_PrintJson(arg.data); + std::vector coloredNodes; + + for(const APClient::TextNode& node : arg.data) { + APClient* client = apClient.get(); + std::string color; + std::string text; + + if(node.type == "player_id") { + int id = std::stoi(node.text); + if (color.empty() && id == client->get_player_number()) color = "magenta"; + else if(color.empty()) color = "yellow"; + text = client->get_player_alias(id); + } else if (node.type == "item_id") { + int64_t id = std::stoll(node.text); + if(color.empty()) { + if (node.flags & APClient::ItemFlags::FLAG_ADVANCEMENT) color = "plum"; + else if (node.flags & APClient::ItemFlags::FLAG_NEVER_EXCLUDE) color = "slateblue"; + else if (node.flags & APClient::ItemFlags::FLAG_TRAP) color = "salmon"; + else color = "cyan"; + } + text = client->get_item_name(id, client->get_player_game(node.player)); + } else if (node.type == "location_id") { + int64_t id = std::stoll(node.text); + if (color.empty()) color = "blue"; + text = client->get_location_name(id, client->get_player_game(node.player)); + } else if (node.type == "hint_status") { + text = node.text; + if (node.hintStatus == APClient::HINT_FOUND) color = "green"; + else if (node.hintStatus == APClient::HINT_UNSPECIFIED) color = "grey"; + else if (node.hintStatus == APClient::HINT_NO_PRIORITY) color = "slateblue"; + else if (node.hintStatus == APClient::HINT_AVOID) color = "salmon"; + else if (node.hintStatus == APClient::HINT_PRIORITY) color = "plum"; + else color = "red"; // unknown status -> red + } else if (node.type == "ERROR") { + color = "ERROR"; + text = node.text; + } else if (node.type == "LOG") { + color = "LOG"; + text = node.text; + } else { + color = "white"; + text = node.text; + } + + ColoredTextNode Colornode; + Colornode.color = color; + Colornode.text = text; + coloredNodes.push_back(Colornode); + } + + ArchipelagoConsole_PrintJson(coloredNodes); }); return true; diff --git a/soh/soh/Network/Archipelago/Archipelago.h b/soh/soh/Network/Archipelago/Archipelago.h index c52a7bea9..bd8a14d6e 100644 --- a/soh/soh/Network/Archipelago/Archipelago.h +++ b/soh/soh/Network/Archipelago/Archipelago.h @@ -27,6 +27,11 @@ class ArchipelagoClient{ uint64_t index; }; + struct ColoredTextNode { + std::string text; + std::string color; + }; + static ArchipelagoClient& GetInstance(); bool StartClient(); diff --git a/soh/soh/Network/Archipelago/ArchipelagoConsoleWindow.cpp b/soh/soh/Network/Archipelago/ArchipelagoConsoleWindow.cpp index 169571c70..eea74ac02 100644 --- a/soh/soh/Network/Archipelago/ArchipelagoConsoleWindow.cpp +++ b/soh/soh/Network/Archipelago/ArchipelagoConsoleWindow.cpp @@ -4,7 +4,7 @@ #include "soh/SohGui/SohGui.hpp" #include "soh/OTRGlobals.h" -std::vector> Items; +std::vector> Items; bool autoScroll = true; using namespace UIWidgets; @@ -19,21 +19,20 @@ void ArchipelagoConsole_SendMessage(const char* fmt, bool debugMessage, ...) { vsnprintf(buf, IM_ARRAYSIZE(buf), fmt, args); buf[IM_ARRAYSIZE(buf) - 1] = 0; va_end(args); - APClient::TextNode node; + ArchipelagoClient::ColoredTextNode node; + node.text = std::string(buf); + node.color = "white"; if (strstr(buf, "[ERROR]")) { - node.type = "ERROR"; node.color = "ERROR"; } else if (strstr(buf, "[LOG]")) { - node.type = "LOG"; node.color = "LOG"; } - node.text = std::string(buf); - std::list line; + std::vector line; line.push_back(node); Items.push_back(line); } -void ArchipelagoConsole_PrintJson(const std::list nodes) { +void ArchipelagoConsole_PrintJson(const std::vector nodes) { Items.push_back(nodes); } @@ -43,56 +42,15 @@ void ArchipelagoConsoleWindow::DrawElement() { ImGui::PushStyleColor(ImGuiCol_ChildBg, ImVec4(0.15f, 0.15f, 0.15f, 1.0f)); ImGui::PushStyleVar(ImGuiStyleVar_ChildRounding, 8.0f); ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(15.0f, 12.0f)); - ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0.0f, 2.0f)); + ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0.0f, 1.0f)); if (ImGui::BeginChild("ScrollingRegion", ImVec2(0, 400), ImGuiChildFlags_AlwaysUseWindowPadding, ImGuiWindowFlags_HorizontalScrollbar)) { - for (const std::list& line : Items) { - for(const APClient::TextNode& node : line) { - APClient* client = ArchipelagoClient::GetInstance().apClient.get(); - std::string color; - std::string text; - - if(node.type == "player_id") { - int id = std::stoi(node.text); - if (color.empty() && id == client->get_player_number()) color = "magenta"; - else if(color.empty()) color = "yellow"; - text = client->get_player_alias(id); - } else if (node.type == "item_id") { - int64_t id = std::stoll(node.text); - if(color.empty()) { - if (node.flags & APClient::ItemFlags::FLAG_ADVANCEMENT) color = "plum"; - else if (node.flags & APClient::ItemFlags::FLAG_NEVER_EXCLUDE) color = "slateblue"; - else if (node.flags & APClient::ItemFlags::FLAG_TRAP) color = "salmon"; - else color = "cyan"; - } - text = client->get_item_name(id, client->get_player_game(node.player)); - } else if (node.type == "location_id") { - int64_t id = std::stoll(node.text); - if (color.empty()) color = "blue"; - text = client->get_location_name(id, client->get_player_game(node.player)); - } else if (node.type == "hint_status") { - text = node.text; - if (node.hintStatus == APClient::HINT_FOUND) color = "green"; - else if (node.hintStatus == APClient::HINT_UNSPECIFIED) color = "grey"; - else if (node.hintStatus == APClient::HINT_NO_PRIORITY) color = "slateblue"; - else if (node.hintStatus == APClient::HINT_AVOID) color = "salmon"; - else if (node.hintStatus == APClient::HINT_PRIORITY) color = "plum"; - else color = "red"; // unknown status -> red - } else if (node.type == "ERROR") { - color = "ERROR"; - text = node.text; - } else if (node.type == "LOG") { - color = "LOG"; - text = node.text; - } else { - color = "white"; - text = node.text; - } - - ImGui::PushStyleColor(ImGuiCol_Text, getColorVal(color)); - ImGui::TextUnformatted(text.c_str()); + for(const std::vector& line : Items) { + for(const ArchipelagoClient::ColoredTextNode& node : line) { + ImGui::PushStyleColor(ImGuiCol_Text, getColorVal(node.color)); + ImGui::TextUnformatted(node.text.c_str()); ImGui::SameLine(); ImGui::PopStyleColor(); } @@ -110,7 +68,7 @@ void ArchipelagoConsoleWindow::DrawElement() { ImGui::PopStyleVar(3); }; -ImVec4 getColorVal(const std::string& color) { +ImVec4 getColorVal(const std::string& color) { // TODO change color strings to an enum if (color == "ERROR") { return ImVec4(1.0f, 0.4f, 0.4f, 1.0f); } else if(color =="LOG") { diff --git a/soh/soh/Network/Archipelago/ArchipelagoConsoleWindow.h b/soh/soh/Network/Archipelago/ArchipelagoConsoleWindow.h index 60332e1b6..07597c515 100644 --- a/soh/soh/Network/Archipelago/ArchipelagoConsoleWindow.h +++ b/soh/soh/Network/Archipelago/ArchipelagoConsoleWindow.h @@ -3,7 +3,7 @@ #define ARCHIPELAGO_CONSOLE_WINDOW_H #include -#include +#include "Archipelago.h" #include #include @@ -19,7 +19,7 @@ class ArchipelagoConsoleWindow final : public Ship::GuiWindow { }; void ArchipelagoConsole_SendMessage(const char* fmt, bool debugMessage = false, ...); -void ArchipelagoConsole_PrintJson(const std::list nodes); +void ArchipelagoConsole_PrintJson(const std::vector nodes); ImVec4 getColorVal(const std::string& color); #endif // ARCHIPELAGO_CONSOLE_WINDOW_H \ No newline at end of file From 497700fe6af3711188cbf4ae836e2f0b2398e3c5 Mon Sep 17 00:00:00 2001 From: Jerom Venneker Date: Thu, 29 May 2025 19:38:38 +0200 Subject: [PATCH 7/8] Added textbox to console window for chatting and server commands --- soh/soh/Network/Archipelago/Archipelago.cpp | 8 ++++++++ soh/soh/Network/Archipelago/Archipelago.h | 2 +- .../Archipelago/ArchipelagoConsoleWindow.cpp | 20 +++++++++++++++++++ 3 files changed, 29 insertions(+), 1 deletion(-) diff --git a/soh/soh/Network/Archipelago/Archipelago.cpp b/soh/soh/Network/Archipelago/Archipelago.cpp index 6e64489cc..1990f7c1c 100644 --- a/soh/soh/Network/Archipelago/Archipelago.cpp +++ b/soh/soh/Network/Archipelago/Archipelago.cpp @@ -342,6 +342,14 @@ void ArchipelagoClient::SendGameWon() { } } +void ArchipelagoClient::SendMessage(const char* message) { + if(apClient == nullptr) { + return; + } + + apClient->Say(std::string(message)); +} + void ArchipelagoClient::Poll() { if(apClient == nullptr) { return; diff --git a/soh/soh/Network/Archipelago/Archipelago.h b/soh/soh/Network/Archipelago/Archipelago.h index bd8a14d6e..a2056c71a 100644 --- a/soh/soh/Network/Archipelago/Archipelago.h +++ b/soh/soh/Network/Archipelago/Archipelago.h @@ -58,7 +58,7 @@ class ArchipelagoClient{ void QueueExternalCheck(int64_t apLocation); void SendGameWon(); - + void SendMessage(const char* message); void Poll(); std::unique_ptr apClient; diff --git a/soh/soh/Network/Archipelago/ArchipelagoConsoleWindow.cpp b/soh/soh/Network/Archipelago/ArchipelagoConsoleWindow.cpp index eea74ac02..66a91d692 100644 --- a/soh/soh/Network/Archipelago/ArchipelagoConsoleWindow.cpp +++ b/soh/soh/Network/Archipelago/ArchipelagoConsoleWindow.cpp @@ -66,6 +66,26 @@ void ArchipelagoConsoleWindow::DrawElement() { ImGui::EndChild(); ImGui::PopStyleColor(); ImGui::PopStyleVar(3); + + static char textEntryBuf[1024]; + static bool keepFocus = false; + + if(keepFocus) { + ImGui::SetKeyboardFocusHere(); + keepFocus = false; + } + if(ImGui::InputText("##AP_MessageField", textEntryBuf, 1023, ImGuiInputTextFlags_EnterReturnsTrue)) { + ArchipelagoClient::GetInstance().SendMessage(textEntryBuf); + textEntryBuf[0] = '\0'; + keepFocus = true; + } + //keepFocus = ImGui::IsItemActive(); + ImGui::SameLine(); + if(ImGui::Button("Send")) { + ArchipelagoClient::GetInstance().SendMessage(textEntryBuf); + textEntryBuf[0] = '\0'; + keepFocus = true; + } }; ImVec4 getColorVal(const std::string& color) { // TODO change color strings to an enum From 03c93484fd72a360b885c2120a66f1dabb5f258c Mon Sep 17 00:00:00 2001 From: Jerom Venneker Date: Fri, 30 May 2025 11:36:34 +0200 Subject: [PATCH 8/8] Added Error messages when attempting to send messages while disconnected and when attempting to use local commands --- soh/soh/Network/Archipelago/Archipelago.cpp | 13 ++++++++++--- soh/soh/Network/Archipelago/Archipelago.h | 2 +- .../Archipelago/ArchipelagoConsoleWindow.cpp | 4 ++-- 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/soh/soh/Network/Archipelago/Archipelago.cpp b/soh/soh/Network/Archipelago/Archipelago.cpp index 1990f7c1c..c6e495608 100644 --- a/soh/soh/Network/Archipelago/Archipelago.cpp +++ b/soh/soh/Network/Archipelago/Archipelago.cpp @@ -342,12 +342,19 @@ void ArchipelagoClient::SendGameWon() { } } -void ArchipelagoClient::SendMessage(const char* message) { - if(apClient == nullptr) { +void ArchipelagoClient::SendMessage(const std::string message) { + // local commands not implemented yet + if(message.starts_with("/")) { + ArchipelagoConsole_SendMessage("Ship of Harkinian does not have any local commands yet.\nUse !help\" to see server commands instead", false); return; } - apClient->Say(std::string(message)); + if(apClient == nullptr) { + ArchipelagoConsole_SendMessage("[ERROR] Could not send message. Please Connect to your slot.", false); + return; + } + + apClient->Say(message); } void ArchipelagoClient::Poll() { diff --git a/soh/soh/Network/Archipelago/Archipelago.h b/soh/soh/Network/Archipelago/Archipelago.h index a2056c71a..fecb6038a 100644 --- a/soh/soh/Network/Archipelago/Archipelago.h +++ b/soh/soh/Network/Archipelago/Archipelago.h @@ -58,7 +58,7 @@ class ArchipelagoClient{ void QueueExternalCheck(int64_t apLocation); void SendGameWon(); - void SendMessage(const char* message); + void SendMessage(const std::string message); void Poll(); std::unique_ptr apClient; diff --git a/soh/soh/Network/Archipelago/ArchipelagoConsoleWindow.cpp b/soh/soh/Network/Archipelago/ArchipelagoConsoleWindow.cpp index 66a91d692..b1580711f 100644 --- a/soh/soh/Network/Archipelago/ArchipelagoConsoleWindow.cpp +++ b/soh/soh/Network/Archipelago/ArchipelagoConsoleWindow.cpp @@ -75,14 +75,14 @@ void ArchipelagoConsoleWindow::DrawElement() { keepFocus = false; } if(ImGui::InputText("##AP_MessageField", textEntryBuf, 1023, ImGuiInputTextFlags_EnterReturnsTrue)) { - ArchipelagoClient::GetInstance().SendMessage(textEntryBuf); + ArchipelagoClient::GetInstance().SendMessage(std::string(textEntryBuf)); textEntryBuf[0] = '\0'; keepFocus = true; } //keepFocus = ImGui::IsItemActive(); ImGui::SameLine(); if(ImGui::Button("Send")) { - ArchipelagoClient::GetInstance().SendMessage(textEntryBuf); + ArchipelagoClient::GetInstance().SendMessage(std::string(textEntryBuf)); textEntryBuf[0] = '\0'; keepFocus = true; }