mirror of
https://github.com/smartcmd/MinecraftConsoles.git
synced 2026-03-27 01:18:14 +05:00
Add asynchronous server joining (#1408)
This commit is contained in:
@@ -47,7 +47,8 @@ public:
|
||||
{
|
||||
JOINGAME_SUCCESS,
|
||||
JOINGAME_FAIL_GENERAL,
|
||||
JOINGAME_FAIL_SERVER_FULL
|
||||
JOINGAME_FAIL_SERVER_FULL,
|
||||
JOINGAME_PENDING
|
||||
} eJoinGameResult;
|
||||
|
||||
void Initialise();
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -67,6 +67,16 @@ SOCKET WinsockNetLayer::s_splitScreenSocket[XUSER_MAX_COUNT] = { INVALID_SOCKET,
|
||||
BYTE WinsockNetLayer::s_splitScreenSmallId[XUSER_MAX_COUNT] = { 0xFF, 0xFF, 0xFF, 0xFF };
|
||||
HANDLE WinsockNetLayer::s_splitScreenRecvThread[XUSER_MAX_COUNT] = {nullptr, nullptr, nullptr, nullptr};
|
||||
|
||||
// async stuff
|
||||
HANDLE WinsockNetLayer::s_joinThread = nullptr;
|
||||
volatile WinsockNetLayer::eJoinState WinsockNetLayer::s_joinState = WinsockNetLayer::eJoinState_Idle;
|
||||
volatile int WinsockNetLayer::s_joinAttempt = 0;
|
||||
volatile bool WinsockNetLayer::s_joinCancel = false;
|
||||
char WinsockNetLayer::s_joinIP[256] = {};
|
||||
int WinsockNetLayer::s_joinPort = 0;
|
||||
BYTE WinsockNetLayer::s_joinAssignedSmallId = 0;
|
||||
DisconnectPacket::eDisconnectReason WinsockNetLayer::s_joinRejectReason = DisconnectPacket::eDisconnect_Quitting;
|
||||
|
||||
bool g_Win64MultiplayerHost = false;
|
||||
bool g_Win64MultiplayerJoin = false;
|
||||
int g_Win64MultiplayerPort = WIN64_NET_DEFAULT_PORT;
|
||||
@@ -114,6 +124,15 @@ void WinsockNetLayer::Shutdown()
|
||||
StopAdvertising();
|
||||
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_connected = false;
|
||||
|
||||
@@ -421,6 +440,215 @@ bool WinsockNetLayer::JoinGame(const char* ip, int port)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WinsockNetLayer::BeginJoinGame(const char* ip, int port)
|
||||
{
|
||||
if (!s_initialized && !Initialize()) return false;
|
||||
|
||||
// if there isnt any cleanup it sometime caused issues. Oops
|
||||
CancelJoinGame();
|
||||
if (s_joinThread != nullptr)
|
||||
{
|
||||
WaitForSingleObject(s_joinThread, 5000);
|
||||
CloseHandle(s_joinThread);
|
||||
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);
|
||||
s_joinPort = port;
|
||||
s_joinAttempt = 0;
|
||||
s_joinCancel = false;
|
||||
s_joinAssignedSmallId = 0;
|
||||
s_joinRejectReason = DisconnectPacket::eDisconnect_Quitting;
|
||||
s_joinState = eJoinState_Connecting;
|
||||
|
||||
s_joinThread = CreateThread(nullptr, 0, JoinThreadProc, nullptr, 0, nullptr);
|
||||
if (s_joinThread == nullptr)
|
||||
{
|
||||
s_joinState = eJoinState_Failed;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
DWORD WINAPI WinsockNetLayer::JoinThreadProc(LPVOID param)
|
||||
{
|
||||
struct addrinfo hints = {};
|
||||
struct addrinfo* result = nullptr;
|
||||
|
||||
hints.ai_family = AF_INET;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
hints.ai_protocol = IPPROTO_TCP;
|
||||
|
||||
char portStr[16];
|
||||
sprintf_s(portStr, "%d", s_joinPort);
|
||||
|
||||
int iResult = getaddrinfo(s_joinIP, portStr, &hints, &result);
|
||||
if (iResult != 0)
|
||||
{
|
||||
app.DebugPrintf("getaddrinfo failed for %s:%d - %d\n", s_joinIP, s_joinPort, iResult);
|
||||
s_joinState = eJoinState_Failed;
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool connected = false;
|
||||
BYTE assignedSmallId = 0;
|
||||
SOCKET sock = INVALID_SOCKET;
|
||||
|
||||
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)
|
||||
{
|
||||
app.DebugPrintf("socket() failed: %d\n", WSAGetLastError());
|
||||
break;
|
||||
}
|
||||
|
||||
int noDelay = 1;
|
||||
setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (const char*)&noDelay, sizeof(noDelay));
|
||||
|
||||
iResult = connect(sock, result->ai_addr, static_cast<int>(result->ai_addrlen));
|
||||
if (iResult == SOCKET_ERROR)
|
||||
{
|
||||
int err = WSAGetLastError();
|
||||
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;
|
||||
}
|
||||
|
||||
BYTE assignBuf[1];
|
||||
int bytesRecv = recv(sock, (char*)assignBuf, 1, 0);
|
||||
if (bytesRecv != 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;
|
||||
for (int w = 0; w < 4 && !s_joinCancel; w++)
|
||||
Sleep(50);
|
||||
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;
|
||||
for (int w = 0; w < 4 && !s_joinCancel; w++)
|
||||
Sleep(50);
|
||||
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;
|
||||
}
|
||||
|
||||
s_hostConnectionSocket = sock;
|
||||
s_joinAssignedSmallId = assignedSmallId;
|
||||
s_joinState = eJoinState_Success;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void WinsockNetLayer::CancelJoinGame()
|
||||
{
|
||||
if (s_joinState == eJoinState_Connecting)
|
||||
{
|
||||
s_joinCancel = true;
|
||||
}
|
||||
else if (s_joinState == eJoinState_Success)
|
||||
{
|
||||
// fix a race cond
|
||||
if (s_hostConnectionSocket != INVALID_SOCKET)
|
||||
{
|
||||
closesocket(s_hostConnectionSocket);
|
||||
s_hostConnectionSocket = INVALID_SOCKET;
|
||||
}
|
||||
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("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;
|
||||
}
|
||||
|
||||
bool WinsockNetLayer::SendOnSocket(SOCKET sock, const void* data, int dataSize)
|
||||
{
|
||||
if (sock == INVALID_SOCKET || dataSize <= 0 || dataSize > WIN64_NET_MAX_PACKET_SIZE) return false;
|
||||
@@ -1334,4 +1562,25 @@ DWORD WINAPI WinsockNetLayer::DiscoveryThreadProc(LPVOID param)
|
||||
return 0;
|
||||
}
|
||||
|
||||
// some lazy helper funcs
|
||||
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;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -21,6 +21,8 @@
|
||||
|
||||
class Socket;
|
||||
|
||||
#include "..\..\..\Minecraft.World\DisconnectPacket.h"
|
||||
|
||||
#pragma pack(push, 1)
|
||||
struct Win64LANBroadcast
|
||||
{
|
||||
@@ -69,6 +71,23 @@ public:
|
||||
static bool HostGame(int port, const char* bindIp = nullptr);
|
||||
static bool JoinGame(const char* ip, int port);
|
||||
|
||||
enum eJoinState
|
||||
{
|
||||
eJoinState_Idle,
|
||||
eJoinState_Connecting,
|
||||
eJoinState_Success,
|
||||
eJoinState_Failed,
|
||||
eJoinState_Rejected,
|
||||
eJoinState_Cancelled
|
||||
};
|
||||
static bool BeginJoinGame(const char* ip, int port);
|
||||
static void CancelJoinGame();
|
||||
static eJoinState GetJoinState();
|
||||
static int GetJoinAttempt();
|
||||
static int GetJoinMaxAttempts();
|
||||
static DisconnectPacket::eDisconnectReason GetJoinRejectReason();
|
||||
static bool FinalizeJoin();
|
||||
|
||||
static bool SendToSmallId(BYTE targetSmallId, const void* data, int dataSize);
|
||||
static bool SendOnSocket(SOCKET sock, const void* data, int dataSize);
|
||||
|
||||
@@ -112,6 +131,17 @@ private:
|
||||
static DWORD WINAPI SplitScreenRecvThreadProc(LPVOID param);
|
||||
static DWORD WINAPI AdvertiseThreadProc(LPVOID param);
|
||||
static DWORD WINAPI DiscoveryThreadProc(LPVOID param);
|
||||
static DWORD WINAPI JoinThreadProc(LPVOID param);
|
||||
|
||||
static HANDLE s_joinThread;
|
||||
static volatile eJoinState s_joinState;
|
||||
static volatile int s_joinAttempt;
|
||||
static volatile bool s_joinCancel;
|
||||
static char s_joinIP[256];
|
||||
static int s_joinPort;
|
||||
static BYTE s_joinAssignedSmallId;
|
||||
static DisconnectPacket::eDisconnectReason s_joinRejectReason;
|
||||
static const int JOIN_MAX_ATTEMPTS = 4;
|
||||
|
||||
static SOCKET s_listenSocket;
|
||||
static SOCKET s_hostConnectionSocket;
|
||||
|
||||
Reference in New Issue
Block a user