diff --git a/soh/include/z64save.h b/soh/include/z64save.h index 6a0e0b720..3aa867891 100644 --- a/soh/include/z64save.h +++ b/soh/include/z64save.h @@ -178,6 +178,7 @@ typedef struct ShipArchipelagoSaveContextData { u32 lastReceivedItemIndex; char roomHash[100]; char slotName[17]; + char archiUri[50]; ArchipelagoLocationData locations[RC_MAX]; } ShipArchipelagoSaveContextData; diff --git a/soh/soh/Enhancements/FileSelectEnhancements.cpp b/soh/soh/Enhancements/FileSelectEnhancements.cpp index 4d8208733..b75e7d81c 100644 --- a/soh/soh/Enhancements/FileSelectEnhancements.cpp +++ b/soh/soh/Enhancements/FileSelectEnhancements.cpp @@ -111,6 +111,24 @@ std::array ArchipelagoSettingsMenuText[ASM_MAX]{ "Todo", "Todo", }, + //ASM_CHAR_START_TO_CONNECT + { + "Start to automatically connect to this slot", + "Todo", + "Todo", + }, + //ASM_CHAR_SELECT_CONNECTED_TO_OTHER_SLOT + { + "Connected to a different slot", + "Todo", + "Todo", + }, + // ASM_CHAR_SELECT_CHANGE_CONNECTION_INFO + { + "Z-Connection Settings", + "Z-Todo", + "Z-Todo", + } }; const char* SohFileSelect_GetRandomizerSettingText(uint8_t optionIndex, uint8_t language) { diff --git a/soh/soh/Enhancements/FileSelectEnhancements.h b/soh/soh/Enhancements/FileSelectEnhancements.h index 680c7be1e..b76f728e7 100644 --- a/soh/soh/Enhancements/FileSelectEnhancements.h +++ b/soh/soh/Enhancements/FileSelectEnhancements.h @@ -30,6 +30,9 @@ typedef enum { ASM_CONNECTING, ASM_CONNECTED, ASM_STATUS, + ASM_CHAR_START_TO_CONNECT, + ASM_CHAR_SELECT_CONNECTED_TO_OTHER_SLOT, + ASM_CHAR_SELECT_CHANGE_CONNECTION_INFO, ASM_MAX } ArchipelagoSettingsMenuEnums; diff --git a/soh/soh/Network/Archipelago/Archipelago.cpp b/soh/soh/Network/Archipelago/Archipelago.cpp index a73b30d8a..d5abd4e88 100644 --- a/soh/soh/Network/Archipelago/Archipelago.cpp +++ b/soh/soh/Network/Archipelago/Archipelago.cpp @@ -45,9 +45,10 @@ bool ArchipelagoClient::StartClient() { disconnecting = false; retries = 0; + uri = CVarGetString(CVAR_REMOTE_ARCHIPELAGO("ServerAddress"), "localhost:38281"); apClient = std::unique_ptr( new APClient(uuid, AP_Client_consts::AP_GAME_NAME, - CVarGetString(CVAR_REMOTE_ARCHIPELAGO("ServerAddress"), "localhost:38281"), "cacert.pem")); + uri, "cacert.pem")); CVarSetInteger(CVAR_REMOTE_ARCHIPELAGO("ConnectionStatus"), 1); // Connecting @@ -424,6 +425,23 @@ void ArchipelagoClient::Poll() { apClient->poll(); } +bool ArchipelagoClient::slotMatch(const std::string& slotName, const std::string& roomHash) { + if (apClient == nullptr) { + return false; + } + + if(disconnecting) { + return false; + } + + const std::string seed = apClient->get_seed(); + const std::string slot = GetSlotName(); + + const bool seedMatch = apClient->get_seed().compare(roomHash) == 0; + const bool slotMatch = GetSlotName().compare(slotName) == 0; + return seedMatch && slotMatch; +} + 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; @@ -524,6 +542,8 @@ extern "C" void Archipelago_InitSaveFile() { 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)); + SohUtils::CopyStringToCharArray(gSaveContext.ship.quest.data.archipelago.archiUri, client.uri, + ARRAY_COUNT(gSaveContext.ship.quest.data.archipelago.archiUri)); for (uint32_t i = 0; i < scoutedItems.size(); i++) { RandomizerCheck rc = Rando::StaticData::locationNameToEnum[scoutedItems[i].locationName]; @@ -546,6 +566,8 @@ void LoadArchipelagoData() { ARRAY_COUNT(gSaveContext.ship.quest.data.archipelago.roomHash)); SaveManager::Instance->LoadCharArray("slotName", gSaveContext.ship.quest.data.archipelago.slotName, ARRAY_COUNT(gSaveContext.ship.quest.data.archipelago.slotName)); + SaveManager::Instance->LoadCharArray("archiUri", gSaveContext.ship.quest.data.archipelago.archiUri, + ARRAY_COUNT(gSaveContext.ship.quest.data.archipelago.archiUri)); SaveManager::Instance->LoadArray( "locations", ARRAY_COUNT(gSaveContext.ship.quest.data.archipelago.locations), [](size_t i) { @@ -567,6 +589,7 @@ void SaveArchipelagoData(SaveContext* saveContext, int sectionID, bool fullSave) SaveManager::Instance->SaveData("roomHash", saveContext->ship.quest.data.archipelago.roomHash); SaveManager::Instance->SaveData("slotName", saveContext->ship.quest.data.archipelago.slotName); + SaveManager::Instance->SaveData("archiUri", saveContext->ship.quest.data.archipelago.archiUri); SaveManager::Instance->SaveArray( "locations", ARRAY_COUNT(saveContext->ship.quest.data.archipelago.locations), [&](size_t i) { @@ -587,6 +610,8 @@ void InitArchipelagoData(bool isDebug) { ARRAY_COUNT(gSaveContext.ship.quest.data.archipelago.roomHash)); SohUtils::CopyStringToCharArray(gSaveContext.ship.quest.data.archipelago.slotName, "", ARRAY_COUNT(gSaveContext.ship.quest.data.archipelago.slotName)); + SohUtils::CopyStringToCharArray(gSaveContext.ship.quest.data.archipelago.archiUri, "", + ARRAY_COUNT(gSaveContext.ship.quest.data.archipelago.archiUri)); for (uint32_t i = 0; i < ARRAY_COUNT(gSaveContext.ship.quest.data.archipelago.locations); i++) { SohUtils::CopyStringToCharArray(gSaveContext.ship.quest.data.archipelago.locations[i].itemName, "", diff --git a/soh/soh/Network/Archipelago/Archipelago.h b/soh/soh/Network/Archipelago/Archipelago.h index d71d5466d..17adb3747 100644 --- a/soh/soh/Network/Archipelago/Archipelago.h +++ b/soh/soh/Network/Archipelago/Archipelago.h @@ -62,11 +62,14 @@ class ArchipelagoClient { void SendMessageToConsole(const std::string message); void Poll(); + bool slotMatch(const std::string& slotName, const std::string& roomHash); + std::unique_ptr apClient; bool itemQueued; bool disconnecting; bool isDeathLinkedDeath; int retries; + std::string uri; protected: ArchipelagoClient(); diff --git a/soh/soh/OTRGlobals.cpp b/soh/soh/OTRGlobals.cpp index 53b65a848..76e9afeee 100644 --- a/soh/soh/OTRGlobals.cpp +++ b/soh/soh/OTRGlobals.cpp @@ -2728,6 +2728,12 @@ extern "C" void ParseArchipelago() { OTRGlobals::Instance->gRandoContext->ParseArchipelago(); } +extern "C" bool checkArchipelagoSlotInfo(const char* slotName, const char* roomHash) { + const std::string slot = std::string(slotName); + const std::string room = std::string(roomHash); + return ArchipelagoClient::GetInstance().slotMatch(slot, room); +} + extern "C" void CheckTracker_RecalculateAvailableChecks() { CheckTracker::RecalculateAvailableChecks(); } diff --git a/soh/soh/OTRGlobals.h b/soh/soh/OTRGlobals.h index e3d4e9048..74029ce59 100644 --- a/soh/soh/OTRGlobals.h +++ b/soh/soh/OTRGlobals.h @@ -173,6 +173,7 @@ void CheckTracker_RecalculateAvailableChecks(); GetItemID RetrieveGetItemIDFromItemID(ItemID itemID); RandomizerGet RetrieveRandomizerGetFromItemID(ItemID itemID); void ParseArchipelago(); +bool checkArchipelagoSlotInfo(const char* slotName, const char* roomHash); void Messagebox_ShowErrorBox(char* title, char* body); #endif diff --git a/soh/soh/SaveManager.cpp b/soh/soh/SaveManager.cpp index c7eb49950..c9fbb7582 100644 --- a/soh/soh/SaveManager.cpp +++ b/soh/soh/SaveManager.cpp @@ -154,6 +154,9 @@ SaveManager::SaveManager() { info.buildVersionMinor = 0; info.buildVersionPatch = 0; memset(&info.buildVersion, 0, sizeof(info.buildVersion)); + + memset(&info.archiUri, 0, sizeof(info.archiUri)); + memset(&info.slotName, 0, sizeof(info.slotName)); } } @@ -509,6 +512,13 @@ void SaveManager::InitMeta(int fileNum) { fileMetaInfo[fileNum].buildVersionPatch = gSaveContext.ship.stats.buildVersionPatch; SohUtils::CopyStringToCharArray(fileMetaInfo[fileNum].buildVersion, gSaveContext.ship.stats.buildVersion, ARRAY_COUNT(fileMetaInfo[fileNum].buildVersion)); + + SohUtils::CopyStringToCharArray(fileMetaInfo[fileNum].archiUri, gSaveContext.ship.quest.data.archipelago.archiUri, + ARRAY_COUNT(fileMetaInfo[fileNum].archiUri)); + SohUtils::CopyStringToCharArray(fileMetaInfo[fileNum].slotName, gSaveContext.ship.quest.data.archipelago.slotName, + ARRAY_COUNT(fileMetaInfo[fileNum].slotName)); + SohUtils::CopyStringToCharArray(fileMetaInfo[fileNum].archiRoomSeed, gSaveContext.ship.quest.data.archipelago.roomHash, + ARRAY_COUNT(fileMetaInfo[fileNum].archiRoomSeed)); } void SaveManager::InitFile(bool isDebug) { diff --git a/soh/soh/SaveManager.h b/soh/soh/SaveManager.h index 8cdb16a91..7baad1dac 100644 --- a/soh/soh/SaveManager.h +++ b/soh/soh/SaveManager.h @@ -33,6 +33,10 @@ typedef struct { s32 filenameLanguage; s32 gregFound; s32 hasWallet; + + char archiRoomSeed[100]; + char slotName[17]; + char archiUri[50]; } SaveFileMetaInfo; typedef enum { diff --git a/soh/src/overlays/gamestates/ovl_file_choose/z_file_choose.c b/soh/src/overlays/gamestates/ovl_file_choose/z_file_choose.c index 0e323d565..6ace3962e 100644 --- a/soh/src/overlays/gamestates/ovl_file_choose/z_file_choose.c +++ b/soh/src/overlays/gamestates/ovl_file_choose/z_file_choose.c @@ -2478,7 +2478,8 @@ void FileChoose_DrawFileInfo(GameState* thisx, s16 fileIndex, s16 isActive) { &deathCountSplit[2]); // draw death count - if (CVarGetInteger(CVAR_ENHANCEMENT("FileSelectMoreInfo"), 0) == 0 || this->menuMode != FS_MENU_MODE_SELECT) { + if (CVarGetInteger(CVAR_ENHANCEMENT("FileSelectMoreInfo"), 0) == 0 || this->menuMode != FS_MENU_MODE_SELECT || + Save_GetSaveMetaInfo(this->selectedFileIndex)->archiSave) { for (i = 0, vtxOffset = 0; i < 3; i++, vtxOffset += 4) { FileChoose_DrawCharacter(this->state.gfxCtx, sp54->fontBuf + deathCountSplit[i] * FONT_CHAR_TEX_SIZE, vtxOffset); @@ -2504,7 +2505,8 @@ void FileChoose_DrawFileInfo(GameState* thisx, s16 fileIndex, s16 isActive) { i = Save_GetSaveMetaInfo(fileIndex)->healthCapacity / 0x10; - if (CVarGetInteger(CVAR_ENHANCEMENT("FileSelectMoreInfo"), 0) == 0 || this->menuMode != FS_MENU_MODE_SELECT) { + if (CVarGetInteger(CVAR_ENHANCEMENT("FileSelectMoreInfo"), 0) == 0 || this->menuMode != FS_MENU_MODE_SELECT || + Save_GetSaveMetaInfo(this->selectedFileIndex)->archiSave) { // draw hearts for (vtxOffset = 0, j = 0; j < i; j++, vtxOffset += 4) { gSPVertex(POLY_OPA_DISP++, &this->windowContentVtx[D_8081284C[fileIndex] + vtxOffset] + 0x30, 4, 0); @@ -2521,7 +2523,8 @@ void FileChoose_DrawFileInfo(GameState* thisx, s16 fileIndex, s16 isActive) { textAlpha = 255; } - if (CVarGetInteger(CVAR_ENHANCEMENT("FileSelectMoreInfo"), 0) != 0 && this->menuMode == FS_MENU_MODE_SELECT) { + if (CVarGetInteger(CVAR_ENHANCEMENT("FileSelectMoreInfo"), 0) != 0 && this->menuMode == FS_MENU_MODE_SELECT && + Save_GetSaveMetaInfo(this->selectedFileIndex)->archiSave == 0) { DrawMoreInfo(this, fileIndex, textAlpha); } else { // draw quest items @@ -2545,6 +2548,53 @@ void FileChoose_DrawFileInfo(GameState* thisx, s16 fileIndex, s16 isActive) { } } } + + if(Save_GetSaveMetaInfo(this->selectedFileIndex)->archiSave) { + uint8_t language = (gSaveContext.language == LANGUAGE_JPN) ? LANGUAGE_ENG : gSaveContext.language; + + // Connection status text + int statusPos = 61 + Interface_DrawTextLine(this->state.gfxCtx, SohFileSelect_GetArchipelagoSettingText(ASM_STATUS, language), + 58, 133, 200, 200, 200, textAlpha, 0.8f, true); + + const bool connectedToThisSlot = checkArchipelagoSlotInfo(Save_GetSaveMetaInfo(this->selectedFileIndex)->slotName, + Save_GetSaveMetaInfo(this->selectedFileIndex)->archiRoomSeed); + + switch(CVarGetInteger(CVAR_REMOTE_ARCHIPELAGO("ConnectionStatus"), 0)) { + case 0: // Not Connected + Interface_DrawTextLine(this->state.gfxCtx, + SohFileSelect_GetArchipelagoSettingText(ASM_NOT_CONNECTED, language), + statusPos, 133, 255, 120, 120, textAlpha, 0.8f, true); + break; + case 1: // Connecting + case 2: // Connection error, retrying + case 3: // Connected + Interface_DrawTextLine(this->state.gfxCtx, + SohFileSelect_GetArchipelagoSettingText(ASM_CONNECTING, language), + statusPos, 133, 185, 185, 185, textAlpha, 0.8f, true); + break; + case 4: // Connected + Locations Scouted + if(connectedToThisSlot) { + Interface_DrawTextLine(this->state.gfxCtx, + SohFileSelect_GetArchipelagoSettingText(ASM_CONNECTED, language), + statusPos, 133, 120, 255, 120, textAlpha, 0.8f, true); + } else { + Interface_DrawTextLine(this->state.gfxCtx, + SohFileSelect_GetArchipelagoSettingText(ASM_CHAR_SELECT_CONNECTED_TO_OTHER_SLOT, language), + statusPos, 133, 255, 255, 120, textAlpha, 0.8f, true); + } + + break; + } + + if(!connectedToThisSlot) { + Interface_DrawTextLine(this->state.gfxCtx, SohFileSelect_GetArchipelagoSettingText(ASM_CHAR_START_TO_CONNECT, language), + 58, 144, 200, 200, 200, textAlpha, 0.8f, true); + } + + //Interface_DrawTextLine(this->state.gfxCtx, + // SohFileSelect_GetArchipelagoSettingText(ASM_CHAR_SELECT_CHANGE_CONNECTION_INFO, language), 95, 220, + // 100, 250, 255, textAlpha, 1.0f, true); + } } CLOSE_DISPS(this->state.gfxCtx); @@ -2944,25 +2994,25 @@ void FileChoose_DrawWindowContents(GameState* thisx) { 155, 185, 185, 185, textAlpha, 0.8f, true); // Connection status text - Interface_DrawTextLine(this->state.gfxCtx, SohFileSelect_GetArchipelagoSettingText(ASM_STATUS, language), 70, + int statusPos = 75 + Interface_DrawTextLine(this->state.gfxCtx, SohFileSelect_GetArchipelagoSettingText(ASM_STATUS, language), 70, 175, 255, 255, 255, textAlpha, 0.8f, true); switch (CVarGetInteger(CVAR_REMOTE_ARCHIPELAGO("ConnectionStatus"), 0)) { case 0: // Not Connected Interface_DrawTextLine(this->state.gfxCtx, - SohFileSelect_GetArchipelagoSettingText(ASM_NOT_CONNECTED, language), 110, 175, + SohFileSelect_GetArchipelagoSettingText(ASM_NOT_CONNECTED, language), statusPos, 175, 255, 120, 120, textAlpha, 0.8f, true); break; case 1: // Connecting case 2: // Connection error, retrying case 3: // Connected Interface_DrawTextLine(this->state.gfxCtx, - SohFileSelect_GetArchipelagoSettingText(ASM_CONNECTING, language), 110, 175, 185, + SohFileSelect_GetArchipelagoSettingText(ASM_CONNECTING, language), statusPos, 175, 185, 185, 185, textAlpha, 0.8f, true); break; case 4: // Connected + Locations Scouted Interface_DrawTextLine(this->state.gfxCtx, - SohFileSelect_GetArchipelagoSettingText(ASM_CONNECTED, language), 110, 175, 120, + SohFileSelect_GetArchipelagoSettingText(ASM_CONNECTED, language), statusPos, 175, 120, 255, 120, textAlpha, 0.8f, true); break; } @@ -3005,7 +3055,7 @@ void FileChoose_DrawWindowContents(GameState* thisx) { // Draw the small file name box instead when more meta info is enabled if (CVarGetInteger(CVAR_ENHANCEMENT("FileSelectMoreInfo"), 0) != 0 && - this->menuMode == FS_MENU_MODE_SELECT) { + this->menuMode == FS_MENU_MODE_SELECT && Save_GetSaveMetaInfo(this->selectedFileIndex)->archiSave == 0) { // Location of file 1 small name box vertices gSPVertex(POLY_OPA_DISP++, &this->windowContentVtx[68], 4, 0);