From 1a50770647c582c5ce194e5741e3014bb1c1e8b2 Mon Sep 17 00:00:00 2001 From: Sylvessa <225480449+sylvessa@users.noreply.github.com> Date: Thu, 26 Mar 2026 09:15:11 -0500 Subject: Add asynchronous server joining (#1408) --- .../Common/UI/UIScene_ConnectingProgress.cpp | 127 +++++++++++++++++++++ .../Common/UI/UIScene_ConnectingProgress.h | 5 + Minecraft.Client/Common/UI/UIScene_JoinMenu.cpp | 18 +++ 3 files changed, 150 insertions(+) (limited to 'Minecraft.Client/Common/UI') diff --git a/Minecraft.Client/Common/UI/UIScene_ConnectingProgress.cpp b/Minecraft.Client/Common/UI/UIScene_ConnectingProgress.cpp index e10a5a62..40557cd5 100644 --- a/Minecraft.Client/Common/UI/UIScene_ConnectingProgress.cpp +++ b/Minecraft.Client/Common/UI/UIScene_ConnectingProgress.cpp @@ -2,6 +2,16 @@ #include "UI.h" #include "UIScene_ConnectingProgress.h" #include "..\..\Minecraft.h" +#ifdef _WINDOWS64 +#include "..\..\Windows64\Network\WinsockNetLayer.h" +#include "..\..\..\Minecraft.World\DisconnectPacket.h" + +static int ConnectingProgress_OnRejectedDialogOK(LPVOID, int iPad, const C4JStorage::EMessageResult) +{ + ui.NavigateBack(iPad); + return 0; +} +#endif UIScene_ConnectingProgress::UIScene_ConnectingProgress(int iPad, void *_initData, UILayer *parentLayer) : UIScene(iPad, parentLayer) { @@ -43,6 +53,12 @@ UIScene_ConnectingProgress::UIScene_ConnectingProgress(int iPad, void *_initData m_cancelFuncParam = param->cancelFuncParam; m_removeLocalPlayer = false; m_showingButton = false; + +#ifdef _WINDOWS64 + WinsockNetLayer::eJoinState initState = WinsockNetLayer::GetJoinState(); + m_asyncJoinActive = (initState != WinsockNetLayer::eJoinState_Idle && initState != WinsockNetLayer::eJoinState_Cancelled); + m_asyncJoinFailed = false; +#endif } UIScene_ConnectingProgress::~UIScene_ConnectingProgress() @@ -53,6 +69,18 @@ UIScene_ConnectingProgress::~UIScene_ConnectingProgress() void UIScene_ConnectingProgress::updateTooltips() { +#ifdef _WINDOWS64 + if (m_asyncJoinActive) + { + ui.SetTooltips( m_iPad, -1, IDS_TOOLTIPS_BACK); + return; + } + if (m_asyncJoinFailed) + { + ui.SetTooltips( m_iPad, IDS_TOOLTIPS_SELECT, -1); + return; + } +#endif // 4J-PB - removing the option of cancel join, since it didn't work anyway //ui.SetTooltips( m_iPad, -1, m_showTooltips?IDS_TOOLTIPS_CANCEL_JOIN:-1); ui.SetTooltips( m_iPad, -1, -1); @@ -62,6 +90,85 @@ void UIScene_ConnectingProgress::tick() { UIScene::tick(); +#ifdef _WINDOWS64 + if (m_asyncJoinActive) + { + WinsockNetLayer::eJoinState state = WinsockNetLayer::GetJoinState(); + if (state == WinsockNetLayer::eJoinState_Connecting) + { + // connecting............. + int attempt = WinsockNetLayer::GetJoinAttempt(); + int maxAttempts = WinsockNetLayer::GetJoinMaxAttempts(); + char buf[128]; + if (attempt <= 1) + sprintf_s(buf, "Connecting..."); + else + sprintf_s(buf, "Connecting failed, trying again (%d/%d)", attempt, maxAttempts); + wchar_t wbuf[128]; + mbstowcs(wbuf, buf, 128); + m_labelTitle.setLabel(wstring(wbuf)); + } + else if (state == WinsockNetLayer::eJoinState_Success) + { + m_asyncJoinActive = false; + // go go go + } + else if (state == WinsockNetLayer::eJoinState_Cancelled) + { + // cancel + m_asyncJoinActive = false; + navigateBack(); + } + else if (state == WinsockNetLayer::eJoinState_Rejected) + { + // server full and banned are passed differently compared to other disconnects it seems + m_asyncJoinActive = false; + DisconnectPacket::eDisconnectReason reason = WinsockNetLayer::GetJoinRejectReason(); + int exitReasonStringId; + switch (reason) + { + case DisconnectPacket::eDisconnect_ServerFull: + exitReasonStringId = IDS_DISCONNECTED_SERVER_FULL; + break; + case DisconnectPacket::eDisconnect_Banned: + exitReasonStringId = IDS_DISCONNECTED_KICKED; + break; + default: + exitReasonStringId = IDS_CONNECTION_LOST_SERVER; + break; + } + UINT uiIDA[1]; + uiIDA[0] = IDS_CONFIRM_OK; + ui.RequestErrorMessage(IDS_CONNECTION_FAILED, exitReasonStringId, uiIDA, 1, ProfileManager.GetPrimaryPad(), ConnectingProgress_OnRejectedDialogOK, nullptr, nullptr); + } + else if (state == WinsockNetLayer::eJoinState_Failed) + { + // FAIL + m_asyncJoinActive = false; + m_asyncJoinFailed = true; + + int maxAttempts = WinsockNetLayer::GetJoinMaxAttempts(); + char buf[256]; + sprintf_s(buf, "Failed to connect after %d attempts. The server may be unavailable.", maxAttempts); + wchar_t wbuf[256]; + mbstowcs(wbuf, buf, 256); + + // TIL that these exist + // not going to use a actual popup due to it requiring messing with strings which can really mess things up + // i dont trust myself with that + // these need to be touched up later as teh button is a bit offset + m_labelTitle.setLabel(L"Unable to connect to server"); + m_progressBar.setLabel(wstring(wbuf)); + m_progressBar.showBar(false); + m_progressBar.setVisible(true); + m_buttonConfirm.setVisible(true); + m_showingButton = true; + m_controlTimer.setVisible(false); + } + return; + } +#endif + if( m_removeLocalPlayer ) { m_removeLocalPlayer = false; @@ -94,6 +201,8 @@ void UIScene_ConnectingProgress::handleGainFocus(bool navBack) void UIScene_ConnectingProgress::handleLoseFocus() { + if (!m_runFailTimer) return; + int millisecsLeft = getTimer(0)->targetTime - System::currentTimeMillis(); int millisecsTaken = getTimer(0)->duration - millisecsLeft; app.DebugPrintf("\n"); @@ -208,6 +317,17 @@ void UIScene_ConnectingProgress::handleInput(int iPad, int key, bool repeat, boo switch(key) { // 4J-PB - Removed the option to cancel join - it didn't work anyway +#ifdef _WINDOWS64 + case ACTION_MENU_CANCEL: + if (pressed && m_asyncJoinActive) + { + m_asyncJoinActive = false; + WinsockNetLayer::CancelJoinGame(); + navigateBack(); + handled = true; + } + break; +#endif // case ACTION_MENU_CANCEL: // { // if(m_cancelFunc != nullptr) @@ -250,6 +370,13 @@ void UIScene_ConnectingProgress::handlePress(F64 controlId, F64 childId) case eControl_Confirm: if(m_showingButton) { +#ifdef _WINDOWS64 + if (m_asyncJoinFailed) + { + navigateBack(); + } + else +#endif if( m_iPad != ProfileManager.GetPrimaryPad() && g_NetworkManager.IsInSession() ) { // The connection failed if we see the button, so the temp player should be removed and the viewports updated again diff --git a/Minecraft.Client/Common/UI/UIScene_ConnectingProgress.h b/Minecraft.Client/Common/UI/UIScene_ConnectingProgress.h index 2c52284c..eaaea7f6 100644 --- a/Minecraft.Client/Common/UI/UIScene_ConnectingProgress.h +++ b/Minecraft.Client/Common/UI/UIScene_ConnectingProgress.h @@ -13,6 +13,11 @@ private: void (*m_cancelFunc)(LPVOID param); LPVOID m_cancelFuncParam; +#ifdef _WINDOWS64 + bool m_asyncJoinActive; + bool m_asyncJoinFailed; +#endif + enum EControls { eControl_Confirm diff --git a/Minecraft.Client/Common/UI/UIScene_JoinMenu.cpp b/Minecraft.Client/Common/UI/UIScene_JoinMenu.cpp index 417c1700..5b83ea7c 100644 --- a/Minecraft.Client/Common/UI/UIScene_JoinMenu.cpp +++ b/Minecraft.Client/Common/UI/UIScene_JoinMenu.cpp @@ -583,6 +583,24 @@ void UIScene_JoinMenu::JoinGame(UIScene_JoinMenu* pClass) // Alert the app the we no longer want to be informed of ethernet connections app.SetLiveLinkRequired( false ); +#ifdef _WINDOWS64 + if (result == CGameNetworkManager::JOINGAME_PENDING) + { + pClass->m_bIgnoreInput = false; + + ConnectionProgressParams *param = new ConnectionProgressParams(); + param->iPad = ProfileManager.GetPrimaryPad(); + param->stringId = -1; + param->showTooltips = true; + param->setFailTimer = false; + param->timerTime = 0; + param->cancelFunc = nullptr; + param->cancelFuncParam = nullptr; + ui.NavigateToScene(ProfileManager.GetPrimaryPad(), eUIScene_ConnectingProgress, param); + return; + } +#endif + if( result != CGameNetworkManager::JOINGAME_SUCCESS ) { int exitReasonStringId = -1; -- cgit v1.2.3