From 1fe3871f6c4e6b055e9c8f5f339aa1f6e7f5656f Mon Sep 17 00:00:00 2001 From: Jerom Venneker Date: Thu, 12 Jun 2025 21:52:47 +0200 Subject: [PATCH] Added automatic move to name entry after connecting and scouting --- soh/soh/Network/Archipelago/Archipelago.cpp | 19 +++++- soh/soh/Network/Archipelago/Archipelago.h | 2 + .../ovl_file_choose/z_file_choose.c | 66 +++++++++++++++---- 3 files changed, 73 insertions(+), 14 deletions(-) diff --git a/soh/soh/Network/Archipelago/Archipelago.cpp b/soh/soh/Network/Archipelago/Archipelago.cpp index 656c27670..2a024facc 100644 --- a/soh/soh/Network/Archipelago/Archipelago.cpp +++ b/soh/soh/Network/Archipelago/Archipelago.cpp @@ -43,10 +43,24 @@ bool ArchipelagoClient::StartClient() { } disconnecting = false; + retries = 0; apClient = std::unique_ptr( new APClient(uuid, AP_Client_consts::AP_GAME_NAME, CVarGetString(CVAR_REMOTE_ARCHIPELAGO("ServerAddress"), "localhost:38281"), "cacert.pem")); + CVarSetInteger(CVAR_REMOTE_ARCHIPELAGO("ConnectionStatus"), 1); // connecting + + apClient->set_socket_error_handler([&](const std::string& msg) { + retries++; + if(retries > AP_Client_consts::MAX_RETRIES) { + ArchipelagoConsole_SendMessage("[ERROR] Could not connect to server"); + CVarSetInteger(CVAR_REMOTE_ARCHIPELAGO("ConnectionStatus"), 2); // connection error + disconnecting = true; + return; + } + ArchipelagoConsole_SendMessage("[ERROR] Could not connect to server, retrying..."); + }); + apClient->set_room_info_handler([&]() { std::list tags; // tags.push_back("DeathLink"); // todo, implement deathlink @@ -56,6 +70,7 @@ bool ArchipelagoClient::StartClient() { }); apClient->set_slot_connected_handler([&](const nlohmann::json data) { + CVarSetInteger(CVAR_REMOTE_ARCHIPELAGO("ConnectionStatus"), 3); // slot connected ArchipelagoConsole_SendMessage("[LOG] Connected.", true); ArchipelagoClient::StartLocationScouts(); @@ -117,6 +132,7 @@ bool ArchipelagoClient::StartClient() { } ArchipelagoConsole_SendMessage("[LOG] Scouting finished.", true); + CVarSetInteger(CVAR_REMOTE_ARCHIPELAGO("ConnectionStatus"), 4); // locations scouted }); // 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) { @@ -370,6 +386,7 @@ void ArchipelagoClient::Poll() { if(disconnecting) { apClient->reset(); apClient = nullptr; + disconnecting = false; return; } @@ -527,7 +544,7 @@ void RegisterArchipelago() { // make sure the client is constructed ArchipelagoClient::GetInstance(); - CVarSetInteger(CVAR_REMOTE_ARCHIPELAGO("Connected"), 0); + CVarSetInteger(CVAR_REMOTE_ARCHIPELAGO("ConnectionStatus"), 0); COND_HOOK(GameInteractor::OnGameFrameUpdate, true, [](){ArchipelagoClient::GetInstance().Poll();}); COND_HOOK(GameInteractor::PostLoadGame, true, [](int32_t file_id){ArchipelagoClient::GetInstance().GameLoaded();}); diff --git a/soh/soh/Network/Archipelago/Archipelago.h b/soh/soh/Network/Archipelago/Archipelago.h index c2170145a..95e31c2ff 100644 --- a/soh/soh/Network/Archipelago/Archipelago.h +++ b/soh/soh/Network/Archipelago/Archipelago.h @@ -15,6 +15,7 @@ namespace AP_Client_consts { static constexpr int MAX_PASSWORD_LENGTH = 32; static constexpr char const* AP_GAME_NAME = "Ship of Harkinian"; + static constexpr int MAX_RETRIES = 6; } class ArchipelagoClient{ @@ -64,6 +65,7 @@ class ArchipelagoClient{ std::unique_ptr apClient; bool itemQueued; bool disconnecting; + int retries; protected: ArchipelagoClient(); 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 c00f92f70..333a29431 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 @@ -1076,14 +1076,14 @@ void FileChoose_UpdateRandomizer() { } } -u8 connecting; - -void FileChoose_UpdateArchipelago() { - if (CVarGetInteger(CVAR_REMOTE_ARCHIPELAGO("Connected"), 0) && !fileSelectArchipelagoLoaded) { +bool FileChoose_UpdateArchipelago() { + if (CVarGetInteger(CVAR_REMOTE_ARCHIPELAGO("ConnectionStatus"), 0) == 4 && !fileSelectArchipelagoLoaded) { ParseArchipelago(); fileSelectArchipelagoLoaded = true; Audio_PlayFanfare(NA_BGM_HORSE_GOAL); + return true; } + return false; } static s16 sLastFileChooseButtonIndex; @@ -1774,11 +1774,46 @@ void FileChoose_UpdateArchipelagoMenu(GameState* thisx) { Input* input = &this->state.input[0]; bool dpad = CVarGetInteger(CVAR_SETTING("DpadInText"), 0); - FileChoose_UpdateArchipelago(); - - if(connecting) { - return; + if(FileChoose_UpdateArchipelago()) { + Audio_PlaySoundGeneral(NA_SE_SY_FSEL_DECIDE_L, &gSfxDefaultPos, 4, &gSfxDefaultFreqAndVolScale, + &gSfxDefaultFreqAndVolScale, &gSfxDefaultReverb); + static u8 emptyName[] = { 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E }; + static u8 emptyNameNES[] = { 0xDF, 0xDF, 0xDF, 0xDF, 0xDF, 0xDF, 0xDF, 0xDF }; + static u8 linkName[] = { 0x15, 0x2C, 0x31, 0x2E, 0x3E, 0x3E, 0x3E, 0x3E }; + static u8 linkNameNES[] = { 0xB6, 0xB3, 0xB8, 0xB5, 0xDF, 0xDF, 0xDF, 0xDF }; + static u8 linkNameJP[] = { 0x81, 0x87, 0x61, 0xDF, 0xDF, 0xDF, 0xDF, 0xDF }; + u8* defaultName; + + this->prevConfigMode = this->configMode; + this->configMode = CM_ROTATE_TO_NAME_ENTRY; + this->logoAlpha = 0; + CVarSetInteger(CVAR_GENERAL("OnFileSelectNameEntry"), 1); + this->kbdButton = FS_KBD_BTN_NONE; + this->charPage = FS_CHAR_PAGE_ENG; + this->kbdX = 0; + this->kbdY = 0; + this->charIndex = 0; + this->charBgAlpha = 0; + this->newFileNameCharCount = CVarGetInteger(CVAR_ENHANCEMENT("LinkDefaultName"), 0) ? 4 : 0; + this->nameEntryBoxPosX = 120; + this->nameEntryBoxAlpha = 0; + if (ResourceMgr_GetGameRegion(0) == GAME_REGION_PAL && gSaveContext.language != LANGUAGE_JPN) { + defaultName = CVarGetInteger(CVAR_ENHANCEMENT("LinkDefaultName"), 0) ? &linkName : &emptyName; + } else if (gSaveContext.language == LANGUAGE_JPN) { // Japanese + if (CVarGetInteger(CVAR_ENHANCEMENT("LinkDefaultName"), 0) != 0) { + // Set player name to "リンク" ("Link" in Katakana, 3 characters long) when playing in Japanese. + defaultName = &linkNameJP; + this->newFileNameCharCount = 3; + } else { + defaultName = &emptyNameNES; + } + this->charPage = FS_CHAR_PAGE_HIRA; // Default to Hiragana Keyboard + } else { // GAME_REGION_NTSC + defaultName = CVarGetInteger(CVAR_ENHANCEMENT("LinkDefaultName"), 0) ? &linkNameNES : &emptyNameNES; + } + memcpy(Save_GetSaveMetaInfo(this->buttonIndex)->playerName, defaultName, 8); } + // Fade in elements after opening Archipelago Options menu this->archipelagoUIAlpha += 25; @@ -2845,11 +2880,16 @@ void FileChoose_DrawWindowContents(GameState* thisx) { Interface_DrawTextLine(this->state.gfxCtx, SohFileSelect_GetArchipelagoSettingText(index, language), 70, (80 + ((5 + index) * 16)), textColorR, textColorG, textColorB, textAlpha, 0.8f, true); } - - // Show text to indicate the client is connecting to the server. - if (connecting) { - Interface_DrawTextLine(this->state.gfxCtx, SohFileSelect_GetArchipelagoSettingText(ASM_CONNECTING, language), 70, - (80 + 64), 255, 255, 255, textAlpha, 0.8f, true); + + switch(CVarGetInteger(CVAR_REMOTE_ARCHIPELAGO("ConnectionStatus"), 0)) { + case 1: + Interface_DrawTextLine(this->state.gfxCtx, SohFileSelect_GetArchipelagoSettingText(ASM_CONNECTING, language), 70, + (80 + 64), 185, 185, 185, textAlpha, 0.8f, true); + break; + case 2: + Interface_DrawTextLine(this->state.gfxCtx, SohFileSelect_GetArchipelagoSettingText(ASM_CONNECTION_ERROR, language), 70, + (80 + 64), 255, 100, 100, textAlpha, 0.8f, true); + break; } uint16_t textOffset = 16 * (5 + this->archipelagoIndex);