mirror of
https://git.huckle.dev/Huckles-Minecraft-Archive/LCE-Revelations.git
synced 2026-09-24 01:40:47 +00:00
Refactor async server joining with eJoinState enum and dedicated progress UI
Replace the boolean-flag-based async join system with a clean state machine (eJoinState enum) and move connection progress handling from UIScene_JoinMenu into UIScene_ConnectingProgress as a dedicated UI class. Combines the best of two approaches: non-blocking sockets with select() timeout and SO_RCVTIMEO clearing (prevents random disconnects) with the upstream's state enum, FinalizeJoin separation, and ConnectingProgress UI. JoinGame() now returns JOINGAME_PENDING on Win64, and PlatformNetworkManagerStub::DoWork() polls the join state to finalize the connection when the background thread succeeds.
This commit is contained in:
@@ -773,31 +773,10 @@ void CGameNetworkManager::CancelJoinGame(LPVOID lpParam)
|
|||||||
s_pPlatformNetworkManager->CancelJoinGame();
|
s_pPlatformNetworkManager->CancelJoinGame();
|
||||||
#endif
|
#endif
|
||||||
#ifdef _WINDOWS64
|
#ifdef _WINDOWS64
|
||||||
static_cast<CPlatformNetworkManagerStub*>(s_pPlatformNetworkManager)->CancelJoinGame();
|
WinsockNetLayer::CancelJoinGame();
|
||||||
#endif
|
#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)
|
bool CGameNetworkManager::LeaveGame(bool bMigrateHost)
|
||||||
{
|
{
|
||||||
Minecraft::GetInstance()->gui->clearMessages();
|
Minecraft::GetInstance()->gui->clearMessages();
|
||||||
|
|||||||
@@ -47,7 +47,8 @@ public:
|
|||||||
{
|
{
|
||||||
JOINGAME_SUCCESS,
|
JOINGAME_SUCCESS,
|
||||||
JOINGAME_FAIL_GENERAL,
|
JOINGAME_FAIL_GENERAL,
|
||||||
JOINGAME_FAIL_SERVER_FULL
|
JOINGAME_FAIL_SERVER_FULL,
|
||||||
|
JOINGAME_PENDING
|
||||||
} eJoinGameResult;
|
} eJoinGameResult;
|
||||||
|
|
||||||
void Initialise();
|
void Initialise();
|
||||||
@@ -106,10 +107,6 @@ public:
|
|||||||
bool JoinGameFromInviteInfo( int userIndex, int userMask, const INVITE_INFO *pInviteInfo);
|
bool JoinGameFromInviteInfo( int userIndex, int userMask, const INVITE_INFO *pInviteInfo);
|
||||||
eJoinGameResult JoinGame(FriendSessionInfo *searchResult, int localUsersMask);
|
eJoinGameResult JoinGame(FriendSessionInfo *searchResult, int localUsersMask);
|
||||||
static void CancelJoinGame(LPVOID lpParam); // Not part of the shared interface
|
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);
|
bool LeaveGame(bool bMigrateHost);
|
||||||
static int JoinFromInvite_SignInReturned(void *pParam,bool bContinue, int iPad);
|
static int JoinFromInvite_SignInReturned(void *pParam,bool bContinue, int iPad);
|
||||||
void UpdateAndSetGameSessionData(INetworkPlayer *pNetworkPlayerLeaving = nullptr);
|
void UpdateAndSetGameSessionData(INetworkPlayer *pNetworkPlayerLeaving = nullptr);
|
||||||
|
|||||||
@@ -173,6 +173,9 @@ bool CPlatformNetworkManagerStub::Initialise(CGameNetworkManager *pGameNetworkMa
|
|||||||
m_bSearchPending = false;
|
m_bSearchPending = false;
|
||||||
|
|
||||||
m_bIsOfflineGame = false;
|
m_bIsOfflineGame = false;
|
||||||
|
#ifdef _WINDOWS64
|
||||||
|
m_bJoinPending = false;
|
||||||
|
#endif
|
||||||
m_pSearchParam = nullptr;
|
m_pSearchParam = nullptr;
|
||||||
m_SessionsUpdatedCallback = nullptr;
|
m_SessionsUpdatedCallback = nullptr;
|
||||||
|
|
||||||
@@ -282,6 +285,39 @@ void CPlatformNetworkManagerStub::DoWork()
|
|||||||
m_bLeaveGameOnTick = false;
|
m_bLeaveGameOnTick = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Async join finalization: when the background thread reports success,
|
||||||
|
// register players and transition the session to starting state.
|
||||||
|
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
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -517,90 +553,19 @@ int CPlatformNetworkManagerStub::JoinGame(FriendSessionInfo* searchResult, int l
|
|||||||
|
|
||||||
WinsockNetLayer::StopDiscovery();
|
WinsockNetLayer::StopDiscovery();
|
||||||
|
|
||||||
if (!WinsockNetLayer::JoinGame(hostIP, hostPort))
|
if (!WinsockNetLayer::BeginJoinGame(hostIP, hostPort))
|
||||||
{
|
{
|
||||||
app.DebugPrintf("Win64 LAN: Failed to connect to %s:%d\n", hostIP, hostPort);
|
app.DebugPrintf("Win64 LAN: Failed to start async join to %s:%d\n", hostIP, hostPort);
|
||||||
return CGameNetworkManager::JOINGAME_FAIL_GENERAL;
|
return CGameNetworkManager::JOINGAME_FAIL_GENERAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
BYTE localSmallId = WinsockNetLayer::GetLocalSmallId();
|
m_bJoinPending = true;
|
||||||
|
return CGameNetworkManager::JOINGAME_PENDING;
|
||||||
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;
|
|
||||||
#else
|
#else
|
||||||
return CGameNetworkManager::JOINGAME_SUCCESS;
|
return CGameNetworkManager::JOINGAME_SUCCESS;
|
||||||
#endif
|
#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)
|
bool CPlatformNetworkManagerStub::SetLocalGame(bool isLocal)
|
||||||
{
|
{
|
||||||
m_bIsOfflineGame = isLocal;
|
m_bIsOfflineGame = isLocal;
|
||||||
|
|||||||
@@ -42,11 +42,6 @@ public:
|
|||||||
|
|
||||||
virtual void HostGame(int localUsersMask, bool bOnlineGame, bool bIsPrivate, unsigned char publicSlots = MINECRAFT_NET_MAX_PLAYERS, unsigned char privateSlots = 0);
|
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 );
|
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 SetLocalGame(bool isLocal);
|
||||||
virtual bool IsLocalGame() { return m_bIsOfflineGame; }
|
virtual bool IsLocalGame() { return m_bIsOfflineGame; }
|
||||||
virtual void SetPrivateGame(bool isPrivate);
|
virtual void SetPrivateGame(bool isPrivate);
|
||||||
@@ -81,6 +76,9 @@ private:
|
|||||||
bool m_bIsOfflineGame;
|
bool m_bIsOfflineGame;
|
||||||
bool m_bIsPrivateGame;
|
bool m_bIsPrivateGame;
|
||||||
int m_flagIndexSize;
|
int m_flagIndexSize;
|
||||||
|
#ifdef _WINDOWS64
|
||||||
|
bool m_bJoinPending;
|
||||||
|
#endif
|
||||||
|
|
||||||
// This is only maintained by the host, and is not valid on client machines
|
// This is only maintained by the host, and is not valid on client machines
|
||||||
GameSessionData m_hostGameSessionData;
|
GameSessionData m_hostGameSessionData;
|
||||||
|
|||||||
@@ -2,6 +2,15 @@
|
|||||||
#include "UI.h"
|
#include "UI.h"
|
||||||
#include "UIScene_ConnectingProgress.h"
|
#include "UIScene_ConnectingProgress.h"
|
||||||
#include "..\..\Minecraft.h"
|
#include "..\..\Minecraft.h"
|
||||||
|
#ifdef _WINDOWS64
|
||||||
|
#include "..\..\Windows64\Network\WinsockNetLayer.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)
|
UIScene_ConnectingProgress::UIScene_ConnectingProgress(int iPad, void *_initData, UILayer *parentLayer) : UIScene(iPad, parentLayer)
|
||||||
{
|
{
|
||||||
@@ -43,6 +52,12 @@ UIScene_ConnectingProgress::UIScene_ConnectingProgress(int iPad, void *_initData
|
|||||||
m_cancelFuncParam = param->cancelFuncParam;
|
m_cancelFuncParam = param->cancelFuncParam;
|
||||||
m_removeLocalPlayer = false;
|
m_removeLocalPlayer = false;
|
||||||
m_showingButton = false;
|
m_showingButton = false;
|
||||||
|
#ifdef _WINDOWS64
|
||||||
|
WinsockNetLayer::eJoinState initState = WinsockNetLayer::GetJoinState();
|
||||||
|
m_asyncJoinActive = (initState == WinsockNetLayer::eJoinState_Connecting ||
|
||||||
|
initState == WinsockNetLayer::eJoinState_Success);
|
||||||
|
m_asyncJoinFailed = false;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
UIScene_ConnectingProgress::~UIScene_ConnectingProgress()
|
UIScene_ConnectingProgress::~UIScene_ConnectingProgress()
|
||||||
@@ -53,6 +68,18 @@ UIScene_ConnectingProgress::~UIScene_ConnectingProgress()
|
|||||||
|
|
||||||
void UIScene_ConnectingProgress::updateTooltips()
|
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
|
// 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, m_showTooltips?IDS_TOOLTIPS_CANCEL_JOIN:-1);
|
||||||
ui.SetTooltips( m_iPad, -1, -1);
|
ui.SetTooltips( m_iPad, -1, -1);
|
||||||
@@ -62,6 +89,61 @@ void UIScene_ConnectingProgress::tick()
|
|||||||
{
|
{
|
||||||
UIScene::tick();
|
UIScene::tick();
|
||||||
|
|
||||||
|
#ifdef _WINDOWS64
|
||||||
|
if (m_asyncJoinActive)
|
||||||
|
{
|
||||||
|
WinsockNetLayer::eJoinState state = WinsockNetLayer::GetJoinState();
|
||||||
|
switch (state)
|
||||||
|
{
|
||||||
|
case WinsockNetLayer::eJoinState_Connecting:
|
||||||
|
{
|
||||||
|
int attempt = WinsockNetLayer::GetJoinAttempt();
|
||||||
|
int maxAttempts = WinsockNetLayer::GetJoinMaxAttempts();
|
||||||
|
wchar_t buf[128];
|
||||||
|
if (attempt > 1)
|
||||||
|
swprintf_s(buf, L"Connecting... (attempt %d/%d)", attempt, maxAttempts);
|
||||||
|
else
|
||||||
|
swprintf_s(buf, L"Connecting...");
|
||||||
|
m_labelTitle.setLabel(buf);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case WinsockNetLayer::eJoinState_Success:
|
||||||
|
m_asyncJoinActive = false;
|
||||||
|
m_labelTitle.setLabel(L"Joining world...");
|
||||||
|
break;
|
||||||
|
case WinsockNetLayer::eJoinState_Cancelled:
|
||||||
|
m_asyncJoinActive = false;
|
||||||
|
navigateBack();
|
||||||
|
break;
|
||||||
|
case WinsockNetLayer::eJoinState_Rejected:
|
||||||
|
{
|
||||||
|
m_asyncJoinActive = false;
|
||||||
|
DisconnectPacket::eDisconnectReason reason = WinsockNetLayer::GetJoinRejectReason();
|
||||||
|
int reasonStringId = IDS_CONNECTION_LOST_SERVER;
|
||||||
|
if (reason == DisconnectPacket::eDisconnect_ServerFull)
|
||||||
|
reasonStringId = IDS_DISCONNECTED_SERVER_FULL;
|
||||||
|
else if (reason == DisconnectPacket::eDisconnect_Kicked)
|
||||||
|
reasonStringId = IDS_DISCONNECTED_KICKED;
|
||||||
|
|
||||||
|
UINT uiIDA[1];
|
||||||
|
uiIDA[0] = IDS_CONFIRM_OK;
|
||||||
|
ui.RequestErrorMessage(IDS_CONNECTION_FAILED, reasonStringId, uiIDA, 1, m_iPad, ConnectingProgress_OnRejectedDialogOK, nullptr);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case WinsockNetLayer::eJoinState_Failed:
|
||||||
|
m_asyncJoinActive = false;
|
||||||
|
m_asyncJoinFailed = true;
|
||||||
|
m_labelTitle.setLabel(app.GetString(IDS_CONNECTION_FAILED));
|
||||||
|
m_buttonConfirm.setVisible(true);
|
||||||
|
m_showingButton = true;
|
||||||
|
updateTooltips();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if( m_removeLocalPlayer )
|
if( m_removeLocalPlayer )
|
||||||
{
|
{
|
||||||
m_removeLocalPlayer = false;
|
m_removeLocalPlayer = false;
|
||||||
@@ -94,6 +176,7 @@ void UIScene_ConnectingProgress::handleGainFocus(bool navBack)
|
|||||||
|
|
||||||
void UIScene_ConnectingProgress::handleLoseFocus()
|
void UIScene_ConnectingProgress::handleLoseFocus()
|
||||||
{
|
{
|
||||||
|
if (!m_runFailTimer) return;
|
||||||
int millisecsLeft = getTimer(0)->targetTime - System::currentTimeMillis();
|
int millisecsLeft = getTimer(0)->targetTime - System::currentTimeMillis();
|
||||||
int millisecsTaken = getTimer(0)->duration - millisecsLeft;
|
int millisecsTaken = getTimer(0)->duration - millisecsLeft;
|
||||||
app.DebugPrintf("\n");
|
app.DebugPrintf("\n");
|
||||||
@@ -207,6 +290,18 @@ void UIScene_ConnectingProgress::handleInput(int iPad, int key, bool repeat, boo
|
|||||||
|
|
||||||
switch(key)
|
switch(key)
|
||||||
{
|
{
|
||||||
|
#ifdef _WINDOWS64
|
||||||
|
case ACTION_MENU_CANCEL:
|
||||||
|
if (pressed && m_asyncJoinActive)
|
||||||
|
{
|
||||||
|
m_asyncJoinActive = false;
|
||||||
|
WinsockNetLayer::CancelJoinGame();
|
||||||
|
navigateBack();
|
||||||
|
handled = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
// 4J-PB - Removed the option to cancel join - it didn't work anyway
|
// 4J-PB - Removed the option to cancel join - it didn't work anyway
|
||||||
// case ACTION_MENU_CANCEL:
|
// case ACTION_MENU_CANCEL:
|
||||||
// {
|
// {
|
||||||
@@ -250,6 +345,13 @@ void UIScene_ConnectingProgress::handlePress(F64 controlId, F64 childId)
|
|||||||
case eControl_Confirm:
|
case eControl_Confirm:
|
||||||
if(m_showingButton)
|
if(m_showingButton)
|
||||||
{
|
{
|
||||||
|
#ifdef _WINDOWS64
|
||||||
|
if (m_asyncJoinFailed)
|
||||||
|
{
|
||||||
|
navigateBack();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
if( m_iPad != ProfileManager.GetPrimaryPad() && g_NetworkManager.IsInSession() )
|
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
|
// The connection failed if we see the button, so the temp player should be removed and the viewports updated again
|
||||||
|
|||||||
@@ -12,6 +12,10 @@ private:
|
|||||||
bool m_showingButton;
|
bool m_showingButton;
|
||||||
void (*m_cancelFunc)(LPVOID param);
|
void (*m_cancelFunc)(LPVOID param);
|
||||||
LPVOID m_cancelFuncParam;
|
LPVOID m_cancelFuncParam;
|
||||||
|
#ifdef _WINDOWS64
|
||||||
|
bool m_asyncJoinActive;
|
||||||
|
bool m_asyncJoinFailed;
|
||||||
|
#endif
|
||||||
|
|
||||||
enum EControls
|
enum EControls
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -29,8 +29,6 @@ UIScene_JoinMenu::UIScene_JoinMenu(int iPad, void *_initData, UILayer *parentLay
|
|||||||
m_editServerPhase = eEditServer_Idle;
|
m_editServerPhase = eEditServer_Idle;
|
||||||
m_editServerButtonIndex = -1;
|
m_editServerButtonIndex = -1;
|
||||||
m_deleteServerButtonIndex = -1;
|
m_deleteServerButtonIndex = -1;
|
||||||
m_asyncJoinInProgress = false;
|
|
||||||
m_joinLocalUsersMask = 0;
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -64,35 +62,6 @@ void UIScene_JoinMenu::updateTooltips()
|
|||||||
|
|
||||||
void UIScene_JoinMenu::tick()
|
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 )
|
if( !m_friendInfoRequestIssued )
|
||||||
{
|
{
|
||||||
ui.NavigateToScene(m_iPad, eUIScene_Timer);
|
ui.NavigateToScene(m_iPad, eUIScene_Timer);
|
||||||
@@ -316,19 +285,6 @@ wstring UIScene_JoinMenu::getMoviePath()
|
|||||||
|
|
||||||
void UIScene_JoinMenu::handleInput(int iPad, int key, bool repeat, bool pressed, bool released, bool &handled)
|
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;
|
if(m_bIgnoreInput) return;
|
||||||
|
|
||||||
ui.AnimateKeyPress(m_iPad, key, repeat, pressed, released);
|
ui.AnimateKeyPress(m_iPad, key, repeat, pressed, released);
|
||||||
@@ -625,23 +581,28 @@ void UIScene_JoinMenu::JoinGame(UIScene_JoinMenu* pClass)
|
|||||||
ProfileManager.DisplaySystemMessage( SCE_MSG_DIALOG_SYSMSG_TYPE_TRC_PSN_CHAT_RESTRICTION, ProfileManager.GetPrimaryPad() );
|
ProfileManager.DisplaySystemMessage( SCE_MSG_DIALOG_SYSMSG_TYPE_TRC_PSN_CHAT_RESTRICTION, ProfileManager.GetPrimaryPad() );
|
||||||
}
|
}
|
||||||
#endif
|
#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 );
|
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
|
// Alert the app the we no longer want to be informed of ethernet connections
|
||||||
app.SetLiveLinkRequired( false );
|
app.SetLiveLinkRequired( false );
|
||||||
|
|
||||||
|
#ifdef _WINDOWS64
|
||||||
|
if (result == CGameNetworkManager::JOINGAME_PENDING)
|
||||||
|
{
|
||||||
|
pClass->m_bIgnoreInput = false;
|
||||||
|
ConnectionProgressParams *param = new ConnectionProgressParams();
|
||||||
|
param->iPad = ProfileManager.GetPrimaryPad();
|
||||||
|
param->stringId = IDS_PROGRESS_CONNECTING;
|
||||||
|
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 )
|
if( result != CGameNetworkManager::JOINGAME_SUCCESS )
|
||||||
{
|
{
|
||||||
int exitReasonStringId = -1;
|
int exitReasonStringId = -1;
|
||||||
|
|||||||
@@ -70,8 +70,6 @@ private:
|
|||||||
wstring m_editServerPort;
|
wstring m_editServerPort;
|
||||||
int m_editServerButtonIndex;
|
int m_editServerButtonIndex;
|
||||||
int m_deleteServerButtonIndex;
|
int m_deleteServerButtonIndex;
|
||||||
bool m_asyncJoinInProgress;
|
|
||||||
DWORD m_joinLocalUsersMask;
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|||||||
@@ -67,12 +67,14 @@ SOCKET WinsockNetLayer::s_splitScreenSocket[XUSER_MAX_COUNT] = { INVALID_SOCKET,
|
|||||||
BYTE WinsockNetLayer::s_splitScreenSmallId[XUSER_MAX_COUNT] = { 0xFF, 0xFF, 0xFF, 0xFF };
|
BYTE WinsockNetLayer::s_splitScreenSmallId[XUSER_MAX_COUNT] = { 0xFF, 0xFF, 0xFF, 0xFF };
|
||||||
HANDLE WinsockNetLayer::s_splitScreenRecvThread[XUSER_MAX_COUNT] = {nullptr, nullptr, nullptr, nullptr};
|
HANDLE WinsockNetLayer::s_splitScreenRecvThread[XUSER_MAX_COUNT] = {nullptr, nullptr, nullptr, nullptr};
|
||||||
|
|
||||||
volatile bool WinsockNetLayer::s_joinCancelled = false;
|
HANDLE WinsockNetLayer::s_joinThread = nullptr;
|
||||||
volatile bool WinsockNetLayer::s_joinComplete = false;
|
volatile WinsockNetLayer::eJoinState WinsockNetLayer::s_joinState = WinsockNetLayer::eJoinState_Idle;
|
||||||
bool WinsockNetLayer::s_joinResult = false;
|
volatile int WinsockNetLayer::s_joinAttempt = 0;
|
||||||
HANDLE WinsockNetLayer::s_joinGameThread = nullptr;
|
volatile bool WinsockNetLayer::s_joinCancel = false;
|
||||||
char WinsockNetLayer::s_joinIP[256] = {};
|
char WinsockNetLayer::s_joinIP[256] = {};
|
||||||
int WinsockNetLayer::s_joinPort = 0;
|
int WinsockNetLayer::s_joinPort = 0;
|
||||||
|
BYTE WinsockNetLayer::s_joinAssignedSmallId = 0;
|
||||||
|
DisconnectPacket::eDisconnectReason WinsockNetLayer::s_joinRejectReason = DisconnectPacket::eDisconnect_Quitting;
|
||||||
|
|
||||||
bool g_Win64MultiplayerHost = false;
|
bool g_Win64MultiplayerHost = false;
|
||||||
bool g_Win64MultiplayerJoin = false;
|
bool g_Win64MultiplayerJoin = false;
|
||||||
@@ -121,6 +123,15 @@ void WinsockNetLayer::Shutdown()
|
|||||||
StopAdvertising();
|
StopAdvertising();
|
||||||
StopDiscovery();
|
StopDiscovery();
|
||||||
|
|
||||||
|
s_joinCancel = true;
|
||||||
|
if (s_joinThread != nullptr)
|
||||||
|
{
|
||||||
|
WaitForSingleObject(s_joinThread, 5000);
|
||||||
|
CloseHandle(s_joinThread);
|
||||||
|
s_joinThread = nullptr;
|
||||||
|
}
|
||||||
|
s_joinState = eJoinState_Idle;
|
||||||
|
|
||||||
s_active = false;
|
s_active = false;
|
||||||
s_connected = false;
|
s_connected = false;
|
||||||
|
|
||||||
@@ -349,7 +360,7 @@ bool WinsockNetLayer::JoinGame(const char* ip, int port)
|
|||||||
|
|
||||||
for (int attempt = 0; attempt < maxAttempts; ++attempt)
|
for (int attempt = 0; attempt < maxAttempts; ++attempt)
|
||||||
{
|
{
|
||||||
if (s_joinCancelled)
|
if (s_joinCancel)
|
||||||
{
|
{
|
||||||
app.DebugPrintf("JoinGame cancelled by user\n");
|
app.DebugPrintf("JoinGame cancelled by user\n");
|
||||||
break;
|
break;
|
||||||
@@ -478,56 +489,235 @@ bool WinsockNetLayer::JoinGame(const char* ip, int port)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
DWORD WINAPI WinsockNetLayer::JoinGameThreadProc(LPVOID param)
|
bool WinsockNetLayer::BeginJoinGame(const char* ip, int port)
|
||||||
{
|
{
|
||||||
s_joinResult = JoinGame(s_joinIP, s_joinPort);
|
if (!s_initialized && !Initialize()) return false;
|
||||||
s_joinComplete = true;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool WinsockNetLayer::StartJoinGameAsync(const char* ip, int port)
|
// Clean up any prior join attempt
|
||||||
{
|
CancelJoinGame();
|
||||||
// Wait for any previous join thread to finish
|
if (s_joinThread != nullptr)
|
||||||
if (s_joinGameThread != nullptr)
|
|
||||||
{
|
{
|
||||||
WaitForSingleObject(s_joinGameThread, 5000);
|
WaitForSingleObject(s_joinThread, 5000);
|
||||||
CloseHandle(s_joinGameThread);
|
CloseHandle(s_joinThread);
|
||||||
s_joinGameThread = nullptr;
|
s_joinThread = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
s_isHost = false;
|
||||||
|
s_hostSmallId = 0;
|
||||||
|
s_connected = false;
|
||||||
|
s_active = false;
|
||||||
|
|
||||||
|
if (s_hostConnectionSocket != INVALID_SOCKET)
|
||||||
|
{
|
||||||
|
closesocket(s_hostConnectionSocket);
|
||||||
|
s_hostConnectionSocket = INVALID_SOCKET;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (s_clientRecvThread != nullptr)
|
||||||
|
{
|
||||||
|
WaitForSingleObject(s_clientRecvThread, 5000);
|
||||||
|
CloseHandle(s_clientRecvThread);
|
||||||
|
s_clientRecvThread = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
strncpy_s(s_joinIP, sizeof(s_joinIP), ip, _TRUNCATE);
|
strncpy_s(s_joinIP, sizeof(s_joinIP), ip, _TRUNCATE);
|
||||||
s_joinPort = port;
|
s_joinPort = port;
|
||||||
s_joinCancelled = false;
|
s_joinAttempt = 0;
|
||||||
s_joinComplete = false;
|
s_joinCancel = false;
|
||||||
s_joinResult = false;
|
s_joinAssignedSmallId = 0;
|
||||||
|
s_joinRejectReason = DisconnectPacket::eDisconnect_Quitting;
|
||||||
|
s_joinState = eJoinState_Connecting;
|
||||||
|
|
||||||
s_joinGameThread = CreateThread(nullptr, 0, JoinGameThreadProc, nullptr, 0, nullptr);
|
s_joinThread = CreateThread(nullptr, 0, JoinThreadProc, nullptr, 0, nullptr);
|
||||||
return s_joinGameThread != nullptr;
|
if (s_joinThread == nullptr)
|
||||||
|
{
|
||||||
|
s_joinState = eJoinState_Failed;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WinsockNetLayer::IsJoinComplete()
|
DWORD WINAPI WinsockNetLayer::JoinThreadProc(LPVOID param)
|
||||||
{
|
{
|
||||||
return s_joinComplete;
|
struct addrinfo hints = {}, *result = nullptr;
|
||||||
}
|
hints.ai_family = AF_INET;
|
||||||
|
hints.ai_socktype = SOCK_STREAM;
|
||||||
|
hints.ai_protocol = IPPROTO_TCP;
|
||||||
|
|
||||||
bool WinsockNetLayer::GetJoinResult()
|
char portStr[16];
|
||||||
{
|
sprintf_s(portStr, "%d", s_joinPort);
|
||||||
return s_joinResult;
|
|
||||||
|
if (getaddrinfo(s_joinIP, portStr, &hints, &result) != 0)
|
||||||
|
{
|
||||||
|
app.DebugPrintf("getaddrinfo failed for %s:%d\n", s_joinIP, s_joinPort);
|
||||||
|
s_joinState = eJoinState_Failed;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool connected = false;
|
||||||
|
BYTE assignedSmallId = 0;
|
||||||
|
SOCKET sock = INVALID_SOCKET;
|
||||||
|
const int connectTimeoutSec = 5;
|
||||||
|
|
||||||
|
for (int attempt = 0; attempt < JOIN_MAX_ATTEMPTS; ++attempt)
|
||||||
|
{
|
||||||
|
if (s_joinCancel) { freeaddrinfo(result); s_joinState = eJoinState_Cancelled; return 0; }
|
||||||
|
|
||||||
|
s_joinAttempt = attempt + 1;
|
||||||
|
|
||||||
|
sock = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
|
||||||
|
if (sock == INVALID_SOCKET) break;
|
||||||
|
|
||||||
|
int noDelay = 1;
|
||||||
|
setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (const char*)&noDelay, sizeof(noDelay));
|
||||||
|
|
||||||
|
// Non-blocking connect with select() timeout
|
||||||
|
u_long nonBlocking = 1;
|
||||||
|
ioctlsocket(sock, FIONBIO, &nonBlocking);
|
||||||
|
|
||||||
|
int iResult = connect(sock, result->ai_addr, static_cast<int>(result->ai_addrlen));
|
||||||
|
if (iResult == SOCKET_ERROR)
|
||||||
|
{
|
||||||
|
int err = WSAGetLastError();
|
||||||
|
if (err == WSAEWOULDBLOCK)
|
||||||
|
{
|
||||||
|
fd_set writeSet, errorSet;
|
||||||
|
FD_ZERO(&writeSet); FD_SET(sock, &writeSet);
|
||||||
|
FD_ZERO(&errorSet); FD_SET(sock, &errorSet);
|
||||||
|
struct timeval tv = { connectTimeoutSec, 0 };
|
||||||
|
|
||||||
|
int selectResult = select(0, nullptr, &writeSet, &errorSet, &tv);
|
||||||
|
if (selectResult <= 0 || FD_ISSET(sock, &errorSet))
|
||||||
|
{
|
||||||
|
app.DebugPrintf("connect() to %s:%d timed out (attempt %d/%d)\n", s_joinIP, s_joinPort, attempt + 1, JOIN_MAX_ATTEMPTS);
|
||||||
|
closesocket(sock); sock = INVALID_SOCKET;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
app.DebugPrintf("connect() to %s:%d failed (attempt %d/%d): %d\n", s_joinIP, s_joinPort, attempt + 1, JOIN_MAX_ATTEMPTS, err);
|
||||||
|
closesocket(sock); sock = INVALID_SOCKET;
|
||||||
|
for (int w = 0; w < 4 && !s_joinCancel; w++) Sleep(50);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Restore blocking mode
|
||||||
|
u_long blocking = 0;
|
||||||
|
ioctlsocket(sock, FIONBIO, &blocking);
|
||||||
|
|
||||||
|
// Temporary recv timeout for the handshake only
|
||||||
|
DWORD recvTimeout = connectTimeoutSec * 1000;
|
||||||
|
setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (const char*)&recvTimeout, sizeof(recvTimeout));
|
||||||
|
|
||||||
|
BYTE assignBuf[1];
|
||||||
|
if (recv(sock, (char*)assignBuf, 1, 0) != 1)
|
||||||
|
{
|
||||||
|
app.DebugPrintf("Failed to receive small ID assignment from host (attempt %d/%d)\n", attempt + 1, JOIN_MAX_ATTEMPTS);
|
||||||
|
closesocket(sock); sock = INVALID_SOCKET;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (assignBuf[0] == WIN64_SMALLID_REJECT)
|
||||||
|
{
|
||||||
|
BYTE rejectBuf[5];
|
||||||
|
if (!RecvExact(sock, rejectBuf, 5))
|
||||||
|
{
|
||||||
|
app.DebugPrintf("Failed to receive reject reason from host\n");
|
||||||
|
closesocket(sock); sock = INVALID_SOCKET;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
int reason = ((rejectBuf[1] & 0xff) << 24) | ((rejectBuf[2] & 0xff) << 16) |
|
||||||
|
((rejectBuf[3] & 0xff) << 8) | (rejectBuf[4] & 0xff);
|
||||||
|
s_joinRejectReason = (DisconnectPacket::eDisconnectReason)reason;
|
||||||
|
closesocket(sock);
|
||||||
|
freeaddrinfo(result);
|
||||||
|
s_joinState = eJoinState_Rejected;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
assignedSmallId = assignBuf[0];
|
||||||
|
connected = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
freeaddrinfo(result);
|
||||||
|
|
||||||
|
if (s_joinCancel)
|
||||||
|
{
|
||||||
|
if (sock != INVALID_SOCKET) closesocket(sock);
|
||||||
|
s_joinState = eJoinState_Cancelled;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!connected)
|
||||||
|
{
|
||||||
|
s_joinState = eJoinState_Failed;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear recv timeout before handing socket to recv thread
|
||||||
|
DWORD noTimeout = 0;
|
||||||
|
setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (const char*)&noTimeout, sizeof(noTimeout));
|
||||||
|
|
||||||
|
s_hostConnectionSocket = sock;
|
||||||
|
s_joinAssignedSmallId = assignedSmallId;
|
||||||
|
s_joinState = eJoinState_Success;
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void WinsockNetLayer::CancelJoinGame()
|
void WinsockNetLayer::CancelJoinGame()
|
||||||
{
|
{
|
||||||
s_joinCancelled = true;
|
s_joinCancel = true;
|
||||||
|
|
||||||
// Close the socket to immediately unblock any in-progress connect/select/recv
|
// Close socket to immediately unblock any in-progress connect/select/recv
|
||||||
SOCKET sock = s_hostConnectionSocket;
|
SOCKET sock = s_hostConnectionSocket;
|
||||||
if (sock != INVALID_SOCKET)
|
if (sock != INVALID_SOCKET)
|
||||||
{
|
{
|
||||||
s_hostConnectionSocket = INVALID_SOCKET;
|
s_hostConnectionSocket = INVALID_SOCKET;
|
||||||
closesocket(sock);
|
closesocket(sock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (s_joinState == eJoinState_Success || s_joinState == eJoinState_Connecting)
|
||||||
|
{
|
||||||
|
s_joinState = eJoinState_Cancelled;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool WinsockNetLayer::FinalizeJoin()
|
||||||
|
{
|
||||||
|
if (s_joinState != eJoinState_Success)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
s_localSmallId = s_joinAssignedSmallId;
|
||||||
|
|
||||||
|
strncpy_s(g_Win64MultiplayerIP, sizeof(g_Win64MultiplayerIP), s_joinIP, _TRUNCATE);
|
||||||
|
g_Win64MultiplayerPort = s_joinPort;
|
||||||
|
|
||||||
|
app.DebugPrintf("Win64 LAN: Connected to %s:%d, assigned smallId=%d\n",
|
||||||
|
s_joinIP, s_joinPort, s_localSmallId);
|
||||||
|
|
||||||
|
s_active = true;
|
||||||
|
s_connected = true;
|
||||||
|
|
||||||
|
s_clientRecvThread = CreateThread(nullptr, 0, ClientRecvThreadProc, nullptr, 0, nullptr);
|
||||||
|
|
||||||
|
if (s_joinThread != nullptr)
|
||||||
|
{
|
||||||
|
WaitForSingleObject(s_joinThread, 2000);
|
||||||
|
CloseHandle(s_joinThread);
|
||||||
|
s_joinThread = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
s_joinState = eJoinState_Idle;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
WinsockNetLayer::eJoinState WinsockNetLayer::GetJoinState() { return s_joinState; }
|
||||||
|
int WinsockNetLayer::GetJoinAttempt() { return s_joinAttempt; }
|
||||||
|
int WinsockNetLayer::GetJoinMaxAttempts() { return JOIN_MAX_ATTEMPTS; }
|
||||||
|
DisconnectPacket::eDisconnectReason WinsockNetLayer::GetJoinRejectReason() { return s_joinRejectReason; }
|
||||||
|
|
||||||
bool WinsockNetLayer::SendOnSocket(SOCKET sock, const void* data, int dataSize)
|
bool WinsockNetLayer::SendOnSocket(SOCKET sock, const void* data, int dataSize)
|
||||||
{
|
{
|
||||||
if (sock == INVALID_SOCKET || dataSize <= 0 || dataSize > WIN64_NET_MAX_PACKET_SIZE) return false;
|
if (sock == INVALID_SOCKET || dataSize <= 0 || dataSize > WIN64_NET_MAX_PACKET_SIZE) return false;
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
#include <WS2tcpip.h>
|
#include <WS2tcpip.h>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include "..\..\Common\Network\NetworkPlayerInterface.h"
|
#include "..\..\Common\Network\NetworkPlayerInterface.h"
|
||||||
|
#include "..\..\..\Minecraft.World\DisconnectPacket.h"
|
||||||
|
|
||||||
#pragma comment(lib, "Ws2_32.lib")
|
#pragma comment(lib, "Ws2_32.lib")
|
||||||
|
|
||||||
@@ -69,11 +70,23 @@ public:
|
|||||||
static bool HostGame(int port, const char* bindIp = nullptr);
|
static bool HostGame(int port, const char* bindIp = nullptr);
|
||||||
static bool JoinGame(const char* ip, int port);
|
static bool JoinGame(const char* ip, int port);
|
||||||
|
|
||||||
// Async join: runs JoinGame on a background thread so the UI stays responsive
|
// Async join: runs connection on a background thread so the UI stays responsive
|
||||||
static bool StartJoinGameAsync(const char* ip, int port);
|
enum eJoinState
|
||||||
static bool IsJoinComplete();
|
{
|
||||||
static bool GetJoinResult();
|
eJoinState_Idle,
|
||||||
|
eJoinState_Connecting,
|
||||||
|
eJoinState_Success,
|
||||||
|
eJoinState_Failed,
|
||||||
|
eJoinState_Rejected,
|
||||||
|
eJoinState_Cancelled
|
||||||
|
};
|
||||||
|
static bool BeginJoinGame(const char* ip, int port);
|
||||||
static void CancelJoinGame();
|
static void CancelJoinGame();
|
||||||
|
static bool FinalizeJoin();
|
||||||
|
static eJoinState GetJoinState();
|
||||||
|
static int GetJoinAttempt();
|
||||||
|
static int GetJoinMaxAttempts();
|
||||||
|
static DisconnectPacket::eDisconnectReason GetJoinRejectReason();
|
||||||
|
|
||||||
static bool SendToSmallId(BYTE targetSmallId, const void* data, int dataSize);
|
static bool SendToSmallId(BYTE targetSmallId, const void* data, int dataSize);
|
||||||
static bool SendOnSocket(SOCKET sock, const void* data, int dataSize);
|
static bool SendOnSocket(SOCKET sock, const void* data, int dataSize);
|
||||||
@@ -118,7 +131,7 @@ private:
|
|||||||
static DWORD WINAPI SplitScreenRecvThreadProc(LPVOID param);
|
static DWORD WINAPI SplitScreenRecvThreadProc(LPVOID param);
|
||||||
static DWORD WINAPI AdvertiseThreadProc(LPVOID param);
|
static DWORD WINAPI AdvertiseThreadProc(LPVOID param);
|
||||||
static DWORD WINAPI DiscoveryThreadProc(LPVOID param);
|
static DWORD WINAPI DiscoveryThreadProc(LPVOID param);
|
||||||
static DWORD WINAPI JoinGameThreadProc(LPVOID param);
|
static DWORD WINAPI JoinThreadProc(LPVOID param);
|
||||||
|
|
||||||
static SOCKET s_listenSocket;
|
static SOCKET s_listenSocket;
|
||||||
static SOCKET s_hostConnectionSocket;
|
static SOCKET s_hostConnectionSocket;
|
||||||
@@ -162,12 +175,15 @@ private:
|
|||||||
static CRITICAL_SECTION s_smallIdToSocketLock;
|
static CRITICAL_SECTION s_smallIdToSocketLock;
|
||||||
|
|
||||||
// Async join state
|
// Async join state
|
||||||
static volatile bool s_joinCancelled;
|
static const int JOIN_MAX_ATTEMPTS = 3;
|
||||||
static volatile bool s_joinComplete;
|
static HANDLE s_joinThread;
|
||||||
static bool s_joinResult;
|
static volatile eJoinState s_joinState;
|
||||||
static HANDLE s_joinGameThread;
|
static volatile int s_joinAttempt;
|
||||||
|
static volatile bool s_joinCancel;
|
||||||
static char s_joinIP[256];
|
static char s_joinIP[256];
|
||||||
static int s_joinPort;
|
static int s_joinPort;
|
||||||
|
static BYTE s_joinAssignedSmallId;
|
||||||
|
static DisconnectPacket::eDisconnectReason s_joinRejectReason;
|
||||||
|
|
||||||
// Per-pad split-screen TCP connections (client-side, non-host only)
|
// Per-pad split-screen TCP connections (client-side, non-host only)
|
||||||
static SOCKET s_splitScreenSocket[XUSER_MAX_COUNT];
|
static SOCKET s_splitScreenSocket[XUSER_MAX_COUNT];
|
||||||
|
|||||||
Reference in New Issue
Block a user