Fix server list refresh and add cancellable non-blocking connection
Server list: edits and deletions now update the UI immediately by calling SearchForGames() in ForceFriendsSessionRefresh() and UpdateGamesList() on nav-back to LoadOrJoinMenu. Connection: moved WinsockNetLayer::JoinGame() to a background thread with non-blocking sockets (5s timeout, 3 retries). Users can cancel with B/Escape during the attempt. Failed connections always show an error dialog.
This commit is contained in:
@@ -772,8 +772,32 @@ void CGameNetworkManager::CancelJoinGame(LPVOID lpParam)
|
||||
#ifdef _XBOX_ONE
|
||||
s_pPlatformNetworkManager->CancelJoinGame();
|
||||
#endif
|
||||
#ifdef _WINDOWS64
|
||||
static_cast<CPlatformNetworkManagerStub*>(s_pPlatformNetworkManager)->CancelJoinGame();
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef _WINDOWS64
|
||||
bool CGameNetworkManager::BeginJoinGameAsync(FriendSessionInfo *searchResult, int localUsersMask)
|
||||
{
|
||||
app.SetTutorialMode(false);
|
||||
g_NetworkManager.SetLocalGame(false);
|
||||
|
||||
int primaryUserIndex = ProfileManager.GetLockedProfile();
|
||||
|
||||
Minecraft::GetInstance()->clearConnectionFailed();
|
||||
|
||||
localUsersMask |= GetLocalPlayerMask(ProfileManager.GetPrimaryPad());
|
||||
|
||||
return static_cast<CPlatformNetworkManagerStub*>(s_pPlatformNetworkManager)->BeginJoinGameAsync(searchResult, localUsersMask, primaryUserIndex);
|
||||
}
|
||||
|
||||
int CGameNetworkManager::FinishJoinGame(FriendSessionInfo *searchResult)
|
||||
{
|
||||
return static_cast<CPlatformNetworkManagerStub*>(s_pPlatformNetworkManager)->FinishJoinGame(searchResult);
|
||||
}
|
||||
#endif
|
||||
|
||||
bool CGameNetworkManager::LeaveGame(bool bMigrateHost)
|
||||
{
|
||||
Minecraft::GetInstance()->gui->clearMessages();
|
||||
|
||||
@@ -106,6 +106,10 @@ public:
|
||||
bool JoinGameFromInviteInfo( int userIndex, int userMask, const INVITE_INFO *pInviteInfo);
|
||||
eJoinGameResult JoinGame(FriendSessionInfo *searchResult, int localUsersMask);
|
||||
static void CancelJoinGame(LPVOID lpParam); // Not part of the shared interface
|
||||
#ifdef _WINDOWS64
|
||||
bool BeginJoinGameAsync(FriendSessionInfo *searchResult, int localUsersMask);
|
||||
int FinishJoinGame(FriendSessionInfo *searchResult);
|
||||
#endif
|
||||
bool LeaveGame(bool bMigrateHost);
|
||||
static int JoinFromInvite_SignInReturned(void *pParam,bool bContinue, int iPad);
|
||||
void UpdateAndSetGameSessionData(INetworkPlayer *pNetworkPlayerLeaving = nullptr);
|
||||
|
||||
@@ -546,6 +546,61 @@ int CPlatformNetworkManagerStub::JoinGame(FriendSessionInfo* searchResult, int l
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef _WINDOWS64
|
||||
bool CPlatformNetworkManagerStub::BeginJoinGameAsync(FriendSessionInfo* searchResult, int localUsersMask, int primaryUserIndex)
|
||||
{
|
||||
if (searchResult == nullptr)
|
||||
return false;
|
||||
|
||||
const char* hostIP = searchResult->data.hostIP;
|
||||
int hostPort = searchResult->data.hostPort;
|
||||
|
||||
if (hostPort <= 0 || hostIP[0] == 0)
|
||||
return false;
|
||||
|
||||
m_bLeavingGame = false;
|
||||
m_bLeaveGameOnTick = false;
|
||||
IQNet::s_isHosting = false;
|
||||
m_pIQNet->ClientJoinGame();
|
||||
|
||||
IQNet::m_player[0].m_smallId = 0;
|
||||
IQNet::m_player[0].m_isRemote = true;
|
||||
IQNet::m_player[0].m_isHostPlayer = true;
|
||||
IQNet::m_player[0].m_resolvedXuid = Win64Xuid::GetLegacyEmbeddedHostXuid();
|
||||
wcsncpy_s(IQNet::m_player[0].m_gamertag, 32, searchResult->data.hostName, _TRUNCATE);
|
||||
|
||||
WinsockNetLayer::StopDiscovery();
|
||||
|
||||
return WinsockNetLayer::StartJoinGameAsync(hostIP, hostPort);
|
||||
}
|
||||
|
||||
int CPlatformNetworkManagerStub::FinishJoinGame(FriendSessionInfo* searchResult)
|
||||
{
|
||||
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();
|
||||
|
||||
return CGameNetworkManager::JOINGAME_SUCCESS;
|
||||
}
|
||||
|
||||
void CPlatformNetworkManagerStub::CancelJoinGame()
|
||||
{
|
||||
WinsockNetLayer::CancelJoinGame();
|
||||
}
|
||||
#endif
|
||||
|
||||
bool CPlatformNetworkManagerStub::SetLocalGame(bool isLocal)
|
||||
{
|
||||
m_bIsOfflineGame = isLocal;
|
||||
@@ -955,6 +1010,13 @@ void CPlatformNetworkManagerStub::ForceFriendsSessionRefresh()
|
||||
delete m_pSearchResults[i];
|
||||
m_pSearchResults[i] = nullptr;
|
||||
}
|
||||
|
||||
#ifdef _WINDOWS64
|
||||
// Immediately rebuild the session list from servers.db so that
|
||||
// edits/deletions are visible as soon as the UI regains focus,
|
||||
// rather than waiting for the next TickSearch() cycle.
|
||||
SearchForGames();
|
||||
#endif
|
||||
}
|
||||
|
||||
INetworkPlayer *CPlatformNetworkManagerStub::addNetworkPlayer(IQNetPlayer *pQNetPlayer)
|
||||
|
||||
@@ -42,6 +42,11 @@ public:
|
||||
|
||||
virtual void HostGame(int localUsersMask, bool bOnlineGame, bool bIsPrivate, unsigned char publicSlots = MINECRAFT_NET_MAX_PLAYERS, unsigned char privateSlots = 0);
|
||||
virtual int JoinGame(FriendSessionInfo *searchResult, int localUsersMask, int primaryUserIndex );
|
||||
#ifdef _WINDOWS64
|
||||
bool BeginJoinGameAsync(FriendSessionInfo *searchResult, int localUsersMask, int primaryUserIndex);
|
||||
int FinishJoinGame(FriendSessionInfo *searchResult);
|
||||
void CancelJoinGame();
|
||||
#endif
|
||||
virtual bool SetLocalGame(bool isLocal);
|
||||
virtual bool IsLocalGame() { return m_bIsOfflineGame; }
|
||||
virtual void SetPrivateGame(bool isPrivate);
|
||||
|
||||
@@ -7,6 +7,9 @@
|
||||
#include "..\..\MinecraftServer.h"
|
||||
#include "..\..\..\Minecraft.World\net.minecraft.world.level.h"
|
||||
#include "..\..\..\Minecraft.World\net.minecraft.world.h"
|
||||
#ifdef _WINDOWS64
|
||||
#include "..\..\Windows64\Network\WinsockNetLayer.h"
|
||||
#endif
|
||||
|
||||
#define UPDATE_PLAYERS_TIMER_ID 0
|
||||
#define UPDATE_PLAYERS_TIMER_TIME 30000
|
||||
@@ -26,6 +29,8 @@ UIScene_JoinMenu::UIScene_JoinMenu(int iPad, void *_initData, UILayer *parentLay
|
||||
m_editServerPhase = eEditServer_Idle;
|
||||
m_editServerButtonIndex = -1;
|
||||
m_deleteServerButtonIndex = -1;
|
||||
m_asyncJoinInProgress = false;
|
||||
m_joinLocalUsersMask = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -59,6 +64,35 @@ void UIScene_JoinMenu::updateTooltips()
|
||||
|
||||
void UIScene_JoinMenu::tick()
|
||||
{
|
||||
#ifdef _WINDOWS64
|
||||
if (m_asyncJoinInProgress && WinsockNetLayer::IsJoinComplete())
|
||||
{
|
||||
m_asyncJoinInProgress = false;
|
||||
if (WinsockNetLayer::GetJoinResult())
|
||||
{
|
||||
int result = g_NetworkManager.FinishJoinGame(m_selectedSession);
|
||||
app.SetLiveLinkRequired(false);
|
||||
if (result != CGameNetworkManager::JOINGAME_SUCCESS)
|
||||
{
|
||||
m_bIgnoreInput = false;
|
||||
m_buttonJoinGame.setLabel(app.GetString(IDS_JOIN_GAME));
|
||||
updateTooltips();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
app.SetLiveLinkRequired(false);
|
||||
m_bIgnoreInput = false;
|
||||
m_buttonJoinGame.setLabel(app.GetString(IDS_JOIN_GAME));
|
||||
updateTooltips();
|
||||
|
||||
UINT uiIDA[1];
|
||||
uiIDA[0] = IDS_CONFIRM_OK;
|
||||
ui.RequestErrorMessage(IDS_CONNECTION_FAILED, IDS_CONNECTION_LOST_SERVER, uiIDA, 1, ProfileManager.GetPrimaryPad());
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if( !m_friendInfoRequestIssued )
|
||||
{
|
||||
ui.NavigateToScene(m_iPad, eUIScene_Timer);
|
||||
@@ -282,6 +316,19 @@ wstring UIScene_JoinMenu::getMoviePath()
|
||||
|
||||
void UIScene_JoinMenu::handleInput(int iPad, int key, bool repeat, bool pressed, bool released, bool &handled)
|
||||
{
|
||||
#ifdef _WINDOWS64
|
||||
if (m_asyncJoinInProgress && key == ACTION_MENU_CANCEL && pressed)
|
||||
{
|
||||
g_NetworkManager.CancelJoinGame(nullptr);
|
||||
m_asyncJoinInProgress = false;
|
||||
m_bIgnoreInput = false;
|
||||
m_buttonJoinGame.setLabel(app.GetString(IDS_JOIN_GAME));
|
||||
updateTooltips();
|
||||
handled = true;
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
if(m_bIgnoreInput) return;
|
||||
|
||||
ui.AnimateKeyPress(m_iPad, key, repeat, pressed, released);
|
||||
@@ -578,7 +625,19 @@ void UIScene_JoinMenu::JoinGame(UIScene_JoinMenu* pClass)
|
||||
ProfileManager.DisplaySystemMessage( SCE_MSG_DIALOG_SYSMSG_TYPE_TRC_PSN_CHAT_RESTRICTION, ProfileManager.GetPrimaryPad() );
|
||||
}
|
||||
#endif
|
||||
#ifdef _WINDOWS64
|
||||
if (g_NetworkManager.BeginJoinGameAsync(pClass->m_selectedSession, dwLocalUsersMask))
|
||||
{
|
||||
pClass->m_asyncJoinInProgress = true;
|
||||
pClass->m_joinLocalUsersMask = dwLocalUsersMask;
|
||||
pClass->m_buttonJoinGame.setLabel(app.GetString(IDS_PROGRESS_CONNECTING));
|
||||
ui.SetTooltips(DEFAULT_XUI_MENU_USER, -1, IDS_TOOLTIPS_CANCEL_JOIN);
|
||||
return;
|
||||
}
|
||||
CGameNetworkManager::eJoinGameResult result = CGameNetworkManager::JOINGAME_FAIL_GENERAL;
|
||||
#else
|
||||
CGameNetworkManager::eJoinGameResult result = g_NetworkManager.JoinGame( pClass->m_selectedSession, dwLocalUsersMask );
|
||||
#endif
|
||||
|
||||
// Alert the app the we no longer want to be informed of ethernet connections
|
||||
app.SetLiveLinkRequired( false );
|
||||
@@ -637,16 +696,18 @@ void UIScene_JoinMenu::JoinGame(UIScene_JoinMenu* pClass)
|
||||
|
||||
if( exitReasonStringId == -1 )
|
||||
{
|
||||
ui.NavigateBack(pClass->m_iPad);
|
||||
// No specific disconnect reason was set — the server was likely
|
||||
// unreachable. Show a "Connection Failed" dialog instead of
|
||||
// silently navigating back so the user knows what happened.
|
||||
exitReasonStringId = IDS_CONNECTION_LOST_SERVER;
|
||||
}
|
||||
else
|
||||
|
||||
{
|
||||
UINT uiIDA[1];
|
||||
uiIDA[0]=IDS_CONFIRM_OK;
|
||||
ui.RequestErrorMessage( IDS_CONNECTION_FAILED, exitReasonStringId, uiIDA,1,ProfileManager.GetPrimaryPad());
|
||||
exitReasonStringId = -1;
|
||||
|
||||
ui.NavigateToHomeMenu();
|
||||
pClass->m_bIgnoreInput = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,6 +70,8 @@ private:
|
||||
wstring m_editServerPort;
|
||||
int m_editServerButtonIndex;
|
||||
int m_deleteServerButtonIndex;
|
||||
bool m_asyncJoinInProgress;
|
||||
DWORD m_joinLocalUsersMask;
|
||||
#endif
|
||||
|
||||
public:
|
||||
|
||||
@@ -637,6 +637,11 @@ void UIScene_LoadOrJoinMenu::handleGainFocus(bool navBack)
|
||||
|
||||
if( m_bMultiplayerAllowed )
|
||||
{
|
||||
#ifdef _WINDOWS64
|
||||
// Refresh the games list immediately so that any server
|
||||
// edits/deletions made in the JoinMenu are visible now.
|
||||
UpdateGamesList();
|
||||
#endif
|
||||
#if TO_BE_IMPLEMENTED
|
||||
HXUICLASS hClassFullscreenProgress = XuiFindClass( L"CScene_FullscreenProgress" );
|
||||
HXUICLASS hClassConnectingProgress = XuiFindClass( L"CScene_ConnectingProgress" );
|
||||
|
||||
Reference in New Issue
Block a user