diff options
| author | Sylvessa <225480449+sylvessa@users.noreply.github.com> | 2026-03-26 09:15:11 -0500 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-03-26 10:15:11 -0400 |
| commit | 1a50770647c582c5ce194e5741e3014bb1c1e8b2 (patch) | |
| tree | 8160994034f5f58b222032b73f8cda8c42e92479 /Minecraft.Client/Common | |
| parent | dee559bd16e5fc4fb1d8cdd16e7e3924666b01c9 (diff) | |
Add asynchronous server joining (#1408)
Diffstat (limited to 'Minecraft.Client/Common')
6 files changed, 201 insertions, 21 deletions
diff --git a/Minecraft.Client/Common/Network/GameNetworkManager.h b/Minecraft.Client/Common/Network/GameNetworkManager.h index 3357b3cd..22d58807 100644 --- a/Minecraft.Client/Common/Network/GameNetworkManager.h +++ b/Minecraft.Client/Common/Network/GameNetworkManager.h @@ -47,7 +47,8 @@ public: { JOINGAME_SUCCESS, JOINGAME_FAIL_GENERAL, - JOINGAME_FAIL_SERVER_FULL + JOINGAME_FAIL_SERVER_FULL, + JOINGAME_PENDING } eJoinGameResult; void Initialise(); diff --git a/Minecraft.Client/Common/Network/PlatformNetworkManagerStub.cpp b/Minecraft.Client/Common/Network/PlatformNetworkManagerStub.cpp index 1e625098..430f2c11 100644 --- a/Minecraft.Client/Common/Network/PlatformNetworkManagerStub.cpp +++ b/Minecraft.Client/Common/Network/PlatformNetworkManagerStub.cpp @@ -173,6 +173,11 @@ bool CPlatformNetworkManagerStub::Initialise(CGameNetworkManager *pGameNetworkMa m_bSearchPending = false; m_bIsOfflineGame = false; +#ifdef _WINDOWS64 + m_bJoinPending = false; + m_joinLocalUsersMask = 0; + m_joinHostName[0] = 0; +#endif m_pSearchParam = nullptr; m_SessionsUpdatedCallback = nullptr; @@ -282,6 +287,38 @@ void CPlatformNetworkManagerStub::DoWork() m_bLeaveGameOnTick = false; } } + + if (m_bJoinPending) + { + WinsockNetLayer::eJoinState state = WinsockNetLayer::GetJoinState(); + if (state == WinsockNetLayer::eJoinState_Success) + { + WinsockNetLayer::FinalizeJoin(); + + BYTE localSmallId = WinsockNetLayer::GetLocalSmallId(); + + IQNet::m_player[localSmallId].m_smallId = localSmallId; + IQNet::m_player[localSmallId].m_isRemote = false; + IQNet::m_player[localSmallId].m_isHostPlayer = false; + IQNet::m_player[localSmallId].m_resolvedXuid = Win64Xuid::ResolvePersistentXuid(); + + Minecraft* pMinecraft = Minecraft::GetInstance(); + wcscpy_s(IQNet::m_player[localSmallId].m_gamertag, 32, pMinecraft->user->name.c_str()); + IQNet::s_playerCount = localSmallId + 1; + + NotifyPlayerJoined(&IQNet::m_player[0]); + NotifyPlayerJoined(&IQNet::m_player[localSmallId]); + + m_pGameNetworkManager->StateChange_AnyToStarting(); + m_bJoinPending = false; + } + else if (state == WinsockNetLayer::eJoinState_Failed || + state == WinsockNetLayer::eJoinState_Rejected || + state == WinsockNetLayer::eJoinState_Cancelled) + { + m_bJoinPending = false; + } + } #endif } @@ -511,36 +548,22 @@ int CPlatformNetworkManagerStub::JoinGame(FriendSessionInfo* searchResult, int l IQNet::m_player[0].m_smallId = 0; IQNet::m_player[0].m_isRemote = true; IQNet::m_player[0].m_isHostPlayer = true; - // Remote host still maps to legacy host XUID in mixed old/new sessions. IQNet::m_player[0].m_resolvedXuid = Win64Xuid::GetLegacyEmbeddedHostXuid(); wcsncpy_s(IQNet::m_player[0].m_gamertag, 32, searchResult->data.hostName, _TRUNCATE); WinsockNetLayer::StopDiscovery(); - if (!WinsockNetLayer::JoinGame(hostIP, hostPort)) + wcsncpy_s(m_joinHostName, 32, searchResult->data.hostName, _TRUNCATE); + m_joinLocalUsersMask = localUsersMask; + + if (!WinsockNetLayer::BeginJoinGame(hostIP, hostPort)) { app.DebugPrintf("Win64 LAN: Failed to connect to %s:%d\n", hostIP, hostPort); return CGameNetworkManager::JOINGAME_FAIL_GENERAL; } - BYTE localSmallId = WinsockNetLayer::GetLocalSmallId(); - - IQNet::m_player[localSmallId].m_smallId = localSmallId; - IQNet::m_player[localSmallId].m_isRemote = false; - IQNet::m_player[localSmallId].m_isHostPlayer = false; - // Local non-host identity is the persistent uid.dat XUID. - IQNet::m_player[localSmallId].m_resolvedXuid = Win64Xuid::ResolvePersistentXuid(); - - Minecraft* pMinecraft = Minecraft::GetInstance(); - wcscpy_s(IQNet::m_player[localSmallId].m_gamertag, 32, pMinecraft->user->name.c_str()); - IQNet::s_playerCount = localSmallId + 1; - - NotifyPlayerJoined(&IQNet::m_player[0]); - NotifyPlayerJoined(&IQNet::m_player[localSmallId]); - - m_pGameNetworkManager->StateChange_AnyToStarting(); - - return CGameNetworkManager::JOINGAME_SUCCESS; + m_bJoinPending = true; + return CGameNetworkManager::JOINGAME_PENDING; #else return CGameNetworkManager::JOINGAME_SUCCESS; #endif diff --git a/Minecraft.Client/Common/Network/PlatformNetworkManagerStub.h b/Minecraft.Client/Common/Network/PlatformNetworkManagerStub.h index 4a3f4068..dffa3953 100644 --- a/Minecraft.Client/Common/Network/PlatformNetworkManagerStub.h +++ b/Minecraft.Client/Common/Network/PlatformNetworkManagerStub.h @@ -77,6 +77,12 @@ private: bool m_bIsPrivateGame; int m_flagIndexSize; +#ifdef _WINDOWS64 + bool m_bJoinPending; + int m_joinLocalUsersMask; + wchar_t m_joinHostName[32]; +#endif + // This is only maintained by the host, and is not valid on client machines GameSessionData m_hostGameSessionData; CGameNetworkManager *m_pGameNetworkManager; 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; |
